OSDN Git Service

"button down on uri and move" does not change the selection of ThreadView.
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_view.py
1 # Copyright (C) 2007 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 import pygtk
19 pygtk.require('2.0')
20 import gtk
21 import pango
22 from FukuiNoNamariExt import thread_view_extend
23
24
25 class Line:
26
27     HEIGHT = 15
28
29     def __init__(self, start_index, end_index, rectangle):
30         self.start_index = start_index
31         self.end_index = end_index
32         self.rectangle = rectangle
33
34     def is_on_xy(self, x, y):
35         left = self.rectangle.x
36         right = left + self.rectangle.width
37         top = self.rectangle.y
38         bottom = top + self.rectangle.height
39         return x >= left and x < right and y >= top and y < bottom
40         
41
42 class ElementEmpty:
43
44     def __init__(self):
45         self.initialize()
46
47     def initialize(self):
48         self.line_list = []
49
50     def is_on_xy(self, x, y):
51         for line in self.line_list:
52             if line.is_on_xy(x, y):
53                 return True
54         return False
55
56     def xy_to_index(self, x, y):
57         return 0
58
59     def build_line_list(self, x, y, width, left_margin):
60         self.initialize()
61
62         line = Line(0, 0, gtk.gdk.Rectangle(x, y, width - x, Line.HEIGHT))
63         self.line_list.append(line)
64
65         return width, y
66
67     def get_text(self, selection=False, start_index=0, end_index=0xffffff):
68         return ""
69
70     def draw(self, drawingarea, y_offset, pango_layout,
71              selection=False, start_index=0, end_index=0xffffff):
72         pass
73
74     
75 class ElementText:
76
77     def __init__(self, text, pango_layout):
78         self.text = text
79
80         attrlist = self._get_attrs()
81         self.widths = thread_view_extend.get_char_width(
82             pango_layout.get_context(), text, attrlist)
83
84         self.line_list = []
85
86     def _get_attrs(self):
87         attrs = pango.AttrList()
88         return attrs
89
90     def is_on_xy(self, x, y):
91         for line in self.line_list:
92             if line.is_on_xy(x, y):
93                 return True
94         return False
95
96     def xy_to_index(self, x, y):
97         for line in self.line_list:
98             top = line.rectangle.y
99             bottom = top + line.rectangle.height
100             if y >= top and y < bottom:
101                 sum_of_widths = line.rectangle.x
102                 index = line.start_index
103                 for width in self.widths[line.start_index:line.end_index]:
104                     if sum_of_widths + width/2 > x:
105                         break
106                     sum_of_widths += width
107                     index += 1
108                 return index
109         
110     def build_line_list(self, x, y, width, left_margin):
111         self.line_list = []
112
113         current_line_start_index = 0
114         current_line_x = x
115         current_line_y = y
116         current_line_width = 0
117
118         for index, ch in enumerate(self.text):
119             ch_w = self.widths[index]
120             ch_h = Line.HEIGHT
121             if current_line_x + current_line_width + ch_w > width:
122                 line = Line(
123                     current_line_start_index, index,
124                     gtk.gdk.Rectangle(
125                     current_line_x, current_line_y,
126                     current_line_width, Line.HEIGHT))
127                 self.line_list.append(line)
128
129                 current_line_start_index = index
130                 current_line_x = left_margin
131                 current_line_y += Line.HEIGHT
132                 current_line_width = ch_w
133             else:
134                 current_line_width += ch_w
135
136         if current_line_start_index < len(self.text):
137             line = Line(current_line_start_index, len(self.text),
138                         gtk.gdk.Rectangle(current_line_x,
139                                           current_line_y,
140                                           current_line_width,
141                                           Line.HEIGHT))
142             self.line_list.append(line)
143
144             current_line_x += current_line_width
145
146         return current_line_x, current_line_y
147
148     def get_text(self, selection=False, start_index=0, end_index=0xffffff):
149
150         text = ""
151
152         for line in self.line_list:
153
154             t = self.text[line.start_index:line.end_index]
155             if selection:
156                 s = start_index - line.start_index
157                 s = max(s, 0)
158                 s = min(s, line.end_index - line.start_index)
159
160                 e = end_index - line.start_index
161                 e = min(e, line.end_index - line.start_index)
162                 e = max(e, 0)
163
164                 t = t[s:e]
165
166             text += t
167
168         return text
169
170     def draw(self, drawingarea, y_offset, pango_layout,
171              selection=False, start_index=0, end_index=0xffffff):
172
173         selection_fg = drawingarea.style.fg[3]
174         selection_bg = drawingarea.style.bg[3]
175
176         for line in self.line_list:
177
178             text = self.text[line.start_index:line.end_index]
179             u_text = text.encode("utf8")
180             gc = drawingarea.window.new_gc()
181             attrs = self._get_attrs()
182             if selection:
183
184                 s = start_index - line.start_index
185                 s = max(s, 0)
186                 s = min(s, line.end_index - line.start_index)
187                 s = len(text[:s].encode("utf8"))
188
189                 e = end_index - line.start_index
190                 e = min(e, line.end_index - line.start_index)
191                 e = max(e, 0)
192                 e = len(text[:e].encode("utf8"))
193                     
194                 selection_all_attr_fg = pango.AttrForeground(
195                     selection_fg.red, selection_fg.green, selection_fg.blue,
196                     s, e)
197                 selection_all_attr_bg= pango.AttrBackground(
198                     selection_bg.red, selection_bg.green, selection_bg.blue,
199                     s, e)
200                 attrs.insert(selection_all_attr_fg)
201                 attrs.insert(selection_all_attr_bg)
202
203             pango_layout.set_text(u_text)
204             pango_layout.set_attributes(attrs)
205             drawingarea.window.draw_layout(
206                 gc, line.rectangle.x, line.rectangle.y + y_offset,
207                 pango_layout)
208
209
210 class ElementBoldText(ElementText):
211
212     def _get_attrs(self):
213         attrlist = pango.AttrList()
214         attr = pango.AttrWeight(pango.WEIGHT_BOLD,
215                                    end_index=0xffffff)
216         attrlist.insert(attr)
217         return attrlist
218
219
220 class ElementLink(ElementText):
221     
222     def __init__(self, text, href, pango_layout):
223         self.href = href
224         ElementText.__init__(self, text, pango_layout)
225
226     def _get_attrs(self):
227         attrlist = pango.AttrList()
228         attr = pango.AttrUnderline(pango.UNDERLINE_SINGLE,
229                                    end_index=0xffffff)
230         attrlist.insert(attr)
231         return attrlist
232
233
234 class ResLayout:
235 # represent one line
236
237     def __init__(self, left_margin, resnum, pango_layout):
238         self.element_list = [ElementEmpty()]
239         self.width = 0
240         self.height = 0
241         self.pango_layout = pango_layout
242         self.left_margin = left_margin
243         self.resnum = resnum
244         self.posY = 0
245         self.list_index = 0
246
247     def add_text(self, text, bold, href):
248         if isinstance(self.element_list[0], ElementEmpty):
249             self.element_list = []
250
251         if href:
252             element = ElementLink(text, href, self.pango_layout)
253             self.element_list.append(element)
254         elif bold:
255             element = ElementBoldText(text, self.pango_layout)
256             self.element_list.append(element)
257         else:
258             element = ElementText(text, self.pango_layout)
259             self.element_list.append(element)
260
261     def get_element_from_xy(self, x, y):
262         for element in self.element_list:
263             if element.is_on_xy(x, y):
264                 return element
265         return None
266
267     def get_close_element_from_xy(self, x, y):
268         x= max(x, self.left_margin)
269         element = self.get_element_from_xy(x, y)
270         if element is None and len(self.element_list) != 0:
271             element = self.element_list[len(self.element_list) - 1]
272         return element
273
274     def set_width(self, width):
275
276         self.width = width
277         
278         current_x = self.left_margin
279         current_y = 0
280
281         for element in self.element_list:
282             current_x, current_y = element.build_line_list(
283                 current_x, current_y, width, self.left_margin)
284
285         self.height = current_y + Line.HEIGHT
286
287     def get_pixel_size(self):
288         return self.width, self.height
289
290     def get_text(self, selection_start, selection_end):
291         s_s = selection_start
292         e_s = selection_end
293         s_l, s_e, s_i = selection_start
294         e_l, e_e, e_i = selection_end
295
296         text = ""
297
298         if (s_l is None or s_e is None or s_i is None or
299             e_l is None or e_e is None or e_i is None or
300             self.posY < s_l.posY or self.posY > e_l.posY):
301
302             # nothing to do
303             pass
304
305         elif self.posY > s_s[0].posY and self.posY < e_s[0].posY:
306
307             for element in self.element_list:
308                 text += element.get_text(selection=True)
309
310         elif self == s_s[0] and self == e_s[0]:
311
312             selection = False
313
314             for element in self.element_list:
315                 if s_e == element:
316                     selection = True
317                     start = s_i
318                     end = 0xffffff
319                     if e_e == element:
320                         end = e_i
321                         selection = False
322                     text += element.get_text(selection=True, start_index=start,
323                                              end_index=end)
324                 elif e_e == element:
325                     end = e_i
326                     selection = False
327                     text += element.get_text(
328                         selection=True, end_index=end)
329                 elif selection:
330                     text += element.get_text(selection=True)
331
332         elif self == s_s[0]:
333
334             selection = False
335
336             for element in self.element_list:
337                 if s_e == element:
338                     selection = True
339                     start = s_i
340                     text += element.get_text(selection=True, start_index=start)
341                 elif selection:
342                     text += element.get_text(selection=True)
343
344         elif self == e_s[0]:
345
346             selection = True
347
348             for element in self.element_list:
349                 if e_e == element:
350                     end = e_i
351                     text += element.get_text(selection=True, end_index=e_i)
352                     selection = False
353                 elif selection:
354                     text += element.get_text(selection=True)
355
356         else:
357             # nothing to do
358             pass
359
360         return text
361
362
363     def draw(self, drawingarea, x_offset, y_offset,
364              start_selection, end_selection):
365
366         s_s = start_selection
367         e_s = end_selection
368
369         s_l, s_e, s_i = s_s
370         e_l, e_e, e_i = e_s
371
372         if (s_l is None or s_e is None or s_i is None or
373             e_l is None or e_e is None or e_i is None or
374             self.posY < s_l.posY or self.posY > e_l.posY):
375
376             for element in self.element_list:
377                 element.draw(drawingarea, y_offset, self.pango_layout)
378
379         elif self.posY > s_s[0].posY and self.posY < e_s[0].posY:
380
381             for element in self.element_list:
382                 element.draw(drawingarea, y_offset, self.pango_layout,
383                              selection=True)
384
385         elif self == s_s[0] and self == e_s[0]:
386
387             selection = False
388
389             for element in self.element_list:
390                 if s_e == element:
391                     selection = True
392                     start = s_i
393                     end = 0xffffff
394                     if e_e == element:
395                         end = e_i
396                         selection = False
397                     element.draw(drawingarea, y_offset, self.pango_layout,
398                                  selection=True,
399                                  start_index=start,
400                                  end_index=end)
401                 elif e_e == element:
402                     end = e_i
403                     selection = False
404                     element.draw(drawingarea, y_offset, self.pango_layout,
405                                  selection=True, end_index=end)
406                 else:
407                     element.draw(drawingarea, y_offset, self.pango_layout,
408                                  selection=selection)
409
410         elif self == s_s[0]:
411
412             selection = False
413
414             for element in self.element_list:
415                 if s_e == element:
416                     selection = True
417                     start = s_i
418                     element.draw(drawingarea, y_offset, self.pango_layout,
419                                  selection=selection, start_index = start)
420                 else:
421                     element.draw(drawingarea, y_offset, self.pango_layout,
422                                  selection=selection)
423
424         elif self == e_s[0]:
425
426             selection = True
427
428             for element in self.element_list:
429                 if e_e == element:
430                     end = e_i
431                     element.draw(drawingarea, y_offset, self.pango_layout,
432                                  selection=selection, end_index=e_i)
433                     selection = False
434                 else:
435                     element.draw(drawingarea, y_offset, self.pango_layout,
436                                  selection=selection)
437
438         else:
439             for element in self.element_list:
440                 element.draw(drawingarea, y_offset, self.pango_layout)
441                 
442
443
444 class ThreadView(gtk.HBox):
445     hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
446     regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
447     arrow_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
448
449     def __init__(self):
450         gtk.HBox.__init__(self, False, 0)
451         self.drawingarea = gtk.DrawingArea()
452         self.vscrollbar = gtk.VScrollbar()
453         self.pack_start(self.drawingarea)
454         self.pack_start(self.vscrollbar, expand=False)
455         self.adjustment  = self.vscrollbar.get_adjustment()
456
457         self.drawingarea.add_events(
458             gtk.gdk.SCROLL_MASK |
459             gtk.gdk.POINTER_MOTION_MASK |
460             gtk.gdk.BUTTON_PRESS_MASK |
461             gtk.gdk.BUTTON_RELEASE_MASK)
462
463         self.drawingarea_prev_width = 0
464
465         self.drawingarea.connect(
466             "expose-event", self.on_drawingarea_expose_event)
467         self.drawingarea.connect(
468             "configure-event", self.on_drawingarea_configure_event)
469         self.drawingarea.connect(
470             "scroll-event", self.on_drawingarea_scroll_event)
471         self.drawingarea.connect(
472             "motion-notify-event", self.on_drawingrarea_motion_notify_event)
473         self.drawingarea.connect(
474             "button-press-event", self.on_drawingarea_button_press_event)
475         self.drawingarea.connect(
476             "button-release-event", self.on_drawingarea_button_release_event)
477         self.vscrollbar.connect(
478             "value-changed", self.on_vscrollbar_value_changed)
479
480         self.pango_layout = self.drawingarea.create_pango_layout("")
481
482         self.initialize_buffer()
483
484         self.on_uri_clicked = self._on_uri_clicked
485
486         self.button1_pressed = False
487         self.current_pressed_uri = None
488             
489         self.popupmenu = None
490         self.menu_openuri = None
491         self.menu_copylinkaddress = None
492         self.menu_separator_link = None
493         self.menu_copyselection = None
494         self.menu_openasuri = None
495         self.menu_separator_selection = None
496
497         self.menud_uri = None
498
499         # for selection
500         self.button_pressed_pt = (None, None, None)
501         self.button_moving_pt = (None, None, None)
502
503     def _on_uri_clicked(self, uri):
504         print uri, "clicked!!!!"
505
506     def initialize_buffer(self):
507         self.res_layout_list = []
508         self.layout_posY_map = [(0, [])]
509
510     def add_layout(self, res_layout):
511         if (len(self.res_layout_list) != 0):
512             last = self.res_layout_list[len(self.res_layout_list)-1]
513             x, y = last.get_pixel_size()
514             res_layout.posY = last.posY + y
515         self.set_layout_width(res_layout)
516         res_layout.list_index = len(self.res_layout_list)
517         self.res_layout_list.append(res_layout)
518
519         if len(self.layout_posY_map[len(self.layout_posY_map)-1][1]) == 128:
520             self.layout_posY_map.append((res_layout.posY, []))
521         self.layout_posY_map[len(self.layout_posY_map)-1][1].append(res_layout)
522
523         x, y = res_layout.get_pixel_size()
524         self.adjustment.upper = res_layout.posY + y
525         self.redraw()
526         self.change_vscrollbar_visible()
527
528     def create_res_layout(self, left_margin, resnum):
529         return ResLayout(left_margin, resnum, self.pango_layout)
530
531     def set_layout_width(self, layout):
532         width = self.drawingarea.allocation.width
533         layout.set_width(width)
534         
535     def redraw(self):
536         self.drawingarea.queue_draw()
537
538     def relayout(self):
539         self.layout_posY_map = [(0, [])]
540
541         width = self.drawingarea.allocation.width
542         sum_height = 0
543         for layout in self.res_layout_list:
544             layout.set_width(width)
545             layout.posY = sum_height
546             x, y = layout.get_pixel_size()
547             sum_height += y
548
549             if len(self.layout_posY_map[len(self.layout_posY_map)-1][1])==128:
550                 self.layout_posY_map.append((layout.posY, []))
551             self.layout_posY_map[len(self.layout_posY_map)-1][1].append(layout)
552
553         self.vscrollbar.set_range(0, sum_height)
554         self.change_vscrollbar_visible()
555
556     def change_vscrollbar_visible(self):
557         if self.adjustment.upper < self.adjustment.page_size:
558             self.vscrollbar.hide()
559         else:
560             self.vscrollbar.show()
561
562     def jump(self, value):
563         self.vscrollbar.set_value(value)
564
565     def jump_to_layout(self, layout):
566         self.jump(layout.posY)
567         
568     def jump_to_the_end(self):
569         value = self.adjustment.upper - self.adjustment.page_size
570         self.vscrollbar.set_value(value)
571
572     def jump_to_res(self, resnum):
573         for layout in self.res_layout_list:
574             if layout.resnum == resnum:
575                 self.jump_to_layout(layout)
576                 return True
577         return False
578
579
580     def _get_selection_start_end(self):
581         pressed_layout, pressed_element, pressed_index = self.button_pressed_pt
582         moving_layout, moving_element, moving_index = self.button_moving_pt
583
584         if (pressed_layout is None or pressed_element is None or
585             pressed_index is None or moving_layout is None or
586             moving_element is None or moving_index is None):
587             return (None, None, None), (None, None, None)
588         
589         if pressed_layout == moving_layout:
590             if pressed_element == moving_element:
591                 if moving_index < pressed_index:
592                     return self.button_moving_pt, self.button_pressed_pt
593             else:
594                 pressed_element_index = pressed_layout.element_list.index(
595                     pressed_element)
596                 moving_element_index = moving_layout.element_list.index(
597                     moving_element)
598                 if moving_element_index < pressed_element_index:
599                     return self.button_moving_pt, self.button_pressed_pt
600         elif moving_layout.posY < pressed_layout.posY:
601             return self.button_moving_pt, self.button_pressed_pt
602
603         return self.button_pressed_pt, self.button_moving_pt
604
605     def draw_viewport(self, area):
606         view_y = self.vscrollbar.get_value()
607         self.drawingarea.window.draw_rectangle(
608             self.drawingarea.style.base_gc[0],
609             True, area.x, area.y, area.width, area.height)
610
611         selection_start, selection_end = self._get_selection_start_end()
612
613
614         top_layout = self.get_layout_on_y(view_y)
615         index = 0
616         if top_layout:
617             index = top_layout.list_index
618         while index < len(self.res_layout_list):
619             layout = self.res_layout_list[index]
620             w, h = layout.get_pixel_size()
621             layout_top = layout.posY
622             layout_bottom = layout.posY + h
623             area_top = view_y + area.y
624             area_bottom = view_y + area.y + area.height
625             if layout_top <= area_bottom and layout_bottom >= area_top:
626                 layout.draw(self.drawingarea,
627                             0, layout.posY - int(view_y),
628                             selection_start, selection_end)
629             if layout_top > area_bottom:
630                 break
631
632             index += 1
633
634     def transform_coordinate_gdk_to_adj(self, y):
635         return y + self.vscrollbar.get_value()
636
637     def transform_coordinate_adj_to_layout(self, x, y, layout):
638         return x, y - layout.posY
639
640     def transform_coordinate_gdk_to_layout(self, x, y, layout):
641         return self.transform_coordinate_adj_to_layout(
642             x, self.transform_coordinate_gdk_to_adj(y), layout)
643
644     def get_layout_on_y(self, y):
645         layout_list = None
646         for pos, lay_lst in self.layout_posY_map:
647             if pos > y:
648                 break
649             layout_list = lay_lst
650         if layout_list:
651             layout = None
652             for lay in layout_list:
653                 if lay.posY > y:
654                     break
655                 layout = lay
656             return layout
657         return None
658
659     def ptrpos_to_layout(self, x, y):
660         # transform coordinate, GdkWindow -> adjustment
661         adj_y = self.transform_coordinate_gdk_to_adj(y)
662         return self.get_layout_on_y(adj_y)
663
664     def ptrpos_to_uri(self,  x, y):
665         # x, y is GdkWindow coordinate
666
667         layout = self.ptrpos_to_layout(x, y)
668
669         if layout is None:
670             return None, None, None
671
672         # transform coordinate, GdkWindow -> res_layout_list
673         lay_x, lay_y = self.transform_coordinate_gdk_to_layout(x, y, layout)
674
675         # xy -> element
676         element = layout.get_element_from_xy(lay_x, lay_y)
677         if isinstance(element, ElementLink):
678             return element.href, layout, element
679
680         return None, layout, None
681
682     def get_selected_text(self):
683         selection_start, selection_end = self._get_selection_start_end()
684         s_l, s_e, s_i = selection_start
685         e_l, e_e, e_i = selection_end
686
687         if (s_l is None or s_e is None or s_i is None or
688             e_l is None or e_e is None or e_i is None):
689             return ""
690
691         text = ""
692         index = s_l.list_index
693         end = e_l.list_index
694
695         while index <= end:
696             layout = self.res_layout_list[index]
697
698             text += layout.get_text(selection_start, selection_end)
699             if index != end:
700                 text += "\n"
701
702             index += 1
703
704         return text
705
706     def _set_button_pressed_pt(self, pt):
707         self.button_pressed_pt = (None, None, None)
708         if pt == None:
709             return
710
711         x, y = pt
712         layout = self.ptrpos_to_layout(x, y)
713         if layout is None:
714             return
715
716         x, y = self.transform_coordinate_gdk_to_layout(x, y, layout)
717         element = layout.get_element_from_xy(x, y)
718         if element is None:
719             element = layout.get_close_element_from_xy(x, y)
720
721         if element is None:
722             return
723
724         index = element.xy_to_index(x, y)
725         if index is None:
726             return
727
728         self.button_pressed_pt = (layout, element, index)
729
730     def _set_button_moving_pt(self, pt):
731         self.button_moving_pt = (None, None, None)
732         if pt == None:
733             return
734
735         x, y = pt
736         layout = self.ptrpos_to_layout(x, y)
737         if layout is None:
738             return
739
740         x, y = self.transform_coordinate_gdk_to_layout(x, y, layout)
741         element = layout.get_element_from_xy(x, y)
742         if element is None:
743             element = layout.get_close_element_from_xy(x, y)
744
745         if element is None:
746             return
747
748         index = element.xy_to_index(x, y)
749         if index is None:
750             return
751
752         self.button_moving_pt = (layout, element, index)
753
754     def on_drawingarea_expose_event(self, widget, event, data=None):
755         self.draw_viewport(event.area)
756
757     def on_drawingarea_configure_event(self, widget, event, data=None):
758         if event.width != self.drawingarea_prev_width:
759
760             # before relayout, find top layout on gdkwindow
761             top_layout = None
762             delta = 0
763             for lay in self.res_layout_list:
764                 if lay.posY > self.adjustment.value:
765                     break
766                 top_layout = lay
767
768             if top_layout is not None:
769                 delta = top_layout.posY - self.vscrollbar.get_value()
770
771             self.relayout()
772             self.drawingarea_prev_width = event.width
773
774             # after relayout, set vscrollbar.value to top layout's posY
775             if top_layout is not None:
776                 self.vscrollbar.set_value(top_layout.posY - delta)
777
778         self.adjustment.page_size = self.drawingarea.allocation.height
779         self.vscrollbar.set_increments(20, self.drawingarea.allocation.height)
780
781         # re-set 'value' for prevent overflow
782         self.vscrollbar.set_value(self.vscrollbar.get_value())
783         self.change_vscrollbar_visible()
784
785     def on_vscrollbar_value_changed(self, widget, data=None):
786         self.drawingarea.queue_draw()
787
788     def on_drawingarea_scroll_event(self, widget, event, data=None):
789         self.vscrollbar.emit("scroll-event", event)
790
791     def on_drawingrarea_motion_notify_event(self, widget, event, data=None):
792         if event.state & gtk.gdk.BUTTON1_MASK != gtk.gdk.BUTTON1_MASK:
793             self.button1_pressed = False
794
795         if self.button1_pressed and self.current_pressed_uri is None:
796             old_lay, old_elem, old_idx = self.button_moving_pt
797             self._set_button_moving_pt((event.x, event.y))
798             new_lay, new_elem, new_idx = self.button_moving_pt
799             if (old_lay != new_lay
800                 or old_elem != new_elem
801                 or old_idx != new_idx):
802                 view_y = self.vscrollbar.get_value()
803                 o_y = old_lay.posY
804                 n_y = new_lay.posY
805                 o_width, o_height = old_lay.get_pixel_size()
806                 n_width, n_height = new_lay.get_pixel_size()
807
808                 y = min(o_y, n_y)
809                 height = max(o_y, n_y) - y
810                 if o_y > n_y: height += o_height
811                 else: height += n_height
812
813                 y -= view_y
814
815                 self.drawingarea.queue_draw_area(0, y, n_width, height+1)
816                 #self.drawingarea.window.process_updates(False)
817
818         cursor = ThreadView.regular_cursor
819
820         uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
821         if layout is None:
822             cursor = ThreadView.arrow_cursor
823         else:
824             if uri is not None and uri != "":
825                 cursor = ThreadView.hand_cursor
826
827         self.drawingarea.window.set_cursor(cursor)
828
829     def on_drawingarea_button_press_event(self, widget, event, data=None):
830         if event.button == 1:
831             self.current_pressed_uri = None
832             self.button1_pressed = True
833             uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
834             if uri is not None and layout is not None and element is not None:
835                 self.current_pressed_uri = (uri, layout, element)
836             else:
837                 self._set_button_moving_pt((event.x, event.y))
838                 self._set_button_pressed_pt((event.x, event.y))
839                 self.drawingarea.queue_draw()
840                 
841         elif event.button == 3:
842             time = event.time
843             uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
844             if uri is not None and layout is not None and element is not None:
845                 self.menu_openuri.show()
846                 self.menu_copylinkaddress.show()
847                 self.menu_separator_link.show()
848                 self.menu_openuri.uri = uri
849                 self.menu_copylinkaddress.uri = uri
850             else:
851                 self.menu_openuri.hide()
852                 self.menu_copylinkaddress.hide()
853                 self.menu_separator_link.hide()
854                 self.menu_openuri.uri = None
855                 self.menu_copylinkaddress.uri = None
856
857             text = self.get_selected_text()
858             if text and len(text) > 0:
859                 self.menu_copyselection.show()
860                 self.menu_openasuri.show()
861                 self.menu_separator_selection.show()
862             else:
863                 self.menu_copyselection.hide()
864                 self.menu_openasuri.hide()
865                 self.menu_separator_selection.hide()
866
867             self.popupmenu.popup(None, None, None, event.button, time)
868             return True
869             
870
871     def on_drawingarea_button_release_event(self, widget, event, data=None):
872         if event.button == 1:
873             button1_pressed = self.button1_pressed
874             self.button1_pressed = False
875
876             if button1_pressed and self.current_pressed_uri is not None:
877                 uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
878                 p_uri, p_layout, p_element = self.current_pressed_uri
879                 self.current_pressed_uri = None
880                 if (uri == p_uri and layout == p_layout and
881                     element == p_element):
882                     self.on_uri_clicked(uri)