Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on May 9th, 2012  |  syntax: None  |  size: 43.92 KB  |  hits: 20  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python
  2. # -*- coding: iso-8859-1 -*-
  3.  
  4. import pygtk
  5. pygtk.require('2.0')
  6. import sys, os, errno
  7. import gtk
  8. import pango
  9.  
  10.  
  11. RESPONSE_FORWARD = 0
  12. RESPONSE_BACKWARD = 1
  13.  
  14. book_closed_xpm = [
  15. "16 16 6 1",
  16. "       c None s None",
  17. ".      c black",
  18. "X      c red",
  19. "o      c yellow",
  20. "O      c #808080",
  21. "#      c white",
  22. "                ",
  23. "       ..       ",
  24. "     ..XX.      ",
  25. "   ..XXXXX.     ",
  26. " ..XXXXXXXX.    ",
  27. ".ooXXXXXXXXX.   ",
  28. "..ooXXXXXXXXX.  ",
  29. ".X.ooXXXXXXXXX. ",
  30. ".XX.ooXXXXXX..  ",
  31. " .XX.ooXXX..#O  ",
  32. "  .XX.oo..##OO. ",
  33. "   .XX..##OO..  ",
  34. "    .X.#OO..    ",
  35. "     ..O..      ",
  36. "      ..        ",
  37. "                "]
  38.  
  39. def hsv_to_rgb(h, s, v):
  40.     if s == 0.0:
  41.         return (v, v, v)
  42.     else:
  43.         hue = h * 6.0
  44.         saturation = s
  45.         value = v
  46.  
  47.         if hue >= 6.0:
  48.             hue = 0.0
  49.  
  50.         f = hue - int(hue)
  51.         p = value * (1.0 - saturation)
  52.         q = value * (1.0 - saturation * f)
  53.         t = value * (1.0 - saturation * (1.0 - f))
  54.  
  55.         ihue = int(hue)
  56.         if ihue == 0:
  57.             return(value, t, p)
  58.         elif ihue == 1:
  59.             return(q, value, p)
  60.         elif ihue == 2:
  61.             return(p, value, t)
  62.         elif ihue == 3:
  63.             return(p, q, value)
  64.         elif ihue == 4:
  65.             return(t, p, value)
  66.         elif ihue == 5:
  67.             return(value, p, q)
  68.  
  69. def hue_to_color(hue):
  70.     if hue > 1.0:
  71.         raise ValueError
  72.  
  73.     h, s, v = hsv_to_rgb (hue, 1.0, 1.0)
  74.     return (h*65535, s*65535, v*65535)
  75.  
  76. class FileSel(gtk.FileSelection):
  77.     def __init__(self):
  78.         gtk.FileSelection.__init__(self)
  79.         self.result = False
  80.  
  81.     def ok_cb(self, button):
  82.         self.hide()
  83.         if self.ok_func(self.get_filename()):
  84.             self.destroy()
  85.             self.result = True
  86.         else:
  87.             self.show()
  88.  
  89.     def run(self, parent, title, start_file, func):
  90.         if start_file:
  91.             self.set_filename(start_file)
  92.  
  93.         self.ok_func = func
  94.         self.ok_button.connect("clicked", self.ok_cb)
  95.         self.cancel_button.connect("clicked", lambda x: self.destroy())
  96.         self.connect("destroy", lambda x: gtk.main_quit())
  97.         self.set_modal(True)
  98.         self.show()
  99.         gtk.main()
  100.         return self.result
  101.  
  102. class Buffer(gtk.TextBuffer):
  103.     N_COLORS = 16
  104.     PANGO_SCALE = 1024
  105.  
  106.     def __init__(self):
  107.         gtk.TextBuffer.__init__(self)
  108.         tt = self.get_tag_table()
  109.         self.refcount = 0
  110.         self.filename = None
  111.         self.untitled_serial = -1
  112.         self.color_tags = []
  113.         self.color_cycle_timeout_id = 0
  114.         self.start_hue = 0.0
  115.  
  116.         for i in range(Buffer.N_COLORS):
  117.             tag = self.create_tag()
  118.             self.color_tags.append(tag)
  119.  
  120.         #self.invisible_tag = self.create_tag(None, invisible=True)
  121.         self.not_editable_tag = self.create_tag(editable=False,
  122.                                                 foreground="purple")
  123.         self.found_text_tag = self.create_tag(foreground="red")
  124.  
  125.         tabs = pango.TabArray(4, True)
  126.         tabs.set_tab(0, pango.TAB_LEFT, 10)
  127.         tabs.set_tab(1, pango.TAB_LEFT, 30)
  128.         tabs.set_tab(2, pango.TAB_LEFT, 60)
  129.         tabs.set_tab(3, pango.TAB_LEFT, 120)
  130.         self.custom_tabs_tag = self.create_tag(tabs=tabs, foreground="green")
  131.         TestText.buffers.push(self)
  132.  
  133.     def pretty_name(self):
  134.         if self.filename:
  135.             return os.path.basename(self.filename)
  136.         else:
  137.             if self.untitled_serial == -1:
  138.                 self.untitled_serial = TestText.untitled_serial
  139.                 TestText.untitled_serial += 1
  140.  
  141.             if self.untitled_serial == 1:
  142.                 return "Untitled"
  143.             else:
  144.                 return "Untitled #%d" % self.untitled_serial
  145.  
  146.     def filename_set(self):
  147.         for view in TestText.views:
  148.             if view.text_view.get_buffer() == self:
  149.                 view.set_view_title()
  150.  
  151.     def search(self, str, view, forward):
  152.         # remove tag from whole buffer
  153.         start, end = self.get_bounds()
  154.         self.remove_tag(self.found_text_tag, start, end)
  155.  
  156.         iter = self.get_iter_at_mark(self.get_insert())
  157.  
  158.         i = 0
  159.         if str:
  160.             if forward:
  161.                 while 1:
  162.                     res = iter.forward_search(str, gtk.TEXT_SEARCH_TEXT_ONLY)
  163.                     if not res:
  164.                         break
  165.                     match_start, match_end = res
  166.                     i += 1
  167.                     self.apply_tag(self.found_text_tag, match_start, match_end)
  168.                     iter = match_end
  169.             else:
  170.                 while 1:
  171.                     res = iter.backward_search(str, gtk.TEXT_SEARCH_TEXT_ONLY)
  172.                     if not res:
  173.                         break
  174.                     match_start, match_end = res
  175.                     i += 1
  176.                     self.apply_tag(self.found_text_tag, match_start, match_end)
  177.                     iter = match_start
  178.  
  179.         dialog = gtk.MessageDialog(view,
  180.                                    gtk.DIALOG_DESTROY_WITH_PARENT,
  181.                                    gtk.MESSAGE_INFO,
  182.                                    gtk.BUTTONS_OK,
  183.                                    "%d strings found and marked in red" % i)
  184.  
  185.         dialog.connect("response", lambda x,y: dialog.destroy())
  186.  
  187.         dialog.show()
  188.  
  189.     def search_forward(self, str, view):
  190.         self.search(str, view, True)
  191.  
  192.     def search_backward(self, str, view):
  193.         self.search(str, view, False)
  194.  
  195.     def ref(self):
  196.         self.refcount += 1
  197.  
  198.     def unref(self):
  199.         self.refcount -= 1
  200.         if self.refcount == 0:
  201.             self.set_colors(False)
  202.             TestText.buffers.remove(self)
  203.             del self
  204.  
  205.     def color_cycle_timeout(self):
  206.         self.cycle_colors()
  207.         return True
  208.  
  209.     def set_colors(self, enabled):
  210.         hue = 0.0
  211.  
  212.         if (enabled and self.color_cycle_timeout_id == 0):
  213.             self.color_cycle_timeout_id = gtk.timeout_add(
  214.                 200, self.color_cycle_timeout)
  215.         elif (not enabled and self.color_cycle_timeout_id != 0):
  216.             gtk.timeout_remove(self.color_cycle_timeout_id)
  217.             self.color_cycle_timeout_id = 0
  218.    
  219.         for tag in self.color_tags:
  220.             if enabled:
  221.                 color = apply(TestText.colormap.alloc_color,
  222.                               hue_to_color(hue))
  223.                 tag.set_property("foreground_gdk", color)
  224.             else:
  225.                 tag.set_property("foreground_set", False)
  226.             hue += 1.0 / Buffer.N_COLORS
  227.      
  228.     def cycle_colors(self):
  229.         hue = self.start_hue
  230.  
  231.         for tag in self.color_tags:
  232.             color = apply(TestText.colormap.alloc_color,
  233.                           hue_to_color (hue))
  234.             tag.set_property("foreground_gdk", color)
  235.  
  236.             hue += 1.0 / Buffer.N_COLORS
  237.             if hue > 1.0:
  238.                 hue = 0.0
  239.  
  240.         self.start_hue += 1.0 / Buffer.N_COLORS
  241.         if self.start_hue > 1.0:
  242.             self.start_hue = 0.0
  243.  
  244.     def tag_event_handler(self, tag, widget, event, iter):
  245.         char_index = iter.get_offset()
  246.         tag_name = tag.get_property("name")
  247.         if event.type == gtk.gdk.MOTION_NOTIFY:
  248.             print "Motion event at char %d tag `%s'\n" % (char_index, tag_name)
  249.         elif event.type == gtk.gdk.BUTTON_PRESS:
  250.             print "Button press at char %d tag `%s'\n" % (char_index, tag_name)
  251.         elif event.type == gtk.gdk._2BUTTON_PRESS:
  252.             print "Double click at char %d tag `%s'\n" % (char_index, tag_name)
  253.         elif event.type == gtk.gdk._3BUTTON_PRESS:
  254.             print "Triple click at char %d tag `%s'\n" % (char_index, tag_name)
  255.         elif event.type == gtk.gdk.BUTTON_RELEASE:
  256.             print "Button release at char %d tag `%s'\n" % (char_index, tag_name)
  257.         elif (event.type == gtk.gdk.KEY_PRESS or
  258.               event.type == gtk.gdk.KEY_RELEASE):
  259.             print "Key event at char %d tag `%s'\n" % (char_index, tag_name)
  260.  
  261.         return False
  262.  
  263.     def init_tags(self):
  264.         colormap = TestText.colormap
  265.         color = colormap.alloc_color(0, 0, 0xffff)
  266.         tag = self.create_tag("fg_blue",
  267.                                 foreground_gdk=color,
  268.                                 background='yellow',
  269.                                 size_points=24.0)
  270.         tag.connect("event", self.tag_event_handler)
  271.  
  272.         color = colormap.alloc_color(0xffff, 0, 0)
  273.         tag = self.create_tag("fg_red",
  274.                                 rise= -4*Buffer.PANGO_SCALE,
  275.                                 foreground_gdk=color)
  276.         tag.connect("event", self.tag_event_handler)
  277.  
  278.         color = colormap.alloc_color(0, 0xffff, 0)
  279.         tag = self.create_tag("bg_green",
  280.                                 background_gdk=color,
  281.                                 size_points=10.0)
  282.         tag.connect("event", self.tag_event_handler)
  283.  
  284.         tag = self.create_tag("strikethrough",
  285.                                 strikethrough=True)
  286.         tag.connect("event", self.tag_event_handler)
  287.  
  288.         tag = self.create_tag("underline",
  289.                                 underline=pango.UNDERLINE_SINGLE)
  290.         tag.connect("event", self.tag_event_handler)
  291.  
  292.         tag = self.create_tag("centered",
  293.                                 justification=gtk.JUSTIFY_CENTER)
  294.  
  295.         tag = self.create_tag("rtl_quote",
  296.                                 wrap_mode=gtk.WRAP_WORD,
  297.                                 direction=gtk.TEXT_DIR_RTL,
  298.                                 indent=30,
  299.                                 left_margin=20,
  300.                                 right_margin=20)
  301.  
  302.         tag = self.create_tag("negative_indent",
  303.                                 indent=-25)
  304.  
  305.     def fill_example_buffer(self):
  306.         tagtable = self.get_tag_table()
  307.         if not tagtable.lookup("fg_blue"):
  308.             self.init_tags()
  309.         iter = self.get_iter_at_offset(0)
  310.         anchor = self.create_child_anchor(iter)
  311.         self.set_data("anchor", anchor)
  312.         pixbuf = gtk.gdk.pixbuf_new_from_xpm_data(book_closed_xpm)
  313.         #pixbuf = gtk.gdk.pixbuf_new_from_file('book_closed.xpm')
  314.  
  315.         for i in range(100):
  316.             iter = self.get_iter_at_offset(0)
  317.             self.insert_pixbuf(iter, pixbuf)
  318.          
  319.             str = "%d Hello World! blah blah blah blah blah blah blah blah blah blah blah blah\nwoo woo woo woo woo woo woo woo woo woo woo woo woo woo woo\n" % i
  320.             self.insert(iter, str)
  321.  
  322.             iter = self.get_iter_at_line_offset(0, 5)
  323.             self.insert(iter,
  324.                           "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line with a significant quantity of text on it. This line really does contain some text. More text! More text! More text!\n"
  325.                           "German (Deutsch Süd) Grüß Gott Greek (Ελληνικά) Γειά σας Hebrew(שלום) Hebrew punctuation(\xd6\xbfש\xd6\xbb\xd6\xbc\xd6\xbb\xd6\xbfל\xd6\xbcו\xd6\xbc\xd6\xbb\xd6\xbb\xd6\xbfם\xd6\xbc\xd6\xbb\xd6\xbf) Japanese (日本語) Thai (สวัสดีครับ) Thai wrong spelling (คำต่อไปนื่สะกดผิด พัั้ัั่งโกะ)\n")
  326.  
  327.             temp_mark = self.create_mark("tmp_mark", iter, True);
  328.  
  329.             iter = self.get_iter_at_line_offset(0, 6)
  330.             iter2 = self.get_iter_at_line_offset(0, 13)
  331.             self.apply_tag_by_name("fg_blue", iter, iter2)
  332.  
  333.             iter = self.get_iter_at_line_offset(1, 10)
  334.             iter2 = self.get_iter_at_line_offset(1, 16)
  335.             self.apply_tag_by_name("underline", iter, iter2)
  336.  
  337.             iter = self.get_iter_at_line_offset(1, 14)
  338.             iter2 = self.get_iter_at_line_offset(1, 24)
  339.             self.apply_tag_by_name("strikethrough", iter, iter2)
  340.          
  341.             iter = self.get_iter_at_line_offset(0, 9)
  342.             iter2 = self.get_iter_at_line_offset(0, 16)
  343.             self.apply_tag_by_name("bg_green", iter, iter2)
  344.  
  345.             iter = self.get_iter_at_line_offset(4, 2)
  346.             iter2 = self.get_iter_at_line_offset(4, 10)
  347.             self.apply_tag_by_name("bg_green", iter, iter2)
  348.  
  349.             iter = self.get_iter_at_line_offset(4, 8)
  350.             iter2 = self.get_iter_at_line_offset(4, 15)
  351.             self.apply_tag_by_name("fg_red", iter, iter2)
  352.  
  353.             iter = self.get_iter_at_mark(temp_mark)
  354.             self.insert(iter, "Centered text!\n")
  355.          
  356.             iter2 = self.get_iter_at_mark(temp_mark)
  357.             self.apply_tag_by_name("centered", iter2, iter)
  358.  
  359.             self.move_mark(temp_mark, iter)
  360.             self.insert(iter, "Word wrapped, Right-to-left Quote\n")
  361.             self.insert(iter, "وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لا تسعى للربح، ثم تحولت في السنوات الخمس الماضية إلى مؤسسات مالية منظمة، وباتت جزءا من النظام المالي في بلدانها، ولكنها تتخصص في خدمة قطاع المشروعات الصغيرة. وأحد أكثر هذه المؤسسات نجاحا هو »بانكوسول« في بوليفيا.\n")
  362.             iter2 = self.get_iter_at_mark(temp_mark)
  363.             self.apply_tag_by_name("rtl_quote", iter2, iter)
  364.  
  365.             self.insert_with_tags(iter,
  366.                                     "Paragraph with negative indentation. blah blah blah blah blah. The quick brown fox jumped over the lazy dog.\n",
  367.                                     self.get_tag_table().lookup("negative_indent"))
  368.      
  369.         print "%d lines %d chars\n" % (self.get_line_count(),
  370.                                        self.get_char_count())
  371.  
  372.         # Move cursor to start
  373.         iter = self.get_iter_at_offset(0)
  374.         self.place_cursor(iter)
  375.         self.set_modified(False)
  376.  
  377.     def fill_file_buffer(self, filename):
  378.         try:
  379.             f = open(filename, "r")
  380.         except IOError, (errnum, errmsg):
  381.             err = "Cannot open file '%s': %s" % (filename, errmsg)
  382.             view = TestText.active_window_stack.get()
  383.             dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  384.                                        gtk.MESSAGE_INFO,
  385.                                        gtk.BUTTONS_OK, err);
  386.             result = dialog.run()
  387.             dialog.destroy()
  388.             return False
  389.  
  390.         iter = self.get_iter_at_offset(0)
  391.         buf = f.read()
  392.         f.close()
  393.         self.set_text(buf)
  394.         self.set_modified(False)
  395.         return True
  396.  
  397.     def save_buffer(self):
  398.         result = False
  399.         have_backup = False
  400.         if not self.filename:
  401.             return False
  402.  
  403.         bak_filename = self.filename + "~"
  404.         try:
  405.             os.rename(self.filename, bak_filename)
  406.         except (OSError, IOError), (errnum, errmsg):
  407.             if errnum != errno.ENOENT:
  408.                 err = "Cannot back up '%s' to '%s': %s" % (self.filename,
  409.                                                            bak_filename,
  410.                                                            errmsg)
  411.                 view = TestText.active_window_stack.get()
  412.                 dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  413.                                            gtk.MESSAGE_INFO,
  414.                                            gtk.BUTTONS_OK, err);
  415.                 dialog.run()
  416.                 dialog.destroy()
  417.                 return False
  418.  
  419.         have_backup = True
  420.         start, end = self.get_bounds()
  421.         chars = self.get_slice(start, end, False)
  422.         try:
  423.             file = open(self.filename, "w")
  424.             file.write(chars)
  425.             file.close()
  426.             result = True
  427.             self.set_modified(False)
  428.         except IOError, (errnum, errmsg):
  429.             err = "Error writing to '%s': %s" % (self.filename, errmsg)
  430.             view = TestText.active_window_stack.get()
  431.             dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  432.                                        gtk.MESSAGE_INFO,
  433.                                        gtk.BUTTONS_OK, err);
  434.             dialog.run()
  435.             dialog.destroy()
  436.  
  437.         if not result and have_backup:
  438.             try:
  439.                 os.rename(bak_filename, self.filename)
  440.             except OSError, (errnum, errmsg):
  441.                 err = "Can't restore backup file '%s' to '%s': %s\nBackup left as '%s'" % (
  442.                     self.filename, bak_filename, errmsg, bak_filename)
  443.                 view = TestText.active_window_stack.get()
  444.                 dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  445.                                            gtk.MESSAGE_INFO,
  446.                                            gtk.BUTTONS_OK, err);
  447.                 dialog.run()
  448.                 dialog.destroy()
  449.  
  450.         return result
  451.  
  452.     def save_as_ok_func(self, filename):
  453.         old_filename = self.filename
  454.  
  455.         if (not self.filename or filename != self.filename):
  456.             if os.path.exists(filename):
  457.                 err = "Ovewrite existing file '%s'?"  % filename
  458.                 view = TestText.active_window_stack.get()
  459.                 dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  460.                                            gtk.MESSAGE_QUESTION,
  461.                                            gtk.BUTTONS_YES_NO, err);
  462.                 result = dialog.run()
  463.                 dialog.destroy()
  464.                 if result != gtk.RESPONSE_YES:
  465.                     return False
  466.  
  467.         self.filename = filename
  468.  
  469.         if self.save_buffer():
  470.             self.filename_set()
  471.             return True
  472.         else:
  473.             self.filename = old_filename
  474.             return False
  475.  
  476.     def save_as_buffer(self):
  477.         return FileSel().run(self, "Save File", None, self.save_as_ok_func)
  478.  
  479.     def check_buffer_saved(self):
  480.         if self.get_modified():
  481.             pretty_name = self.pretty_name()
  482.             msg = "Save changes to '%s'?" % pretty_name
  483.             view = TestText.active_window_stack.get()
  484.             dialog = gtk.MessageDialog(view, gtk.DIALOG_MODAL,
  485.                                        gtk.MESSAGE_QUESTION,
  486.                                        gtk.BUTTONS_YES_NO, msg);
  487.             dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  488.             result = dialog.run()
  489.             dialog.destroy()
  490.             if result == gtk.RESPONSE_YES:
  491.                 if self.filename:
  492.                     return self.save_buffer()
  493.                 return self.save_as_buffer()
  494.             elif result == gtk.RESPONSE_NO:
  495.                 return True
  496.             else:
  497.                 return False
  498.         else:
  499.             return True
  500.  
  501. class View(gtk.Window):
  502.     def __init__(self, buffer=None):
  503.         menu_items = [
  504.             ( "/_File", None, None, 0, "<Branch>" ),
  505.             ( "/File/_New", "<control>N", self.do_new, 0, None ),
  506.             ( "/File/New _View", None, self.do_new_view, 0, None ),
  507.             ( "/File/_Open", "<control>O", self.do_open, 0, None ),
  508.             ( "/File/_Save", "<control>S", self.do_save, 0, None ),
  509.             ( "/File/Save _As...", None, self.do_save_as, 0, None ),
  510.             ( "/File/sep1", None, None, 0, "<Separator>" ),
  511.             ( "/File/_Close", "<control>W" , self.do_close, 0, None ),
  512.             ( "/File/E_xit", "<control>Q" , self.do_exit, 0, None ),
  513.             ( "/_Edit", None, None, 0, "<Branch>" ),
  514.             ( "/Edit/Find...", None, self.do_search, 0, None ),
  515.             ( "/_Settings", None, None, 0, "<Branch>" ),
  516.             ( "/Settings/Wrap _Off", None, self.do_wrap_changed, gtk.WRAP_NONE, "<RadioItem>" ),
  517.             ( "/Settings/Wrap _Words", None, self.do_wrap_changed, gtk.WRAP_WORD, "/Settings/Wrap Off" ),
  518.             ( "/Settings/Wrap _Chars", None, self.do_wrap_changed, gtk.WRAP_CHAR, "/Settings/Wrap Off" ),
  519.             ( "/Settings/sep1", None, None, 0, "<Separator>" ),
  520.             ( "/Settings/Editable", None, self.do_editable_changed, True, "<RadioItem>" ),
  521.             ( "/Settings/Not editable", None, self.do_editable_changed, False, "/Settings/Editable" ),
  522.             ( "/Settings/sep1", None, None, 0, "<Separator>" ),
  523.             ( "/Settings/Cursor visible", None, self.do_cursor_visible_changed, True, "<RadioItem>" ),
  524.             ( "/Settings/Cursor not visible", None, self.do_cursor_visible_changed, False, "/Settings/Cursor visible" ),
  525.             ( "/Settings/sep1", None, None, 0, "<Separator>" ),
  526.             ( "/Settings/Left-to-Right", None, self.do_direction_changed, gtk.TEXT_DIR_LTR, "<RadioItem>" ),
  527.             ( "/Settings/Right-to-Left", None, self.do_direction_changed, gtk.TEXT_DIR_RTL, "/Settings/Left-to-Right" ),
  528.             ( "/Settings/sep1", None, None, 0, "<Separator>" ),
  529.             ( "/Settings/Sane spacing", None, self.do_spacing_changed, False, "<RadioItem>" ),
  530.             ( "/Settings/Funky spacing", None, self.do_spacing_changed, True, "/Settings/Sane spacing" ),
  531.             ( "/Settings/sep1", None, None, 0, "<Separator>" ),
  532.             ( "/Settings/Don't cycle color tags", None, self.do_color_cycle_changed, False, "<RadioItem>" ),
  533.             ( "/Settings/Cycle colors", None, self.do_color_cycle_changed, True, "/Settings/Don't cycle color tags" ),
  534.             ( "/_Attributes", None, None, 0, "<Branch>" ),
  535.             ( "/Attributes/Editable", None, self.do_apply_editable, True, None ),
  536.             ( "/Attributes/Not editable", None, self.do_apply_editable, False, None ),
  537.             ( "/Attributes/Invisible", None, self.do_apply_invisible, False, None ),
  538.             ( "/Attributes/Visible", None, self.do_apply_invisible, True, None ),
  539.             ( "/Attributes/Custom tabs", None, self.do_apply_tabs, False, None ),
  540.             ( "/Attributes/Default tabs", None, self.do_apply_tabs, True, None ),
  541.             ( "/Attributes/Color cycles", None, self.do_apply_colors, True, None ),
  542.             ( "/Attributes/No colors", None, self.do_apply_colors, False, None ),
  543.             ( "/Attributes/Remove all tags", None, self.do_remove_tags, 0, None ),
  544.             ( "/Attributes/Properties", None, self.do_properties, 0, None ),
  545.             ( "/_Test", None, None, 0, "<Branch>" ),
  546.             ( "/Test/_Example", None, self.do_example, 0, None ),
  547.             ( "/Test/_Insert and scroll", None, self.do_insert_and_scroll, 0, None ),
  548.             ( "/Test/_Add movable children", None, self.do_add_children, 0, None ),
  549.             ( "/Test/A_dd focusable children", None, self.do_add_focus_children, 0, None ),
  550.             ]
  551.  
  552.         if not buffer:
  553.             buffer = Buffer()
  554.         gtk.Window.__init__(self)
  555.  
  556.         TestText.views.push(self)
  557.  
  558.         buffer.ref()
  559.  
  560.         if not TestText.colormap:
  561.             TestText.colormap = self.get_colormap()
  562.  
  563.         self.connect("delete_event", self.delete_event_cb)
  564.  
  565.         self.accel_group = gtk.AccelGroup()
  566.         self.item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>",
  567.                                         self.accel_group)
  568.         self.item_factory.set_data("view", self)
  569.         self.item_factory.create_items(menu_items)
  570.  
  571.         self.add_accel_group(self.accel_group)
  572.  
  573.         vbox = gtk.VBox(False, 0)
  574.         self.add(vbox)
  575.  
  576.         vbox.pack_start(self.item_factory.get_widget("<main>"),
  577.                         False, False, 0)
  578.  
  579.         sw = gtk.ScrolledWindow()
  580.         sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  581.  
  582.         self.text_view = gtk.TextView(buffer)
  583.         self.text_view.set_wrap_mode(gtk.WRAP_WORD)
  584.  
  585.         # Make sure border width works, no real reason to do this other
  586.         # than testing
  587.         self.text_view.set_border_width(10)
  588.  
  589.         # Draw tab stops in the top and bottom windows.
  590.         self.text_view.set_border_window_size(gtk.TEXT_WINDOW_TOP, 15)
  591.         self.text_view.set_border_window_size(gtk.TEXT_WINDOW_BOTTOM, 15)
  592.  
  593.         self.text_view.connect("expose_event", self.tab_stops_expose)
  594.  
  595.         self.bhid = buffer.connect("mark_set", self.cursor_set_callback)
  596.  
  597.         # Draw line numbers in the side windows; we should really be
  598.         # more scientific about what width we set them to.
  599.         self.text_view.set_border_window_size(gtk.TEXT_WINDOW_RIGHT, 30)
  600.         self.text_view.set_border_window_size(gtk.TEXT_WINDOW_LEFT, 30)
  601.  
  602.         self.text_view.connect("expose_event", self.line_numbers_expose)
  603.  
  604.         vbox.pack_start(sw, True, True, 0)
  605.         sw.add(self.text_view)
  606.  
  607.         self.set_default_size(500, 500)
  608.         self.text_view.grab_focus()
  609.  
  610.         self.set_view_title()
  611.         self.init_menus()
  612.         self.add_example_widgets()
  613.  
  614.         self.show_all()
  615.  
  616.     def delete_event_cb(self, window, event, data=None):
  617.         TestText.active_window_stack.push(self)
  618.         self.check_close_view()
  619.         TestText.active_window_stack.pop()
  620.         return True
  621.     #
  622.     # Menu callbacks
  623.     #
  624.     def get_empty_view(self):
  625.         buffer = self.text_view.get_buffer()
  626.         if (not buffer.filename and not buffer.get_modified()):
  627.             return self
  628.         else:
  629.             return View(Buffer())
  630.  
  631.     def view_from_widget(widget):
  632.         if isinstance(widget, gtk.MenuItem):
  633.             item_factory = gtk.item_factory_from_widget(widget)
  634.             return item_factory.get_data("view")
  635.         else:
  636.             app = widget.get_toplevel()
  637.             return app.get_data("view")
  638.  
  639.     def do_new(self, callback_action, widget):
  640.         View()
  641.  
  642.     def do_new_view(self, callback_action, widget):
  643.         View(self.text_view.get_buffer())
  644.  
  645.     def open_ok_func(self, filename):
  646.         new_view = self.get_empty_view()
  647.         buffer = new_view.text_view.get_buffer()
  648.         if not buffer.fill_file_buffer(filename):
  649.             if new_view != self:
  650.                 new_view.close_view()
  651.             return False
  652.         else:
  653.             buffer.filename = filename
  654.             buffer.filename_set()
  655.             return True;
  656.  
  657.     def do_open(self, callback_action, widget):
  658.         FileSel().run(self, "Open File", None, self.open_ok_func)
  659.  
  660.     def do_save_as(self, callback_action, widget):
  661.         TestText.active_window_stack.push(self)
  662.         self.text_view.get_buffer().save_as_buffer()
  663.         TestText.active_window_stack.pop()
  664.  
  665.     def do_save(self, callback_action, widget):
  666.         TestText.active_window_stack.push(self)
  667.         buffer = self.text_view.get_buffer()
  668.         if not buffer.filename:
  669.             self.do_save_as(callback_data, callback_action)
  670.         else:
  671.             buffer.save_buffer()
  672.             TestText.active_window_stack.pop()
  673.  
  674.     def do_close(self, callback_action, widget):
  675.         TestText.active_window_stack.push(self)
  676.         self.check_close_view()
  677.         TestText.active_window_stack.pop()
  678.  
  679.     def do_exit(self, callback_action, widget):
  680.         TestText.active_window_stack.push(self)
  681.         for tmp in TestText.buffers:
  682.             if not tmp.check_buffer_saved():
  683.                 return
  684.  
  685.         gtk.main_quit()
  686.         TestText.active_window_stack.pop()
  687.  
  688.     def do_example(self, callback_action, widget):
  689.         new_view = self.get_empty_view()
  690.         buffer = new_view.text_view.get_buffer()
  691.         buffer.fill_example_buffer()
  692.  
  693.         new_view.add_example_widgets()
  694.  
  695.     def do_insert_and_scroll(self, callback_action, widget):
  696.         buffer = self.text_view.get_buffer()
  697.  
  698.         start, end = buffer.get_bounds()
  699.         mark = buffer.create_mark(None, end, False)
  700.  
  701.         buffer.insert(end,
  702.                       "Hello this is multiple lines of text\n"
  703.                       "Line 1\n"  "Line 2\n"
  704.                       "Line 3\n"  "Line 4\n"
  705.                       "Line 5\n")
  706.  
  707.         self.text_view.scroll_to_mark(mark, 0, True, 0.0, 1.0)
  708.         buffer.delete_mark(mark)
  709.  
  710.     def do_wrap_changed(self, callback_action, widget):
  711.         self.text_view.set_wrap_mode(callback_action)
  712.  
  713.     def do_direction_changed(self, callback_action, widget):
  714.         self.text_view.set_direction(callback_action)
  715.         self.text_view.queue_resize()
  716.  
  717.     def do_spacing_changed(self, callback_action, widget):
  718.         if callback_action:
  719.             self.text_view.set_pixels_above_lines(23)
  720.             self.text_view.set_pixels_below_lines(21)
  721.             self.text_view.set_pixels_inside_wrap(9)
  722.         else:
  723.             self.text_view.set_pixels_above_lines(0)
  724.             self.text_view.set_pixels_below_lines(0)
  725.             self.text_view.set_pixels_inside_wrap(0)
  726.  
  727.     def do_editable_changed(self, callback_action, widget):
  728.         self.text_view.set_editable(callback_action)
  729.  
  730.     def do_cursor_visible_changed(self, callback_action, widget):
  731.         self.text_view.set_cursor_visible(callback_action)
  732.  
  733.     def do_color_cycle_changed(self, callback_action, widget):
  734.         self.text_view.get_buffer().set_colors(callback_action)
  735.  
  736.     def do_apply_editable(self, callback_action, widget):
  737.         buffer = self.text_view.get_buffer()
  738.         bounds = buffer.get_selection_bounds()
  739.         if bounds:
  740.             start, end = bounds
  741.             if callback_action:
  742.                 buffer.remove_tag(buffer.not_editable_tag, start, end)
  743.             else:
  744.                 buffer.apply_tag(buffer.not_editable_tag, start, end)
  745.  
  746.     def do_apply_invisible(self, callback_action, widget):
  747.         buffer = self.text_view.get_buffer()
  748.         bounds = buffer.get_selection_bounds()
  749.         if bounds:
  750.             start, end = bounds
  751.             if callback_action:
  752.                 buffer.remove_tag(buffer.invisible_tag, start, end)
  753.             else:
  754.                 buffer.apply_tag(buffer.invisible_tag, start, end)
  755.  
  756.     def do_apply_tabs(self, callback_action, widget):
  757.         buffer = self.text_view.get_buffer()
  758.         bounds = buffer.get_selection_bounds()
  759.         if bounds:
  760.             start, end = bounds
  761.             if callback_action:
  762.                 buffer.remove_tag(buffer.custom_tabs_tag, start, end)
  763.             else:
  764.                 buffer.apply_tag(buffer.custom_tabs_tag, start, end)
  765.  
  766.     def do_apply_colors(self, callback_action, widget):
  767.         buffer = self.text_view.get_buffer()
  768.         bounds = buffer.get_selection_bounds()
  769.         if bounds:
  770.             start, end = bounds
  771.             if not callback_action:
  772.                 for tag in buffer.color_tags:
  773.                     buffer.remove_tag(tag, start, end)
  774.             else:
  775.                 tmp = buffer.color_tags
  776.                 i = 0
  777.                 next = start.copy()
  778.                 while next.compare(end) < 0:
  779.                     next.forward_chars(2)
  780.                     if next.compare(end) >= 0:
  781.                         next = end
  782.  
  783.                     buffer.apply_tag(tmp[i], start, next)
  784.                     i += 1
  785.                     if i >= len(tmp):
  786.                         i = 0
  787.                     start = next.copy()
  788.  
  789.     def do_remove_tags(self, callback_action, widget):
  790.         buffer = self.text_view.get_buffer()
  791.         bounds = buffer.get_selection_bounds()
  792.         if bounds:
  793.             start, end = bounds
  794.             buffer.remove_all_tags(start, end)
  795.  
  796.     def do_properties(self, callback_action, widget):
  797.         #create_prop_editor(view.text_view, 0)
  798.         pass
  799.  
  800.     def dialog_response_callback(self, dialog, response_id):
  801.         if (response_id != RESPONSE_FORWARD and
  802.             response_id != RESPONSE_BACKWARD):
  803.             dialog.destroy()
  804.             return
  805.  
  806.         start, end = dialog.buffer.get_bounds()
  807.         search_string = start.get_text(end)
  808.  
  809.         print "Searching for `%s'\n" % search_string
  810.  
  811.         buffer = self.text_view.get_buffer()
  812.         if response_id == RESPONSE_FORWARD:
  813.             buffer.search_forward(search_string, self)
  814.         elif response_id == RESPONSE_BACKWARD:
  815.             buffer.search_backward(search_string, self)
  816.    
  817.         dialog.destroy()
  818.  
  819.     def do_search(self, callback_action, widget):
  820.         search_text = gtk.TextView()
  821.         dialog = gtk.Dialog("Search", self,
  822.                             gtk.DIALOG_DESTROY_WITH_PARENT,
  823.                             ("Forward", RESPONSE_FORWARD,
  824.                              "Backward", RESPONSE_BACKWARD,
  825.                              gtk.STOCK_CANCEL, gtk.RESPONSE_NONE))
  826.         dialog.vbox.pack_end(search_text, True, True, 0)
  827.         dialog.buffer = search_text.get_buffer()
  828.         dialog.connect("response", self.dialog_response_callback)
  829.  
  830.         search_text.show()
  831.         search_text.grab_focus()
  832.         dialog.show_all()
  833.  
  834.     def movable_child_callback(self, child, event):
  835.         text_view = self.text_view
  836.         info = child.get_data("testtext-move-info")
  837.  
  838.         if not info:
  839.             info = {}
  840.             info['start_x'] = -1
  841.             info['start_y'] = -1
  842.             info['button'] = -1
  843.             child.set_data("testtext-move-info", info)
  844.  
  845.         if event.type == gtk.gdk.BUTTON_PRESS:
  846.             if info['button'] < 0:
  847.                 info['button'] = event.button
  848.                 info['start_x'] = child.allocation.x
  849.                 info['start_y'] = child.allocation.y
  850.                 info['click_x'] = child.allocation.x + event.x
  851.                 info['click_y'] = child.allocation.y + event.y
  852.         elif event.type == gtk.gdk.BUTTON_RELEASE:
  853.             if info['button'] < 0:
  854.                 return False
  855.  
  856.             if info['button'] == event.button:
  857.                 info['button'] = -1;
  858.                 # convert to window coords from event box coords
  859.                 x = info['start_x'] + (event.x + child.allocation.x \
  860.                                        - info['click_x'])
  861.                 y = info['start_y'] + (event.y + child.allocation.y \
  862.                                        - info['click_y'])
  863.                 text_view.move_child(child, x, y)
  864.         elif gtk.gdk.MOTION_NOTIFY:
  865.             if info['button'] < 0:
  866.                 return False
  867.             x, y = child.get_pointer() # ensure more events
  868.             # to window coords from event box coords
  869.             x += child.allocation.x
  870.             y += child.allocation.y
  871.             x = info['start_x'] + (x - info['click_x'])
  872.             y = info['start_y'] + (y - info['click_y'])
  873.             text_view.move_child(child, x, y)
  874.  
  875.         return False
  876.  
  877.     def add_movable_child(self, text_view, window):
  878.         label = gtk.Label("Drag me around")  
  879.  
  880.         event_box = gtk.EventBox()
  881.         event_box.add_events(gtk.gdk.BUTTON_PRESS_MASK |
  882.                              gtk.gdk.BUTTON_RELEASE_MASK |
  883.                              gtk.gdk.POINTER_MOTION_MASK |
  884.                              gtk.gdk.POINTER_MOTION_HINT_MASK)
  885.  
  886.         color = TestText.colormap.alloc_color(0xffff, 0, 0)
  887.         event_box.modify_bg(gtk.STATE_NORMAL, color)
  888.         event_box.add(label)
  889.         event_box.show_all()
  890.  
  891.         event_box.connect("event", self.movable_child_callback)
  892.  
  893.         text_view.add_child_in_window(event_box, window, 0, 0)
  894.  
  895.     def do_add_children(self, callback_action, widget):
  896.         text_view = self.text_view
  897.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_WIDGET)
  898.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_LEFT)
  899.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_RIGHT)
  900.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_TEXT)
  901.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_TOP)
  902.         self.add_movable_child(text_view, gtk.TEXT_WINDOW_BOTTOM)
  903.  
  904.     def do_add_focus_children(self, callback_action, widget):
  905.         text_view = self.text_view
  906.  
  907.         child = gtk.EventBox()
  908.         b = gtk.Button("Button _A in widget.window")
  909.         child.add(b)
  910.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_WIDGET, 0, 200)
  911.  
  912.         child = gtk.EventBox()
  913.         b = gtk.Button("Button _B in text.window")
  914.         child.add(b)
  915.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_TEXT, 50, 50)
  916.  
  917.         child = gtk.EventBox()
  918.         b = gtk.Button("Button _T in top window")
  919.         child.add(b)
  920.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_TOP, 100, 0)
  921.  
  922.         child = gtk.EventBox()
  923.         b = gtk.Button("Button _W in bottom window")
  924.         child.add(b)
  925.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_BOTTOM, 100, 0)
  926.  
  927.         child = gtk.EventBox()
  928.         b = gtk.Button("Button _C in left window")
  929.         child.add(b)
  930.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_LEFT, 0, 50)
  931.  
  932.         child = gtk.EventBox()
  933.         b = gtk.Button("Button _D in right window")
  934.         child.add(b)
  935.         text_view.add_child_in_window(child, gtk.TEXT_WINDOW_RIGHT, 0, 25)
  936.  
  937.         buffer = text_view.get_buffer()
  938.         iter = buffer.get_start_iter()
  939.         anchor = buffer.create_child_anchor(iter)
  940.         child = gtk.Button("Button _E in buffer")
  941.         text_view.add_child_at_anchor(child, anchor)
  942.  
  943.         anchor = buffer.create_child_anchor(iter)
  944.         child = gtk.Button("Button _F in buffer")
  945.         text_view.add_child_at_anchor(child, anchor)
  946.  
  947.         anchor = buffer.create_child_anchor(iter)
  948.         child = gtk.Button("Button _G in buffer")
  949.         text_view.add_child_at_anchor(child, anchor)
  950.  
  951.         # show all the buttons
  952.         text_view.show_all()
  953.  
  954.     def init_menus(self):
  955.         text_view = self.text_view
  956.         direction = text_view.get_direction()
  957.         wrap_mode = text_view.get_wrap_mode()
  958.         menu_item = None
  959.  
  960.         if direction == gtk.TEXT_DIR_LTR:
  961.             menu_item = self.item_factory.get_widget("/Settings/Left-to-Right")
  962.         elif direction == gtk.TEXT_DIR_RTL:
  963.             menu_item = self.item_factory.get_widget("/Settings/Right-to-Left")
  964.  
  965.         if menu_item:
  966.             menu_item.activate()
  967.  
  968.         if wrap_mode == gtk.WRAP_NONE:
  969.             menu_item = self.item_factory.get_widget("/Settings/Wrap Off")
  970.         elif wrap_mode == gtk.WRAP_WORD:
  971.             menu_item = self.item_factory.get_widget("/Settings/Wrap Words")
  972.         elif wrap_mode == gtk.WRAP_CHAR:
  973.             menu_item = self.item_factory.get_widget("/Settings/Wrap Chars")
  974.  
  975.         if menu_item:
  976.             menu_item.activate()
  977.  
  978.     def close_view(self):
  979.         TestText.views.remove(self)
  980.         buffer = self.text_view.get_buffer()
  981.         buffer.unref()
  982.         buffer.disconnect(self.bhid)
  983.         self.text_view.destroy()
  984.         del self.text_view
  985.         self.text_view = None
  986.         self.destroy()
  987.         del self
  988.         if not TestText.views:
  989.             gtk.main_quit()
  990.  
  991.     def check_close_view(self):
  992.         buffer = self.text_view.get_buffer()
  993.         if (buffer.refcount > 1 or
  994.             buffer.check_buffer_saved()):
  995.             self.close_view()
  996.  
  997.     def set_view_title(self):
  998.         pretty_name = self.text_view.get_buffer().pretty_name()
  999.         title = "testtext - " + pretty_name
  1000.         self.set_title(title)
  1001.  
  1002.     def cursor_set_callback(self, buffer, location, mark):
  1003.         # Redraw tab windows if the cursor moves
  1004.         # on the mapped widget (windows may not exist before realization...
  1005.  
  1006.         text_view = self.text_view
  1007.         if mark == buffer.get_insert():
  1008.             tab_window = text_view.get_window(gtk.TEXT_WINDOW_TOP)
  1009.             tab_window.invalidate_rect(None, False)
  1010.             #tab_window.invalidate_rect(tab_window.get_geometry()[:4], False)
  1011.      
  1012.             tab_window = text_view.get_window(gtk.TEXT_WINDOW_BOTTOM)
  1013.             tab_window.invalidate_rect(None, False)
  1014.             #tab_window.invalidate_rect(tab_window.get_geometry()[:4], False)
  1015.  
  1016.     def tab_stops_expose(self, widget, event):
  1017.         #print self, widget, event
  1018.         text_view = widget
  1019.  
  1020.         # See if this expose is on the tab stop window
  1021.         top_win = text_view.get_window(gtk.TEXT_WINDOW_TOP)
  1022.         bottom_win = text_view.get_window(gtk.TEXT_WINDOW_BOTTOM)
  1023.  
  1024.         if event.window == top_win:
  1025.             type = gtk.TEXT_WINDOW_TOP
  1026.             target = top_win
  1027.         elif event.window == bottom_win:
  1028.             type = gtk.TEXT_WINDOW_BOTTOM
  1029.             target = bottom_win
  1030.         else:
  1031.             return False
  1032.  
  1033.         first_x = event.area.x
  1034.         last_x = first_x + event.area.width
  1035.  
  1036.         first_x, y = text_view.window_to_buffer_coords(type, first_x, 0)
  1037.         last_x, y = text_view.window_to_buffer_coords(type, last_x, 0)
  1038.  
  1039.         buffer = text_view.get_buffer()
  1040.         insert = buffer.get_iter_at_mark(buffer.get_insert())
  1041.         attrs = gtk.TextAttributes()
  1042.         insert.get_attributes(attrs)
  1043.  
  1044.         tabslist = []
  1045.         in_pixels = False
  1046.         if attrs.tabs:
  1047.             tabslist = attrs.tabs.get_tabs()
  1048.             in_pixels = attrs.tabs.get_positions_in_pixels()
  1049.      
  1050.         for align, position in tabslist:
  1051.             if not in_pixels:
  1052.                 position = pango.PIXELS(position)
  1053.      
  1054.             pos, y = text_view.buffer_to_window_coords(type, position, 0)
  1055.             target.draw_line(text_view.style.fg_gc[text_view.state],
  1056.                              pos, 0, pos, 15)
  1057.  
  1058.         return True
  1059.  
  1060.     def get_lines(self, first_y, last_y, buffer_coords, numbers):
  1061.         text_view = self.text_view
  1062.         # Get iter at first y
  1063.         iter, top = text_view.get_line_at_y(first_y)
  1064.  
  1065.         # For each iter, get its location and add it to the arrays.
  1066.         # Stop when we pass last_y
  1067.         count = 0
  1068.         size = 0
  1069.  
  1070.         while not iter.is_end():
  1071.             y, height = text_view.get_line_yrange(iter)
  1072.             buffer_coords.append(y)
  1073.             line_num = iter.get_line()
  1074.             numbers.append(line_num)
  1075.             count += 1
  1076.             if (y + height) >= last_y:
  1077.                 break
  1078.             iter.forward_line()
  1079.  
  1080.         return count
  1081.  
  1082.     def line_numbers_expose(self, widget, event, user_data=None):
  1083.         text_view = widget
  1084.  
  1085.         # See if this expose is on the line numbers window
  1086.         left_win = text_view.get_window(gtk.TEXT_WINDOW_LEFT)
  1087.         right_win = text_view.get_window(gtk.TEXT_WINDOW_RIGHT)
  1088.  
  1089.         if event.window == left_win:
  1090.             type = gtk.TEXT_WINDOW_LEFT
  1091.             target = left_win
  1092.         elif event.window == right_win:
  1093.             type = gtk.TEXT_WINDOW_RIGHT
  1094.             target = right_win
  1095.         else:
  1096.             return False
  1097.  
  1098.         first_y = event.area.y
  1099.         last_y = first_y + event.area.height
  1100.  
  1101.         x, first_y = text_view.window_to_buffer_coords(type, 0, first_y)
  1102.         x, last_y = text_view.window_to_buffer_coords(type, 0, last_y)
  1103.  
  1104.         numbers = []
  1105.         pixels = []
  1106.         count = self.get_lines(first_y, last_y, pixels, numbers)
  1107.  
  1108.         # Draw fully internationalized numbers!
  1109.         layout = widget.create_pango_layout("")
  1110.  
  1111.         for i in range(count):
  1112.             x, pos = text_view.buffer_to_window_coords(type, 0, pixels[i])
  1113.             str = "%d" % numbers[i]
  1114.             layout.set_text(str)
  1115.             widget.style.paint_layout(target, widget.state, False,
  1116.                                       None, widget, None, 2, pos + 2, layout)
  1117.  
  1118.         # don't stop emission, need to draw children
  1119.         return False
  1120.  
  1121.     def add_example_widgets(self):
  1122.         buffer = self.text_view.get_buffer()
  1123.  
  1124.         anchor = buffer.get_data("anchor")
  1125.  
  1126.         if (anchor and not anchor.get_deleted()):
  1127.             widget = gtk.Button("Foo")
  1128.             self.text_view.add_child_at_anchor(widget, anchor)
  1129.             widget.show()
  1130.  
  1131. class Stack(list):
  1132.     def __init__(self):
  1133.         list.__init__(self)
  1134.  
  1135.     def push(self, item):
  1136.         self.insert(-1, item)
  1137.  
  1138.     def pop(self):
  1139.         del self[0]
  1140.  
  1141.     def get(self):
  1142.         return self[0]
  1143.    
  1144. class TestText:
  1145.     untitled_serial = 1
  1146.     colormap = None
  1147.     active_window_stack = Stack()
  1148.     buffers = Stack()
  1149.     views = Stack()
  1150.  
  1151.     def __init__(self, filelist):
  1152.         view = View()
  1153.         self.active_window_stack.push(view)
  1154.         for fname in filelist:
  1155.             filename = os.path.abspath(fname)
  1156.             view.open_ok_func(filename)
  1157.         self.active_window_stack.pop()
  1158.  
  1159.     def main(self):
  1160.         gtk.main()
  1161.         return 0
  1162.  
  1163. if __name__ == "__main__":
  1164.     testtext = TestText(sys.argv[1:])
  1165.     testtext.main()