diff options
author | John Finlay <finlay@src.gnome.org> | 2004-10-01 23:35:38 +0000 |
---|---|---|
committer | John Finlay <finlay@src.gnome.org> | 2004-10-01 23:35:38 +0000 |
commit | f0c4fccb74b1876073604e6367ddb7449af295ef (patch) | |
tree | 22cde104cfadaddd481c6242502d48ceca2d4322 | |
parent | f5debbde7c331fb13e1ffe154cf5f582a8707959 (diff) | |
download | pygtk-f0c4fccb74b1876073604e6367ddb7449af295ef.tar.gz |
examples/pygtk-demo/* Replace the pygtk-demo with the new version written
* examples/pygtk-demo/* Replace the pygtk-demo with the new
version written by Maik Hertha. Fixes #138823.
39 files changed, 3999 insertions, 1775 deletions
@@ -1,3 +1,8 @@ +2004-10-01 John Finlay <finlay@moeraki.com> + + * examples/pygtk-demo/* Replace the pygtk-demo with the new + version written by Maik Hertha. Fixes #138823. + 2004-09-27 John Ehresman <jpe@wingide.com> * gobject/gobjectmodule.c (pyg_enable_threads): Allow gtk_main to diff --git a/examples/pygtk-demo/demos/__init__.py b/examples/pygtk-demo/demos/__init__.py index ee3fc5e7..44028ca4 100644 --- a/examples/pygtk-demo/demos/__init__.py +++ b/examples/pygtk-demo/demos/__init__.py @@ -1,18 +1,24 @@ import os -_modlist = filter(lambda x: len(x) > 3 and x[-3:] == '.py', - os.listdir(os.path.dirname(__file__))) +_file_list = [ + x for x in os.listdir(os.path.dirname(__file__)) + if len(x) > 3 and x[-3:] == '.py'] -demos = [] -for _mod in _modlist: - if _mod[0] != '_': - _mod = _mod[:-3] - try: - exec 'import ' + _mod + '\n' + \ - '_description = ' + _mod + '.description' - demos.append((_description, _mod)) - except: - pass -demos.sort() +demo_list = [] +for _mod in _file_list: + # Leave underscored Modulnames. + if _mod.startswith('_'): + continue + _mod = _mod[:-3] + try: + exec 'import ' + _mod + '\n' + \ + '_doc = ' + _mod + '.__doc__' + _description = _doc.splitlines()[0] + demo_list.append((_description, _mod)) + except (ImportError, AttributeError), msg: + # ImportError or AttributeError (if _doc is None) + #print 'failed: ', _mod + pass +demo_list.sort() diff --git a/examples/pygtk-demo/demos/appwindow.py b/examples/pygtk-demo/demos/appwindow.py index 7e96b635..c12b5b2b 100644 --- a/examples/pygtk-demo/demos/appwindow.py +++ b/examples/pygtk-demo/demos/appwindow.py @@ -1,180 +1,297 @@ #!/usr/bin/env python -"""Application main window +'''Application main window -Demonstrates a typical application window, with menubar, toolbar, statusbar.""" - -description = 'Application main window' +Demonstrates a typical application window, with menubar, toolbar, statusbar.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> +import gobject import gtk -def menuitem_cb(window, action, widget): - dialog = gtk.MessageDialog(window, gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, - 'You selected or toggled the menu item: ' - '"%s"' % (gtk.item_factory_path_from_widget(widget),)) - dialog.connect('response', lambda dialog, response: dialog.destroy()) - dialog.show() - -menu_items = ( - ('/_File', None, None, 0, '<Branch>' ), - ('/File/tearoff1', None, menuitem_cb, 0, '<Tearoff>'), - ('/File/_New', '<control>N', menuitem_cb, 0, '<StockItem>', gtk.STOCK_NEW), - ('/File/_Open', '<control>O', menuitem_cb, 0, '<StockItem>', gtk.STOCK_OPEN), - ('/File/_Save', '<control>S', menuitem_cb, 0, '<StockItem>', gtk.STOCK_SAVE), - ('/File/Save _As...', None, menuitem_cb, 0, '<StockItem>', gtk.STOCK_SAVE), - ('/File/sep1', None, menuitem_cb, 0, '<Separator>'), - ('/File/_Quit', '<control>Q', menuitem_cb, 0, '<StockItem>', gtk.STOCK_QUIT), - - ('/_Preferences', None, None, 0, '<Branch>'), - ('/_Preferences/_Color', None, None, 0, '<Branch>'), - ('/_Preferences/Color/_Red', None, menuitem_cb, 0, '<RadioItem>'), - ('/_Preferences/Color/_Green', None, menuitem_cb, 0, '/Preferences/Color/Red'), - ('/_Preferences/Color/_Blue', None, menuitem_cb, 0, '/Preferences/Color/Red'), - ('/_Preferences/_Shape', None, None, 0, '<Branch>'), - ('/_Preferences/Shape/_Square', None, menuitem_cb, 0, '<RadioItem>'), - ('/_Preferences/Shape/_Rectangle', None, menuitem_cb, 0, '/Preferences/Shape/Square'), - ('/_Preferences/Shape/_Oval', None, menuitem_cb, 0, '/Preferences/Shape/Rectangle'), - - # If you wanted this to be right justified you would use - # "<LastBranch>", not "<Branch>". Right justified help menu items - # are generally considered a bad idea now days. - - ('/_Help', None, None, 0, '<Branch>'), - ('/Help/_About', None, menuitem_cb, 0, ''), - ) - -def toolbar_cb(button, window): - dialog = gtk.MessageDialog(window, gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, - 'You selected a toolbar button') - dialog.connect('response', lambda dialog, response: dialog.destroy()) - dialog.show() - -def register_stock_icons (): +( + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE +) = range(3) + +( + SHAPE_SQUARE, + SHAPE_RECTANGLE, + SHAPE_OVAL, +) = range(3) + +ui_info = \ +'''<ui> + <menubar name='MenuBar'> + <menu action='FileMenu'> + <menuitem action='New'/> + <menuitem action='Open'/> + <menuitem action='Save'/> + <menuitem action='SaveAs'/> + <separator/> + <menuitem action='Quit'/> + </menu> + <menu action='PreferencesMenu'> + <menu action='ColorMenu'> + <menuitem action='Red'/> + <menuitem action='Green'/> + <menuitem action='Blue'/> + </menu> + <menu action='ShapeMenu'> + <menuitem action='Square'/> + <menuitem action='Rectangle'/> + <menuitem action='Oval'/> + </menu> + <menuitem action='Bold'/> + </menu> + <menu action='HelpMenu'> + <menuitem action='About'/> + </menu> + </menubar> + <toolbar name='ToolBar'> + <toolitem action='Open'/> + <toolitem action='Quit'/> + <separator/> + <toolitem action='Logo'/> + </toolbar> +</ui>''' + + +# It's totally optional to do this, you could just manually insert icons +# and have them not be themeable, especially if you never expect people +# to theme your app. +def register_stock_icons(): + ''' This function registers our custom toolbar icons, so they + can be themed. + ''' items = [('demo-gtk-logo', '_GTK!', 0, 0, '')] - # Register our stock items - gtk.stock_add (items) - + gtk.stock_add(items) + # Add our custom icon factory to the list of defaults - factory = gtk.IconFactory () - factory.add_default () - - pixbuf = gtk.gdk.pixbuf_new_from_file ('gtk-logo-rgb.gif') - pixbuf = pixbuf.add_alpha(True, chr(0xff), chr(0xff), chr(0xff)) - - # Register icon to accompany stock item - if pixbuf: - icon_set = gtk.IconSet (pixbuf) - factory.add ('demo-gtk-logo', icon_set) - else: - print 'failed to load GTK logo for toolbar' - -def update_statusbar(buffer, statusbar): - # clear any previous message, underflow is allowed - statusbar.pop(0) - count = buffer.get_char_count() - iter = buffer.get_iter_at_mark(buffer.get_insert()) - row = iter.get_line() - col = iter.get_line_offset() - statusbar.push(0, 'Cursor at row %d column %d - %d chars in document' % - (row, col, count)) - -mark_set_callback = (lambda buffer, new_location, mark, statusbar: - update_statusbar(buffer, statusbar)) - + factory = gtk.IconFactory() + factory.add_default() -def main(): - register_stock_icons () - - # Create the toplevel window - window = gtk.Window() - window.set_title('Application Window') - window.connect('destroy', lambda win: gtk.main_quit()) - - table = gtk.Table(1, 4, gtk.FALSE) - window.add(table) - - # Create the menubar - - accel_group = gtk.AccelGroup() - window.add_accel_group(accel_group) - - item_factory = gtk.ItemFactory(gtk.MenuBar, '<main>', accel_group) - - # create menu items - - item_factory.create_items(menu_items, window) - - table.attach(item_factory.get_widget('<main>'), - # X direction Y direction - 0, 1, 0, 1, - gtk.EXPAND | gtk.FILL, 0, - 0, 0) - - # Create the toolbar - - toolbar = gtk.Toolbar() - toolbar.insert_stock(gtk.STOCK_OPEN, - "This is a demo button with an 'open' icon", - None, - toolbar_cb, - window, - -1) - toolbar.insert_stock(gtk.STOCK_CLOSE, - "This is a demo button with an 'close' icon", - None, - toolbar_cb, - window, - -1) - - toolbar.append_space() - - toolbar.insert_stock('demo-gtk-logo', - "This is a demo button with a 'gtk' icon", - None, - toolbar_cb, - window, - -1) - - table.attach(toolbar, - # X direction Y direction - 0, 1, 1, 2, - gtk.EXPAND | gtk.FILL, 0, - 0, 0) - - # Create document - - sw = gtk.ScrolledWindow() - sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - sw.set_shadow_type(gtk.SHADOW_IN) - table.attach(sw, - # X direction Y direction - 0, 1, 2, 3, - gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, - 0, 0) - - window.set_default_size(200, 200) - - contents = gtk.TextView() - sw.add(contents) - - # Create statusbar - - statusbar = gtk.Statusbar(); - table.attach(statusbar, - # X direction Y direction - 0, 1, 3, 4, - gtk.EXPAND | gtk.FILL, 0, - 0, 0) - - buffer = contents.get_buffer() - buffer.connect('changed', update_statusbar, statusbar) - buffer.connect('mark_set', mark_set_callback, statusbar) - update_statusbar(buffer, statusbar) - - window.show_all() + import os + img_dir = os.path.join(os.path.dirname(__file__), 'images') + img_path = os.path.join(img_dir, 'gtk-logo-rgb.gif') + try: + pixbuf = gtk.gdk.pixbuf_new_from_file(img_path) + + # Register icon to accompany stock item + + # The gtk-logo-rgb icon has a white background, make it transparent + # the call is wrapped to (gboolean, guchar, guchar, guchar) + transparent = pixbuf.add_alpha(True, chr(255), chr(255),chr(255)) + icon_set = gtk.IconSet(transparent) + factory.add('demo-gtk-logo', icon_set) + + except gobject.GError, error: + print 'failed to load GTK logo for toolbar' + +class ApplicationMainWindowDemo(gtk.Window): + def __init__(self, parent=None): + register_stock_icons() + + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_default_size(200, 200) + + merge = gtk.UIManager() + self.set_data("ui-manager", merge) + merge.insert_action_group(self.__create_action_group(), 0) + self.add_accel_group(merge.get_accel_group()) + + try: + mergeid = merge.add_ui_from_string(ui_info) + except gobject.GError, msg: + print "building menus failed: %s" % msg + bar = merge.get_widget("/MenuBar") + bar.show() + + table = gtk.Table(1, 4, gtk.FALSE) + self.add(table) + + table.attach(bar, + # X direction # # Y direction + 0, 1, 0, 1, + gtk.EXPAND | gtk.FILL, 0, + 0, 0); + + bar = merge.get_widget("/ToolBar") + bar.set_tooltips(True) + bar.show() + table.attach(bar, + # X direction # # Y direction + 0, 1, 1, 2, + gtk.EXPAND | gtk.FILL, 0, + 0, 0) + + # Create document + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + sw.set_shadow_type(gtk.SHADOW_IN) + + table.attach(sw, + # X direction Y direction + 0, 1, 2, 3, + gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, + 0, 0) + + contents = gtk.TextView() + contents.grab_focus() + sw.add (contents) + + # Create statusbar + self.statusbar = gtk.Statusbar() + table.attach(self.statusbar, + # X direction Y direction + 0, 1, 3, 4, + gtk.EXPAND | gtk.FILL, 0, + 0, 0) + + # Show text widget info in the statusbar + buffer = contents.get_buffer() + buffer.connect("changed", self.update_statusbar) + mark_set_callback = (lambda buffer, new_location, mark: + self.update_statusbar(buffer)) + + # cursor moved + buffer.connect("mark_set", mark_set_callback) + + self.connect("window_state_event", self.update_resize_grip) + self.update_statusbar(buffer) + + self.show_all() + + def __create_action_group(self): + # GtkActionEntry + entries = ( + ( "FileMenu", None, "_File" ), # name, stock id, label + ( "PreferencesMenu", None, "_Preferences" ), # name, stock id, label + ( "ColorMenu", None, "_Color" ), # name, stock id, label + ( "ShapeMenu", None, "_Shape" ), # name, stock id, label + ( "HelpMenu", None, "_Help" ), # name, stock id, label + ( "New", gtk.STOCK_NEW, # name, stock id + "_New", "<control>N", # label, accelerator + "Create a new file", # tooltip + self.activate_action ), + ( "Open", gtk.STOCK_OPEN, # name, stock id + "_Open","<control>O", # label, accelerator + "Open a file", # tooltip + self.activate_action ), + ( "Save", gtk.STOCK_SAVE, # name, stock id + "_Save","<control>S", # label, accelerator + "Save current file", # tooltip + self.activate_action ), + ( "SaveAs", gtk.STOCK_SAVE, # name, stock id + "Save _As...", None, # label, accelerator + "Save to a file", # tooltip + self.activate_action ), + ( "Quit", gtk.STOCK_QUIT, # name, stock id + "_Quit", "<control>Q", # label, accelerator + "Quit", # tooltip + self.activate_action ), + ( "About", None, # name, stock id + "_About", "<control>A", # label, accelerator + "About", # tooltip + self.activate_action ), + ( "Logo", "demo-gtk-logo", # name, stock id + None, None, # label, accelerator + "GTK+", # tooltip + self.activate_action ), + ); + + # GtkToggleActionEntry + toggle_entries = ( + ( "Bold", gtk.STOCK_BOLD, # name, stock id + "_Bold", "<control>B", # label, accelerator + "Bold", # tooltip + self.activate_action, + True ), # is_active + ) + + # GtkRadioActionEntry + color_entries = ( + ( "Red", None, # name, stock id + "_Red", "<control><shift>R", # label, accelerator + "Blood", COLOR_RED ), # tooltip, value + ( "Green", None, # name, stock id + "_Green", "<control><shift>G", # label, accelerator + "Grass", COLOR_GREEN ), # tooltip, value + ( "Blue", None, # name, stock id + "_Blue", "<control><shift>B", # label, accelerator + "Sky", COLOR_BLUE ), # tooltip, value + ) + + # GtkRadioActionEntry + shape_entries = ( + ( "Square", None, # name, stock id + "_Square", "<control><shift>S", # label, accelerator + "Square", SHAPE_SQUARE ), # tooltip, value + ( "Rectangle", None, # name, stock id + "_Rectangle", "<control><shift>R", # label, accelerator + "Rectangle", SHAPE_RECTANGLE ), # tooltip, value + ( "Oval", None, # name, stock id + "_Oval", "<control><shift>O", # label, accelerator + "Egg", SHAPE_OVAL ), # tooltip, value + ) + + # Create the menubar and toolbar + action_group = gtk.ActionGroup("AppWindowActions") + action_group.add_actions(entries) + action_group.add_toggle_actions(toggle_entries) + action_group.add_radio_actions(color_entries, COLOR_RED, self.activate_radio_action) + action_group.add_radio_actions(shape_entries, SHAPE_OVAL, self.activate_radio_action) + + return action_group + + + def activate_action(self, action): + dialog = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, + 'You activated action: "%s" of type "%s"' % (action.get_name(), type(action))) + # Close dialog on user response + dialog.connect ("response", lambda d, r: d.destroy()) + dialog.show() + + def activate_radio_action(self, action, current): + active = current.get_active() + value = current.get_current_value() + + if active: + dialog = gtk.MessageDialog(self, gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_INFO, gtk.BUTTONS_CLOSE, + "You activated radio action: \"%s\" of type \"%s\".\nCurrent value: %d" % + (current.get_name(), type(current), value)) + + # Close dialog on user response + dialog.connect("response", lambda d, r: d.destroy()) + dialog.show() + + def update_statusbar(self, buffer): + # clear any previous message, underflow is allowed + self.statusbar.pop(0) + count = buffer.get_char_count() + iter = buffer.get_iter_at_mark(buffer.get_insert()) + row = iter.get_line() + col = iter.get_line_offset() + self.statusbar.push(0, + 'Cursor at row %d column %d - %d chars in document' % (row, col, count)) + + def update_resize_grip(self, widget, event): + mask = gtk.gdk.WINDOW_STATE_MAXIMIZED | gtk.gdk.WINDOW_STATE_FULLSCREEN + if (event.changed_mask & mask): + self.statusbar.set_has_resize_grip(not (event.new_window_state & mask)) + +def main(): + ApplicationMainWindowDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/buttonbox.py b/examples/pygtk-demo/demos/buttonbox.py index 818508fa..cf201dfa 100644 --- a/examples/pygtk-demo/demos/buttonbox.py +++ b/examples/pygtk-demo/demos/buttonbox.py @@ -1,21 +1,19 @@ #!/usr/bin/env python -'''Button Box Test +'''Button Box This demo shows various button box configurations available. It also uses stock buttons, and use of mnemonics for navigation.''' -description = 'Button Boxes' - import gtk -def create_bbox(horizontal=gtk.TRUE, title=None, spacing=0, - layout=gtk.BUTTONBOX_SPREAD): +def create_bbox(horizontal=True, title=None, spacing=0, + layout=gtk.BUTTONBOX_SPREAD): frame = gtk.Frame(title) if horizontal: - bbox = gtk.HButtonBox() + bbox = gtk.HButtonBox() else: - bbox = gtk.VButtonBox() + bbox = gtk.VButtonBox() bbox.set_border_width(5) bbox.set_layout(layout) @@ -33,50 +31,58 @@ def create_bbox(horizontal=gtk.TRUE, title=None, spacing=0, return frame +class ButtonBoxDemo(gtk.Window): + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_border_width(10) + + main_vbox = gtk.VBox() + self.add(main_vbox) + + frame_horiz = gtk.Frame("Horizontal Button Boxes") + main_vbox.pack_start(frame_horiz, padding=10) + + vbox = gtk.VBox() + vbox.set_border_width(10) + frame_horiz.add(vbox) + + vbox.pack_start(create_bbox(gtk.TRUE, "Spread", 40, gtk.BUTTONBOX_SPREAD), + padding=0) + vbox.pack_start(create_bbox(gtk.TRUE, "Edge", 40, gtk.BUTTONBOX_EDGE), + padding=5) + vbox.pack_start(create_bbox(gtk.TRUE, "Start", 40, gtk.BUTTONBOX_START), + padding=5) + vbox.pack_start(create_bbox(gtk.TRUE, "End", 40, gtk.BUTTONBOX_END), + padding=5) + + frame_vert = gtk.Frame("Vertical Button Boxes") + main_vbox.pack_start(frame_vert, padding=10) + + hbox = gtk.HBox() + hbox.set_border_width(10) + frame_vert.add(hbox) + + hbox.pack_start(create_bbox(gtk.FALSE, "Spread", 40, gtk.BUTTONBOX_SPREAD), + padding=0) + hbox.pack_start(create_bbox(gtk.FALSE, "Edge", 40, gtk.BUTTONBOX_EDGE), + padding=5) + hbox.pack_start(create_bbox(gtk.FALSE, "Start", 40, gtk.BUTTONBOX_START), + padding=5) + hbox.pack_start(create_bbox(gtk.FALSE, "End", 40, gtk.BUTTONBOX_END), + padding=5) + + self.show_all() + def main(): - win = gtk.Window() - win.connect('destroy', lambda win: gtk.main_quit()) - - win.set_title('Button Boxes') - win.set_border_width(10) - - main_vbox = gtk.VBox() - win.add(main_vbox) - - frame_horiz = gtk.Frame("Horizontal Button Boxes") - main_vbox.pack_start(frame_horiz, padding=10) - - vbox = gtk.VBox() - vbox.set_border_width(10) - frame_horiz.add(vbox) - - vbox.pack_start(create_bbox(gtk.TRUE, "Spread", 40, gtk.BUTTONBOX_SPREAD), - padding=0) - vbox.pack_start(create_bbox(gtk.TRUE, "Edge", 40, gtk.BUTTONBOX_EDGE), - padding=5) - vbox.pack_start(create_bbox(gtk.TRUE, "Start", 40, gtk.BUTTONBOX_START), - padding=5) - vbox.pack_start(create_bbox(gtk.TRUE, "End", 40, gtk.BUTTONBOX_END), - padding=5) - - frame_vert = gtk.Frame("Vertical Button Boxes") - main_vbox.pack_start(frame_vert, padding=10) - - hbox = gtk.HBox() - hbox.set_border_width(10) - frame_vert.add(hbox) - - hbox.pack_start(create_bbox(gtk.FALSE, "Spread", 40, gtk.BUTTONBOX_SPREAD), - padding=0) - hbox.pack_start(create_bbox(gtk.FALSE, "Edge", 40, gtk.BUTTONBOX_EDGE), - padding=5) - hbox.pack_start(create_bbox(gtk.FALSE, "Start", 40, gtk.BUTTONBOX_START), - padding=5) - hbox.pack_start(create_bbox(gtk.FALSE, "End", 40, gtk.BUTTONBOX_END), - padding=5) - - win.show_all() + ButtonBoxDemo() gtk.main() - + if __name__ == '__main__': main() diff --git a/examples/pygtk-demo/demos/changedisplay.py b/examples/pygtk-demo/demos/changedisplay.py new file mode 100644 index 00000000..592a7e0f --- /dev/null +++ b/examples/pygtk-demo/demos/changedisplay.py @@ -0,0 +1,414 @@ +#!/usr/bin/env python +'''Change Display + +Demonstrates migrating a window between different displays and +screens. A display is a mouse and keyboard with some number of +associated monitors. A screen is a set of monitors grouped +into a single physical work area. The neat thing about having +multiple displays is that they can be on a completely separate +computers, as long as there is a network connection to the +computer where the application is running. + +Only some of the windowing systems where GTK+ runs have the +concept of multiple displays and screens. (The X Window System +is the main example.) Other windowing systems can only +handle one keyboard and mouse, and combine all monitors into +a single screen. + +This is a moderately complex example, and demonstrates: + +- Tracking the currently open displays and screens +- Changing the screen for a window +- Letting the user choose a window by clicking on it +- Using GtkListStore and GtkTreeView +- Using GtkDialog +''' +import gtk +import gobject + +# These enumerations provide symbolic names for the columns +# in the two GtkListStore models. +# +( + DISPLAY_COLUMN_NAME, + DISPLAY_COLUMN_DISPLAY, + DISPLAY_NUM_COLUMNS +) = range(3) + +( + SCREEN_COLUMN_NUMBER, + SCREEN_COLUMN_SCREEN, + SCREEN_NUM_COLUMNS +) = range(3) + +def find_toplevel_at_pointer(display): + ''' Finds the toplevel window under the mouse pointer, if any. + ''' + pointer_window = display.get_window_at_pointer()[0] + + # The user data field of a GdkWindow is used to store a pointer + # to the widget that created it. + # + if pointer_window: + widget = pointer_window.get_user_data() + + return widget and widget.get_toplevel() or None + +class QueryForToplevel(gtk.Window): + ''' Asks the user to click on a window, then waits for them click + the mouse. When the mouse is released, returns the toplevel + window under the pointer, or NULL, if there is none. + ''' + + def __init__(self, screen, prompt): + gtk.Window.__init__(self, gtk.WINDOW_POPUP) + self.set_screen(screen) + self.set_modal(True) + self.set_position(gtk.WIN_POS_CENTER) + + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_OUT) + self.add(frame) + + label = gtk.Label(prompt) + label.set_padding(10, 10) + frame.add(label) + + self.show_all() + + def run(self): + display = self.get_screen().get_display() + cursor = gtk.gdk.Cursor(display, gtk.gdk.CROSSHAIR) + + main_context = gobject.main_context_default() + if (gtk.gdk.pointer_grab(self.window, False, + gtk.gdk.BUTTON_RELEASE_MASK, None, cursor) == gtk.gdk.GRAB_SUCCESS): + self.query_clicked = False + self.connect("button-release-event", self.button_release_event_cb) + + # Process events until clicked is set by button_release_event_cb. + # We pass in may_block=TRUE since we want to wait if there + # are no events currently. + # + while self.query_clicked is False: + main_context.iteration(True) + + toplevel = find_toplevel_at_pointer(display) + if (toplevel == self): + toplevel = None; + + self.destroy() + gtk.gdk.flush() # Really release the grab + + return toplevel + + def button_release_event_cb(self, winref, event): + self.query_clicked = True + return True + + +class LeftAlignButton(gtk.Button): + ''' If we have a stack of buttons, it often looks better if their contents + are left-aligned, rather than centered. This class creates a button + and left-aligns it contents. + ''' + def __init__(self, label): + gtk.Button.__init__(self, label) + child = self.get_children()[0] + child.set_alignment(0., 0.5) + + +# Main entry point. If the dialog for this demo doesn't yet exist, creates +# it. +# +class ChangeDisplayDemo(gtk.Dialog): + size_group = None + display_model = None + screen_model = None + screen_selection = None + current_display = None + current_screen = None + + def __init__(self, parent=None): + gtk.Dialog.__init__(self, "Change Screen or display", parent, + gtk.DIALOG_NO_SEPARATOR, + (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE, + "Change", gtk.RESPONSE_OK)) + self.set_default_size(300, 400) + + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.connect("response", self.response_cb) + self.connect("destroy", self.destroy_cb) + + vbox = gtk.VBox(False, 5) + vbox.set_border_width(8) + + self.vbox.pack_start(vbox, True, True, 0) + + frame = self.__create_display_frame() + vbox.pack_start(frame, True, True, 0) + + frame = self.__create_screen_frame() + vbox.pack_start(frame, True, True, 0) + + self.__initialize_displays() + + self.show_all() + + def __initialize_displays(self): + ''' Adds all currently open displays to our list of displays, + and set up a signal connection so that we'll be notified + when displays are opened in the future as well. + ''' + manager = gtk.gdk.display_manager_get() + displays = manager.list_displays() + + for item in displays: + self.add_display(item) + id = manager.connect("display_opened", self.display_opened_cb) + manager.set_data('user-callback', id) + + def __create_frame(self, title): + ''' This function is used both for creating the "Display" and + "Screen" frames, since they have a similar structure. The + caller hooks up the right context for the value returned + in tree_view, and packs any relevant buttons into button_vbox. + ''' + frame = gtk.Frame(title) + + hbox = gtk.HBox(False, 8) + hbox.set_border_width(8) + frame.add(hbox) + + scrollwin = gtk.ScrolledWindow(); + scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + scrollwin.set_shadow_type (gtk.SHADOW_IN) + hbox.pack_start(scrollwin, True, True, 0) + + tree_view = gtk.TreeView() + tree_view.set_headers_visible(False) + scrollwin.add(tree_view) + + selection = tree_view.get_selection() + selection.set_mode(gtk.SELECTION_BROWSE) + + button_vbox = gtk.VBox(False, 5) + hbox.pack_start(button_vbox, False, False, 0) + + if self.size_group is None: + self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + self.size_group.add_widget(button_vbox) + + return (frame, tree_view, button_vbox) + + + def __create_display_frame(self): + ''' Creates the "Display" frame in the main window. + ''' + frame, tree_view, button_vbox = self.__create_frame("Display") + + button = LeftAlignButton("_Open...") + button.connect("clicked", self.open_display_cb) + button_vbox.pack_start(button, False, False, 0) + + button = LeftAlignButton("_Close") + button.connect ("clicked", self.close_display_cb) + button_vbox.pack_start(button, False, False, 0) + + self.display_model = gtk.ListStore(str, object); + tree_view.set_model(self.display_model) + + column = gtk.TreeViewColumn("Name", gtk.CellRendererText(), + text=DISPLAY_COLUMN_NAME) + tree_view.append_column(column) + + selection = tree_view.get_selection() + selection.connect("changed", self.display_changed_cb) + + return frame + + def __create_screen_frame(self): + ''' Creates the "Screen" frame in the main window. + ''' + frame, tree_view, button_vbox = self.__create_frame("Screen") + + self.screen_model = gtk.ListStore(int, object); + tree_view.set_model(self.screen_model) + + column = gtk.TreeViewColumn("Number", gtk.CellRendererText(), + text=SCREEN_COLUMN_NUMBER) + tree_view.append_column(column) + + self.screen_selection = tree_view.get_selection() + self.screen_selection.connect("changed", self.screen_changed_cb) + + return frame + + def query_change_display(self): + ''' Prompts the user for a toplevel window to move, and then moves + that window to the currently selected display + ''' + screen = self.window.get_screen() + + toplevel = QueryForToplevel(screen, + "Please select the toplevel\nto move to the new screen").run() + + if toplevel is not None: + toplevel.set_screen(self.current_screen) + else: + screen.get_display().beep() + + + def response_cb(self, dialog, response_id): + ''' Called when the user clicks on a button in our dialog or + closes the dialog through the window manager. Unless the + "Change" button was clicked, we destroy the dialog. + ''' + if response_id == gtk.RESPONSE_OK: + self.query_change_display() + else: + dialog.destroy() + + def open_display_cb(self, button): + ''' Called when the user clicks on "Open..." in the display + frame. Prompts for a new display, and then opens a connection + to that display. + ''' + dialog = gtk.Dialog("Open Display", self, gtk.DIALOG_MODAL, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)) + + dialog.set_default_response(gtk.RESPONSE_OK) + display_entry = gtk.Entry() + display_entry.set_activates_default(True) + dialog_label = gtk.Label("Please enter the name of\nthe new display\n") + + dialog.vbox.add(dialog_label) + dialog.vbox.add(display_entry) + + display_entry.grab_focus() + dialog.show_all() + + result = None + while result is None: + response_id = dialog.run() + if response_id != gtk.RESPONSE_OK: + break; + new_screen_name = display_entry.get_chars(0, -1) + print new_screen_name + if new_screen_name != "": + result = gtk.gdk.Display(new_screen_name) + if result is None: + error_msg = ( + "Can't open display :\n\t%s\nplease try another one\n" % + (new_screen_name,)) + dialog_label.set_text(error_msg) + + dialog.destroy() + + def close_display_cb(self, button): + ''' Called when the user clicks on the "Close" button in the + "Display" frame. Closes the selected display. + ''' + if self.current_display: + self.current_display.close() + + + def display_changed_cb(self, selection): + ''' Called when the selected row in the display list changes. + Updates info.current_display, then refills the list of + screens. + ''' + model, iter = selection.get_selected() + if iter is not None: + self.current_display = model.get_value(iter, DISPLAY_COLUMN_DISPLAY) + else: + self.current_display = None + self.fill_screens() + + def screen_changed_cb(self, selection): + ''' Called when the selected row in the sceen list changes. + Updates info->current_screen. + ''' + model, iter = selection.get_selected() + if iter: + self.current_screen = model.get(iter, SCREEN_COLUMN_SCREEN) + else: + self.current_screen = None; + + def destroy_cb(self, parent): + self.destroy_info() + if parent is None: + gtk.main_quit() + + + def fill_screens(self): + ''' Fills in the screen list based on the current display + ''' + self.screen_model.clear() + if self.current_display is not None: + n_screens = self.current_display.get_n_screens() + + for i in range(n_screens): + screen = self.current_display.get_screen(i); + iter = self.screen_model.append() + self.screen_model.set(iter, + SCREEN_COLUMN_NUMBER, i, SCREEN_COLUMN_SCREEN, screen) + if (i == 0): + self.screen_selection.select_iter(iter) + + def display_closed_cb(self, display, is_error, info): + ''' Called when one of the currently open displays is closed. + Remove it from our list of displays. + ''' + iter = self.display_model.get_iter_first() + while iter: + tmp_display = self.display_model.get_value(iter, DISPLAY_COLUMN_DISPLAY) + if (tmp_display == display): + info.display_model.remove(iter) + break; + iter = info.display_model.iter_next() + + def add_display(self, display): + ''' Adds a new display to our list of displays, and connects + to the "closed" signal so that we can remove it from the + list of displays again. + ''' + name = display.get_name() + + iter = self.display_model.append() + self.display_model.set(iter, + DISPLAY_COLUMN_NAME, name, DISPLAY_COLUMN_DISPLAY, display) + id = display.connect("closed", self.display_closed_cb) + display.set_data('user-callback', id) + + def display_opened_cb(self, manager, display): + ''' Called when a new display is opened + ''' + self.add_display(display) + + def destroy_info(self): + ''' Cleans up when the toplevel is destroyed; we remove the + connections we use to track currently open displays. + ''' + manager = gtk.gdk.display_manager_get() + displays = manager.list_displays() + + id = manager.get_data('user-callback') + manager.disconnect(id) + + for tmp_list in displays: + id = tmp_list.get_data('user-callback') + tmp_list.disconnect(id) + + +def main(): + ChangeDisplayDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/examples/pygtk-demo/demos/colorsel.py b/examples/pygtk-demo/demos/colorsel.py index 444423fa..d3f6c904 100644 --- a/examples/pygtk-demo/demos/colorsel.py +++ b/examples/pygtk-demo/demos/colorsel.py @@ -4,71 +4,69 @@ GtkColorSelection lets the user choose a color. GtkColorSelectionDialog is a prebuilt dialog containing a GtkColorSelection.""" -description = "Color Selector" - import gtk -window = None -color = None -da = None - -def change_color_cb(w): - global window, color, da - - dialog = gtk.ColorSelectionDialog("Changing color") - dialog.set_transient_for(window) - colorsel = dialog.colorsel - - colorsel.set_previous_color(color) - colorsel.set_current_color(color) - colorsel.set_has_palette(gtk.TRUE) - - response = dialog.run() - - if response == gtk.RESPONSE_OK: - color = colorsel.get_current_color() - da.modify_bg(gtk.STATE_NORMAL, color) - - dialog.destroy() +class ColorSelectorDemo(gtk.Window): + color = gtk.gdk.color_parse("blue") + + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_border_width(8) + vbox = gtk.VBox() + vbox.set_border_width(8) + self.add(vbox) + + # Create the color swatch area + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) + vbox.pack_start(frame, True, True, 8) + + self.d_area = gtk.DrawingArea() + self.d_area.set_size_request(200, 200) + self.d_area.modify_bg(gtk.STATE_NORMAL, self.color) + frame.add(self.d_area) + + alignment = gtk.Alignment(1.0, 0.5, 0.0, 0.0) + + button = gtk.Button("_Change the above color") + alignment.add(button) + + vbox.pack_start(alignment, True, True) + + button.connect('clicked', self.on_change_color_clicked) + button.set_flags(gtk.CAN_DEFAULT) + button.grab_default() + + self.show_all() + + def on_change_color_clicked(self, button): + + dialog = gtk.ColorSelectionDialog("Changing color") + dialog.set_transient_for(self) + colorsel = dialog.colorsel + + colorsel.set_previous_color(self.color) + colorsel.set_current_color(self.color) + colorsel.set_has_palette(gtk.TRUE) + + response = dialog.run() + + if response == gtk.RESPONSE_OK: + self.color = colorsel.get_current_color() + self.d_area.modify_bg(gtk.STATE_NORMAL, self.color) + + dialog.destroy() + return True def main(): - global window, color, da - - color = gtk.gdk.color_parse("blue") - - window = gtk.Window() - window.set_title("Color selection") - window.set_border_width(8) - window.connect('destroy', lambda win: gtk.main_quit()) - - vbox = gtk.VBox() - vbox.set_border_width(8) - window.add(vbox) - - # Create the color swatch area - - frame = gtk.Frame() - frame.set_shadow_type(gtk.SHADOW_IN) - vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 8) - - da = gtk.DrawingArea() - da.set_size_request(200, 200) - da.modify_bg(gtk.STATE_NORMAL, color) - frame.add(da) - - alignment = gtk.Alignment(1.0, 0.5, 0.0, 0.0) - - button = gtk.Button("_Change the above color") - alignment.add(button) - - vbox.pack_start(alignment, gtk.TRUE, gtk.TRUE) - - button.connect('clicked', change_color_cb) - button.set_flags(gtk.CAN_DEFAULT) - button.grab_default() - - window.show_all() - + ColorSelectorDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/dialogs.py b/examples/pygtk-demo/demos/dialogs.py index 9b90d3c2..edea0701 100644 --- a/examples/pygtk-demo/demos/dialogs.py +++ b/examples/pygtk-demo/demos/dialogs.py @@ -3,130 +3,127 @@ Dialog widgets are used to pop up a transient window for user feedback.""" -description = "Dialog and Message Boxes" - import gtk -window = None -entry1 = None -entry2 = None -counter = 1 - -def message_dialog_clicked(w): - global window, counter - - dialog = gtk.MessageDialog(window, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_INFO, gtk.BUTTONS_OK, - "This message box has been popped up %d time%s." % - (counter, counter > 1 and 's' or '')) - dialog.run() - dialog.destroy() - counter += 1 - -def interactive_dialog_clicked(w): - global window, entry1, entry2 - - dialog = gtk.Dialog("Interactive Dialog", window, 0, - (gtk.STOCK_OK, gtk.RESPONSE_OK, - "_Non-stock button", gtk.RESPONSE_CANCEL)) - - hbox = gtk.HBox(gtk.FALSE, 8) - hbox.set_border_width(8) - dialog.vbox.pack_start(hbox, gtk.FALSE, gtk.FALSE, 0) - - stock = gtk.image_new_from_stock( - gtk.STOCK_DIALOG_QUESTION, - gtk.ICON_SIZE_DIALOG) - hbox.pack_start(stock, gtk.FALSE, gtk.FALSE, 0) - - table = gtk.Table(2, 2) - table.set_row_spacings(4) - table.set_col_spacings(4) - hbox.pack_start(table, gtk.TRUE, gtk.TRUE, 0) - - label = gtk.Label("Entry _1") - label.set_use_underline(gtk.TRUE) - table.attach_defaults(label, 0, 1, 0, 1) - local_entry1 = gtk.Entry() - local_entry1.set_text(entry1.get_text()) - table.attach_defaults(local_entry1, 1, 2, 0, 1) - label.set_mnemonic_widget(local_entry1) - - label = gtk.Label("Entry _2") - label.set_use_underline(gtk.TRUE) - table.attach_defaults(label, 0, 1, 1, 2) - local_entry2 = gtk.Entry() - local_entry2.set_text(entry2.get_text()) - table.attach_defaults(local_entry2, 1, 2, 1, 2) - label.set_mnemonic_widget(local_entry2) - - dialog.show_all() - - response = dialog.run() - - if response == gtk.RESPONSE_OK: - entry1.set_text(local_entry1.get_text()) - entry2.set_text(local_entry2.get_text()) - - dialog.destroy() +class DialogAndMessageBoxesDemo(gtk.Window): + counter = 1 + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_border_width(8) + + frame = gtk.Frame("Dialogs") + self.add(frame) + + vbox = gtk.VBox(False, 8) + vbox.set_border_width(8) + frame.add(vbox) + + # Standard message dialog + hbox = gtk.HBox(False, 8) + vbox.pack_start(hbox) + button = gtk.Button("_Message Dialog") + button.connect('clicked', self.on_message_dialog_clicked) + hbox.pack_start(button, False, False, 0) + vbox.pack_start(gtk.HSeparator(), False, False, 0) + + # Interactive dialog + hbox = gtk.HBox(False, 8) + vbox.pack_start(hbox, False, False, 0) + vbox2 = gtk.VBox() + + button = gtk.Button("_Interactive Dialog") + button.connect('clicked', self.on_interactive_dialog_clicked) + hbox.pack_start(vbox2, False, False, 0) + vbox2.pack_start(button, False, False, 0) + + table = gtk.Table(2, 2) + table.set_row_spacings(4) + table.set_col_spacings(4) + hbox.pack_start(table, False, False, 0) + + label = gtk.Label("Entry _1") + label.set_use_underline(True) + table.attach(label, 0, 1, 0, 1) + + self.entry1 = gtk.Entry() + table.attach(self.entry1, 1, 2, 0, 1) + label.set_mnemonic_widget(self.entry1) + + label = gtk.Label("Entry _2") + label.set_use_underline(True) + table.attach(label, 0, 1, 1, 2) + + self.entry2 = gtk.Entry() + table.attach(self.entry2, 1, 2, 1, 2) + label.set_mnemonic_widget(self.entry2) + + self.show_all() + + def on_message_dialog_clicked(self, button): + dialog = gtk.MessageDialog(self, + gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_INFO, gtk.BUTTONS_OK, + "This message box has been popped up %d time%s." % + (self.counter, self.counter > 1 and 's' or '')) + dialog.run() + dialog.destroy() + self.counter += 1 + + def on_interactive_dialog_clicked(self, button): + + dialog = gtk.Dialog("Interactive Dialog", self, 0, + (gtk.STOCK_OK, gtk.RESPONSE_OK, + "_Non-stock button", gtk.RESPONSE_CANCEL)) + + hbox = gtk.HBox(False, 8) + hbox.set_border_width(8) + dialog.vbox.pack_start(hbox, False, False, 0) + + stock = gtk.image_new_from_stock( + gtk.STOCK_DIALOG_QUESTION, + gtk.ICON_SIZE_DIALOG) + hbox.pack_start(stock, False, False, 0) + + table = gtk.Table(2, 2) + table.set_row_spacings(4) + table.set_col_spacings(4) + hbox.pack_start(table, True, True, 0) + + label = gtk.Label("Entry _1") + label.set_use_underline(True) + table.attach(label, 0, 1, 0, 1) + local_entry1 = gtk.Entry() + local_entry1.set_text(self.entry1.get_text()) + table.attach(local_entry1, 1, 2, 0, 1) + label.set_mnemonic_widget(local_entry1) + + label = gtk.Label("Entry _2") + label.set_use_underline(True) + table.attach(label, 0, 1, 1, 2) + local_entry2 = gtk.Entry() + local_entry2.set_text(self.entry2.get_text()) + table.attach(local_entry2, 1, 2, 1, 2) + label.set_mnemonic_widget(local_entry2) + + dialog.show_all() + + response = dialog.run() + + if response == gtk.RESPONSE_OK: + self.entry1.set_text(local_entry1.get_text()) + self.entry2.set_text(local_entry2.get_text()) + + dialog.destroy() def main(): - global window, entry1, entry2 - - window = gtk.Window() - window.set_title("Dialogs") - window.set_border_width(8) - window.connect('destroy', lambda win: gtk.main_quit()) - - frame = gtk.Frame("Dialogs") - window.add(frame) - - vbox = gtk.VBox(gtk.FALSE, 8) - vbox.set_border_width(8) - frame.add(vbox) - - # Standard message dialog - hbox = gtk.HBox(gtk.FALSE, 8) - vbox.pack_start(hbox) - button = gtk.Button("_Message Dialog") - button.connect('clicked', message_dialog_clicked) - hbox.pack_start(button, gtk.FALSE, gtk.FALSE, 0) - vbox.pack_start(gtk.HSeparator(), gtk.FALSE, gtk.FALSE, 0) - - # Interactive dialog - hbox = gtk.HBox(gtk.FALSE, 8) - vbox.pack_start(hbox, gtk.FALSE, gtk.FALSE, 0) - vbox2 = gtk.VBox() - - button = gtk.Button("_Interactive Dialog") - button.connect('clicked', interactive_dialog_clicked) - hbox.pack_start(vbox2, gtk.FALSE, gtk.FALSE, 0) - vbox2.pack_start(button, gtk.FALSE, gtk.FALSE, 0) - - table = gtk.Table(2, 2) - table.set_row_spacings(4) - table.set_col_spacings(4) - hbox.pack_start(table, gtk.FALSE, gtk.FALSE, 0) - - label = gtk.Label("Entry _1") - label.set_use_underline(gtk.TRUE) - table.attach_defaults(label, 0, 1, 0, 1) - - entry1 = gtk.Entry() - table.attach_defaults(entry1, 1, 2, 0, 1) - label.set_mnemonic_widget(entry1) - - label = gtk.Label("Entry _2") - label.set_use_underline(gtk.TRUE) - table.attach_defaults(label, 0, 1, 1, 2) - - entry2 = gtk.Entry() - table.attach_defaults(entry2, 1, 2, 1, 2) - label.set_mnemonic_widget(entry2) - - window.show_all() - + DialogAndMessageBoxesDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/dnd.py b/examples/pygtk-demo/demos/dnd.py index b1f386bb..44d4610b 100644 --- a/examples/pygtk-demo/demos/dnd.py +++ b/examples/pygtk-demo/demos/dnd.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -'''Drag and Drop Test +'''Drag and Drop This is a test of the drag and drop capabilities of gtk. It is a fairly straight forward port of the example distributed with gtk. @@ -7,199 +7,200 @@ fairly straight forward port of the example distributed with gtk. FIXME: there are still a few things missing since I converted the GdkDragContext wrapper to being a GObject.''' -description = 'Drag and Drop' - import gtk from dndpixmap import * -trashcan_open = None -trashcan_open_mask = None -trashcan_closed = None -trashcan_closed_mask = None - -have_drag = gtk.FALSE -popped_up = gtk.FALSE -in_popup = gtk.FALSE -popup_timer = 0 -popdown_timer = 0 -popup_win = None - - TARGET_STRING = 0 TARGET_ROOTWIN = 1 target = [ ('STRING', 0, TARGET_STRING), ('text/plain', 0, TARGET_STRING), - ('application/x-rootwin-drop', 0, TARGET_ROOTWIN)] - -def target_drag_leave(w, context, time): - global trashcan_closed, trashcan_closed_mask - global have_drag - print 'leave' - have_drag = gtk.FALSE - w.set_from_pixmap(trashcan_closed, trashcan_closed_mask) - -def target_drag_motion(w, context, x, y, time): - global trashcan_open, trashcan_open_mask - global have_drag - if not have_drag: - have_drag = gtk.TRUE - w.set_from_pixmap(trashcan_open, trashcan_open_mask) - source_widget = context.get_source_widget() - print 'motion, source ', - if source_widget: - print source_widget.__class__.__name__ - else: - print 'unknown' - context.drag_status(context.suggested_action, time) - return gtk.TRUE - -def target_drag_drop(w, context, x, y, time): - global trashcan_closed, trashcan_closed_mask - global have_drag - print 'drop' - have_drag = gtk.FALSE - w.set_from_pixmap(trashcan_closed, trashcan_closed_mask) - if context.targets: - w.drag_get_data(context, context.targets[0], time) - return gtk.TRUE - return gtk.FALSE - -def target_drag_data_received(w, context, x, y, data, info, time): - if data.format == 8: - print 'Received "%s" in trashcan' % data.data - context.finish(gtk.TRUE, gtk.FALSE, time) - else: - context.finish(gtk.FALSE, gtk.FALSE, time) - -def label_drag_data_received(w, context, x, y, data, info, time): - if data and data.format == 8: - print 'Received "%s" in label' % data.data - context.finish(gtk.TRUE, gtk.FALSE, time) - else: - context.finish(gtk.FALSE, gtk.FALSE, time) - -def source_drag_data_get(w, context, selection_data, info, time): - if info == TARGET_ROOTWIN: - print 'I was dropped on the rootwin' - else: - selection_data.set(selection_data.target, 8, "I'm Data!") - -def popdown_cb(): - global popdown_timer, popped_up - global popup_win - popdown_timer = 0 - popup_win.hide() - popped_up = gtk.FALSE - return gtk.FALSE - -def popup_motion(w, context, x, y, time): - global in_popup, popdown_timer - if not in_popup: - in_popup = gtk.TRUE - if popdown_timer: - print 'removed popdown' - gtk.timeout_remove(popdown_timer) - popdown_timer = 0 - return gtk.TRUE - -def popup_leave(w, context, time): - global in_popup, popdown_timer - print 'popup_leave' - if in_popup: - in_popup = gtk.FALSE - if not popdown_timer: - print 'added popdown' - popdown_timer = gtk.timeout_add(500, popdown_cb) - -def popup_cb(): - global popped_up, popup_win - global popup_timer, popdown_timer - if not popped_up: - if not popup_win: - popup_win = gtk.Window(gtk.WINDOW_POPUP) - popup_win.set_position(gtk.WIN_POS_MOUSE) - table = gtk.Table(3, 3) - for k in range(9): - i, j = divmod(k, 3) - b = gtk.Button("%d,%d" % (i,j)) - table.attach(b, i,i+1,j,j+1) - b.drag_dest_set(gtk.DEST_DEFAULT_ALL, target, - gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) - b.connect('drag_motion', popup_motion) - b.connect('drag_leave', popup_leave) - table.show_all() - popup_win.add(table) - popup_win.show() - popped_up = gtk.TRUE - popdown_timer = gtk.timeout_add(500, popdown_cb) - print 'added popdown' - popup_timer = 0 - return gtk.FALSE - -def popsite_motion(w, context, x, y, time): - global popup_timer - if not popup_timer: - popup_timer = gtk.timeout_add(500, popup_cb) - return gtk.TRUE - -def popsite_leave(w, context, time): - global popup_timer - if popup_timer: - gtk.timeout_remove(popup_timer) - popup_timer = 0 - -def source_drag_data_delete(w, context, data): - print 'Delete the data!' - -def create_pixmap(widget, xpm): - return gtk.gdk.pixmap_colormap_create_from_xpm_d(None, - widget.get_colormap(), - None, xpm) + ('application/x-rootwin-drop', 0, TARGET_ROOTWIN) +] + +def create_pixmap(widget, xpm_data): + return \ + gtk.gdk.pixmap_colormap_create_from_xpm_d( + None, widget.get_colormap(), None, xpm_data) + +class DragAndDropDemo(gtk.Window): + trashcan_open = None + trashcan_open_mask = None + trashcan_closed = None + trashcan_closed_mask = None + drag_icon = None + drag_mask = None + have_drag = False + popped_up = False + in_popup = False + popup_timer = None + popdown_timer = 0 + popup_win = None + + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) + + table = gtk.Table(2,2) + self.add(table) + + self.drag_icon, self.drag_mask = \ + create_pixmap(self, drag_icon_xpm) + self.trashcan_open, self.trashcan_open_mask = \ + create_pixmap(self, trashcan_open_xpm) + self.trashcan_closed, self.trashcan_closed_mask = \ + create_pixmap(self, trashcan_closed_xpm) + + label = gtk.Label('Drop Here!\n') + label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], + gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) + label.connect('drag_data_received', self.label_drag_data_received) + table.attach(label, 0, 1, 0, 1) + + label = gtk.Label('Popup\n') + label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], + gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) + table.attach(label, 1, 2, 1, 2) + label.connect('drag_motion', self.popsite_motion) + label.connect('drag_leave', self.popsite_leave) + + image = gtk.Image() + image.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) + image.drag_dest_set(0, [], 0) + table.attach(image, 1, 2, 0, 1) + image.connect('drag_leave', self.target_drag_leave) + image.connect('drag_motion', self.target_drag_motion) + image.connect('drag_drop', self.target_drag_drop) + image.connect('drag_data_received', self.target_drag_data_received) + + b = gtk.Button('Drag Here\n') + b.drag_source_set(gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, + target, gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) + b.drag_source_set_icon(self.get_colormap(), self.drag_icon, self.drag_mask) + table.attach(b, 0, 1, 1, 2) + b.connect('drag_data_get', self.source_drag_data_get) + b.connect('drag_data_delete', self.source_drag_data_delete) + self.show_all() + + def label_drag_data_received(self, w, context, x, y, data, info, time): + if data and data.format == 8: + print 'Received "%s" in label' % data.data + context.finish(True, False, time) + else: + context.finish(False, False, time) + + def popsite_motion(self, w, context, x, y, time): + if self.popup_timer is None: + self.popup_timer = gtk.timeout_add(500, self.popup_cb) + return True + + def popsite_leave(self, w, context, time): + if self.popup_timer is not None: + gtk.timeout_remove(self.popup_timer) + self.popup_timer = None + + def popup_motion(self, w, context, x, y, time): + print 'popup_motion' + if not self.in_popup: + self.in_popup = True + if self.popdown_timer is not None: + print 'removed popdown' + gtk.timeout_remove(self.popdown_timer) + self.popdown_timer = None + return True + + def popup_leave(self, w, context, time): + print 'popup_leave' + if self.in_popup: + self.in_popup = False + if self.popdown_timer is None: + print 'added popdown' + self.popdown_timer = gtk.timeout_add(500, self.popdown_cb) + + def popup_cb(self): + if not self.popped_up: + if self.popup_win is None: + self.popup_win = gtk.Window(gtk.WINDOW_POPUP) + self.popup_win.set_position(gtk.WIN_POS_MOUSE) + table = gtk.Table(3, 3) + for k in range(9): + i, j = divmod(k, 3) + b = gtk.Button("%d,%d" % (i,j)) + b.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], + gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) + b.connect('drag_motion', self.popup_motion, None) + b.connect('drag_leave', self.popup_leave) + table.attach(b, i, i+1, j, j+1) + table.show_all() + self.popup_win.add(table) + self.popup_win.show() + self.popped_up = True + self.in_popup = True + self.popdown_timer = gtk.timeout_add(500, self.popdown_cb) + print 'added popdown' + self.popup_timer = None + return False + + def popdown_cb(self): + print 'popdown' + #if self.in_popup: + # return True + self.popdown_timer = None + self.popup_win.hide() + self.popped_up = False + return False + + def target_drag_leave(self, img, context, time): + print 'leave' + self.have_drag = False + img.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) + + def target_drag_motion(self, img, context, x, y, time): + if self.have_drag is False: + self.have_drag = True + img.set_from_pixmap(self.trashcan_open, self.trashcan_open_mask) + source_widget = context.get_source_widget() + print 'motion, source ', + if source_widget: + print source_widget.__class__.__name__ + else: + print 'unknown' + context.drag_status(context.suggested_action, time) + return True + + def target_drag_drop(self, img, context, x, y, time): + print 'drop' + self.have_drag = False + img.set_from_pixmap(self.trashcan_closed, self.trashcan_closed_mask) + if context.targets: + img.drag_get_data(context, context.targets[0], time) + return True + return False + + def target_drag_data_received(self, img, context, x, y, data, info, time): + if data.format == 8: + print 'Received "%s" in trashcan' % data.data + context.finish(True, False, time) + else: + context.finish(False, False, time) + + def source_drag_data_get(self, btn, context, selection_data, info, time): + if info == TARGET_ROOTWIN: + print 'I was dropped on the rootwin' + else: + selection_data.set(selection_data.target, 8, "I'm Data!") + + def source_drag_data_delete(self, btn, context, data): + print 'Delete the data!' def main(): - global trashcan_open, trashcan_open_mask - global trashcan_closed, trashcan_closed_mask - global drag_icon, drag_mask - win = gtk.Window() - win.connect('destroy', lambda win: gtk.main_quit()) - table = gtk.Table(2,2) - win.add(table) - drag_icon, drag_mask = create_pixmap(win, drag_icon_xpm) - trashcan_open, trashcan_open_mask = create_pixmap(win, trashcan_open_xpm) - trashcan_closed, trashcan_closed_mask = create_pixmap(win, trashcan_closed_xpm) - label = gtk.Label('Drop Here!\n') - label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], - gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) - label.connect('drag_data_received', label_drag_data_received) - table.attach(label, 0, 1, 0, 1) - - label = gtk.Label('Popup\n') - label.drag_dest_set(gtk.DEST_DEFAULT_ALL, target[:-1], - gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) - table.attach(label, 1, 2, 1, 2) - label.connect('drag_motion', popsite_motion) - label.connect('drag_leave', popsite_leave) - - image = gtk.Image() - image.set_from_pixmap(trashcan_closed, trashcan_closed_mask) - image.drag_dest_set(0, [], 0) - table.attach(image, 1, 2, 0, 1) - image.connect('drag_leave', target_drag_leave) - image.connect('drag_motion', target_drag_motion) - image.connect('drag_drop', target_drag_drop) - image.connect('drag_data_received', target_drag_data_received) - - b = gtk.Button('Drag Here\n') - b.drag_source_set(gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, - target, gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) - b.drag_source_set_icon(win.get_colormap(), drag_icon, drag_mask) - table.attach(b, 0, 1, 1, 2) - b.connect('drag_data_get', source_drag_data_get) - b.connect('drag_data_delete', source_drag_data_delete) - win.show_all() + DragAndDropDemo() gtk.main() - + if __name__ == '__main__': main() diff --git a/examples/pygtk-demo/demos/editable_cells.py b/examples/pygtk-demo/demos/editable_cells.py index 07d198d9..a8acb5c3 100644 --- a/examples/pygtk-demo/demos/editable_cells.py +++ b/examples/pygtk-demo/demos/editable_cells.py @@ -1,144 +1,166 @@ -"""Tree View/Editable Cells +#!/usr/bin/env python +'''Tree View/Editable Cells -This demo demonstrates the use of editable cells in a GtkTreeView. If -you're new to the GtkTreeView widgets and associates, look into -the GtkListStore example first. - -""" - -description = 'Editable cells' +This demo demonstrates the use of editable cells in a GtkTreeView. +If you're new to the GtkTreeView widgets and associates, look into the +GtkListStore example first.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> import gobject import gtk -from gtk import TRUE, FALSE - -COLUMN_NUMBER = 0 -COLUMN_PRODUCT = 1 -COLUMN_EDITABLE = 2 - -ARTICLES = [ - [3, "bottles of coke", TRUE], - [5, "packages of noodles", TRUE], - [2, "packages of chocolate chip cookies", TRUE], - [1, "can vanilla ice cream", TRUE], - [6, "eggs", TRUE] + +# columns +( + COLUMN_NUMBER, + COLUMN_PRODUCT, + COLUMN_EDITABLE +) = range(3) + +# data +articles = [ + [ 3, "bottles of coke", True ], + [ 5, "packages of noodles", True ], + [ 2, "packages of chocolate chip cookies", True ], + [ 1, "can vanilla ice cream", True ], + [ 6, "eggs", True ] ] -def create_model(): - # create model - model = gtk.ListStore(gobject.TYPE_INT, - gobject.TYPE_STRING, - gobject.TYPE_BOOLEAN) +class EditableCellsDemo(gtk.Window): + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) + self.set_border_width(5) + self.set_default_size(320, 200) + + vbox = gtk.VBox(False, 5) + self.add(vbox) + + label = gtk.Label("Shopping list (you can edit the cells!)") + vbox.pack_start(label, False, False) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + vbox.pack_start(sw) + + # create model + model = self.__create_model() + + # create tree view + treeview = gtk.TreeView(model) + treeview.set_rules_hint(True) + treeview.get_selection().set_mode(gtk.SELECTION_SINGLE) + + self.__add_columns(treeview) + + sw.add(treeview) + + # some buttons + hbox = gtk.HBox(True, 4) + vbox.pack_start(hbox, False, False) + + button = gtk.Button("Add item") + button.connect("clicked", self.on_add_item_clicked, model) + hbox.pack_start(button) + + button = gtk.Button("Remove item") + button.connect("clicked", self.on_remove_item_clicked, treeview) + hbox.pack_start(button) + + self.show_all() + + def __create_model(self): + + # create list store + model = gtk.ListStore( + gobject.TYPE_INT, + gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN + ) + + # add items + for item in articles: + iter = model.append() + + model.set (iter, + COLUMN_NUMBER, item[COLUMN_NUMBER], + COLUMN_PRODUCT, item[COLUMN_PRODUCT], + COLUMN_EDITABLE, item[COLUMN_EDITABLE] + ) + return model + + + def __add_columns(self, treeview): + + model = treeview.get_model() + + # number column + renderer = gtk.CellRendererText() + renderer.connect("edited", self.on_cell_edited, model) + renderer.set_data("column", COLUMN_NUMBER) + + column = gtk.TreeViewColumn("Number", renderer, text=COLUMN_NUMBER, + editable=COLUMN_EDITABLE) + treeview.append_column(column) + + # product column + renderer = gtk.CellRendererText() + renderer.connect("edited", self.on_cell_edited, model) + renderer.set_data("column", COLUMN_PRODUCT) + + column = gtk.TreeViewColumn("Product", renderer, text=COLUMN_PRODUCT, + editable=COLUMN_EDITABLE) + treeview.append_column(column) + + + def on_add_item_clicked(self, button, model): + new_item = [0, "Description here", True] + articles.append(new_item) - # insert articles - for article in ARTICLES: iter = model.append() - model.set(iter, - COLUMN_NUMBER, article[0], - COLUMN_PRODUCT, article[1], - COLUMN_EDITABLE, article[2]) - return model - -def add_item(button, model): - item = [0, "Description here", TRUE] - - ARTICLES.append(item) - - iter = model.append() - model.set(iter, - COLUMN_NUMBER, item[0], - COLUMN_PRODUCT, item[1], - COLUMN_EDITABLE, item[2]) - -def remove_item(button, treeview): - selection = treeview.get_selection() - selected = selection.get_selected() - if selected: - model, iter = selected - i = model.get_path(iter)[0] - model.remove(iter) - ARTICLES.pop(i) - -def cell_edited (cell, row, new_text, model): - article = ARTICLES[int(row)] - iter = model.get_iter_from_string(row) - - column = cell.get_data("column") - if column == COLUMN_NUMBER: - article[column] = int(new_text) - model.set(iter, column, article[column]) - elif column == COLUMN_PRODUCT: - article[column] = new_text - model.set(iter, column, article[column]) - -def add_columns(treeview): - model = treeview.get_model() - - # number column - renderer = gtk.CellRendererText() - renderer.connect('edited', cell_edited, model) - renderer.set_data('column', COLUMN_NUMBER) - treeview.insert_column_with_attributes(-1, 'Number', renderer, - text=COLUMN_NUMBER, - editable=COLUMN_EDITABLE) - # product column - renderer = gtk.CellRendererText() - renderer.connect('edited', cell_edited, model) - renderer.set_data('column', COLUMN_PRODUCT) - - treeview.insert_column_with_attributes(-1, 'Number', renderer, - text=COLUMN_PRODUCT, - editable=COLUMN_EDITABLE) - -def main(): - # create window, etc - window = gtk.Window() - window.set_title('Shopping list') - window.set_border_width(5) - window.connect('destroy', lambda win: gtk.mainquit()) + model.set (iter, + COLUMN_NUMBER, new_item[COLUMN_NUMBER], + COLUMN_PRODUCT, new_item[COLUMN_PRODUCT], + COLUMN_EDITABLE, new_item[COLUMN_EDITABLE] + ) - vbox = gtk.VBox() - window.add(vbox) - label = gtk.Label("Shopping list (you can edit the cells!)") - vbox.pack_start(label, FALSE, FALSE) + def on_remove_item_clicked(self, button, treeview): - sw = gtk.ScrolledWindow() - sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) - sw.set_policy(gtk.POLICY_AUTOMATIC, - gtk.POLICY_AUTOMATIC) - vbox.pack_start(sw) + selection = treeview.get_selection() + model, iter = selection.get_selected() - # create model - model = create_model() + if iter: + path = model.get_path(iter)[0] + model.remove(iter) - # create tree view - treeview = gtk.TreeView(model) - treeview.set_rules_hint(TRUE) - treeview.set_headers_visible(TRUE) - selection = treeview.get_selection() - selection.set_mode(gtk.SELECTION_SINGLE) + del articles[ path ] - add_columns(treeview) - sw.add(treeview) + def on_cell_edited(self, cell, path_string, new_text, model): - # some buttons - hbox = gtk.HBox() - vbox.pack_start(hbox, FALSE, FALSE) + iter = model.get_iter_from_string(path_string) + path = model.get_path(iter)[0] + column = cell.get_data("column") - button = gtk.Button('Add item') - button.connect('clicked', add_item, model) - hbox.pack_start(button) - - button = gtk.Button('Remove item') - button.connect('clicked', remove_item, treeview) - hbox.pack_start(button) + if column == COLUMN_NUMBER: + articles[path][COLUMN_NUMBER] = int(new_text) - window.set_default_size(330, 220) - window.show_all() + model.set(iter, column, articles[path][COLUMN_NUMBER]) + elif column == COLUMN_PRODUCT: + old_text = model.get_value(iter, column) + articles[path][COLUMN_PRODUCT] = new_text + + model.set(iter, column, articles[path][COLUMN_PRODUCT]) + +def main(): + EditableCellsDemo() gtk.main() - -if __name__=="__main__": + +if __name__ == '__main__': main() diff --git a/examples/pygtk-demo/demos/entry_completion.py b/examples/pygtk-demo/demos/entry_completion.py new file mode 100644 index 00000000..52e8568c --- /dev/null +++ b/examples/pygtk-demo/demos/entry_completion.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +'''Entry Completion + +GtkEntryCompletion provides a mechanism for adding support for +completion in GtkEntry. +''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import gtk + +class EntryCompletionDemo(gtk.Dialog): + + def __init__(self, parent=None): + gtk.Dialog.__init__(self, self.__class__.__name__, parent, + 0, + (gtk.STOCK_CLOSE, gtk.RESPONSE_NONE)) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.connect("response", lambda d, r: d.destroy()) + self.set_resizable(False) + + vbox = gtk.VBox(False, 5) + self.vbox.pack_start(vbox, True, True, 0) + vbox.set_border_width(5) + + label = gtk.Label() + label.set_markup("Completion demo, try writing <b>total</b> " + "or <b>gnome</b> for example.") + vbox.pack_start(label, False, False, 0) + + # Create our entry + entry = gtk.Entry() + vbox.pack_start(entry, False, False, 0) + + # Create the completion object + completion = gtk.EntryCompletion() + + # Assign the completion to the entry + entry.set_completion(completion) + + # Create a tree model and use it as the completion model + completion_model = self.__create_completion_model() + completion.set_model(completion_model) + + # Use model column 0 as the text column + completion.set_text_column(0) + + self.show_all() + + def __create_completion_model(self): + ''' Creates a tree model containing the completions. + ''' + store = gtk.ListStore(str) + + # Append one word + iter = store.append() + store.set(iter, 0, "GNOME") + + # Append another word + iter = store.append() + store.set(iter, 0, "total") + + # And another word + iter = store.append() + store.set(iter, 0, "totally") + + return store + +def main(): + EntryCompletionDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/examples/pygtk-demo/demos/entrycompletion.py b/examples/pygtk-demo/demos/entrycompletion.py deleted file mode 100644 index 3148aad8..00000000 --- a/examples/pygtk-demo/demos/entrycompletion.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Entry Completion - - gtk.EntryCompletion Test - (c) Fernando San MartÃn Woerner 2004 - snmartin@galilea.cl - - A simple test for gtk.EntryCompletion widget -""" -description = 'Entry Completion' - - -import pygtk; pygtk.require("2.0") -import gobject -import gtk - -def on_match_selected(completion, model, iter): - month = model.get_value(iter,0) - print "You have selected " + month - -def main(): - # The window... - window = gtk.Window() - window.set_title("EntryCompletion Test") - window.connect('delete-event', gtk.main_quit) - - # The entry to fill with autocompletion - entry = gtk.Entry() - - # The EntryCompletion Widget - compl = gtk.EntryCompletion() - - # Connected to on_match_selected - compl.connect("match-selected", on_match_selected) - - # The model with autocompletion - model = gtk.ListStore(str) - - # A model and a text column - compl.set_model(model) - compl.set_text_column(0) - - # Adding rows - model.append(["JANUARY"]) - model.append(["FEBRUARY"]) - model.append(["MARCH"]) - model.append(["APRIL"]) - model.append(["MAY"]) - model.append(["JUN"]) - model.append(["JULY"]) - model.append(["AUGUST"]) - model.append(["SEPTEMBER"]) - model.append(["OCTOBER"]) - model.append(["NOVEMBER"]) - model.append(["DECEMBER"]) - - # Setting the widgets together - entry.set_completion(compl) - - vbox = gtk.VBox() - window.add(vbox) - vbox.pack_start(gtk.Label("Type a month:")) - vbox.pack_start(entry) - window.show_all() - # Running - gtk.main() - - -if __name__ == '__main__': - main() diff --git a/examples/pygtk-demo/demos/expander.py b/examples/pygtk-demo/demos/expander.py new file mode 100644 index 00000000..37f6b5b7 --- /dev/null +++ b/examples/pygtk-demo/demos/expander.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +'''Expander + +GtkExpander allows to provide additional content that is initially hidden. +This is also known as "disclosure triangle". +''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import gtk + +class ExpanderDemo(gtk.Dialog): + + def __init__(self, parent=None): + gtk.Dialog.__init__(self, self.__class__.__name__, parent, + 0, + (gtk.STOCK_CLOSE, gtk.RESPONSE_NONE)) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.connect("response", lambda d, r: d.destroy()) + self.set_resizable(False) + + vbox = gtk.VBox(False, 5) + self.vbox.pack_start(vbox, True, True, 0) + vbox.set_border_width(5) + + label = gtk.Label() + label.set_markup("Expander demo. Click on the triangle for details.") + vbox.pack_start(label, False, False, 0) + + # Create the expander + expander = gtk.Expander("Details") + vbox.pack_start(expander, False, False, 0) + + # The Label for the expander + label = gtk.Label("Details can be shown or hidden.") + expander.add(label) + + self.show_all() + +def main(): + ExpanderDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/examples/pygtk-demo/demos/hypertext.py b/examples/pygtk-demo/demos/hypertext.py new file mode 100644 index 00000000..d7386b3d --- /dev/null +++ b/examples/pygtk-demo/demos/hypertext.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python +'''Text Widget/Hypertext + +Usually, tags modify the appearance of text in the view, e.g. making it +bold or colored or underlined. But tags are not restricted to appearance. +They can also affect the behavior of mouse and key presses, as this demo +shows.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import gtk +import pango + +class HypertextDemo(gtk.Window): + hovering_over_link = False + hand_cursor = gtk.gdk.Cursor(gtk.gdk.HAND2) + regular_cursor = gtk.gdk.Cursor(gtk.gdk.XTERM) + + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_default_size(450, 450) + self.set_border_width(0) + + view = gtk.TextView() + view.set_wrap_mode(gtk.WRAP_WORD) + view.connect("key-press-event", self.key_press_event) + view.connect("event-after", self.event_after) + view.connect("motion-notify-event", self.motion_notify_event) + view.connect("visibility-notify-event", self.visibility_notify_event) + + buffer = view.get_buffer() + + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.add(sw) + sw.add(view) + + self.show_page(buffer, 1) + + self.show_all() + + # Links can be activated by pressing Enter. + def key_press_event(self, text_view, event): + if event.keyval == gtk.gdk.Return or \ + event.keyval == gtk.gdk.KP_Enter: + buffer = text_view.get_buffer() + iter = buffer.get_iter_at_mark(buffer.get_insert()) + follow_if_link(text_view, iter) + return False + + # Links can also be activated by clicking. + def event_after(self, text_view, event): + if event.type != gtk.gdk.BUTTON_RELEASE: + return False + if event.button != 1: + return False + buffer = text_view.get_buffer() + + # we shouldn't follow a link if the user has selected something + try: + start, end = buffer.get_selection_bounds() + except ValueError: + # If there is nothing selected, None is return + pass + else: + if start.get_offset() != end.get_offset(): + return False + + x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, + int(event.x), int(event.y)) + iter = text_view.get_iter_at_location(x, y) + + self.follow_if_link(text_view, iter) + return False + + + # Looks at all tags covering the position (x, y) in the text view, + # and if one of them is a link, change the cursor to the "hands" cursor + # typically used by web browsers. + def set_cursor_if_appropriate(self, text_view, x, y): + hovering = False + + buffer = text_view.get_buffer() + iter = text_view.get_iter_at_location(x, y) + + tags = iter.get_tags() + for tag in tags: + page = tag.get_data("page") + if page != 0: + hovering = True + break + + if hovering != self.hovering_over_link: + self.hovering_over_link = hovering + + if self.hovering_over_link: + text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.hand_cursor) + else: + text_view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(self.regular_cursor) + + # Update the cursor image if the pointer moved. + def motion_notify_event(self, text_view, event): + x, y = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, + int(event.x), int(event.y)) + self.set_cursor_if_appropriate(text_view, x, y) + text_view.window.get_pointer() + return False + + # Also update the cursor image if the window becomes visible + # (e.g. when a window covering it got iconified). + def visibility_notify_event(self, text_view, event): + wx, wy, mod = text_view.window.get_pointer() + bx, by = text_view.window_to_buffer_coords(gtk.TEXT_WINDOW_WIDGET, wx, wy) + + self.set_cursor_if_appropriate (text_view, bx, by) + return False + + def insert_link(self, buffer, iter, text, page): + ''' Inserts a piece of text into the buffer, giving it the usual + appearance of a hyperlink in a web browser: blue and underlined. + Additionally, attaches some data on the tag, to make it recognizable + as a link. + ''' + tag = buffer.create_tag(None, + foreground="blue", underline=pango.UNDERLINE_SINGLE) + tag.set_data("page", page) + buffer.insert_with_tags(iter, text, tag) + + + def show_page(self, buffer, page): + ''' Fills the buffer with text and interspersed links. In any real + hypertext app, this method would parse a file to identify the links. + ''' + buffer.set_text("", 0) + iter = buffer.get_iter_at_offset(0) + if page == 1: + buffer.insert(iter, "Some text to show that simple ") + self.insert_link(buffer, iter, "hypertext", 3) + buffer.insert(iter, " can easily be realized with ") + self.insert_link(buffer, iter, "tags", 2) + buffer.insert(iter, ".") + + elif page == 2: + buffer.insert(iter, + "A tag is an attribute that can be applied to some range of text. " + "For example, a tag might be called \"bold\" and make the text inside " + "the tag bold. However, the tag concept is more general than that " + "tags don't have to affect appearance. They can instead affect the " + "behavior of mouse and key presses, \"lock\" a range of text so the " + "user can't edit it, or countless other things.\n", -1) + self.insert_link(buffer, iter, "Go back", 1) + elif page == 3: + tag = buffer.create_tag(None, weight=pango.WEIGHT_BOLD) + buffer.insert_with_tags(iter, "hypertext:\n", tag) + buffer.insert(iter, + "machine-readable text that is not sequential but is organized " + "so that related items of information are connected.\n") + self.insert_link(buffer, iter, "Go back", 1) + + + def follow_if_link(self, text_view, iter): + ''' Looks at all tags covering the position of iter in the text view, + and if one of them is a link, follow it by showing the page identified + by the data attached to it. + ''' + tags = iter.get_tags() + for tag in tags: + page = tag.get_data("page") + if page != 0: + self.show_page(text_view.get_buffer(), page) + break + + +def main(): + HypertextDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/examples/pygtk-demo/demos/images.py b/examples/pygtk-demo/demos/images.py index e6cc7cb7..d3f0a7c3 100644 --- a/examples/pygtk-demo/demos/images.py +++ b/examples/pygtk-demo/demos/images.py @@ -1,164 +1,306 @@ #!/usr/bin/env python -# -# Copyright (C) 2004 Joey Tsai <joeytsai@joeytsai.com> -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -"""Images +'''Images GtkImage is used to display an image; the image can be in a number of formats. Typically, you load an image into a GdkPixbuf, then display the pixbuf. - This demo code shows some of the more obscure cases, in the simple case a call -to gtk.Image's set_from_file() is all you need. -""" - -import sys - -import pygtk -pygtk.require("2.0") +to gtk_image_new_from_file() is all you need. +If you want to put image data in your program as a C variable, use the +make-inline-pixbuf program that comes with GTK+. This way you won't need to +depend on loading external files, your application binary can be self-contained.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> +import os import gobject import gtk -description = "Images" +IMAGEDIR = os.path.join(os.path.dirname(__file__), 'images') +ALPHA_IMAGE = os.path.join(IMAGEDIR, 'alphatest.png') +GTKLOGO_IMAGE = os.path.join(IMAGEDIR, 'gtk-logo-rgb.gif') +BUDDY_IMAGE = os.path.join(IMAGEDIR, 'floppybuddy.gif') -def error_dialog(message, parent=None): - dialog = gtk.MessageDialog(parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, message) - dialog.run() - dialog.destroy() +def progressive_prepared_callback(loader, image): + pixbuf = loader.get_pixbuf() -def on_timeout(loader, fileobject): - run_again = True + # Avoid displaying random memory contents, since the pixbuf + # isn't filled in yet. + #images.c -> gdk_pixbuf_fill(pixbuf, 0xaaaaaaff) + pixbuf.fill(0) + image.set_from_pixbuf(pixbuf) - try: - bytes = fileobject.read(256) - loader.write(bytes) - except (IOError, gobject.GError), e: - error_dialog(str(e)) - run_again = False - if not bytes: - run_again = False +def progressive_updated_callback(loader, x, y, width, height, image): + ''' We know the pixbuf inside the GtkImage has changed, but the image + itself doesn't know this; so queue a redraw. If we wanted to be + really efficient, we could use a drawing area or something + instead of a GtkImage, so we could control the exact position of + the pixbuf on the display, then we could queue a draw for only + the updated area of the image. + ''' + image.queue_draw() - if not run_again: - try: - fileobject.close() - loader.close() - except gobject.GError, e: - # bug 136989, loader.close() will throw an exception - pass +class ImagesDemo(gtk.Window): + pixbuf_loader = None + load_timeout = None + image_stream = None - return run_again + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.connect("destroy", self.cleanup_callback) + self.set_title(self.__class__.__name__) + self.set_border_width(8) -def on_area_prepared(loader, image): - pixbuf = loader.get_pixbuf() - image.set_from_pixbuf(pixbuf) + vbox = gtk.VBox(False, 8) + vbox.set_border_width(8) + self.add(vbox) -def on_area_updated(loader, x, y, w, h, image): - image.queue_draw() + label = gtk.Label(); + label.set_markup("<u>Image loaded from a file</u>") + vbox.pack_start(label, False, False, 0) -def get_progressive_image(filename): - try: - fileobject = open(filename, "r") - except IOError, e: - error_dialog(str(e)) - return + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) - image = gtk.Image() + # The alignment keeps the frame from growing when users resize + # the window + align = gtk.Alignment(0.5, 0.5, 0, 0) + align.add(frame) + vbox.pack_start(align, False, False, 0) - loader = gtk.gdk.PixbufLoader() - loader.connect("area_prepared", on_area_prepared, image) - loader.connect("area_updated", on_area_updated, image) - - gobject.timeout_add(150, on_timeout, loader, fileobject) + image = gtk.Image() - return image + # use the current directory for the file + try: + pixbuf = gtk.gdk.pixbuf_new_from_file(GTKLOGO_IMAGE) + image.set_from_pixbuf(pixbuf) -def get_image(filename): - try: - anim = gtk.gdk.PixbufAnimation(filename) - except gobject.GError, e: - error_dialog(str(e)) - return + except gobject.GError, error: - image = gtk.Image() + # This code shows off error handling. You can just use + # gtk_image_new_from_file() instead if you don't want to report + # errors to the user. If the file doesn't load when using + # gtk_image_new_from_file(), a "missing image" icon will + # be displayed instead. - if anim.is_static_image(): - image.set_from_pixbuf( anim.get_static_image() ) - else: - image.set_from_animation( anim ) + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Unable to open image file 'gtk-logo-rgb.gif': \n%s" % error) - return image + dialog.connect("response", lambda dlg, resp: dlg.destroy()) + dialog.show() -def align_image(image, label_text): - label = gtk.Label() - label.set_markup("<u>%s</u>" % label_text) + frame.add(image) - frame = gtk.Frame() - frame.set_shadow_type(gtk.SHADOW_IN) + # Animation - if image: - frame.add(image) - else: - frame.add(gtk.Label("(No image)")) + label = gtk.Label() + label.set_markup("<u>Animation loaded from a file</u>") + vbox.pack_start(label, False, False, 0) - align = gtk.Alignment(0.5, 0.5, 0, 0) - align.add(frame) + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) - vbox = gtk.VBox(spacing=8) - vbox.set_border_width(4) - vbox.pack_start(label) - vbox.pack_start(align) + # The alignment keeps the frame from growing when users resize + # the window - return vbox + align = gtk.Alignment(0.5, 0.5, 0, 0) + align.add(frame) + vbox.pack_start(align, False, False, 0) -def on_button_toggled(button, vbox): - for widget in vbox.get_children(): - if widget != button: - widget.set_sensitive(not button.get_active()) + image = gtk.Image() + image.set_from_file(BUDDY_IMAGE); + frame.add(image) -def main(): - vbox = gtk.VBox() + # Progressive - button = gtk.ToggleButton("_Insensitive") - button.connect("toggled", on_button_toggled, vbox) + label = gtk.Label() + label.set_markup("<u>Progressive image loading</u>") + vbox.pack_start(label, False, False, 0) - i1 = get_image("gtk-logo-rgb.gif") - i2 = get_image("floppybuddy.gif") - i3 = get_progressive_image("alphatest.png") + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) - vbox.pack_start(align_image(i1, "Image loaded from a file")) - vbox.pack_start(align_image(i2, "Animation loaded from a file")) - vbox.pack_start(align_image(i3, "Progressive image loading")) - vbox.pack_start(button) + # The alignment keeps the frame from growing when users resize + # the window - win = gtk.Window() - win.set_title("Images") - win.set_border_width(8) - win.connect("destroy", gtk.main_quit) - win.add(vbox) - win.show_all() + align = gtk.Alignment(0.5, 0.5, 0, 0) + align.add(frame) + vbox.pack_start(align, False, False, 0) - gtk.main() + # Create an empty image for now; the progressive loader + # will create the pixbuf and fill it in. + + image = gtk.Image() + image.set_from_pixbuf(None) + frame.add(image) + + self.start_progressive_loading(image) + + # Sensitivity control + + button = gtk.ToggleButton("_Insensitive"); + vbox.pack_start(button, False, False, 0) + + button.connect("toggled", self.on_sensitivity_toggled, vbox) + + self.show_all() + + def cleanup_callback(self, win): + if self.load_timeout != 0: + gtk.timeout_remove(self.load_timeout) + self.load_timeout = 0 + + if self.pixbuf_loader is not None: + self.pixbuf_loader.close() + self.pixbuf_loader = None + + if self.image_stream is not None: + self.image_stream.close() + self.image_stream = None + + + def on_sensitivity_toggled(self, togglebutton, container): + children = container.get_children() + + for child in children: + + # don't disable our toggle + if type(child) != type(togglebutton): + child.set_sensitive(not togglebutton.get_active()) + + def start_progressive_loading(self, image): + ''' This is obviously totally contrived(we slow down loading + on purpose to show how incremental loading works). + The real purpose of incremental loading is the case where + you are reading data from a slow source such as the network. + The timeout simply simulates a slow data source by inserting + pauses in the reading process. + ''' + self.load_timeout = gtk.timeout_add(150, self.progressive_timeout, image) + + def progressive_timeout(self, image): + + # This shows off fully-paranoid error handling, so looks scary. + # You could factor out the error handling code into a nice separate + # function to make things nicer. + + if self.image_stream is not None: # file is already opened + try: + buf = self.image_stream.read(256) + bytes_read = len(buf) + + except IOError, error: + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Failure reading image file 'alphatest.png': %s" % error) + + dialog.connect("response", lambda d, r: d.destroy()) + + self.image_stream.close() + self.image_stream = None + + dialog.show() - return 0 + self.load_timeout = 0 + + return False; # uninstall the timeout + + if not self.pixbuf_loader.write(buf, bytes_read): + + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Failed to load image") + + dialog.connect("response", lambda d, r: d.destroy()) + + self.image_stream.close() + self.image_stream = None + + dialog.show() + + self.load_timeout = 0 + + return False # uninstall the timeout + + #if(feof(image_stream)): + if bytes_read == 0: + + self.image_stream.close() + self.image_stream = None + + # Errors can happen on close, e.g. if the image + # file was truncated we'll know on close that + # it was incomplete. + + if not self.pixbuf_loader.close(): + + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Failed to load image") + + dialog.connect("response", lambda d, r: dlg.destroy()) + dialog.show() + + self.pixbuf_loader = None + + self.load_timeout = 0 + + return False # uninstall the timeout + + # if feof(image_stream) + self.pixbuf_loader = None + + else: # if(image_stream) ... + try: + self.image_stream = open(ALPHA_IMAGE, "rb") + + except IOError, error: + error_message = "Unable to open image file 'alphatest.png' : %s" + + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + error_message % error) + + dialog.connect("response", lambda d, r: d.destroy()) + dialog.show() + + self.load_timeout = 0 + + return False # uninstall the timeout + + if self.pixbuf_loader is not None: + self.pixbuf_loader.close() + self.pixbuf_loader = None + + self.pixbuf_loader = gtk.gdk.PixbufLoader() + + self.pixbuf_loader.connect("area_prepared", + progressive_prepared_callback, image) + + self.pixbuf_loader.connect("area_updated", + progressive_updated_callback, image) + + # leave timeout installed + return True; + +def main(): + ImagesDemo() + gtk.main() -if __name__ == "__main__": - sys.exit(main()) +if __name__ == '__main__': + main() diff --git a/examples/pygtk-demo/alphatest.png b/examples/pygtk-demo/demos/images/alphatest.png Binary files differindex eb5885f8..eb5885f8 100644 --- a/examples/pygtk-demo/alphatest.png +++ b/examples/pygtk-demo/demos/images/alphatest.png diff --git a/examples/pygtk-demo/demos/images/apple-red.png b/examples/pygtk-demo/demos/images/apple-red.png Binary files differnew file mode 100644 index 00000000..b0a24e94 --- /dev/null +++ b/examples/pygtk-demo/demos/images/apple-red.png diff --git a/examples/pygtk-demo/demos/images/background.jpg b/examples/pygtk-demo/demos/images/background.jpg Binary files differnew file mode 100644 index 00000000..86c006aa --- /dev/null +++ b/examples/pygtk-demo/demos/images/background.jpg diff --git a/examples/pygtk-demo/floppybuddy.gif b/examples/pygtk-demo/demos/images/floppybuddy.gif Binary files differindex ac986c8e..ac986c8e 100644 --- a/examples/pygtk-demo/floppybuddy.gif +++ b/examples/pygtk-demo/demos/images/floppybuddy.gif diff --git a/examples/pygtk-demo/demos/images/gnome-applets.png b/examples/pygtk-demo/demos/images/gnome-applets.png Binary files differnew file mode 100644 index 00000000..8d3549e9 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-applets.png diff --git a/examples/pygtk-demo/demos/images/gnome-calendar.png b/examples/pygtk-demo/demos/images/gnome-calendar.png Binary files differnew file mode 100644 index 00000000..889f329a --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-calendar.png diff --git a/examples/pygtk-demo/demos/images/gnome-foot.png b/examples/pygtk-demo/demos/images/gnome-foot.png Binary files differnew file mode 100644 index 00000000..04766585 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-foot.png diff --git a/examples/pygtk-demo/demos/images/gnome-gimp.png b/examples/pygtk-demo/demos/images/gnome-gimp.png Binary files differnew file mode 100644 index 00000000..f6bbc6d3 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-gimp.png diff --git a/examples/pygtk-demo/demos/images/gnome-gmush.png b/examples/pygtk-demo/demos/images/gnome-gmush.png Binary files differnew file mode 100644 index 00000000..0a4b0d04 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-gmush.png diff --git a/examples/pygtk-demo/demos/images/gnome-gsame.png b/examples/pygtk-demo/demos/images/gnome-gsame.png Binary files differnew file mode 100644 index 00000000..01c06115 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnome-gsame.png diff --git a/examples/pygtk-demo/demos/images/gnu-keys.png b/examples/pygtk-demo/demos/images/gnu-keys.png Binary files differnew file mode 100644 index 00000000..58a33770 --- /dev/null +++ b/examples/pygtk-demo/demos/images/gnu-keys.png diff --git a/examples/pygtk-demo/gtk-logo-rgb.gif b/examples/pygtk-demo/demos/images/gtk-logo-rgb.gif Binary files differindex 63c622b9..63c622b9 100644 --- a/examples/pygtk-demo/gtk-logo-rgb.gif +++ b/examples/pygtk-demo/demos/images/gtk-logo-rgb.gif diff --git a/examples/pygtk-demo/demos/itemfactory.py b/examples/pygtk-demo/demos/itemfactory.py deleted file mode 100644 index cc049600..00000000 --- a/examples/pygtk-demo/demos/itemfactory.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python -"""Item Factory - -The GtkItemFactory object allows the easy creation of menus -from an array of descriptions of menu items.""" - -description = 'Item Factory' - -import gtk - -def ifactory_cb(action, widget): - print 'ItemFactory: activated "%s"' % (gtk.item_factory_path_from_widget(widget),) - -menu_items = ( - ('/_File', None, None, 0, '<Branch>' ), - ('/File/tearoff1', None, ifactory_cb, 0, '<Tearoff>'), - ('/File/_New', '<control>N', ifactory_cb, 0, ''), - ('/File/_Open', '<control>O', ifactory_cb, 0, ''), - ('/File/_Save', '<control>S', ifactory_cb, 0, ''), - ('/File/Save _As...', None, ifactory_cb, 0, ''), - ('/File/sep1', None, ifactory_cb, 0, '<Separator>'), - ('/File/_Quit', '<control>Q', ifactory_cb, 0, ''), - - ('/_Preferences', None, None, 0, '<Branch>'), - ('/_Preferences/_Color', None, None, 0, '<Branch>'), - ('/_Preferences/Color/_Red', None, ifactory_cb, 0, '<RadioItem>'), - ('/_Preferences/Color/_Green', None, ifactory_cb, 0, '/Preferences/Color/Red'), - ('/_Preferences/Color/_Blue', None, ifactory_cb, 0, '/Preferences/Color/Red'), - ('/_Preferences/_Shape', None, None, 0, '<Branch>'), - ('/_Preferences/Shape/_Square', None, ifactory_cb, 0, '<RadioItem>'), - ('/_Preferences/Shape/_Rectangle', None, ifactory_cb, 0, '/Preferences/Shape/Square'), - ('/_Preferences/Shape/_Oval', None, ifactory_cb, 0, '/Preferences/Shape/Rectangle'), - - ('/_Help', None, None, 0, '<LastBranch>'), - ('/Help/_About', None, ifactory_cb, 0, ''), - ) - -def main(): - win = gtk.Window() - win.connect('destroy', lambda win: gtk.main_quit()) - - win.set_title('Item Factory') - win.set_border_width(10) - - box1 = gtk.VBox() - win.add(box1) - win.set_title('Item Factory') - win.set_border_width(0) - - accelgroup = gtk.AccelGroup() - win.add_accel_group(accelgroup) - - item_factory = gtk.ItemFactory(gtk.MenuBar, '<main>', accelgroup) - item_factory.create_items(menu_items) - # this is required so that the item factory doesn't get freed when - # it goes out of scope. - win.item_factory = item_factory - - menubar = item_factory.get_widget('<main>') - box1.pack_start(menubar) - - label = gtk.Label('Type\n<F10>\nto start') - label.set_size_request(200, 200); - box1.pack_start(label) - - separator = gtk.HSeparator() - box1.pack_start(separator) - - box2 = gtk.VBox(gtk.FALSE, 10) - box2.set_border_width(10) - box1.pack_start(box2) - - button = gtk.Button('close') - button.connect('clicked', lambda button, win=win: win.destroy()) - box2.pack_start(button, gtk.TRUE, gtk.TRUE) - button.set_flags(gtk.CAN_DEFAULT) - button.grab_default() - - win.show_all() - gtk.main() - -if __name__ == '__main__': - main() diff --git a/examples/pygtk-demo/demos/list_store.py b/examples/pygtk-demo/demos/list_store.py index 8162433f..1d920bb3 100644 --- a/examples/pygtk-demo/demos/list_store.py +++ b/examples/pygtk-demo/demos/list_store.py @@ -1,130 +1,142 @@ #!/usr/bin/env python '''Tree View/List Store -The GtkListStore is used to store data in list form, to be used +The GtkListStore is used to store data in list form, to be used later on by a GtkTreeView to display it. This demo builds a simple GtkListStore and displays it. See the Stock Browser -demo for a more advanced example.''' # " - -description = 'List Store' +demo for a more advanced example.''' import gobject import gtk -from gtk import TRUE, FALSE -COLUMN_FIXED = 0 -COLUMN_NUMBER = 1 -COLUMN_SEVERITY = 2 -COLUMN_DESCRIPTION = 3 +( + COLUMN_FIXED, + COLUMN_NUMBER, + COLUMN_SEVERITY, + COLUMN_DESCRIPTION +) = range(4) data = \ -[[FALSE, 60482, 'Normal', 'scrollable notebooks and hidden tabs'], - [FALSE, 60620, 'Critical', - 'gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe'], - [FALSE, 50214, 'Major', 'Xft support does not clean up correctly'], - [TRUE, 52877, 'Major', 'GtkFileSelection needs a refresh method. '], - [FALSE, 56070, 'Normal', "Can't click button after setting in sensitive"], - [TRUE, 56355, 'Normal', 'GtkLabel - Not all changes propagate correctly'], - [FALSE, 50055, 'Normal', 'Rework width/height computations for TreeView'], - [FALSE, 58278, 'Normal', "gtk_dialog_set_response_sensitive () doesn't work"], - [FALSE, 55767, 'Normal', 'Getters for all setters'], - [FALSE, 56925, 'Normal', 'Gtkcalender size'], - [FALSE, 56221, 'Normal', 'Selectable label needs right-click copy menu'], - [TRUE, 50939, 'Normal', 'Add shift clicking to GtkTextView'], - [FALSE, 6112, 'Enhancement', 'netscape-like collapsable toolbars'], - [FALSE, 1, 'Normal', 'First bug :=)']] - -def create_model(): - store = gtk.ListStore(gobject.TYPE_BOOLEAN, - gobject.TYPE_UINT, - gobject.TYPE_STRING, - gobject.TYPE_STRING) - for item in data: - iter = store.append() - store.set(iter, COLUMN_FIXED, item[0], - COLUMN_NUMBER, item[1], - COLUMN_SEVERITY, item[2], - COLUMN_DESCRIPTION, item[3]) - return store - -def fixed_toggled(cell, path, model): - # get toggled iter - iter = model.get_iter((int(path),)) - fixed = model.get_value(iter, COLUMN_FIXED) - - # do something with the value - fixed = not fixed - - # set new value - model.set(iter, COLUMN_FIXED, fixed) - -def add_columns(treeview): - model = treeview.get_model() - - # column for fixed toggles - renderer = gtk.CellRendererToggle() - renderer.connect('toggled', fixed_toggled, model) - - column = gtk.TreeViewColumn('Fixed?', renderer, active=COLUMN_FIXED) - column.set_clickable(TRUE) - - # set this column to a fixed sizing(of 50 pixels) - column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - column.set_fixed_width(50) - column.set_clickable(TRUE) - - treeview.append_column(column) - - # column for bug numbers - column = gtk.TreeViewColumn('Bug Number', gtk.CellRendererText(), - text=COLUMN_NUMBER) - treeview.append_column(column) - - # columns for severities - column = gtk.TreeViewColumn('Severity', gtk.CellRendererText(), - text=COLUMN_SEVERITY) - treeview.append_column(column) - - # column for description - column = gtk.TreeViewColumn('Description', gtk.CellRendererText(), - text=COLUMN_DESCRIPTION) - treeview.append_column(column) - +((False, 60482, 'Normal', 'scrollable notebooks and hidden tabs'), + (False, 60620, 'Critical', + 'gdk_window_clear_area(gdkwindow-win32.c) is not thread-safe'), + (False, 50214, 'Major', 'Xft support does not clean up correctly'), + (True, 52877, 'Major', 'GtkFileSelection needs a refresh method. '), + (False, 56070, 'Normal', "Can't click button after setting in sensitive"), + (True, 56355, 'Normal', 'GtkLabel - Not all changes propagate correctly'), + (False, 50055, 'Normal', 'Rework width/height computations for TreeView'), + (False, 58278, 'Normal', "gtk_dialog_set_response_sensitive() doesn't work"), + (False, 55767, 'Normal', 'Getters for all setters'), + (False, 56925, 'Normal', 'Gtkcalender size'), + (False, 56221, 'Normal', 'Selectable label needs right-click copy menu'), + (True, 50939, 'Normal', 'Add shift clicking to GtkTextView'), + (False, 6112, 'Enhancement', 'netscape-like collapsable toolbars'), + (False, 1, 'Normal', 'First bug :=)')) + +class ListStoreDemo(gtk.Window): + def __init__(self, parent=None): + # create window, etc + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) + + self.set_border_width(8) + self.set_default_size(300, 250) + + vbox = gtk.VBox(False, 8) + self.add(vbox) + + label = gtk.Label('This is the bug list (note: not based on real data, ' + 'it would be nice to have a nice ODBC interface to bugzilla or so, though).') + vbox.pack_start(label, False, False) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + vbox.pack_start(sw) + + # create tree model + model = self.__create_model() + + # create tree view + treeview = gtk.TreeView(model) + treeview.set_rules_hint(True) + treeview.set_search_column(COLUMN_DESCRIPTION) + + sw.add(treeview) + + # add columns to the tree view + self.__add_columns(treeview) + + self.show_all() + + def __create_model(self): + lstore = gtk.ListStore( + gobject.TYPE_BOOLEAN, + gobject.TYPE_UINT, + gobject.TYPE_STRING, + gobject.TYPE_STRING) + + for item in data: + iter = lstore.append() + lstore.set(iter, + COLUMN_FIXED, item[COLUMN_FIXED], + COLUMN_NUMBER, item[COLUMN_NUMBER], + COLUMN_SEVERITY, item[COLUMN_SEVERITY], + COLUMN_DESCRIPTION, item[COLUMN_DESCRIPTION]) + return lstore + + def fixed_toggled(self, cell, path, model): + # get toggled iter + iter = model.get_iter((int(path),)) + fixed = model.get_value(iter, COLUMN_FIXED) + + # do something with the value + fixed = not fixed + + # set new value + model.set(iter, COLUMN_FIXED, fixed) + + def __add_columns(self, treeview): + model = treeview.get_model() + + # column for fixed toggles + renderer = gtk.CellRendererToggle() + renderer.connect('toggled', self.fixed_toggled, model) + + column = gtk.TreeViewColumn('Fixed?', renderer, active=COLUMN_FIXED) + + # set this column to a fixed sizing(of 50 pixels) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + + treeview.append_column(column) + + # column for bug numbers + column = gtk.TreeViewColumn('Bug Number', gtk.CellRendererText(), + text=COLUMN_NUMBER) + column.set_sort_column_id(COLUMN_NUMBER) + treeview.append_column(column) + + # columns for severities + column = gtk.TreeViewColumn('Severity', gtk.CellRendererText(), + text=COLUMN_SEVERITY) + column.set_sort_column_id(COLUMN_SEVERITY) + treeview.append_column(column) + + # column for description + column = gtk.TreeViewColumn('Description', gtk.CellRendererText(), + text=COLUMN_DESCRIPTION) + column.set_sort_column_id(COLUMN_DESCRIPTION) + treeview.append_column(column) + def main(): - win = gtk.Window() - win.connect('destroy', lambda win: gtk.main_quit()) - - win.set_title('GtkListStore demo') - win.set_border_width(8) - - vbox = gtk.VBox(FALSE, 8) - win.add(vbox) - - label = gtk.Label('This is the bug list (note: not based on real data, '+\ - 'it would be nice to have a nice ODBC interface to bugzilla or so, though).') - vbox.pack_start(label, FALSE, FALSE) - - sw = gtk.ScrolledWindow() - sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) - sw.set_policy(gtk.POLICY_NEVER, - gtk.POLICY_AUTOMATIC) - vbox.pack_start(sw) - - model = create_model() - - treeview = gtk.TreeView(model) - treeview.set_rules_hint(TRUE) - treeview.set_search_column(COLUMN_DESCRIPTION) - - sw.add(treeview) - - add_columns(treeview) - - win.set_default_size(280, 250) - - win.show_all() + ListStoreDemo() gtk.main() - + if __name__ == '__main__': main() - + diff --git a/examples/pygtk-demo/demos/menu.py b/examples/pygtk-demo/demos/menu.py index cc99e00e..3a61a427 100644 --- a/examples/pygtk-demo/demos/menu.py +++ b/examples/pygtk-demo/demos/menu.py @@ -1,76 +1,88 @@ #!/usr/bin/env python -'''Menus Test +'''Menu This example demonstrates the use of various menu types in gtk. It demonstrates the new submenu navigation and scrolling menu features of gtk 2.0.''' -description = 'Menus' - import gtk def create_menu(depth, length=5): if depth < 1: - return None + return None + menu = gtk.Menu() group= None + for i in range(length): - menuitem = gtk.RadioMenuItem(group, 'item %2d - %d' % (depth, i)) - group = menuitem - menu.add(menuitem) - menuitem.show() - if depth > 1: - submenu = create_menu(depth - 1) - menuitem.set_submenu(submenu) + menuitem = gtk.RadioMenuItem(group, 'item %2d - %d' % (depth, i)) + group = menuitem + menu.add(menuitem) + menuitem.show() + if depth > 1: + submenu = create_menu(depth - 1) + menuitem.set_submenu(submenu) return menu +class MenuDemo(gtk.Window): + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + + vbox = gtk.VBox() + self.add(vbox) + + menubar = gtk.MenuBar() + vbox.pack_start(menubar, expand=False) + + menuitem = gtk.MenuItem('test\nline2') + menuitem.set_submenu(create_menu(2, 50)) + menubar.add(menuitem) + + menuitem = gtk.MenuItem('foo') + menuitem.set_submenu(create_menu(2)) + menubar.add(menuitem) + + menuitem = gtk.MenuItem('bar') + menuitem.set_submenu(create_menu(2)) + menuitem.set_right_justified(True) + menubar.add(menuitem) + + vbox2 = gtk.VBox(spacing=10) + vbox2.set_border_width(10) + vbox.pack_start(vbox2) + + combo_box = gtk.combo_box_new_text() + combo_box.set_wrap_width(2) + for i in range(50): + combo_box.append_text('item - %d' % i) + combo_box.set_active(0) + vbox2.pack_start(combo_box) + + separator = gtk.HSeparator() + vbox.pack_start(separator, expand=False) + + vbox2 = gtk.VBox(spacing=10) + vbox2.set_border_width(10) + vbox.pack_start(vbox2, expand=False) + + button = gtk.Button('close') + button.connect('clicked', lambda button, w=self: w.destroy()) + vbox2.pack_start(button) + button.set_flags(gtk.CAN_DEFAULT) + button.grab_default() + + self.show_all() + def main(): - window = gtk.Window() - window.connect('destroy', lambda win: gtk.main_quit()) - window.set_title('Menus') - - vbox = gtk.VBox() - window.add(vbox) - - menubar = gtk.MenuBar() - vbox.pack_start(menubar, expand=gtk.FALSE) - - menuitem = gtk.MenuItem('test\nline2') - menuitem.set_submenu(create_menu(2, 50)) - menubar.add(menuitem) - - menuitem = gtk.MenuItem('foo') - menuitem.set_submenu(create_menu(2)) - menubar.add(menuitem) - - menuitem = gtk.MenuItem('bar') - menuitem.set_submenu(create_menu(2)) - menuitem.set_right_justified(gtk.TRUE) - menubar.add(menuitem) - - vbox2 = gtk.VBox(spacing=10) - vbox2.set_border_width(10) - vbox.pack_start(vbox2) - - optionmenu = gtk.OptionMenu() - optionmenu.set_menu(create_menu(1,50)) - vbox2.pack_start(optionmenu) - - separator = gtk.HSeparator() - vbox.pack_start(separator, expand=gtk.FALSE) - - vbox2 = gtk.VBox(spacing=10) - vbox2.set_border_width(10) - vbox.pack_start(vbox2, expand=gtk.FALSE) - - button = gtk.Button('close') - button.connect('clicked', lambda widget, window=window: window.destroy()) - vbox2.pack_start(button) - button.set_flags(gtk.CAN_DEFAULT) - button.grab_default() - - window.show_all() + MenuDemo() gtk.main() - + if __name__ == '__main__': main() diff --git a/examples/pygtk-demo/demos/panes.py b/examples/pygtk-demo/demos/panes.py index 1553ab4e..007ec077 100644 --- a/examples/pygtk-demo/demos/panes.py +++ b/examples/pygtk-demo/demos/panes.py @@ -5,111 +5,119 @@ The GtkHPaned and GtkVPaned Widgets divide their content area into two panes with a divider in between that the user can adjust. A separate child is placed into each pane. There are a number of options that can be set for each pane. This test contains -both a horizontal (HPaned) and a vertical (VPaned) widget, and allows you to +both a horizontal(HPaned) and a vertical(VPaned) widget, and allows you to adjust the options for each side of each widget.""" -description = "Paned Widgets" - import gtk -def toggle_resize(w, child): - paned = child.parent - - if child == paned.get_children()[0]: - paned.remove(child) - paned.pack1(child, w.get_active(), 0) - else: - paned.remove(child) - paned.pack2(child, w.get_active(), 0) - -def toggle_shrink(w, child): - paned = child.parent - - if child == paned.get_children()[0]: - paned.remove(child) - paned.pack1(child, 0, w.get_active()) - else: - paned.remove(child) - paned.pack2(child, 0, w.get_active()) - -def create_pane_options(paned, frame_label, label1, label2): - frame = gtk.Frame(frame_label) - frame.set_border_width(4) - - table = gtk.Table(3, 2, gtk.TRUE) - frame.add(table) - - label = gtk.Label(label1) - table.attach_defaults(label, 0, 1, 0, 1) - - check_button = gtk.CheckButton("_Resize") - check_button.connect('toggled', toggle_resize, paned.get_children()[0]) - table.attach_defaults(check_button, 0, 1, 1, 2) - - check_button = gtk.CheckButton("_Shrink") - check_button.set_active(gtk.TRUE) - check_button.connect('toggled', toggle_shrink, paned.get_children()[0]) - table.attach_defaults(check_button, 0, 1, 2, 3) - - label = gtk.Label(label2) - table.attach_defaults(label, 1, 2, 0, 1) - - check_button = gtk.CheckButton("_Resize") - check_button.set_active(gtk.TRUE) - check_button.connect('toggled', toggle_resize, paned.get_children()[1]) - table.attach_defaults(check_button, 1, 2, 1, 2) - - check_button = gtk.CheckButton("_Shrink") - check_button.set_active(gtk.TRUE) - check_button.connect('toggled', toggle_shrink, paned.get_children()[1]) - table.attach_defaults(check_button, 1, 2, 2, 3) - - return frame +class PanedWidgetsDemo(gtk.Window): + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_border_width(0) + + vbox = gtk.VBox(False, 0) + self.add(vbox) + + vpaned = gtk.VPaned() + vbox.pack_start(vpaned, True, True) + vpaned.set_border_width(5) + + hpaned = gtk.HPaned() + vpaned.add1(hpaned) + + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) + frame.set_size_request(60, 60) + hpaned.add1(frame) + + button = gtk.Button("_Hi there") + frame.add(button) + + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) + frame.set_size_request(80, 60) + hpaned.add2(frame) + + frame = gtk.Frame() + frame.set_shadow_type(gtk.SHADOW_IN) + frame.set_size_request(60, 80) + vpaned.add2(frame) + + # Now create toggle buttons to control sizing + + vbox.pack_start( + self.__create_pane_options(hpaned, "Horizontal", "Left", "Right"), + False, False, 0) + + vbox.pack_start( + self.__create_pane_options(vpaned, "Vertical", "Top", "Bottom"), + False, False, 0) + + self.show_all() + + def on_resize_toggled(self, tbutton, child): + paned = child.parent + + if child == paned.get_children()[0]: + paned.remove(child) + paned.pack1(child, tbutton.get_active(), 0) + else: + paned.remove(child) + paned.pack2(child, tbutton.get_active(), 0) + + def on_shrink_toggled(self, tbutton, child): + paned = child.parent + + if child == paned.get_children()[0]: + paned.remove(child) + paned.pack1(child, 0, tbutton.get_active()) + else: + paned.remove(child) + paned.pack2(child, 0, tbutton.get_active()) + + def __create_pane_options(self, paned, frame_label, label1, label2): + frame = gtk.Frame(frame_label) + frame.set_border_width(4) + + table = gtk.Table(3, 2, True) + frame.add(table) + + label = gtk.Label(label1) + table.attach(label, 0, 1, 0, 1) + + check_button = gtk.CheckButton("_Resize") + check_button.connect('toggled', self.on_resize_toggled, paned.get_children()[0]) + table.attach(check_button, 0, 1, 1, 2) + + check_button = gtk.CheckButton("_Shrink") + check_button.set_active(True) + check_button.connect('toggled', self.on_shrink_toggled, paned.get_children()[0]) + table.attach(check_button, 0, 1, 2, 3) + + label = gtk.Label(label2) + table.attach(label, 1, 2, 0, 1) + + check_button = gtk.CheckButton("_Resize") + check_button.set_active(True) + check_button.connect('toggled', self.on_resize_toggled, paned.get_children()[1]) + table.attach(check_button, 1, 2, 1, 2) + + check_button = gtk.CheckButton("_Shrink") + check_button.set_active(True) + check_button.connect('toggled', self.on_shrink_toggled, paned.get_children()[1]) + table.attach(check_button, 1, 2, 2, 3) + + return frame def main(): - window = gtk.Window() - window.set_title("Paned Widgets") - window.set_border_width(0) - window.connect('destroy', lambda win: gtk.main_quit()) - - vbox = gtk.VBox(gtk.FALSE, 0) - window.add(vbox) - - vpaned = gtk.VPaned() - vbox.pack_start(vpaned, gtk.TRUE, gtk.TRUE) - vpaned.set_border_width(5) - - hpaned = gtk.HPaned() - vpaned.add1(hpaned) - - frame = gtk.Frame() - frame.set_shadow_type(gtk.SHADOW_IN) - frame.set_size_request(60, 60) - hpaned.add1(frame) - - button = gtk.Button("_Hi there") - frame.add(button) - - frame = gtk.Frame() - frame.set_shadow_type(gtk.SHADOW_IN) - frame.set_size_request(80, 60) - hpaned.add2(frame) - - frame = gtk.Frame() - frame.set_shadow_type(gtk.SHADOW_IN) - frame.set_size_request(60, 80) - vpaned.add2(frame) - - # Now create toggle buttons to control sizing - - vbox.pack_start(create_pane_options(hpaned, "Horizontal", "Left", "Right"), - gtk.FALSE, gtk.FALSE, 0) - - vbox.pack_start(create_pane_options(vpaned, "Vertical", "Top", "Bottom"), - gtk.FALSE, gtk.FALSE, 0) - - window.show_all() - + PanedWidgetsDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/pixbufs.py b/examples/pygtk-demo/demos/pixbufs.py new file mode 100644 index 00000000..538a0209 --- /dev/null +++ b/examples/pygtk-demo/demos/pixbufs.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python +'''Pixbufs + +A GdkPixbuf represents an image, normally in RGB or RGBA format. +Pixbufs are normally used to load files from disk and perform image scaling. +This demo is not all that educational, but looks cool. It was written by +Extreme Pixbuf Hacker Federico Mena Quintero. It also shows off how to use +GtkDrawingArea to do a simple animation. +Look at the Image demo for additional pixbuf usage examples.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import os +import math +import gobject +import gtk + +FRAME_DELAY = 50 +CYCLE_LEN = 60 +IMAGE_DIR = os.path.join(os.path.dirname(__file__), 'images') +BACKGROUND_NAME = "background.jpg" + +image_names = [ + "apple-red.png", + "gnome-applets.png", + "gnome-calendar.png", + "gnome-foot.png", + "gnome-gmush.png", + "gnome-gimp.png", + "gnome-gsame.png", + "gnu-keys.png" +] + +class PixbufsDemo(gtk.Window): + frame = None # frame of the background image + background = None # background-pixbuf + images = [] # list of pixbufs + back_width = 0 # width of background image + back_height = 0 # height of background image + timeout_id = 0 # timeout id + frame_num = 0 # number of the current frame + timeout_id = None + + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect("destroy", lambda *w: gtk.main_quit()) + self.connect("destroy", self.cleanup_callback) + self.set_title(self.__class__.__name__) + self.set_resizable(False) + + if not self.load_pixbufs(): + dialog = gtk.MessageDialog(self, + gtk.DIALOG_DESTROY_WITH_PARENT, + gtk.MESSAGE_ERROR, + gtk.BUTTONS_CLOSE, + "Failed to load an image") + dialog.connect("response", lambda d, r: dlg.destroy()) + dialog.show() + + else: + self.set_size_request(self.back_width, self.back_height) + + self.frame = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, + self.back_width, self.back_height) + + da = gtk.DrawingArea() + da.connect("expose_event", self.expose_cb) + self.add(da) + + self.timeout_id = gtk.timeout_add(FRAME_DELAY, self.timeout) + + self.show_all() + + def load_pixbufs(self): + ''' Loads the images for the demo and returns whether the + operation succeeded. + ''' + if self.background is not None: + return True # already loaded earlier + + # look in the the current directory where the file is installed + try: + self.background = gtk.gdk.pixbuf_new_from_file( + os.path.join(IMAGE_DIR, BACKGROUND_NAME)) + except gobject.GError, error: + return False + + self.back_width = self.background.get_width() + self.back_height = self.background.get_height() + + for filename in image_names: + try: + self.images.append(gtk.gdk.pixbuf_new_from_file( + os.path.join(IMAGE_DIR, filename))) + except gobject.GError, error: + return False + + return True + + def expose_cb(self, draw_area, event): + ''' Expose callback for the drawing area. ''' + rowstride = self.frame.get_rowstride() + + # FIXME: what should be the result, string guchar an integer result? + #pixels = frame.get_pixels() + rowstride * event.area.y + event.area.x * 3 + #pixels = frame.get_pixels()[len(frame.get_pixels()) + rowstride * event.area.y + event.area.x * 3] + pixels = self.frame.get_pixels() + + # FIXME: draw_rgb_image_dithalign seems not to be available + #draw_area.window.draw_rgb_image_dithalign(widget.style.black_gc, + draw_area.window.draw_rgb_image( + draw_area.style.black_gc, + event.area.x, event.area.y, + event.area.width, event.area.height, + 'normal', + pixels, rowstride, + event.area.x, event.area.y) + + return True + + def cleanup_callback(self, win): + if self.timeout_id is not None: + gtk.timeout_remove(self.timeout_id) + self.timeout_id = None + + def timeout(self): + ''' Timeout handler to regenerate the frame. ''' + self.background.copy_area(0, 0, self.back_width, self.back_height, + self.frame, 0, 0) + + f = float(self.frame_num % CYCLE_LEN) / float(CYCLE_LEN) + + xmid = self.back_width / 2.0 + ymid = self.back_height / 2.0 + + radius = min(xmid, ymid) / 2.0 + + N_IMAGES = len(image_names) + for i_name in image_names: + i = image_names.index(i_name) + + ang = 2.0 * math.pi * i / N_IMAGES - f * 2.0 * math.pi + + iw = self.images[i].get_width() + ih = self.images[i].get_height() + + r = radius +(radius / 3.0) * math.sin(f * 2.0 * math.pi) + + xpos = math.floor(xmid + r * math.cos(ang) - iw / 2.0 + 0.5) + ypos = math.floor(ymid + r * math.sin(ang) - ih / 2.0 + 0.5) + + k = (i & 1) and math.sin(f * 2.0 * math.pi) or math.cos(f * 2.0 * math.pi) + k = 2.0 * k * k + k = max(0.25, k) + + # satisfy the c-source + r1 = gtk.gdk.Rectangle() + r1.x = int(xpos) + r1.y = int(ypos) + r1.width = iw * k + r1.height = ih * k + + r2 = gtk.gdk.Rectangle() + r2.x = 0 + r2.y = 0 + r2.width = self.back_width + r2.height = self.back_height + + dest = r1.intersect(r2) + if dest is not None: + self.images[i].composite( + self.frame, + dest.x, dest.y, + dest.width, dest.height, + xpos, ypos, + k, k, + gtk.gdk.INTERP_NEAREST, + ((i & 1) + and int(max(127, math.fabs(255 * math.sin(f * 2.0 * math.pi)))) + or int(max(127, math.fabs(255 * math.cos(f * 2.0 * math.pi)))))) + + if self is not None: + self.queue_draw() + + self.frame_num += 1 + return True + +def main(): + PixbufsDemo() + gtk.main() + +if __name__ == '__main__': + main() diff --git a/examples/pygtk-demo/demos/sizegroup.py b/examples/pygtk-demo/demos/sizegroup.py index d4a99c54..a780390e 100644 --- a/examples/pygtk-demo/demos/sizegroup.py +++ b/examples/pygtk-demo/demos/sizegroup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -"""Size Groups +"""Size Group GtkSizeGroup provides a mechanism for grouping a number of widgets together so they all request the same amount of space. This is typically useful when you @@ -12,96 +12,96 @@ actually be the same size, you need to pack them in such a way that they get the size they request and not more. For example, if you are packing your widgets into a table, you would not include the GTK_FILL flag.""" -description = "Size Groups" - import gtk -def create_option_menu(options): - menu = gtk.Menu() - for str in options: - menu_item = gtk.MenuItem(str) - menu_item.show() - gtk.MenuShell.append(menu, menu_item) - - option_menu = gtk.OptionMenu() - option_menu.set_menu(menu) - - return option_menu - -def add_row(table, row, size_group, label_text, options): - label = gtk.Label(label_text) - label.set_use_underline(gtk.TRUE) - label.set_alignment(0, 1) - table.attach(label, 0, 1, row, row + 1, gtk.EXPAND + gtk.FILL, 0, 0, 0) - - option_menu = create_option_menu(options) - label.set_mnemonic_widget(option_menu) - size_group.add_widget(option_menu) - table.attach(option_menu, 1, 2, row, row + 1, 0, 0, 0, 0) - -def toggle_grouping(check_button, size_group): - # gtk.SIZE_GROUP_NONE is not generally useful, but is useful - # here to show the effect of gtk.SIZE_GROUP_HORIZONTAL by - # contrast. - if check_button.get_active(): - size_group.set_mode(gtk.SIZE_GROUP_HORIZONTAL) - else: - size_group.set_mode(gtk.SIZE_GROUP_NONE) +class SizeGroupDemo(gtk.Dialog): + def __init__(self, parent=None): + gtk.Dialog.__init__(self, "Size Groups", parent, + 0, + (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.connect('response', lambda d, r: d.destroy()) + self.set_resizable(False) + + vbox = gtk.VBox(False, 5) + self.vbox.pack_start(vbox, True, True, 0) + vbox.set_border_width(5) + + self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) + + # Create one frame holding color options + frame = gtk.Frame("Color options") + vbox.pack_start(frame, True, True, 0) + + table = gtk.Table(2, 2, False) + table.set_border_width(5) + table.set_row_spacings(5) + table.set_col_spacings(10) + frame.add(table) + + color_options = ("Red", "Green", "Blue") + self.__add_row(table, 0, "_Foreground", color_options) + self.__add_row(table, 1, "_Background", color_options) + + # And another frame holding line style options + frame = gtk.Frame("Line options") + vbox.pack_start(frame, False, False, 0) + + table = gtk.Table(2, 2, False) + table.set_border_width(5) + table.set_row_spacings(5) + table.set_col_spacings(10) + frame.add(table) + + dash_options = ("Solid", "Dashed", "Dotted") + end_options = ("Square", "Round", "Arrow") + self.__add_row(table, 0, "_Dashing", dash_options) + self.__add_row(table, 1, "_Line ends", end_options) + + # And a check button to turn grouping on and off + + check_button = gtk.CheckButton("_Enable grouping") + vbox.pack_start(check_button, False, False, 0) + check_button.set_active(True) + check_button.connect('toggled', self.on_toggle_grouping) + + self.show_all() + + def __create_option_menu(self, options): + + option_menu = gtk.combo_box_new_text() + for opt in options: + option_menu.append_text(opt) + + option_menu.set_active(0) + return option_menu + + def __add_row(self, table, row, label_text, options): + label = gtk.Label(label_text) + label.set_use_underline(True) + label.set_alignment(0, 1) + table.attach(label, 0, 1, row, row + 1, gtk.EXPAND | gtk.FILL, 0, 0, 0) + + option_menu = self.__create_option_menu(options) + label.set_mnemonic_widget(option_menu) + self.size_group.add_widget(option_menu) + table.attach(option_menu, 1, 2, row, row + 1, 0, 0, 0, 0) + + def on_toggle_grouping(self, check_button): + + # gtk.SIZE_GROUP_NONE is not generally useful, but is useful + # here to show the effect of gtk.SIZE_GROUP_HORIZONTAL by + # contrast. + if check_button.get_active(): + self.size_group.set_mode(gtk.SIZE_GROUP_HORIZONTAL) + else: + self.size_group.set_mode(gtk.SIZE_GROUP_NONE) def main(): - color_options = ["Red", "Green", "Blue"] - dash_options = ["Solid", "Dashed", "Dotted"] - end_options = ["Square", "Round", "Arrow"] - - window = gtk.Dialog("GtkSizeGroups", None, 0, - (gtk.STOCK_CLOSE, gtk.RESPONSE_NONE)) - window.set_resizable(gtk.FALSE) - window.connect('response', lambda w, d: window.destroy()) - window.connect('destroy', lambda win: gtk.main_quit()) - - vbox = gtk.VBox(gtk.FALSE, 5) - window.vbox.pack_start(vbox, gtk.TRUE, gtk.TRUE, 0) - vbox.set_border_width(5) - - size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) - - # Create one frame holding color options - - frame = gtk.Frame("Color options") - vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, 0) - - table = gtk.Table(2, 2, gtk.FALSE) - table.set_border_width(5) - table.set_row_spacings(5) - table.set_col_spacings(10) - frame.add(table) - - add_row(table, 0, size_group, "_Foreground", color_options) - add_row(table, 1, size_group, "_Background", color_options) - - # And another frame holding line style options - - frame = gtk.Frame("Line options") - vbox.pack_start(frame, gtk.FALSE, gtk.FALSE, 0) - - table = gtk.Table(2, 2, gtk.FALSE) - table.set_border_width(5) - table.set_row_spacings(5) - table.set_col_spacings(10) - frame.add(table) - - add_row(table, 0, size_group, "_Dashing", dash_options) - add_row(table, 1, size_group, "_Line ends", end_options) - - # And a check button to turn grouping on and off - - check_button = gtk.CheckButton("_Enable grouping") - vbox.pack_start(check_button, gtk.FALSE, gtk.FALSE, 0) - check_button.set_active(gtk.TRUE) - check_button.connect('toggled', toggle_grouping, size_group) - - window.show_all() - + SizeGroupDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/stock_browser.py b/examples/pygtk-demo/demos/stock_browser.py index 179125cf..1689230f 100644 --- a/examples/pygtk-demo/demos/stock_browser.py +++ b/examples/pygtk-demo/demos/stock_browser.py @@ -1,218 +1,270 @@ -"""Stock Item and Icon Browser +#!/usr/bin/env python +'''Stock Item and Icon Browser -This source code for this demo doesn't demonstrate anything -particularly useful in applications. The purpose of the "demo" is - just to provide a handy place to browse the available stock icons - and stock items.""" - -description = "Stock Browser" +This source code for this demo doesn't demonstrate anything particularly +useful in applications. The purpose of the "demo" is just to provide a +handy place to browse the available stock icons and stock items. +''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> import gobject import gtk +import re -window = None - -class StockItemInfo(gobject.GObject): - id = '' - item = None - small_icon = None - macro = '' - accel_str = '' -gobject.type_register(StockItemInfo) - -class StockItemDisplay: - pass - -def id_to_macro(str): - if str.startswith('gtk-'): - str = str.replace('gtk-', 'gtk-stock-') - str = str.upper() - return str.replace('-', '_') - -def create_model(): - store = gtk.ListStore(StockItemInfo) - - ids = gtk.stock_list_ids() - ids.sort() - - for id in ids: - info = StockItemInfo() - info.id = id - item = gtk.stock_lookup(info.id) - if item: - info.item = item - else: - info.item = [None, None, 0, 0, None] - - icon_set = gtk.icon_factory_lookup_default(info.id) - if icon_set: - sizes = icon_set.get_sizes() - if gtk.ICON_SIZE_MENU in sizes: - size = gtk.ICON_SIZE_MENU - else: - size = sizes[0] - - info.small_icon = window.render_icon(info.id, - size) - if size != gtk.ICON_SIZE_MENU: - #w, h = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU) - raise NotImplementedError - - if info.item[2]: - info.accel_str = gtk.accelerator_name(info.item[3], - info.item[2]) - - info.macro = id_to_macro(info.id) - - iter = store.append() - store.set(iter, 0, info) - - return store - -def get_largest_size(id): - set = gtk.icon_factory_lookup_default(id) +def id_to_macro(stock_id): + if stock_id == '': + return '' + if stock_id.startswith('gtk'): + # gtk-foo-bar -> gtk.STOCK_FOO_BAR + macro = 'gtk.STOCK' + \ + re.sub('-([^-]+)', lambda m:('_' + m.group(1).upper()), stock_id[3:]) + + else: + # demo-gtk-logo -> DEMO_GTK_LOGO as with custom icon-factories + macro = re.sub('([^-]+)-?', lambda m:('_' + m.group(1).upper()), stock_id) + macro = macro[1:] # there is a leading '_' always + + return macro + + +class StockItemInfo(object): + def __init__(self, stock_id=''): + self.stock_id = stock_id + self.stock_item = None + self.small_icon = None + self.macro = id_to_macro(stock_id) + self.accel_str = '' + +class StockItemDisplay(object): + def __init__(self): + self.type_label = None + self.macro_label = None + self.id_label = None + self.label_accel_label = None + self.icon_image = None + + +def get_largest_size(stockid): + ''' Finds the largest size at which the given image stock id is + available. This would not be useful for a normal application. + ''' + set = gtk.icon_factory_lookup_default(stockid) best_size = gtk.ICON_SIZE_INVALID best_pixels = 0 - - for size in set.get_sizes(): - width, height = gtk.icon_size_lookup(size) - if width * height > best_pixels: - best_size = size - best_pixels = width * height - return best_size + sizes = set.get_sizes() + n_sizes = len(sizes) -def selection_changed(selection): - treeview = selection.get_tree_view() - display = treeview.get_data('stock-display') - value = selection.get_selected() - if value: - model, iter = value - info = model.get_value(iter, 0) - - if info.small_icon and info.item[1]: - display.type_label.set_text('Icon and Item') - elif info.small_icon: - display.type_label.set_text('Icon only') - elif info.item[1]: - display.type_label.set_text('Item only') - else: - display.type_label.set_text('???????') + i = 0 + while(i < n_sizes): + width, height = gtk.icon_size_lookup(sizes[i]) - display.macro_label.set_text(info.macro) - display.id_label.set_text(info.id) + if(width * height > best_pixels): + best_size = sizes[i] + best_pixels = width * height - if info.item[1]: - display.label_accel_label.set_text_with_mnemonic('%s %s' % \ - (info.item[1], - info.accel_str)) - else: - display.label_accel_label.set_text('') + i += 1 - if info.small_icon: - display.icon_image.set_from_stock(info.id, get_largest_size(info.id)) - else: - display.icon_image.set_from_pixbuf(None) - else: - display.type_label.set_text('No selected item') - display.macro_label.set_text('') - display.id_label.set_text('') - display.label_accel_label.set_text('') - display.icon_image.set_from_pixbuf(None) - -def macro_set_func_text(tree, cell, model, iter): - info = model.get_value(iter, 0) - cell.set_property('text', info.macro) + return best_size -def macro_set_func_pixbuf(tree, cell, model, iter): + +def macro_set_func_text(tree_column, cell, model, iter): info = model.get_value(iter, 0) - cell.set_property('pixbuf', info.small_icon) - -def id_set_func(tree, cell, model, iter): + cell.set_property("text", info.macro) + +def id_set_func(tree_column, cell, model, iter): info = model.get_value(iter, 0) - cell.set_property('text', info.id) + cell.set_property("text", info.stock_id) -def accel_set_func(tree, cell, model, iter): +def accel_set_func(tree_column, cell, model, iter): info = model.get_value(iter, 0) - cell.set_property('text', info.accel_str) + cell.set_property("text", info.accel_str) -def label_set_func(tree, cell, model, iter): +def label_set_func(tree_column, cell, model, iter): info = model.get_value(iter, 0) - cell.set_property('text', info.item[1]) - + cell.set_property("text", info.stock_item[1]) + + +class StockItemAndIconBrowserDemo(gtk.Window): + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_default_size(-1, 500) + self.set_border_width(8) + + hbox = gtk.HBox(False, 8) + self.add(hbox) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) + hbox.pack_start(sw, False, False, 0) + + model = self.__create_model() + treeview = gtk.TreeView(model) + sw.add(treeview) + + column = gtk.TreeViewColumn() + column.set_title("Macro") + + cell_renderer = gtk.CellRendererPixbuf() + column.pack_start(cell_renderer, False) + column.set_attributes(cell_renderer, stock_id=1) + + cell_renderer = gtk.CellRendererText() + column.pack_start(cell_renderer, True) + column.set_cell_data_func(cell_renderer, macro_set_func_text) + + treeview.append_column(column) + + cell_renderer = gtk.CellRendererText() + treeview.insert_column_with_data_func(-1, "Label", cell_renderer, label_set_func) + + cell_renderer = gtk.CellRendererText() + treeview.insert_column_with_data_func(-1, "Accel", cell_renderer, accel_set_func) + + cell_renderer = gtk.CellRendererText() + treeview.insert_column_with_data_func(-1, "ID", cell_renderer, id_set_func) + + align = gtk.Alignment(0.5, 0.0, 0.0, 0.0) + hbox.pack_end(align, False, False, 0) + + frame = gtk.Frame("Selected Item") + align.add(frame) + + vbox = gtk.VBox(False, 8) + vbox.set_border_width(4) + frame.add(vbox) + + display = StockItemDisplay() + treeview.set_data("stock-display", display) + + display.type_label = gtk.Label() + display.macro_label = gtk.Label() + display.id_label = gtk.Label() + display.label_accel_label = gtk.Label() + display.icon_image = gtk.Image(); # empty image + + vbox.pack_start(display.type_label, False, False, 0) + vbox.pack_start(display.icon_image, False, False, 0) + vbox.pack_start(display.label_accel_label, False, False, 0) + vbox.pack_start(display.macro_label, False, False, 0) + vbox.pack_start(display.id_label, False, False, 0) + + selection = treeview.get_selection() + selection.set_mode(gtk.SELECTION_SINGLE) + + selection.connect("changed", self.on_selection_changed) + + self.show_all() + + def __create_model(self): + store = gtk.ListStore( + gobject.TYPE_PYOBJECT, + gobject.TYPE_STRING) + + ids = gtk.stock_list_ids() + ids.sort() + + for data in ids: + info = StockItemInfo(stock_id=data) + stock_item = gtk.stock_lookup(data) + + if stock_item: + info.stock_item = stock_item + else: + # stock_id, label, modifier, keyval, translation_domain + info.stock_item =('', '', 0, 0, '') + + # only show icons for stock IDs that have default icons + icon_set = gtk.icon_factory_lookup_default(info.stock_id) + if icon_set is None: + info.small_icon = None + else: + # See what sizes this stock icon really exists at + sizes = icon_set.get_sizes() + n_sizes = len(sizes) + + # Use menu size if it exists, otherwise first size found + size = sizes[0]; + i = 0; + while(i < n_sizes): + if(sizes[i] == gtk.ICON_SIZE_MENU): + size = gtk.ICON_SIZE_MENU + break + i += 1 + + info.small_icon = self.render_icon(info.stock_id, size) + + if(size != gtk.ICON_SIZE_MENU): + # Make the result the proper size for our thumbnail + w, h = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU) + + scaled = info.small_icon.scale_simple(w, h, 'bilinear') + info.small_icon = scaled + + if info.stock_item[3] == 0: + info.accel_str = "" + else: + info.accel_str = \ + gtk.accelerator_name(info.stock_item[3], info.stock_item[2]) + + iter = store.append() + store.set(iter, 0, info, 1, info.stock_id) + + return store + + def on_selection_changed(self, selection): + treeview = selection.get_tree_view() + display = treeview.get_data("stock-display") + + model, iter = selection.get_selected() + if iter: + info = model.get_value(iter, 0) + + if(info.small_icon and info.stock_item[1]): + display.type_label.set_text("Icon and Item") + + elif(info.small_icon): + display.type_label.set_text("Icon Only") + + elif(info.stock_item[1]): + display.type_label.set_text("Item Only") + + else: + display.type_label.set_text("???????") + + display.macro_label.set_text(info.macro) + display.id_label.set_text(info.stock_id) + + if(info.stock_item[1]): + s = "%s %s" % (info.stock_item[1], info.accel_str) + display.label_accel_label.set_text_with_mnemonic(s) + + else: + display.label_accel_label.set_text("") + + if(info.small_icon): + display.icon_image.set_from_stock(info.stock_id, + get_largest_size(info.stock_id)) + else: + display.icon_image.set_from_pixbuf(None) + + else: + display.type_label.set_text("No selected item") + display.macro_label.set_text("") + display.id_label.set_text("") + display.label_accel_label.set_text("") + display.icon_image.set_from_pixbuf(None) + def main(): - global window - - window = gtk.Window(gtk.WINDOW_TOPLEVEL) - window.set_title('Stock Icons and Items') - window.set_default_size(-1, 500) - - window.connect('destroy', lambda *x: gtk.mainquit()) - window.set_border_width(8) - - hbox = gtk.HBox(False, 8) - window.add(hbox) - - sw = gtk.ScrolledWindow() - sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - hbox.pack_start(sw) - - model = create_model() - - treeview = gtk.TreeView(model) - sw.add(treeview) - - column = gtk.TreeViewColumn() - column.set_title('Macro') - - cell_renderer = gtk.CellRendererPixbuf() - column.pack_start(cell_renderer, False) - column.set_cell_data_func(cell_renderer, macro_set_func_pixbuf) - cell_renderer = gtk.CellRendererText() - column.pack_start(cell_renderer, True) - column.set_cell_data_func(cell_renderer, macro_set_func_text) - treeview.append_column(column) - - cell_renderer = gtk.CellRendererText() - treeview.insert_column_with_data_func(-1, "Label", cell_renderer, - label_set_func) - treeview.insert_column_with_data_func(-1, "Accel", cell_renderer, - accel_set_func) - treeview.insert_column_with_data_func(-1, "ID", cell_renderer, - id_set_func) - - align = gtk.Alignment(0.5, 0.0, 0.0, 0.0) - hbox.pack_start(align) - - frame = gtk.Frame("Selected Item") - align.add(frame) - - vbox = gtk.VBox(False, 8) - vbox.set_border_width(4) - frame.add(vbox) - - - display = StockItemDisplay() - treeview.set_data('stock-display', display) - display.type_label = gtk.Label() - display.macro_label = gtk.Label() - display.id_label = gtk.Label() - display.label_accel_label = gtk.Label() - display.icon_image = gtk.Image() - - vbox.pack_start(display.type_label) - vbox.pack_start(display.icon_image) - vbox.pack_start(display.label_accel_label) - vbox.pack_start(display.macro_label) - vbox.pack_start(display.id_label) - - selection = treeview.get_selection() - selection.set_mode(gtk.SELECTION_SINGLE) - selection.connect('changed', selection_changed) - - window.show_all() + StockItemAndIconBrowserDemo() + gtk.main() if __name__ == '__main__': main() - gtk.main() - diff --git a/examples/pygtk-demo/demos/textview.py b/examples/pygtk-demo/demos/textview.py new file mode 100644 index 00000000..833d2302 --- /dev/null +++ b/examples/pygtk-demo/demos/textview.py @@ -0,0 +1,499 @@ +#!/usr/bin/env python +"""Text Widget/TextView + +The GtkTextView widget displays a GtkTextBuffer. One GtkTextBuffer can be displayed +by multiple GtkTextViews. This demo has two views displaying a single buffer, and +shows off the widget's text formatting features.""" +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import sys +import os + +import gobject +import gtk +import pango + +gray50_width = 2 +gray50_height = 2 +gray50_bits = '\x02\x01' +GTKLOGO_IMAGE = os.path.join(os.path.dirname(__file__), + 'images', 'gtk-logo-rgb.gif') +FLOPPYBUDDY_IMAGE = os.path.join(os.path.dirname(__file__), + 'images', 'floppybuddy.gif') + +class TextViewDemo(gtk.Window): + def __init__(self, parent=None): + # Create the toplevel window + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + + self.set_title(self.__class__.__name__) + self.set_default_size(450, 450) + self.set_border_width(0) + + vpaned = gtk.VPaned() + vpaned.set_border_width(5) + self.add(vpaned) + + # For convenience, we just use the autocreated buffer from + # the first text view; you could also create the buffer + # by itself with gtk.text_buffer_new(), then later create + # a view widget. + + view1 = gtk.TextView(); + buffer_1 = view1.get_buffer() + view2 = gtk.TextView(buffer_1) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + vpaned.add1(sw) + + sw.add(view1) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + vpaned.add2(sw) + + sw.add(view2) + + self.create_tags(buffer_1) + self.insert_text(buffer_1) + + self.attach_widgets(view1) + self.attach_widgets(view2) + self.win = None + self.show_all() + + def create_tags(self, text_buffer): + ''' + Create a bunch of tags. Note that it's also possible to + create tags with gtk.text_tag_new() then add them to the + tag table for the buffer, text_buffer.create_tag() is + just a convenience function. Also note that you don't have + to give tags a name; pass None for the name to create an + anonymous tag. + + In any real app, another useful optimization would be to create + a GtkTextTagTable in advance, and reuse the same tag table for + all the buffers with the same tag set, instead of creating + new copies of the same tags for every buffer. + + Tags are assigned default priorities in order of addition to the + tag table. That is, tags created later that affect the same text + property affected by an earlier tag will override the earlier + tag. You can modify tag priorities with + gtk.text_tag_set_priority(). + ''' + + import pango + text_buffer.create_tag("heading", + weight=pango.WEIGHT_BOLD, + size=15 * pango.SCALE) + + text_buffer.create_tag("italic", style=pango.STYLE_ITALIC) + + text_buffer.create_tag("bold", weight=pango.WEIGHT_BOLD) + + # points times the pango.SCALE factor + text_buffer.create_tag("big", size=20 * pango.SCALE) + + text_buffer.create_tag("xx-small", scale=pango.SCALE_XX_SMALL) + + text_buffer.create_tag("x-large", scale=pango.SCALE_X_LARGE) + + text_buffer.create_tag("monospace", family="monospace") + + text_buffer.create_tag("blue_foreground", foreground="blue") + + text_buffer.create_tag("red_background", background="red") + + stipple = gtk.gdk.bitmap_create_from_data(None, + gray50_bits, gray50_width, gray50_height) + + text_buffer.create_tag("background_stipple", background_stipple=stipple) + + text_buffer.create_tag("foreground_stipple", foreground_stipple=stipple) + + text_buffer.create_tag("big_gap_before_line", pixels_above_lines=30) + + text_buffer.create_tag("big_gap_after_line", pixels_below_lines=30) + + text_buffer.create_tag("double_spaced_line", pixels_inside_wrap=10) + + text_buffer.create_tag("not_editable", editable=False) + + text_buffer.create_tag("word_wrap", wrap_mode=gtk.WRAP_WORD) + + text_buffer.create_tag("char_wrap", wrap_mode=gtk.WRAP_CHAR) + + text_buffer.create_tag("no_wrap", wrap_mode=gtk.WRAP_NONE) + + text_buffer.create_tag("center", justification=gtk.JUSTIFY_CENTER) + + text_buffer.create_tag("right_justify", justification=gtk.JUSTIFY_RIGHT) + + text_buffer.create_tag("wide_margins", + left_margin=50, right_margin=50) + + text_buffer.create_tag("strikethrough", strikethrough=True) + + text_buffer.create_tag("underline", + underline=pango.UNDERLINE_SINGLE) + + text_buffer.create_tag("double_underline", + underline=pango.UNDERLINE_DOUBLE) + + text_buffer.create_tag("superscript", + rise=10 * pango.SCALE, # 10 pixels + size=8 * pango.SCALE) # 8 points + + text_buffer.create_tag("subscript", + rise=-10 * pango.SCALE, # 10 pixels + size=8 * pango.SCALE) # 8 points + + text_buffer.create_tag("rtl_quote", + wrap_mode=gtk.WRAP_WORD, direction=gtk.TEXT_DIR_RTL, + indent=30, left_margin=20, right_margin=20) + + def insert_text(self, text_buffer): + # use the current directory for the file + try: + pixbuf = gtk.gdk.pixbuf_new_from_file(GTKLOGO_IMAGE) + except gobject.GError, error: + sys.exit("Failed to load image file gtk-logo-rgb.gif\n") + + scaled = pixbuf.scale_simple(32, 32, 'bilinear') + pixbuf = scaled + + # get start of buffer; each insertion will revalidate the + # iterator to point to just after the inserted text. + iter = text_buffer.get_iter_at_offset(0) + + text_buffer.insert(iter, "The text widget can display text with " + "all kinds of nifty attributes. It also supports multiple views " + "of the same buffer; this demo is showing the same buffer in " + "two places.\n\n") + + text_buffer.insert_with_tags_by_name(iter, "Font styles. ", "heading") + + text_buffer.insert(iter, "For example, you can have ") + text_buffer.insert_with_tags_by_name(iter, + "italic", "italic") + text_buffer.insert(iter, ", "); + text_buffer.insert_with_tags_by_name(iter, + "bold", "bold") + text_buffer.insert(iter, ", or ", -1) + text_buffer.insert_with_tags_by_name(iter, + "monospace(typewriter)", "monospace") + text_buffer.insert(iter, ", or ") + text_buffer.insert_with_tags_by_name(iter, + "big", "big") + text_buffer.insert(iter, " text. ") + text_buffer.insert(iter, "It's best not to hardcode specific text " + "sizes; you can use relative sizes as with CSS, such as ") + text_buffer.insert_with_tags_by_name(iter, + "xx-small", "xx-small") + text_buffer.insert(iter, " or ") + text_buffer.insert_with_tags_by_name(iter, + "x-large", "x-large") + text_buffer.insert(iter, " to ensure that your program properly " + "adapts if the user changes the default font size.\n\n") + + text_buffer.insert_with_tags_by_name(iter, "Colors. ", "heading") + + text_buffer.insert(iter, "Colors such as "); + text_buffer.insert_with_tags_by_name(iter, + "a blue foreground", "blue_foreground") + text_buffer.insert(iter, " or "); + text_buffer.insert_with_tags_by_name(iter, + "a red background", + "red_background") + text_buffer.insert(iter, " or even ", -1); + text_buffer.insert_with_tags_by_name(iter, + "a stippled red background", + "red_background", + "background_stipple") + + text_buffer.insert(iter, " or ", -1); + text_buffer.insert_with_tags_by_name(iter, + "a stippled blue foreground on solid red background", + "blue_foreground", + "red_background", + "foreground_stipple") + text_buffer.insert(iter, "(select that to read it) can be used.\n\n", -1); + + text_buffer.insert_with_tags_by_name(iter, + "Underline, strikethrough, and rise. ", "heading") + + text_buffer.insert_with_tags_by_name(iter, + "Strikethrough", + "strikethrough") + text_buffer.insert(iter, ", ", -1) + text_buffer.insert_with_tags_by_name(iter, + "underline", + "underline") + text_buffer.insert(iter, ", ", -1) + text_buffer.insert_with_tags_by_name(iter, + "double underline", + "double_underline") + text_buffer.insert(iter, ", ", -1) + text_buffer.insert_with_tags_by_name(iter, + "superscript", + "superscript") + text_buffer.insert(iter, ", and ", -1) + text_buffer.insert_with_tags_by_name(iter, + "subscript", + "subscript") + text_buffer.insert(iter, " are all supported.\n\n", -1) + + text_buffer.insert_with_tags_by_name(iter, "Images. ", + "heading") + + text_buffer.insert(iter, "The buffer can have images in it: ", -1) + text_buffer.insert_pixbuf(iter, pixbuf) + text_buffer.insert_pixbuf(iter, pixbuf) + text_buffer.insert_pixbuf(iter, pixbuf) + text_buffer.insert(iter, " for example.\n\n", -1) + + text_buffer.insert_with_tags_by_name(iter, "Spacing. ", + "heading") + + text_buffer.insert(iter, + "You can adjust the amount of space before each line.\n", -1) + + text_buffer.insert_with_tags_by_name(iter, + "This line has a whole lot of space before it.\n", + "big_gap_before_line", "wide_margins") + text_buffer.insert_with_tags_by_name(iter, + "You can also adjust the amount of space after each line; " + "this line has a whole lot of space after it.\n", + "big_gap_after_line", "wide_margins") + + text_buffer.insert_with_tags_by_name(iter, + "You can also adjust the amount of space between wrapped " + "lines; this line has extra space between each wrapped line " + "in the same paragraph. To show off wrapping, some filler " + "text: the quick brown fox jumped over the lazy dog. Blah " + "blah blah blah blah blah blah blah blah.\n", + "double_spaced_line", "wide_margins") + + text_buffer.insert(iter, "Also note that those lines have " + "extra-wide margins.\n\n", -1) + + text_buffer.insert_with_tags_by_name(iter, "Editability. ", "heading") + + text_buffer.insert_with_tags_by_name(iter, + "This line is 'locked down' and can't be edited by the " + "user - just try it! You can't delete this line.\n\n", + "not_editable") + + text_buffer.insert_with_tags_by_name(iter, "Wrapping. ", "heading") + + text_buffer.insert(iter, + "This line(and most of the others in this buffer) is " + "word-wrapped, using the proper Unicode algorithm. Word " + "wrap should work in all scripts and languages that GTK+ " + "supports. Let's make this a long paragraph to demonstrate: " + "blah blah blah blah blah blah blah blah blah blah blah " + "blah blah blah blah blah blah blah blah\n\n", -1); + + text_buffer.insert_with_tags_by_name(iter, + "This line has character-based wrapping, and can wrap " + "between any two character glyphs. Let's make this a long " + "paragraph to demonstrate: blah blah blah blah blah blah " + "blah blah blah blah blah blah blah blah blah blah blah " + "blah blah\n\n", "char_wrap") + + text_buffer.insert_with_tags_by_name(iter, + "This line has all wrapping turned off, so it makes the " + "horizontal scrollbar appear.\n\n\n", "no_wrap") + + text_buffer.insert_with_tags_by_name(iter, "Justification. ", + "heading"); + + text_buffer.insert_with_tags_by_name(iter, + "\nThis line has center justification.\n", "center") + + text_buffer.insert_with_tags_by_name(iter, + "This line has right justification.\n", "right_justify") + + text_buffer.insert_with_tags_by_name(iter, + "\nThis line has big wide margins. Text text text text " + "text text text text text text text text text text text " + "text text text text text text text text text text text " + "text text text text text text text text text text.\n", + "wide_margins"); + + text_buffer.insert_with_tags_by_name(iter, + "Internationalization. ", "heading") + + text_buffer.insert(iter, + "You can put all sorts of Unicode text in the buffer.\n\n" + "German(Deutsch S\303\274d) Gr\303\274\303\237 Gott\nGreek" + "(\316\225\316\273\316\273\316\267\316\275\316\271\316\272" + "\316\254) \316\223\316\265\316\271\316\254 \317\203\316\261" + "\317\202\nHebrew \327\251\327\234\327\225\327\235\n" + "Japanese(\346\227\245\346\234\254\350\252\236)\n\nThe " + "widget properly handles bidirectional text, word wrapping, " + "DOS/UNIX/Unicode paragraph separators, grapheme boundaries, " + "and so on using the Pango internationalization framework.\n", -1) + + text_buffer.insert(iter, "Here's a word-wrapped quote in a " + "right-to-left language:\n", -1) + text_buffer.insert_with_tags_by_name(iter, + "\331\210\331\202\330\257 \330\250\330\257\330\243 " + "\330\253\331\204\330\247\330\253 \331\205\331\206 " + "\330\243\331\203\330\253\330\261 \330\247\331\204\331" + "\205\330\244\330\263\330\263\330\247\330\252 \330\252" + "\331\202\330\257\331\205\330\247 \331\201\331\212 \330" + "\264\330\250\331\203\330\251 \330\247\331\203\330\263" + "\331\212\331\210\331\206 \330\250\330\261\330\247\331" + "\205\330\254\331\207\330\247 \331\203\331\205\331\206" + "\330\270\331\205\330\247\330\252 \331\204\330\247 \330" + "\252\330\263\330\271\331\211 \331\204\331\204\330\261" + "\330\250\330\255\330\214 \330\253\331\205 \330\252\330" + "\255\331\210\331\204\330\252 \331\201\331\212 \330\247" + "\331\204\330\263\331\206\331\210\330\247\330\252 \330" + "\247\331\204\330\256\331\205\330\263 \330\247\331\204" + "\331\205\330\247\330\266\331\212\330\251 \330\245\331" + "\204\331\211 \331\205\330\244\330\263\330\263\330\247" + "\330\252 \331\205\330\247\331\204\331\212\330\251 \331" + "\205\331\206\330\270\331\205\330\251\330\214 \331\210" + "\330\250\330\247\330\252\330\252 \330\254\330\262\330\241" + "\330\247 \331\205\331\206 \330\247\331\204\331\206\330\270" + "\330\247\331\205 \330\247\331\204\331\205\330\247\331\204" + "\331\212 \331\201\331\212 \330\250\331\204\330\257\330\247" + "\331\206\331\207\330\247\330\214 \331\210\331\204\331\203" + "\331\206\331\207\330\247 \330\252\330\252\330\256\330\265" + "\330\265 \331\201\331\212 \330\256\330\257\331\205\330\251 " + "\331\202\330\267\330\247\330\271 \330\247\331\204\331\205\330" + "\264\330\261\331\210\330\271\330\247\330\252 \330\247\331\204" + "\330\265\330\272\331\212\330\261\330\251. \331\210\330\243" + "\330\255\330\257 \330\243\331\203\330\253\330\261 \331\207" + "\330\260\331\207 \330\247\331\204\331\205\330\244\330\263" + "\330\263\330\247\330\252 \331\206\330\254\330\247\330\255" + "\330\247 \331\207\331\210 \302\273\330\250\330\247\331\206" + "\331\203\331\210\330\263\331\210\331\204\302\253 \331\201" + "\331\212 \330\250\331\210\331\204\331\212\331\201\331\212" + "\330\247.\n\n", "rtl_quote") + + text_buffer.insert(iter, "You can put widgets in the buffer: " + "Here's a button: ", -1) + + anchor = text_buffer.create_child_anchor(iter) + text_buffer.insert(iter, " and a menu: ", -1) + anchor = text_buffer.create_child_anchor(iter) + text_buffer.insert(iter, " and a scale: ", -1) + anchor = text_buffer.create_child_anchor(iter) + text_buffer.insert(iter, " and an animation: ", -1) + anchor = text_buffer.create_child_anchor(iter) + text_buffer.insert(iter, " finally a text entry: ", -1) + anchor = text_buffer.create_child_anchor(iter) + text_buffer.insert(iter, ".\n", -1) + + text_buffer.insert(iter, "\n\nThis demo doesn't demonstrate all " + "the GtkTextBuffer features; it leaves out, for example: " + "invisible/hidden text(doesn't work in GTK 2, but planned), " + "tab stops, application-drawn areas on the sides of the " + "widget for displaying breakpoints and such...", -1) + + # Apply word_wrap tag to whole buffer */ + start, end = text_buffer.get_bounds() + text_buffer.apply_tag_by_name("word_wrap", start, end) + + def attach_widgets(self, text_view): + buffer = text_view.get_buffer() + iter = buffer.get_start_iter() + i = 0 + while self.find_anchor(iter): + anchor = iter.get_child_anchor() + if i == 0: + widget = gtk.Button("Click Me") + widget.connect("clicked", self.easter_egg_callback) + elif i == 1: + widget = gtk.combo_box_new_text() + widget.append_text("Option 1") + widget.append_text("Option 2") + widget.append_text("Option 3") + elif i == 2: + widget = gtk.HScale() + widget.set_range(0, 100) + widget.set_size_request(70, -1) + elif i == 3: + widget = gtk.Image() + widget.set_from_file(FLOPPYBUDDY_IMAGE) + elif i == 4: + widget = gtk.Entry() + else: + raise ValueError + + text_view.add_child_at_anchor(widget, anchor) + widget.show_all() + i += 1 + return + + def find_anchor(self, iter): + while iter.forward_char(): + if iter.get_child_anchor(): + return True + return False + + def easter_egg_callback(self, button): + if self.win: + self.win.present() + return + + buffer = gtk.TextBuffer() + iter = buffer.get_start_iter() + buffer.insert(iter, + "This buffer is shared by a set of nested text views.\n Nested view:\n") + anchor = buffer.create_child_anchor(iter) + buffer.insert(iter, + "\nDon't do this in real applications, please.\n") + + view = gtk.TextView(buffer) + + self.recursive_attach_view(0, view, anchor) + + self.win = gtk.Window() + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + + self.win.add(sw) + sw.add(view) + self.win.set_default_size(300, 400) + self.win.show_all() + return + + def recursive_attach_view(self, depth, view, anchor): + if depth > 4: + return + child_view = gtk.TextView(view.get_buffer()) + # Event box is needed to add a black border around each child view + event_box = gtk.EventBox() + color = gtk.gdk.color_parse("black") + event_box.modify_bg(gtk.STATE_NORMAL, color) + align = gtk.Alignment(0.5, 0.5, 1.0, 1.0) + align.set_border_width(1) + + event_box.add(align) + align.add(child_view) + + view.add_child_at_anchor(event_box, anchor) + + self.recursive_attach_view(depth + 1, child_view, anchor) + return + +def main(): + TextViewDemo() + gtk.main() + +if __name__ == '__main__': + main() diff --git a/examples/pygtk-demo/demos/toolbar.py b/examples/pygtk-demo/demos/toolbar.py deleted file mode 100644 index 9a889a8c..00000000 --- a/examples/pygtk-demo/demos/toolbar.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -'''Toolbar Demo - -This demonstration demonstrates the use of toolbars in GTK+''' - -description = 'Toolbars' - -import gtk - -folder_icon = [ - "20 19 5 1", - " c None", - ". c #000000", - "X c #FFFFFF", - "o c #FFFF00", - "O c #7F7F00", - " ", - " ", - " ", - " ... ", - " . . . ", - " .. ", - " ... ... ", - " .oXo....... ", - " .XoXoXoXoX. ", - " .oXoXoXoXo. ", - " .XoXo........... ", - " .oXo.OOOOOOOOO. ", - " .Xo.OOOOOOOOO. ", - " .o.OOOOOOOOO. ", - " ..OOOOOOOOO. ", - " ........... ", - " ", - " ", - " " -] - -def set_orient_cb(button, toolbar, orient): - toolbar.set_orientation(orient) -def set_style_cb(button, toolbar, style): - toolbar.set_style(style) -def set_tooltips_cb(button, toolbar, enable): - toolbar.set_tooltips(enable) - -def Image(pix, mask): - image = gtk.Image() - image.set_from_pixmap(pix, mask) - return image - -def main(): - win = gtk.Window() - win.connect('destroy', lambda win: gtk.main_quit()) - - win.set_title("Toolbar") - win.set_resizable(gtk.FALSE) - win.set_border_width(5) - - pix, mask = gtk.gdk.pixmap_colormap_create_from_xpm_d(None, - win.get_colormap(), - None, folder_icon) - toolbar = gtk.Toolbar() - win.add(toolbar) - - button = toolbar.append_item("Horizontal", "Horizontal toolbar layout", - None, Image(pix, mask), None, None) - button.connect("clicked", set_orient_cb, toolbar, - gtk.ORIENTATION_HORIZONTAL) - - button = toolbar.append_item("Vertical", "Vertical toolbar layout", - None, Image(pix, mask), None, None) - button.connect("clicked", set_orient_cb, toolbar, - gtk.ORIENTATION_VERTICAL) - - toolbar.append_space() - - button = toolbar.append_item("Icons", "Only show toolbar icons", - None, Image(pix, mask), None, None) - button.connect("clicked", set_style_cb, toolbar, gtk.TOOLBAR_ICONS) - - button = toolbar.append_item("Text", "Only show toolbar texts", - None, Image(pix, mask), None, None) - button.connect("clicked", set_style_cb, toolbar, gtk.TOOLBAR_TEXT) - - button = toolbar.append_item("Both", "Show toolbar icons and text", - None, Image(pix, mask), None, None) - button.connect("clicked", set_style_cb, toolbar, gtk.TOOLBAR_BOTH) - - toolbar.append_space() - - entry = gtk.Entry() - toolbar.append_widget(entry, None, None) - - toolbar.append_space() - - button = toolbar.append_item("Enable", "Enable tooltips", - None, Image(pix, mask), None, None) - button.connect("clicked", set_tooltips_cb, toolbar, gtk.TRUE) - - button = toolbar.append_item("Disable", "Disable tooltips", - None, Image(pix, mask), None, None) - button.connect("clicked", set_tooltips_cb, toolbar, gtk.FALSE) - - win.show_all() - - gtk.main() - -if __name__ == '__main__': - main() diff --git a/examples/pygtk-demo/demos/tree_store.py b/examples/pygtk-demo/demos/tree_store.py new file mode 100644 index 00000000..c7d0b709 --- /dev/null +++ b/examples/pygtk-demo/demos/tree_store.py @@ -0,0 +1,335 @@ +#!/usr/bin/env python +'''Tree View/Tree Store + +The GtkTreeStore is used to store data in tree form, to be used +later on by a GtkTreeView to display it. This demo builds a simple +GtkTreeStore and displays it. If you're new to the GtkTreeView widgets +and associates, look into the GtkListStore example first.''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import gobject +import gtk + +# columns +( + HOLIDAY_NAME_COLUMN, + ALEX_COLUMN, + HAVOC_COLUMN, + TIM_COLUMN, + OWEN_COLUMN, + DAVE_COLUMN, + VISIBLE_COLUMN, + WORLD_COLUMN, + NUM_COLUMNS +) = range(9) + +# tree data +january = \ +[ + ["New Years Day", True, True, True, True, False, True ], + ["Presidential Inauguration", False, True, False, True, False, False ], + ["Martin Luther King Jr. day", False, True, False, True, False, False ] +] + +february = \ +[ + [ "Presidents' Day", False, True, False, True, False, False ], + [ "Groundhog Day", False, False, False, False, False, False ], + [ "Valentine's Day", False, False, False, False, True, True ] +] + +march = \ +[ + [ "National Tree Planting Day", False, False, False, False, False, False ], + [ "St Patrick's Day", False, False, False, False, False, True ] +] +april = \ +[ + [ "April Fools' Day", False, False, False, False, False, True ], + [ "Army Day", False, False, False, False, False, False ], + [ "Earth Day", False, False, False, False, False, True ], + [ "Administrative Professionals' Day", False, False, False, False, False, False ] +] + +may = \ +[ + [ "Nurses' Day", False, False, False, False, False, False ], + [ "National Day of Prayer", False, False, False, False, False, False ], + [ "Mothers' Day", False, False, False, False, False, True ], + [ "Armed Forces Day", False, False, False, False, False, False ], + [ "Memorial Day", True, True, True, True, False, True ] +] + +june = \ +[ + [ "June Fathers' Day", False, False, False, False, False, True ], + [ "Juneteenth(Liberation of Slaves)", False, False, False, False, False, False ], + [ "Flag Day", False, True, False, True, False, False ] +] + +july = \ +[ + [ "Parents' Day", False, False, False, False, False, True ], + [ "Independence Day", False, True, False, True, False, False ] +] + +august = \ +[ + [ "Air Force Day", False, False, False, False, False, False ], + [ "Coast Guard Day", False, False, False, False, False, False ], + [ "Friendship Day", False, False, False, False, False, False ] +] + +september = \ +[ + [ "Grandparents' Day", False, False, False, False, False, True ], + [ "Citizenship Day or Constitution Day", False, False, False, False, False, False ], + [ "Labor Day", True, True, True, True, False, True ] +] + +october = \ +[ + [ "National Children's Day", False, False, False, False, False, False ], + [ "Bosses' Day", False, False, False, False, False, False ], + [ "Sweetest Day", False, False, False, False, False, False ], + [ "Mother-in-Law's Day", False, False, False, False, False, False ], + [ "Navy Day", False, False, False, False, False, False ], + [ "Columbus Day", False, True, False, True, False, False ], + [ "Halloween", False, False, False, False, False, True ] +] + +november = \ +[ + [ "Marine Corps Day", False, False, False, False, False, False ], + [ "Veterans' Day", True, True, True, True, False, True ], + [ "Thanksgiving", False, True, False, True, False, False ] +] + +december = \ +[ + [ "Pearl Harbor Remembrance Day", False, False, False, False, False, False ], + [ "Christmas", True, True, True, True, False, True ], + [ "Kwanzaa", False, False, False, False, False, False ] +] + + +toplevel = \ +[ + ["January", False, False, False, False, False, False, january], + ["February", False, False, False, False, False, False, february], + ["March", False, False, False, False, False, False, march], + ["April", False, False, False, False, False, False, april], + ["May", False, False, False, False, False, False, may], + ["June", False, False, False, False, False, False, june], + ["July", False, False, False, False, False, False, july], + ["August", False, False, False, False, False, False, august], + ["September", False, False, False, False, False, False, september], + ["October", False, False, False, False, False, False, october], + ["November", False, False, False, False, False, False, november], + ["December", False, False, False, False, False, False, december] +] + +class TreeStoreDemo(gtk.Window): + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) + self.set_default_size(650, 400) + self.set_border_width(8) + + vbox = gtk.VBox(False, 8) + self.add(vbox) + + label = gtk.Label("Jonathan's Holiday Card Planning Sheet") + vbox.pack_start(label, False, False) + + sw = gtk.ScrolledWindow() + sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + vbox.pack_start(sw) + + # create model + model = self.__create_model() + + # create treeview + treeview = gtk.TreeView(model) + treeview.set_rules_hint(True) + + self.__add_columns(treeview) + + sw.add(treeview) + + # expand all rows after the treeview widget has been realized + treeview.connect('realize', lambda tv: tv.expand_all()) + + self.show_all() + + def __create_model(self): + + # create tree store + model = gtk.TreeStore( + gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN, + gobject.TYPE_BOOLEAN) + + # add data to the tree store + for month in toplevel: + iter = model.append(None) + model.set(iter, + HOLIDAY_NAME_COLUMN, month[HOLIDAY_NAME_COLUMN], + ALEX_COLUMN, False, + HAVOC_COLUMN, False, + TIM_COLUMN, False, + OWEN_COLUMN, False, + DAVE_COLUMN, False, + VISIBLE_COLUMN, False, + WORLD_COLUMN, False + ) + + # add children + for holiday in month[-1]: + child_iter = model.append(iter); + model.set(child_iter, + HOLIDAY_NAME_COLUMN, holiday[HOLIDAY_NAME_COLUMN], + ALEX_COLUMN, holiday[ALEX_COLUMN], + HAVOC_COLUMN, holiday[HAVOC_COLUMN], + TIM_COLUMN, holiday[TIM_COLUMN], + OWEN_COLUMN, holiday[OWEN_COLUMN], + DAVE_COLUMN, holiday[DAVE_COLUMN], + VISIBLE_COLUMN, True, + WORLD_COLUMN, holiday[WORLD_COLUMN-1] + ) + + return model + + def on_item_toggled(self, cell, path_str, model): + + # get selected column + column = cell.get_data('column') + + # get toggled iter + iter = model.get_iter_from_string(path_str) + toggle_item = model.get_value(iter, column) + + # do something with the value + toggle_item = not toggle_item + + # set new value + model.set(iter, column, toggle_item) + + + def __add_columns(self, treeview): + model = treeview.get_model() + + # column for holiday names + renderer = gtk.CellRendererText() + renderer.set_property("xalign", 0.0) + + #col_offset = gtk.TreeViewColumn("Holiday", renderer, text=HOLIDAY_NAME_COLUMN) + column = gtk.TreeViewColumn("Holiday", renderer, text=HOLIDAY_NAME_COLUMN) + #column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), col_offset - 1); + column.set_clickable(True) + + treeview.append_column(column) + + # alex column */ + renderer = gtk.CellRendererToggle() + renderer.set_property("xalign", 0.0) + renderer.set_data("column", ALEX_COLUMN) + + renderer.connect("toggled", self.on_item_toggled, model) + + column = gtk.TreeViewColumn("Alex", renderer, active=ALEX_COLUMN, + visible=VISIBLE_COLUMN, activatable=WORLD_COLUMN) + + # set this column to a fixed sizing(of 50 pixels) + #column = gtk_tree_view_get_column(GTK_TREE_VIEW(treeview), col_offset - 1); + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + column.set_clickable(True) + + treeview.append_column(column) + + # havoc column + renderer = gtk.CellRendererToggle(); + renderer.set_property("xalign", 0.0) + renderer.set_data("column", HAVOC_COLUMN) + + renderer.connect("toggled", self.on_item_toggled, model) + + column = gtk.TreeViewColumn("Havoc", renderer, active=HAVOC_COLUMN, + visible=VISIBLE_COLUMN) + + #column = treeview.get_column(col_offset - 1) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + column.set_clickable(True) + + treeview.append_column(column) + + # tim column + renderer = gtk.CellRendererToggle(); + renderer.set_property("xalign", 0.0) + renderer.set_data("column", TIM_COLUMN) + + renderer.connect("toggled", self.on_item_toggled, model) + + column = gtk.TreeViewColumn("Tim", renderer, active=TIM_COLUMN, + visible=VISIBLE_COLUMN, activatable=WORLD_COLUMN) + + #column = treeview.get_column(col_offset - 1) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + column.set_clickable(True) + + treeview.append_column(column) + + # owen column + renderer = gtk.CellRendererToggle(); + renderer.set_property("xalign", 0.0) + renderer.set_data("column", OWEN_COLUMN) + + renderer.connect("toggled", self.on_item_toggled, model) + + column = gtk.TreeViewColumn("Owen", renderer, active=OWEN_COLUMN, + visible=VISIBLE_COLUMN) + + #column = treeview.get_column(col_offset - 1) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + column.set_clickable(True) + + treeview.append_column(column) + + # dave column + renderer = gtk.CellRendererToggle(); + renderer.set_property("xalign", 0.0) + renderer.set_data("column", DAVE_COLUMN) + + renderer.connect("toggled", self.on_item_toggled, model) + + column = gtk.TreeViewColumn("Dave", renderer, active=DAVE_COLUMN, + visible=VISIBLE_COLUMN) + + #column = treeview.get_column(col_offset - 1) + column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + column.set_fixed_width(50) + column.set_clickable(True) + + treeview.append_column(column) + +def main(): + TreeStoreDemo() + gtk.main() + +if __name__ == '__main__': + main() + diff --git a/examples/pygtk-demo/demos/treemodel.py b/examples/pygtk-demo/demos/treemodel.py index 13d2c817..b8195db6 100644 --- a/examples/pygtk-demo/demos/treemodel.py +++ b/examples/pygtk-demo/demos/treemodel.py @@ -1,9 +1,8 @@ #!/usr/bin/env python -'''Tree Model Test +'''Tree View/Generic Tree Model This test is designed to demonstrate creating a new type of tree model in python for use with the new tree widget in gtk 2.0.''' -description = 'Tree Model' import gtk import gobject @@ -25,87 +24,93 @@ class MyTreeModel(gtk.GenericTreeModel): TREE_DEPTH = 4 TREE_SIBLINGS = 5 def __init__(self): - '''constructor for the model. Make sure you call - PyTreeModel.__init__''' - gtk.GenericTreeModel.__init__(self) + '''constructor for the model. Make sure you call + PyTreeModel.__init__''' + gtk.GenericTreeModel.__init__(self) # the implementations for TreeModel methods are prefixed with on_ def on_get_flags(self): - '''returns the GtkTreeModelFlags for this particular type of model''' - return 0 + '''returns the GtkTreeModelFlags for this particular type of model''' + return 0 def on_get_n_columns(self): - '''returns the number of columns in the model''' - return 1 + '''returns the number of columns in the model''' + return 1 def on_get_column_type(self, index): - '''returns the type of a column in the model''' - return gobject.TYPE_STRING + '''returns the type of a column in the model''' + return gobject.TYPE_STRING def on_get_path(self, node): - '''returns the tree path (a tuple of indices at the various - levels) for a particular node.''' - return node + '''returns the tree path(a tuple of indices at the various + levels) for a particular node.''' + return node def on_get_iter(self, path): '''returns the node corresponding to the given path. In our case, the node is the path''' return path def on_get_value(self, node, column): - '''returns the value stored in a particular column for the node''' - assert column == 0 - return `node` + '''returns the value stored in a particular column for the node''' + assert column == 0 + return `node` def on_iter_next(self, node): - '''returns the next node at this level of the tree''' - if node[-1] == self.TREE_SIBLINGS - 1: # last node at level - return None - return node[:-1] + (node[-1]+1,) + '''returns the next node at this level of the tree''' + if node[-1] == self.TREE_SIBLINGS - 1: # last node at level + return None + return node[:-1] +(node[-1]+1,) def on_iter_children(self, node): - '''returns the first child of this node''' - if node == None: # top of tree - return (0,) - if len(node) >= self.TREE_DEPTH: # no more levels - return None - return node + (0,) + '''returns the first child of this node''' + if node == None: # top of tree + return(0,) + if len(node) >= self.TREE_DEPTH: # no more levels + return None + return node +(0,) def on_iter_has_child(self, node): - '''returns true if this node has children''' - return len(node) < self.TREE_DEPTH + '''returns true if this node has children''' + return len(node) < self.TREE_DEPTH def on_iter_n_children(self, node): - '''returns the number of children of this node''' - if len(node) < self.TREE_DEPTH: - return self.TREE_SIBLINGS - else: - return 0 + '''returns the number of children of this node''' + if len(node) < self.TREE_DEPTH: + return self.TREE_SIBLINGS + else: + return 0 def on_iter_nth_child(self, node, n): - '''returns the nth child of this node''' + '''returns the nth child of this node''' if node == None: - return (n,) - if len(node) < self.TREE_DEPTH and n < self.TREE_SIBLINGS: - return node + (n,) - else: - return None + return(n,) + if len(node) < self.TREE_DEPTH and n < self.TREE_SIBLINGS: + return node +(n,) + else: + return None def on_iter_parent(self, node): - '''returns the parent of this node''' - if len(node) == 0: - return None - else: - return node[:-1] + '''returns the parent of this node''' + if len(node) == 0: + return None + else: + return node[:-1] -def main(): - window = gtk.Window() - window.connect('destroy', lambda win: gtk.main_quit()) - window.set_title('Menus') +class GenericTreeModelDemo(gtk.Window): + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) - scrolled_window = gtk.ScrolledWindow() - scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - window.add(scrolled_window) + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + self.add(scrolled_window) - model = MyTreeModel() - tree_view = gtk.TreeView(model) - cell = gtk.CellRendererText() - # the text in the column comes from column 0 - column = gtk.TreeViewColumn("tuples", cell, text=0) - tree_view.append_column(column) + model = MyTreeModel() + tree_view = gtk.TreeView(model) + cell = gtk.CellRendererText() + # the text in the column comes from column 0 + column = gtk.TreeViewColumn("tuples", cell, text=0) + tree_view.append_column(column) - scrolled_window.add(tree_view) - window.show_all() + scrolled_window.add(tree_view) + self.show_all() +def main(): + GenericTreeModelDemo() gtk.main() if __name__ == '__main__': diff --git a/examples/pygtk-demo/demos/ui_manager.py b/examples/pygtk-demo/demos/ui_manager.py new file mode 100644 index 00000000..c473f08c --- /dev/null +++ b/examples/pygtk-demo/demos/ui_manager.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +'''UI Manager + +The GtkUIManager object allows the easy creation of menus +from an array of actions and a description of the menu hierarchy. +''' +# pygtk version: Maik Hertha <maik.hertha@berlin.de> + +import gtk + +def activate_action(action): + print 'Action "%s" activated' % action.get_name() + +def activate_radio_action(action, current): + print 'Radio action "%s" selected'% current.get_name() + +entries = ( + ( "FileMenu", None, "_File" ), # name, stock id, label + ( "PreferencesMenu", None, "_Preferences" ), # name, stock id, label + ( "ColorMenu", None, "_Color" ), # name, stock id, label + ( "ShapeMenu", None, "_Shape" ), # name, stock id, label + ( "HelpMenu", None, "_Help" ), # name, stock id, label + ( "New", gtk.STOCK_NEW, # name, stock id + "_New", "<control>N", # label, accelerator + "Create a new file", # tooltip + activate_action ), + ( "Open", gtk.STOCK_OPEN, # name, stock id + "_Open","<control>O", # label, accelerator + "Open a file", # tooltip + activate_action ), + ( "Save", gtk.STOCK_SAVE, # name, stock id + "_Save","<control>S", # label, accelerator + "Save current file", # tooltip + activate_action ), + ( "SaveAs", gtk.STOCK_SAVE, # name, stock id + "Save _As...", None, # label, accelerator + "Save to a file", # tooltip + activate_action ), + ( "Quit", gtk.STOCK_QUIT, # name, stock id + "_Quit", "<control>Q", # label, accelerator + "Quit", # tooltip + activate_action ), + ( "About", None, # name, stock id + "_About", "<control>A", # label, accelerator + "About", # tooltip + activate_action ), + ( "Logo", "demo-gtk-logo", # name, stock id + None, None, # label, accelerator + "GTK+", # tooltip + activate_action ), +) + +toggle_entries = ( + ( "Bold", gtk.STOCK_BOLD, # name, stock id + "_Bold", "<control>B", # label, accelerator + "Bold", # tooltip + activate_action, + True ), # is_active +) + +( + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE +) = range(3) + +color_entries = ( + ( "Red", None, # name, stock id + "_Red", "<control>R", # label, accelerator + "Blood", COLOR_RED ), # tooltip, value + ( "Green", None, # name, stock id + "_Green", "<control>G", # label, accelerator + "Grass", COLOR_GREEN ), # tooltip, value + ( "Blue", None, # name, stock id + "_Blue", "<control>B", # label, accelerator + "Sky", COLOR_BLUE ), # tooltip, value +) + +( + SHAPE_SQUARE, + SHAPE_RECTANGLE, + SHAPE_OVAL, +) = range(3) + +# GtkRadioActionEntry +shape_entries = ( + ( "Square", None, # name, stock id + "_Square", "<control>S", # label, accelerator + "Square", SHAPE_SQUARE ), # tooltip, value + ( "Rectangle", None, # name, stock id + "_Rectangle", "<control>R", # label, accelerator + "Rectangle", SHAPE_RECTANGLE ), # tooltip, value + ( "Oval", None, # name, stock id + "_Oval", "<control>O", # label, accelerator + "Egg", SHAPE_OVAL ), # tooltip, value +) + +ui_info = \ +'''<ui> + <menubar name='MenuBar'> + <menu action='FileMenu'> + <menuitem action='New'/> + <menuitem action='Open'/> + <menuitem action='Save'/> + <menuitem action='SaveAs'/> + <separator/> + <menuitem action='Quit'/> + </menu> + <menu action='PreferencesMenu'> + <menu action='ColorMenu'> + <menuitem action='Red'/> + <menuitem action='Green'/> + <menuitem action='Blue'/> + </menu> + <menu action='ShapeMenu'> + <menuitem action='Square'/> + <menuitem action='Rectangle'/> + <menuitem action='Oval'/> + </menu> + <menuitem action='Bold'/> + </menu> + <menu action='HelpMenu'> + <menuitem action='About'/> + </menu> + </menubar> + <toolbar name='ToolBar'> + <toolitem action='Open'/> + <toolitem action='Quit'/> + <separator action='Sep1'/> + <toolitem action='Logo'/> + </toolbar> +</ui>''' + +class UIManagerDemo(gtk.Window): + + def __init__(self, parent=None): + gtk.Window.__init__(self) + try: + self.set_screen(parent.get_screen()) + except AttributeError: + self.connect('destroy', lambda *w: gtk.main_quit()) + self.set_title(self.__class__.__name__) + self.set_border_width(0) + + actions = gtk.ActionGroup("Actions") + actions.add_actions(entries) + actions.add_toggle_actions(toggle_entries) + actions.add_radio_actions(color_entries, COLOR_RED, activate_radio_action) + actions.add_radio_actions(shape_entries, SHAPE_OVAL, activate_radio_action) + + ui = gtk.UIManager() + ui.insert_action_group(actions, 0) + self.add_accel_group(ui.get_accel_group()) + + try: + mergeid = ui.add_ui_from_string(ui_info) + except gobject.GError, msg: + print "building menus failed: %s" % msg + + box1 = gtk.VBox(False, 0) + self.add(box1) + + box1.pack_start(ui.get_widget("/MenuBar"), False, False, 0) + + label = gtk.Label("Type\n<alt>\nto start") + label.set_size_request(200, 200) + label.set_alignment(0.5, 0.5) + box1.pack_start(label, True, True, 0) + + separator = gtk.HSeparator() + box1.pack_start(separator, False, True, 0) + + box2 = gtk.VBox(False, 10) + box2.set_border_width(10) + box1.pack_start(box2, False, True, 0) + + button = gtk.Button("close") + button.connect("clicked", lambda b, w=self: w.destroy()) + box2.pack_start(button, True, True, 0) + button.set_flags(gtk.CAN_DEFAULT) + button.grab_default() + + self.show_all() + +def main(): + UIManagerDemo() + gtk.main() + +if __name__ == '__main__': + main() 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() |