X-Git-Url: http://git.sourceforge.jp/view?p=fukui-no-namari%2Ffukui-no-namari.git;a=blobdiff_plain;f=src%2FFukuiNoNamari%2Fthread_view.py;h=d7b0b432d43b33be0d83c624dacacbd60daa9a73;hp=23f151a6cd8b52938f529c92df8bf4b8f28df8c9;hb=9ac09b5d8aba300c495f4e50faf452566e439180;hpb=b8349ab8107af1c480c5e7de4301f51457da4576 diff --git a/src/FukuiNoNamari/thread_view.py b/src/FukuiNoNamari/thread_view.py index 23f151a..d7b0b43 100644 --- a/src/FukuiNoNamari/thread_view.py +++ b/src/FukuiNoNamari/thread_view.py @@ -19,6 +19,8 @@ import pygtk pygtk.require('2.0') import gtk import pango +import gobject +import itertools from FukuiNoNamariExt import thread_view_extend @@ -29,6 +31,14 @@ def get_approximate_char_height(pango_context): return log[3] / pango.SCALE + 2 +class Rectangle: + def __init__(self, x, y, width, height): + self.x = x + self.y = y + self.width = width + self.height = height + + class Line: HEIGHT = 15 @@ -70,7 +80,7 @@ class ElementEmpty: def build_line_list(self, x, y, width, left_margin): self.initialize() - line = Line(0, 0, gtk.gdk.Rectangle( + line = Line(0, 0, Rectangle( x, y, width - x, get_approximate_char_height(self.pango_layout.get_context()))) self.line_list.append(line) @@ -87,20 +97,38 @@ class ElementEmpty: class ElementText: + ch_width_dict = {} # key: char, value: width + def __init__(self, text, pango_layout): self.text = text self.pango_layout = pango_layout - attrlist = self._get_attrs() - self.widths = thread_view_extend.get_char_width( - pango_layout.get_context(), text, attrlist) + self.recalc_char_widths() self.line_list = [] def recalc_char_widths(self): - attrlist = self._get_attrs() - self.widths = thread_view_extend.get_char_width( - self.pango_layout.get_context(), self.text, attrlist) + self.widths = [i for i in itertools.repeat(0, len(self.text))] + + dict = self._get_ch_width_dict() + need_to_get = False + for index, ch in enumerate(self.text): + if ch not in dict: + need_to_get = True + break + else: + width = dict[ch] + self.widths[index] = width + + if need_to_get: + attrlist = self._get_attrs() + self.widths = thread_view_extend.get_char_width( + self.pango_layout.get_context(), self.text, attrlist) + for index, width in enumerate(self.widths): + dict[self.text[index]] = self.widths[index] + + def _get_ch_width_dict(self): + return ElementText.ch_width_dict def _get_attrs(self): attrs = pango.AttrList() @@ -141,7 +169,7 @@ class ElementText: if current_line_x + current_line_width + ch_w > width: line = Line( current_line_start_index, index, - gtk.gdk.Rectangle( + Rectangle( current_line_x, current_line_y, current_line_width, ch_h)) self.line_list.append(line) @@ -155,7 +183,7 @@ class ElementText: if current_line_start_index < len(self.text): line = Line(current_line_start_index, len(self.text), - gtk.gdk.Rectangle(current_line_x, + Rectangle(current_line_x, current_line_y, current_line_width, ch_h)) @@ -190,14 +218,20 @@ class ElementText: def draw(self, drawingarea, y_offset, pango_layout, selection=False, start_index=0, end_index=0xffffff): - selection_fg = drawingarea.style.fg[3] - selection_bg = drawingarea.style.bg[3] + if drawingarea.get_property("has-focus"): + selection_fg = drawingarea.style.text[gtk.STATE_SELECTED] + selection_bg = drawingarea.style.base[gtk.STATE_SELECTED] + else: + selection_fg = drawingarea.style.text[gtk.STATE_ACTIVE] + selection_bg = drawingarea.style.base[gtk.STATE_ACTIVE] for line in self.line_list: text = self.text[line.start_index:line.end_index] u_text = text.encode("utf8") gc = drawingarea.window.new_gc() + gc.set_foreground(drawingarea.style.text[gtk.STATE_NORMAL]) + gc.set_background(drawingarea.style.base[gtk.STATE_NORMAL]) attrs = self._get_attrs() if selection: @@ -223,7 +257,7 @@ class ElementText: pango_layout.set_text(u_text) pango_layout.set_attributes(attrs) drawingarea.window.draw_layout( - gc, line.rectangle.x, line.rectangle.y + y_offset, + gc, int(line.rectangle.x), line.rectangle.y + y_offset, pango_layout) @@ -236,6 +270,11 @@ class ElementBoldText(ElementText): attrlist.insert(attr) return attrlist + def recalc_char_widths(self): + attrlist = self._get_attrs() + self.widths = thread_view_extend.get_char_width( + self.pango_layout.get_context(), self.text, attrlist) + class ElementLink(ElementText): @@ -462,10 +501,24 @@ class ResLayout: else: for element in self.element_list: element.draw(drawingarea, y_offset, self.pango_layout) - + + def clone(self): + import copy + layout = ResLayout(self.left_margin, self.resnum, self.pango_layout) + layout.element_list = [] + for element in self.element_list: + layout.element_list.append(copy.copy(element)) + return layout class ThreadView(gtk.HBox): + __gsignals__ = { + "cursor-over-link-event": + (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, object, )), + "uri-clicked-event": + (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, )) + } + 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) @@ -473,12 +526,15 @@ class ThreadView(gtk.HBox): def __init__(self): gtk.HBox.__init__(self, False, 0) self.drawingarea = gtk.DrawingArea() + self.drawingarea.set_property("can_focus", True) + 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 +556,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) @@ -507,8 +565,6 @@ class ThreadView(gtk.HBox): self.initialize_buffer() - self.on_uri_clicked = self._on_uri_clicked - self.button1_pressed = False self.current_pressed_uri = None @@ -526,9 +582,6 @@ class ThreadView(gtk.HBox): self.button_pressed_pt = (None, None, None) self.button_moving_pt = (None, None, None) - def _on_uri_clicked(self, uri): - print uri, "clicked!!!!" - def initialize_buffer(self): self.res_layout_list = [] @@ -585,7 +638,7 @@ class ThreadView(gtk.HBox): self.change_vscrollbar_visible() def change_vscrollbar_visible(self): - if self.adjustment.upper < self.adjustment.page_size: + if self.adjustment.upper <= self.adjustment.page_size: self.vscrollbar.hide() else: self.vscrollbar.show() @@ -641,26 +694,18 @@ class ThreadView(gtk.HBox): selection_start, selection_end = self._get_selection_start_end() - top_layout = self.get_layout_on_y(view_y) - index = 0 - if top_layout: - index = top_layout.list_index - while index < len(self.res_layout_list): - layout = self.res_layout_list[index] - w, h = layout.get_pixel_size() - layout_top = layout.posY - layout_bottom = layout.posY + h - area_top = view_y + area.y - area_bottom = view_y + area.y + area.height - if layout_top <= area_bottom and layout_bottom >= area_top: - layout.draw(self.drawingarea, - 0, layout.posY - int(view_y), - selection_start, selection_end) - if layout_top > area_bottom: - break + if top_layout is None: + return + #area_top = view_y + area.y + area_bottom = view_y + area.y + area.height - index += 1 + iter = range(top_layout.list_index, len(self.res_layout_list)) + iter = itertools.imap(lambda index: self.res_layout_list[index], iter) + iter = itertools.takewhile(lambda lay: lay.posY <= area_bottom, iter) + for layout in iter: + layout.draw(self.drawingarea, 0, layout.posY - int(view_y), + selection_start, selection_end) def transform_coordinate_gdk_to_adj(self, y): return y + self.vscrollbar.get_value() @@ -855,6 +900,7 @@ class ThreadView(gtk.HBox): else: if uri is not None and uri != "": cursor = ThreadView.hand_cursor + self.emit("cursor-over-link-event", event, uri) self.drawingarea.window.set_cursor(cursor) @@ -911,7 +957,7 @@ class ThreadView(gtk.HBox): self.current_pressed_uri = None if (uri == p_uri and layout == p_layout and element == p_element): - self.on_uri_clicked(uri) + self.emit("uri-clicked-event", uri) def on_drawingarea_style_set(self, widget, previous_style, data=None): if previous_style is None: @@ -923,3 +969,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()