Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 1 | |
| 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 | |
| 16 | from Tkinter import * |
| 17 | |
| 18 | class Option: |
| 19 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 20 | varclass = StringVar # May be overridden |
| 21 | |
| 22 | def __init__(self, dialog, option): |
| 23 | self.dialog = dialog |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 24 | self.option = option |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 25 | self.master = dialog.top |
| 26 | self.default, self.klass = dialog.options[option] |
| 27 | self.var = self.varclass(self.master) |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 28 | 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 Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 35 | self.addoption() |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 36 | |
| 37 | def refresh(self): |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 38 | self.dialog.refresh() |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 39 | self.update() |
| 40 | |
| 41 | def update(self): |
| 42 | try: |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 43 | self.current = self.dialog.current[self.option] |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 44 | except KeyError: |
| 45 | self.current = self.default |
| 46 | self.var.set(self.current) |
| 47 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 48 | def set(self, e=None): # Should be overridden |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 49 | pass |
| 50 | |
| 51 | class BooleanOption(Option): |
| 52 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 53 | varclass = BooleanVar |
| 54 | |
| 55 | def addoption(self): |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 56 | 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 | |
| 67 | class EnumOption(Option): |
| 68 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 69 | def addoption(self): |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 70 | 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 Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 78 | for v in self.dialog.classes[self.klass]: |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 79 | self.menu.add_radiobutton( |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 80 | {'label': v, |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 81 | 'variable': self.var, |
| 82 | 'value': v, |
| 83 | 'command': self.set, |
| 84 | }) |
| 85 | |
| 86 | class StringOption(Option): |
| 87 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 88 | def addoption(self): |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 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 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 99 | class ReadonlyOption(Option): |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 100 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 101 | def addoption(self): |
| 102 | self.label = Label(self.frame, |
| 103 | {'textvariable': self.var, |
| 104 | Pack: {'side': 'right'}}) |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 105 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 106 | class Dialog: |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 107 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 108 | 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 | |
| 142 | class 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() |
| 151 | |
| 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 Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 165 | |
| 166 | options = { |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 167 | '.class': (None, 'Class'), |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 168 | 'after': (None, 'Widet'), |
| 169 | 'anchor': ('center', 'Anchor'), |
| 170 | 'before': (None, 'Widget'), |
| 171 | 'expand': ('no', 'Boolean'), |
| 172 | 'fill': ('none', 'Fill'), |
| 173 | 'in': (None, 'Widget'), |
| 174 | 'ipadx': (0, 'Pad'), |
| 175 | 'ipady': (0, 'Pad'), |
| 176 | 'padx': (0, 'Pad'), |
| 177 | 'pady': (0, 'Pad'), |
| 178 | 'side': ('top', 'Side'), |
| 179 | } |
| 180 | |
| 181 | classes = { |
| 182 | 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'), |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 183 | 'Boolean': 'boolean', |
| 184 | 'Class': 'readonly', |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 185 | 'Expand': 'boolean', |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 186 | 'Fill': ('none', 'x', 'y', 'both'), |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 187 | 'Pad': 'pixel', |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 188 | 'Side': ('top', 'right', 'bottom', 'left'), |
| 189 | 'Widget': 'readonly', |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 190 | } |
| 191 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 192 | class RemotePackDialog(PackDialog): |
| 193 | |
| 194 | def __init__(self, master, app, widget): |
| 195 | self.master = master |
| 196 | self.app = app |
| 197 | self.widget = widget |
| 198 | self.refresh() |
| 199 | self.top = Toplevel(self.master) |
| 200 | self.top.title('Remote %s Pack: %s' % (self.app, self.widget)) |
| 201 | self.top.minsize(1, 1) # XXX |
| 202 | self.addchoices() |
| 203 | |
| 204 | def refresh(self): |
| 205 | try: |
| 206 | words = self.master.tk.splitlist( |
| 207 | self.master.send(self.app, |
| 208 | 'pack', |
| 209 | 'newinfo', |
| 210 | self.widget)) |
| 211 | except TclError, msg: |
| 212 | print 'send pack newinfo', self.widget, ':', msg |
| 213 | return |
| 214 | dict = {} |
| 215 | for i in range(0, len(words), 2): |
| 216 | key = words[i][1:] |
| 217 | value = words[i+1] |
| 218 | dict[key] = value |
| 219 | dict['.class'] = self.master.send(self.app, |
| 220 | 'winfo', |
| 221 | 'class', |
| 222 | self.widget) |
| 223 | self.current = dict |
| 224 | |
| 225 | class remotepackoption: # Mix-in class |
| 226 | def set(self, e=None): |
| 227 | self.current = self.var.get() |
| 228 | try: |
| 229 | self.dialog.master.send( |
| 230 | self.dialog.app, |
| 231 | 'pack', 'config', self.dialog.widget, |
| 232 | '-'+self.option, self.current) |
| 233 | except TclError, msg: |
| 234 | print 'send pack config ... :', msg |
| 235 | self.refresh() |
| 236 | |
| 237 | class booleanoption(remotepackoption, BooleanOption): pass |
| 238 | class enumoption(remotepackoption, EnumOption): pass |
| 239 | class stringoption(remotepackoption, StringOption): pass |
| 240 | class readonlyoption(remotepackoption, ReadonlyOption): pass |
| 241 | |
| 242 | class WidgetDialog(Dialog): |
| 243 | |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 244 | def __init__(self, widget): |
| 245 | self.widget = widget |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 246 | if self.addclasses.has_key(self.widget.widgetName): |
| 247 | classes = {} |
| 248 | for c in (self.classes, |
| 249 | self.addclasses[self.widget.widgetName]): |
| 250 | for k in c.keys(): |
| 251 | classes[k] = c[k] |
| 252 | self.classes = classes |
| 253 | Dialog.__init__(self, widget) |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 254 | |
| 255 | def refresh(self): |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 256 | self.configuration = self.widget.config() |
| 257 | self.current = {} |
| 258 | self.options = {} |
Guido van Rossum | 28bb652 | 1994-07-12 15:55:43 +0000 | [diff] [blame] | 259 | self.options['.class'] = (None, 'Class') |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 260 | self.current['.class'] = self.widget.winfo_class() |
| 261 | for k, v in self.configuration.items(): |
| 262 | if len(v) > 4: |
| 263 | self.current[k] = v[4] |
| 264 | self.options[k] = v[3], v[2] # default, klass |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 265 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 266 | class widgetoption: # Mix-in class |
| 267 | def set(self, e=None): |
| 268 | self.current = self.var.get() |
| 269 | try: |
| 270 | self.dialog.widget[self.option] = self.current |
| 271 | except TclError: |
| 272 | self.refresh() |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 273 | |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 274 | class booleanoption(widgetoption, BooleanOption): pass |
| 275 | class enumoption(widgetoption, EnumOption): pass |
| 276 | class stringoption(widgetoption, StringOption): pass |
| 277 | class readonlyoption(widgetoption, ReadonlyOption): pass |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 278 | |
| 279 | # Universal classes |
| 280 | classes = { |
| 281 | 'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'), |
| 282 | 'Aspect': 'integer', |
| 283 | 'Background': 'color', |
| 284 | 'Bitmap': 'bitmap', |
| 285 | 'BorderWidth': 'pixel', |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 286 | 'Class': 'readonly', |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 287 | 'CloseEnough': 'double', |
| 288 | 'Command': 'command', |
| 289 | 'Confine': 'boolean', |
| 290 | 'Cursor': 'cursor', |
| 291 | 'CursorWidth': 'pixel', |
| 292 | 'DisabledForeground': 'color', |
| 293 | 'ExportSelection': 'boolean', |
| 294 | 'Font': 'font', |
| 295 | 'Foreground': 'color', |
| 296 | 'From': 'integer', |
| 297 | 'Geometry': 'geometry', |
| 298 | 'Height': 'pixel', |
| 299 | 'InsertWidth': 'time', |
| 300 | 'Justify': ('left', 'center', 'right'), |
| 301 | 'Label': 'string', |
| 302 | 'Length': 'pixel', |
| 303 | 'MenuName': 'widget', |
| 304 | 'OffTime': 'time', |
| 305 | 'OnTime': 'time', |
| 306 | 'Orient': ('horizontal', 'vertical'), |
| 307 | 'Pad': 'pixel', |
| 308 | 'Relief': ('raised', 'sunken', 'flat', 'ridge', 'groove'), |
| 309 | 'RepeatDelay': 'time', |
| 310 | 'RepeatInterval': 'time', |
| 311 | 'ScrollCommand': 'command', |
| 312 | 'ScrollIncrement': 'pixel', |
| 313 | 'ScrollRegion': 'rectangle', |
| 314 | 'ShowValue': 'boolean', |
| 315 | 'SetGrid': 'boolean', |
| 316 | 'Sliderforeground': 'color', |
| 317 | 'SliderLength': 'pixel', |
| 318 | 'Text': 'string', |
| 319 | 'TickInterval': 'integer', |
| 320 | 'To': 'integer', |
| 321 | 'Underline': 'index', |
| 322 | 'Variable': 'variable', |
| 323 | 'Value': 'string', |
| 324 | 'Width': 'pixel', |
| 325 | 'Wrap': ('none', 'char', 'word'), |
| 326 | } |
| 327 | |
| 328 | # Classes that (may) differ per widget type |
| 329 | _tristate = {'State': ('normal', 'active', 'disabled')} |
| 330 | _bistate = {'State': ('normal', 'disabled')} |
| 331 | addclasses = { |
| 332 | 'button': _tristate, |
| 333 | 'radiobutton': _tristate, |
| 334 | 'checkbutton': _tristate, |
| 335 | 'entry': _bistate, |
| 336 | 'text': _bistate, |
| 337 | 'menubutton': _tristate, |
| 338 | 'slider': _bistate, |
| 339 | } |
| 340 | |
| 341 | |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 342 | def test(): |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 343 | import sys |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 344 | root = Tk() |
| 345 | root.minsize(1, 1) |
Guido van Rossum | b78e03c | 1994-07-12 15:53:26 +0000 | [diff] [blame] | 346 | if sys.argv[2:]: |
| 347 | pd = RemotePackDialog(root, sys.argv[1], sys.argv[2]) |
| 348 | else: |
| 349 | frame = Frame(root, {Pack: {'expand': 1, 'fill': 'both'}}) |
| 350 | button = Button(frame, {'text': 'button', |
| 351 | Pack: {'expand': 1}}) |
| 352 | canvas = Canvas(frame, {Pack: {}}) |
| 353 | bpd = PackDialog(button) |
| 354 | bwd = WidgetDialog(button) |
| 355 | cpd = PackDialog(canvas) |
| 356 | cwd = WidgetDialog(canvas) |
Guido van Rossum | 3e395be | 1994-07-12 08:58:25 +0000 | [diff] [blame] | 357 | root.mainloop() |
| 358 | |
| 359 | test() |