OSDN Git Service

Fix: spell miss of commit fbac42a0d137286b9320842ad465a42c6d28397c
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_view.py
index b256795..7228b60 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,7 +34,11 @@ 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
@@ -41,14 +48,36 @@ class ThreadView(gtk.HBox):
         self.drawingarea.connect(
             "size-allocate", self.on_drawingarea_size_allocate)
         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 = []
 
@@ -61,7 +90,9 @@ class ThreadView(gtk.HBox):
         self.pangolayout.append(pangolayout)
         x, y = pangolayout.get_pixel_size()
         self.adjustment.upper = pangolayout.posY + y
+        self.prevent_adjustment_overflow()
         self.redraw()
+        self.change_vscrollbar_visible()
 
     def create_pango_layout(self, text):
         return self.drawingarea.create_pango_layout(text)
@@ -82,6 +113,14 @@ class ThreadView(gtk.HBox):
             x, y = layout.get_pixel_size()
             sum_height += y
         self.adjustment.upper = sum_height
+        self.prevent_adjustment_overflow()
+        self.change_vscrollbar_visible()
+
+    def change_vscrollbar_visible(self):
+        if self.adjustment.upper < self.adjustment.page_size:
+            self.vscrollbar.hide()
+        else:
+            self.vscrollbar.show()
 
     def jump(self, value):
         if value > self.adjustment.upper - self.adjustment.page_size:
@@ -121,6 +160,56 @@ 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.adjustment.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()
 
@@ -131,19 +220,78 @@ class ThreadView(gtk.HBox):
         self.adjustment.page_size = self.drawingarea.allocation.height
         self.adjustment.page_increment = self.drawingarea.allocation.height
 
-    def on_drawingarea_button_press_event(self, widget, event, data=None):
-        self.drawingarea.queue_draw()
+        self.prevent_adjustment_overflow()
+        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)
+
+        if self.adjustment.value < 0:
+            self.adjustment.value = 0
 
     def on_vscrollbar_value_changed(self, widget, data=None):
         self.drawingarea.queue_draw()
 
     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.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):
+        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
+
+            self.menu_copyselection.hide()
+            self.menu_openasuri.hide()
+            self.menu_separator_selection.hide()
+
+            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)