From 26f16aa26b7ae0b3b276729412a77236534996a2 Mon Sep 17 00:00:00 2001 From: Aiwota Programmer Date: Sat, 8 Dec 2007 16:18:38 +0900 Subject: [PATCH] replace GtkTextView with DrawingArea. --- src/FukuiNoNamari/thread_window.py | 289 +++++---------- src/data/thread_window.glade | 707 ++++++++++++++++--------------------- 2 files changed, 395 insertions(+), 601 deletions(-) diff --git a/src/FukuiNoNamari/thread_window.py b/src/FukuiNoNamari/thread_window.py index 9d38f86..d40bd1c 100644 --- a/src/FukuiNoNamari/thread_window.py +++ b/src/FukuiNoNamari/thread_window.py @@ -82,7 +82,39 @@ class WinWrap(winwrapbase.WinWrapBase): regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM) + def relayout(self): + width = self.drawingarea.allocation.width + sum_height = 0 + for layout in self.pangolayout: + layout.set_width(width * pango.SCALE) + layout.posY = sum_height + x, y = layout.get_pixel_size() + sum_height += y + self.drawingarea.set_size_request(-1, sum_height) + + def draw_viewport(self, area): + gc = self.drawingarea.window.new_gc() + self.drawingarea.window.draw_rectangle( + self.drawingarea.style.base_gc[0], + True, area.x, area.y, area.width, area.height) + + for layout in self.pangolayout: + w, h = layout.get_pixel_size() + if ((layout.posY >= area.y and + layout.posY < area.y + area.height) or + (layout.posY + h >= area.y and + layout.posY + h < area.y + area.height) or + (layout.posY <= area.y and layout.posY + h >= area.y)): + self.drawingarea.window.draw_layout(gc, 0, layout.posY, layout) + + def on_drawingarea_expose_event(self, widget, event, data=None): + self.relayout() + self.draw_viewport(event.area) + return True + def __init__(self, uri): + self.pangolayout = [] + from BbsType import bbs_type_judge_uri from BbsType import bbs_type_exception self.bbs_type = bbs_type_judge_uri.get_type(uri) @@ -101,14 +133,12 @@ class WinWrap(winwrapbase.WinWrapBase): self.window = self.widget_tree.get_widget("thread_window") self.toolbar = self.widget_tree.get_widget("toolbar") self.toolbar.unset_style() - self.statusbar = self.widget_tree.get_widget("appbar") - self.textview = self.widget_tree.get_widget("textview") - self.textview.drag_dest_unset() + self.statusbar = self.widget_tree.get_widget("statusbar") + self.drawingarea = self.widget_tree.get_widget("drawingarea") + self.viewport = self.drawingarea.parent self.initialize_buffer() - self.hint = HintWrap() - sigdic = {"on_refresh_activate": self.update, "on_compose_activate": self.on_compose_clicked, "on_toolbar_activate": self.on_toolbar_activate, @@ -118,6 +148,7 @@ class WinWrap(winwrapbase.WinWrapBase): "on_quit_activate": self.on_quit_activate, "on_show_board_activate": self.on_show_board_activate, "on_delete_activate": self.on_delete_activate, + "on_drawingarea_expose_event": self.on_drawingarea_expose_event, "on_thread_window_delete_event": self.on_thread_window_delete_event, "on_add_bookmark_activate": self.on_add_bookmark_activate, @@ -126,24 +157,21 @@ class WinWrap(winwrapbase.WinWrapBase): "on_thread_window_destroy": self.on_thread_window_destroy} self.widget_tree.signal_autoconnect(sigdic) - self.textview.connect("event-after", self.on_event_after) - self.textview.connect("motion-notify-event", - self.on_motion_notify_event) - self.textview.connect("visibility-notify-event", - self.on_visibility_notify_event) self.restore() - self.window.show() + self.window.show_all() self.created() def initialize_buffer(self): self.textbuffer = gtk.TextBuffer() - self.textview.set_buffer(self.textbuffer) + self.enditer = self.textbuffer.get_end_iter() self.boldtag = self.textbuffer.create_tag(weight=pango.WEIGHT_BOLD) self.leftmargintag = self.textbuffer.create_tag() self.leftmargintag.set_property("left-margin", 20) + + def destroy(self): self.save() self.window.destroy() @@ -156,10 +184,10 @@ class WinWrap(winwrapbase.WinWrapBase): submit_window.open(self.bbs_type.get_thread_uri()) def on_toolbar_activate(self, widget): - if self.toolbar.parent.get_property("visible"): - self.toolbar.parent.hide() + if self.toolbar.get_property("visible"): + self.toolbar.hide() else: - self.toolbar.parent.show() + self.toolbar.show() def on_statusbar_activate(self, widget): if self.statusbar.get_property("visible"): @@ -167,116 +195,6 @@ class WinWrap(winwrapbase.WinWrapBase): else: self.statusbar.show() - def on_event_after(self, widget, event): - if event.type != gtk.gdk.BUTTON_RELEASE: - return False - if event.button != 1: - return False - buffer = widget.get_buffer() - - try: - start, end = buffer.get_selection_bounds() - except ValueError: - pass - else: - if start.get_offset() != end.get_offset(): - return False - - x, y = widget.window_to_buffer_coords( - gtk.TEXT_WINDOW_WIDGET, int (event.x), int(event.y)) - iter = widget.get_iter_at_location(x, y) - if not iter.has_tag(self.leftmargintag) or x > 20: - tags = iter.get_tags() - for tag in tags: - href = tag.get_data("href") - if href: - self.on_link_clicked(widget, href) - return False - - def on_link_clicked(self, widget, href): - - if not href.startswith("http://"): - # maybe a relative uri. - href = urlparse.urljoin(self.bbs_type.get_uri_base(), href) - - try: - uri_opener.open_uri(href) - except bbs_type_exception.BbsTypeError: - # not supported, show with the web browser. - gnome.url_show(href) - - def on_motion_notify_event(self, widget, event): - x, y = widget.window_to_buffer_coords( - gtk.TEXT_WINDOW_WIDGET, int(event.x), int(event.y)) - self.set_cursor_if_appropriate(widget, x, y) - widget.window.get_pointer() - return False - - def on_visibility_notify_event(self, widget, event): - wx, wy, mod = widget.window.get_pointer() - bx, by = widget.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy) - - self.set_cursor_if_appropriate(widget, bx, by) - return False - - def set_cursor_if_appropriate(self, widget, x, y): - hovering = False - href = "" - - buffer = widget.get_buffer() - iter = widget.get_iter_at_location(x, y) - if not iter.has_tag(self.leftmargintag) or x > 20: - tags = iter.get_tags() - for tag in tags: - href = tag.get_data("href") - if href: - hovering = True - - if hovering != self.hovering_over_link: - self.hovering_over_link = hovering - - if self.hovering_over_link: - widget.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor( - self.hand_cursor) - if href: - if not href.startswith("http://"): - href = urlparse.urljoin(self.bbs_type.get_uri_base(), href) - - strict_uri = self.bbs_type.get_thread_uri() - if href != strict_uri and href.startswith(strict_uri): - resnum = href[len(strict_uri):] - match = re.match("\d+", resnum) - if match: - resnum = int(match.group()) - if not self.hint.visible(resnum): - mark = self.textbuffer.get_mark(str(resnum)) - n_mark = self.textbuffer.get_mark(str(resnum+1)) - if mark and n_mark: - iter = self.textbuffer.get_iter_at_mark(mark) - n_iter = self.textbuffer.get_iter_at_mark( - n_mark) - text = self.textbuffer.get_text( - iter, n_iter, False) - if text: - iter = self.textview.get_iter_at_location( - x, y) - rect = self.textview.get_iter_location( - iter) - x, y = \ - self.textview.buffer_to_window_coords( - gtk.TEXT_WINDOW_WIDGET, rect.x, rect.y) - x, y = self.textview.translate_coordinates( - self.window, x, y) - wx, wy = self.window.get_position() - x += wx - y += wy - y += rect.height - self.hint.show(x, y, text, resnum) - else: - widget.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor( - self.regular_cursor) - self.hint.destroy() - def on_close_activate(self, widget): self.destroy() @@ -339,12 +257,13 @@ class WinWrap(winwrapbase.WinWrapBase): try: res = opener.open(req) except urllib2.HTTPError, e: - gobject.idle_add( - self.statusbar.set_status, "%d %s" % (e.code, e.msg)) + pass +# gobject.idle_add( +# lambda x: self.statusbar.push(0, x), "%d %s" % (e.code, e.msg)) else: headers = res.info() - gobject.idle_add( - self.statusbar.set_status, "%d %s" % (res.code, res.msg)) +# gobject.idle_add( +# lambda x: self.statusbar.push(0, x), "%d %s" % (res.code, res.msg)) maybe_incomplete = False for line in res: @@ -402,9 +321,9 @@ class WinWrap(winwrapbase.WinWrapBase): num = self.jump_request_num self.jump_request_num = 0 mark = self.textbuffer.get_mark(str(num)) - if mark: - self.textview.scroll_to_mark( - mark, 0, True, 0, 0) +# if mark: +# self.textview.scroll_to_mark( +# mark, 0, True, 0, 0) else: self.jump_to_the_end(num) @@ -427,8 +346,8 @@ class WinWrap(winwrapbase.WinWrapBase): num = self.jump_request_num self.jump_request_num = 0 mark = self.textbuffer.get_mark(str(num)) - if mark: - self.textview.scroll_to_mark(mark, 0, True, 0, 0) +# if mark: +# self.textview.scroll_to_mark(mark, 0, True, 0, 0) gobject.idle_add(do_jump) @@ -462,8 +381,8 @@ class WinWrap(winwrapbase.WinWrapBase): num = self.jump_request_num self.jump_request_num = 0 mark = self.textbuffer.get_mark(str(num)) - if mark: - self.textview.scroll_to_mark(mark, 0, True, 0, 0) +# if mark: +# self.textview.scroll_to_mark(mark, 0, True, 0, 0) else: self.jump_to_the_end(num) @@ -522,7 +441,7 @@ class WinWrap(winwrapbase.WinWrapBase): def process_res_queue(res_queue, num): self.process_queue(res_queue) # for next res - self.textbuffer.create_mark(str(num+1), self.enditer, True) + #self.textbuffer.create_mark(str(num+1), self.enditer, True) gobject.idle_add( process_res_queue, self.res_queue, self.num) @@ -556,24 +475,31 @@ class WinWrap(winwrapbase.WinWrapBase): return tag def process_queue(self, queue): + text = "" for data, bold, href, margin in queue: - taglist = [] - if bold: - taglist.append(self.boldtag) - if href: - taglist.append(self.href_tag(href)) - if margin: - taglist.append(self.leftmargintag) - - if taglist: - self.textbuffer.insert_with_tags(self.enditer, data, *taglist) - else: - self.textbuffer.insert(self.enditer, data) + text += data + layout = self.drawingarea.create_pango_layout(text) + layout.set_wrap(pango.WRAP_CHAR) + layout.posY = 0 + self.pangolayout.append(layout) + self.relayout() +# taglist = [] +# if bold: +# taglist.append(self.boldtag) +# if href: +# taglist.append(self.href_tag(href)) +# if margin: +# taglist.append(self.leftmargintag) +# +# if taglist: +# self.textbuffer.insert_with_tags(self.enditer, data, *taglist) +# else: +# self.textbuffer.insert(self.enditer, data) def jump_to_the_end(self, num): mark = self.textbuffer.get_mark(str(num+1)) - if mark: - self.textview.scroll_to_mark(mark, 0) +# if mark: +# self.textview.scroll_to_mark(mark, 0) def lock(self): if self.lock_obj: @@ -596,11 +522,11 @@ class WinWrap(winwrapbase.WinWrapBase): if match: resnum = match.group() mark = self.textbuffer.get_mark(resnum) - if mark: - self.textview.scroll_to_mark(mark, 0, True, 0, 0) - elif self.progress: - # try later. - self.jump_request_num = int(resnum) +# if mark: +# self.textview.scroll_to_mark(mark, 0, True, 0, 0) +# elif self.progress: +# # try later. +# self.jump_request_num = int(resnum) def load(self, update=False): dat_path = misc.get_thread_dat_path(self.bbs_type) @@ -618,7 +544,7 @@ class WinWrap(winwrapbase.WinWrapBase): # save only if dat file exists. if os.path.exists(dat_path): window_width, window_height = self.window.get_size() - toolbar_visible = self.toolbar.parent.get_property("visible") + toolbar_visible = self.toolbar.get_property("visible") statusbar_visible = self.statusbar.get_property("visible") dirname = os.path.dirname(states_path) @@ -690,57 +616,10 @@ class WinWrap(winwrapbase.WinWrapBase): self.window.set_default_size(window_width, window_height) if not toolbar_visible: - gobject.idle_add(self.toolbar.parent.hide, + gobject.idle_add(self.toolbar.hide, priority=gobject.PRIORITY_HIGH) if not statusbar_visible: gobject.idle_add(self.statusbar.hide, priority=gobject.PRIORITY_HIGH) except: traceback.print_exc() - - -class HintWrap: - - def __init__(self): - self.window = None - self.textview = None - self.nums = None - - def __del__(self): - print "destruct" - self.destroy() - - def destroy(self): - if self.window: - self.window.destroy() - self.window = None - self.textview = None - self.nums = None - - def show(self, x, y, text, *nums): - self.destroy() - - self.window = gtk.Window(gtk.WINDOW_POPUP) - self.window.set_default_size(400, 10) - self.window.move(x, y) - - self.textview = gtk.TextView() - self.window.add(self.textview) - - self.textview.set_wrap_mode(gtk.WRAP_CHAR) - self.textview.set_editable(False) - - buffer = self.textview.get_buffer() - buffer.set_text(text.rstrip()) - self.nums = nums - - self.window.show_all() - - def visible(self, *nums): - if not self.nums or len(self.nums) != len(nums): - return False - - for num, mun in itertools.izip(self.nums, nums): - if num != mun: - return False - return True diff --git a/src/data/thread_window.glade b/src/data/thread_window.glade index 5d6702a..9d34a2e 100644 --- a/src/data/thread_window.glade +++ b/src/data/thread_window.glade @@ -1,398 +1,313 @@ - - - + + + - - - - - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - 600 - 600 - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - - - - - - True - True - - - - True - GTK_SHADOW_NONE - - - - True - - - - True - GNOMEUIINFO_MENU_FILE_TREE - - - - - - - True - Show Board - True - - - - - True - gtk-go-up - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _Compose Message - True - - - - - - True - gnome-stock-mail-new - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - _Delete Log - True - - - - - True - gtk-delete - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - GNOMEUIINFO_MENU_CLOSE_ITEM - - - - - - - True - - - - - - True - GNOMEUIINFO_MENU_EXIT_ITEM - - - - - - - - - - - True - GNOMEUIINFO_MENU_EDIT_TREE - - - - - - True - GNOMEUIINFO_MENU_VIEW_TREE - - - - - - - True - _Refresh - True - - - - - - True - gtk-refresh - 1 - 0.5 - 0.5 - 0 - 0 - - - - - - - - True - - - - - - True - _Toolbar - True - - - - - - - True - _Statusbar - True - - - - - - - - - - - True - _Bookmarks - True - - - - - - - True - Bookmark This Page - True - - - - - - - True - Show Bookmarks - True - - - - - - - - - - - True - GNOMEUIINFO_MENU_HELP_TREE - - - - - - - BONOBO_DOCK_TOP - 0 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE|BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL|BONOBO_DOCK_ITEM_BEH_LOCKED - - - - - - True - GTK_SHADOW_OUT - - - - True - GTK_ORIENTATION_HORIZONTAL - GTK_TOOLBAR_BOTH - True - True - - - - True - gtk-refresh - True - True - False - - - - False - True - - - - - - True - Board - True - gtk-go-up - True - True - False - - - - False - True - - - - - - True - Compose - True - gnome-stock-mail-new - True - True - False - - - - False - True - - - - - - True - gtk-delete - True - True - False - - - - False - True - - - - - - - BONOBO_DOCK_TOP - 1 - 0 - 0 - BONOBO_DOCK_ITEM_BEH_EXCLUSIVE|BONOBO_DOCK_ITEM_BEH_LOCKED - - - - - - True - True - GTK_POLICY_AUTOMATIC - GTK_POLICY_AUTOMATIC - GTK_SHADOW_NONE - GTK_CORNER_TOP_LEFT - - - - True - True - True - False - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_CHAR - False - 0 - 0 - 0 - 0 - 0 - 0 - - - - - - - - 0 - True - True - - - - - - True - True - True - - - 0 - True - True - - - - + + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _File + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Show Board + True + + + + gtk-go-up + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Compose Message + True + + + + + gtk-edit + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-delete + True + True + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-close + True + True + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-quit + True + True + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Edit + True + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _View + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-refresh + True + True + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Toolbar + True + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Statusbar + True + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Bookmarks + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + Bookmark This Page + True + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Show Bookmarks + True + + + + + + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + _Help + True + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + gtk-about + True + True + + + + + + + + + False + + + + + True + GTK_TOOLBAR_BOTH + + + True + gtk-refresh + + + + False + + + + + True + Board + True + gtk-go-up + + + + False + + + + + True + Compose + True + gnome-stock-mail-new + + + + False + + + + + True + gtk-delete + + + + False + + + + + False + 1 + + + + + True + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + GTK_RESIZE_QUEUE + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + + + + + + + + 2 + + + + + True + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK + 2 + + + False + 3 + + + + + -- 2.11.0