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

guilherme.polo python-checkins at python.org
Wed Jul 2 20:04:07 CEST 2008


Author: guilherme.polo
Date: Wed Jul  2 20:04:06 2008
New Revision: 64668

Log:
Images can be edited and removed now;
Added support for image format specification;
Removed self._custom_options as it has no uses, at least for now;
The sash between the top and bottom frames is adjusted just when the app starts now.


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	Wed Jul  2 20:04:06 2008
@@ -6,10 +6,11 @@
 
 # XXX ToDo List:
 #   * Save/Load style changes, maybe.
-#   * Add a way to edit images/elements.
+#   * Add a way to edit elements.
 #   * Add pre-defined elements for the current theme:
 #       - Just after editing elements feature is added.
 
+import os
 import sys
 import ttk
 import pprint
@@ -19,6 +20,8 @@
 from tkMessageBox import showwarning, showerror
 from tkFileDialog import askopenfilename
 
+IMAGE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "img")
+
 def map_widgets():
     """Maps Ttk widgets to their respective layout(s), factory and
     possibly others."""
@@ -247,16 +250,22 @@
         return False
 
 
-class NewImage(NewOption): # reusing buttonbox
-    """A dialog that asks for a image name and image path or data."""
+class ImageDialog(NewOption): # reusing buttonbox
+    """A dialog that asks for a image name and image path or data and then
+    creates a PhotoImage from the data, or, receives data to edit."""
     
-    def __init__(self, master, title="New Image"):
+    def __init__(self, master, title="New Image", image=None):
+        self._editing = True if image else False
+        self._image = image
         NewOption.__init__(self, master, title)
 
     def body(self, master):
         lbl = ttk.Label(master, text="Image name")
         self.img_name = ttk.Entry(master)
 
+        lbl_format = ttk.Label(master, text="Image Format")
+        self.img_format = ttk.Entry(master)
+
         lbl_val = ttk.Label(master, text="Image path")
         self.img_path = ttk.Entry(master)
         browse = ttk.Button(master, text="Find", command=self._find_image)
@@ -264,21 +273,34 @@
         lbl_other = ttk.Label(master, text="or")
 
         lbl_data = ttk.Label(master, text="Image data")
-        self.img_data = ScrolledText(master, width=60, height=6)
+        self.img_data = ScrolledText(master, width=60, height=8)
 
         lbl.grid(row=0, column=0, padx=6, sticky='e')
         self.img_name.grid(row=0, column=1, padx=6, columnspan=2, sticky='ew')
-        lbl_val.grid(row=1, column=0, padx=6, pady=6, sticky='e')
-        self.img_path.grid(row=1, column=1, padx=6, sticky='ew')
-        browse.grid(row=1, column=2, padx=6, sticky='e')
-        lbl_other.grid(row=2, columnspan=3, pady=3)
-        lbl_data.grid(row=3, column=0, padx=6, sticky='new')
-        self.img_data.grid(row=3, column=1, columnspan=2)
+        lbl_format.grid(row=1, column=0, padx=6, sticky='e', pady=6)
+        self.img_format.grid(row=1, column=1, padx=6, columnspan=2,
+            sticky='ew', pady=6)
+        lbl_val.grid(row=2, column=0, padx=6, sticky='e')
+        self.img_path.grid(row=2, column=1, padx=6, sticky='ew')
+        browse.grid(row=2, column=2, padx=6, sticky='e')
+        lbl_other.grid(row=3, columnspan=3, pady=3)
+        lbl_data.grid(row=4, column=0, padx=6, sticky='new')
+        self.img_data.grid(row=4, column=1, columnspan=2)
 
         master.grid_columnconfigure(1, weight=1)
 
         self.resizable(False, False)
 
+        if self._editing:
+            self.img_name.insert(0, self._image.name)
+            self.img_name['state'] = 'readonly'
+            self.img_format.insert(0, self._image['format'])
+
+            if self._image['file']:
+                self.img_path.insert(0, self._image['file'])
+            else:
+                self.img_data.insert('1.0', self._image['data'])
+
     def validate(self):
         """Verify that a name was defined and only one between data and
         image path has been defined."""
@@ -293,18 +315,54 @@
                 "a image path or the image data.", parent=self)
             return False
 
+        if self._editing:
+            if not self._change_image(img_name, img_path, img_data):
+                return False
+        else:
+            if not self._create_image(img_name, img_path, img_data):
+                return False
+
+        return True
+
+    def _create_image(self, img_name, img_path, img_data):
+        """Create a new PhotoImage."""
         try:
+            kwargs = {'name': img_name}
+            if self.img_format.get():
+                kwargs['format'] = self.img_format.get()
+
             if img_data:
-                self.result = Tkinter.PhotoImage(name=img_name, data=img_data)
+                kwargs['data'] = img_data
             else:
-                self.result = Tkinter.PhotoImage(name=img_name, file=img_path)
+                kwargs['file'] = img_path
+
+            self.result = Tkinter.PhotoImage(**kwargs)
         except Tkinter.TclError, err:
             showerror("Error creating image", err, parent=self)
             return False
+        else:
+            return True
 
-        return True
+    def _change_image(self, img_name, img_path, img_data):
+        """Change an existing PhotoImage."""
+        try:
+            if self.img_format.get():
+                self._image['format'] = self.img_format.get()
+
+            if img_path:
+                self._image['file'] = img_path
+                self._image['data'] = ''
+            else:
+                self._image['file'] = ''
+                self._image['data'] = img_data
+        except Tkinter.TclError, err:
+            showerror("Error updating image", err, parent=self)
+            return False
+        else:
+            return True
 
     def _find_image(self):
+        """Open a file browser and search for the image path."""
         path = askopenfilename(parent=self)
         if path:
             # erase previous content
@@ -406,7 +464,7 @@
 
         self._style = ttk.Style(self.master)
         self._current_widget = {'layout': None, 'widget': None}
-        self._custom_options = {} # custom options per widget
+        self._images = {}
 
         self.__create_menu()
         self.__setup_widgets()
@@ -555,7 +613,7 @@
         self._update_layout_text(layout[layout.find('.') + 1:])
         self.layouttext.layout = layout
 
-    def _ask_new_frame_opt(self, frame, func):
+    def _new_frame_opt(self, frame, func):
         """Open a dialog asking for a new option to be added in the
         specified frame and then add it."""
         widget = self._current_widget
@@ -569,14 +627,9 @@
         dlg = NewOption(self.master)
         if dlg.result is not None:
             option, value = dlg.result
-
-            if layout_name not in self._custom_options:
-                self._custom_options[layout_name] = []
-
-            self._custom_options[layout_name].append(option)
             self._add_opt_frame(frame, func, layout_name, option, value)
 
-    def _ask_new_element(self, frame):
+    def _new_element(self, frame):
         """Open a dialog for getting data for a new style element and then
         create it."""
         dlg = NewElement(self.master, imglist=self._imagelist)
@@ -595,8 +648,8 @@
 
             # create element
             try:
-                self._style.element_create(name, dlg.result['etype'], *args,
-                    **dlg.result['opts'])
+                self._style.element_create(name,
+                    dlg.result['etype'], *args, **dlg.result['opts'])
             except Tkinter.TclError, err:
                 showerror("Element couldn't be created",
                     "The specified element couldn'be created, reason: "
@@ -605,16 +658,42 @@
                 # add it to the list
                 self._elems.set(name)
                 self._elems['values'] = (self._elems['values'] or ()) + (name, )
+                # the new element could have affected the current widget, so
+                # we need to update the preview area.
+                treeview = self._tv_widgets
+                self._change_preview(treeview, invalid=True)
 
-    def _ask_new_image(self):
+    def _new_image(self):
         """Add a new image to the image combobox. This image can be used
         in any widget layout."""
-        dlg = NewImage(self.master)
+        dlg = ImageDialog(self.master)
         if dlg.result: # add new image to the images list
             img = dlg.result
-            self._imagelist.set(img.name)
+            img_name = img.name
+            self._images[img_name] = img
+            self._imagelist.set(img_name)
             self._imagelist['values'] = (self._imagelist['values'] or ()) + \
-                (img.name, )
+                (img_name, )
+
+    def _edit_image(self):
+        """Edit current selected image in imagelist."""
+        img_name = self._imagelist.get()
+        if not img_name:
+            return
+
+        ImageDialog(self.master, "Editing Image", self._images[img_name])
+
+    def _remove_image(self):
+        """Remove current selected image in imagelist."""
+        img_name = self._imagelist.get()
+        if not img_name:
+            return
+
+        del self._images[img_name]
+        values = set(self._imagelist['values']) - set([img_name])
+        self._imagelist['values'] = list(values)
+        value = values.pop() if values else ''
+        self._imagelist.set(value)
 
     def _change_theme(self, event):
         """New theme selected at themes combobox, change current theme."""
@@ -662,7 +741,7 @@
         left.pack(side='left', fill='y')
         # widget listing
         self._tv_widgets = ScrolledTreeview(left, selectmode='browse')
-        self._tv_widgets.pack(side='top', fill='y', anchor='w', expand=True)
+        self._tv_widgets.pack(side='top', fill='y', expand=True)
         self._tv_widgets.heading('#0', text="Widgets")
         self._tv_widgets.bind('<<TreeviewSelect>>', self._change_preview)
 
@@ -672,27 +751,26 @@
 
         # preview area
         self._preview_area = ttk.Frame(topright, width=200)
-        self._preview_area.pack(anchor='center', side='left', expand=True,
-            fill='both', padx=12)
+        self._preview_area.pack(side='left', expand=True, fill='both', padx=12)
 
         # options, images and themes
         frames = ttk.Frame(topright)
         frames.pack(side='right', anchor='n')
         # style notebook and frames
         styleframe = ttk.Labelframe(frames, text="Style", padding=6)
-        styleframe.pack(fill='both', anchor='n')
+        styleframe.pack(fill='both')
         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,
+            command=lambda: self._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,
+            command=lambda: self._new_frame_opt(self._mapframe,
                 self._style.map))
         newmopt.pack(side='bottom', anchor='e')
         self._mapframe.pack()
