mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 10:26:02 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			452 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			452 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| 
 | |
| # The options of a widget are described by the following attributes
 | |
| # of the Pack and Widget dialogs:
 | |
| #
 | |
| # Dialog.current: {name: value}
 | |
| # -- changes during Widget's lifetime
 | |
| #
 | |
| # Dialog.options: {name: (default, klass)}
 | |
| # -- depends on widget class only
 | |
| #
 | |
| # Dialog.classes: {klass: (v0, v1, v2, ...) | 'boolean' | 'other'}
 | |
| # -- totally static, though different between PackDialog and WidgetDialog
 | |
| #    (but even that could be unified)
 | |
| 
 | |
| from Tkinter import *
 | |
| 
 | |
| class Option:
 | |
| 
 | |
|     varclass = StringVar            # May be overridden
 | |
| 
 | |
|     def __init__(self, dialog, option):
 | |
|         self.dialog = dialog
 | |
|         self.option = option
 | |
|         self.master = dialog.top
 | |
|         self.default, self.klass = dialog.options[option]
 | |
|         self.var = self.varclass(self.master)
 | |
|         self.frame = Frame(self.master)
 | |
|         self.frame.pack(fill=X)
 | |
|         self.label = Label(self.frame, text=(option + ":"))
 | |
|         self.label.pack(side=LEFT)
 | |
|         self.update()
 | |
|         self.addoption()
 | |
| 
 | |
|     def refresh(self):
 | |
|         self.dialog.refresh()
 | |
|         self.update()
 | |
| 
 | |
|     def update(self):
 | |
|         try:
 | |
|             self.current = self.dialog.current[self.option]
 | |
|         except KeyError:
 | |
|             self.current = self.default
 | |
|         self.var.set(self.current)
 | |
| 
 | |
|     def set(self, e=None):          # Should be overridden
 | |
|         pass
 | |
| 
 | |
| class BooleanOption(Option):
 | |
| 
 | |
|     varclass = BooleanVar
 | |
| 
 | |
|     def addoption(self):
 | |
|         self.button = Checkbutton(self.frame,
 | |
|                                  text='on/off',
 | |
|                                  onvalue=1,
 | |
|                                  offvalue=0,
 | |
|                                  variable=self.var,
 | |
|                                  relief=RAISED,
 | |
|                                  borderwidth=2,
 | |
|                                  command=self.set)
 | |
|         self.button.pack(side=RIGHT)
 | |
| 
 | |
| class EnumOption(Option):
 | |
| 
 | |
|     def addoption(self):
 | |
|         self.button = Menubutton(self.frame,
 | |
|                                  textvariable=self.var,
 | |
|                                  relief=RAISED, borderwidth=2)
 | |
|         self.button.pack(side=RIGHT)
 | |
|         self.menu = Menu(self.button)
 | |
|         self.button['menu'] = self.menu
 | |
|         for v in self.dialog.classes[self.klass]:
 | |
|             self.menu.add_radiobutton(
 | |
|                 label=v,
 | |
|                 variable=self.var,
 | |
|                 value=v,
 | |
|                 command=self.set)
 | |
| 
 | |
| class StringOption(Option):
 | |
| 
 | |
|     def addoption(self):
 | |
|         self.entry = Entry(self.frame,
 | |
|                            textvariable=self.var,
 | |
|                            width=10,
 | |
|                            relief=SUNKEN,
 | |
|                            borderwidth=2)
 | |
|         self.entry.pack(side=RIGHT, fill=X, expand=1)
 | |
|         self.entry.bind('<Return>', self.set)
 | |
| 
 | |
| class ReadonlyOption(Option):
 | |
| 
 | |
|     def addoption(self):
 | |
|         self.label = Label(self.frame, textvariable=self.var,
 | |
|                            anchor=E)
 | |
|         self.label.pack(side=RIGHT)
 | |
| 
 | |
| class Dialog:
 | |
| 
 | |
|     def __init__(self, master):
 | |
|         self.master = master
 | |
|         self.fixclasses()
 | |
|         self.refresh()
 | |
|         self.top = Toplevel(self.master)
 | |
|         self.top.title(self.__class__.__name__)
 | |
|         self.top.minsize(1, 1)
 | |
|         self.addchoices()
 | |
| 
 | |
|     def refresh(self): pass         # Must override
 | |
| 
 | |
|     def fixclasses(self): pass      # May override
 | |
| 
 | |
|     def addchoices(self):
 | |
|         self.choices = {}
 | |
|         list = []
 | |
|         for k, dc in self.options.items():
 | |
|             list.append((k, dc))
 | |
|         list.sort()
 | |
|         for k, (d, c) in list:
 | |
|             try:
 | |
