blob: 05da37d52b9d2a0c7c0ecfe2e2a3dc94658db2f8 [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
15
16from Tkinter import *
17
18class Option:
19
Guido van Rossumb78e03c1994-07-12 15:53:26 +000020 varclass = StringVar # May be overridden
21
22 def __init__(self, dialog, option):
23 self.dialog = dialog
Guido van Rossum3e395be1994-07-12 08:58:25 +000024 self.option = option
Guido van Rossumb78e03c1994-07-12 15:53:26 +000025 self.master = dialog.top
26 self.default, self.klass = dialog.options[option]
27 self.var = self.varclass(self.master)
Guido van Rossum3e395be1994-07-12 08:58:25 +000028 self.frame = Frame(self.master,
29 {Pack: {'expand': 0, 'fill': 'x'}})
30 self.label = Label(self.frame,
31 {'text': option + ':',
32 Pack: {'side': 'left'},
33 })
34 self.update()
Guido van Rossumb78e03c1994-07-12 15:53:26 +000035 self.addoption()
Guido van Rossum3e395be1994-07-12 08:58:25 +000036
37 def refresh(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +000038 self.dialog.refresh()
Guido van Rossum3e395be1994-07-12 08:58:25 +000039 self.update()
40
41 def update(self):
42 try:
Guido van Rossumb78e03c1994-07-12 15:53:26 +000043 self.current = self.dialog.current[self.option]
Guido van Rossum3e395be1994-07-12 08:58:25 +000044 except KeyError:
45 self.current = self.default
46 self.var.set(self.current)
47
Guido van Rossumb78e03c1994-07-12 15:53:26 +000048 def set(self, e=None): # Should be overridden
Guido van Rossum3e395be1994-07-12 08:58:25 +000049 pass
50
51class BooleanOption(Option):
52
Guido van Rossumb78e03c1994-07-12 15:53:26 +000053 varclass = BooleanVar
54
55 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000056 self.button = Checkbutton(self.frame,
57 {'text': 'on/off',
58 'onvalue': '1',
59 'offvalue': '0',
60 'variable': self.var,
61 'relief': 'raised',
62 'borderwidth': 2,
63 'command': self.set,
64 Pack: {'side': 'right'},
65 })
66
67class EnumOption(Option):
68
Guido van Rossumb78e03c1994-07-12 15:53:26 +000069 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000070 self.button = Menubutton(self.frame,
71 {'textvariable': self.var,
72 'relief': 'raised',
73 'borderwidth': 2,
74 Pack: {'side': 'right'},
75 })
76 self.menu = Menu(self.button)
77 self.button['menu'] = self.menu
Guido van Rossumb78e03c1994-07-12 15:53:26 +000078 for v in self.dialog.classes[self.klass]:
Guido van Rossum3e395be1994-07-12 08:58:25 +000079 self.menu.add_radiobutton(
Guido van Rossumb78e03c1994-07-12 15:53:26 +000080 {'label': v,
Guido van Rossum3e395be1994-07-12 08:58:25 +000081 'variable': self.var,
82 'value': v,
83 'command': self.set,
84 })
85
86class StringOption(Option):
87
Guido van Rossumb78e03c1994-07-12 15:53:26 +000088 def addoption(self):
Guido van Rossum3e395be1994-07-12 08:58:25 +000089 self.entry = Entry(self.frame,
90 {'textvariable': self.var,
91 'width': 10,
92 'relief': 'sunken',
93 'borderwidth': 2,
94 Pack: {'side': 'right',
95 'fill': 'x', 'expand': 1},
96 })
97 self.entry.bind('<Return>', self.set)
98
Guido van Rossumb78e03c1994-07-12 15:53:26 +000099class ReadonlyOption(Option):
Guido van Rossum3e395be1994-07-12 08:58:25 +0000100
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000101 def addoption(self):
102 self.label = Label(self.frame,
103 {'textvariable': self.var,
104 Pack: {'side': 'right'}})
Guido van Rossum3e395be1994-07-12 08:58:25 +0000105
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000106class Dialog:
Guido van Rossum3e395be1994-07-12 08:58:25 +0000107
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000108 def __init__(self, master):
109 self.master = master
110 self.refresh()
111 self.top = Toplevel(self.master)
112 self.top.title(self.__class__.__name__)
113 self.top.minsize(1, 1)
114 self.addchoices()
115
116 def addchoices(self):
117 self.choices = {}
118 list = []
119 for k, dc in self.options.items():
120 list.append(k, dc)
121 list.sort()
122 for k, (d, c) in list:
123 try:
124 cl = self.classes[c]
125 except KeyError:
126 cl = 'unknown'
127 if type(cl) == TupleType:
128 cl = self.enumoption
129 elif cl == 'boolean':
130 cl = self.booleanoption
131 elif cl == 'readonly':
132 cl = self.readonlyoption
133 else:
134 cl = self.stringoption
135 self.choices[k] = cl(self, k)
136
137 booleanoption = BooleanOption
138 stringoption = StringOption
139 enumoption = EnumOption
140 readonlyoption = ReadonlyOption
141
142class PackDialog(Dialog):
143
144 def __init__(self, widget):
145 self.widget = widget
146 Dialog.__init__(self, widget)
147
148 def refresh(self):
149 self.current = self.widget.newinfo()
150 self.current['.class'] = self.widget.winfo_class()
Guido van Rossum50f437c1994-07-12 16:37:21 +0000151 self.current['.name'] = self.widget._w
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000152
153 class packoption: # Mix-in class
154 def set(self, e=None):
155 self.current = self.var.get()
156 try:
157 Pack.config(self.dialog.widget,
158 {self.option: self.current})
159 except TclError:
160 self.refresh()
161
162 class booleanoption(packoption, BooleanOption): pass
163 class enumoption(packoption, EnumOption): pass
164 class stringoption(packoption, StringOption): pass
165 class readonlyoption(packoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000166
167 options = {
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000168 '.class': (None, 'Class'),
Guido van Rossum50f437c1994-07-12 16:37:21 +0000169 '.name': (None, 'Name'),
170 'after': (None, 'Widget'),
Guido van Rossum3e395be1994-07-12 08:58:25 +0000171 'anchor': ('center', 'Anchor'),
172 'before': (None, 'Widget'),
173 'expand': ('no', 'Boolean'),
174 'fill': ('none', 'Fill'),
175 'in': (None, 'Widget'),
176 'ipadx': (0, 'Pad'),
177 'ipady': (0, 'Pad'),
178 'padx': (0, 'Pad'),
179 'pady': (0, 'Pad'),
180 'side': ('top', 'Side'),
181 }
182
183 classes = {
184 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000185 'Boolean': 'boolean',
186 'Class': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000187 'Expand': 'boolean',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000188 'Fill': ('none', 'x', 'y', 'both'),
Guido van Rossum50f437c1994-07-12 16:37:21 +0000189 'Name': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000190 'Pad': 'pixel',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000191 'Side': ('top', 'right', 'bottom', 'left'),
192 'Widget': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000193 }
194
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000195class RemotePackDialog(PackDialog):
196
197 def __init__(self, master, app, widget):
198 self.master = master
199 self.app = app
200 self.widget = widget
201 self.refresh()
202 self.top = Toplevel(self.master)
Guido van Rossum50f437c1994-07-12 16:37:21 +0000203 self.top.title(self.app + ' PackDialog')
204 self.top.minsize(1, 1)
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000205 self.addchoices()
206
207 def refresh(self):
208 try:
209 words = self.master.tk.splitlist(
210 self.master.send(self.app,
211 'pack',
212 'newinfo',
213 self.widget))
214 except TclError, msg:
215 print 'send pack newinfo', self.widget, ':', msg
216 return
217 dict = {}
218 for i in range(0, len(words), 2):
219 key = words[i][1:]
220 value = words[i+1]
221 dict[key] = value
222 dict['.class'] = self.master.send(self.app,
223 'winfo',
224 'class',
225 self.widget)
Guido van Rossum50f437c1994-07-12 16:37:21 +0000226 dict['.name'] = self.widget
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000227 self.current = dict
228
229 class remotepackoption: # Mix-in class
230 def set(self, e=None):
231 self.current = self.var.get()
232 try:
233 self.dialog.master.send(
234 self.dialog.app,
235 'pack', 'config', self.dialog.widget,
236 '-'+self.option, self.current)
237 except TclError, msg:
238 print 'send pack config ... :', msg
239 self.refresh()
240
241 class booleanoption(remotepackoption, BooleanOption): pass
242 class enumoption(remotepackoption, EnumOption): pass
243 class stringoption(remotepackoption, StringOption): pass
244 class readonlyoption(remotepackoption, ReadonlyOption): pass
245
246class WidgetDialog(Dialog):
247
Guido van Rossum3e395be1994-07-12 08:58:25 +0000248 def __init__(self, widget):
249 self.widget = widget
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000250 if self.addclasses.has_key(self.widget.widgetName):
251 classes = {}
252 for c in (self.classes,
253 self.addclasses[self.widget.widgetName]):
254 for k in c.keys():
255 classes[k] = c[k]
256 self.classes = classes
257 Dialog.__init__(self, widget)
Guido van Rossum3e395be1994-07-12 08:58:25 +0000258
259 def refresh(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000260 self.configuration = self.widget.config()
Guido van Rossum50f437c1994-07-12 16:37:21 +0000261 self.update()
262 self.current['.class'] = self.widget.winfo_class()
263 self.current['.name'] = self.widget._w
264
265 def update(self):
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000266 self.current = {}
267 self.options = {}
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000268 for k, v in self.configuration.items():
269 if len(v) > 4:
270 self.current[k] = v[4]
271 self.options[k] = v[3], v[2] # default, klass
Guido van Rossum50f437c1994-07-12 16:37:21 +0000272 self.options['.class'] = (None, 'Class')
273 self.options['.name'] = (None, 'Name')
Guido van Rossum3e395be1994-07-12 08:58:25 +0000274
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000275 class widgetoption: # Mix-in class
276 def set(self, e=None):
277 self.current = self.var.get()
278 try:
279 self.dialog.widget[self.option] = self.current
280 except TclError:
281 self.refresh()
Guido van Rossum3e395be1994-07-12 08:58:25 +0000282
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000283 class booleanoption(widgetoption, BooleanOption): pass
284 class enumoption(widgetoption, EnumOption): pass
285 class stringoption(widgetoption, StringOption): pass
286 class readonlyoption(widgetoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000287
288 # Universal classes
289 classes = {
290 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
291 'Aspect': 'integer',
292 'Background': 'color',
293 'Bitmap': 'bitmap',
294 'BorderWidth': 'pixel',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000295 'Class': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000296 'CloseEnough': 'double',
297 'Command': 'command',
298 'Confine': 'boolean',
299 'Cursor': 'cursor',
300 'CursorWidth': 'pixel',
301 'DisabledForeground': 'color',
302 'ExportSelection': 'boolean',
303 'Font': 'font',
304 'Foreground': 'color',
305 'From': 'integer',
306 'Geometry': 'geometry',
307 'Height': 'pixel',
308 'InsertWidth': 'time',
309 'Justify': ('left', 'center', 'right'),
310 'Label': 'string',
311 'Length': 'pixel',
312 'MenuName': 'widget',
Guido van Rossum50f437c1994-07-12 16:37:21 +0000313 'Name': 'readonly',
Guido van Rossum3e395be1994-07-12 08:58:25 +0000314 'OffTime': 'time',
315 'OnTime': 'time',
316 'Orient': ('horizontal', 'vertical'),
317 'Pad': 'pixel',
318 'Relief': ('raised', 'sunken', 'flat', 'ridge', 'groove'),
319 'RepeatDelay': 'time',
320 'RepeatInterval': 'time',
321 'ScrollCommand': 'command',
322 'ScrollIncrement': 'pixel',
323 'ScrollRegion': 'rectangle',
324 'ShowValue': 'boolean',
325 'SetGrid': 'boolean',
326 'Sliderforeground': 'color',
327 'SliderLength': 'pixel',
328 'Text': 'string',
329 'TickInterval': 'integer',
330 'To': 'integer',
331 'Underline': 'index',
332 'Variable': 'variable',
333 'Value': 'string',
334 'Width': 'pixel',
335 'Wrap': ('none', 'char', 'word'),
336 }
337
338 # Classes that (may) differ per widget type
339 _tristate = {'State': ('normal', 'active', 'disabled')}
340 _bistate = {'State': ('normal', 'disabled')}
341 addclasses = {
342 'button': _tristate,
343 'radiobutton': _tristate,
344 'checkbutton': _tristate,
345 'entry': _bistate,
346 'text': _bistate,
347 'menubutton': _tristate,
348 'slider': _bistate,
349 }
Guido van Rossum50f437c1994-07-12 16:37:21 +0000350
351class RemoteWidgetDialog(WidgetDialog):
352
353 def __init__(self, master, app, widget):
354 self.master = master
355 self.app = app
356 self.widget = widget
357 self.refresh()
358 self.top = Toplevel(self.master)
359 self.top.title(self.app + ' WidgetDialog')
360 self.top.minsize(1, 1)
361 self.addchoices()
362
363 def refresh(self):
364 try:
365 items = self.master.tk.splitlist(
366 self.master.send(self.app,
367 self.widget,
368 'config'))
369 except TclError, msg:
370 print 'send widget config', self.widget, ':', msg
371 return
372 dict = {}
373 for item in items:
374 words = self.master.tk.splitlist(item)
375 key = words[0][1:]
376 value = (key,) + words[1:]
377 dict[key] = value
378 self.configuration = dict
379 self.update()
380 self.current['.class'] = self.master.send(self.app,
381 'winfo',
382 'class',
383 self.widget)
384 self.current['.name'] = self.widget
385
386 class remotewidgetoption: # Mix-in class
387 def set(self, e=None):
388 self.current = self.var.get()
389 try:
390 self.dialog.master.send(
391 self.dialog.app,
392 self.dialog.widget,
393 'config',
394 '-'+self.option,
395 self.current)
396 except TclError, msg:
397 print 'send widget config :', msg
398 self.refresh()
399
400 class booleanoption(remotewidgetoption, BooleanOption): pass
401 class enumoption(remotewidgetoption, EnumOption): pass
402 class stringoption(remotewidgetoption, StringOption): pass
403 class readonlyoption(remotewidgetoption, ReadonlyOption): pass
Guido van Rossum3e395be1994-07-12 08:58:25 +0000404
Guido van Rossum3e395be1994-07-12 08:58:25 +0000405def test():
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000406 import sys
Guido van Rossum3e395be1994-07-12 08:58:25 +0000407 root = Tk()
408 root.minsize(1, 1)
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000409 if sys.argv[2:]:
410 pd = RemotePackDialog(root, sys.argv[1], sys.argv[2])
Guido van Rossum50f437c1994-07-12 16:37:21 +0000411 wd = RemoteWidgetDialog(root, sys.argv[1], sys.argv[2])
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000412 else:
Guido van Rossum50f437c1994-07-12 16:37:21 +0000413 frame = Frame(root, {'name': 'frame',
414 Pack: {'expand': 1, 'fill': 'both'},
415 })
416 button = Button(frame, {'name': 'button',
417 'text': 'button',
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000418 Pack: {'expand': 1}})
Guido van Rossum50f437c1994-07-12 16:37:21 +0000419 canvas = Canvas(frame, {'name': 'canvas',
420 Pack: {}})
421 fpd = PackDialog(frame)
422 fwd = WidgetDialog(frame)
Guido van Rossumb78e03c1994-07-12 15:53:26 +0000423 bpd = PackDialog(button)
424 bwd = WidgetDialog(button)
425 cpd = PackDialog(canvas)
426 cwd = WidgetDialog(canvas)
Guido van Rossum3e395be1994-07-12 08:58:25 +0000427 root.mainloop()
428
429test()