[Python-checkins] r64574 - sandbox/trunk/ttk-gsoc/samples/theming.py

guilherme.polo python-checkins at python.org
Sat Jun 28 18:18:04 CEST 2008


Author: guilherme.polo
Date: Sat Jun 28 18:18:03 2008
New Revision: 64574

Log:
Dropped py3k support;
Added support for element creation;
Added support for custom layout creation;
Some refactoring;


Modified:
   sandbox/trunk/ttk-gsoc/samples/theming.py

Modified: sandbox/trunk/ttk-gsoc/samples/theming.py
==============================================================================
--- sandbox/trunk/ttk-gsoc/samples/theming.py	(original)
+++ sandbox/trunk/ttk-gsoc/samples/theming.py	Sat Jun 28 18:18:03 2008
@@ -1,26 +1,23 @@
-"""Sample application for playing with Ttk theming.
-A lot of features are missing for now.
+"""
+Sample application for playing with Ttk theming.
+* A lot of features are missing for now.
+
+-- Guilherme Polo, 2008.
 """
 
 # ToDO: Add a way to remove options.
-#       Add a way to edit image name and path/data.
+#       Add a way to edit images/elements.
+#       Handling element options.
 #       ...
 
 import sys
 import ttk
 import pprint
-try:
-    import cStringIO
-    import Tkinter
-    from tkSimpleDialog import Dialog
-    from tkMessageBox import showwarning
-    from tkFileDialog import askopenfilename
-except ImportError: # assuming py3k
-    import tkinter as Tkinter
-    from tkinter.simpledialog import Dialog
-    from tkinter.messagebox import showwarning
-    from tkinter.filedialog import askopenfilename
-    import io as cStringIO
+import cStringIO
+import Tkinter
+from tkSimpleDialog import Dialog, askstring
+from tkMessageBox import showwarning
+from tkFileDialog import askopenfilename
 
 def available_widgets():
     """Returns a list of Ttk widgets."""
@@ -265,7 +262,7 @@
                 self.result = Tkinter.PhotoImage(name=img_name, data=img_data)
             else:
                 self.result = Tkinter.PhotoImage(name=img_name, file=img_path)
-        except Tkinter.TclError as err:
+        except Tkinter.TclError, err:
             showwarning("Error creating image", err, parent=self)
             return False
 
@@ -280,6 +277,66 @@
             self.img_path.insert(0, path)
 
 
+class NewElement(NewOption): # reusing buttonbox
+    """A dialog for collecting data for a new image element."""
+
+    def __init__(self, master, title="New Element", imglist=None):
+        self._imglist = imglist
+        NewOption.__init__(self, master, title)
+
+    def body(self, master):
+        # element name
+        name = ttk.Label(master, text="Element name")
+        self.name = ttk.Entry(master)
+        # only image type is being supported for now
+        etype = ttk.Label(master, text="Element type")
+        self.etype = ttk.Entry(master)
+        self.etype.insert(0, "image")
+        self.etype['state'] = 'readonly'
+        defimg = ttk.Label(master, text="Default image")
+        self.defimg = ttk.Combobox(master)
+        if self._imglist:
+            self.defimg['values'] = self._imglist['values']
+        # options
+        opts = ttk.Label(master, text="Options")
+        self.opts = ttk.Entry(master)
+        # statespec(s)
+        sspec = ttk.Label(master, text="StateSpec(s)")
+        self.sspec = ttk.Entry(master)
+
+        # place the widgets
+        name.grid(row=0, column=0, sticky='w', padx=6, pady=3)
+        self.name.grid(row=0, column=1, pady=3, sticky='ew')
+        etype.grid(row=0, column=2, sticky='w', padx=6, pady=3)
+        self.etype.grid(row=0, column=3, pady=3)
+        defimg.grid(row=1, column=0, sticky='w', padx=6, pady=3)
+        self.defimg.grid(row=1, column=1, pady=3, sticky='ew')
+        opts.grid(row=1, column=2, sticky='w', padx=6, pady=3)
+        self.opts.grid(row=1, column=3, pady=3)
+        sspec.grid(row=2, column=0, sticky='w', padx=6, pady=3)
+        self.sspec.grid(row=2, column=1, columnspan=3, sticky='ew', pady=3)
+
+        self.resizable(False, False)
+
+    def validate(self):
+        """Check if an, apparently, correct element specification has been
+        entered."""
+        entries = [('elementname', self.name), ('etype', self.etype),
+            ('def', self.defimg), ('sspec', self.sspec), ('opts', self.opts)]
+        values = {}
+        for name, entry in entries:
+            values[name] = entry.get()
+
+        if not all((values['elementname'], values['etype'], values['def'])):
+            showwarning("Invalid element specification",
+                "You need to specify a name, a type and a default image "
+                "at least.", parent=self)
+            return False
+
+        self.result = values
+        return True
+
+
 class MainWindow(object):
     def __init__(self, master, title=None):
         frame = ttk.Frame(master)
@@ -314,10 +371,17 @@
 
         complement = ''
         opts = {}
-        if '.' in widget_name: # horizontal/vertical layout
+        if '.' in widget_name: # horizontal/vertical layout (maybe)
             complement, widget_name = widget_name.split('.')
             opts = {'orient': complement.lower()}
 
+        # check if this is a widget or a custom layout
+        if not hasattr(ttk, widget_name): # custom layout
+            self._current_widget['layout'] = "Custom.T%s.%s" % (complement,
+                widget_name)
+            self._update_layout_text()
+            return
+
         # create a sample widget
         if widget.get('factory', None):
             widget_class = getattr(ttk, widget_name)
@@ -343,13 +407,14 @@
         """Update the layout text for the current widget."""
         layout_name = self._current_widget['layout']
         output = cStringIO.StringIO()
-        layout = pprint.pprint(self._style.layout(layout_name), stream=output)
+        pprint.pprint(self._style.layout(layout_name), stream=output)
         layout = output.getvalue()
         output.close()
         self.layouttext.delete('1.0', 'end') # clear current text
         self.layouttext.insert('1.0', layout) # set new text
 
     def _remove_previous_widgets(self):
+        """Remove widgets from the style frames."""
         self._current_options = self._current_options or []
         # remove previous widgets
         for widget in self._current_options:
@@ -364,6 +429,7 @@
         self._update_style(self._style.map, self._mapframe)
 
     def _update_style(self, func, frame):
+        """Treeview selection changed, update the displayed style."""
         widget = self._current_widget
         layout_name = widget['layout']
         raw_name = layout_name[layout_name.find('.', 1) + 1:]
@@ -374,6 +440,17 @@
         for opt_name, opt_value in options.items():
             self._add_opt_frame(frame, func, layout_name, opt_name, opt_value)
 
+    def _add_custom_layout(self):
+        """Create a new, and empty, custom layout."""
+        result = askstring("New Layout", "Layout name")
+        if result:
+            # create an empty layout
+            self._style.layout(result, '')
+            # create a "semi-widget"
+            treeview = self._tv_custom
+            widget_d = {'factory': None, 'layouts': None}
+            self._add_widget(result, widget_d, treeview)
+
     def _add_opt_frame(self, frame, func, layout_name, opt_name, opt_value):
         """Add a new option to a frame."""
         def change_opt(option, text):
@@ -413,7 +490,7 @@
             return
 
         text = self.layouttext.get('1.0', 'end')
-        # XXX Warning, eval usage!
+        # XXX Warning: eval usage!
         self._style.layout(layout, eval(text))
 
     def _reset_layout(self):
@@ -442,7 +519,39 @@
             option, value = dlg.result
             self._add_opt_frame(frame, func, layout_name, option, value)
 
-    def _new_image(self):
+    def _ask_new_element(self, frame):
+        """Open a dialog for getting data for a new style element."""
+        dlg = NewElement(self.master, imglist=self._imagelist)
+        if dlg.result:
+            name = dlg.result['elementname']
+            # format args
+            if dlg.result['sspec']:
+                # XXX Warning: eval usage!
+                sspec = eval(dlg.result['sspec'])
+                if dlg.result['sspec'].count('(') == 1:
+                    # only one statespec defined
+                    sspec = (sspec, )
+            else:
+                sspec = ()
+            args = (dlg.result['def'], ) + sspec
+
+            # format opts (XXX Not done)
+            #if dlg.result['opts']:
+            #    print dlg.result['opts']
+            
+            # create element
+            try:
+                self._style.element_create(name, dlg.result['etype'], *args)
+            except Tkinter.TclError, err:
+                showwarning("Element couldn't be created",
+                    "The specified element couldn'be created, reason: "
+                    "\n%s" % err, parent=self.master)
+
+            # add it to the list
+            self._elems.set(name)
+            self._elems['values'] = (self._elems['values'] or ()) + (name, )
+
+    def _ask_new_image(self):
         """Add a new image to the image combobox. This image can be used
         in any widget layout."""
         dlg = NewImage(self.master)
@@ -452,6 +561,21 @@
             self._imagelist['values'] = (self._imagelist['values'] or ()) + \
                 (img.name, )
 
+    def _add_widget(self, name, opts, treeview=None):
+        """Add a new widget to self._widget."""
+        treeview = treeview or self._tv_widgets
+        children = opts.pop('layouts') or ()
+
+        parent = treeview.insert('', 'end', text=name)
+        self._widget[name] = {'tv_item': parent, 'class': None}
+        self._widget[name].update(opts)
+
+        for child in children:
+            child_name = '%s.%s' % (child, name)
+            item = treeview.insert(parent, 'end', text=child_name)
+            self._widget[child_name] = {'tv_item': item, 'class': None}
+            self._widget[child_name].update(opts)
+
     def __create_menu(self):
         menu = Tkinter.Menu()
         self.master['menu'] = menu
@@ -462,7 +586,12 @@
         file_menu.add_command(label="Exit", underline=1,
             command=self.master.destroy)
 
+        layout_menu = Tkinter.Menu(menu, tearoff=False)
+        layout_menu.add_command(label="New layout",
+            command=self._add_custom_layout)
+
         menu.add('cascade', menu=file_menu, label="File", underline=0)
+        menu.add('cascade', menu=layout_menu, label="Custom Layouts")
 
     def __setup_widgets(self):
         """Create and layout widgets."""
@@ -472,26 +601,23 @@
         top = ttk.Frame(paned)
         top.pack(side='top', fill='both', expand=True)
 
-        # top left frame (widget listing, images)
+        # top left frame (widget listing, custom layouts, images)
         left = ttk.Frame(top)
         left.pack(side='left', fill='y')
-        tframe = ttk.Frame(left)
-        tframe.pack(side='top', fill='y', expand=True)
-        self._tv_widgets = treeview = ScrolledTreeview(tframe,
-            selectmode='browse')
-        treeview.pack(side='left', fill='y', expand=True)
-        treeview.heading('#0', text="Widgets")
-        treeview.bind('<<TreeviewSelect>>', self._change_preview)
-        # images
-        imagesframe = ttk.Labelframe(left, text="Images", padding=6)
-        self._imagelist = ttk.Combobox(imagesframe, state='readonly')
-        self._imagelist.pack(fill='x', pady=6)
-        newimg = ttk.Button(imagesframe, text="Add Image",
-            command=self._new_image)
-        newimg.pack(side='bottom', anchor='e')
-        imagesframe.pack(fill='x', pady=12)
+        # widget listing
+        self._tv_widgets = ScrolledTreeview(left, selectmode='browse')
+        self._tv_widgets.pack(side='top', fill='y', anchor='w', expand=True)
+        self._tv_widgets.heading('#0', text="Widgets")
+        self._tv_widgets.bind('<<TreeviewSelect>>', self._change_preview)
+        # custom layouts
+        self._tv_custom = ScrolledTreeview(left, selectmode='browse',
+            height=4)
+        self._tv_custom.pack(side='top', anchor='w')
+        self._tv_custom.heading('#0', text="Custom Layouts")
+        self._tv_custom.bind('<<TreeviewSelect>>', self._change_preview)
 
-        # top right frame (preview, style conf, style map, themes)
+        # top right frame (preview, style conf, style map, elements, themes and
+        #                  images)
         topright = ttk.Frame(top)
         topright.pack(side='top', fill='both', expand=True, padx=6)
 
@@ -505,19 +631,31 @@
         frames.pack(side='right', anchor='n')
         # style notebook and frames
         styleframe = ttk.Labelframe(frames, text="Style", padding=6)
+        styleframe.pack(fill='both', anchor='n')
         stylenb = ttk.Notebook(styleframe)
+        # style configure
         self._configframe = ttk.Frame(stylenb, padding=6)
         newopt = ttk.Button(self._configframe, text="Add option",
             command=lambda: self._ask_new_frame_opt(self._configframe,
                 self._style.configure))
         newopt.pack(side='bottom', anchor='e')
         self._configframe.pack()
+        # style map
         self._mapframe = ttk.Frame(stylenb, padding=6)
         newmopt = ttk.Button(self._mapframe, text="Add option",
             command=lambda: self._ask_new_frame_opt(self._mapframe,
                 self._style.map))
         newmopt.pack(side='bottom', anchor='e')
         self._mapframe.pack()
+        # style elements
+        elemframe = ttk.Frame(stylenb, padding=6)
+        self._elems = ttk.Combobox(elemframe, state='readonly')
+        self._elems.pack(fill='x', pady=6)
+        newelem = ttk.Button(elemframe, text="New element",
+            command=lambda: self._ask_new_element(elemframe))
+        newelem.pack(side='bottom', anchor='e')
+        elemframe.pack()
+        # themes
         themeframe = ttk.Frame(stylenb, padding=6)
         themeframe.pack(padx=6)
         themes = ttk.Combobox(themeframe, values=self._style.theme_names(),
@@ -525,11 +663,20 @@
         themes.set("Pick one")
         themes.bind('<<ComboboxSelected>>', self._change_theme)
         themes.pack(fill='x')
+        # add frames to the style notebook
         stylenb.add(self._configframe, text="Configure")
         stylenb.add(self._mapframe, text="Map")
+        stylenb.add(elemframe, text="Elems")
         stylenb.add(themeframe, text="Themes")
         stylenb.pack(fill='both', anchor='n')
-        styleframe.pack(fill='both', anchor='n')
+        # images frame
+        imagesframe = ttk.Labelframe(frames, text="Images", padding=6)
+        self._imagelist = ttk.Combobox(imagesframe, state='readonly')
+        self._imagelist.pack(fill='x', pady=6)
+        newimg = ttk.Button(imagesframe, text="Add Image",
+            command=self._ask_new_image)
+        newimg.pack(side='bottom', anchor='e')
+        imagesframe.pack(fill='x', pady=12)
 
         # bottom frame (layout)
         bottom = ttk.Frame(paned, padding=[0, 0, 6])
@@ -565,17 +712,7 @@
         self._widget = {}
         widgets = available_widgets()
         for name, opts in sorted(widgets.items()):
-            children = opts.pop('layouts') or ()
-
-            parent = self._tv_widgets.insert('', 'end', text=name)
-            self._widget[name] = {'tv_item': parent, 'class': None}
-            self._widget[name].update(opts)
-
-            for child in children:
-                child_name = '%s.%s' % (child, name)
-                item = self._tv_widgets.insert(parent, 'end', text=child_name)
-                self._widget[child_name] = {'tv_item': item, 'class': None}
-                self._widget[child_name].update(opts)
+            self._add_widget(name, opts)
 
 
 def main(args=None):


More information about the Python-checkins mailing list