|                 cl = self.classes[c]
 | |
|             except KeyError:
 | |
|                 cl = 'unknown'
 | |
|             if type(cl) == TupleType:
 | |
|                 cl = self.enumoption
 | |
|             elif cl == 'boolean':
 | |
|                 cl = self.booleanoption
 | |
|             elif cl == 'readonly':
 | |
|                 cl = self.readonlyoption
 | |
|             else:
 | |
|                 cl = self.stringoption
 | |
|             self.choices[k] = cl(self, k)
 | |
| 
 | |
|     # Must override:
 | |
|     options = {}
 | |
|     classes = {}
 | |
| 
 | |
|     # May override:
 | |
|     booleanoption = BooleanOption
 | |
|     stringoption = StringOption
 | |
|     enumoption = EnumOption
 | |
|     readonlyoption = ReadonlyOption
 | |
| 
 | |
| class PackDialog(Dialog):
 | |
| 
 | |
|     def __init__(self, widget):
 | |
|         self.widget = widget
 | |
|         Dialog.__init__(self, widget)
 | |
| 
 | |
|     def refresh(self):
 | |
|         self.current = self.widget.info()
 | |
|         self.current['.class'] = self.widget.winfo_class()
 | |
|         self.current['.name'] = self.widget._w
 | |
| 
 | |
|     class packoption: # Mix-in class
 | |
|         def set(self, e=None):
 | |
|             self.current = self.var.get()
 | |
|             try:
 | |
|                 apply(self.dialog.widget.pack, (),
 | |
|                       {self.option: self.current})
 | |
|             except TclError, msg:
 | |
|                 print msg
 | |
|                 self.refresh()
 | |
| 
 | |
|     class booleanoption(packoption, BooleanOption): pass
 | |
|     class enumoption(packoption, EnumOption): pass
 | |
|     class stringoption(packoption, StringOption): pass
 | |
|     class readonlyoption(packoption, ReadonlyOption): pass
 | |
| 
 | |
|     options = {
 | |
|             '.class': (None, 'Class'),
 | |
|             '.name': (None, 'Name'),
 | |
|             'after': (None, 'Widget'),
 | |
|             'anchor': ('center', 'Anchor'),
 | |
|             'before': (None, 'Widget'),
 | |
|             'expand': ('no', 'Boolean'),
 | |
|             'fill': ('none', 'Fill'),
 | |
|             'in': (None, 'Widget'),
 | |
|             'ipadx': (0, 'Pad'),
 | |
|             'ipady': (0, 'Pad'),
 | |
|             'padx': (0, 'Pad'),
 | |
|             'pady': (0, 'Pad'),
 | |
|             'side': ('top', 'Side'),
 | |
|             }
 | |
| 
 | |
|     classes = {
 | |
|             'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
 | |
|             'Boolean': 'boolean',
 | |
|             'Class': 'readonly',
 | |
|             'Expand': 'boolean',
 | |
|             'Fill': (NONE, X, Y, BOTH),
 | |
|             'Name': 'readonly',
 | |
|             'Pad': 'pixel',
 | |
|             'Side': (TOP, RIGHT, BOTTOM, LEFT),
 | |
|             'Widget': 'readonly',
 | |
|             }
 | |
| 
 | |
| class RemotePackDialog(PackDialog):
 | |
| 
 | |
|     def __init__(self, master, app, widget):
 | |
|         self.master = master
 | |
|         self.app = app
 | |
|         self.widget = widget
 | |
|         self.refresh()
 | |
|         self.top = Toplevel(self.master)
 | |
|         self.top.title(self.app + ' PackDialog')
 | |
|         self.top.minsize(1, 1)
 | |
|         self.addchoices()
 | |
| 
 | |
|     def refresh(self):
 | |
|         try:
 | |
|             words = self.master.tk.splitlist(
 | |
|                     self.master.send(self.app,
 | |
|                                      'pack',
 | |
|                                      'info',
 | |
|                                      self.widget))
 | |
|         except TclError, msg:
 | |
|             print msg
 | |
|             return
 | |
|         dict = {}
 | |
|         for i in range(0, len(words), 2):
 | |
|             key = words[i][1:]
 | |
|             value = words[i+1]
 | |
|             dict[key] = value
 | |
|         dict['.class'] = self.master.send(self.app,
 | |
|                                           'winfo',
 | |
|                                           'class',
 | |
|                                           self.widget)
 | |
|         dict['.name'] = self.widget
 | |
|         self.current = dict
 | |
| 
 | |
|     class remotepackoption: # Mix-in class
 | |
|         def set(self, e=None):
 | |
|             self.current = self.var.get()
 | |
|             try:
 | |
