1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 from copy import deepcopy
26 from numpy import uint8, zeros
27 from os import sep
28 from string import split
29 import webbrowser
30 import wx
31 import wx.html
32 from wx.lib.wordwrap import wordwrap
33
34
35 from graphics import IMAGE_PATH
36 from info import Info_box
37 from status import Status; status = Status()
38
39
40 from gui.fonts import font
41 from gui.icons import relax_icons
42
43
45 """The about dialog base class."""
46
47
48 colour1 = None
49 colour2 = None
50
51
52 dim_x = 400
53 dim_y = 600
54 max_x = None
55 max_y = None
56
57
58 border = 0
59
60
61 style = wx.BORDER_NONE | wx.STAY_ON_TOP
62
63
64 DESTROY_ON_CLICK = True
65
66
67 SCROLL_RATE = 20
68
69 - def __init__(self, parent=None, id=-1, title='', html_text=None):
70 """Build the dialog."""
71
72
73 super(About_base, self).__init__(parent=parent, id=id, title=title, style=self.style)
74
75
76 self.SetIcons(relax_icons)
77
78
79 self.window = wx.ScrolledWindow(self, -1)
80
81
82 self._offset_val = 0
83
84
85 self.cursor_type = 'normal'
86
87
88 self.url_text = []
89 self.url_pos = []
90
91
92 self.text_max_x = 0
93 self.virtual_size()
94
95
96 self.SetSize((self.virt_x, self.dim_y))
97
98
99 self.window.SetVirtualSize((self.virt_x, self.virt_y))
100
101
102 self.window.SetScrollRate(0, self.SCROLL_RATE)
103
104
105 self.create_buffered_dc()
106
107
108 if html_text:
109 self.add_html(html_text)
110
111
112 self.window.Bind(wx.EVT_PAINT, self.generate)
113
114
115 self.window.Bind(wx.EVT_MOTION, self.cursor_style)
116
117
118 self.window.Bind(wx.EVT_LEFT_DOWN, self.process_click)
119
120
121 self.Centre()
122
123
125 """Add the given HTML text to the DC.
126
127 @param text: The HTML text.
128 @type text: str
129 """
130
131
132 self.html = wx.html.HtmlDCRenderer()
133
134
135 self.html.SetFonts("Roman", "Courier")
136
137
138 self.html.SetDC(self.dc, 1.0)
139
140
141 self.html.SetSize(self.virt_x, self.virt_y)
142
143
144 self.html.SetHtmlText(text)
145
146
147 self.html.Render(self.border, self.border, known_pagebreaks=[])
148
149
152
153
155 """Build the buffered dc containing the window contents."""
156
157
158 size = max(self.virt_x, self.virt_y)
159 self.buffer = wx.EmptyBitmap(size, size)
160
161
162 self.dc = wx.BufferedDC(None, self.buffer)
163
164
165 self.set_background()
166
167
168 if status.debug:
169
170 self.dc.DrawLine(0, 0, self.virt_x, self.virt_y)
171 self.dc.DrawLine(self.virt_x, 0, 0, self.virt_y)
172
173
174 num = self.virt_y / 200
175 for i in range(num):
176 pos = i * 200
177 self.dc.DrawLine(0, pos, self.virt_x, pos)
178 self.dc.SetFont(wx.Font(8, wx.FONTFAMILY_SCRIPT, wx.NORMAL, wx.NORMAL))
179 self.dc.DrawText(str(pos), self.virt_x-40, pos-10)
180
181
182
183 self.build_widget()
184
185
186 self.dc.EndDrawing()
187
188
190 """Change the mouse cursor when over the url."""
191
192
193 x = event.GetX()
194 y = event.GetY()
195
196
197 y = y + self.window.GetViewStart()[1]*self.SCROLL_RATE
198
199
200 over_url = False
201 for i in range(len(self.url_pos)):
202 if x > self.url_pos[i][0, 0] and x < self.url_pos[i][0, 1] and y > self.url_pos[i][1, 0] and y < self.url_pos[i][1, 1]:
203 over_url = True
204
205
206 if over_url and self.cursor_type == 'normal':
207
208 select_cursor = wx.StockCursor(wx.CURSOR_HAND)
209
210
211 self.window.SetCursor(select_cursor)
212
213
214 self.cursor_type = 'select'
215
216
217 if not over_url and self.cursor_type == 'select':
218
219 select_cursor = wx.StockCursor(wx.CURSOR_ARROW)
220
221
222 self.window.SetCursor(select_cursor)
223
224
225 self.cursor_type = 'normal'
226
227
228 - def draw_url(self, url_text=None, pos_x=0, carriage_ret=False, centre=False):
229 """Draw a URL as a hyperlink.
230
231 @keyword url_text: The text of the url.
232 @type url_text: str
233 @keyword pos_x: The starting x position for the text.
234 @type pos_x: int
235 @keyword carriage_ret: A flag which if True will cause a carriage return, by shifting the offset by y.
236 @type carriage_ret: bool
237 @keyword centre: A flag which if True will cause the URL to be centred in the window.
238 @type centre: bool
239 """
240
241
242 orig_font = self.dc.GetFont()
243 orig_fg = deepcopy(self.dc.GetTextForeground())
244
245
246 self.dc.SetFont(font.roman_normal)
247 self.dc.SetTextForeground('#0017aa')
248
249
250 x, y = self.dc.GetTextExtent(url_text)
251
252
253 if centre:
254 pos_x = (self.dim_x - x)/2
255
256
257 text = self.dc.DrawText(url_text, pos_x, self.offset())
258
259
260 self.url_pos.append(zeros((2, 2), int))
261 self.url_pos[-1][0] = [pos_x, pos_x + x]
262 self.url_pos[-1][1] = [self.offset(), self.offset()+y]
263
264
265 if carriage_ret:
266 self.offset(y)
267
268
269 self.url_text.append(url_text)
270
271
272 self.dc.SetFont(orig_font)
273 self.dc.SetTextForeground(orig_fg)
274
275
277 """Draw the title.
278
279 @param text: The text of the title.
280 @type text: str
281 @keyword alt_font: An alternative font.
282 @type alt_font: wx.Font instance
283 """
284
285
286 if alt_font == None:
287 alt_font = font.roman_title
288
289 self.dc.SetFont(alt_font)
290
291
292 x, y = self.dc.GetTextExtent(text)
293
294
295 self.dc.DrawText(text, (self.virt_x - x)/2, self.offset(15))
296
297
298 self.offset(y)
299
300
301 - def draw_wrapped_text(self, text, spacer=10):
302 """Generic method for drawing wrapped text in the relax about widget.
303
304 @param text: The text to wrap and draw.
305 @type text: str
306 @keyword spacer: The pixel width of the spacer to place above the text block.
307 @type spacer: int
308 """
309
310
311 self.dc.SetFont(font.roman_normal)
312
313
314 width = self.dim_x - 2*self.border
315 wrapped_text = wordwrap(text, width, self.dc)
316
317
318 full_x, full_y = self.dc.GetTextExtent(wrapped_text)
319
320
321 self.offset(10)
322
323
324 lines = split(wrapped_text, '\n')
325 for line in lines:
326
327 text_elements, url = self.split_refs(line)
328
329
330 pos_x = self.border
331 for i in range(len(text_elements)):
332
333 if url[i]:
334 self.draw_url(url_text=text_elements[i], pos_x=pos_x)
335
336
337 else:
338 self.dc.DrawText(text_elements[i], pos_x, self.offset())
339
340
341 x, y = self.dc.GetTextExtent(text_elements[i])
342 pos_x += x
343
344
345 self.offset(y + 1)
346
347
349 """Build the device context, add the background, and build the dialog.
350
351 @param event: The wx event.
352 @type event: wx event
353 """
354
355
356
357
358
359 dc = wx.PaintDC(self.window)
360 self.window.PrepareDC(dc)
361 dc.DrawBitmap(self.buffer, 0, 0)
362
363
365 """Shift the y-offset by the given value and return the new offset.
366
367 @keyword val: The value to add to the offset (can be negative).
368 @type val: int
369 @return: The new offset.
370 @rtype: int
371 """
372
373
374 self._offset_val = self._offset_val + val
375
376
377 return self._offset_val
378
379
381 """Determine what to do with the mouse click.
382
383 @param event: The wx event.
384 @type event: wx event
385 """
386
387
388 x = event.GetX()
389 y = event.GetY()
390
391
392 y = y + self.window.GetViewStart()[1]*self.SCROLL_RATE
393
394
395 for i in range(len(self.url_pos)):
396 if x > self.url_pos[i][0, 0] and x < self.url_pos[i][0, 1] and y > self.url_pos[i][1, 0] and y < self.url_pos[i][1, 1]:
397 webbrowser.open_new(self.url_text[i])
398
399
400 if self.DESTROY_ON_CLICK:
401 self.Destroy()
402
403
405 """Build a background for the dialog."""
406
407
408 if self.colour1 and not self.colour2:
409 self.SetBackgroundColour(self.colour1)
410
411
412 elif self.colour1 and self.colour2:
413 self.dc.GradientFillLinear((0, 0, self.virt_x, self.virt_y), self.colour1, self.colour2, wx.SOUTH)
414
415
417 """Split up text based on the location of URLs.
418
419 @param text: The text to parse and split up.
420 @type text: str
421 @return: The list of text elements, and a list of flags which if True indicates a corresponding URL in the text list.
422 @rtype: list of str, list of bool
423 """
424
425
426 elements = []
427 url = []
428
429
430 for i in range(len(text)):
431
432 if len(text) - i < 7:
433 break
434
435
436 if text[i:i+7] == 'http://':
437
438 elements.append(text[0:i])
439 url.append(False)
440
441
442 end_char = [')', ' ']
443 for j in range(i+7, len(text)):
444 if text[j] in end_char:
445 end_i = j
446 break
447
448
449 elements.append(text[i:j])
450 url.append(True)
451
452
453 elements.append(text[j:])
454 url.append(False)
455
456
457 break
458
459
460 if not len(elements):
461 elements.append(text)
462 url.append(False)
463
464
465 return elements, url
466
467
469 """Determine the virtual size of the window."""
470
471
472 if self.max_x:
473 self.virt_x = self.max_x
474 else:
475 self.virt_x = self.dim_x
476 if self.max_y:
477 self.virt_y = self.max_y
478 else:
479 self.virt_y = self.dim_y
480
481
482
484 """The about relax dialog."""
485
486
487 colour1 = '#e5feff'
488 colour2 = '#88cbff'
489
490
491 dim_x = 450
492 dim_y = 700
493
494
495 border = 10
496
497 - def __init__(self, parent=None, id=-1, title="About relax"):
505
506
529
530
532 """Draw the copyright statements."""
533
534
535 self.dc.SetFont(font.roman_normal)
536
537
538 x1, y1 = self.dc.GetTextExtent(self.info.copyright[0])
539 x2, y2 = self.dc.GetTextExtent(self.info.copyright[1])
540
541
542 self.dc.DrawText(self.info.copyright[0], (self.dim_x - x1)/2, self.offset(15))
543 self.dc.DrawText(self.info.copyright[1], (self.dim_x - x2)/2, self.offset(y1+3))
544
545
546 self.offset(y2)
547
548
550 """Draw the long relax description."""
551
552 self.draw_wrapped_text(self.info.desc_long, spacer=10)
553
554
556 """Draw the relax description text."""
557
558
559 self.dc.SetFont(font.roman_font_12)
560
561
562 x, y = self.dc.GetTextExtent(self.info.desc)
563
564
565 self.dc.DrawText(self.info.desc, (self.dim_x - x)/2, self.offset(15))
566
567
568 self.offset(y)
569
570
572 """Draw the relax icon on the canvas."""
573
574
575 self.dc.DrawBitmap(wx.Bitmap(IMAGE_PATH+'ulysses_shadowless_400x168.png'), (self.dim_x - 400)/2, self.offset(20), True)
576
577
578 self.offset(168)
579
580
585