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