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
     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 has 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 _dict_from_tcltuple(ttuple, cut_minus=True):
    246     """Break tuple in pairs, format it properly, then build the return
    247     dict. If cut_minus is True, the supposed '-' prefixing options will
    248     be removed.
    249 
    250     ttuple is expected to contain an even number of elements."""
    251     opt_start = 1 if cut_minus else 0
    252 
    253     retdict = {}
    254     it = iter(ttuple)
    255     for opt, val in zip(it, it):
    256         retdict[str(opt)[opt_start:]] = val
    257 
    258     return tclobjs_to_py(retdict)
    259 
    260 def _list_from_statespec(stuple):
    261     """Construct a list from the given statespec tuple according to the
    262     accepted statespec accepted by _format_mapdict."""
    263     nval = []
    264     for val in stuple:
    265         typename = getattr(val, 'typename', None)
    266         if typename is None:
    267             nval.append(val)
    268         else: # this is a Tcl object
    269             val = str(val)
    270             if typename == 'StateSpec':
    271                 val = val.split()
    272             nval.append(val)
    273 
    274     it = iter(nval)
    275     return [_flatten(spec) for spec in zip(it, it)]
    276 
    277 def _list_from_layouttuple(ltuple):
    278     """Construct a list from the tuple returned by ttk::layout, this is
    279     somewhat the reverse of _format_layoutlist."""
    280     res = []
    281 
    282     indx = 0
    283     while indx < len(ltuple):
    284         name = ltuple[indx]
    285         opts = {}
    286         res.append((name, opts))
    287         indx += 1
    288 
    289         while indx < len(ltuple): # grab name's options
    290             opt, val = ltuple[indx:indx + 2]
    291             if not opt.startswith('-'): # found next name
    292                 break
    293 
    294             opt = opt[1:] # remove the '-' from the option
    295             indx += 2
    296 
    297             if opt == 'children':
    298                 val = _list_from_layouttuple(val)
    299 
    300             opts[opt] = val
    301 
    302     return res
    303 
    304 def _val_or_dict(options, func, *args):
    305     """Format options then call func with args and options and return
    306     the appropriate result.
    307 
    308     If no option is specified, a dict is returned. If a option is
    309     specified with the None value, the value for that option is returned.
    310     Otherwise, the function just sets the passed options and the caller
    311     shouldn't be expecting a return value anyway."""
    312     options = _format_optdict(options)
    313     res = func(*(args + options))
    314 
    315     if len(options) % 2: # option specified without a value, return its value
    316         return res
    317 
    318     return _dict_from_tcltuple(res)
    319 
    320 def _convert_stringval(value):
    321     """Converts a value to, hopefully, a more appropriate Python object."""
    322     value = unicode(value)
    323     try:
    324         value = int(value)
    325     except (ValueError, TypeError):
    326         pass
    327 
    328     return value
    329 
    330 def tclobjs_to_py(adict):
    331     """Returns adict with its values converted from Tcl objects to Python
    332     objects."""
    333     for opt, val in adict.iteritems():
    334         if val and hasattr(val, '__len__') and not isinstance(val, basestring):
    335             if getattr(val[0], 'typename', None) == 'StateSpec':
    336                 val = _list_from_statespec(val)
    337             else:
    338                 val = map(_convert_stringval, val)
    339 
    340         elif hasattr(val, 'typename'): # some other (single) Tcl object
    341             val = _convert_stringval(val)
    342 
    343         adict[opt] = val
    344 
    345     return adict
    346 
    347 def setup_master(master=None):
    348     """If master is not None, itself is returned. If master is None,
    349     the default master is returned if there is one, otherwise a new
    350     master is created and returned.
    351 
    352     If it is not allowed to use the default root and master is None,
    353     RuntimeError is raised."""
    354     if master is None:
    355         if Tkinter._support_default_root:
    356             master = Tkinter._default_root or Tkinter.Tk()
    357         else:
    358             raise RuntimeError(
    359                     "No master specified and Tkinter is "
    360                     "configured to not support default root")
    361     return master
    362 
    363 
    364 class Style(object):
    365     """Manipulate style database."""
    366 
    367     _name = "ttk::style"
    368 
    369     def __init__(self, master=None):
    370         master = setup_master(master)
    371 
    372         if not getattr(master, '_tile_loaded', False):
    373             # Load tile now, if needed
    374             _load_tile(master)
    375 
    376         self.master = master
    377         self.tk = self.master.tk
    378 
    379 
    380     def configure(self, style, query_opt=None, **kw):
    381         """Query or sets the default value of the specified option(s) in
    382         style.
    383 
    384         Each key in kw is an option and each value is either a string or
    385         a sequence identifying the value for that option."""
    386         if query_opt is not None:
    387             kw[query_opt] = None
    388         return _val_or_dict(kw, self.tk.call, self._name, "configure", style)
    389 
    390 
    391     def map(self, style, query_opt=None, **kw):
    392         """Query or sets dynamic values of the specified option(s) in
    393         style.
    394 
    395         Each key in kw is an option and each value should be a list or a
    396         tuple (usually) containing statespecs grouped in tuples, or list,
    397         or something else of your preference. A statespec is compound of
    398         one or more states and then a value."""
    399         if query_opt is not None:
    400             return _list_from_statespec(
    401                 self.tk.call(self._name, "map", style, '-%s' % query_opt))
    402 
    403         return _dict_from_tcltuple(
    404             self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))
    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(
    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.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.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.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.call(self._w, "instate", ' '.join(statespec))
    574         if ret and callback:
    575             return callback(*args, **kw)
    576 
    577         return bool(ret)
    578 
    579 
    580     def state(self, statespec=None):
    581         """Modify or inquire widget state.
    582 
    583         Widget state is returned if statespec is None, otherwise it is
    584         set according to the statespec flags and then a new state spec
    585         is returned indicating which flags were changed. statespec is
    586         expected to be a sequence."""
    587         if statespec is not None:
    588             statespec = ' '.join(statespec)
    589 
    590         return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))
    591 
    592 
    593 class Button(Widget):
    594     """Ttk Button widget, displays a textual label and/or image, and
    595     evaluates a command when pressed."""
    596 
    597     def __init__(self, master=None, **kw):
    598         """Construct a Ttk Button widget with the parent master.
    599 
    600         STANDARD OPTIONS
    601 
    602             class, compound, cursor, image, state, style, takefocus,
    603             text, textvariable, underline, width
    604 
    605         WIDGET-SPECIFIC OPTIONS
    606 
    607             command, default, width
    608         """
    609         Widget.__init__(self, master, "ttk::button", kw)
    610 
    611 
    612     def invoke(self):
    613         """Invokes the command associated with the button."""
    614         return self.tk.call(self._w, "invoke")
    615 
    616 
    617 class Checkbutton(Widget):
    618     """Ttk Checkbutton widget which is either in on- or off-state."""
    619 
    620     def __init__(self, master=None, **kw):
    621         """Construct a Ttk Checkbutton widget with the parent master.
    622 
    623         STANDARD OPTIONS
    624 
    625             class, compound, cursor, image, state, style, takefocus,
    626             text, textvariable, underline, width
    627 
    628         WIDGET-SPECIFIC OPTIONS
    629 
    630             command, offvalue, onvalue, variable
    631         """
    632         Widget.__init__(self, master, "ttk::checkbutton", kw)
    633 
    634 
    635     def invoke(self):
    636         """Toggles between the selected and deselected states and
    637         invokes the associated command. If the widget is currently
    638         selected, sets the option variable to the offvalue option
    639         and deselects the widget; otherwise, sets the option variable
    640         to the option onvalue.
    641 
    642         Returns the result of the associated command."""
    643         return self.tk.call(self._w, "invoke")
    644 
    645 
    646 class Entry(Widget, Tkinter.Entry):
    647     """Ttk Entry widget displays a one-line text string and allows that
    648     string to be edited by the user."""
    649 
    650     def __init__(self, master=None, widget=None, **kw):
    651         """Constructs a Ttk Entry widget with the parent master.
    652 
    653         STANDARD OPTIONS
    654 
    655             class, cursor, style, takefocus, xscrollcommand
    656 
    657         WIDGET-SPECIFIC OPTIONS
    658 
    659             exportselection, invalidcommand, justify, show, state,
    660             textvariable, validate, validatecommand, width
    661 
    662         VALIDATION MODES
    663 
    664             none, key, focus, focusin, focusout, all
    665         """
    666         Widget.__init__(self, master, widget or "ttk::entry", kw)
    667 
    668 
    669     def bbox(self, index):
    670         """Return a tuple of (x, y, width, height) which describes the
    671         bounding box of the character given by index."""
    672         return self.tk.call(self._w, "bbox", index)
    673 
    674 
    675     def identify(self, x, y):
    676         """Returns the name of the element at position x, y, or the
    677         empty string if the coordinates are outside the window."""
    678         return self.tk.call(self._w, "identify", x, y)
    679 
    680 
    681     def validate(self):
    682         """Force revalidation, independent of the conditions specified
    683         by the validate option. Returns False if validation fails, True
    684         if it succeeds. Sets or clears the invalid state accordingly."""
    685         return bool(self.tk.call(self._w, "validate"))
    686 
    687 
    688 class Combobox(Entry):
    689     """Ttk Combobox widget combines a text field with a pop-down list of
    690     values."""
    691 
    692     def __init__(self, master=None, **kw):
    693         """Construct a Ttk Combobox widget with the parent master.
    694 
    695         STANDARD OPTIONS
    696 
    697             class, cursor, style, takefocus
    698 
    699         WIDGET-SPECIFIC OPTIONS
    700 
    701             exportselection, justify, height, postcommand, state,
    702             textvariable, values, width
    703         """
    704         Entry.__init__(self, master, "ttk::combobox", **kw)
    705 
    706 
    707     def current(self, newindex=None):
    708         """If newindex is supplied, sets the combobox value to the
    709         element at position newindex in the list of values. Otherwise,
    710         returns the index of the current value in the list of values
    711         or -1 if the current value does not appear in the list."""
    712         return self.tk.call(self._w, "current", newindex)
    713 
    714 
    715     def set(self, value):
    716         """Sets the value of the combobox to value."""
    717         self.tk.call(self._w, "set", value)
    718 
    719 
    720 class Frame(Widget):
    721     """Ttk Frame widget is a container, used to group other widgets
    722     together."""
    723 
    724     def __init__(self, master=None, **kw):
    725         """Construct a Ttk Frame with parent master.
    726 
    727         STANDARD OPTIONS
    728 
    729             class, cursor, style, takefocus
    730 
    731         WIDGET-SPECIFIC OPTIONS
    732 
    733             borderwidth, relief, padding, width, height
    734         """
    735         Widget.__init__(self, master, "ttk::frame", kw)
    736 
    737 
    738 class Label(Widget):
    739     """Ttk Label widget displays a textual label and/or image."""
    740 
    741     def __init__(self, master=None, **kw):
    742         """Construct a Ttk Label with parent master.
    743 
    744         STANDARD OPTIONS
    745 
    746             class, compound, cursor, image, style, takefocus, text,
    747             textvariable, underline, width
    748 
    749         WIDGET-SPECIFIC OPTIONS
    750 
    751             anchor, background, font, foreground, justify, padding,
    752             relief, text, wraplength
    753         """
    754         Widget.__init__(self, master, "ttk::label", kw)
    755 
    756 
    757 class Labelframe(Widget):
    758     """Ttk Labelframe widget is a container used to group other widgets
    759     together. It has an optional label, which may be a plain text string
    760     or another widget."""
    761 
    762     def __init__(self, master=None, **kw):
    763         """Construct a Ttk Labelframe with parent master.
    764 
    765         STANDARD OPTIONS
    766 
    767             class, cursor, style, takefocus
    768 
    769         WIDGET-SPECIFIC OPTIONS
    770             labelanchor, text, underline, padding, labelwidget, width,
    771             height
    772         """
    773         Widget.__init__(self, master, "ttk::labelframe", kw)
    774 
    775 LabelFrame = Labelframe # Tkinter name compatibility
    776 
    777 
    778 class Menubutton(Widget):
    779     """Ttk Menubutton widget displays a textual label and/or image, and
    780     displays a menu when pressed."""
    781 
    782     def __init__(self, master=None, **kw):
    783         """Construct a Ttk Menubutton with parent master.
    784 
    785         STANDARD OPTIONS
    786 
    787             class, compound, cursor, image, state, style, takefocus,
    788             text, textvariable, underline, width
    789 
    790         WIDGET-SPECIFIC OPTIONS
    791 
    792             direction, menu
    793         """
    794         Widget.__init__(self, master, "ttk::menubutton", kw)
    795 
    796 
    797 class Notebook(Widget):
    798     """Ttk Notebook widget manages a collection of windows and displays
    799     a single one at a time. Each child window is associated with a tab,
    800     which the user may select to change the currently-displayed window."""
    801 
    802     def __init__(self, master=None, **kw):
    803         """Construct a Ttk Notebook with parent master.
    804 
    805         STANDARD OPTIONS
    806 
    807             class, cursor, style, takefocus
    808 
    809         WIDGET-SPECIFIC OPTIONS
    810 
    811             height, padding, width
    812 
    813         TAB OPTIONS
    814 
    815             state, sticky, padding, text, image, compound, underline
    816 
    817         TAB IDENTIFIERS (tab_id)
    818 
    819             The tab_id argument found in several methods may take any of
    820             the following forms:
    821 
    822                 * An integer between zero and the number of tabs
    823                 * The name of a child window
    824                 * A positional specification of the form "@x,y", which
    825                   defines the tab
    826                 * The string "current", which identifies the
    827                   currently-selected tab
    828                 * The string "end", which returns the number of tabs (only
    829                   valid for method index)
    830         """
    831         Widget.__init__(self, master, "ttk::notebook", kw)
    832 
    833 
    834     def add(self, child, **kw):
    835         """Adds a new tab to the notebook.
    836 
    837         If window is currently managed by the notebook but hidden, it is
    838         restored to its previous position."""
    839         self.tk.call(self._w, "add", child, *(_format_optdict(kw)))
    840 
    841 
    842     def forget(self, tab_id):
    843         """Removes the tab specified by tab_id, unmaps and unmanages the
    844         associated window."""
    845         self.tk.call(self._w, "forget", tab_id)
    846 
    847 
    848     def hide(self, tab_id):
    849         """Hides the tab specified by tab_id.
    850 
    851         The tab will not be displayed, but the associated window remains
    852         managed by the notebook and its configuration remembered. Hidden
    853         tabs may be restored with the add command."""
    854         self.tk.call(self._w, "hide", tab_id)
    855 
    856 
    857     def identify(self, x, y):
    858         """Returns the name of the tab element at position x, y, or the
    859         empty string if none."""
    860         return self.tk.call(self._w, "identify", x, y)
    861 
    862 
    863     def index(self, tab_id):
    864         """Returns the numeric index of the tab specified by tab_id, or
    865         the total number of tabs if tab_id is the string "end"."""
    866         return self.tk.call(self._w, "index", tab_id)
    867 
    868 
    869     def insert(self, pos, child, **kw):
    870         """Inserts a pane at the specified position.
    871 
    872         pos is either the string end, an integer index, or the name of
    873         a managed child. If child is already managed by the notebook,
    874         moves it to the specified position."""
    875         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
    876 
    877 
    878     def select(self, tab_id=None):
    879         """Selects the specified tab.
    880 
    881         The associated child window will be displayed, and the
    882         previously-selected window (if different) is unmapped. If tab_id
    883         is omitted, returns the widget name of the currently selected
    884         pane."""
    885         return self.tk.call(self._w, "select", tab_id)
    886 
    887 
    888     def tab(self, tab_id, option=None, **kw):
    889         """Query or modify the options of the specific tab_id.
    890 
    891         If kw is not given, returns a dict of the tab option values. If option
    892         is specified, returns the value of that option. Otherwise, sets the
    893         options to the corresponding values."""
    894         if option is not None:
    895             kw[option] = None
    896         return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id)
    897 
    898 
    899     def tabs(self):
    900         """Returns a list of windows managed by the notebook."""
    901         return self.tk.call(self._w, "tabs") or ()
    902 
    903 
    904     def enable_traversal(self):
    905         """Enable keyboard traversal for a toplevel window containing
    906         this notebook.
    907 
    908         This will extend the bindings for the toplevel window containing
    909         this notebook as follows:
    910 
    911             Control-Tab: selects the tab following the currently selected
    912                          one
    913 
    914             Shift-Control-Tab: selects the tab preceding the currently
    915                                selected one
    916 
    917             Alt-K: where K is the mnemonic (underlined) character of any
    918                    tab, will select that tab.
    919 
    920         Multiple notebooks in a single toplevel may be enabled for
    921         traversal, including nested notebooks. However, notebook traversal
    922         only works properly if all panes are direct children of the
    923         notebook."""
    924         # The only, and good, difference I see is about mnemonics, which works
    925         # after calling this method. Control-Tab and Shift-Control-Tab always
    926         # works (here at least).
    927         self.tk.call("ttk::notebook::enableTraversal", self._w)
    928 
    929 
    930 class Panedwindow(Widget, Tkinter.PanedWindow):
    931     """Ttk Panedwindow widget displays a number of subwindows, stacked
    932     either vertically or horizontally."""
    933 
    934     def __init__(self, master=None, **kw):
    935         """Construct a Ttk Panedwindow with parent master.
    936 
    937         STANDARD OPTIONS
    938 
    939             class, cursor, style, takefocus
    940 
    941         WIDGET-SPECIFIC OPTIONS
    942 
    943             orient, width, height
    944 
    945         PANE OPTIONS
    946 
    947             weight
    948         """
    949         Widget.__init__(self, master, "ttk::panedwindow", kw)
    950 
    951 
    952     forget = Tkinter.PanedWindow.forget # overrides Pack.forget
    953 
    954 
    955     def insert(self, pos, child, **kw):
    956         """Inserts a pane at the specified positions.
    957 
    958         pos is either the string end, and integer index, or the name
    959         of a child. If child is already managed by the paned window,
    960         moves it to the specified position."""
    961         self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
    962 
    963 
    964     def pane(self, pane, option=None, **kw):
    965         """Query or modify the options of the specified pane.
    966 
    967         pane is either an integer index or the name of a managed subwindow.
    968         If kw is not given, returns a dict of the pane option values. If
    969         option is specified then the value for that option is returned.
    970         Otherwise, sets the options to the corresponding values."""
    971         if option is not None:
    972             kw[option] = None
    973         return _val_or_dict(kw, self.tk.call, self._w, "pane", pane)
    974 
    975 
    976     def sashpos(self, index, newpos=None):
    977         """If newpos is specified, sets the position of sash number index.
    978 
    979         May adjust the positions of adjacent sashes to ensure that
    980         positions are monotonically increasing. Sash positions are further
    981         constrained to be between 0 and the total size of the widget.
    982 
    983         Returns the new position of sash number index."""
    984         return self.tk.call(self._w, "sashpos", index, newpos)
    985 
    986 PanedWindow = Panedwindow # Tkinter name compatibility
    987 
    988 
    989 class Progressbar(Widget):
    990     """Ttk Progressbar widget shows the status of a long-running
    991     operation. They can operate in two modes: determinate mode shows the
    992     amount completed relative to the total amount of work to be done, and
    993     indeterminate mode provides an animated display to let the user know
    994     that something is happening."""
    995 
    996     def __init__(self, master=None, **kw):
    997         """Construct a Ttk Progressbar with parent master.
    998 
    999         STANDARD OPTIONS
   1000 
   1001             class, cursor, style, takefocus
   1002 
   1003         WIDGET-SPECIFIC OPTIONS
   1004 
   1005             orient, length, mode, maximum, value, variable, phase
   1006         """
   1007         Widget.__init__(self, master, "ttk::progressbar", kw)
   1008 
   1009 
   1010     def start(self, interval=None):
   1011         """Begin autoincrement mode: schedules a recurring timer event
   1012         that calls method step every interval milliseconds.
   1013 
   1014         interval defaults to 50 milliseconds (20 steps/second) if ommited."""
   1015         self.tk.call(self._w, "start", interval)
   1016 
   1017 
   1018     def step(self, amount=None):
   1019         """Increments the value option by amount.
   1020 
   1021         amount defaults to 1.0 if omitted."""
   1022         self.tk.call(self._w, "step", amount)
   1023 
   1024 
   1025     def stop(self):
   1026         """Stop autoincrement mode: cancels any recurring timer event
   1027         initiated by start."""
   1028         self.tk.call(self._w, "stop")
   1029 
   1030 
   1031 class Radiobutton(Widget):
   1032     """Ttk Radiobutton widgets are used in groups to show or change a
   1033     set of mutually-exclusive options."""
   1034 
   1035     def __init__(self, master=None, **kw):
   1036         """Construct a Ttk Radiobutton with parent master.
   1037 
   1038         STANDARD OPTIONS
   1039 
   1040             class, compound, cursor, image, state, style, takefocus,
   1041             text, textvariable, underline, width
   1042 
   1043         WIDGET-SPECIFIC OPTIONS
   1044 
   1045             command, value, variable
   1046         """
   1047         Widget.__init__(self, master, "ttk::radiobutton", kw)
   1048 
   1049 
   1050     def invoke(self):
   1051         """Sets the option variable to the option value, selects the
   1052         widget, and invokes the associated command.
   1053 
   1054         Returns the result of the command, or an empty string if
   1055         no command is specified."""
   1056         return self.tk.call(self._w, "invoke")
   1057 
   1058 
   1059 class Scale(Widget, Tkinter.Scale):
   1060     """Ttk Scale widget is typically used to control the numeric value of
   1061     a linked variable that varies uniformly over some range."""
   1062 
   1063     def __init__(self, master=None, **kw):
   1064         """Construct a Ttk Scale with parent master.
   1065 
   1066         STANDARD OPTIONS
   1067 
   1068             class, cursor, style, takefocus
   1069 
   1070         WIDGET-SPECIFIC OPTIONS
   1071 
   1072             command, from, length, orient, to, value, variable
   1073         """
   1074         Widget.__init__(self, master, "ttk::scale", kw)
   1075 
   1076 
   1077     def configure(self, cnf=None, **kw):
   1078         """Modify or query scale options.
   1079 
   1080         Setting a value for any of the "from", "from_" or "to" options
   1081         generates a <<RangeChanged>> event."""
   1082         if cnf:
   1083             kw.update(cnf)
   1084         Widget.configure(self, **kw)
   1085         if any(['from' in kw, 'from_' in kw, 'to' in kw]):
   1086             self.event_generate('<<RangeChanged>>')
   1087 
   1088 
   1089     def get(self, x=None, y=None):
   1090         """Get the current value of the value option, or the value
   1091         corresponding to the coordinates x, y if they are specified.
   1092 
   1093         x and y are pixel coordinates relative to the scale widget
   1094         origin."""
   1095         return self.tk.call(self._w, 'get', x, y)
   1096 
   1097 
   1098 class Scrollbar(Widget, Tkinter.Scrollbar):
   1099     """Ttk Scrollbar controls the viewport of a scrollable widget."""
   1100 
   1101     def __init__(self, master=None, **kw):
   1102         """Construct a Ttk Scrollbar with parent master.
   1103 
   1104         STANDARD OPTIONS
   1105 
   1106             class, cursor, style, takefocus
   1107 
   1108         WIDGET-SPECIFIC OPTIONS
   1109 
   1110             command, orient
   1111         """
   1112         Widget.__init__(self, master, "ttk::scrollbar", kw)
   1113 
   1114 
   1115 class Separator(Widget):
   1116     """Ttk Separator widget displays a horizontal or vertical separator
   1117     bar."""
   1118 
   1119     def __init__(self, master=None, **kw):
   1120         """Construct a Ttk Separator with parent master.
   1121 
   1122         STANDARD OPTIONS
   1123 
   1124             class, cursor, style, takefocus
   1125 
   1126         WIDGET-SPECIFIC OPTIONS
   1127 
   1128             orient
   1129         """
   1130         Widget.__init__(self, master, "ttk::separator", kw)
   1131 
   1132 
   1133 class Sizegrip(Widget):
   1134     """Ttk Sizegrip allows the user to resize the containing toplevel
   1135     window by pressing and dragging the grip."""
   1136 
   1137     def __init__(self, master=None, **kw):
   1138         """Construct a Ttk Sizegrip with parent master.
   1139 
   1140         STANDARD OPTIONS
   1141 
   1142             class, cursor, state, style, takefocus
   1143         """
   1144         Widget.__init__(self, master, "ttk::sizegrip", kw)
   1145 
   1146 
   1147 class Treeview(Widget, Tkinter.XView, Tkinter.YView):
   1148     """Ttk Treeview widget displays a hierarchical collection of items.
   1149 
   1150     Each item has a textual label, an optional image, and an optional list
   1151     of data values. The data values are displayed in successive columns
   1152     after the tree label."""
   1153 
   1154     def __init__(self, master=None, **kw):
   1155         """Construct a Ttk Treeview with parent master.
   1156 
   1157         STANDARD OPTIONS
   1158 
   1159             class, cursor, style, takefocus, xscrollcommand,
   1160             yscrollcommand
   1161 
   1162         WIDGET-SPECIFIC OPTIONS
   1163 
   1164             columns, displaycolumns, height, padding, selectmode, show
   1165 
   1166         ITEM OPTIONS
   1167 
   1168             text, image, values, open, tags
   1169 
   1170         TAG OPTIONS
   1171 
   1172             foreground, background, font, image
   1173         """
   1174         Widget.__init__(self, master, "ttk::treeview", kw)
   1175 
   1176 
   1177     def bbox(self, item, column=None):
   1178         """Returns the bounding box (relative to the treeview widget's
   1179         window) of the specified item in the form x y width height.
   1180 
   1181         If column is specified, returns the bounding box of that cell.
   1182         If the item is not visible (i.e., if it is a descendant of a
   1183         closed item or is scrolled offscreen), returns an empty string."""
   1184         return self.tk.call(self._w, "bbox", item, column)
   1185 
   1186 
   1187     def get_children(self, item=None):
   1188         """Returns a tuple of children belonging to item.
   1189 
   1190         If item is not specified, returns root children."""
   1191         return self.tk.call(self._w, "children", item or '') or ()
   1192 
   1193 
   1194     def set_children(self, item, *newchildren):
   1195         """Replaces item's child with newchildren.
   1196 
   1197         Children present in item that are not present in newchildren
   1198         are detached from tree. No items in newchildren may be an
   1199         ancestor of item."""
   1200         self.tk.call(self._w, "children", item, newchildren)
   1201 
   1202 
   1203     def column(self, column, option=None, **kw):
   1204         """Query or modify the options for the specified column.
   1205 
   1206         If kw is not given, returns a dict of the column option values. If
   1207         option is specified then the value for that option is returned.
   1208         Otherwise, sets the options to the corresponding values."""
   1209         if option is not None:
   1210             kw[option] = None
   1211         return _val_or_dict(kw, self.tk.call, self._w, "column", column)
   1212 
   1213 
   1214     def delete(self, *items):
   1215         """Delete all specified items and all their descendants. The root
   1216         item may not be deleted."""
   1217         self.tk.call(self._w, "delete", items)
   1218 
   1219 
   1220     def detach(self, *items):
   1221         """Unlinks all of the specified items from the tree.
   1222 
   1223         The items and all of their descendants are still present, and may
   1224         be reinserted at another point in the tree, but will not be
   1225         displayed. The root item may not be detached."""
   1226         self.tk.call(self._w, "detach", items)
   1227 
   1228 
   1229     def exists(self, item):
   1230         """Returns True if the specified item is present in the tree,
   1231         False otherwise."""
   1232         return bool(self.tk.call(self._w, "exists", item))
   1233 
   1234 
   1235     def focus(self, item=None):
   1236         """If item is specified, sets the focus item to item. Otherwise,
   1237         returns the current focus item, or '' if there is none."""
   1238         return self.tk.call(self._w, "focus", item)
   1239 
   1240 
   1241     def heading(self, column, option=None, **kw):
   1242         """Query or modify the heading options for the specified column.
   1243 
   1244         If kw is not given, returns a dict of the heading option values. If
   1245         option is specified then the value for that option is returned.
   1246         Otherwise, sets the options to the corresponding values.
   1247 
   1248         Valid options/values are:
   1249             text: text
   1250                 The text to display in the column heading
   1251             image: image_name
   1252                 Specifies an image to display to the right of the column
   1253                 heading
   1254             anchor: anchor
   1255                 Specifies how the heading text should be aligned. One of
   1256                 the standard Tk anchor values
   1257             command: callback
   1258                 A callback to be invoked when the heading label is
   1259                 pressed.
   1260 
   1261         To configure the tree column heading, call this with column = "#0" """
   1262         cmd = kw.get('command')
   1263         if cmd and not isinstance(cmd, basestring):
   1264             # callback not registered yet, do it now
   1265             kw['command'] = self.master.register(cmd, self._substitute)
   1266 
   1267         if option is not None:
   1268             kw[option] = None
   1269 
   1270         return _val_or_dict(kw, self.tk.call, self._w, 'heading', column)
   1271 
   1272 
   1273     def identify(self, component, x, y):
   1274         """Returns a description of the specified component under the
   1275         point given by x and y, or the empty string if no such component
   1276         is present at that position."""
   1277         return self.tk.call(self._w, "identify", component, x, y)
   1278 
   1279 
   1280     def identify_row(self, y):
   1281         """Returns the item ID of the item at position y."""
   1282         return self.identify("row", 0, y)
   1283 
   1284 
   1285     def identify_column(self, x):
   1286         """Returns the data column identifier of the cell at position x.
   1287 
   1288         The tree column has ID #0."""
   1289         return self.identify("column", x, 0)
   1290 
   1291 
   1292     def identify_region(self, x, y):
   1293         """Returns one of:
   1294 
   1295         heading: Tree heading area.
   1296         separator: Space between two columns headings;
   1297         tree: The tree area.
   1298         cell: A data cell.
   1299 
   1300         * Availability: Tk 8.6"""
   1301         return self.identify("region", x, y)
   1302 
   1303 
   1304     def identify_element(self, x, y):
   1305         """Returns the element at position x, y.
   1306 
   1307         * Availability: Tk 8.6"""
   1308         return self.identify("element", x, y)
   1309 
   1310 
   1311     def index(self, item):
   1312         """Returns the integer index of item within its parent's list
   1313         of children."""
   1314         return self.tk.call(self._w, "index", item)
   1315 
   1316 
   1317     def insert(self, parent, index, iid=None, **kw):
   1318         """Creates a new item and return the item identifier of the newly
   1319         created item.
   1320 
   1321         parent is the item ID of the parent item, or the empty string
   1322         to create a new top-level item. index is an integer, or the value
   1323         end, specifying where in the list of parent's children to insert
   1324         the new item. If index is less than or equal to zero, the new node
   1325         is inserted at the beginning, if index is greater than or equal to
   1326         the current number of children, it is inserted at the end. If iid
   1327         is specified, it is used as the item identifier, iid must not
   1328         already exist in the tree. Otherwise, a new unique identifier
   1329         is generated."""
   1330         opts = _format_optdict(kw)
   1331         if iid:
   1332             res = self.tk.call(self._w, "insert", parent, index,
   1333                 "-id", iid, *opts)
   1334         else:
   1335             res = self.tk.call(self._w, "insert", parent, index, *opts)
   1336 
   1337         return res
   1338 
   1339 
   1340     def item(self, item, option=None, **kw):
   1341         """Query or modify the options for the specified item.
   1342 
   1343         If no options are given, a dict with options/values for the item
   1344         is returned. If option is specified then the value for that option
   1345         is returned. Otherwise, sets the options to the corresponding
   1346         values as given by kw."""
   1347         if option is not None:
   1348             kw[option] = None
   1349         return _val_or_dict(kw, self.tk.call, self._w, "item", item)
   1350 
   1351 
   1352     def move(self, item, parent, index):
   1353         """Moves item to position index in parent's list of children.
   1354 
   1355         It is illegal to move an item under one of its descendants. If
   1356         index is less than or equal to zero, item is moved to the
   1357         beginning, if greater than or equal to the number of children,
   1358         it is moved to the end. If item was detached it is reattached."""
   1359         self.tk.call(self._w, "move", item, parent, index)
   1360 
   1361     reattach = move # A sensible method name for reattaching detached items
   1362 
   1363 
   1364     def next(self, item):
   1365         """Returns the identifier of item's next sibling, or '' if item
   1366         is the last child of its parent."""
   1367         return self.tk.call(self._w, "next", item)
   1368 
   1369 
   1370     def parent(self, item):
   1371         """Returns the ID of the parent of item, or '' if item is at the
   1372         top level of the hierarchy."""
   1373         return self.tk.call(self._w, "parent", item)
   1374 
   1375 
   1376     def prev(self, item):
   1377         """Returns the identifier of item's previous sibling, or '' if
   1378         item is the first child of its parent."""
   1379         return self.tk.call(self._w, "prev", item)
   1380 
   1381 
   1382     def see(self, item):
   1383         """Ensure that item is visible.
   1384 
   1385         Sets all of item's ancestors open option to True, and scrolls
   1386         the widget if necessary so that item is within the visible
   1387         portion of the tree."""
   1388         self.tk.call(self._w, "see", item)
   1389 
   1390 
   1391     def selection(self, selop=None, items=None):
   1392         """If selop is not specified, returns selected items."""
   1393         return self.tk.call(self._w, "selection", selop, items)
   1394 
   1395 
   1396     def selection_set(self, items):
   1397         """items becomes the new selection."""
   1398         self.selection("set", items)
   1399 
   1400 
   1401     def selection_add(self, items):
   1402         """Add items to the selection."""
   1403         self.selection("add", items)
   1404 
   1405 
   1406     def selection_remove(self, items):
   1407         """Remove items from the selection."""
   1408         self.selection("remove", items)
   1409 
   1410 
   1411     def selection_toggle(self, items):
   1412         """Toggle the selection state of each item in items."""
   1413         self.selection("toggle", items)
   1414 
   1415 
   1416     def set(self, item, column=None, value=None):
   1417         """With one argument, returns a dictionary of column/value pairs
   1418         for the specified item. With two arguments, returns the current
   1419         value of the specified column. With three arguments, sets the
   1420         value of given column in given item to the specified value."""
   1421         res = self.tk.call(self._w, "set", item, column, value)
   1422         if column is None and value is None:
   1423             return _dict_from_tcltuple(res, False)
   1424         else:
   1425             return res
   1426 
   1427 
   1428     def tag_bind(self, tagname, sequence=None, callback=None):
   1429         """Bind a callback for the given event sequence to the tag tagname.
   1430         When an event is delivered to an item, the callbacks for each
   1431         of the item's tags option are called."""
   1432         self._bind((self._w, "tag", "bind", tagname), sequence, callback, add=0)
   1433 
   1434 
   1435     def tag_configure(self, tagname, option=None, **kw):
   1436         """Query or modify the options for the specified tagname.
   1437 
   1438         If kw is not given, returns a dict of the option settings for tagname.
   1439         If option is specified, returns the value for that option for the
   1440         specified tagname. Otherwise, sets the options to the corresponding
   1441         values for the given tagname."""
   1442         if option is not None:
   1443             kw[option] = None
   1444         return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure",
   1445             tagname)
   1446 
   1447 
   1448     def tag_has(self, tagname, item=None):
   1449         """If item is specified, returns 1 or 0 depending on whether the
   1450         specified item has the given tagname. Otherwise, returns a list of
   1451         all items which have the specified tag.
   1452 
   1453         * Availability: Tk 8.6"""
   1454         return self.tk.call(self._w, "tag", "has", tagname, item)
   1455 
   1456 
   1457 # Extensions
   1458 
   1459 class LabeledScale(Frame, object):
   1460     """A Ttk Scale widget with a Ttk Label widget indicating its
   1461     current value.
   1462 
   1463     The Ttk Scale can be accessed through instance.scale, and Ttk Label
   1464     can be accessed through instance.label"""
   1465 
   1466     def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
   1467         """Construct an horizontal LabeledScale with parent master, a
   1468         variable to be associated with the Ttk Scale widget and its range.
   1469         If variable is not specified, a Tkinter.IntVar is created.
   1470 
   1471         WIDGET-SPECIFIC OPTIONS
   1472 
   1473             compound: 'top' or 'bottom'
   1474                 Specifies how to display the label relative to the scale.
   1475                 Defaults to 'top'.
   1476         """
   1477         self._label_top = kw.pop('compound', 'top') == 'top'
   1478 
   1479         Frame.__init__(self, master, **kw)
   1480         self._variable = variable or Tkinter.IntVar(master)
   1481         self._variable.set(from_)
   1482         self._last_valid = from_
   1483 
   1484         self.label = Label(self)
   1485         self.scale = Scale(self, variable=self._variable, from_=from_, to=to)
   1486         self.scale.bind('<<RangeChanged>>', self._adjust)
   1487 
   1488         # position scale and label according to the compound option
   1489         scale_side = 'bottom' if self._label_top else 'top'
   1490         label_side = 'top' if scale_side == 'bottom' else 'bottom'
   1491         self.scale.pack(side=scale_side, fill='x')
   1492         tmp = Label(self).pack(side=label_side) # place holder
   1493         self.label.place(anchor='n' if label_side == 'top' else 's')
   1494 
   1495         # update the label as scale or variable changes
   1496         self.__tracecb = self._variable.trace_variable('w', self._adjust)
   1497         self.bind('<Configure>', self._adjust)
   1498         self.bind('<Map>', self._adjust)
   1499 
   1500 
   1501     def destroy(self):
   1502         """Destroy this widget and possibly its associated variable."""
   1503         try:
   1504             self._variable.trace_vdelete('w', self.__tracecb)
   1505         except AttributeError:
   1506             # widget has been destroyed already
   1507             pass
   1508         else:
   1509             del self._variable
   1510             Frame.destroy(self)
   1511 
   1512 
   1513     def _adjust(self, *args):
   1514         """Adjust the label position according to the scale."""
   1515         def adjust_label():
   1516             self.update_idletasks() # "force" scale redraw
   1517 
   1518             x, y = self.scale.coords()
   1519             if self._label_top:
   1520                 y = self.scale.winfo_y() - self.label.winfo_reqheight()
   1521             else:
   1522                 y = self.scale.winfo_reqheight() + self.label.winfo_reqheight()
   1523 
   1524             self.label.place_configure(x=x, y=y)
   1525 
   1526         from_, to = self.scale['from'], self.scale['to']
   1527         if to < from_:
   1528             from_, to = to, from_
   1529         newval = self._variable.get()
   1530         if not from_ <= newval <= to:
   1531             # value outside range, set value back to the last valid one
   1532             self.value = self._last_valid
   1533             return
   1534 
   1535         self._last_valid = newval
   1536         self.label['text'] = newval
   1537         self.after_idle(adjust_label)
   1538 
   1539 
   1540     def _get_value(self):
   1541         """Return current scale value."""
   1542         return self._variable.get()
   1543 
   1544 
   1545     def _set_value(self, val):
   1546         """Set new scale value."""
   1547         self._variable.set(val)
   1548 
   1549 
   1550     value = property(_get_value, _set_value)
   1551 
   1552 
   1553 class OptionMenu(Menubutton):
   1554     """Themed OptionMenu, based after Tkinter's OptionMenu, which allows
   1555     the user to select a value from a menu."""
   1556 
   1557     def __init__(self, master, variable, default=None, *values, **kwargs):
   1558         """Construct a themed OptionMenu widget with master as the parent,
   1559         the resource textvariable set to variable, the initially selected
   1560         value specified by the default parameter, the menu values given by
   1561         *values and additional keywords.
   1562 
   1563         WIDGET-SPECIFIC OPTIONS
   1564 
   1565             style: stylename
   1566                 Menubutton style.
   1567             direction: 'above', 'below', 'left', 'right', or 'flush'
   1568                 Menubutton direction.
   1569             command: callback
   1570                 A callback that will be invoked after selecting an item.
   1571         """
   1572         kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
   1573               'direction': kwargs.pop('direction', None)}
   1574         Menubutton.__init__(self, master, **kw)
   1575         self['menu'] = Tkinter.Menu(self, tearoff=False)
   1576 
   1577         self._variable = variable
   1578         self._callback = kwargs.pop('command', None)
   1579         if kwargs:
   1580             raise Tkinter.TclError('unknown option -%s' % (
   1581                 kwargs.iterkeys().next()))
   1582 
   1583         self.set_menu(default, *values)
   1584 
   1585 
   1586     def __getitem__(self, item):
   1587         if item == 'menu':
   1588             return self.nametowidget(Menubutton.__getitem__(self, item))
   1589 
   1590         return Menubutton.__getitem__(self, item)
   1591 
   1592 
   1593     def set_menu(self, default=None, *values):
   1594         """Build a new menu of radiobuttons with *values and optionally
   1595         a default value."""
   1596         menu = self['menu']
   1597         menu.delete(0, 'end')
   1598         for val in values:
   1599             menu.add_radiobutton(label=val,
   1600                 command=Tkinter._setit(self._variable, val, self._callback))
   1601 
   1602         if default:
   1603             self._variable.set(default)
   1604 
   1605 
   1606     def destroy(self):
   1607         """Destroy this widget and its associated variable."""
   1608         del self._variable
   1609         Menubutton.destroy(self)
   1610