|                 self.dialog.master.send(
 | |
|                         self.dialog.app,
 | |
|                         'pack',
 | |
|                         'config',
 | |
|                         self.dialog.widget,
 | |
|                         '-'+self.option,
 | |
|                         self.dialog.master.tk.merge(
 | |
|                                 self.current))
 | |
|             except TclError, msg:
 | |
|                 print msg
 | |
|                 self.refresh()
 | |
| 
 | |
|     class booleanoption(remotepackoption, BooleanOption): pass
 | |
|     class enumoption(remotepackoption, EnumOption): pass
 | |
|     class stringoption(remotepackoption, StringOption): pass
 | |
|     class readonlyoption(remotepackoption, ReadonlyOption): pass
 | |
| 
 | |
| class WidgetDialog(Dialog):
 | |
| 
 | |
|     def __init__(self, widget):
 | |
|         self.widget = widget
 | |
|         self.klass = widget.winfo_class()
 | |
|         Dialog.__init__(self, widget)
 | |
| 
 | |
|     def fixclasses(self):
 | |
|         if self.addclasses.has_key(self.klass):
 | |
|             classes = {}
 | |
|             for c in (self.classes,
 | |
|                       self.addclasses[self.klass]):
 | |
|                 for k in c.keys():
 | |
|                     classes[k] = c[k]
 | |
|             self.classes = classes
 | |
| 
 | |
|     def refresh(self):
 | |
|         self.configuration = self.widget.config()
 | |
|         self.update()
 | |
|         self.current['.class'] = self.widget.winfo_class()
 | |
|         self.current['.name'] = self.widget._w
 | |
| 
 | |
|     def update(self):
 | |
|         self.current = {}
 | |
|         self.options = {}
 | |
|         for k, v in self.configuration.items():
 | |
|             if len(v) > 4:
 | |
|                 self.current[k] = v[4]
 | |
|                 self.options[k] = v[3], v[2] # default, klass
 | |
|         self.options['.class'] = (None, 'Class')
 | |
|         self.options['.name'] = (None, 'Name')
 | |
| 
 | |
|     class widgetoption: # Mix-in class
 | |
|         def set(self, e=None):
 | |
|             self.current = self.var.get()
 | |
|             try:
 | |
|                 self.dialog.widget[self.option] = self.current
 | |
|             except TclError, msg:
 | |
|                 print msg
 | |
|                 self.refresh()
 | |
| 
 | |
|     class booleanoption(widgetoption, BooleanOption): pass
 | |
|     class enumoption(widgetoption, EnumOption): pass
 | |
|     class stringoption(widgetoption, StringOption): pass
 | |
|     class readonlyoption(widgetoption, ReadonlyOption): pass
 | |
| 
 | |
|     # Universal classes
 | |
|     classes = {
 | |
|             'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
 | |
|             'Aspect': 'integer',
 | |
|             'Background': 'color',
 | |
|             'Bitmap': 'bitmap',
 | |
|             'BorderWidth': 'pixel',
 | |
|             'Class': 'readonly',
 | |
|             'CloseEnough': 'double',
 | |
|             'Command': 'command',
 | |
|             'Confine': 'boolean',
 | |
|             'Cursor': 'cursor',
 | |
|             'CursorWidth': 'pixel',
 | |
|             'DisabledForeground': 'color',
 | |
|             'ExportSelection': 'boolean',
 | |
|             'Font': 'font',
 | |
|             'Foreground': 'color',
 | |
|             'From': 'integer',
 | |
|             'Geometry': 'geometry',
 | |
|             'Height': 'pixel',
 | |
|             'InsertWidth': 'time',
 | |
|             'Justify': (LEFT, CENTER, RIGHT),
 | |
|             'Label': 'string',
 | |
|             'Length': 'pixel',
 | |
|             'MenuName': 'widget',
 | |
|             'Name': 'readonly',
 | |
|             'OffTime': 'time',
 | |
|             'OnTime': 'time',
 | |
|             'Orient': (HORIZONTAL, VERTICAL),
 | |
|             'Pad': 'pixel',
 | |
|             'Relief': (RAISED, SUNKEN, FLAT, RIDGE, GROOVE),
 | |
|             'RepeatDelay': 'time',
 | |
|             'RepeatInterval': 'time',
 | |
|             'ScrollCommand': 'command',
 | |
|             'ScrollIncrement': 'pixel',
 | |
|             'ScrollRegion': 'rectangle',
 | |
|             'ShowValue': 'boolean',
 | |
|             'SetGrid': 'boolean',
 | |
|             'Sliderforeground': 'color',
 | |
|             'SliderLength': 'pixel',
 | |
|             'Text': 'string',
 | |
|             'TickInterval': 'integer',
 | |
|             'To': 'integer',
 | |
|             'Underline': 'index',
 | |
|             'Variable': 'variable',
 | |
|             'Value': 'string',
 | |
|             'Width': 'pixel',
 | |
|             'Wrap': (NONE, CHAR, WORD),
 | |
|             }
 | |
