blob: 6eba09a324ace429dd9b45ea275a14031a9035c8 [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
20 def __init__(self, packdialog, option, varclass):
21 self.packdialog = packdialog
22 self.option = option
23 self.master = packdialog.top
24 self.default, self.klass = packdialog.options[option]
25 self.var = varclass(self.master)
26 self.frame = Frame(self.master,
27 {Pack: {'expand': 0, 'fill': 'x'}})
28 self.label = Label(self.frame,
29 {'text': option + ':',
30 Pack: {'side': 'left'},
31 })
32 self.update()
33
34 def refresh(self):
35 self.packdialog.refresh()
36 self.update()
37
38 def update(self):
39 try:
40 self.current = self.packdialog.current[self.option]
41 except KeyError:
42 self.current = self.default
43 self.var.set(self.current)
44
45 def set(self, e=None):
46 pass
47
48class BooleanOption(Option):
49
50 def __init__(self, packdialog, option):
51 Option.__init__(self, packdialog, option, BooleanVar)
52 self.button = Checkbutton(self.frame,
53 {'text': 'on/off',
54 'onvalue': '1',
55 'offvalue': '0',
56 'variable': self.var,
57 'relief': 'raised',
58 'borderwidth': 2,
59 'command': self.set,
60 Pack: {'side': 'right'},
61 })
62
63class EnumOption(Option):
64
65 def __init__(self, packdialog, option):
66 Option.__init__(self, packdialog, option, StringVar)
67 self.button = Menubutton(self.frame,
68 {'textvariable': self.var,
69 'relief': 'raised',
70 'borderwidth': 2,
71 Pack: {'side': 'right'},
72 })
73 self.menu = Menu(self.button)
74 self.button['menu'] = self.menu
75 for v in self.packdialog.classes[self.klass]:
76 label = v
77 if v == self.default: label = label + ' (default)'
78 self.menu.add_radiobutton(
79 {'label': label,
80 'variable': self.var,
81 'value': v,
82 'command': self.set,
83 })
84
85class StringOption(Option):
86
87 def __init__(self, packdialog, option):
88 Option.__init__(self, packdialog, option, StringVar)
89 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
99class PackOption: # Mix-in class
100
101 def set(self, e=None):
102 self.current = self.var.get()
103 try:
104 Pack.config(self.packdialog.widget,
105 {self.option: self.current})
106 except TclError:
107 self.refresh()
108
109class BooleanPackOption(PackOption, BooleanOption): pass
110class EnumPackOption(PackOption, EnumOption): pass
111class StringPackOption(PackOption, StringOption): pass
112
113class PackDialog:
114
115 options = {
116 'after': (None, 'Widet'),
117 'anchor': ('center', 'Anchor'),
118 'before': (None, 'Widget'),
119 'expand': ('no', 'Boolean'),
120 'fill': ('none', 'Fill'),
121 'in': (None, 'Widget'),
122 'ipadx': (0, 'Pad'),
123 'ipady': (0, 'Pad'),
124 'padx': (0, 'Pad'),
125 'pady': (0, 'Pad'),
126 'side': ('top', 'Side'),
127 }
128
129 classes = {
130 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
131 'Fill': ('none', 'x', 'y', 'both'),
132 'Side': ('top', 'right', 'bottom', 'left'),
133 'Expand': 'boolean',
134 'Pad': 'pixel',
135 'Widget': 'widget',
136 }
137
138 def __init__(self, widget):
139 self.widget = widget
140 self.refresh()
141 self.top = Toplevel(self.widget)
142 self.top.title('Pack: %s' % widget.widgetName)
143 self.top.minsize(1, 1) # XXX
144 self.anchor = EnumPackOption(self, 'anchor')
145 self.side = EnumPackOption(self, 'side')
146 self.fill = EnumPackOption(self, 'fill')
147 self.expand = BooleanPackOption(self, 'expand')
148 self.ipadx = StringPackOption(self, 'ipadx')
149 self.ipady = StringPackOption(self, 'ipady')
150 self.padx = StringPackOption(self, 'padx')
151 self.pady = StringPackOption(self, 'pady')
152 # XXX after, before, in
153
154 def refresh(self):
155 self.current = self.widget.newinfo()
156
157class WidgetOption: # Mix-in class
158
159 def set(self, e=None):
160 self.current = self.var.get()
161 try:
162 self.packdialog.widget[self.option] = self.current
163 except TclError:
164 self.refresh()
165
166class BooleanWidgetOption(WidgetOption, BooleanOption): pass
167class EnumWidgetOption(WidgetOption, EnumOption): pass
168class StringWidgetOption(WidgetOption, StringOption): pass
169
170class WidgetDialog:
171
172 # Universal classes
173 classes = {
174 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
175 'Aspect': 'integer',
176 'Background': 'color',
177 'Bitmap': 'bitmap',
178 'BorderWidth': 'pixel',
179 'CloseEnough': 'double',
180 'Command': 'command',
181 'Confine': 'boolean',
182 'Cursor': 'cursor',
183 'CursorWidth': 'pixel',
184 'DisabledForeground': 'color',
185 'ExportSelection': 'boolean',
186 'Font': 'font',
187 'Foreground': 'color',
188 'From': 'integer',
189 'Geometry': 'geometry',
190 'Height': 'pixel',
191 'InsertWidth': 'time',
192 'Justify': ('left', 'center', 'right'),
193 'Label': 'string',
194 'Length': 'pixel',
195 'MenuName': 'widget',
196 'OffTime': 'time',
197 'OnTime': 'time',
198 'Orient': ('horizontal', 'vertical'),
199 'Pad': 'pixel',
200 'Relief': ('raised', 'sunken', 'flat', 'ridge', 'groove'),
201 'RepeatDelay': 'time',
202 'RepeatInterval': 'time',
203 'ScrollCommand': 'command',
204 'ScrollIncrement': 'pixel',
205 'ScrollRegion': 'rectangle',
206 'ShowValue': 'boolean',
207 'SetGrid': 'boolean',
208 'Sliderforeground': 'color',
209 'SliderLength': 'pixel',
210 'Text': 'string',
211 'TickInterval': 'integer',
212 'To': 'integer',
213 'Underline': 'index',
214 'Variable': 'variable',
215 'Value': 'string',
216 'Width': 'pixel',
217 'Wrap': ('none', 'char', 'word'),
218 }
219
220 # Classes that (may) differ per widget type
221 _tristate = {'State': ('normal', 'active', 'disabled')}
222 _bistate = {'State': ('normal', 'disabled')}
223 addclasses = {
224 'button': _tristate,
225 'radiobutton': _tristate,
226 'checkbutton': _tristate,
227 'entry': _bistate,
228 'text': _bistate,
229 'menubutton': _tristate,
230 'slider': _bistate,
231 }
232
233
234 def __init__(self, widget):
235 self.widget = widget
236 if self.addclasses.has_key(self.widget.widgetName):
237 classes = {}
238 for c in (self.classes,
239 self.addclasses[self.widget.widgetName]):
240 for k in c.keys():
241 classes[k] = c[k]
242 self.classes = classes
243 self.refresh()
244 self.top = Toplevel(self.widget)
245 self.top.title('Widget: %s' % widget.widgetName)
246 self.top.minsize(1, 1)
247 self.choices = {}
248 for k, (d, c) in self.options.items():
249 try:
250 cl = self.classes[c]
251 except KeyError:
252 cl = 'unknown'
253 if type(cl) == TupleType:
254 cl = EnumWidgetOption
255 elif cl == 'boolean':
256 cl = BooleanWidgetOption
257 else:
258 cl = StringWidgetOption
259 self.choices[k] = cl(self, k)
260
261 def refresh(self):
262 self.configuration = self.widget.config()
263 self.current = {}
264 self.options = {}
265 for k, v in self.configuration.items():
266 if len(v) > 4:
267 self.current[k] = v[4]
268 self.options[k] = v[3], v[2] # default, klass
269
270def test():
271 root = Tk()
272 root.minsize(1, 1)
273 frame = Frame(root, {Pack: {'expand': 1, 'fill': 'both'}})
274 button = Button(frame, {'text': 'button',
275 Pack: {'expand': 1}})
276 canvas = Canvas(frame, {Pack: {}})
277 bpd = PackDialog(button)
278 bwd = WidgetDialog(button)
279 cpd = PackDialog(canvas)
280 cwd = WidgetDialog(canvas)
281 root.mainloop()
282
283test()