OSDN Git Service

not connect size-allocate on threadview, connect configure-event
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_view.py
index 120bd64..57c1b1b 100644 (file)
@@ -22,6 +22,9 @@ import pango
 
 
 class ThreadView(gtk.HBox):
+    hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
+    regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
+    arrow_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
 
     def __init__(self):
         gtk.HBox.__init__(self, False, 0)
@@ -31,24 +34,49 @@ class ThreadView(gtk.HBox):
         self.pack_start(self.vscrollbar, expand=False)
         self.adjustment  = self.vscrollbar.get_adjustment()
 
-        self.drawingarea.add_events(gtk.gdk.SCROLL_MASK)
+        self.drawingarea.add_events(
+            gtk.gdk.SCROLL_MASK |
+            gtk.gdk.POINTER_MOTION_MASK |
+            gtk.gdk.BUTTON_PRESS_MASK |
+            gtk.gdk.BUTTON_RELEASE_MASK)
 
-        self.adjustment.step_increment = 20
         self.drawingarea_prev_width = 0
 
         self.drawingarea.connect(
             "expose-event", self.on_drawingarea_expose_event)
         self.drawingarea.connect(
-            "size-allocate", self.on_drawingarea_size_allocate)
+            "configure-event", self.on_drawingarea_configure_event)
+        self.drawingarea.connect(
+            "scroll-event", self.on_drawingarea_scroll_event)
+        self.drawingarea.connect(
+            "motion-notify-event", self.on_drawingrarea_motion_notify_event)
         self.drawingarea.connect(
             "button-press-event", self.on_drawingarea_button_press_event)
         self.drawingarea.connect(
-            "scroll-event", self.on_drawingarea_scroll_event)
+            "button-release-event", self.on_drawingarea_button_release_event)
         self.vscrollbar.connect(
             "value-changed", self.on_vscrollbar_value_changed)
 
         self.initialize_buffer()
 
+        self.on_uri_clicked = self._on_uri_clicked
+
+        self.button1_pressed = False
+        self.current_pressed_uri = None
+            
+        self.popupmenu = None
+        self.menu_openuri = None
+        self.menu_copylinkaddress = None
+        self.menu_separator_link = None
+        self.menu_copyselection = None
+        self.menu_openasuri = None
+        self.menu_separator_selection = None
+
+        self.menud_uri = None
+
+    def _on_uri_clicked(self, uri):
+        print uri, "clicked!!!!"
+
     def initialize_buffer(self):
         self.pangolayout = []
 
@@ -60,8 +88,7 @@ class ThreadView(gtk.HBox):
         self.set_layout_width(pangolayout)
         self.pangolayout.append(pangolayout)
         x, y = pangolayout.get_pixel_size()
-        self.adjustment.upper = pangolayout.posY + y
-        self.prevent_adjustment_overflow()
+        self.vscrollbar.set_range(0, pangolayout.posY + y)
         self.redraw()
         self.change_vscrollbar_visible()
 
@@ -83,8 +110,7 @@ class ThreadView(gtk.HBox):
             layout.posY = sum_height
             x, y = layout.get_pixel_size()
             sum_height += y
-        self.adjustment.upper = sum_height
-        self.prevent_adjustment_overflow()
+        self.vscrollbar.set_range(0, sum_height)
         self.change_vscrollbar_visible()
 
     def change_vscrollbar_visible(self):
@@ -94,16 +120,14 @@ class ThreadView(gtk.HBox):
             self.vscrollbar.show()
 
     def jump(self, value):
-        if value > self.adjustment.upper - self.adjustment.page_size:
-            value = self.adjustment.upper - self.adjustment.page_size
-        self.adjustment.set_value(value)
+        self.vscrollbar.set_value(value)
 
     def jump_to_layout(self, layout):
         self.jump(layout.posY)
         
     def jump_to_the_end(self):
         value = self.adjustment.upper - self.adjustment.page_size
-        self.adjustment.set_value(value)
+        self.vscrollbar.set_value(value)
 
     def jump_to_res(self, resnum):
         for layout in self.pangolayout:
@@ -113,7 +137,7 @@ class ThreadView(gtk.HBox):
         return False
 
     def draw_viewport(self):