| 
 | |
|     # Classes that (may) differ per widget type
 | |
|     _tristate = {'State': (NORMAL, ACTIVE, DISABLED)}
 | |
|     _bistate = {'State': (NORMAL, DISABLED)}
 | |
|     addclasses = {
 | |
|             'Button': _tristate,
 | |
|             'Radiobutton': _tristate,
 | |
|             'Checkbutton': _tristate,
 | |
|             'Entry': _bistate,
 | |
|             'Text': _bistate,
 | |
|             'Menubutton': _tristate,
 | |
|             'Slider': _bistate,
 | |
|             }
 | |
| 
 | |
| class RemoteWidgetDialog(WidgetDialog):
 | |
| 
 | |
|     def __init__(self, master, app, widget):
 | |
|         self.app = app
 | |
|         self.widget = widget
 | |
|         self.klass = master.send(self.app,
 | |
|                                  'winfo',
 | |
|                                  'class',
 | |
|                                  self.widget)
 | |
|         Dialog.__init__(self, master)
 | |
| 
 | |
|     def refresh(self):
 | |
|         try:
 | |
|             items = self.master.tk.splitlist(
 | |
|                     self.master.send(self.app,
 | |
|                                      self.widget,
 | |
|                                      'config'))
 | |
|         except TclError, msg:
 | |
|             print msg
 | |
|             return
 | |
|         dict = {}
 | |
|         for item in items:
 | |
|             words = self.master.tk.splitlist(item)
 | |
|             key = words[0][1:]
 | |
|             value = (key,) + words[1:]
 | |
|             dict[key] = value
 | |
|         self.configuration = dict
 | |
|         self.update()
 | |
|         self.current['.class'] = self.klass
 | |
|         self.current['.name'] = self.widget
 | |
| 
 | |
|     class remotewidgetoption: # Mix-in class
 | |
|         def set(self, e=None):
 | |
|             self.current = self.var.get()
 | |
|             try:
 | |
|                 self.dialog.master.send(
 | |
|                         self.dialog.app,
 | |
|                         self.dialog.widget,
 | |
|                         'config',
 | |
|                         '-'+self.option,
 | |
|                         self.current)
 | |
|             except TclError, msg:
 | |
|                 print msg
 | |
|                 self.refresh()
 | |
| 
 | |
|     class booleanoption(remotewidgetoption, BooleanOption): pass
 | |
|     class enumoption(remotewidgetoption, EnumOption): pass
 | |
|     class stringoption(remotewidgetoption, StringOption): pass
 | |
|     class readonlyoption(remotewidgetoption, ReadonlyOption): pass
 | |
| 
 | |
| def test():
 | |
|     import sys
 | |
|     root = Tk()
 | |
|     root.minsize(1, 1)
 | |
|     if sys.argv[1:]:
 | |
|         remotetest(root, sys.argv[1])
 | |
|     else:
 | |
|         frame = Frame(root, name='frame')
 | |
|         frame.pack(expand=1, fill=BOTH)
 | |
|         button = Button(frame, name='button', text='button')
 | |
|         button.pack(expand=1)
 | |
|         canvas = Canvas(frame, name='canvas')
 | |
|         canvas.pack()
 | |
|         fpd = PackDialog(frame)
 | |
|         fwd = WidgetDialog(frame)
 | |
|         bpd = PackDialog(button)
 | |
|         bwd = WidgetDialog(button)
 | |
|         cpd = PackDialog(canvas)
 | |
|         cwd = WidgetDialog(canvas)
 | |
|     root.mainloop()
 | |
| 
 | |
| def remotetest(root, app):
 | |
|     from listtree import listtree
 | |
|     list = listtree(root, app)
 | |
|     list.bind('<Any-Double-1>', opendialogs)
 | |
|     list.app = app                  # Pass it on to handler
 | |
| 
 | |
| def opendialogs(e):
 | |
|     import string
 | |
|     list = e.widget
 | |
|     sel = list.curselection()
 | |
|     for i in sel:
 | |
|         item = list.get(i)
 | |
|         widget = string.split(item)[0]
 | |
|         RemoteWidgetDialog(list, list.app, widget)
 | |
|         if widget == '.': continue
 | |
|         try:
 | |
|             RemotePackDialog(list, list.app, widget)
 | |
|         except TclError, msg:
 | |
|             print msg
 | |
| 
 | |
| test()
 | 
