blob: 496aae1c9cba51ce6f716d97a0b088587d291ec4 [file] [log] [blame]
Guido van Rossum3e395be1994-07-12 08:58:25 +00001
2# The options of a widget are described by the following attributes
3# of the Pack and Widget dialogs:
4#
5# Dialog.current: {name: value}
6# -- changes during Widget's lifetime
7#
8# Dialog.options: {name: (default, klass)}
9# -- depends on widget class only
10#
11# Dialog.classes: {klass: (v0, v1, v2, ...) | 'boolean' | 'other'}
12# -- totally static, though different between PackDialog and WidgetDialog
13# (but even that could be unified)
14
Guido van Rossum3e395be1994-07-12 08:58:25 +000015from Tkinter import *
16
17class Option:
18
Guido van Rossumb78e03c1994-07-12 15:53:26 +000019 varclass = StringVar # May be overridden
20
21 def __init__(self, dialog, option):
22 self.dialog = dialog
Guido van Rossum3e395be1994-07-12 08:58:25 +000023 self.option = option
Guido van Rossumb78e03c1994-07-12 15:53:26 +000024 self.master = dialog.top
25 self.default, self.klass = dialog.options[option]
26 self.var = self.varclass(self.master)
Guido van Rossum3e395be1994-07-12 08:58:25 +000027 self.frame = Frame(self.master,
28 {Pack: {'expand': 0, 'fill': 'x'}})
29 self.label = Label(self.frame,
30 {'text': option + ':',
31 Pack: {'side': 'left'},
32 })
33 self.update()
Guido van Rossumb78e03c1994-07-12 15:53:26 +000034 self.addoption()
Guido van Rossum3e395be1994-07-12 08:58:25 +000035
36 def refresh(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +000037 self.dialog.refresh()
Guido van Rossum3e395be1994-07-12 08:58:25 +000038 self.update()
39
40 def update(self):
41 try:
Guido van Rossumb78e03c1994-07-12 15:53:26 +000042 self.current = self.dialog.current[self.option]
Guido van Rossum3e395be1994-07-12 08:58:25 +000043 except KeyError:
44 self.current = self.default
45 self.var.set(self.current)
46
Guido van Rossumb78e03c1994-07-12 15:53:26 +000047 def set(self, e=None): # Should be overridden
Guido van Rossum3e395be1994-07-12 08:58:25 +000048 pass
49
50class BooleanOption(Option):
51
Guido van Rossumb78e03c1994-07-12 15:53:26 +000052 varclass = BooleanVar
53
54 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000055 self.button = Checkbutton(self.frame,
56 {'text': 'on/off',
57 'onvalue': '1',
58 'offvalue': '0',
59 'variable': self.var,
60 'relief': 'raised',
61 'borderwidth': 2,
62 'command': self.set,
63 Pack: {'side': 'right'},
64 })
65
66class EnumOption(Option):
67
Guido van Rossumb78e03c1994-07-12 15:53:26 +000068 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000069 self.button = Menubutton(self.frame,
70 {'textvariable': self.var,
71 'relief': 'raised',
72 'borderwidth': 2,
73 Pack: {'side': 'right'},
74 })
75 self.menu = Menu(self.button)
76 self.button['menu'] = self.menu
Guido van Rossumb78e03c1994-07-12 15:53:26 +000077 for v in self.dialog.classes[self.klass]:
Guido van Rossum3e395be1994-07-12 08:58:25 +000078 self.menu.add_radiobutton(
Guido van Rossumb78e03c1994-07-12 15:53:26 +000079 {'label': v,
Guido van Rossum3e395be1994-07-12 08:58:25 +000080 'variable': self.var,
81 'value': v,
82 'command': self.set,
83 })
84
85class StringOption(Option):
86
Guido van Rossumb78e03c1994-07-12 15:53:26 +000087 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000088 self.entry = Entry(self.frame,
89 {'textvariable': self.var,
90 'width': 10,
91 'relief': 'sunken',
92 'borderwidth': 2,
93 Pack: {'side': 'right',
94 'fill': 'x', 'expand': 1},
95 })
96 self.entry.bind('<Return>', self.set)
97
Guido van Rossumb78e03c1994-07-12 15:53:26 +000098class ReadonlyOption(Option):
Guido van Rossum3e395be1994-07-12 08:58:25 +000099
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000100 def addoption(self):
101 self.label = Label(self.frame,
102 {'textvariable': self.var,
103 Pack: {'side': 'right'}})
Guido van Rossum3e395be1994-07-12 08:58:25 +0000104
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000105class Dialog:
Guido van Rossum3e395be1994-07-12 08:58:25 +0000106
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000107 def __init__(self, master):
108 self.master = master
109 self.refresh()
110 self.top = Toplevel(self.master)
111 self.top.title(self.__class__.__name__)
112 self.top.minsize(1, 1)
113 self.addchoices()
114
115 def addchoices(self):
116 self.choices = {}
117 list = []
118 for k, dc in self.options.items():
119 list.append(k, dc)
120 list.sort()
121 for k, (d, c) in list:
122 try:
123 cl = self.classes[c]
124 except KeyError:
125 cl = 'unknown'
126 if type(cl) == TupleType:
127 cl = self.enumoption
128 elif cl == 'boolean':
129 cl = self.booleanoption
130 elif cl == 'readonly':
131 cl = self.readonlyoption
132 else:
133 cl = self.stringoption
134 self.choices[k] = cl(self, k)
135
136 booleanoption = BooleanOption
137 stringoption = StringOption
138 enumoption = EnumOption
139 readonlyoption = ReadonlyOption
140
141class PackDialog(Dialog):
142
143 def __init__(self, widget):
144 self.widget = widget
145 Dialog.__init__(self, widget)
146
147 def refresh(self):
148 self.current = self.widget.newinfo()
149 self.current['.class'] = self.widget.winfo_class()
Guido van Rossum50f437c1994-07-12 16:37:21 +0000150 self.current['.name'] = self.widget._w
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000151
152 class packoption: # Mix-in class
153 def set(self, e=None):
154 self.current = self.var.get()
155 try:
156 Pack.config(self.dialog.widget,
157 {self.option: self.current})
158 except TclError:
159 self.refresh()
160
161 class booleanoption(packoption, BooleanOption): pass
162 class enumoption(packoption, EnumOption): pass
163 class stringoption(packoption, StringOption): pass
164 class readonlyoption(packoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000165
166 options = {
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000167 '.class': (None, 'Class'),
Guido van Rossum50f437c1994-07-12 16:37:21 +0000168 '.name': (None, 'Name'),
169 'after': (None, 'Widget'),
Guido van Rossum3e395be1994-07-12 08:58:25 +0000170 'anchor': ('center', 'Anchor'),
171 'before': (None, 'Widget'),
172 'expand': ('no', 'Boolean'),
173 'fill': ('none', 'Fill'),
174 'in': (None, 'Widget'),
175 'ipadx': (0, 'Pad'),
176 'ipady': (0, 'Pad'),
177 'padx': (0, 'Pad'),
178 'pady': (0, 'Pad'),
179 'side': ('top', 'Side'),
180 }
181
182 classes = {
183 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000184 'Boolean': 'boolean',
185 'Class': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000186 'Expand': 'boolean',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000187 'Fill': ('none', 'x', 'y', 'both'),
Guido van Rossum50f437c1994-07-12 16:37:21 +0000188 'Name': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000189 'Pad': 'pixel',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000190 'Side': ('top', 'right', 'bottom', 'left'),
191 'Widget': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000192 }
193
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000194class RemotePackDialog(PackDialog):
195
196 def __init__(self, master, app, widget):
197 self.master = master
198 self.app = app
199 self.widget = widget
200 self.refresh()
201 self.top = Toplevel(self.master)
Guido van Rossum50f437c1994-07-12 16:37:21 +0000202 self.top.title(self.app + ' PackDialog')
203 self.top.minsize(1, 1)
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000204 self.addchoices()
205
206 def refresh(self):
207 try:
208 words = self.master.tk.splitlist(
209 self.master.send(self.app,
210 'pack',
211 'newinfo',
212 self.widget))
213 except TclError, msg:
214 print 'send pack newinfo', self.widget, ':', msg
215 return
216 dict = {}
217 for i in range(0, len(words), 2):
218 key = words[i][1:]
219 value = words[i+1]
220 dict[key] = value
221 dict['.class'] = self.master.send(self.app,
222 'winfo',
223 'class',
224 self.widget)
Guido van Rossum50f437c1994-07-12 16:37:21 +0000225 dict['.name'] = self.widget
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000226 self.current = dict
227
228 class remotepackoption: # Mix-in class
229 def set(self, e=None):
230 self.current = self.var.get()
231 try:
232 self.dialog.master.send(
233 self.dialog.app,
234 'pack', 'config', self.dialog.widget,
235 '-'+self.option, self.current)
236 except TclError, msg:
237 print 'send pack config ... :', msg
238 self.refresh()
239
240 class booleanoption(remotepackoption, BooleanOption): pass
241 class enumoption(remotepackoption, EnumOption): pass
242 class stringoption(remotepackoption, StringOption): pass
243 class readonlyoption(remotepackoption, ReadonlyOption): pass
244
245class WidgetDialog(Dialog):
246
Guido van Rossum3e395be1994-07-12 08:58:25 +0000247 def __init__(self, widget):
248 self.widget = widget
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000249 if self.addclasses.has_key(self.widget.widgetName):
250 classes = {}
251 for c in (self.classes,
252 self.addclasses[self.widget.widgetName]):
253 for k in c.keys():
254 classes[k] = c[k]
255 self.classes = classes
256 Dialog.__init__(self, widget)
Guido van Rossum3e395be1994-07-12 08:58:25 +0000257
258 def refresh(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000259 self.configuration = self.widget.config()
Guido van Rossum50f437c1994-07-12 16:37:21 +0000260 self.update()
261 self.current['.class'] = self.widget.winfo_class()
262 self.current['.name'] = self.widget._w
263
264 def update(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000265 self.current = {}
266 self.options = {}
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000267 for k, v in self.configuration.items():
268 if len(v) > 4:
269 self.current[k] = v[4]
270 self.options[k] = v[3], v[2] # default, klass
Guido van Rossum50f437c1994-07-12 16:37:21 +0000271 self.options['.class'] = (None, 'Class')
272 self.options['.name'] = (None, 'Name')
Guido van Rossum3e395be1994-07-12 08:58:25 +0000273
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000274 class widgetoption: # Mix-in class
275 def set(self, e=None):
276 self.current = self.var.get()
277 try:
278 self.dialog.widget[self.option] = self.current
279 except TclError:
280 self.refresh()
Guido van Rossum3e395be1994-07-12 08:58:25 +0000281
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000282 class booleanoption(widgetoption, BooleanOption): pass
283 class enumoption(widgetoption, EnumOption): pass
284 class stringoption(widgetoption, StringOption): pass
285 class readonlyoption(widgetoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000286
287 # Universal classes
288 classes = {
289 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
290 'Aspect': 'integer',
291 'Background': 'color',
292 'Bitmap': 'bitmap',
293 'BorderWidth': 'pixel',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000294 'Class': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000295 'CloseEnough': 'double',
296 'Command': 'command',
297 'Confine': 'boolean',
298 'Cursor': 'cursor',
299 'CursorWidth': 'pixel',
300 'DisabledForeground': 'color',
301 'ExportSelection': 'boolean',
302 'Font': 'font',
303 'Foreground': 'color',
304 'From': 'integer',
305 'Geometry': 'geometry',
306 'Height': 'pixel',
307 'InsertWidth': 'time',
308 'Justify': ('left', 'center', 'right'),
309 'Label': 'string',
310 'Length': 'pixel',
311 'MenuName': 'widget',
Guido van Rossum50f437c1994-07-12 16:37:21 +0000312 'Name': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000313 'OffTime': 'time',
314 'OnTime': 'time',
315 'Orient': ('horizontal', 'vertical'),
316 'Pad': 'pixel',
317 'Relief': ('raised', 'sunken', 'flat', 'ridge', 'groove'),
318 'RepeatDelay': 'time',
319 'RepeatInterval': 'time',
320 'ScrollCommand': 'command',
321 'ScrollIncrement': 'pixel',
322 'ScrollRegion': 'rectangle',
323 'ShowValue': 'boolean',
324 'SetGrid': 'boolean',
325 'Sliderforeground': 'color',
326 'SliderLength': 'pixel',
327 'Text': 'string',
328 'TickInterval': 'integer',
329 'To': 'integer',
330 'Underline': 'index',
331 'Variable': 'variable',
332 'Value': 'string',
333 'Width': 'pixel',
334 'Wrap': ('none', 'char', 'word'),
335 }
336
337 # Classes that (may) differ per widget type
338 _tristate = {'State': ('normal', 'active', 'disabled')}
339 _bistate = {'State': ('normal', 'disabled')}
340 addclasses = {
341 'button': _tristate,
342 'radiobutton': _tristate,
343 'checkbutton': _tristate,
344 'entry': _bistate,
345 'text': _bistate,
346 'menubutton': _tristate,
347 'slider': _bistate,
348 }
Guido van Rossum50f437c1994-07-12 16:37:21 +0000349
350class RemoteWidgetDialog(WidgetDialog):
351
352 def __init__(self, master, app, widget):
353 self.master = master
354 self.app = app
355 self.widget = widget
356 self.refresh()
357 self.top = Toplevel(self.master)
358 self.top.title(self.app + ' WidgetDialog')
359 self.top.minsize(1, 1)
360 self.addchoices()
361
362 def refresh(self):
363 try:
364 items = self.master.tk.splitlist(
365 self.master.send(self.app,
366 self.widget,
367 'config'))
368 except TclError, msg:
369 print 'send widget config', self.widget, ':', msg
370 return
371 dict = {}
372 for item in items:
373 words = self.master.tk.splitlist(item)
374 key = words[0][1:]
375 value = (key,) + words[1:]
376 dict[key] = value
377 self.configuration = dict
378 self.update()
379 self.current['.class'] = self.master.send(self.app,
380 'winfo',
381 'class',
382 self.widget)
383 self.current['.name'] = self.widget
384
385 class remotewidgetoption: # Mix-in class
386 def set(self, e=None):
387 self.current = self.var.get()
388 try:
389 self.dialog.master.send(
390 self.dialog.app,
391 self.dialog.widget,
392 'config',
393 '-'+self.option,
394 self.current)
395 except TclError, msg:
396 print 'send widget config :', msg
397 self.refresh()
398
399 class booleanoption(remotewidgetoption, BooleanOption): pass
400 class enumoption(remotewidgetoption, EnumOption): pass
401 class stringoption(remotewidgetoption, StringOption): pass
402 class readonlyoption(remotewidgetoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000403
Guido van Rossum3e395be1994-07-12 08:58:25 +0000404def test():
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000405 import sys
Guido van Rossum3e395be1994-07-12 08:58:25 +0000406 root = Tk()
407 root.minsize(1, 1)
Guido van Rossume7e8d1e1994-07-13 12:56:10 +0000408 if sys.argv[1:]:
409 remotetest(root, sys.argv[1])
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000410 else:
Guido van Rossum50f437c1994-07-12 16:37:21 +0000411 frame = Frame(root, {'name': 'frame',
412 Pack: {'expand': 1, 'fill': 'both'},
413 })
414 button = Button(frame, {'name': 'button',
415 'text': 'button',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000416 Pack: {'expand': 1}})
Guido van Rossum50f437c1994-07-12 16:37:21 +0000417 canvas = Canvas(frame, {'name': 'canvas',
418 Pack: {}})
419 fpd = PackDialog(frame)
420 fwd = WidgetDialog(frame)
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000421 bpd = PackDialog(button)
422 bwd = WidgetDialog(button)
423 cpd = PackDialog(canvas)
424 cwd = WidgetDialog(canvas)
Guido van Rossum3e395be1994-07-12 08:58:25 +0000425 root.mainloop()
426
Guido van Rossume7e8d1e1994-07-13 12:56:10 +0000427def remotetest(root, app):
428 from listtree import listtree
429 list = listtree(root, app)
430 list.bind('<Any-Double-1>', opendialogs)
431 list.app = app # Pass it on to handler
432
433def opendialogs(e):
434 import string
435 list = e.widget
436 sel = list.curselection()
437 for i in sel:
438 item = list.get(i)
439 widget = string.split(item)[0]
440 RemoteWidgetDialog(list, list.app, widget)
441 if widget == '.': continue
442 try:
443 RemotePackDialog(list, list.app, widget)
444 except TclError, msg:
445 print msg
446
Guido van Rossum3e395be1994-07-12 08:58:25 +0000447test()