1 # Copyright (C) 2007 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 from FukuiNoNamariExt import thread_view_extend
27 def get_approximate_char_height(pango_context):
28 desc = pango_context.get_font_description()
29 font = pango_context.load_font(desc)
30 ink, log = font.get_glyph_extents(0)
31 return log[3] / pango.SCALE + 2
35 def __init__(self, x, y, width, height):
46 def __init__(self, start_index, end_index, rectangle):
47 self.start_index = start_index
48 self.end_index = end_index
49 self.rectangle = rectangle
51 def is_on_xy(self, x, y):
52 left = self.rectangle.x
53 right = left + self.rectangle.width
54 top = self.rectangle.y
55 bottom = top + self.rectangle.height
56 return x >= left and x < right and y >= top and y < bottom
61 def __init__(self, pango_layout):
62 self.pango_layout = pango_layout
65 def recalc_char_widths(self):
71 def is_on_xy(self, x, y):
72 for line in self.line_list:
73 if line.is_on_xy(x, y):
77 def xy_to_index(self, x, y):
80 def build_line_list(self, x, y, width, left_margin):
83 line = Line(0, 0, Rectangle(
85 get_approximate_char_height(self.pango_layout.get_context())))
86 self.line_list.append(line)
90 def get_text(self, selection=False, start_index=0, end_index=0xffffff):
93 def draw(self, drawingarea, y_offset, pango_layout,
94 selection=False, start_index=0, end_index=0xffffff):
100 ch_width_dict = {} # key: char, value: width
102 def __init__(self, text, pango_layout):
104 self.pango_layout = pango_layout
106 self.recalc_char_widths()
110 def recalc_char_widths(self):
111 self.widths = [i for i in itertools.repeat(0, len(self.text))]
113 dict = self._get_ch_width_dict()
115 for index, ch in enumerate(self.text):
121 self.widths[index] = width
124 attrlist = self._get_attrs()
125 self.widths = thread_view_extend.get_char_width(
126 self.pango_layout.get_context(), self.text, attrlist)
127 for index, width in enumerate(self.widths):
128 dict[self.text[index]] = self.widths[index]
130 def _get_ch_width_dict(self):
131 return ElementText.ch_width_dict
133 def _get_attrs(self):
134 attrs = pango.AttrList()
137 def is_on_xy(self, x, y):
138 for line in self.line_list:
139 if line.is_on_xy(x, y):
143 def xy_to_index(self, x, y):
144 for line in self.line_list:
145 top = line.rectangle.y
146 bottom = top + line.rectangle.height
147 if y >= top and y < bottom:
148 sum_of_widths = line.rectangle.x
149 index = line.start_index
150 for width in self.widths[line.start_index:line.end_index]:
151 if sum_of_widths + width/2 > x:
153 sum_of_widths += width
157 def build_line_list(self, x, y, width, left_margin):
160 current_line_start_index = 0
163 current_line_width = 0
165 ch_h = get_approximate_char_height(self.pango_layout.get_context())
167 for index, ch in enumerate(self.text):
168 ch_w = self.widths[index]
169 if current_line_x + current_line_width + ch_w > width:
171 current_line_start_index, index,
173 current_line_x, current_line_y,
174 current_line_width, ch_h))
175 self.line_list.append(line)
177 current_line_start_index = index
178 current_line_x = left_margin
179 current_line_y += ch_h
180 current_line_width = ch_w
182 current_line_width += ch_w
184 if current_line_start_index < len(self.text):
185 line = Line(current_line_start_index, len(self.text),
186 Rectangle(current_line_x,
190 self.line_list.append(line)
192 current_line_x += current_line_width
194 return current_line_x, current_line_y
196 def get_text(self, selection=False, start_index=0, end_index=0xffffff):
200 for line in self.line_list:
202 t = self.text[line.start_index:line.end_index]
204 s = start_index - line.start_index
206 s = min(s, line.end_index - line.start_index)
208 e = end_index - line.start_index
209 e = min(e, line.end_index - line.start_index)
218 def draw(self, drawingarea, y_offset, pango_layout,
219 selection=False, start_index=0, end_index=0xffffff):
221 if drawingarea.get_property("has-focus"):
222 selection_fg = drawingarea.style.text[gtk.STATE_SELECTED]
223 selection_bg = drawingarea.style.base[gtk.STATE_SELECTED]
225 selection_fg = drawingarea.style.text[gtk.STATE_ACTIVE]
226 selection_bg = drawingarea.style.base[gtk.STATE_ACTIVE]
228 for line in self.line_list:
230 text = self.text[line.start_index:line.end_index]
231 u_text = text.encode("utf8")
232 gc = drawingarea.window.new_gc()
233 gc.set_foreground(drawingarea.style.text[gtk.STATE_NORMAL])
234 gc.set_background(drawingarea.style.base[gtk.STATE_NORMAL])
235 attrs = self._get_attrs()
238 s = start_index - line.start_index
240 s = min(s, line.end_index - line.start_index)
241 s = len(text[:s].encode("utf8"))
243 e = end_index - line.start_index
244 e = min(e, line.end_index - line.start_index)
246 e = len(text[:e].encode("utf8"))
248 selection_all_attr_fg = pango.AttrForeground(
249 selection_fg.red, selection_fg.green, selection_fg.blue,
251 selection_all_attr_bg= pango.AttrBackground(
252 selection_bg.red, selection_bg.green, selection_bg.blue,
254 attrs.insert(selection_all_attr_fg)
255 attrs.insert(selection_all_attr_bg)
257 pango_layout.set_text(u_text)
258 pango_layout.set_attributes(attrs)
259 drawingarea.window.draw_layout(
260 gc, int(line.rectangle.x), line.rectangle.y + y_offset,
264 class ElementBoldText(ElementText):
266 def _get_attrs(self):
267 attrlist = pango.AttrList()
268 attr = pango.AttrWeight(pango.WEIGHT_BOLD,
270 attrlist.insert(attr)
273 def recalc_char_widths(self):
274 attrlist = self._get_attrs()
275 self.widths = thread_view_extend.get_char_width(
276 self.pango_layout.get_context(), self.text, attrlist)
279 class ElementLink(ElementText):
281 def __init__(self, text, href, pango_layout):
283 ElementText.__init__(self, text, pango_layout)
285 def _get_attrs(self):
286 attrlist = pango.AttrList()
287 attr = pango.AttrUnderline(pango.UNDERLINE_SINGLE,
289 attrlist.insert(attr)
296 def __init__(self, left_margin, resnum, pango_layout):
297 self.element_list = [ElementEmpty(pango_layout)]
300 self.pango_layout = pango_layout
301 self.left_margin = left_margin
306 def add_text(self, text, bold, href):
307 if isinstance(self.element_list[0], ElementEmpty):
308 self.element_list = []
311 element = ElementLink(text, href, self.pango_layout)
312 self.element_list.append(element)
314 element = ElementBoldText(text, self.pango_layout)
315 self.element_list.append(element)
317 element = ElementText(text, self.pango_layout)
318 self.element_list.append(element)
320 def get_element_from_xy(self, x, y):
321 for element in self.element_list:
322 if element.is_on_xy(x, y):
326 def get_close_element_from_xy(self, x, y):
327 x= max(x, self.left_margin)
328 element = self.get_element_from_xy(x, y)
329 if element is None and len(self.element_list) != 0:
330 element = self.element_list[len(self.element_list) - 1]
333 def recalc_char_widths(self):
334 for element in self.element_list:
335 element.recalc_char_widths()
337 def set_width(self, width):
341 current_x = self.left_margin
344 for element in self.element_list:
345 current_x, current_y = element.build_line_list(
346 current_x, current_y, width, self.left_margin)
348 self.height = current_y + get_approximate_char_height(self.pango_layout.get_context())
350 def get_pixel_size(self):
351 return self.width, self.height
353 def get_text(self, selection_start, selection_end):
354 s_s = selection_start
356 s_l, s_e, s_i = selection_start
357 e_l, e_e, e_i = selection_end
361 if (s_l is None or s_e is None or s_i is None or
362 e_l is None or e_e is None or e_i is None or
363 self.posY < s_l.posY or self.posY > e_l.posY):
368 elif self.posY > s_s[0].posY and self.posY < e_s[0].posY:
370 for element in self.element_list:
371 text += element.get_text(selection=True)
373 elif self == s_s[0] and self == e_s[0]:
377 for element in self.element_list:
385 text += element.get_text(selection=True, start_index=start,
390 text += element.get_text(
391 selection=True, end_index=end)
393 text += element.get_text(selection=True)
399 for element in self.element_list:
403 text += element.get_text(selection=True, start_index=start)
405 text += element.get_text(selection=True)
411 for element in self.element_list:
414 text += element.get_text(selection=True, end_index=e_i)
417 text += element.get_text(selection=True)
426 def draw(self, drawingarea, x_offset, y_offset,
427 start_selection, end_selection):
429 s_s = start_selection
435 if (s_l is None or s_e is None or s_i is None or
436 e_l is None or e_e is None or e_i is None or
437 self.posY < s_l.posY or self.posY > e_l.posY):
439 for element in self.element_list:
440 element.draw(drawingarea, y_offset, self.pango_layout)
442 elif self.posY > s_s[0].posY and self.posY < e_s[0].posY:
444 for element in self.element_list:
445 element.draw(drawingarea, y_offset, self.pango_layout,
448 elif self == s_s[0] and self == e_s[0]:
452 for element in self.element_list:
460 element.draw(drawingarea, y_offset, self.pango_layout,
467 element.draw(drawingarea, y_offset, self.pango_layout,
468 selection=True, end_index=end)
470 element.draw(drawingarea, y_offset, self.pango_layout,
477 for element in self.element_list:
481 element.draw(drawingarea, y_offset, self.pango_layout,
482 selection=selection, start_index = start)
484 element.draw(drawingarea, y_offset, self.pango_layout,
491 for element in self.element_list:
494 element.draw(drawingarea, y_offset, self.pango_layout,
495 selection=selection, end_index=e_i)
498 element.draw(drawingarea, y_offset, self.pango_layout,
502 for element in self.element_list:
503 element.draw(drawingarea, y_offset, self.pango_layout)
507 layout = ResLayout(self.left_margin, self.resnum, self.pango_layout)
508 layout.element_list = []
509 for element in self.element_list:
510 layout.element_list.append(copy.copy(element))
514 class ThreadView(gtk.HBox):
516 "cursor-over-link-event":
517 (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, object, )),
519 (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object, ))
522 hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2)
523 regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM)
524 arrow_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
527 gtk.HBox.__init__(self, False, 0)
528 self.drawingarea = gtk.DrawingArea()
529 self.drawingarea.set_property("can_focus", True)
531 self.vscrollbar = gtk.VScrollbar()
532 self.pack_start(self.drawingarea)
533 self.pack_start(self.vscrollbar, expand=False)
534 self.adjustment = self.vscrollbar.get_adjustment()
536 self.drawingarea.add_events(
537 gtk.gdk.KEY_PRESS_MASK |
538 gtk.gdk.SCROLL_MASK |
539 gtk.gdk.POINTER_MOTION_MASK |
540 gtk.gdk.BUTTON_PRESS_MASK |
541 gtk.gdk.BUTTON_RELEASE_MASK)
543 self.drawingarea_prev_width = 0
545 self.drawingarea.connect(
546 "expose-event", self.on_drawingarea_expose_event)
547 self.drawingarea.connect(
548 "configure-event", self.on_drawingarea_configure_event)
549 self.drawingarea.connect(
550 "scroll-event", self.on_drawingarea_scroll_event)
551 self.drawingarea.connect(
552 "motion-notify-event", self.on_drawingrarea_motion_notify_event)
553 self.drawingarea.connect(
554 "button-press-event", self.on_drawingarea_button_press_event)
555 self.drawingarea.connect(
556 "button-release-event", self.on_drawingarea_button_release_event)
557 self.drawingarea.connect(
558 "style-set", self.on_drawingarea_style_set)
559 self.drawingarea.connect(
560 "key-press-event", self.on_drawingarea_key_press_event)
561 self.adjustment.connect(
562 "value-changed", self.on_adjustment_value_changed)
563 self.adjustment.connect(
564 "changed", self.on_adjustment_changed)
566 self.pango_layout = self.drawingarea.create_pango_layout("")
568 self.initialize_buffer()
570 self.button1_pressed = False
571 self.current_pressed_uri = None
573 self.popupmenu = None
574 self.menu_openuri = None
575 self.menu_copylinkaddress = None
576 self.menu_separator_link = None
577 self.menu_copyselection = None
578 self.menu_openasuri = None
579 self.menu_separator_selection = None
581 self.menud_uri = None
584 self.button_pressed_pt = (None, None, None)
585 self.button_moving_pt = (None, None, None)
587 def initialize_buffer(self):
588 self.res_layout_list = []
590 def add_layout(self, res_layout):
591 if (len(self.res_layout_list) != 0):
592 last = self.res_layout_list[len(self.res_layout_list)-1]
593 x, y = last.get_pixel_size()
594 res_layout.posY = last.posY + y
595 self.set_layout_width(res_layout)
596 res_layout.list_index = len(self.res_layout_list)
597 self.res_layout_list.append(res_layout)
599 x, y = res_layout.get_pixel_size()
600 self.adjustment.upper = res_layout.posY + y
601 # do not use this method in a loop because expensive.
604 def create_res_layout(self, left_margin, resnum):
605 return ResLayout(left_margin, resnum, self.pango_layout)
607 def set_layout_width(self, layout):
608 width = self.drawingarea.allocation.width
609 layout.set_width(width)
612 self.drawingarea.queue_draw()
614 def wrap_relayout(self):
615 # before relayout, find top layout on gdkwindow
616 top_layout = self.get_layout_on_y(self.adjustment.value)
619 if top_layout is not None:
620 delta = top_layout.posY - self.adjustment.value
623 self.drawingarea_prev_width = self.drawingarea.allocation.width
625 # after relayout, set adjustment.value to top layout's posY
626 if top_layout is not None:
627 self.adjustment.value = top_layout.posY - delta
630 width = self.drawingarea.allocation.width
632 for layout in self.res_layout_list:
633 layout.set_width(width)
634 layout.posY = sum_height
635 x, y = layout.get_pixel_size()
638 self.adjustment.upper = sum_height
640 def change_vscrollbar_visible(self):
641 if self.adjustment.upper <= self.adjustment.page_size:
642 self.vscrollbar.hide()
644 self.vscrollbar.show()
646 def _set_adjustment_value(self, value):
647 value = min(self.adjustment.upper - self.adjustment.page_size, value)
648 value = max(self.adjustment.lower, value)
649 self.adjustment.value = value
651 def jump(self, value):
652 self._set_adjustment_value(value)
654 def jump_to_layout(self, layout):
655 self.jump(layout.posY)
657 def jump_to_the_end(self):
658 value = self.adjustment.upper - self.adjustment.page_size
659 self._set_adjustment_value(value)
661 def jump_to_res(self, resnum):
662 for layout in self.res_layout_list:
663 if layout.resnum == resnum:
664 self.jump_to_layout(layout)
669 def _get_selection_start_end(self):
670 pressed_layout, pressed_element, pressed_index = self.button_pressed_pt
671 moving_layout, moving_element, moving_index = self.button_moving_pt
673 if (pressed_layout is None or pressed_element is None or
674 pressed_index is None or moving_layout is None or
675 moving_element is None or moving_index is None):
676 return (None, None, None), (None, None, None)
678 if pressed_layout == moving_layout:
679 if pressed_element == moving_element:
680 if moving_index < pressed_index:
681 return self.button_moving_pt, self.button_pressed_pt
683 pressed_element_index = pressed_layout.element_list.index(
685 moving_element_index = moving_layout.element_list.index(
687 if moving_element_index < pressed_element_index:
688 return self.button_moving_pt, self.button_pressed_pt
689 elif moving_layout.posY < pressed_layout.posY:
690 return self.button_moving_pt, self.button_pressed_pt
692 return self.button_pressed_pt, self.button_moving_pt
694 def draw_viewport(self, area):
695 view_y = self.adjustment.value
696 self.drawingarea.window.draw_rectangle(
697 self.drawingarea.style.base_gc[0],
698 True, area.x, area.y, area.width, area.height)
700 selection_start, selection_end = self._get_selection_start_end()
702 top_layout = self.get_layout_on_y(view_y)
703 if top_layout is None:
705 #area_top = view_y + area.y
706 area_bottom = view_y + area.y + area.height
708 iter = range(top_layout.list_index, len(self.res_layout_list))
709 iter = itertools.imap(lambda index: self.res_layout_list[index], iter)
710 iter = itertools.takewhile(lambda lay: lay.posY <= area_bottom, iter)
712 layout.draw(self.drawingarea, 0, layout.posY - int(view_y),
713 selection_start, selection_end)
715 def transform_coordinate_gdk_to_adj(self, y):
716 return y + self.adjustment.value
718 def transform_coordinate_adj_to_layout(self, x, y, layout):
719 return x, y - layout.posY
721 def transform_coordinate_gdk_to_layout(self, x, y, layout):
722 return self.transform_coordinate_adj_to_layout(
723 x, self.transform_coordinate_gdk_to_adj(y), layout)
725 def get_layout_on_y(self, y):
727 def binary_search(lst, start, end, func):
732 m = (start + end) / 2
738 return binary_search(lst, start, m, func)
739 return binary_search(lst, m+1, end, func)
741 def on_y(layout, _y):
743 width, height = layout.get_pixel_size()
744 bottom = top + height
745 if _y >= top and _y < bottom:
752 self.res_layout_list, 0, len(self.res_layout_list),
753 lambda x: on_y(x, y))
755 return self.res_layout_list[ret]
758 def ptrpos_to_layout(self, x, y):
759 # transform coordinate, GdkWindow -> adjustment
760 adj_y = self.transform_coordinate_gdk_to_adj(y)
761 return self.get_layout_on_y(adj_y)
763 def ptrpos_to_uri(self, x, y):
764 # x, y is GdkWindow coordinate
766 layout = self.ptrpos_to_layout(x, y)
769 return None, None, None
771 # transform coordinate, GdkWindow -> res_layout_list
772 lay_x, lay_y = self.transform_coordinate_gdk_to_layout(x, y, layout)
775 element = layout.get_element_from_xy(lay_x, lay_y)
776 if isinstance(element, ElementLink):
777 return element.href, layout, element
779 return None, layout, None
781 def get_selected_text(self):
782 selection_start, selection_end = self._get_selection_start_end()
783 s_l, s_e, s_i = selection_start
784 e_l, e_e, e_i = selection_end
786 if (s_l is None or s_e is None or s_i is None or
787 e_l is None or e_e is None or e_i is None):
791 index = s_l.list_index
795 layout = self.res_layout_list[index]
797 text += layout.get_text(selection_start, selection_end)
805 def _set_button_pressed_pt(self, pt):
806 self.button_pressed_pt = (None, None, None)
811 layout = self.ptrpos_to_layout(x, y)
815 x, y = self.transform_coordinate_gdk_to_layout(x, y, layout)
816 element = layout.get_element_from_xy(x, y)
818 element = layout.get_close_element_from_xy(x, y)
823 index = element.xy_to_index(x, y)
827 self.button_pressed_pt = (layout, element, index)
829 def _set_button_moving_pt(self, pt):
830 self.button_moving_pt = (None, None, None)
835 layout = self.ptrpos_to_layout(x, y)
839 x, y = self.transform_coordinate_gdk_to_layout(x, y, layout)
840 element = layout.get_element_from_xy(x, y)
842 element = layout.get_close_element_from_xy(x, y)
847 index = element.xy_to_index(x, y)
851 self.button_moving_pt = (layout, element, index)
853 def on_drawingarea_expose_event(self, widget, event, data=None):
854 self.draw_viewport(event.area)
856 def on_drawingarea_configure_event(self, widget, event, data=None):
857 if event.width != self.drawingarea_prev_width:
860 self.adjustment.page_size = self.drawingarea.allocation.height
861 self.adjustment.step_increment = 20
862 self.adjustment.page_increment = self.drawingarea.allocation.height
864 # re-set 'value' for prevent overflow
865 self._set_adjustment_value(self.adjustment.value)
867 def on_adjustment_value_changed(self, widget, data=None):
868 self.drawingarea.queue_draw()
870 def on_adjustment_changed(self, widget, data=None):
871 self.change_vscrollbar_visible()
873 def on_drawingarea_scroll_event(self, widget, event, data=None):
874 self.vscrollbar.emit("scroll-event", event)
876 def on_drawingrarea_motion_notify_event(self, widget, event, data=None):
877 if event.state & gtk.gdk.BUTTON1_MASK != gtk.gdk.BUTTON1_MASK:
878 self.button1_pressed = False
880 if self.button1_pressed and self.current_pressed_uri is None:
881 old_lay, old_elem, old_idx = self.button_moving_pt
882 self._set_button_moving_pt((event.x, event.y))
883 new_lay, new_elem, new_idx = self.button_moving_pt
884 if (old_lay != new_lay
885 or old_elem != new_elem
886 or old_idx != new_idx):
887 view_y = self.adjustment.value
890 o_width, o_height = old_lay.get_pixel_size()
891 n_width, n_height = new_lay.get_pixel_size()
894 height = max(o_y, n_y) - y
895 if o_y > n_y: height += o_height
896 else: height += n_height
900 self.drawingarea.queue_draw_area(0, y, n_width, height+1)
901 #self.drawingarea.window.process_updates(False)
903 cursor = ThreadView.regular_cursor
905 uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
907 cursor = ThreadView.arrow_cursor
909 if uri is not None and uri != "":
910 cursor = ThreadView.hand_cursor
911 self.emit("cursor-over-link-event", event, uri)
913 self.drawingarea.window.set_cursor(cursor)
915 def on_drawingarea_button_press_event(self, widget, event, data=None):
916 if event.button == 1:
917 self.current_pressed_uri = None
918 self.button1_pressed = True
919 uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
920 if uri is not None and layout is not None and element is not None:
921 self.current_pressed_uri = (uri, layout, element)
923 self._set_button_moving_pt((event.x, event.y))
924 self._set_button_pressed_pt((event.x, event.y))
925 self.drawingarea.queue_draw()
927 elif event.button == 3:
929 uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
930 if uri is not None and layout is not None and element is not None:
931 self.menu_openuri.show()
932 self.menu_copylinkaddress.show()
933 self.menu_separator_link.show()
934 self.menu_openuri.uri = uri
935 self.menu_copylinkaddress.uri = uri
937 self.menu_openuri.hide()
938 self.menu_copylinkaddress.hide()
939 self.menu_separator_link.hide()
940 self.menu_openuri.uri = None
941 self.menu_copylinkaddress.uri = None
943 text = self.get_selected_text()
944 if text and len(text) > 0:
945 self.menu_copyselection.show()
946 self.menu_openasuri.show()
947 self.menu_separator_selection.show()
949 self.menu_copyselection.hide()
950 self.menu_openasuri.hide()
951 self.menu_separator_selection.hide()
953 self.popupmenu.popup(None, None, None, event.button, time)
957 def on_drawingarea_button_release_event(self, widget, event, data=None):
958 if event.button == 1:
959 button1_pressed = self.button1_pressed
960 self.button1_pressed = False
962 if button1_pressed and self.current_pressed_uri is not None:
963 uri, layout, element = self.ptrpos_to_uri(event.x, event.y)
964 p_uri, p_layout, p_element = self.current_pressed_uri
965 self.current_pressed_uri = None
966 if (uri == p_uri and layout == p_layout and
967 element == p_element):
968 self.emit("uri-clicked-event", uri)
970 def on_drawingarea_style_set(self, widget, previous_style, data=None):
971 if previous_style is None:
974 new = widget.style.font_desc.hash()
975 old = previous_style.font_desc.hash()
977 for layout in self.res_layout_list:
978 layout.recalc_char_widths()
981 def on_drawingarea_key_press_event(self, widget, event, data=None):
982 if event.type is not gtk.gdk.KEY_PRESS:
985 if event.keyval in (gtk.keysyms.Up, gtk.keysyms.Down,
986 gtk.keysyms.Page_Up, gtk.keysyms.Page_Down,
988 value = self.adjustment.value
989 if event.keyval == gtk.keysyms.Up:
990 step_increment = self.adjustment.step_increment
991 value = value - step_increment
992 elif event.keyval == gtk.keysyms.Down:
993 step_increment = self.adjustment.step_increment
994 value = value + step_increment
995 elif event.keyval == gtk.keysyms.Page_Up:
996 step_increment = self.adjustment.page_increment
997 value = value - step_increment
998 elif event.keyval == gtk.keysyms.Page_Down:
999 step_increment = self.adjustment.page_increment
1000 value = value + step_increment
1001 elif event.keyval == gtk.keysyms.Home:
1004 elif event.keyval == gtk.keysyms.End:
1005 self.jump_to_the_end()