[Python-checkins] r64579 - sandbox/trunk/ttk-gsoc/samples/theming.py
guilherme.polo
python-checkins at python.org
Sun Jun 29 01:00:22 CEST 2008
Author: guilherme.polo
Date: Sun Jun 29 01:00:21 2008
New Revision: 64579
Log:
Every widget that needs a factory has one now;
Added sublayouts;
Removed custom layouts since I was using it only for adding sublayouts;
Some other misc changes.
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 Sun Jun 29 01:00:21 2008
@@ -5,11 +5,10 @@
-- Guilherme Polo, 2008.
"""
-# ToDO: Add a way to remove options.
+# ToDO: Support element options.
+# Add a way to remove options.
# Add a way to edit images/elements.
-# Add sublayouts.
# Add pre-defined elements for the current theme.
-# Handling element options.
# ...
import sys
@@ -21,19 +20,24 @@
from tkMessageBox import showwarning
from tkFileDialog import askopenfilename
-def available_widgets():
- """Returns a list of Ttk widgets."""
+def available_widgets(): # XXX misleading function name
+ """Returns a list of Ttk widgets.""" # XXX misleading docstring
widgets = {}
# will discard Style and extension classes
unwanted_names = ('Style', 'LabeledScale', 'OptionMenu')
# some widgets contain Vertical and Horizontal layouts
- special = ('Progressbar', 'Scale', 'Scrollbar')
+ vert_horiz = ('Progressbar', 'Scale', 'Scrollbar')
+ # several widgets contain a single layout named as Twidgetname
+ prefix_t = ('Label', 'Button', 'Checkbutton', 'Radiobutton', 'Menubutton',
+ 'Entry', 'Combobox', 'Frame', 'Labelframe', 'Separator', 'Sizegrip')
sample = {'Button': widget_text, 'Checkbutton': widget_text,
'Label': widget_text, 'Radiobutton': widget_text,
'Labelframe': widget_text_size, 'Combobox': widget_values,
'Progressbar': widget_progress, 'Notebook': widget_notebook,
- 'Treeview': widget_treeview, 'Scrollbar': widget_expand}
+ 'Treeview': widget_treeview, 'Scrollbar': widget_expand,
+ 'Frame': widget_expand, 'Separator': widget_expand,
+ 'Menubutton': widget_menubtn, 'Panedwindow': widget_paned}
for name in ttk.__all__:
if name in unwanted_names:
@@ -46,11 +50,23 @@
widget_d = {'factory': None, 'layouts': None}
- if name in special:
- widget_d['layouts'] = ('Horizontal', 'Vertical')
+ if name in prefix_t:
+ widget_d['layouts'] = ('T%s' % name, )
+ elif name in vert_horiz:
+ widget_d['layouts'] = ('Horizontal.T%s' % name,
+ 'Vertical.T%s' % name)
+ elif name == 'Notebook':
+ widget_d['layouts'] = ('TNotebook', 'Tab')
+ elif name == 'Panedwindow':
+ widget_d['layouts'] = ('TPanedwindow', 'Horizontal.Sash',
+ 'Vertical.Sash')
+ elif name == 'Treeview':
+ widget_d['layouts'] = ('Treeview', 'Item', 'Cell', 'Heading', 'Row')
if name in sample:
widget_d['factory'] = sample[name]
+ if name == 'Scrollbar':
+ widget_d['class'] = 'Vertical.TScrollbar'
widgets[name] = widget_d
@@ -94,10 +110,29 @@
w.insert('', 'end', text="Row %d" % i, values=[i, i + 1])
return w
+def widget_menubtn(widget, master, **kw):
+ """Create a sample menu button with some options."""
+ menu = Tkinter.Menu(tearoff=False)
+ for i in range(5):
+ menu.add_radiobutton(label='Item %d' % i)
+ return widget(master, text="Sample", menu=menu, **kw)
+
+def widget_paned(widget, master, **kw):
+ """Create a sample Panedwindow with two children."""
+ w = widget(master, height=150, **kw)
+ c1 = ttk.Label(w, text="Top")
+ c2 = ttk.Label(w, text="Bottom")
+ w.add(c1)
+ w.add(c2)
+ return w
+
def widget_expand(widget, master, **kw):
"""Instantiate widget and configure it to expand."""
w = widget(master, **kw)
- fill = 'x' if 'horizontal' in str(w['orient']) else 'y'
+ try:
+ fill = 'x' if 'horizontal' in str(w['orient']) else 'y'
+ except Tkinter.TclError:
+ fill = 'both'
w.pack_configure(expand=True, fill=fill)
return w
@@ -358,31 +393,38 @@
self.__setup_widgets()
self.__fill_treeview()
- def _change_preview(self, event):
- """New treeview selection, update preview area."""
+ def _change_preview(self, event, invalid=False):
+ """New treeview selection (or theme changed), update preview area."""
treeview = getattr(event, 'widget', event)
- if not treeview.selection():
- return
- tv_item = treeview.item(treeview.selection()[0])
+ sel = treeview.selection()
+ if not sel: # nothing selected
+ return
+
+ sel = sel[0]
+ tv_item = treeview.item(sel)
widget_name = tv_item['text']
+ widget_style = None
+ opts = {}
+
+ if self._is_layout(widget_name, sel): # not a widget, but a layout
+ self._update_layout_text(widget_name)
+ if 'Horizontal' in widget_name or 'Vertical' in widget_name:
+ opts['orient'] = widget_name.split('.')[0].lower()
+ widget_style = "Custom.%s" % widget_name
+ widget_name = treeview.item(treeview.parent(sel))['text']
+ else:
+ self._empty_layout_text()
+
widget = self._widget[widget_name]
- parent = widget['tv_item']
- if treeview.get_children(parent):
- return
+ widget_style = widget_style or "Custom.%s" % widget['class']
+ curr_widget = self._current_widget
- complement = ''
- opts = {}
- 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
+ if not invalid and curr_widget['layout'] == widget_style:
+ if not opts or \
+ str(curr_widget['widget']['orient']) == opts['orient']:
+ # didn't select a new widget/no new options
+ return
# create a sample widget
if widget.get('factory', None):
@@ -390,30 +432,22 @@
sample = widget['factory'](widget_class, self._preview_area, **opts)
else:
sample = getattr(ttk, widget_name)(self._preview_area, **opts)
- if widget['class'] is None:
- widget['class'] = "%s%s%s" % (complement,
- '.' if complement else '', sample.winfo_class())
- sample['style'] = 'Custom.%s' % widget['class']
- if self._current_widget['widget'] is not None:
- self._current_widget['widget'].pack_forget()
+
+ sample['style'] = widget_style
+ if curr_widget['widget'] is not None:
+ curr_widget['widget'].pack_forget()
sample.pack(expand=True)
- self._current_widget['layout'] = sample['style']
- self._current_widget['widget'] = sample
- self._update_layout_text()
+ curr_widget['layout'] = widget_style
+ curr_widget['widget'] = sample
self._remove_previous_widgets()
self._update_style_configframe()
self._update_style_mapframe()
- def _update_layout_text(self):
- """Update the layout text for the current widget."""
- layout_name = self._current_widget['layout']
- output = cStringIO.StringIO()
- 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 _is_layout(self, name, selection):
+ """Check if a treeview selection is a layout or a widget."""
+ return (name not in self._widget or
+ self._widget[name]['tv_item'] != selection)
def _remove_previous_widgets(self):
"""Remove widgets from the style frames."""
@@ -442,17 +476,6 @@
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):
@@ -464,7 +487,7 @@
func(layout_name, **{option: text})
except (SyntaxError, Tkinter.TclError, TypeError):
pass
- return 1
+ return True
lbl = ttk.Label(frame, text=opt_name)
entry = ttk.Entry(frame)
@@ -477,13 +500,18 @@
self._current_options = self._current_options or []
self._current_options.extend([lbl, entry])
- def _change_theme(self, event):
- """New theme selected at themes combobox, change current theme."""
- widget = event.widget
- self._style.theme_use(widget.get())
+ def _update_layout_text(self, layout_name):
+ """Update the layout text for the current widget."""
+ output = cStringIO.StringIO()
+ pprint.pprint(self._style.layout(layout_name), stream=output)
+ layout = output.getvalue()
+ output.close()
+ self._empty_layout_text()
+ self.layouttext.insert('1.0', layout) # set new text
- treeview = self._tv_widgets
- self._change_preview(treeview)
+ def _empty_layout_text(self):
+ """Clear current text in the layout text widget."""
+ self.layouttext.delete('1.0', 'end')
def _apply_layout(self):
"""Apply the supposed new layout for the current selected widget."""
@@ -492,6 +520,8 @@
return
text = self.layouttext.get('1.0', 'end')
+ if not text.strip(): # no text
+ return
# XXX Warning: eval usage!
self._style.layout(layout, eval(text))
@@ -502,8 +532,7 @@
return
orig_name = widget['layout'][widget['layout'].find('.', 1) + 1:]
- self._style.layout(widget['layout'], self._style.layout(orig_name))
- self._update_layout_text()
+ self._update_layout_text(orig_name)
def _ask_new_frame_opt(self, frame, func):
"""Open a dialog asking for a new option to be added in the
@@ -563,37 +592,39 @@
self._imagelist['values'] = (self._imagelist['values'] or ()) + \
(img.name, )
+ def _change_theme(self, event):
+ """New theme selected at themes combobox, change current theme."""
+ widget = event.widget
+ self._style.theme_use(widget.get())
+
+ treeview = self._tv_widgets
+ self._change_preview(treeview, invalid=True)
+
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 ()
+ children = opts.pop('layouts')
parent = treeview.insert('', 'end', text=name)
- self._widget[name] = {'tv_item': parent, 'class': None}
+ self._widget[name] = {'tv_item': parent, 'class': children[0]}
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)
+ treeview.insert(parent, 'end', text=child)
def __create_menu(self):
menu = Tkinter.Menu()
self.master['menu'] = menu
file_menu = Tkinter.Menu(menu, tearoff=False)
- #file_menu.add_command(label="Save", underline=0)
file_menu.add_separator()
- file_menu.add_command(label="Exit", underline=1,
+ file_menu.add_command(label="Exit", underline=1, accelerator="Ctrl-X",
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")
+ self.master.bind('<Control-x>', 'exit')
def __setup_widgets(self):
"""Create and layout widgets."""
@@ -603,7 +634,7 @@
top = ttk.Frame(paned)
top.pack(side='top', fill='both', expand=True)
- # top left frame (widget listing, custom layouts, images)
+ # top left frame (widget listing, images)
left = ttk.Frame(top)
left.pack(side='left', fill='y')
# widget listing
@@ -611,22 +642,15 @@
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, elements, themes and
- # images)
+ # top right frame (preview, style notebook, images)
topright = ttk.Frame(top)
- topright.pack(side='top', fill='both', expand=True, padx=6)
+ topright.pack(side='top', fill='both', expand=True)
# preview area
- self._preview_area = ttk.Frame(topright, width=200, padding=12)
+ self._preview_area = ttk.Frame(topright, width=200)
self._preview_area.pack(anchor='center', side='left', expand=True,
- fill='both')
+ fill='both', padx=12)
# options, images and themes
frames = ttk.Frame(topright)
More information about the Python-checkins
mailing list