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