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