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