-        view_y = self.adjustment.get_value()
+        view_y = self.vscrollbar.get_value()
         self.drawingarea.window.draw_rectangle(
             self.drawingarea.style.base_gc[0],
             True, 0, 0,
@@ -131,42 +155,130 @@ class ThreadView(gtk.HBox):
                 self.drawingarea.window.draw_layout(
                     gc, layout.marginleft, layout.posY - int(view_y), layout)
 
+    def transform_coordinate_gdk_to_adj(self, y):
+        return y + self.vscrollbar.get_value()
+
+    def transform_coordinate_adj_to_layout(self, x, y, layout):
+        return x - layout.marginleft, y - layout.posY
+
+    def transform_coordinate_gdk_to_layout(self, x, y, layout):
+        return self.transform_coordinate_adj_to_layout(
+            x, self.transform_coordinate_gdk_to_adj(y), layout)
+
+    def ptrpos_to_layout(self, x, y):
+        # transform coordinate, GdkWindow -> adjustment
+        adj_x = x
+        adj_y = self.transform_coordinate_gdk_to_adj(y)
+        for lay in self.pangolayout:
+            width, height = lay.get_pixel_size()
+            if (adj_y >= lay.posY and adj_y < lay.posY + height and
+                adj_x >= lay.marginleft):
+                return lay
+        return None
+
+    def ptrpos_to_uri(self,  x, y):
+        # x, y is GdkWindow coordinate
+
+        layout = self.ptrpos_to_layout(x, y)
+
+        if layout is None:
+            return None, None, None
+
+        # transform coordinate, GdkWindow -> pangolayout
+        lay_x, lay_y = self.transform_coordinate_gdk_to_layout(x, y, layout)
+
+        # xy -> index
+        idx, clk = layout.xy_to_index(
+            int(lay_x)*pango.SCALE, int(lay_y)*pango.SCALE)
+
+        x, y, width, height = layout.index_to_pos(idx)
+        x /= pango.SCALE
+        y /= pango.SCALE
+        width /= pango.SCALE
+        height /= pango.SCALE
+        if (lay_x >= x and lay_x < x + width and
+            lay_y >= y and lay_y < y + height):
+
+            for i, (start, end, href) in enumerate(layout.urilist):
+                if idx >= start and idx < end:
+                    return href, layout, i
+
+        return None, layout, None
+
     def on_drawingarea_expose_event(self, widget, event, data=None):
         self.draw_viewport()
 
-    def on_drawingarea_size_allocate(self, widget, allocation, data=None):
-        if allocation.width != self.drawingarea_prev_width:
+    def on_drawingarea_configure_event(self, widget, event, data=None):
+        if event.width != self.drawingarea_prev_width:
             self.relayout()
-            self.drawingarea_prev_width = allocation.width
+            self.drawingarea_prev_width = event.width
         self.adjustment.page_size = self.drawingarea.allocation.height
-        self.adjustment.page_increment = self.drawingarea.allocation.height
+        self.vscrollbar.set_increments(20, self.drawingarea.allocation.height)
 
-        self.prevent_adjustment_overflow()
+        # re-set 'value' for prevent overflow
+        self.vscrollbar.set_value(self.vscrollbar.get_value())
         self.change_vscrollbar_visible()
 
-    def prevent_adjustment_overflow(self):
-        if (self.adjustment.value >
-            self.adjustment.upper - self.adjustment.page_size):
-            self.adjustment.value = (self.adjustment.upper -
-                                     self.adjustment.page_size)
+    def on_vscrollbar_value_changed(self, widget, data=None):
+        self.drawingarea.queue_draw()
 
-        if self.adjustment.value < 0:
-            self.adjustment.value = 0
+    def on_drawingarea_scroll_event(self, widget, event, data=None):
+        self.vscrollbar.emit("scroll-event", event)
+
+    def on_drawingrarea_motion_notify_event(self, widget, event, data=None):
+        if event.state & gtk.gdk.BUTTON1_MASK != gtk.gdk.BUTTON1_MASK:
+            self.button1_pressed = False
+
+        cursor = ThreadView.regular_cursor
+
+        uri, layout, index = self.ptrpos_to_uri(event.x, event.y)
+        if layout is None:
+            cursor = ThreadView.arrow_cursor
+        else:
+            if uri is not None and uri != "":
+                cursor = ThreadView.hand_cursor
+
+        self.drawingarea.window.set_cursor(cursor)
 
     def on_drawingarea_button_press_event(self, widget, event, data=None):
-        self.drawingarea.queue_draw()
+        if event.button == 1:
+            self.current_pressed_uri = None
+            self.button1_pressed = True
+            uri, layout, index = self.ptrpos_to_uri(event.x, event.y)
+            if uri is not None and layout is not None and index is not None:
+                self.current_pressed_uri = (uri, layout, index)
+        elif event.button == 3:
+            time = event.time
+            uri, layout, index = self.ptrpos_to_uri(event.x, event.y)
+            if uri is not None and layout is not None and index is not None:
+                self.menu_openuri.show()
+                self.menu_copylinkaddress.show()
+                self.menu_separator_link.show()
+                self.menu_openuri.uri = uri
+                self.menu_copylinkaddress.uri = uri
+            else:
+                self.menu_openuri.hide()
+                self.menu_copylinkaddress.hide()
+                self.menu_separator_link.hide()
+                self.menu_openuri.uri = None
+                self.menu_copylinkaddress.uri = None
 
-    def on_vscrollbar_value_changed(self, widget, data=None):
-        self.drawingarea.queue_draw()
+            self.menu_copyselection.hide()
+            self.menu_openasuri.hide()
+            self.menu_separator_selection.hide()
 
-    def on_drawingarea_scroll_event(self, widget, event, data=None):
-        if event.direction == gtk.gdk.SCROLL_UP:
-            self.adjustment.value -= 66.476200804
-            if self.adjustment.value < self.adjustment.lower:
-                self.adjustment.value = self.adjustment.lower
-        if event.direction == gtk.gdk.SCROLL_DOWN:
-            self.adjustment.value += 66.476200804
-            max_value = self.adjustment.upper - self.adjustment.page_size
-            if self.adjustment.value > max_value:
-                self.adjustment.value = max_value
-        self.prevent_adjustment_overflow()
+            self.popupmenu.popup(None, None, None, event.button, time)
+            return True
+            
+
+    def on_drawingarea_button_release_event(self, widget, event, data=None):
+        if event.button == 1:
+            button1_pressed = self.button1_pressed
+            self.button1_pressed = False
+
+            if button1_pressed and self.current_pressed_uri is not None:
+                uri, layout, index = self.ptrpos_to_uri(event.x, event.y)
+                p_uri, p_layout, p_index = self.current_pressed_uri
+                self.current_preesed_uri = None
+                if uri == p_uri and layout == p_layout and index == p_index:
+                    self.on_uri_clicked(uri)