mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			463 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			463 lines
		
	
	
	
		
			11 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,
 | |
| 				   {Pack: {'expand': 0, 'fill': 'x'}})
 | |
| 		self.label = Label(self.frame,
 | |
| 				   {'text': option + ':',
 | |
| 				    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,
 | |
| 					  Pack: {'side': 'right'},
 | |
| 					  })
 | |
| 
 | |
| class EnumOption(Option):
 | |
| 
 | |
| 	def addoption(self):
 | |
| 		self.button = Menubutton(self.frame,
 | |
| 					 {'textvariable': self.var,
 | |
| 					  'relief': 'raised',
 | |
| 					  'borderwidth': 2,
 | |
| 					  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,
 | |
| 				    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',
 | |
| 				    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.newinfo()
 | |
| 		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:
 | |
| 				Pack.config(self.dialog.widget,
 | |
| 					    {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',
 | |
| 						 'newinfo',
 | |
| 						 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',
 | |
| 				     Pack: {'expand': 1, 'fill': 'both'},
 | |
| 				     })
 | |
| 		button = Button(frame, {'name': 'button',
 | |
| 					'text': 'button',
 | |
| 					Pack: {'expand': 1}})
 | |
| 		canvas = Canvas(frame, {'name': '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()
 | 
