Home | History | Annotate | Download | only in lib-tk
      1 """Ttk wrapper.
      2 
      3 This module provides classes to allow using Tk themed widget set.
      4 
      5 Ttk is based on a revised and enhanced version of
      6 TIP #48 (http://tip.tcl.tk/48) specified style engine.
      7 
      8 Its basic idea is to separate, to the extent possible, the code
      9 implementing a widget's behavior from the code implementing its
     10 appearance. Widget class bindings are primarily responsible for
     11 maintaining the widget state and invoking callbacks, all aspects
     12 of the widgets appearance lies at Themes.
     13 """
     14 
     15 __version__ = "0.3.1"
     16 
     17 __author__ = "Guilherme Polo <ggpolo (at] gmail.com>"
     18 
     19 __all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label",
     20            "Labelframe", "LabelFrame", "Menubutton", "Notebook", "Panedwindow",
     21            "PanedWindow", "Progressbar", "Radiobutton", "Scale", "Scrollbar",
     22            "Separator", "Sizegrip", "Style", "Treeview",
     23            # Extensions
     24            "LabeledScale", "OptionMenu",
     25            # functions
     26            "tclobjs_to_py", "setup_master"]
     27 
     28 import Tkinter
     29 from Tkinter import _flatten, _join, _stringify, _splitdict
     30 
     31 # Verify if Tk is new enough to not need the Tile package
     32 _REQUIRE_TILE = True if Tkinter.TkVersion < 8.5 else False
     33 
     34 def _load_tile(master):
     35     if _REQUIRE_TILE:
     36         import os
     37         tilelib = os.environ.get('TILE_LIBRARY')
     38         if tilelib:
     39             # append custom tile path to the list of directories that
     40             # Tcl uses when attempting to resolve packages with the package
     41             # command
     42             master.tk.eval(
     43                     'global auto_path; '
     44                     'lappend auto_path {%s}' % tilelib)
     45 
     46         master.tk.eval('package require tile') # TclError may be raised here
     47         master._tile_loaded = True
     48 
     49 def _format_optvalue(value, script=False):
     50     """Internal function."""
     51     if script:
     52         # if caller passes a Tcl script to tk.call, all the values need to
     53         # be grouped into words (arguments to a command in Tcl dialect)
     54         value = _stringify(value)
     55     elif isinstance(value, (list, tuple)):
     56         value = _join(value)
     57     return value
     58 
     59 def _format_optdict(optdict, script=False, ignore=None):
     60     """Formats optdict to a tuple to pass it to tk.call.
     61 
     62     E.g. (script=False):
     63       {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
     64       ('-foreground', 'blue', '-padding', '1 2 3 4')"""
     65 
     66     opts = []
     67     for opt, value in optdict.iteritems():
     68         if not ignore or opt not in ignore:
     69             opts.append("-%s" % opt)
     70             if value is not None:
     71                 opts.append(_format_optvalue(value, script))
     72 
     73     return _flatten(opts)
     74 
     75 def _mapdict_values(items):
     76     # each value in mapdict is expected to be a sequence, where each item
     77     # is another sequence containing a state (or several) and a value
     78     # E.g. (script=False):
     79     #   [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]
     80     #   returns:
     81     #   ['active selected', 'grey', 'focus', [1, 2, 3, 4]]
     82     opt_val = []
     83     for item in items:
     84         state = item[:-1]
     85         val = item[-1]
     86         # hacks for bakward compatibility
     87         state[0] # raise IndexError if empty
     88         if len(state) == 1:
     89             # if it is empty (something that evaluates to False), then
     90             # format it to Tcl code to denote the "normal" state
     91             state = state[0] or ''
     92         else:
     93             # group multiple states
     94             state = ' '.join(state) # raise TypeError if not str
     95         opt_val.append(state)
     96         if val is not None:
     97             opt_val.append(val)
     98     return opt_val
     99 
    100 def _format_mapdict(mapdict, script=False):
    101     """Formats mapdict to pass it to tk.call.
    102 
    103     E.g. (script=False):
    104       {'expand': [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]}
    105 
    106       returns:
    107 
    108       ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
    109 
    110     opts = []
    111     for opt, value in mapdict.iteritems():
    112         opts.extend(("-%s" % opt,
    113                      _format_optvalue(_mapdict_values(value), script)))
    114 
    115     return _flatten(opts)
    116 
    117 def _format_elemcreate(etype, script=False, *args, **kw):
    118     """Formats args and kw according to the given element factory etype."""
    119     spec = None
    120     opts = ()
    121     if etype in ("image", "vsapi"):
    122         if etype == "image": # define an element based on an image
    123             # first arg should be the default image name
    124             iname = args[0]
    125             # next args, if any, are statespec/value pairs which is almost
    126             # a mapdict, but we just need the value
    127             imagespec = _join(_mapdict_values(args[1:]))
    128             spec = "%s %s" % (iname, imagespec)
    129 
    130         else:
    131             # define an element whose visual appearance is drawn using the
    132             # Microsoft Visual Styles API which is responsible for the
    133             # themed styles on Windows XP and Vista.
    134             # Availability: Tk 8.6, Windows XP and Vista.
    135             class_name, part_id = args[:2]
    136             statemap = _join(_mapdict_values(args[2:]))
    137             spec = "%s %s %s" % (class_name, part_id, statemap)
    138 
    139         opts = _format_optdict(kw, script)
    140 
    141     elif etype == "from": # clone an element
    142         # it expects a themename and optionally an element to clone from,
    143         # otherwise it will clone {} (empty element)
    144         spec = args[0] # theme name
    145         if len(args) > 1: # elementfrom specified
    146             opts = (_format_optvalue(args[1], script),)
    147 
    148     if script:
    149         spec = '{%s}' % spec
    150         opts = ' '.join(opts)
    151 
    152     return spec, opts
    153 
    154 def _format_layoutlist(layout, indent=0, indent_size=2):
    155     """Formats a layout list so we can pass the result to ttk::style
    156     layout and ttk::style settings. Note that the layout doesn't have to
    157     be a list necessarily.
    158 
    159     E.g.:
    160       [("Menubutton.background", None),
    161        ("Menubutton.button", {"children":
    162            [("Menubutton.focus", {"children":
    163                [("Menubutton.padding", {"children":
    164                 [("Menubutton.label", {"side": "left", "expand": 1})]
    165                })]
    166            })]
    167        }),
    168        ("Menubutton.indicator", {"side": "right"})
    169       ]
    170 
    171       returns:
    172 
    173       Menubutton.background
    174       Menubutton.button -children {
    175         Menubutton.focus -children {
    176           Menubutton.padding -children {
    177             Menubutton.label -side left -expand 1
    178           }
    179         }
    180       }
    181       Menubutton.indicator -side right"""
    182     script = []
    183 
    184     for layout_elem in layout:
    185         elem, opts = layout_elem
    186         opts = opts or {}
    187         fopts = ' '.join(_format_optdict(opts, True, ("children",)))
    188         head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')
    189 
    190         if "children" in opts:
    191             script.append(head + " -children {")
    192             indent += indent_size
    193             newscript, indent = _format_layoutlist(opts['children'], indent,
    194                 indent_size)
    195             script.append(newscript)
    196             indent -= indent_size
    197             script.append('%s}' % (' ' * indent))
    198         else:
    199             script.append(head)
    200 
    201     return '\n'.join(script), indent
    202 
    203 def _script_from_settings(settings):
    204     """Returns an appropriate script, based on settings, according to
    205     theme_settings definition to be used by theme_settings and
    206     theme_create."""
    207     script = []
    208     # a script will be generated according to settings passed, which
    209     # will then be evaluated by Tcl
    210     for name, opts in settings.iteritems():
    211         # will format specific keys according to Tcl code
    212         if opts.get('configure'): # format 'configure'
    213             s = ' '.join(_format_optdict(opts['configure'], True))
    214             script.append("ttk::style configure %s %s;" % (name, s))
    215 
    216         if opts.get('map'): # format 'map'
    217             s = ' '.join(_format_mapdict(opts['map'], True))
    218             script.append("ttk::style map %s %s;" % (name, s))
    219 
    220         if 'layout' in opts: # format 'layout' which may be empty
    221             if not opts['layout']:
    222                 s = 'null' # could be any other word, but this one makes sense
    223             else:
    224                 s, _ = _format_layoutlist(opts['layout'])
    225             script.append("ttk::style layout %s {\n%s\n}" % (name, s))
    226 
    227         if opts.get('element create'): # format 'element create'
    228             eopts = opts['element create']
    229             etype = eopts[0]
    230 
    231             # find where args end, and where kwargs start
    232             argc = 1 # etype was the first one
    233             while argc < len(eopts) and not hasattr(eopts[argc], 'iteritems'):
    234                 argc += 1
    235 
    236             elemargs = eopts[1:argc]
    237             elemkw = eopts[argc] if argc < len(eopts) and eopts[argc] else {}
    238             spec, opts = _format_elemcreate(etype, True, *elemargs, **elemkw)
    239 
    240             script.append("ttk::style element create %s %s %s %s" % (
    241                 name, etype, spec, opts))
    242 
    243     return '\n'.join(script)
    244 
    245 def _list_from_statespec(stuple):
    246     """Construct a list from the given statespec tuple according to the
    247     accepted statespec accepted by _format_mapdict."""
    248     nval = []
    249     for val in stuple:
    250         typename = getattr(val, 'typename', None)
    251         if typename is None:
    252             nval.append(val)
    253         else: # this is a Tcl object
    254             val = str(val)
    255             if typename == 'StateSpec':
    256                 val = val.split()
    257             nval.append(val)
    258 
    259     it = iter(nval)
    260     return [_flatten(spec) for spec in zip(it, it)]
    261 
    262 def _list_from_layouttuple(tk, ltuple):
    263     """Construct a list from the tuple returned by ttk::layout, this is
    264     somewhat the reverse of _format_layoutlist."""
    265     ltuple = tk.splitlist(ltuple)
    266     res = []
    267 
    268     indx = 0
    269     while indx < len(ltuple):
    270         name = ltuple[indx]
    271         opts = {}
    272         res.append((name, opts))
    273         indx += 1
    274 
    275         while indx < len(ltuple): # grab name's options
    276             opt, val = ltuple[indx:indx + 2]
    277             if not opt.startswith('-'): # found next name
    278                 break
    279 
    280             opt = opt[1:] # remove the '-' from the option
    281             indx += 2
    282 
    283             if opt == 'children':
    284                 val = _list_from_layouttuple(tk, val)
    285 
    286             opts[opt] = val
    287 
    288     return res
    289 
    290 def _val_or_dict(tk, options, *args):
    291     """Format options then call Tk command with args and options and return
    292     the appropriate result.
    293 
    294     If no option is specified, a dict is returned. If an option is
    295     specified with the None value, the value for that option is returned.
    296     Otherwise, the function just sets the passed options and the caller
    297     shouldn't be expecting a return value anyway."""
    298     options = _format_optdict(options)
    299     res = tk.call(*(args + options))
    300 
    301     if len(options) % 2: # option specified without a value, return its value
    302         return res
    303 
    304     return _splitdict(tk, res, conv=_tclobj_to_py)
    305 
    306 def _convert_stringval(value):
    307     """Converts a value to, hopefully, a more appropriate Python object."""
    308     value = unicode(value)
    309     try:
    310         value = int(value)
    311     except (ValueError, TypeError):
    312         pass
    313 
    314     return value
    315 
    316 def _to_number(x):
    317     if isinstance(x, str):
    318         if '.' in x:
    319             x = float(x)
    320         else:
    321             x = int(x)
    322     return x
    323 
    324 def _tclobj_to_py(val):
    325     """Return value converted from Tcl object to Python object."""
    326     if val and hasattr(val, '__len__') and not isinstance(val, basestring):
    327         if getattr(val[0], 'typename', None) == 'StateSpec':
    328             val = _list_from_statespec(val)
    329         else:
    330             val = map(_convert_stringval, val)
    331 
    332     elif hasattr(val, 'typename'): # some other (single) Tcl object
    333         val = _convert_stringval(val)
    334 
    335     return val
    336 
    337 def tclobjs_to_py(adict):
    338     """Returns adict with its values converted from Tcl objects to Python
    339     objects."""
    340     for opt, val in adict.items():
    341         adict[opt] = _tclobj_to_py(val)
    342 
    343     return adict
    344 
    345 def setup_master(master=None):
    346     """If master is not None, itself is returned. If master is None,
    347     the default master is returned if there is one, otherwise a new
    348     master is created and returned.
    349 
    350     If it is not allowed to use the default root and master is None,
    351     RuntimeError is raised."""
    352     if master is None:
    353         if Tkinter._support_default_root:
    354             master = Tkinter._default_root or Tkinter.Tk()
    355         else:
    356             raise RuntimeError(
    357                     "No master specified and Tkinter is "
    358                     "configured to not support default root")
    359     return master
    360 
    361 
    362 class Style(object):
    363     """Manipulate style database."""
    364 
    365     _name = "ttk::style"
    366 
    367     def __init__(self, master=None):
    368         master = setup_master(master)
    369 
    370         if not getattr(master, '_tile_loaded', False):
    371             # Load tile now, if needed
    372             _load_tile(master)
    373 
    374         self.master = master
    375         self.tk = self.master.tk
    376 
    377 
    378     def configure(self, style, query_opt=None, **kw):
    379         """Query or sets the default value of the specified option(s) in
    380         style.
    381 
    382         Each key in kw is an option and each value is either a string or
    383         a sequence identifying the value for that option."""
    384         if query_opt is not None:
    385             kw[query_opt] = None
    386         return _val_or_dict(self.tk, kw, self._name, "configure", style)
    387 
    388 
    389     def map(self, style, query_opt=None, **kw):
    390         """Query or sets dynamic values of the specified option(s) in
    391         style.
    392 
    393         Each key in kw is an option and each value should be a list or a
    394         tuple (usually) containing statespecs grouped in tuples, or list,
    395         or something else of your preference. A statespec is compound of
    396         one or more states and then a value."""
    397         if query_opt is not None:
    398             return _list_from_statespec(self.tk.splitlist(
    399                 self.tk.call(self._name, "map", style, '-%s' % query_opt)))
    400 
    401         return _splitdict(
    402             self.tk,
    403             self.tk.call(self._name, "map", style, *_format_mapdict(kw)),
    404             conv=_tclobj_to_py)
    405 
    406 
    407     def lookup(self, style, option, state=None, default=None):
    408         """Returns the value specified for option in style.
    409 
    410         If state is specified it is expected to be a sequence of one
    411         or more states. If the default argument is set, it is used as
    412         a fallback value in case no specification for option is found."""
    413         state = ' '.join(state) if state else ''
    414 
    415         return self.tk.call(self._name, "lookup", style, '-%s' % option,
    416             state, default)
    417 
    418 
    419     def layout(self, style, layoutspec=None):
    420         """Define the widget layout for given style. If layoutspec is
    421         omitted, return the layout specification for given style.
    422 
    423         layoutspec is expected to be a list or an object different than
    424         None that evaluates to False if you want to "turn off" that style.
    425         If it is a list (or tuple, or something else), each item should be
    426         a tuple where the first item is the layout name and the second item
    427         should have the format described below:
    428 
    429         LAYOUTS
    430 
    431             A layout can contain the value None, if takes no options, or
    432             a dict of options specifying how to arrange the element.
    433             The layout mechanism uses a simplified version of the pack
    434             geometry manager: given an initial cavity, each element is
    435             allocated a parcel. Valid options/values are:
    436 
    437                 side: whichside
    438                     Specifies which side of the cavity to place the
    439                     element; one of top, right, bottom or left. If
    440                     omitted, the element occupies the entire cavity.
    441 
    442                 sticky: nswe
    443                     Specifies where the element is placed inside its
    444                     allocated parcel.
    445 
    446                 children: [sublayout... ]
    447                     Specifies a list of elements to place inside the
    448                     element. Each element is a tuple (or other sequence)
    449                     where the first item is the layout name, and the other
    450                     is a LAYOUT."""
    451         lspec = None
    452         if layoutspec:
    453             lspec = _format_layoutlist(layoutspec)[0]
    454         elif layoutspec is not None: # will disable the layout ({}, '', etc)
    455             lspec = "null" # could be any other word, but this may make sense
    456                            # when calling layout(style) later
    457 
    458         return _list_from_layouttuple(self.tk,
    459             self.tk.call(self._name, "layout", style, lspec))
    460 
    461 
    462     def element_create(self, elementname, etype, *args, **kw):
    463         """Create a new element in the current theme of given etype."""
    464         spec, opts = _format_elemcreate(etype, False, *args, **kw)
    465         self.tk.call(self._name, "element", "create", elementname, etype,
    466             spec, *opts)
    467 
    468 
    469     def element_names(self):
    470         """Returns the list of elements defined in the current theme."""
    471         return self.tk.splitlist(self.tk.call(self._name, "element", "names"))
    472 
    473 
    474     def element_options(self, elementname):
    475         """Return the list of elementname's options."""
    476         return self.tk.splitlist(self.tk.call(self._name, "element", "options", elementname))
    477 
    478 
    479     def theme_create(self, themename, parent=None, settings=None):
    480         """Creates a new theme.
    481 
    482         It is an error if themename already exists. If parent is
    483         specified, the new theme will inherit styles, elements and
    484         layouts from the specified parent theme. If settings are present,
    485         they are expected to have the same syntax used for theme_settings."""
    486         script = _script_from_settings(settings) if settings else ''
    487 
    488         if parent:
    489             self.tk.call(self._name, "theme", "create", themename,
    490                 "-parent", parent, "-settings", script)
    491         else:
    492             self.tk.call(self._name, "theme", "create", themename,
    493                 "-settings", script)
    494 
    495 
    496     def theme_settings(self, themename, settings):
    497         """Temporarily sets the current theme to themename, apply specified
    498         settings and then restore the previous theme.
    499 
    500         Each key in settings is a style and each value may contain the
    501         keys 'configure', 'map', 'layout' and 'element create' and they
    502         are expected to have the same format as specified by the methods
    503         configure, map, layout and element_create respectively."""
    504         script = _script_from_settings(settings)
    505         self.tk.call(self._name, "theme", "settings", themename, script)
    506 
    507 
    508     def theme_names(self):
    509         """Returns a list of all known themes."""
    510         return self.tk.splitlist(self.tk.call(self._name, "theme", "names"))
    511 
    512 
    513     def theme_use(self, themename=None):
    514         """If themename is None, returns the theme in use, otherwise, set
    515         the current theme to themename, refreshes all widgets and emits
    516         a <<ThemeChanged>> event."""
    517         if themename is None:
    518             # Starting on Tk 8.6, checking this global is no longer needed
    519             # since it allows doing self.tk.call(self._name, "theme", "use")
    520             return self.tk.eval("return $ttk::currentTheme")
    521 
    522         # using "ttk::setTheme" instead of "ttk::style theme use" causes
    523         # the variable currentTheme to be updated, also, ttk::setTheme calls
    524         # "ttk::style theme use" in order to change theme.
    525         self.tk.call("ttk::setTheme", themename)
    526 
    527 
    528 class Widget(Tkinter.Widget):
    529     """Base class for Tk themed widgets."""
    530 
    531     def __init__(self, master, widgetname, kw=None):
    532         """Constructs a Ttk Widget with the parent master.
    533 
    534         STANDARD OPTIONS
    535 
    536             class, cursor, takefocus, style
    537 
    538         SCROLLABLE WIDGET OPTIONS
    539 
    540             xscrollcommand, yscrollcommand
    541 
    542         LABEL WIDGET OPTIONS
    543 
    544             text, textvariable, underline, image, compound, width
    545 
    546         WIDGET STATES
    547 
    548             active, disabled, focus, pressed, selected, background,
    549             readonly, alternate, invalid
    550         """
    551         master = setup_master(master)
    552         if not getattr(master, '_tile_loaded', False):
    553             # Load tile now, if needed
    554             _load_tile(master)
    555         Tkinter.Widget.__init__(self, master, widgetname, kw=kw)
    556 
    557 
    558     def identify(self, x, y):
    559         """Returns the name of the element at position x, y, or the empty
    560         string if the point does not lie within any element.
    561 
    562         x and y are pixel coordinates relative to the widget."""
    563         return self.tk.call(self._w, "identify", x, y)
    564 
    565 
    566     def instate(self, statespec, callback=None, *args, **kw):
    567         """Test the widget's state.
    568 
    569         If callback is not specified, returns True if the widget state
    570         matches statespec and False otherwise. If callback is specified,
    571         then it will be invoked with *args, **kw if the widget state
    572         matches statespec. statespec is expected to be a sequence."""
    573         ret = self.tk.getboolean(
    574                 self.tk.call(self._w, "instate", ' '.join(statespec)))
    575         if ret and callback:
    576             return callback(*args, **kw)
    577 
    578         return ret
    579 
    580 
    581     def state(self, statespec=None):
    582         """Modify or inquire widget state.
    583 
    584         Widget state is returned if statespec is None, otherwise it is
    585         set according to the statespec flags and then a new state spec
    586         is returned indicating which flags were changed. statespec is
    587         expected to be a sequence."""
    588         if statespec is not None:
    589             statespec = ' '.join(statespec)
    590 
    591         return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))
    592 
    593 
    594 class Button(Widget):
    595     """Ttk Button widget, displays a textual label and/or image, and
    596     evaluates a command when pressed."""
    597 
    598     def __init__(self, master=None, **kw):
    599         """Construct a Ttk Button widget with the parent master.
    600 
    601         STANDARD OPTIONS
    602 
    603             class, compound, cursor, image, state, style, takefocus,
    604             text, textvariable, underline, width
    605 
    606         WIDGET-SPECIFIC OPTIONS
    607 
    608             command, default, width
    609         """
    610         Widget.__init__(self, master, "ttk::button", kw)
    611 
    612 
    613     def invoke(self):
    614         """Invokes the command associated with the button."""
    615         return self.tk.call(self._w, "invoke")
    616 
    617 
    618 class Checkbutton(Widget):
    619     """Ttk Checkbutton widget which is either in on- or off-state."""
    620 
    621     def __init__(self, master=None, **kw):
    622         """Construct a Ttk Checkbutton widget with the parent master.
    623 
    624         STANDARD OPTIONS
    625 
    626             class, compound, cursor, image, state, style, takefocus,
    627             text, textvariable, underline, width
    628 
    629         WIDGET-SPECIFIC OPTIONS
    630 
    631             command, offvalue, onvalue, variable
    632         """
    633         Widget.__init__(self, master, "ttk::checkbutton", kw)
    634 
    635 
    636     def invoke(self):
    637         """Toggles between the selected and deselected states and
    638         invokes the associated command. If the widget is currently
    639         selected, sets the option variable to the offvalue option
    640         and deselects the widget; otherwise, sets the option variable
    641         to the option onvalue.
    642 
    643         Returns the result of the associated command."""
    644         return self.tk.call(self._w, "invoke")
    645 
    646 
    647 class Entry(Widget, Tkinter.Entry):
    648     """Ttk Entry widget displays a one-line text string and allows that
    649     string to be edited by the user."""
    650 
    651     def __init__(self, master=None, widget=None, **kw):
    652         """Constructs a Ttk Entry widget with the parent master.
    653 
    654         STANDARD OPTIONS
    655 
    656             class, cursor, style, takefocus, xscrollcommand
    657 
    658         WIDGET-SPECIFIC OPTIONS
    659 
    660             exportselection, invalidcommand, justify, show, state,
    661             textvariable, validate, validatecommand, width
    662 
    663         VALIDATION MODES
    664 
    665             none, key, focus, focusin, focusout, all
    666         """
    667         Widget.__init__(self, master, widget or "ttk::entry", kw)
    668 
    669 
    670     def bbox(self, index):
    671         """Return a tuple of (x, y, width, height) which describes the
    672         bounding box of the character given by index."""
    673         return self._getints(self.tk.call(self._w, "bbox", index))
    674 
    675 
    676     def identify(self, x, y):
    677         """Returns the name of the element at position x, y, or the
    678         empty string if the coordinates are outside the window."""
    679         return self.tk.call(self._w, "identify", x, y)
    680 
    681 
    682     def validate(self):
    683         """Force revalidation, independent of the conditions specified
    684         by the validate option. Returns False if validation fails, True
    685         if it succeeds. Sets or clears the invalid state accordingly."""
    686         return self.tk.getboolean(self.tk.call(self._w, "validate"))
    687 
    688 
    689 class Combobox(Entry):
    690     """Ttk Combobox widget combines a text field with a pop-down list of
    691     values."""
    692 
    693     def __init__(self, master=None, **kw):
    694         """Construct a Ttk Combobox widget with the parent master.
    695 
    696         STANDARD OPTIONS
    697 
    698             class, cursor, style, takefocus
    699 
    700         WIDGET-SPECIFIC OPTIONS
    701 
    702             exportselection, justify, height, postcommand, state,
    703             textvariable, values, width
    704         """
    705         Entry.__init__(self, master, "ttk::combobox", **kw)
    706 
    707 
    708     def current(self, newindex=None):
    709         """If newindex is supplied, sets the combobox value to the
    710         element at position newindex in the list of values. Otherwise,
    711         returns the index of the current value in the list of values
    712         or -1 if the current value does not appear in the list."""
    713         if newindex is None:
    714             return self.tk.getint(self.tk.call(self._w, "current"))
    715         return self.tk.call(self._w, "current", newindex)
    716 
    717 
    718     def set(self, value):
    719         """Sets the value of the combobox to value."""
    720         self.tk.call(self._w, "set", value)
    721 
    722 
    723 class Frame(Widget):
    724     """Ttk Frame widget is a container, used to group other widgets
    725     together."""
    726 
    727     def __init__(self, master=None, **kw):
    728         """Construct a Ttk Frame with parent master.
    729 
    730         STANDARD OPTIONS
    731 
    732             class, cursor, style, takefocus
    733 
    734         WIDGET-SPECIFIC OPTIONS
    735 
    736             borderwidth, relief, padding, width, height
    737         """
    738         Widget.__init__(self, master, "ttk::frame", kw)
    739 
    740 
    741 class Label(Widget):
    742     """Ttk Label widget displays a textual label and/or image."""
    743 
    744     def __init__(self, master=None, **kw):
    745         """Construct a Ttk Label with parent master.
    746 
    747         STANDARD OPTIONS
    748 
    749             class, compound, cursor, image, style, takefocus, text,
    750             textvariable, underline, width
    751 
    752         WIDGET-SPECIFIC OPTIONS
    753 
    754             anchor, background, font, foreground, justify, padding,
    755             relief, text, wraplength
    756         """
    757         Widget.__init__(self, master, "ttk::label", kw)
    758 
    759 
    760 class Labelframe(Widget):
    761     """Ttk Labelframe widget is a container used to group other widgets
    762     together. It has an optional label, which may be a plain text string
    763     or another widget."""
    764 
    765     def __init__(self, master=None, **kw):
    766         """Construct a Ttk Labelframe with parent master.
    767 
    768         STANDARD OPTIONS
    769 
    770             class, cursor, style, takefocus
    771 
    772         WIDGET-SPECIFIC OPTIONS
    773             labelanchor, text, underline, padding, labelwidget, width,
    774             height
    775         """
    776         Widget.__init__(self, master, "ttk::labelframe", kw)
    777 
    778 LabelFrame = Labelframe # Tkinter name compatibility
    779 
    780 
    781 class Menubutton(Widget):
    782     """Ttk Menubutton widget displays a textual label and/or image, and
    783     displays a menu when pressed."""
    784 
    785     def __init__(self, master=None, **kw):
    786         """Construct a Ttk Menubutton with parent master.
    787 
    788         STANDARD OPTIONS
    789 
    790             class, compound, cursor, image, state, style, takefocus,
    791             text, textvariable, underline, width
    792 
    793         WIDGET-SPECIFIC OPTIONS
    794 
    795             direction, menu
    796         """
    797         Widget.__init__(self, master, "ttk::menubutton", kw)
    798 
    799 
    800 class Notebook(Widget):
    801     """Ttk Notebook widget manages a collection of windows and displays
    802     a single one at a time. Each child window is associated with a tab,
    803     which the user may select to change the currently-displayed window."""
    804 
    805     def __init__(self, master=None, **kw):
    806         """Construct a Ttk Notebook with parent master.
    807 
    808         STANDARD OPTIONS
    809 
    810             class, cursor, style, takefocus
    811 
    812         WIDGET-SPECIFIC OPTIONS
    813 
    814             height, padding, width
    815 
    816         TAB OPTIONS
    817 
    818             state, sticky, padding, text, image, compound, underline
    819 
    820         TAB IDENTIFIERS (tab_id)
    821 
    822             The tab_id argument found in several methods may take any of
    823             the following forms:
    824 
    825                 * An integer between zero and the number of tabs
    826                 * The name of a child window
    827                 * A positional specification of the form "@x,y", which
    828                   defines the tab
    829                 * The string "current", which identifies the
    830                   currently-selected tab
    831                 * The string "end", which returns the number of tabs (only
    832                   valid for method index)
    833         """
    834         Widget.__init__(self, master, "ttk::notebook", kw)
    835 
    836 
    837     def add(self, child, **kw):
    838         """Adds a new tab to the notebook.
    839 
    840         If window is currently managed by the notebook but hidden, it is
    841         restored to its previous position."""
    842         self.tk.call(self._w, "add", child, *(_format_optdict(kw)))
    843 
    844 
    845     def forget(self, tab_id):
    846         """Removes the tab specified by tab_id, unmaps and unmanages the
    847         associated window."""
    848         self.tk.call(self._w, "forget", tab_id)
    849 
    850 
    851     def hide(self, tab_id):
    852         """Hides the tab specified by tab_id.
    853 
    854         The tab will not be displayed, but the associated window remains
    855         managed by the notebook and its configuration remembered. Hidden
    856         tabs may be restored with the add command."""
    857         self.tk.call(self._w, "hide", tab_id)
    858 
    859 
    860     def identify(self, x, y):
    861         """Returns the name of the tab element at position x, y, or the
    862         empty string if none."""
    863         return self.tk.call(self._w, "identify", x, y)
    864 
    865 
    866     def index(self, tab_id):
    867         """Returns the numeric index of the tab specified by tab_id, or
    868         the total number of tabs if tab_id is the string "end"."""
    869         return self.tk.getint(self.tk.call(self._w, "index", tab_id))
    870 
    871 
    872     def insert(self, pos, child, **kw):
    873         """Inserts a pane at the specified position.
    874 
    875         pos is either the string end, an integer index, or the name of
    876         a managed child. If child is already managed by the notebook,
    877         moves it to the specified position."""
    878         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
    879 
    880 
    881     def select(self, tab_id=None):
    882         """Selects the specified tab.
    883 
    884         The associated child window will be displayed, and the
    885         previously-selected window (if different) is unmapped. If tab_id
    886         is omitted, returns the widget name of the currently selected
    887         pane."""
    888         return self.tk.call(self._w, "select", tab_id)
    889 
    890 
    891     def tab(self, tab_id, option=None, **kw):
    892         """Query or modify the options of the specific tab_id.
    893 
    894         If kw is not given, returns a dict of the tab option values. If option
    895         is specified, returns the value of that option. Otherwise, sets the
    896         options to the corresponding values."""
    897         if option is not None:
    898             kw[option] = None
    899         return _val_or_dict(self.tk, kw, self._w, "tab", tab_id)
    900 
    901 
    902     def tabs(self):
    903         """Returns a list of windows managed by the notebook."""
    904         return self.tk.splitlist(self.tk.call(self._w, "tabs") or ())
    905 
    906 
    907     def enable_traversal(self):
    908         """Enable keyboard traversal for a toplevel window containing
    909         this notebook.
    910 
    911         This will extend the bindings for the toplevel window containing
    912         this notebook as follows:
    913 
    914             Control-Tab: selects the tab following the currently selected
    915                          one
    916 
    917             Shift-Control-Tab: selects the tab preceding the currently
    918                                selected one
    919 
    920             Alt-K: where K is the mnemonic (underlined) character of any
    921                    tab, will select that tab.
    922 
    923         Multiple notebooks in a single toplevel may be enabled for
    924         traversal, including nested notebooks. However, notebook traversal
    925         only works properly if all panes are direct children of the
    926         notebook."""
    927         # The only, and good, difference I see is about mnemonics, which works
    928         # after calling this method. Control-Tab and Shift-Control-Tab always
    929         # works (here at least).
    930         self.tk.call("ttk::notebook::enableTraversal", self._w)
    931 
    932 
    933 class Panedwindow(Widget, Tkinter.PanedWindow):
    934     """Ttk Panedwindow widget displays a number of subwindows, stacked
    935     either vertically or horizontally."""
    936 
    937     def __init__(self, master=None, **kw):
    938         """Construct a Ttk Panedwindow with parent master.
    939 
    940         STANDARD OPTIONS
    941 
    942             class, cursor, style, takefocus
    943 
    944         WIDGET-SPECIFIC OPTIONS
    945 
    946             orient, width, height
    947 
    948         PANE OPTIONS
    949 
    950             weight
    951         """
    952         Widget.__init__(self, master, "ttk::panedwindow", kw)
    953 
    954 
    955     forget = Tkinter.PanedWindow.forget # overrides Pack.forget
    956 
    957 
    958     def insert(self, pos, child, **kw):
    959         """Inserts a pane at the specified positions.
    960 
    961         pos is either the string end, and integer index, or the name
    962         of a child. If child is already managed by the paned window,
    963         moves it to the specified position."""
    964         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
    965 
    966 
    967     def pane(self, pane, option=None, **kw):
    968         """Query or modify the options of the specified pane.
    969 
    970         pane is either an integer index or the name of a managed subwindow.
    971         If kw is not given, returns a dict of the pane option values. If
    972         option is specified then the value for that option is returned.
    973         Otherwise, sets the options to the corresponding values."""
    974         if option is not None:
    975             kw[option] = None
    976         return _val_or_dict(self.tk, kw, self._w, "pane", pane)
    977 
    978 
    979     def sashpos(self, index, newpos=None):
    980         """If newpos is specified, sets the position of sash number index.
    981 
    982         May adjust the positions of adjacent sashes to ensure that
    983         positions are monotonically increasing. Sash positions are further
    984         constrained to be between 0 and the total size of the widget.
    985 
    986         Returns the new position of sash number index."""
    987         return self.tk.getint(self.tk.call(self._w, "sashpos", index, newpos))
    988 
    989 PanedWindow = Panedwindow # Tkinter name compatibility
    990 
    991 
    992 class Progressbar(Widget):
    993     """Ttk Progressbar widget shows the status of a long-running
    994     operation. They can operate in two modes: determinate mode shows the
    995     amount completed relative to the total amount of work to be done, and
    996     indeterminate mode provides an animated display to let the user know
    997     that something is happening."""
    998 
    999     def __init__(self, master=None, **kw):
   1000         """Construct a Ttk Progressbar with parent master.
   1001 
   1002         STANDARD OPTIONS
   1003 
   1004             class, cursor, style, takefocus
   1005 
   1006         WIDGET-SPECIFIC OPTIONS
   1007 
   1008             orient, length, mode, maximum, value, variable, phase
   1009         """
   1010         Widget.__init__(self, master, "ttk::progressbar", kw)
   1011 
   1012 
   1013     def start(self, interval=None):
   1014         """Begin autoincrement mode: schedules a recurring timer event
   1015         that calls method step every interval milliseconds.
   1016 
   1017         interval defaults to 50 milliseconds (20 steps/second) if omitted."""
   1018         self.tk.call(self._w, "start", interval)
   1019 
   1020 
   1021     def step(self, amount=None):
   1022         """Increments the value option by amount.
   1023 
   1024         amount defaults to 1.0 if omitted."""
   1025         self.tk.call(self._w, "step", amount)
   1026 
   1027 
   1028     def stop(self):
   1029         """Stop autoincrement mode: cancels any recurring timer event
   1030         initiated by start."""
   1031         self.tk.call(self._w, "stop")
   1032 
   1033 
   1034 class Radiobutton(Widget):
   1035     """Ttk Radiobutton widgets are used in groups to show or change a
   1036     set of mutually-exclusive options."""
   1037 
   1038     def __init__(self, master=None, **kw):
   1039         """Construct a Ttk Radiobutton with parent master.
   1040 
   1041         STANDARD OPTIONS
   1042 
   1043             class, compound, cursor, image, state, style, takefocus,
   1044             text, textvariable, underline, width
   1045 
   1046         WIDGET-SPECIFIC OPTIONS
   1047 
   1048             command, value, variable
   1049         """
   1050         Widget.__init__(self, master, "ttk::radiobutton", kw)
   1051 
   1052 
   1053     def invoke(self):
   1054         """Sets the option variable to the option value, selects the
   1055         widget, and invokes the associated command.
   1056 
   1057         Returns the result of the command, or an empty string if
   1058         no command is specified."""
   1059         return self.tk.call(self._w, "invoke")
   1060 
   1061 
   1062 class Scale(Widget, Tkinter.Scale):
   1063     """Ttk Scale widget is typically used to control the numeric value of
   1064     a linked variable that varies uniformly over some range."""
   1065 
   1066     def __init__(self, master=None, **kw):
   1067         """Construct a Ttk Scale with parent master.
   1068 
   1069         STANDARD OPTIONS
   1070 
   1071             class, cursor, style, takefocus
   1072 
   1073         WIDGET-SPECIFIC OPTIONS
   1074 
   1075             command, from, length, orient, to, value, variable
   1076         """
   1077         Widget.__init__(self, master, "ttk::scale", kw)
   1078 
   1079 
   1080     def configure(self, cnf=None, **kw):
   1081         """Modify or query scale options.
   1082 
   1083         Setting a value for any of the "from", "from_" or "to" options
   1084         generates a <<RangeChanged>> event."""
   1085         if cnf:
   1086             kw.update(cnf)
   1087         Widget.configure(self, **kw)
   1088         if any(['from' in kw, 'from_' in kw, 'to' in kw]):
   1089             self.event_generate('<<RangeChanged>>')
   1090 
   1091 
   1092     def get(self, x=None, y=None):
   1093         """Get the current value of the value option, or the value
   1094         corresponding to the coordinates x, y if they are specified.
   1095 
   1096         x and y are pixel coordinates relative to the scale widget
   1097         origin."""
   1098         return self.tk.call(self._w, 'get', x, y)
   1099 
   1100 
   1101 class Scrollbar(Widget, Tkinter.Scrollbar):
   1102     """Ttk Scrollbar controls the viewport of a scrollable widget."""
   1103 
   1104     def __init__(self, master=None, **kw):
   1105         """Construct a Ttk Scrollbar with parent master.
   1106 
   1107         STANDARD OPTIONS
   1108 
   1109             class, cursor, style, takefocus
   1110 
   1111         WIDGET-SPECIFIC OPTIONS
   1112 
   1113             command, orient
   1114         """
   1115         Widget.__init__(self, master, "ttk::scrollbar", kw)
   1116 
   1117 
   1118 class Separator(Widget):
   1119     """Ttk Separator widget displays a horizontal or vertical separator
   1120     bar."""
   1121 
   1122     def __init__(self, master=None, **kw):
   1123         """Construct a Ttk Separator with parent master.
   1124 
   1125         STANDARD OPTIONS
   1126 
   1127             class, cursor, style, takefocus
   1128 
   1129         WIDGET-SPECIFIC OPTIONS
   1130 
   1131             orient
   1132         """
   1133         Widget.__init__(self, master, "ttk::separator", kw)
   1134 
   1135 
   1136 class Sizegrip(Widget):
   1137     """Ttk Sizegrip allows the user to resize the containing toplevel
   1138     window by pressing and dragging the grip."""
   1139 
   1140     def __init__(self, master=None, **kw):
   1141         """Construct a Ttk Sizegrip with parent master.
   1142 
   1143         STANDARD OPTIONS
   1144 
   1145             class, cursor, state, style, takefocus
   1146         """
   1147         Widget.__init__(self, master, "ttk::sizegrip", kw)
   1148 
   1149 
   1150 class Treeview(Widget, Tkinter.XView, Tkinter.YView):
   1151     """Ttk Treeview widget displays a hierarchical collection of items.
   1152 
   1153     Each item has a textual label, an optional image, and an optional list
   1154     of data values. The data values are displayed in successive columns
   1155     after the tree label."""
   1156 
   1157     def __init__(self, master=None, **kw):
   1158         """Construct a Ttk Treeview with parent master.
   1159 
   1160         STANDARD OPTIONS
   1161 
   1162             class, cursor, style, takefocus, xscrollcommand,
   1163             yscrollcommand
   1164 
   1165         WIDGET-SPECIFIC OPTIONS
   1166 
   1167             columns, displaycolumns, height, padding, selectmode, show
   1168 
   1169         ITEM OPTIONS
   1170 
   1171             text, image, values, open, tags
   1172 
   1173         TAG OPTIONS
   1174 
   1175             foreground, background, font, image
   1176         """
   1177         Widget.__init__(self, master, "ttk::treeview", kw)
   1178 
   1179 
   1180     def bbox(self, item, column=None):
   1181         """Returns the bounding box (relative to the treeview widget's
   1182         window) of the specified item in the form x y width height.
   1183 
   1184         If column is specified, returns the bounding box of that cell.
   1185         If the item is not visible (i.e., if it is a descendant of a
   1186         closed item or is scrolled offscreen), returns an empty string."""
   1187         return self._getints(self.tk.call(self._w, "bbox", item, column)) or ''
   1188 
   1189 
   1190     def get_children(self, item=None):
   1191         """Returns a tuple of children belonging to item.
   1192 
   1193         If item is not specified, returns root children."""
   1194         return self.tk.splitlist(
   1195                 self.tk.call(self._w, "children", item or '') or ())
   1196 
   1197 
   1198     def set_children(self, item, *newchildren):
   1199         """Replaces item's child with newchildren.
   1200 
   1201         Children present in item that are not present in newchildren
   1202         are detached from tree. No items in newchildren may be an
   1203         ancestor of item."""
   1204         self.tk.call(self._w, "children", item, newchildren)
   1205 
   1206 
   1207     def column(self, column, option=None, **kw):
   1208         """Query or modify the options for the specified column.
   1209 
   1210         If kw is not given, returns a dict of the column option values. If
   1211         option is specified then the value for that option is returned.
   1212         Otherwise, sets the options to the corresponding values."""
   1213         if option is not None:
   1214             kw[option] = None
   1215         return _val_or_dict(self.tk, kw, self._w, "column", column)
   1216 
   1217 
   1218     def delete(self, *items):
   1219         """Delete all specified items and all their descendants. The root
   1220         item may not be deleted."""
   1221         self.tk.call(self._w, "delete", items)
   1222 
   1223 
   1224     def detach(self, *items):
   1225         """Unlinks all of the specified items from the tree.
   1226 
   1227         The items and all of their descendants are still present, and may
   1228         be reinserted at another point in the tree, but will not be
   1229         displayed. The root item may not be detached."""
   1230         self.tk.call(self._w, "detach", items)
   1231 
   1232 
   1233     def exists(self, item):
   1234         """Returns True if the specified item is present in the tree,
   1235         False otherwise."""
   1236         return self.tk.getboolean(self.tk.call(self._w, "exists", item))
   1237 
   1238 
   1239     def focus(self, item=None):
   1240         """If item is specified, sets the focus item to item. Otherwise,
   1241         returns the current focus item, or '' if there is none."""
   1242         return self.tk.call(self._w, "focus", item)
   1243 
   1244 
   1245     def heading(self, column, option=None, **kw):
   1246         """Query or modify the heading options for the specified column.
   1247 
   1248         If kw is not given, returns a dict of the heading option values. If
   1249         option is specified then the value for that option is returned.
   1250         Otherwise, sets the options to the corresponding values.
   1251 
   1252         Valid options/values are:
   1253             text: text
   1254                 The text to display in the column heading
   1255             image: image_name
   1256                 Specifies an image to display to the right of the column
   1257                 heading
   1258             anchor: anchor
   1259                 Specifies how the heading text should be aligned. One of
   1260                 the standard Tk anchor values
   1261             command: callback
   1262                 A callback to be invoked when the heading label is
   1263                 pressed.
   1264 
   1265         To configure the tree column heading, call this with column = "#0" """
   1266         cmd = kw.get('command')
   1267         if cmd and not isinstance(cmd, basestring):
   1268             # callback not registered yet, do it now
   1269             kw['command'] = self.master.register(cmd, self._substitute)
   1270 
   1271         if option is not None:
   1272             kw[option] = None
   1273 
   1274         return _val_or_dict(self.tk, kw, self._w, 'heading', column)
   1275 
   1276 
   1277     def identify(self, component, x, y):
   1278         """Returns a description of the specified component under the
   1279         point given by x and y, or the empty string if no such component
   1280         is present at that position."""
   1281         return self.tk.call(self._w, "identify", component, x, y)
   1282 
   1283 
   1284     def identify_row(self, y):
   1285         """Returns the item ID of the item at position y."""
   1286         return self.identify("row", 0, y)
   1287 
   1288 
   1289     def identify_column(self, x):
   1290         """Returns the data column identifier of the cell at position x.
   1291 
   1292         The tree column has ID #0."""
   1293         return self.identify("column", x, 0)
   1294 
   1295 
   1296     def identify_region(self, x, y):
   1297         """Returns one of:
   1298 
   1299         heading: Tree heading area.
   1300         separator: Space between two columns headings;
   1301         tree: The tree area.
   1302         cell: A data cell.
   1303 
   1304         * Availability: Tk 8.6"""
   1305         return self.identify("region", x, y)
   1306 
   1307 
   1308     def identify_element(self, x, y):
   1309         """Returns the element at position x, y.
   1310 
   1311         * Availability: Tk 8.6"""
   1312         return self.identify("element", x, y)
   1313 
   1314 
   1315     def index(self, item):
   1316         """Returns the integer index of item within its parent's list
   1317         of children."""
   1318         return self.tk.getint(self.tk.call(self._w, "index", item))
   1319 
   1320 
   1321     def insert(self, parent, index, iid=None, **kw):
   1322         """Creates a new item and return the item identifier of the newly
   1323         created item.
   1324 
   1325         parent is the item ID of the parent item, or the empty string
   1326         to create a new top-level item. index is an integer, or the value
   1327         end, specifying where in the list of parent's children to insert
   1328         the new item. If index is less than or equal to zero, the new node
   1329         is inserted at the beginning, if index is greater than or equal to
   1330         the current number of children, it is inserted at the end. If iid
   1331         is specified, it is used as the item identifier, iid must not
   1332         already exist in the tree. Otherwise, a new unique identifier
   1333         is generated."""
   1334         opts = _format_optdict(kw)
   1335         if iid:
   1336             res = self.tk.call(self._w, "insert", parent, index,
   1337                 "-id", iid, *opts)
   1338         else:
   1339             res = self.tk.call(self._w, "insert", parent, index, *opts)
   1340 
   1341         return res
   1342 
   1343 
   1344     def item(self, item, option=None, **kw):
   1345         """Query or modify the options for the specified item.
   1346 
   1347         If no options are given, a dict with options/values for the item
   1348         is returned. If option is specified then the value for that option
   1349         is returned. Otherwise, sets the options to the corresponding
   1350         values as given by kw."""
   1351         if option is not None:
   1352             kw[option] = None
   1353         return _val_or_dict(self.tk, kw, self._w, "item", item)
   1354 
   1355 
   1356     def move(self, item, parent, index):
   1357         """Moves item to position index in parent's list of children.
   1358 
   1359         It is illegal to move an item under one of its descendants. If
   1360         index is less than or equal to zero, item is moved to the
   1361         beginning, if greater than or equal to the number of children,
   1362         it is moved to the end. If item was detached it is reattached."""
   1363         self.tk.call(self._w, "move", item, parent, index)
   1364 
   1365     reattach = move # A sensible method name for reattaching detached items
   1366 
   1367 
   1368     def next(self, item):
   1369         """Returns the identifier of item's next sibling, or '' if item
   1370         is the last child of its parent."""
   1371         return self.tk.call(self._w, "next", item)
   1372 
   1373 
   1374     def parent(self, item):
   1375         """Returns the ID of the parent of item, or '' if item is at the
   1376         top level of the hierarchy."""
   1377         return self.tk.call(self._w, "parent", item)
   1378 
   1379 
   1380     def prev(self, item):
   1381         """Returns the identifier of item's previous sibling, or '' if
   1382         item is the first child of its parent."""
   1383         return self.tk.call(self._w, "prev", item)
   1384 
   1385 
   1386     def see(self, item):
   1387         """Ensure that item is visible.
   1388 
   1389         Sets all of item's ancestors open option to True, and scrolls
   1390         the widget if necessary so that item is within the visible
   1391         portion of the tree."""
   1392         self.tk.call(self._w, "see", item)
   1393 
   1394 
   1395     def selection(self, selop=None, items=None):
   1396         """If selop is not specified, returns selected items."""
   1397         if isinstance(items, basestring):
   1398             items = (items,)
   1399         return self.tk.splitlist(self.tk.call(self._w, "selection", selop, items))
   1400 
   1401 
   1402     def selection_set(self, items):
   1403         """items becomes the new selection."""
   1404         self.selection("set", items)
   1405 
   1406 
   1407     def selection_add(self, items):
   1408         """Add items to the selection."""
   1409         self.selection("add", items)
   1410 
   1411 
   1412     def selection_remove(self, items):
   1413         """Remove items from the selection."""
   1414         self.selection("remove", items)
   1415 
   1416 
   1417     def selection_toggle(self, items):
   1418         """Toggle the selection state of each item in items."""
   1419         self.selection("toggle", items)
   1420 
   1421 
   1422     def set(self, item, column=None, value=None):
   1423         """Query or set the value of given item.
   1424 
   1425         With one argument, return a dictionary of column/value pairs
   1426         for the specified item. With two arguments, return the current
   1427         value of the specified column. With three arguments, set the
   1428         value of given column in given item to the specified value."""
   1429         res = self.tk.call(self._w, "set", item, column, value)
   1430         if column is None and value is None:
   1431             return _splitdict(self.tk, res,
   1432                               cut_minus=False, conv=_tclobj_to_py)
   1433         else:
   1434             return res
   1435 
   1436 
   1437     def tag_bind(self, tagname, sequence=None, callback=None):
   1438         """Bind a callback for the given event sequence to the tag tagname.
   1439         When an event is delivered to an item, the callbacks for each
   1440         of the item's tags option are called."""
   1441         self._bind((self._w, "tag", "bind", tagname), sequence, callback, add=0)
   1442 
   1443 
   1444     def tag_configure(self, tagname, option=None, **kw):
   1445         """Query or modify the options for the specified tagname.
   1446 
   1447         If kw is not given, returns a dict of the option settings for tagname.
   1448         If option is specified, returns the value for that option for the
   1449         specified tagname. Otherwise, sets the options to the corresponding
   1450         values for the given tagname."""
   1451         if option is not None:
   1452             kw[option] = None
   1453         return _val_or_dict(self.tk, kw, self._w, "tag", "configure",
   1454             tagname)
   1455 
   1456 
   1457     def tag_has(self, tagname, item=None):
   1458         """If item is specified, returns 1 or 0 depending on whether the
   1459         specified item has the given tagname. Otherwise, returns a list of
   1460         all items which have the specified tag.
   1461 
   1462         * Availability: Tk 8.6"""
   1463         if item is None:
   1464             return self.tk.splitlist(
   1465                 self.tk.call(self._w, "tag", "has", tagname))
   1466         else:
   1467             return self.tk.getboolean(
   1468                 self.tk.call(self._w, "tag", "has", tagname, item))
   1469 
   1470 
   1471 # Extensions
   1472 
   1473 class LabeledScale(Frame, object):
   1474     """A Ttk Scale widget with a Ttk Label widget indicating its
   1475     current value.
   1476 
   1477     The Ttk Scale can be accessed through instance.scale, and Ttk Label
   1478     can be accessed through instance.label"""
   1479 
   1480     def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
   1481         """Construct a horizontal LabeledScale with parent master, a
   1482         variable to be associated with the Ttk Scale widget and its range.
   1483         If variable is not specified, a Tkinter.IntVar is created.
   1484 
   1485         WIDGET-SPECIFIC OPTIONS
   1486 
   1487             compound: 'top' or 'bottom'
   1488                 Specifies how to display the label relative to the scale.
   1489                 Defaults to 'top'.
   1490         """
   1491         self._label_top = kw.pop('compound', 'top') == 'top'
   1492 
   1493         Frame.__init__(self, master, **kw)
   1494         self._variable = variable or Tkinter.IntVar(master)
   1495         self._variable.set(from_)
   1496         self._last_valid = from_
   1497 
   1498         self.label = Label(self)
   1499         self.scale = Scale(self, variable=self._variable, from_=from_, to=to)
   1500         self.scale.bind('<<RangeChanged>>', self._adjust)
   1501 
   1502         # position scale and label according to the compound option
   1503         scale_side = 'bottom' if self._label_top else 'top'
   1504         label_side = 'top' if scale_side == 'bottom' else 'bottom'
   1505         self.scale.pack(side=scale_side, fill='x')
   1506         tmp = Label(self).pack(side=label_side) # place holder
   1507         self.label.place(anchor='n' if label_side == 'top' else 's')
   1508 
   1509         # update the label as scale or variable changes
   1510         self.__tracecb = self._variable.trace_variable('w', self._adjust)
   1511         self.bind('<Configure>', self._adjust)
   1512         self.bind('<Map>', self._adjust)
   1513 
   1514 
   1515     def destroy(self):
   1516         """Destroy this widget and possibly its associated variable."""
   1517         try:
   1518             self._variable.trace_vdelete('w', self.__tracecb)
   1519         except AttributeError:
   1520             # widget has been destroyed already
   1521             pass
   1522         else:
   1523             del self._variable
   1524             Frame.destroy(self)
   1525 
   1526 
   1527     def _adjust(self, *args):
   1528         """Adjust the label position according to the scale."""
   1529         def adjust_label():
   1530             self.update_idletasks() # "force" scale redraw
   1531 
   1532             x, y = self.scale.coords()
   1533             if self._label_top:
   1534                 y = self.scale.winfo_y() - self.label.winfo_reqheight()
   1535             else:
   1536                 y = self.scale.winfo_reqheight() + self.label.winfo_reqheight()
   1537 
   1538             self.label.place_configure(x=x, y=y)
   1539 
   1540         from_ = _to_number(self.scale['from'])
   1541         to = _to_number(self.scale['to'])
   1542         if to < from_:
   1543             from_, to = to, from_
   1544         newval = self._variable.get()
   1545         if not from_ <= newval <= to:
   1546             # value outside range, set value back to the last valid one
   1547             self.value = self._last_valid
   1548             return
   1549 
   1550         self._last_valid = newval
   1551         self.label['text'] = newval
   1552         self.after_idle(adjust_label)
   1553 
   1554 
   1555     def _get_value(self):
   1556         """Return current scale value."""
   1557         return self._variable.get()
   1558 
   1559 
   1560     def _set_value(self, val):
   1561         """Set new scale value."""
   1562         self._variable.set(val)
   1563 
   1564 
   1565     value = property(_get_value, _set_value)
   1566 
   1567 
   1568 class OptionMenu(Menubutton):
   1569     """Themed OptionMenu, based after Tkinter's OptionMenu, which allows
   1570     the user to select a value from a menu."""
   1571 
   1572     def __init__(self, master, variable, default=None, *values, **kwargs):
   1573         """Construct a themed OptionMenu widget with master as the parent,
   1574         the resource textvariable set to variable, the initially selected
   1575         value specified by the default parameter, the menu values given by
   1576         *values and additional keywords.
   1577 
   1578         WIDGET-SPECIFIC OPTIONS
   1579 
   1580             style: stylename
   1581                 Menubutton style.
   1582             direction: 'above', 'below', 'left', 'right', or 'flush'
   1583                 Menubutton direction.
   1584             command: callback
   1585                 A callback that will be invoked after selecting an item.
   1586         """
   1587         kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
   1588               'direction': kwargs.pop('direction', None)}
   1589         Menubutton.__init__(self, master, **kw)
   1590         self['menu'] = Tkinter.Menu(self, tearoff=False)
   1591 
   1592         self._variable = variable
   1593         self._callback = kwargs.pop('command', None)
   1594         if kwargs:
   1595             raise Tkinter.TclError('unknown option -%s' % (
   1596                 kwargs.iterkeys().next()))
   1597 
   1598         self.set_menu(default, *values)
   1599 
   1600 
   1601     def __getitem__(self, item):
   1602         if item == 'menu':
   1603             return self.nametowidget(Menubutton.__getitem__(self, item))
   1604 
   1605         return Menubutton.__getitem__(self, item)
   1606 
   1607 
   1608     def set_menu(self, default=None, *values):
   1609         """Build a new menu of radiobuttons with *values and optionally
   1610         a default value."""
   1611         menu = self['menu']
   1612         menu.delete(0, 'end')
   1613         for val in values:
   1614             menu.add_radiobutton(label=val,
   1615                 command=Tkinter._setit(self._variable, val, self._callback))
   1616 
   1617         if default:
   1618             self._variable.set(default)
   1619 
   1620 
   1621     def destroy(self):
   1622         """Destroy this widget and its associated variable."""
   1623         del self._variable
   1624         Menubutton.destroy(self)
   1625