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