OSDN Git Service

key press events (up, down, page up, page down, home, end) are handled
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / thread_view.py
index 6323435..bdb4804 100644 (file)
@@ -19,6 +19,7 @@ import pygtk
 pygtk.require('2.0')
 import gtk
 import pango
+import gobject
 from FukuiNoNamariExt import thread_view_extend
 
 
@@ -473,12 +474,21 @@ class ThreadView(gtk.HBox):
     def __init__(self):
         gtk.HBox.__init__(self, False, 0)
         self.drawingarea = gtk.DrawingArea()
+        self.drawingarea.set_property("can_focus", True)
+
+        def set_focus():
+            top = self.drawingarea.get_toplevel()
+            if top.get_property("type") == gtk.WINDOW_TOPLEVEL:
+                top.set_focus(self.drawingarea)
+        gobject.idle_add(set_focus)
+
         self.vscrollbar = gtk.VScrollbar()
         self.pack_start(self.drawingarea)
         self.pack_start(self.vscrollbar, expand=False)
         self.adjustment  = self.vscrollbar.get_adjustment()
 
         self.drawingarea.add_events(
+            gtk.gdk.KEY_PRESS_MASK |
             gtk.gdk.SCROLL_MASK |
             gtk.gdk.POINTER_MOTION_MASK |
             gtk.gdk.BUTTON_PRESS_MASK |
@@ -500,6 +510,8 @@ class ThreadView(gtk.HBox):
             "button-release-event", self.on_drawingarea_button_release_event)
         self.drawingarea.connect(
             "style-set", self.on_drawingarea_style_set)
+        self.drawingarea.connect(
+            "key-press-event", self.on_drawingarea_key_press_event)
         self.vscrollbar.connect(
             "value-changed", self.on_vscrollbar_value_changed)
 
@@ -531,7 +543,6 @@ class ThreadView(gtk.HBox):
 
     def initialize_buffer(self):
         self.res_layout_list = []
-        self.layout_posY_map = [(0, [])]
 
     def add_layout(self, res_layout):
         if (len(self.res_layout_list) != 0):
@@ -542,13 +553,10 @@ class ThreadView(gtk.HBox):
         res_layout.list_index = len(self.res_layout_list)
         self.res_layout_list.append(res_layout)
 
-        if len(self.layout_posY_map[len(self.layout_posY_map)-1][1]) == 128:
-            self.layout_posY_map.append((res_layout.posY, []))
-        self.layout_posY_map[len(self.layout_posY_map)-1][1].append(res_layout)
-
         x, y = res_layout.get_pixel_size()
         self.adjustment.upper = res_layout.posY + y
-        self.redraw()
+        # do not use this method in a loop because expensive.
+        # self.redraw()
         self.change_vscrollbar_visible()
 
     def create_res_layout(self, left_margin, resnum):
@@ -577,8 +585,6 @@ class ThreadView(gtk.HBox):
             self.vscrollbar.set_value(top_layout.posY - delta)
 
     def relayout(self):
-        self.layout_posY_map = [(0, [])]
-
         width = self.drawingarea.allocation.width
         sum_height = 0
         for layout in self.res_layout_list:
@@ -587,10 +593,6 @@ class ThreadView(gtk.HBox):
             x, y = layout.get_pixel_size()
             sum_height += y
 
-            if len(self.layout_posY_map[len(self.layout_posY_map)-1][1])==128:
-                self.layout_posY_map.append((layout.posY, []))
-            self.layout_posY_map[len(self.layout_posY_map)-1][1].append(layout)
-
         self.vscrollbar.set_range(0, sum_height)
         self.change_vscrollbar_visible()
 
@@ -683,18 +685,36 @@ class ThreadView(gtk.HBox):
             x, self.transform_coordinate_gdk_to_adj(y), layout)
 
     def get_layout_on_y(self, y):
-        layout_list = None
-        for pos, lay_lst in self.layout_posY_map:
-            if pos > y:
-                break
-            layout_list = lay_lst
-        if layout_list:
-            layout = None
-            for lay in layout_list:
-                if lay.posY > y:
-                    break
-                layout = lay
-            return layout
+
+        def binary_search(lst, start, end, func):
+
+            if end - start <= 0:
+                return None
+
+            m = (start + end) / 2
+            ret = func(lst[m])
+
+            if ret == 0:
+                return m
+            if ret > 0:
+                return binary_search(lst, start, m, func)
+            return binary_search(lst, m+1, end, func)
+
+        def on_y(layout, _y):
+            top = layout.posY
+            width, height = layout.get_pixel_size()
+            bottom = top + height
+            if _y >= top and _y < bottom:
+                return 0
+            if _y < top:
+                return 1
+            return -1
+
+        ret = binary_search(
+            self.res_layout_list, 0, len(self.res_layout_list),
+            lambda x: on_y(x, y))
+        if ret is not None:
+            return self.res_layout_list[ret]
         return None
 
     def ptrpos_to_layout(self, x, y):
@@ -915,3 +935,29 @@ class ThreadView(gtk.HBox):
             for layout in self.res_layout_list:
                 layout.recalc_char_widths()
             self.wrap_relayout()
+
+    def on_drawingarea_key_press_event(self, widget, event, data=None):
+        if event.type is not gtk.gdk.KEY_PRESS:
+            return
+
+        if event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down,
+                            gtk.keysyms.Page_Up, gtk.keysyms.Page_Down,
+                            gtk.keysyms.Home):
+            value = self.vscrollbar.get_value()
+            if event.keyval == gtk.keysyms.Up:
+                step_increment = self.adjustment.get_property("step-increment")
+                value = value - step_increment
+            elif event.keyval == gtk.keysyms.Down:
+                step_increment = self.adjustment.get_property("step-increment")
+                value = value + step_increment
+            elif event.keyval == gtk.keysyms.Page_Up:
+                step_increment = self.adjustment.get_property("page-increment")
+                value = value - step_increment
+            elif event.keyval == gtk.keysyms.Page_Down:
+                step_increment = self.adjustment.get_property("page-increment")
+                value = value + step_increment
+            elif event.keyval == gtk.keysyms.Home:
+                value = 0
+            self.jump(value)
+        elif event.keyval == gtk.keysyms.End:
+            self.jump_to_the_end()