@@ -701,7 +779,7 @@
         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))
+            command=lambda: self._new_element(elemframe))
         newelem.pack(side='bottom', anchor='e')
         elemframe.pack()
         # themes
@@ -711,7 +789,7 @@
             state='readonly')
         themes.set("Pick one")
         themes.bind('<<ComboboxSelected>>', self._change_theme)
-        themes.pack(fill='x')
+        themes.pack(fill='x', pady=6)
         # add frames to the style notebook
         stylenb.add(self._configframe, text="Configure")
         stylenb.add(self._mapframe, text="Map")
@@ -719,16 +797,32 @@
         stylenb.add(themeframe, text="Themes")
         stylenb.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 = ttk.Labelframe(frames, padding=6)
         imagesframe.pack(fill='x', pady=12)
+        iframe = ttk.Frame(imagesframe)
+        imagesframe['labelwidget'] = iframe
+        self.__img_add = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+            'add.gif'))
+        self.__img_edit = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+            'stock_properties.gif'))
+        self.__img_del = Tkinter.PhotoImage(file=os.path.join(IMAGE_DIR,
+            'remove.gif'))
+        ilbl = ttk.Label(iframe, text="Images")
+        iadd = ttk.Button(iframe, image=self.__img_add.name,
+            style='Toolbutton', command=self._new_image)
+        iedit = ttk.Button(iframe, image=self.__img_edit.name,
+            style='Toolbutton', command=self._edit_image)
+        iremove = ttk.Button(iframe, image=self.__img_del.name,
+            style='Toolbutton', command=self._remove_image)
+        ilbl.pack(side='left')
+        iadd.pack(side='left')
+        iedit.pack(side='left')
+        iremove.pack(side='left')
+        self._imagelist = ttk.Combobox(imagesframe, state='readonly')
+        self._imagelist.pack(fill='x')
 
         # bottom frame (layout)
-        bottom = ttk.Frame(paned, padding=[0, 0, 6])
+        bottom = ttk.Frame(paned)
         bottom.pack(side='bottom')
         layoutframe = ttk.Labelframe(bottom, text="Layout", padding=6)
         layoutframe.pack(fill='both', expand=True)
@@ -749,13 +843,16 @@
         paned.add(top, weight=1)
         paned.add(bottom, weight=0)
         paned.pack(fill='both', expand=True)
-        paned.bind('<Map>', self.__adjust_sash)
+        self.__funcid = paned.bind('<Map>', self.__adjust_sash)
 
     def __adjust_sash(self, event):
-        """Adjust sash position between the top frame and the bottom frame."""
+        """Adjust the initial sash position between the top frame and the
+        bottom frame."""
         height = self.master.geometry().split('x')[1].split('+')[0]
         paned = event.widget
         paned.sashpos(0, int(height) - 180)
+        paned.unbind('<Map>', self.__funcid)
+        del self.__funcid
 
     def __fill_treeview(self):
         """Insert available widgets in the treeview."""


More information about the Python-checkins mailing list