diff options
Diffstat (limited to 'examples/pygtk-demo/pygtk-demo.py')
-rw-r--r-- | examples/pygtk-demo/pygtk-demo.py | 279 |
1 files changed, 220 insertions, 59 deletions
diff --git a/examples/pygtk-demo/pygtk-demo.py b/examples/pygtk-demo/pygtk-demo.py index d4f938b0..282a14d2 100644 --- a/examples/pygtk-demo/pygtk-demo.py +++ b/examples/pygtk-demo/pygtk-demo.py @@ -1,76 +1,186 @@ #!/usr/bin/env python -import string +''' + $Id$ -import pygtk -pygtk.require('2.0') + pygtk-demo.py + 2004-07-18: Some enhancements for building the demolist like in gtk-demos of the + gtk+ distribution. + 2004-07-22: Simple syntaxhighlighting implemented, based on the tokenizer-module. +''' +import string +import re +try: + import pygtk + pygtk.require('2.0') +except ImportError: + pass import gobject import gtk -from gtk import TRUE, FALSE +import pango + +# use for simple syntax highlighting ;-) +import tokenize +import keyword import demos +D_TEMPL = '%sDemo' + +# Some programmatic definition for the testgtk_demos list. This avoids extra +# maintenance if the demo list grows up. The current definition requires +# a class or function with a swapped case name+'Demo' like in the doc string. +# Swapped case is build from the __doc__-string programatically. +child_demos = {} +testgtk_demos = [] +for descr, mod in demos.demo_list: + # Find some categorized demos + try: + main, child = descr.split('/') + except ValueError: + # No, only one application + demo_class = D_TEMPL % re.sub('(\S+) *', + lambda m:(m.group(1)[0].isupper() and m.group(1) or m.group(1).capitalize()), + descr) + testgtk_demos.append((descr, mod, demo_class)) + else: + # Ok. Some more testing + demo_class = D_TEMPL % re.sub('(\S+) *', + lambda m:(m.group(1)[0].isupper() and m.group(1) or m.group(1).capitalize()), + child) + try: + # Applicationgroup already defined? + child_demos[main.upper()].append((child, mod, demo_class)) + except KeyError: + # No. Start a new category + child_demos.setdefault(main.upper(), []).append((child, mod, demo_class)) + testgtk_demos.append((main, None, None, child_demos[main.upper()])) + +( + TITLE_COLUMN, + MODULE_COLUMN, + FUNC_COLUMN, + ITALIC_COLUMN +) = range(4) + +CHILDREN_COLUMN = 3 + +class InputStream(object): + ''' Simple Wrapper for File-like objects. [c]StringIO doesn't provide + a readline function for use with generate_tokens. + Using a iterator-like interface doesn't succeed, because the readline + function isn't used in such a context. (see <python-lib>/tokenize.py) + ''' + def __init__(self, data): + self.__data = [ '%s\n' % x for x in data.splitlines() ] + self.__lcount = 0 + def readline(self): + try: + line = self.__data[self.__lcount] + self.__lcount += 1 + except IndexError: + line = '' + self.__lcount = 0 + return line -TITLE_COLUMN = 0 -MODULE_COLUMN = 1 class PyGtkDemo(gtk.Window): info_buffer = None source_buffer = None + module_cache = {} + def __init__(self): gtk.Window.__init__(self) + self.set_title("PyGTK+ Code Demos") self.connect('destroy', lambda w: gtk.main_quit()) - self.set_default_size(600, 400) + self.set_default_size(800, 400) - hbox = gtk.HBox(FALSE, 3) + hbox = gtk.HBox(False, 3) self.add(hbox) - treeview = self.create_treeview() - hbox.pack_start(treeview, expand=FALSE) + treeview = self.__create_treeview() + hbox.pack_start(treeview, False, False) self.notebook = gtk.Notebook() - hbox.pack_start(self.notebook, expand=TRUE) - - scrolled_window, self.info_buffer = self.create_text(FALSE) + hbox.pack_start(self.notebook, expand=True) + + scrolled_window, self.info_buffer = self.__create_text(False) self._new_notebook_page(scrolled_window, '_Info') tag = self.info_buffer.create_tag('title') tag.set_property('font', 'Sans 18') - - scrolled_window, self.source_buffer = self.create_text(TRUE) + + scrolled_window, self.source_buffer = self.__create_text(True) self._new_notebook_page(scrolled_window, '_Source') tag = self.source_buffer.create_tag('source') - tag.set_property('font', 'Courier 10') + tag.set_property('font', 'monospace') tag.set_property('pixels_above_lines', 0) tag.set_property('pixels_below_lines', 0) + tag = self.source_buffer.create_tag('keyword', foreground='#00007F', + weight=pango.WEIGHT_BOLD) + tag = self.source_buffer.create_tag('string', foreground='#7F007F') + tag = self.source_buffer.create_tag('comment', foreground='#007F00', + style=pango.STYLE_ITALIC) + + self.show_all() + + def run(self): + gtk.main() def _new_notebook_page(self, widget, label): l = gtk.Label('') l.set_text_with_mnemonic(label) self.notebook.append_page(widget, l) - def create_treeview(self): - model = gtk.ListStore(gobject.TYPE_STRING, - gobject.TYPE_STRING) - + def __create_treeview(self): + model = gtk.TreeStore( + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN + ) + treeview = gtk.TreeView(model) - treeview.connect('row-activated', self.row_activated_cb) selection = treeview.get_selection() - selection.set_mode('single') + selection.set_mode(gtk.SELECTION_BROWSE) treeview.set_size_request(200, -1) - - for title, module in demos.demos: - iter = model.append() - model.set_value(iter, TITLE_COLUMN, title) - model.set_value(iter, MODULE_COLUMN, module) + + for module in testgtk_demos: + iter = model.append(None) + model.set(iter, + TITLE_COLUMN, module[TITLE_COLUMN], + MODULE_COLUMN, module[MODULE_COLUMN], + FUNC_COLUMN, module[FUNC_COLUMN], + ITALIC_COLUMN, False + ) + + try: + children = module[CHILDREN_COLUMN] + for child_module in children: + child_iter = model.append(iter) + model.set(child_iter, + TITLE_COLUMN, child_module[TITLE_COLUMN], + MODULE_COLUMN, child_module[MODULE_COLUMN], + FUNC_COLUMN, child_module[FUNC_COLUMN], + ITALIC_COLUMN, False + ) + except IndexError: + pass cell = gtk.CellRendererText() - column = gtk.TreeViewColumn("Widget", cell, text=TITLE_COLUMN) + cell.set_property('style', pango.STYLE_ITALIC) + + column = gtk.TreeViewColumn("Widget (double click for demo)", cell, + text=TITLE_COLUMN, style_set=ITALIC_COLUMN) + treeview.append_column(column) selection.connect('changed', self.selection_changed_cb) - self.model = model + treeview.connect('row-activated', self.row_activated_cb) + + treeview.expand_all() + return treeview - - def create_text(self, is_source=FALSE): + + def __create_text(self, is_source=False): scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.set_shadow_type(gtk.SHADOW_IN) @@ -80,36 +190,55 @@ class PyGtkDemo(gtk.Window): buffer = gtk.TextBuffer(None) text_view.set_buffer(buffer) - text_view.set_editable(FALSE) - text_view.set_cursor_visible(FALSE) + text_view.set_editable(False) + text_view.set_cursor_visible(False) text_view.set_wrap_mode(not is_source) return scrolled_window, buffer - def row_activated_cb(self, treeview, row, column): - iter = self.model.get_iter(row) - module_name = self.model.get_value(iter, MODULE_COLUMN) - module = getattr(demos, module_name) - module.main() - + def row_activated_cb(self, treeview, path, column): + model = treeview.get_model() + iter = model.get_iter(path) + module_name = model.get_value(iter, MODULE_COLUMN) + func_name = model.get_value(iter, FUNC_COLUMN) + italic_value = model.get_value(iter, ITALIC_COLUMN) + try: + self.module_cache[module_name].present() + except KeyError: + module = getattr(demos, module_name) + model.set(iter, ITALIC_COLUMN, not italic_value) + cmd = 'demos.%s.%s' % (module_name, func_name) + #print cmd + window = eval(cmd)(self) + if window: + window.connect('destroy', self.window_closed_cb, model, path) + self.module_cache[module_name] = window + def selection_changed_cb(self, selection): - selection = selection.get_selected() - if not selection: - return - - model, iter = selection + model, iter = selection.get_selected() + if not iter: + return False name = model.get_value(iter, MODULE_COLUMN) self.load_module(name) + def window_closed_cb (self, window, model, path): + iter = model.get_iter(path) + module_name = model.get_value(iter, MODULE_COLUMN) + del self.module_cache[module_name] + italic_value = model.get_value(iter, ITALIC_COLUMN) + if italic_value: + model.set(iter, ITALIC_COLUMN, not italic_value) + + def read_module(self, module): filename = module.__file__ if filename[-4:] == '.pyc': filename = filename[:-1] fd = open(filename) return fd.read() - + def insert_documentation(self, module): buffer = self.info_buffer iter = buffer.get_iter_at_offset(0) @@ -133,25 +262,57 @@ class PyGtkDemo(gtk.Window): def insert_source(self, data): source_buffer = self.source_buffer iter = source_buffer.get_iter_at_offset(0) - source_buffer.insert(iter, data) - - start = source_buffer.get_iter_at_offset(0) - source_buffer.apply_tag_by_name('source', start, iter) - + + last_erow, last_ecol = 0, 0 + was_newline = False # multiline statement detection + for x in tokenize.generate_tokens(InputStream(data).readline): + # x has 5-tuples + tok_type, tok_str = x[0], x[1] + srow, scol = x[2] + erow, ecol = x[3] + + # The tokenizer 'eats' the whitespaces, so we have to insert this again + # if needed. + if srow == last_erow: + # Same line, spaces between statements + if scol != last_ecol: + source_buffer.insert_with_tags_by_name(iter, ' '*(scol-last_ecol), 'source') + else: + # New line. + # First: Detect multiline statements. There is no special in the tokenizer stream. + if was_newline is False and last_erow != 0: + source_buffer.insert_with_tags_by_name(iter, ' \\\n', 'source') + # new line check if it starts with col 0 + if scol != 0: + source_buffer.insert_with_tags_by_name(iter, ' '*scol, 'source') + last_erow = erow + last_ecol = ecol + + if tok_type == tokenize.COMMENT: + was_newline = True # newline is in tok_str included. + source_buffer.insert_with_tags_by_name(iter, tok_str, 'source', 'comment') + continue + elif tok_type == tokenize.NAME: + if tok_str in keyword.kwlist: + source_buffer.insert_with_tags_by_name(iter, tok_str, 'source', 'keyword') + continue + elif tok_type == tokenize.STRING: + source_buffer.insert_with_tags_by_name(iter, tok_str, 'source', 'string') + continue + + # No special format for use. Check for newline. + was_newline = tok_type in (tokenize.NEWLINE, tokenize.NL) + source_buffer.insert_with_tags_by_name(iter, tok_str, 'source') + def load_module(self, name): self.clear_buffers() - + if name is None: return module = getattr(demos, name) if module.__doc__: self.insert_documentation(module) - + source = self.read_module(module) self.insert_source(source) - -d = PyGtkDemo() -d.show_all() - -gtk.main() -#if __name__ == '__main__': -# main() +if __name__ == '__main__': + PyGtkDemo().run() |