home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / tkinter / guido / AttrDialog.py next >
Text File  |  1996-07-30  |  11KB  |  453 lines

  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. from Tkinter import *
  16.  
  17. class Option:
  18.  
  19.     varclass = StringVar        # May be overridden
  20.  
  21.     def __init__(self, dialog, option):
  22.         self.dialog = dialog
  23.         self.option = option
  24.         self.master = dialog.top
  25.         self.default, self.klass = dialog.options[option]
  26.         self.var = self.varclass(self.master)
  27.         self.frame = Frame(self.master)
  28.         self.frame.pack(fill=X)
  29.         self.label = Label(self.frame, text=(option + ":"))
  30.         self.label.pack(side=LEFT)
  31.         self.update()
  32.         self.addoption()
  33.  
  34.     def refresh(self):
  35.         self.dialog.refresh()
  36.         self.update()
  37.  
  38.     def update(self):
  39.         try:
  40.             self.current = self.dialog.current[self.option]
  41.         except KeyError:
  42.             self.current = self.default
  43.         self.var.set(self.current)
  44.  
  45.     def set(self, e=None):        # Should be overridden
  46.         pass
  47.  
  48. class BooleanOption(Option):
  49.  
  50.     varclass = BooleanVar
  51.  
  52.     def addoption(self):
  53.         self.button = Checkbutton(self.frame,
  54.                      text='on/off',
  55.                      onvalue=1,
  56.                      offvalue=0,
  57.                      variable=self.var,
  58.                      relief=RAISED,
  59.                      borderwidth=2,
  60.                      command=self.set)
  61.         self.button.pack(side=RIGHT)
  62.  
  63. class EnumOption(Option):
  64.  
  65.     def addoption(self):
  66.         self.button = Menubutton(self.frame,
  67.                      textvariable=self.var,
  68.                      relief=RAISED, borderwidth=2)
  69.         self.button.pack(side=RIGHT)
  70.         self.menu = Menu(self.button)
  71.         self.button['menu'] = self.menu
  72.         for v in self.dialog.classes[self.klass]:
  73.             self.menu.add_radiobutton(
  74.                 label=v,
  75.                 variable=self.var,
  76.                 value=v,
  77.                 command=self.set)
  78.  
  79. class StringOption(Option):
  80.  
  81.     def addoption(self):
  82.         self.entry = Entry(self.frame,
  83.                    textvariable=self.var,
  84.                    width=10,
  85.                    relief=SUNKEN,
  86.                    borderwidth=2)
  87.         self.entry.pack(side=RIGHT, fill=X, expand=1)
  88.         self.entry.bind('<Return>', self.set)
  89.  
  90. class ReadonlyOption(Option):
  91.  
  92.     def addoption(self):
  93.         self.label = Label(self.frame, textvariable=self.var,
  94.                    anchor=E)
  95.         self.label.pack(side=RIGHT)
  96.  
  97. class Dialog:
  98.  
  99.     def __init__(self, master):
  100.         self.master = master
  101.         self.fixclasses()
  102.         self.refresh()
  103.         self.top = Toplevel(self.master)
  104.         self.top.title(self.__class__.__name__)
  105.         self.top.minsize(1, 1)
  106.         self.addchoices()
  107.  
  108.     def refresh(self): pass        # Must override
  109.  
  110.     def fixclasses(self): pass    # May override
  111.  
  112.     def addchoices(self):
  113.         self.choices = {}
  114.         list = []
  115.         for k, dc in self.options.items():
  116.             list.append(k, dc)
  117.         list.sort()
  118.         for k, (d, c) in list:
  119.             try:
  120.                 cl = self.classes[c]
  121.             except KeyError:
  122.                 cl = 'unknown'
  123.             if type(cl) == TupleType:
  124.                 cl = self.enumoption
  125.             elif cl == 'boolean':
  126.                 cl = self.booleanoption
  127.             elif cl == 'readonly':
  128.                 cl = self.readonlyoption
  129.             else:
  130.                 cl = self.stringoption
  131.             self.choices[k] = cl(self, k)
  132.  
  133.     # Must override:
  134.     options = {}
  135.     classes = {}
  136.  
  137.     # May override:
  138.     booleanoption = BooleanOption
  139.     stringoption = StringOption
  140.     enumoption = EnumOption
  141.     readonlyoption = ReadonlyOption
  142.  
  143. class PackDialog(Dialog):
  144.  
  145.     def __init__(self, widget):
  146.         self.widget = widget
  147.         Dialog.__init__(self, widget)
  148.  
  149.     def refresh(self):
  150.         self.current = self.widget.info()
  151.         self.current['.class'] = self.widget.winfo_class()
  152.         self.current['.name'] = self.widget._w
  153.  
  154.     class packoption: # Mix-in class
  155.         def set(self, e=None):
  156.             self.current = self.var.get()
  157.             try:
  158.                 apply(self.dialog.widget.pack, (),
  159.                       {self.option: self.current})
  160.             except TclError, msg:
  161.                 print msg
  162.                 self.refresh()
  163.  
  164.     class booleanoption(packoption, BooleanOption): pass
  165.     class enumoption(packoption, EnumOption): pass
  166.     class stringoption(packoption, StringOption): pass
  167.     class readonlyoption(packoption, ReadonlyOption): pass
  168.  
  169.     options = {
  170.         '.class': (None, 'Class'),
  171.         '.name': (None, 'Name'),
  172.         'after': (None, 'Widget'),
  173.         'anchor': ('center', 'Anchor'),
  174.         'before': (None, 'Widget'),
  175.         'expand': ('no', 'Boolean'),
  176.         'fill': ('none', 'Fill'),
  177.         'in': (None, 'Widget'),
  178.         'ipadx': (0, 'Pad'),
  179.         'ipady': (0, 'Pad'),
  180.         'padx': (0, 'Pad'),
  181.         'pady': (0, 'Pad'),
  182.         'side': ('top', 'Side'),
  183.         }
  184.  
  185.     classes = {
  186.         'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
  187.         'Boolean': 'boolean',
  188.         'Class': 'readonly',
  189.         'Expand': 'boolean',
  190.         'Fill': (NONE, X, Y, BOTH),
  191.         'Name': 'readonly',
  192.         'Pad': 'pixel',
  193.         'Side': (TOP, RIGHT, BOTTOM, LEFT),
  194.         'Widget': 'readonly',
  195.         }
  196.  
  197. class RemotePackDialog(PackDialog):
  198.  
  199.     def __init__(self, master, app, widget):
  200.         self.master = master
  201.         self.app = app
  202.         self.widget = widget
  203.         self.refresh()
  204.         self.top = Toplevel(self.master)
  205.         self.top.title(self.app + ' PackDialog')
  206.         self.top.minsize(1, 1)
  207.         self.addchoices()
  208.  
  209.     def refresh(self):
  210.         try:
  211.             words = self.master.tk.splitlist(
  212.                 self.master.send(self.app,
  213.                          'pack',
  214.                          'info',
  215.                          self.widget))
  216.         except TclError, msg:
  217.             print msg
  218.             return
  219.         dict = {}
  220.         for i in range(0, len(words), 2):
  221.             key = words[i][1:]
  222.             value = words[i+1]
  223.             dict[key] = value
  224.         dict['.class'] = self.master.send(self.app,
  225.                           'winfo',
  226.                           'class',
  227.                           self.widget)
  228.         dict['.name'] = self.widget
  229.         self.current = dict
  230.  
  231.     class remotepackoption: # Mix-in class
  232.         def set(self, e=None):
  233.             self.current = self.var.get()
  234.             try:
  235.                 self.dialog.master.send(
  236.                     self.dialog.app,
  237.                     'pack',
  238.                     'config',
  239.                     self.dialog.widget,
  240.                     '-'+self.option,
  241.                     self.dialog.master.tk.merge(
  242.                         self.current))
  243.             except TclError, msg:
  244.                 print msg
  245.                 self.refresh()
  246.  
  247.     class booleanoption(remotepackoption, BooleanOption): pass
  248.     class enumoption(remotepackoption, EnumOption): pass
  249.     class stringoption(remotepackoption, StringOption): pass
  250.     class readonlyoption(remotepackoption, ReadonlyOption): pass
  251.  
  252. class WidgetDialog(Dialog):
  253.  
  254.     def __init__(self, widget):
  255.         self.widget = widget
  256.         self.klass = widget.winfo_class()
  257.         Dialog.__init__(self, widget)
  258.  
  259.     def fixclasses(self):
  260.         if self.addclasses.has_key(self.klass):
  261.             classes = {}
  262.             for c in (self.classes,
  263.                   self.addclasses[self.klass]):
  264.                 for k in c.keys():
  265.                     classes[k] = c[k]
  266.             self.classes = classes
  267.  
  268.     def refresh(self):
  269.         self.configuration = self.widget.config()
  270.         self.update()
  271.         self.current['.class'] = self.widget.winfo_class()
  272.         self.current['.name'] = self.widget._w
  273.  
  274.     def update(self):
  275.         self.current = {}
  276.         self.options = {}
  277.         for k, v in self.configuration.items():
  278.             if len(v) > 4:
  279.                 self.current[k] = v[4]
  280.                 self.options[k] = v[3], v[2] # default, klass
  281.         self.options['.class'] = (None, 'Class')
  282.         self.options['.name'] = (None, 'Name')
  283.  
  284.     class widgetoption: # Mix-in class
  285.         def set(self, e=None):
  286.             self.current = self.var.get()
  287.             try:
  288.                 self.dialog.widget[self.option] = self.current
  289.             except TclError, msg:
  290.                 print msg
  291.                 self.refresh()
  292.  
  293.     class booleanoption(widgetoption, BooleanOption): pass
  294.     class enumoption(widgetoption, EnumOption): pass
  295.     class stringoption(widgetoption, StringOption): pass
  296.     class readonlyoption(widgetoption, ReadonlyOption): pass
  297.  
  298.     # Universal classes
  299.     classes = {
  300.         'Anchor': (N, NE, E, SE, S, SW, W, NW, CENTER),
  301.         'Aspect': 'integer',
  302.         'Background': 'color',
  303.         'Bitmap': 'bitmap',
  304.         'BorderWidth': 'pixel',
  305.         'Class': 'readonly',
  306.         'CloseEnough': 'double',
  307.         'Command': 'command',
  308.         'Confine': 'boolean',
  309.         'Cursor': 'cursor',
  310.         'CursorWidth': 'pixel',
  311.         'DisabledForeground': 'color',
  312.         'ExportSelection': 'boolean',
  313.         'Font': 'font',
  314.         'Foreground': 'color',
  315.         'From': 'integer',
  316.         'Geometry': 'geometry',
  317.         'Height': 'pixel',
  318.         'InsertWidth': 'time',
  319.         'Justify': (LEFT, CENTER, RIGHT),
  320.         'Label': 'string',
  321.         'Length': 'pixel',
  322.         'MenuName': 'widget',
  323.         'Name': 'readonly',
  324.         'OffTime': 'time',
  325.         'OnTime': 'time',
  326.         'Orient': (HORIZONTAL, VERTICAL),
  327.         'Pad': 'pixel',
  328.         'Relief': (RAISED, SUNKEN, FLAT, RIDGE, GROOVE),
  329.         'RepeatDelay': 'time',
  330.         'RepeatInterval': 'time',
  331.         'ScrollCommand': 'command',
  332.         'ScrollIncrement': 'pixel',
  333.         'ScrollRegion': 'rectangle',
  334.         'ShowValue': 'boolean',
  335.         'SetGrid': 'boolean',
  336.         'Sliderforeground': 'color',
  337.         'SliderLength': 'pixel',
  338.         'Text': 'string',
  339.         'TickInterval': 'integer',
  340.         'To': 'integer',
  341.         'Underline': 'index',
  342.         'Variable': 'variable',
  343.         'Value': 'string',
  344.         'Width': 'pixel',
  345.         'Wrap': (NONE, CHAR, WORD),
  346.         }
  347.  
  348.     # Classes that (may) differ per widget type
  349.     _tristate = {'State': (NORMAL, ACTIVE, DISABLED)}
  350.     _bistate = {'State': (NORMAL, DISABLED)}
  351.     addclasses = {
  352.         'Button': _tristate,
  353.         'Radiobutton': _tristate,
  354.         'Checkbutton': _tristate,
  355.         'Entry': _bistate,
  356.         'Text': _bistate,
  357.         'Menubutton': _tristate,
  358.         'Slider': _bistate,
  359.         }
  360.  
  361. class RemoteWidgetDialog(WidgetDialog):
  362.  
  363.     def __init__(self, master, app, widget):
  364.         self.app = app
  365.         self.widget = widget
  366.         self.klass = master.send(self.app,
  367.                      'winfo',
  368.                      'class',
  369.                      self.widget)
  370.         Dialog.__init__(self, master)
  371.  
  372.     def refresh(self):
  373.         try:
  374.             items = self.master.tk.splitlist(
  375.                 self.master.send(self.app,
  376.                          self.widget,
  377.                          'config'))
  378.         except TclError, msg:
  379.             print msg
  380.             return
  381.         dict = {}
  382.         for item in items:
  383.             words = self.master.tk.splitlist(item)
  384.             key = words[0][1:]
  385.             value = (key,) + words[1:]
  386.             dict[key] = value
  387.         self.configuration = dict
  388.         self.update()
  389.         self.current['.class'] = self.klass
  390.         self.current['.name'] = self.widget
  391.  
  392.     class remotewidgetoption: # Mix-in class
  393.         def set(self, e=None):
  394.             self.current = self.var.get()
  395.             try:
  396.                 self.dialog.master.send(
  397.                     self.dialog.app,
  398.                     self.dialog.widget,
  399.                     'config',
  400.                     '-'+self.option,
  401.                     self.current)
  402.             except TclError, msg:
  403.                 print msg
  404.                 self.refresh()
  405.  
  406.     class booleanoption(remotewidgetoption, BooleanOption): pass
  407.     class enumoption(remotewidgetoption, EnumOption): pass
  408.     class stringoption(remotewidgetoption, StringOption): pass
  409.     class readonlyoption(remotewidgetoption, ReadonlyOption): pass
  410.  
  411. def test():
  412.     import sys
  413.     root = Tk()
  414.     root.minsize(1, 1)
  415.     if sys.argv[1:]:
  416.         remotetest(root, sys.argv[1])
  417.     else:
  418.         frame = Frame(root, name='frame')
  419.         frame.pack(expand=1, fill=BOTH)
  420.         button = Button(frame, name='button', text='button')
  421.         button.pack(expand=1)
  422.         canvas = Canvas(frame, name='canvas')
  423.         canvas.pack()
  424.         fpd = PackDialog(frame)
  425.         fwd = WidgetDialog(frame)
  426.         bpd = PackDialog(button)
  427.         bwd = WidgetDialog(button)
  428.         cpd = PackDialog(canvas)
  429.         cwd = WidgetDialog(canvas)
  430.     root.mainloop()
  431.  
  432. def remotetest(root, app):
  433.     from listtree import listtree
  434.     list = listtree(root, app)
  435.     list.bind('<Any-Double-1>', opendialogs)
  436.     list.app = app            # Pass it on to handler
  437.  
  438. def opendialogs(e):
  439.     import string
  440.     list = e.widget
  441.     sel = list.curselection()
  442.     for i in sel:
  443.         item = list.get(i)
  444.         widget = string.split(item)[0]
  445.         RemoteWidgetDialog(list, list.app, widget)
  446.         if widget == '.': continue
  447.         try:
  448.             RemotePackDialog(list, list.app, widget)
  449.         except TclError, msg:
  450.             print msg
  451.  
  452. test()
  453.