[Python-checkins] r69050 - in python/trunk: Doc/library/tk.rst Doc/library/ttk.rst Lib/lib-tk/test Lib/lib-tk/test/README Lib/lib-tk/test/runtktests.py Lib/lib-tk/test/test_ttk Lib/lib-tk/test/test_ttk/__init__.py Lib/lib-tk/test/test_ttk/support.py Lib/lib-tk/test/test_ttk/test_extensions.py Lib/lib-tk/test/test_ttk/test_functions.py Lib/lib-tk/test/test_ttk/test_style.py Lib/lib-tk/test/test_ttk/test_widgets.py Lib/lib-tk/ttk.py Lib/test/test_tk_guionly.py Lib/test/test_tk_textonly.py Misc/NEWS

guilherme.polo python-checkins at python.org
Wed Jan 28 14:09:04 CET 2009


Author: guilherme.polo
Date: Wed Jan 28 14:09:03 2009
New Revision: 69050

Log:
Added the ttk module. See issue #2983: Ttk support for Tkinter.


Added:
   python/trunk/Doc/library/ttk.rst   (contents, props changed)
   python/trunk/Lib/lib-tk/test/
   python/trunk/Lib/lib-tk/test/README
   python/trunk/Lib/lib-tk/test/runtktests.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/   (props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/__init__.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/support.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/test_extensions.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/test_functions.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/test_style.py   (contents, props changed)
   python/trunk/Lib/lib-tk/test/test_ttk/test_widgets.py   (contents, props changed)
   python/trunk/Lib/lib-tk/ttk.py   (contents, props changed)
   python/trunk/Lib/test/test_tk_guionly.py   (contents, props changed)
   python/trunk/Lib/test/test_tk_textonly.py   (contents, props changed)
Modified:
   python/trunk/Doc/library/tk.rst
   python/trunk/Misc/NEWS

Modified: python/trunk/Doc/library/tk.rst
==============================================================================
--- python/trunk/Doc/library/tk.rst	(original)
+++ python/trunk/Doc/library/tk.rst	Wed Jan 28 14:09:03 2009
@@ -12,7 +12,8 @@
 
 Tk/Tcl has long been an integral part of Python.  It provides a robust and
 platform independent windowing toolkit, that is available to Python programmers
-using the :mod:`Tkinter` module, and its extension, the :mod:`Tix` module.
+using the :mod:`Tkinter` module, and its extensions, the :mod:`Tix` and
+the :mod:`ttk` modules.
 
 The :mod:`Tkinter` module is a thin object-oriented layer on top of Tcl/Tk. To
 use :mod:`Tkinter`, you don't need to write Tcl code, but you will need to
@@ -32,6 +33,7 @@
 .. toctree::
 
    tkinter.rst
+   ttk.rst
    tix.rst
    scrolledtext.rst
    turtle.rst

Added: python/trunk/Doc/library/ttk.rst
==============================================================================
--- (empty file)
+++ python/trunk/Doc/library/ttk.rst	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,1399 @@
+:mod:`ttk` --- Tk themed widgets
+================================
+
+.. module:: ttk
+   :synopsis: Tk themed widget set
+.. sectionauthor:: Guilherme Polo <ggpolo at gmail.com>
+
+
+.. index:: single: ttk
+
+The :mod:`ttk` module provides access to the Tk themed widget set, which
+has been introduced in Tk 8.5. If you do not have Python compiled against
+Tk 8.5 you may still use this module as long as you have Tile installed, but
+then you will miss some features provided by the new Tk, like anti-aliased font
+rendering under X11, window transparency (on X11 you will need a composition
+window manager) and others.
+
+The basic idea of :mod:`ttk` is to separate, to the extent possible, the code
+implementing a widget's behavior from the code implementing its appearance.
+
+
+.. seealso::
+
+   `Tk Widget Styling Support <http://www.tcl.tk/cgi-bin/tct/tip/48>`_
+      The document which brought up theming support for Tk
+
+
+Using Ttk
+---------
+
+Basically, to start using Ttk, you have to import its module::
+
+   import ttk
+
+But if you already have some code that does::
+
+   from Tkinter import *
+
+You may optionally want to use::
+
+   from Tkinter import *
+   from ttk import *
+
+And then several :mod:`ttk` widgets (:class:`Button`, :class:`Checkbutton`,
+:class:`Entry`, :class:`Frame`, :class:`Label`, :class:`LabelFrame`,
+:class:`Menubutton`, :class:`PanedWindow`, :class:`Radiobutton`, :class:`Scale`
+and :class:`Scrollbar`) will automatically substitute the Tk widgets.
+
+This has the direct benefit of using the new widgets which gives better
+look & feel across platforms, but you should be aware that they are not
+totally compatible. The main difference you will find out is that widget
+options such as "fg", "bg" and others related to widget styling are no
+longer present in Ttk widgets, instead you will have to use :class:`ttk.Style`
+to achieve the same (or better) styling.
+
+.. seealso::
+
+   `Converting existing applications to use the Tile widgets <http://tktable.sourceforge.net/tile/doc/converting.txt>`_
+     A text which talks in Tcl terms about differences typically found when
+     moving applications to use the new widgets.
+
+
+Ttk Widgets
+-----------
+
+Ttk comes with 17 widgets, where 11 of these already existed in Tkinter:
+:class:`Button`, :class:`Checkbutton`, :class:`Entry`, :class:`Frame`,
+:class:`Label`, :class:`LabelFrame`, :class:`Menubutton`, :class:`PanedWindow`,
+:class:`Radiobutton`, :class:`Scale` and :class:`Scrollbar`. The others 6 are
+new: :class:`Combobox`, :class:`Notebook`, :class:`Progressbar`,
+:class:`Separator`, :class:`Sizegrip` and :class:`Treeview`. And all them are
+subclasses of :class:`Widget`.
+
+Like it was told before, you will notice changes in look & feel as well in the
+styling code. To demonstrate the latter, a very simple example is shown below.
+
+Tk code::
+
+   l1 = Tkinter.Label(text="Test", fg="black", bg="white")
+   l2 = Tkinter.Label(text="Test", fg="black", bg="white")
+
+
+Ttk code::
+
+   style = ttk.Style()
+   style.configure("BW.TLabel", foreground="black", background="white")
+
+   l1 = ttk.Label(text="Test", style="BW.TLabel")
+   l2 = ttk.Label(text="Test", style="BW.TLabel")
+
+For more information about TtkStyling_ read the :class:`Style` class
+documentation.
+
+Widget
+------
+
+:class:`ttk.Widget` defines standard options and methods supported by Tk
+themed widgets and is not supposed to be directly instantiated.
+
+
+Standard Options
+^^^^^^^^^^^^^^^^
+
+All the :mod:`ttk` Widgets accepts the following options:
+
+   +-----------+--------------------------------------------------------------+
+   | Option    | Description                                                  |
+   +===========+==============================================================+
+   | class     | Specifies the window class. The class is used when querying  |
+   |           | the option database for the window's other options, to       |
+   |           | determine the default bindtags for the window, and to select |
+   |           | the widget's default layout and style. This is a read-only   |
+   |           | which may only be specified when the window is created       |
+   +-----------+--------------------------------------------------------------+
+   | cursor    | Specifies the mouse cursor to be used for the widget. If set |
+   |           | to the empty string (the default), the cursor is inherited   |
+   |           | for the parent widget.                                       |
+   +-----------+--------------------------------------------------------------+
+   | takefocus | Determines whether the window accepts the focus during       |
+   |           | keyboard traversal. 0, 1 or an empty is return. If 0 is      |
+   |           | returned, it means that the window should be skipped entirely|
+   |           | during keyboard traversal. If 1, it means that the window    |
+   |           | should receive the input focus as long as it is viewable. And|
+   |           | an empty string means that the traversal scripts make the    |
+   |           | decision about whether or not to focus on the window.        |
+   +-----------+--------------------------------------------------------------+
+   | style     | May be used to specify a custom widget style.                |
+   +-----------+--------------------------------------------------------------+
+
+
+Scrollable Widget Options
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following options are supported by widgets that are controlled by a
+scrollbar.
+
+   +----------------+---------------------------------------------------------+
+   | option         | description                                             |
+   +================+=========================================================+
+   | xscrollcommand | Used to comunicate with horizontal scrollbars.          |
+   |                |                                                         |
+   |                | When the view in the widget's window change, the widget |
+   |                | will generate a Tcl command based on the scrollcommand. |
+   |                |                                                         |
+   |                | Usually this option consists of the method              |
+   |                | :meth:`Scrollbar.set` of some scrollbar. This will cause|
+   |                | the scrollbar to be updated whenever the view in the    |
+   |                | window changes.                                         |
+   +----------------+---------------------------------------------------------+
+   | yscrollcommand | Used to comunicate with vertical scrollbars.            |
+   |                | For some more information, see above.                   |
+   +----------------+---------------------------------------------------------+
+
+
+Label Options
+^^^^^^^^^^^^^
+
+The following options are supported by labels, buttons and other button-like
+widgets.
+
+   +--------------+-----------------------------------------------------------+
+   | option       | description                                               |
+   +==============+===========================================================+
+   | text         | Specifies a text string to be displayed inside the widget.|
+   +--------------+-----------------------------------------------------------+
+   | textvariable | Specifies a name whose value will be used in place of the |
+   |              | text option resource.                                     |
+   +--------------+-----------------------------------------------------------+
+   | underline    | If set, specifies the index (0-based) of a character to   |
+   |              | underline in the text string. The underline character is  |
+   |              | used for mnemonic activation.                             |
+   +--------------+-----------------------------------------------------------+
+   | image        | Specifies an image to display. This is a list of 1 or more|
+   |              | elements. The first element is the default image name. The|
+   |              | rest of the list if a sequence of statespec/value pairs as|
+   |              | defined by :meth:`Style.map`, specifying different images |
+   |              | to use when the widget is in a particular state or a      |
+   |              | combination of states. All images in the list should have |
+   |              | the same size.                                            |
+   +--------------+-----------------------------------------------------------+
+   | compound     | Specifies how to display the image relative to the text,  |
+   |              | in the case both text and images options are present.     |
+   |              | Valid values are:                                         |
+   |              |                                                           |
+   |              | * text: display text only                                 |
+   |              | * image: display image only                               |
+   |              | * top, bottom, left, right: display image above, below,   |
+   |              |   left of, or right of the text, respectively.            |
+   |              | * none: the default. display the image if present,        |
+   |              |   otherwise the text.                                     |
+   +--------------+-----------------------------------------------------------+
+   | width        | If greater than zero, specifies how much space, in        |
+   |              | character widths, to allocate for the text label, if less |
+   |              | than zero, specifies a minimum width. If zero or          |
+   |              | unspecified, the natural width of the text label is used. |
+   +--------------+-----------------------------------------------------------+
+
+
+Compatibility Options
+^^^^^^^^^^^^^^^^^^^^^
+
+   +--------+----------------------------------------------------------------+
+   | option | description                                                    |
+   +========+================================================================+
+   | state  | May be set to "normal" or "disabled" to control the "disabled" |
+   |        | state bit. This is a write-only option: setting it changes the |
+   |        | widget state, but the :meth:`Widget.state` method does not     |
+   |        | affect this option.                                            |
+   +--------+----------------------------------------------------------------+
+
+Widget States
+^^^^^^^^^^^^^
+
+The widget state is a bitmap of independent state flags.
+
+   +------------+-------------------------------------------------------------+
+   | flag       | description                                                 |
+   +============+=============================================================+
+   | active     | The mouse cursor is over the widget and pressing a mouse    |
+   |            | button will cause some action to occur                      |
+   +------------+-------------------------------------------------------------+
+   | disabled   | Widget is disabled under program control                    |
+   +------------+-------------------------------------------------------------+
+   | focus      | Widget has keyboard focus                                   |
+   +------------+-------------------------------------------------------------+
+   | pressed    | Widget is being pressed                                     |
+   +------------+-------------------------------------------------------------+
+   | selected   | "On", "true", or "current" for things like Checkbuttons and |
+   |            | radiobuttons                                                |
+   +------------+-------------------------------------------------------------+
+   | background | Windows and Mac have a notion of an "active" or foreground  |
+   |            | window. The *background* state is set for widgets in a      |
+   |            | background window, and cleared for those in the foreground  |
+   |            | window                                                      |
+   +------------+-------------------------------------------------------------+
+   | readonly   | Widget should not allow user modification                   |
+   +------------+-------------------------------------------------------------+
+   | alternate  | A widget-specific alternate display format                  |
+   +------------+-------------------------------------------------------------+
+   | invalid    | The widget's value is invalid                               |
+   +------------+-------------------------------------------------------------+
+
+A state specification is a sequence of state names, optionally prefixed with
+an exclamation point indicating that the bit is off.
+
+
+ttk.Widget
+^^^^^^^^^^
+
+Besides the methods described below, the class :class:`ttk.Widget` supports the
+methods :meth:`Tkinter.Widget.cget` and :meth:`Tkinter.Widget.configure`.
+
+.. class:: Widget
+
+   .. method:: identify(x, y)
+
+      Returns the name of the element at position *x* *y*, or the empty string
+      if the point does not lie within any element.
+
+      *x* and *y* are pixel coordinates relative to the widget.
+
+
+   .. method:: instate(statespec[, callback=None[, *args[, **kw]]])
+
+      Test the widget's state. If a callback is not specified, returns True
+      if the widget state matches *statespec* and False otherwise. If callback
+      is specified then it is called with args if widget state matches
+      *statespec*.
+
+
+   .. method:: state([statespec=None])
+
+      Modify or inquire widget state. If *statespec* is specified, sets the
+      widget state according to it and return a new *statespec* indicating
+      which flags were changed. If *statespec* is not specified, returns
+      the currently-enabled state flags.
+
+   *statespec* will usually be a list or a tuple.
+
+
+Combobox
+--------
+
+The :class:`ttk.Combobox` widget combines a text field with a pop-down list of
+values. This widget is a subclass of :class:`Entry`.
+
+Besides the methods inherited from :class:`Widget`: :meth:`Widget.cget`,
+:meth:`Widget.configure`, :meth:`Widget.identify`, :meth:`Widget.instate`
+and :meth:`Widget.state`, and the following inherited from :class:`Entry`:
+:meth:`Entry.bbox`, :meth:`Entry.delete`, :meth:`Entry.icursor`,
+:meth:`Entry.index`, :meth:`Entry.inset`, :meth:`Entry.selection`,
+:meth:`Entry.xview`, it has some other methods, described at
+:class:`ttk.Combobox`.
+
+
+Options
+^^^^^^^
+
+This widget accepts the following specific options:
+
+   +-----------------+--------------------------------------------------------+
+   | option          | description                                            |
+   +=================+========================================================+
+   | exportselection | Boolean value. If set, the widget selection is linked  |
+   |                 | to the Window Manager selection (which can be returned |
+   |                 | by invoking Misc.selection_get, for example).          |
+   +-----------------+--------------------------------------------------------+
+   | justify         | Specifies how the text is aligned within the widget.   |
+   |                 | One of "left", "center", or "right".                   |
+   +-----------------+--------------------------------------------------------+
+   | height          | Specifies the height of the pop-down listbox, in rows. |
+   +-----------------+--------------------------------------------------------+
+   | postcommand     | A script (possibly registered with Misc.register) that |
+   |                 | is called immediately before displaying the values. It |
+   |                 | may specify which values to display.                   |
+   +-----------------+--------------------------------------------------------+
+   | state           | One of "normal", "readonly", or "disabled". In the     |
+   |                 | "readonly" state, the value may not be edited directly,|
+   |                 | and the user can only selection of the values from the |
+   |                 | dropdown list. In the "normal" state, the text field is|
+   |                 | directly editable. In the "disabled" state, no         |
+   |                 | interaction is possible.                               |
+   +-----------------+--------------------------------------------------------+
+   | textvariable    | Specifies a name whose value is linked to the widget   |
+   |                 | value. Whenever the value associated with that name    |
+   |                 | changes, the widget value is updated, and vice versa.  |
+   |                 | See :class:`Tkinter.StringVar`.                        |
+   +-----------------+--------------------------------------------------------+
+   | values          | Specifies the list of values to display in the         |
+   |                 | drop-down listbox.                                     |
+   +-----------------+--------------------------------------------------------+
+   | width           | Specifies an integer value indicating the desired width|
+   |                 | of the entry window, in average-size characters of the |
+   |                 | widget's font.                                         |
+   +-----------------+--------------------------------------------------------+
+
+
+Virtual events
+^^^^^^^^^^^^^^
+
+The combobox widgets generates a **<<ComboboxSelected>>** virtual event
+when the user selects an element from the list of values.
+
+
+ttk.Combobox
+^^^^^^^^^^^^
+
+.. class:: Combobox
+
+   .. method:: current([newindex=None])
+
+      If *newindex* is specified, sets the combobox value to the element
+      position *newindex*. Otherwise, returns the index of the current value or
+      -1 if the current value is not in the values list.
+
+
+   .. method:: get()
+
+      Returns the current value of the combobox.
+
+
+   .. method:: set(value)
+
+      Sets the value of the combobox to *value*.
+
+
+Notebook
+--------
+
+Ttk Notebook widget manages a collection of windows and displays a single
+one at a time. Each child window is associated with a tab, which the user
+may select to change the currently-displayed window.
+
+
+Options
+^^^^^^^
+
+This widget accepts the following specific options:
+
+   +---------+----------------------------------------------------------------+
+   | option  | description                                                    |
+   +=========+================================================================+
+   | height  | If present and greater than zero, specifies the desired height |
+   |         | of the pane area (not including internal padding or tabs).     |
+   |         | Otherwise, the maximum height of all panes is used.            |
+   +---------+----------------------------------------------------------------+
+   | padding | Specifies the amount of extra space to add around the outside  |
+   |         | of the notebook. The padding is a list up to four length       |
+   |         | specifications left top right bottom. If fewer than four       |
+   |         | elements are specified, bottom defaults to top, right defaults |
+   |         | to left, and top defaults to left.                             |
+   +---------+----------------------------------------------------------------+
+   | width   | If present and greater than zero, specified the desired width  |
+   |         | of the pane area (not including internal padding). Otherwise,  |
+   |         | the maximum width of all panes is used.                        |
+   +---------+----------------------------------------------------------------+
+
+
+Tab Options
+^^^^^^^^^^^
+
+There are also specific options for tabs:
+
+   +-----------+--------------------------------------------------------------+
+   | option    | description                                                  |
+   +===========+==============================================================+
+   | state     | Either "normal", "disabled" or "hidden". If "disabled", then |
+   |           | the tab is not selectable. If "hidden", then the tab is not  |
+   |           | shown.                                                       |
+   +-----------+--------------------------------------------------------------+
+   | sticky    | Specifies how the child window is positioned within the pane |
+   |           | area. Value is a string containing zero or more of the       |
+   |           | characters "n", "s", "e" or "w". Each letter refers to a     |
+   |           | side (north, south, east or west) that the child window will |
+   |           | stick to, as per the :meth:`grid` geometry manager.          |
+   +-----------+--------------------------------------------------------------+
+   | padding   | Specifies the amount of extra space to add between the       |
+   |           | notebook and this pane. Syntax is the same as for the option |
+   |           | padding used by this widget.                                 |
+   +-----------+--------------------------------------------------------------+
+   | text      | Specifies a text to be displayed in the tab.                 |
+   +-----------+--------------------------------------------------------------+
+   | image     | Specifies an image to display in the tab. See the option     |
+   |           | image described in :class:`Widget`.                          |
+   +-----------+--------------------------------------------------------------+
+   | compound  | Specifies how to display the image relative to the text, in  |
+   |           | the case both options text and image are present. See        |
+   |           | `Label Options`_ for legal values.                           |
+   +-----------+--------------------------------------------------------------+
+   | underline | Specifies the index (0-based) of a character to underline in |
+   |           | the text string. The underlined character is used for        |
+   |           | mnemonic activation if :meth:`Notebook.enable_traversal` is  |
+   |           | called.                                                      |
+   +-----------+--------------------------------------------------------------+
+
+
+Tab Identifiers
+^^^^^^^^^^^^^^^
+
+The tab_id present in several methods of :class:`ttk.Notebook` may take any
+of the following forms:
+
+* An integer between zero and the number of tabs
+* The name of a child window
+* A positional specification of the form "@x,y", which identifies the tab
+* The literal string "current", which identifies the currently-selected tab
+* The literal string "end", which returns the number of tabs (only valid for
+  :meth:`Notebook.index`)
+
+
+Virtual Events
+^^^^^^^^^^^^^^
+
+This widget generates a **<<NotebookTabChanged>>** virtual event after a new
+tab is selected.
+
+
+ttk.Notebook
+^^^^^^^^^^^^
+
+.. class:: Notebook
+
+   .. method:: add(child, **kw)
+
+      Adds a new tab to the notebook.
+
+      If window is currently managed by the notebook but hidden, it is
+      restored to its previous position.
+
+      See `Tab Options`_ for the list of available options.
+
+
+   .. method:: forget(tab_id)
+
+      Removes the tab specified by *tab_id*, unmaps and unmanages the
+      associated window.
+
+
+   .. method:: hide(tab_id)
+
+      Hides the tab specified by *tab_id*.
+
+      The tab will not be displayed, but the associated window remains
+      managed by the notebook and its configuration remembered. Hidden tabs
+      may be restored with the add command.
+
+
+   .. method:: identify(x, y)
+
+      Returns the name of the tab element at position *x*, *y*, or the empty
+      string if none.
+
+
+   .. method:: index(tab_id)
+
+      Returns the numeric index of the tab specified by *tab_id*, or the total
+      number of tabs if *tab_id* is the string "end".
+
+
+   .. method:: insert(pos, child, **kw)
+
+      Inserts a pane at the specified position.
+
+      *pos* is either the string end, an integer index, or the name of a
+      managed child. If *child* is already managed by the notebook, moves it to
+      the specified position.
+
+      See `Tab Options`_ for the list of available options.
+
+
+   .. method:: select([tab_id])
+
+      Selects the specified *tab_id*.
+
+      The associated child window will be displayed, and the
+      previously-selected window (if different) is unmapped. If *tab_id* is
+      omitted, returns the widget name of the currently selected pane.
+
+
+   .. method:: tab(tab_id[, option=None[, **kw]])
+
+      Query or modify the options of the specific *tab_id*.
+
+      If *kw* is not given, returns a dict of the tab option values. If
+      *option* is specified, returns the value of that *option*. Otherwise,
+      sets the options to the corresponding values.
+
+
+   .. method:: tabs()
+
+      Returns a list of windows managed by the notebook.
+
+
+   .. method:: enable_traversal()
+
+      Enable keyboard traversal for a toplevel window containing this notebook.
+
+      This will extend the bindings for the toplevel window containing the
+      notebook as follows:
+
+      * Control-Tab: selects the tab following the currently selected one
+      * Shift-Control-Tab: selects the tab preceding the currently selected one
+      * Alt-K: where K is the mnemonic (underlined) character of any tab, will
+        select that tab.
+
+      Multiple notebooks in a single toplevel may be enabled for traversal,
+      including nested notebooks. However, notebook traversal only works
+      properly if all panes have as master the notebook they are in.
+
+
+Progressbar
+-----------
+
+The :class:`ttk.Progressbar` widget shows the status of a long-running
+operation. It can operate in two modes: determinate mode shows the amount
+completed relative to the total amount of work to be done, and indeterminate
+mode provides an animated display to let the user know that something is
+happening.
+
+
+Options
+^^^^^^^
+
+This widget accepts the following specific options:
+
+   +----------+---------------------------------------------------------------+
+   | option   | description                                                   |
+   +==========+===============================================================+
+   | orient   | One of "horizontal" or "vertical". Specifies the orientation  |
+   |          | of the progress bar.                                          |
+   +----------+---------------------------------------------------------------+
+   | length   | Specifies the length of the long axis of the progress bar     |
+   |          | (width if horizontal, height if vertical).                    |
+   +----------+---------------------------------------------------------------+
+   | mode     | One of "determinate" or "indeterminate".                      |
+   +----------+---------------------------------------------------------------+
+   | maximum  | A number specifying the maximum value. Defaults to 100.       |
+   +----------+---------------------------------------------------------------+
+   | value    | The current value of the progress bar. In "determinate" mode, |
+   |          | this represents the amount of work completed. In              |
+   |          | "indeterminate" mode, it is interpreted as modulo maximum;    |
+   |          | that is, the progress bar completes one "cycle" when its value|
+   |          | increases by maximum.                                         |
+   +----------+---------------------------------------------------------------+
+   | variable | A name which is linked to the option value. If specified, the |
+   |          | value of the progressbar is automatically set to the value of |
+   |          | this name whenever the latter is modified.                    |
+   +----------+---------------------------------------------------------------+
+   | phase    | Read-only option. The widget periodically increments the value|
+   |          | of this option whenever its value is greater than 0 and, in   |
+   |          | determinate mode, less than maximum. This option may be used  |
+   |          | by the current theme to provide additional animation effects. |
+   +----------+---------------------------------------------------------------+
+
+
+ttk.Progressbar
+^^^^^^^^^^^^^^^
+
+.. class:: Progressbar
+
+   .. method:: start([interval])
+
+      Begin autoincrement mode: schedules a recurring timer even that calls
+      :meth:`Progressbar.step` every *interval* milliseconds. If omitted,
+      *interval* defaults to 50 milliseconds.
+
+
+   .. method:: step([amount])
+
+      Increments progressbar's value by *amount*.
+
+      *amount* defaults to 1.0 if omitted.
+
+
+   .. method:: stop()
+
+      Stop autoincrement mode: cancels any recurring timer event initiated by
+      :meth:`Progressbar.start` for this progressbar.
+
+
+Separator
+---------
+
+The :class:`ttk.Separator` widget displays a horizontal or vertical separator
+bar.
+
+It has no other method besides the ones inherited from :class:`ttk.Widget`.
+
+
+Options
+^^^^^^^
+
+This widget accepts the following specific option:
+
+   +--------+----------------------------------------------------------------+
+   | option | description                                                    |
+   +========+================================================================+
+   | orient | One of "horizontal" or "vertical". Specifies the orientation of|
+   |        | the separator.                                                 |
+   +--------+----------------------------------------------------------------+
+
+
+Sizegrip
+--------
+
+The :class:`ttk.Sizegrip` widget (also known as grow box) allows the user to
+resize the containing toplevel window by pressing and dragging the grip.
+
+This widget has no specific options neither specific methods, besides the
+ones inherited from :class:`ttk.Widget`.
+
+
+Platform-specific notes
+^^^^^^^^^^^^^^^^^^^^^^^
+
+* On Mac OSX, toplevel windows automatically include a built-in size grip
+  by default. Adding a Sizegrip there is harmless, since the built-in
+  grip will just mask the widget.
+
+
+Bugs
+^^^^
+
+* If the containing toplevel's position was specified relative to the right
+  or bottom of the screen (e.g. ....), the Sizegrip widget will not resize
+  the window.
+* This widget supports only "southeast" resizing.
+
+
+Treeview
+--------
+
+The :class:`ttk.Treeview` widget displays a hierarchical collection of items.
+Each item has a textual label, an optional image, and an optional list of data
+values. The data values are displayed in successive columns after the tree
+label.
+
+The order in which data values are displayed may be controlled by setting
+the widget option displaycolumns. The tree widget can also display column
+headings. Columns may be accessed by number or symbolic names listed in the
+widget option columns. See `Column Identifiers`_.
+
+Each item is identified by an unique name. The widget will generate item IDs
+if they are not supplied by the caller. There is a distinguished root item,
+named {}. The root item itself is not displayed; its children appear at the
+top level of the hierarchy.
+
+Each item also has a list of tags, which can be used to associate even bindings
+with individual items and control the appearance of the item.
+
+The Treeview widget supports horizontal and vertical scrolling, according to
+the options described in `Scrollable Widget Options`_ and the methods
+:meth:`Treeview.xview` and :meth:`Treeview.yview`.
+
+
+Options
+^^^^^^^
+
+This widget accepts the following specific option:
+
+   +----------------+--------------------------------------------------------+
+   | option         | description                                            |
+   +================+========================================================+
+   | columns        | A list of column identifiers, specifying the number of |
+   |                | columns and their names.                               |
+   +----------------+--------------------------------------------------------+
+   | displaycolumns | A list of column identifiers (either symbolic or       |
+   |                | integer indices) specifying which data columns are     |
+   |                | displayed and the order in which they appear, or the   |
+   |                | string "#all".                                         |
+   +----------------+--------------------------------------------------------+
+   | height         | Specifies the number of rows which should be visible.  |
+   |                | Note: the requested width is determined from the sum   |
+   |                | of the column widths.                                  |
+   +----------------+--------------------------------------------------------+
+   | padding        | Specifies the internal padding for the widget. The     |
+   |                | padding is a list of up to four length specifications. |
+   +----------------+--------------------------------------------------------+
+   | selectmode     | Controls how the built-in class bindings manage the    |
+   |                | selection. One of "extended", "browse" or "none".      |
+   |                | If set to "extended" (the default), multiple items may |
+   |                | be selected. If "browse", only a single item will be   |
+   |                | selected at a time. If "none", the selection will not  |
+   |                | be changed.                                            |
+   |                |                                                        |
+   |                | Note that the application code and tag bindings can set|
+   |                | the selection however they wish, regardless the value  |
+   |                | of this option.                                        |
+   +----------------+--------------------------------------------------------+
+   | show           | A list containing zero or more of the following values,|
+   |                | specifying which elements of the tree to display.      |
+   |                |                                                        |
+   |                | * tree: display tree labels in column #0.              |
+   |                | * headings: display the heading row.                   |
+   |                |                                                        |
+   |                | The default is "tree headings", i.e., show all         |
+   |                | elements.                                              |
+   |                |                                                        |
+   |                | **Note**: Column #0 always refer to the tree column,   |
+   |                | even if show="tree" is not specified.                  |
+   +----------------+--------------------------------------------------------+
+
+
+Item Options
+^^^^^^^^^^^^
+
+The following item options may be specified for items in the insert and item
+widget commands.
+
+   +--------+---------------------------------------------------------------+
+   | option | description                                                   |
+   +========+===============================================================+
+   | text   | The textual label to display for the item.                    |
+   +--------+---------------------------------------------------------------+
+   | image  | A Tk Image, displayed to the left of the label.               |
+   +--------+---------------------------------------------------------------+
+   | values | The list of values associated with the item.                  |
+   |        |                                                               |
+   |        | Each item should have the same number of values as the widget |
+   |        | option columns. If there are fewer values than columns, the   |
+   |        | remaining values are assumed empty. If there are more values  |
+   |        | than columns, the extra values are ignored.                   |
+   +--------+---------------------------------------------------------------+
+   | open   | True/False value indicating whether the item's children should|
+   |        | be displayed or hidden.                                       |
+   +--------+---------------------------------------------------------------+
+   | tags   | A list of tags associated with this item.                     |
+   +--------+---------------------------------------------------------------+
+
+
+Tag Options
+^^^^^^^^^^^
+
+The following options may be specified on tags:
+
+   +------------+-----------------------------------------------------------+
+   | option     | description                                               |
+   +============+===========================================================+
+   | foreground | Specifies the text foreground color.                      |
+   +------------+-----------------------------------------------------------+
+   | background | Specifies the cell or item background color.              |
+   +------------+-----------------------------------------------------------+
+   | font       | Specifies the font to use when drawing text.              |
+   +------------+-----------------------------------------------------------+
+   | image      | Specifies the item image, in case the item's image option |
+   |            | is empty.                                                 |
+   +------------+-----------------------------------------------------------+
+
+
+Column Identifiers
+^^^^^^^^^^^^^^^^^^
+
+Column identifiers take any of the following forms:
+
+* A symbolic name from the list of columns option.
+* An integer n, specifying the nth data column.
+* A string of the form #n, where n is an integer, specifying the nth display
+  column.
+
+Notes:
+
+* Item's option values may be displayed in a different order than the order
+  in which they are stored.
+* Column #0 always refers to the tree column, even if show="tree" is not
+  specified.
+
+A data column number is an index into an item's option values list; a display
+column number is the column number in the tree where the values are displayed.
+Tree labels are displayed in column #0. If option displaycolumns is not set,
+then data column n is displayed in column #n+1. Again, **column #0 always
+refers to the tree column**.
+
+
+Virtual Events
+^^^^^^^^^^^^^^
+
+The Treeview widget generates the following virtual events.
+
+   +--------------------+--------------------------------------------------+
+   | event              | description                                      |
+   +====================+==================================================+
+   | <<TreeviewSelect>> | Generated whenever the selection changes.        |
+   +--------------------+--------------------------------------------------+
+   | <<TreeviewOpen>>   | Generated just before settings the focus item to |
+   |                    | open=True.                                       |
+   +--------------------+--------------------------------------------------+
+   | <<TreeviewClose>>  | Generated just after setting the focus item to   |
+   |                    | open=False.                                      |
+   +--------------------+--------------------------------------------------+
+
+The :meth:`Treeview.focus` and :meth:`Treeview.selection` methods can be used
+to determine the affected item or items.
+
+
+ttk.Treeview
+^^^^^^^^^^^^
+
+.. class:: Treeview
+
+   .. method:: bbox(item[, column=None])
+
+      Returns the bounding box (relative to the treeview widget's window) of
+      the specified *item* in the form (x, y, width, height).
+
+      If *column* is specified, returns the bounding box of that cell. If the
+      *item* is not visible (i.e., if it is a descendant of a closed item or is
+      scrolled offscreen), returns an empty string.
+
+
+   .. method:: get_children([item])
+
+      Returns the list of children belonging to *item*.
+
+      If *item* is not specified, returns root children.
+
+
+   .. method:: set_children(item, *newchildren)
+
+      Replaces item's child with *newchildren*.
+
+      Children present in item that are not present in *newchildren* are
+      detached from tree. No items in *newchildren* may be an ancestor of
+      item. Note that not specifying *newchildren* results in detaching
+      *item*'s children.
+
+
+   .. method:: column(column[, option=None[, **kw]])
+
+      Query or modify the options for the specified *column*.
+
+      If *kw* is not given, returns a dict of the column option values. If
+      *option* is specified then the value for that *option* is returned.
+      Otherwise, sets the options to the corresponding values.
+
+      The valid options/values are:
+
+      * id
+         Returns the column name, this is a read-only option.
+      * anchor: One of the standard Tk anchor values.
+         Specifies how the text in this column should be aligned with respect
+         to the cell.
+      * minwidth: width
+         The minimum width of the column in pixels. The treeview widget will
+         not make the column any smaller than the specified by this option when
+         the widget is resized or the user drags a column.
+      * stretch: True/False
+         Specifies wheter or not the column's width should be adjusted when
+         the widget is resized.
+      * width: width
+         The width of the column in pixels.
+
+      To configure the tree column, call this with column = "#0"
+
+   .. method:: delete(*items)
+
+      Delete all specified *items* and all their descendants.
+
+      The root item may not be deleted.
+
+
+   .. method:: detach(*items)
+
+      Unlinks all of the specified *items* from the tree.
+
+      The items and all of their descendants are still present, and may be
+      reinserted at another point in the tree, but will not be displayed.
+
+      The root item may not be detached.
+
+
+   .. method:: exists(item)
+
+      Returns True if the specified *item* is present in the three,
+      False otherwise.
+
+
+   .. method:: focus([item=None])
+
+      If *item* is specified, sets the focus item to *item*. Otherwise, returns
+      the current focus item, or '' if there is none.
+
+
+   .. method:: heading(column[, option=None[, **kw]])
+
+      Query or modify the heading options for the specified *column*.
+
+      If *kw* is not given, returns a dict of the heading option values. If
+      *option* is specified then the value for that *option* is returned.
+      Otherwise, sets the options to the corresponding values.
+
+      The valid options/values are:
+
+      * text: text
+         The text to display in the column heading.
+      * image: imageName
+         Specifies an image to display to the right of the column heading.
+      * anchor: anchor
+         Specifies how the heading text should be aligned. One of the standard
+         Tk anchor values.
+      * command: callback
+         A callback to be invoked when the heading label is pressed.
+
+      To configure the tree column heading, call this with column = "#0"
+
+
+   .. method:: identify(component, x, y)
+
+      Returns a description of the specified *component* under the point given
+      by *x* and *y*, or the empty string if no such *component* is present at
+      that position.
+
+
+   .. method:: identify_row(y)
+
+      Returns the item ID of the item at position *y*.
+
+
+   .. method:: identify_column(x)
+
+      Returns the data column identifier of the cell at position *x*.
+
+      The tree column has ID #0.
+
+
+   .. method:: identify_region(x, y)
+
+      Returns one of:
+
+      +-----------+--------------------------------------+
+      | region    | meaning                              |
+      +===========+======================================+
+      | heading   | Tree heading area.                   |
+      +-----------+--------------------------------------+
+      | separator | Space between two columns headings.  |
+      +-----------+--------------------------------------+
+      | tree      | The tree area.                       |
+      +-----------+--------------------------------------+
+      | cell      | A data cell.                         |
+      +-----------+--------------------------------------+
+
+      Availability: Tk 8.6.
+
+
+   .. method:: identify_element(x, y)
+
+      Returns the element at position x, y.
+
+      Availability: Tk 8.6.
+
+
+   .. method:: index(item)
+
+      Returns the integer index of *item* within its parent's list of children.
+
+
+   .. method:: insert(parent, index[, iid=None[, **kw]])
+
+      Creates a new item and return the item identifier of the newly created
+      item.
+
+      *parent* is the item ID of the parent item, or the empty string to create
+      a new top-level item. *index* is an integer, or the value "end",
+      specifying where in the list of parent's children to insert the new item.
+      If *index* is less than or equal to zero, the new node is inserted at
+      the beginning, if *index* is greater than or equal to the current number
+      of children, it is inserted at the end. If *iid* is specified, it is used
+      as the item identifier, *iid* must not already exist in the tree.
+      Otherwise, a new unique identifier is generated.
+
+      See `Item Options`_ for the list of available points.
+
+
+   .. method:: item(item[, option[, **kw]])
+
+      Query or modify the options for the specified *item*.
+
+      If no options are given, a dict with options/values for the item is
+      returned.
+      If *option* is specified then the value for that option is returned.
+      Otherwise, sets the options to the corresponding values as given by *kw*.
+
+
+   .. method:: move(item, parent, index)
+
+      Moves *item* to position *index* in *parent*'s list of children.
+
+      It is illegal to move an item under one of its descendants. If index is
+      less than or equal to zero, item is moved to the beginning, if greater
+      than or equal to the number of children, it is moved to the end. If item
+      was detached it is reattached.
+
+
+   .. method:: next(item)
+
+      Returns the identifier of *item*'s next sibling, or '' if *item* is the
+      last child of its parent.
+
+
+   .. method:: parent(item)
+
+      Returns the ID of the parent of *item*, or '' if *item* is at the top
+      level of the hierarchy.
+
+
+   .. method:: prev(item)
+
+      Returns the identifier of *item*'s previous sibling, or '' if *item* is
+      the first child of its parent.
+
+
+   .. method:: reattach(item, parent, index)
+
+      An alias for :meth:`Treeview.move`.
+
+
+   .. method:: see(item)
+
+      Ensure that *item* is visible.
+
+      Sets all of *item*'s ancestors open option to True, and scrolls the
+      widget if necessary so that *item* is within the visible portion of
+      the tree.
+
+
+   .. method:: selection([selop=None[, items=None]])
+
+      If *selop* is not specified, returns selected items. Otherwise, it will
+      act according to the following selection methods.
+
+
+   .. method:: selection_set(items)
+
+      *items* becomes the new selection.
+
+
+   .. method:: selection_add(items)
+
+      Add *items* to the selection.
+
+
+   .. method:: selection_remove(items)
+
+      Remove *items* from the selection.
+
+
+   .. method:: selection_toggle(items)
+
+      Toggle the selection state of each item in *items*.
+
+
+   .. method:: set(item[, column=None[, value=None]])
+
+      With one argument, returns a dictionary of column/value pairs for the
+      specified *item*. With two arguments, returns the current value of the
+      specified *column*. With three arguments, sets the value of given
+      *column* in given *item* to the specified *value*.
+
+
+   .. method:: tag_bind(tagname[, sequence=None[, callback=None]])
+
+      Bind a callback for the given event *sequence* to the tag *tagname*.
+      When an event is delivered to an item, the *callbacks* for each of the
+      item's tags option are called.
+
+
+   .. method:: tag_configure(tagname[, option=None[, **kw]])
+
+      Query or modify the options for the specified *tagname*.
+
+      If *kw* is not given, returns a dict of the option settings for
+      *tagname*. If *option* is specified, returns the value for that *option*
+      for the specified *tagname*. Otherwise, sets the options to the
+      corresponding values for the given *tagname*.
+
+
+   .. method:: tag_has(tagname[, item])
+
+      If *item* is specified, returns 1 or 0 depending on whether the specified
+      *item* has the given *tagname*. Otherwise, returns a list of all items
+      which have the specified tag.
+
+      Availability: Tk 8.6
+
+
+   .. method:: xview(*args)
+
+      Query or modify horizontal position of the treeview.
+
+
+   .. method:: yview(*args)
+
+      Query or modify vertical position of the treeview.
+
+
+.. _TtkStyling:
+
+Ttk Styling
+-----------
+
+Each widget in :mod:`ttk` is assigned a style, which specifies the set of
+elements making up the widget and how they are arranged, along with dynamic
+and default settings for element options. By default the style name is the
+same as the widget's class name, but it may be overriden by the widget's style
+option. If you don't know the class name of a widget, use the method
+:meth:`Misc.winfo_class` (somewidget.winfo_class()).
+
+.. seealso::
+
+   `Tcl'2004 conference presentation <http://tktable.sourceforge.net/tile/tile-tcl2004.pdf>`_
+      This document explains how the theme engine works
+
+
+.. class:: Style
+
+   This class is used to manipulate the style database.
+
+
+   .. method:: configure(style, query_opt=None, **kw)
+
+      Query or sets the default value of the specified option(s) in *style*.
+
+      Each key in *kw* is an option and each value is a string identifying
+      the value for that option.
+
+      For example, to change every default button to be a flat button with
+      some padding and a different background color you could do::
+
+         import ttk
+         import Tkinter
+
+         root = Tkinter.Tk()
+
+         ttk.Style().configure("TButton", padding=6, relief="flat",
+            background="#ccc")
+
+         btn = ttk.Button(text="Sample")
+         btn.pack()
+
+         root.mainloop()
+
+
+   .. method:: map(style, query_opt=None, **kw)
+
+      Query or sets dynamic values of the specified option(s) in *style*.
+
+      Each key in kw is an option and each value should be a list or a
+      tuple (usually) containing statespecs grouped in tuples, or list, or
+      something else of your preference. A statespec is compound of one or more
+      states and then a value.
+
+      An example may make it more understandable::
+
+         import Tkinter
+         import ttk
+
+         root = Tkinter.Tk()
+
+         style = ttk.Style()
+         style.map("C.TButton",
+             foreground=[('pressed', 'red'), ('active', 'blue')],
+             background=[('pressed', '!disabled', 'black'), ('active', 'white')]
+             )
+
+         colored_btn = ttk.Button(text="Test", style="C.TButton").pack()
+
+         root.mainloop()
+
+
+      There is a thing to note in this previous short example:
+
+       * The order of the (states, value) sequences for an option does matter,
+         if you changed the order to [('active', 'blue'), ('pressed', 'red')]
+         in the foreground option, for example, you would get a blue foreground
+         when the widget were in active or pressed states.
+
+
+   .. method:: lookup(style, option[, state=None[, default=None]])
+
+      Returns the value specified for *option* in *style*.
+
+      If *state* is specified, it is expected to be a sequence of one or more
+      states. If the *default* argument is set, it is used as a fallback value
+      in case no specification for option is found.
+
+      To check what font a Button uses by default, you would do::
+
+         import ttk
+
+         print ttk.Style().lookup("TButton", "font")
+
+
+   .. method:: layout(style[, layoutspec=None])
+
+      Define the widget layout for given *style*. If *layoutspec* is omitted,
+      return the layout specification for given style.
+
+      *layoutspec*, if specified, is expected to be a list, or some other
+      sequence type (excluding string), where each item should be a tuple and
+      the first item is the layout name and the second item should have the
+      format described described in `Layouts`_.
+
+      To understand the format, check this example below (it is not intended
+      to do anything useful)::
+
+         import ttk
+         import Tkinter
+
+         root = Tkinter.Tk()
+
+         style = ttk.Style()
+         style.layout("TMenubutton", [
+            ("Menubutton.background", None),
+            ("Menubutton.button", {"children":
+                [("Menubutton.focus", {"children":
+                    [("Menubutton.padding", {"children":
+                        [("Menubutton.label", {"side": "left", "expand": 1})]
+                    })]
+                })]
+            }),
+         ])
+
+         mbtn = ttk.Menubutton(text='Text')
+         mbtn.pack()
+         root.mainloop()
+
+
+   .. method:: element_create(elementname, etype, *args, **kw)
+
+      Create a new element in the current theme of given *etype* which is
+      expected to be either "image", "from" or "vsapi". The latter is only
+      available in Tk 8.6a for Windows XP and Vista and is not described here.
+
+      If "image" is used, *args* should contain the default image name followed
+      by statespec/value pairs (this is the imagespec), *kw* may have the
+      following options:
+
+       * border=padding
+          padding is a list of up to four integers, specifying the left, top,
+          right, and bottom borders, respectively.
+
+       * height=height
+          Specifies a minimum height for the element. If less than zero, the
+          base image's height is used as a default.
+
+       * padding=padding
+          Specifies the element's interior padding. Defaults to border's value
+          if not specified.
+
+       * sticky=spec
+          Specifies how the image is placed within the final parcel. spec
+          contains zero or more characters “n”, “s”, “w”, or “e”.
+
+       * width=width
+          Specifies a minimum width for the element. If less than zero, the
+          base image's width is used as a default.
+
+      But if "from" is used, then :meth:`element_create` will clone an existing
+      element. *args* is expected to contain a themename, which is from where
+      the element will be cloned, and optionally an element to clone from.
+      If this element to clone from is not specified, an empty element will
+      be used. *kw* is discarded here.
+
+
+   .. method:: element_names()
+
+      Returns the list of elements defined in the current theme.
+
+
+   .. method:: element_options(elementname)
+
+      Returns the list of *elementname*'s options.
+
+
+   .. method:: theme_create(themename[, parent=None[, settings=None]])
+
+      Create a new theme.
+
+      It is an error if *themename* already exists. If *parent* is specified,
+      the new theme will inherit styles, elements and layouts from the parent
+      theme. If *settings* are present they are expected to have the same
+      syntax used for :meth:`theme_settings`.
+
+
+   .. method:: theme_settings(themename, settings)
+
+      Temporarily sets the current theme to *themename*, apply specified
+      *settings* and then restore the previous theme.
+
+      Each key in *settings* is a style and each value may contain the keys
+      'configure', 'map', 'layout' and 'element create' and they are expected
+      to have the same format as specified by the methods
+      :meth:`Style.configure`, :meth:`Style.map`, :meth:`Style.layout` and
+      :meth:`Style.element_create` respectively.
+
+      As an example, lets change the Combobox for the default theme a bit::
+
+         import ttk
+         import Tkinter
+
+         root = Tkinter.Tk()
+
+         style = ttk.Style()
+         style.theme_settings("default", {
+            "TCombobox": {
+                "configure": {"padding": 5},
+                "map": {
+                    "background": [("active", "green2"),
+                                   ("!disabled", "green4")],
+                    "fieldbackground": [("!disabled", "green3")],
+                    "foreground": [("focus", "OliveDrab1"),
+                                   ("!disabled", "OliveDrab2")]
+                }
+            }
+         })
+
+         combo = ttk.Combobox().pack()
+
+         root.mainloop()
+
+
+   .. method:: theme_names()
+
+      Returns a list of all known themes.
+
+
+   .. method:: theme_use([themename])
+
+      If *themename* is not given, returns the theme in use, otherwise, set
+      the current theme to *themename*, refreshes all widgets and emits a
+      <<ThemeChanged>> event.
+
+
+Layouts
+^^^^^^^
+
+A layout can be just None, if takes no options, or a dict of options specifying
+how to arrange the element. The layout mechanism uses a simplified
+version of the pack geometry manager: given an initial cavity, each element is
+allocated a parcel. Valid options/values are:
+
+ * side: whichside
+    Specifies which side of the cavity to place the the element; one of
+    top, right, bottom or left. If omitted, the element occupies the
+    entire cavity.
+
+ * sticky: nswe
+    Specifies where the element is placed inside its allocated parcel.
+
+ * unit: 0 or 1
+    If set to 1, causes the element and all of its descendants to be treated as
+    a single element for the purposes of :meth:`Widget.identify` et al. It's
+    used for things like scrollbar thumbs with grips.
+
+ * children: [sublayout... ]
+    Specifies a list of elements to place inside the element. Each
+    element is a tuple (or other sequence type) where the first item is
+    the layout name, and the other is a `Layout`_.
+
+.. _Layout: `Layouts`_

Added: python/trunk/Lib/lib-tk/test/README
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/README	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,14 @@
+Writing new tests
+=================
+
+Precaution
+----------
+
+    New tests should always use only one Tk window at once, like all the
+    current tests do. This means that you have to destroy the current window
+    before creating another one, and clean up after the test. The motivation
+    behind this is that some tests may depend on having its window focused
+    while it is running to work properly, and it may be hard to force focus
+    on your window across platforms (right now only test_traversal at
+    test_ttk.test_widgets.NotebookTest depends on this).
+

Added: python/trunk/Lib/lib-tk/test/runtktests.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/runtktests.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,65 @@
+"""
+Use this module to get and run all tk tests.
+
+Tkinter tests should live in a package inside the directory where this file
+lives, like test_tkinter.
+Extensions also should live in packages following the same rule as above.
+"""
+
+import os
+import sys
+import unittest
+import test.test_support
+
+this_dir_path = os.path.abspath(os.path.dirname(__file__))
+
+def is_package(path):
+    for name in os.listdir(path):
+        if name in ('__init__.py', '__init__.pyc', '__init.pyo'):
+            return True
+    return False
+
+def get_tests_modules(basepath=this_dir_path, gui=True):
+    """This will import and yield modules whose names start with test_
+    and are inside packages found in the path starting at basepath."""
+    py_ext = '.py'
+
+    for dirpath, dirnames, filenames in os.walk(basepath):
+        for dirname in list(dirnames):
+            if dirname[0] == '.':
+                dirnames.remove(dirname)
+
+        if is_package(dirpath) and filenames:
+            pkg_name = dirpath[len(basepath) + len(os.sep):].replace('/', '.')
+            filenames = filter(
+                    lambda x: x.startswith('test_') and x.endswith(py_ext),
+                    filenames)
+
+            for name in filenames:
+                try:
+                    yield __import__(
+                            "%s.%s" % (pkg_name, name[:-len(py_ext)]),
+                            fromlist=['']
+                            )
+                except test.test_support.ResourceDenied:
+                    if gui:
+                        raise
+
+def get_tests(text=True, gui=True):
+    """Yield all the tests in the modules found by get_tests_modules.
+
+    If nogui is True, only tests that do not require a GUI will be
+    returned."""
+    attrs = []
+    if text:
+        attrs.append('tests_nogui')
+    if gui:
+        attrs.append('tests_gui')
+    for module in get_tests_modules(gui=gui):
+        for attr in attrs:
+            for test in getattr(module, attr, ()):
+                yield test
+
+if __name__ == "__main__":
+    test.test_support.use_resources = ['gui']
+    test.test_support.run_unittest(*get_tests())

Added: python/trunk/Lib/lib-tk/test/test_ttk/__init__.py
==============================================================================

Added: python/trunk/Lib/lib-tk/test/test_ttk/support.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/test_ttk/support.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,25 @@
+import Tkinter
+
+def get_tk_root():
+    try:
+        root = Tkinter._default_root
+    except AttributeError:
+        # it is possible to disable default root in Tkinter, although
+        # I haven't seen people doing it (but apparently someone did it
+        # here).
+        root = None
+
+    if root is None:
+        # create a new master only if there isn't one already
+        root = Tkinter.Tk()
+
+    return root
+
+
+def simulate_mouse_click(widget, x, y):
+    """Generate proper events to click at the x, y position (tries to act
+    like an X server)."""
+    widget.event_generate('<Enter>', x=0, y=0)
+    widget.event_generate('<Motion>', x=x, y=y)
+    widget.event_generate('<ButtonPress-1>', x=x, y=y)
+    widget.event_generate('<ButtonRelease-1>', x=x, y=y)

Added: python/trunk/Lib/lib-tk/test/test_ttk/test_extensions.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/test_ttk/test_extensions.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,266 @@
+import sys
+import unittest
+import Tkinter
+import ttk
+from test.test_support import requires, run_unittest
+
+import support
+
+requires('gui')
+
+class LabeledScaleTest(unittest.TestCase):
+
+    def test_widget_destroy(self):
+        # automatically created variable
+        x = ttk.LabeledScale()
+        var = x._variable._name
+        x.destroy()
+        self.failUnlessRaises(Tkinter.TclError, x.tk.globalgetvar, var)
+
+        # manually created variable
+        myvar = Tkinter.DoubleVar()
+        name = myvar._name
+        x = ttk.LabeledScale(variable=myvar)
+        x.destroy()
+        self.failUnlessEqual(x.tk.globalgetvar(name), myvar.get())
+        del myvar
+        self.failUnlessRaises(Tkinter.TclError, x.tk.globalgetvar, name)
+
+        # checking that the tracing callback is properly removed
+        myvar = Tkinter.IntVar()
+        # LabeledScale will start tracing myvar
+        x = ttk.LabeledScale(variable=myvar)
+        x.destroy()
+        # Unless the tracing callback was removed, creating a new
+        # LabeledScale with the same var will cause an error now. This
+        # happens because the variable will be set to (possibly) a new
+        # value which causes the tracing callback to be called and then
+        # it tries calling instance attributes not yet defined.
+        ttk.LabeledScale(variable=myvar)
+        if hasattr(sys, 'last_type'):
+            self.failIf(sys.last_type == Tkinter.TclError)
+
+
+    def test_initialization(self):
+        # master passing
+        x = ttk.LabeledScale()
+        self.failUnlessEqual(x.master, Tkinter._default_root)
+        x.destroy()
+        master = Tkinter.Frame()
+        x = ttk.LabeledScale(master)
+        self.failUnlessEqual(x.master, master)
+        x.destroy()
+
+        # variable initialization/passing
+        passed_expected = ((2.5, 2), ('0', 0), (0, 0), (10, 10),
+            (-1, -1), (sys.maxint + 1, sys.maxint + 1))
+        for pair in passed_expected:
+            x = ttk.LabeledScale(from_=pair[0])
+            self.failUnlessEqual(x.value, pair[1])
+            x.destroy()
+        x = ttk.LabeledScale(from_='2.5')
+        self.failUnlessRaises(ValueError, x._variable.get)
+        x.destroy()
+        x = ttk.LabeledScale(from_=None)
+        self.failUnlessRaises(ValueError, x._variable.get)
+        x.destroy()
+        # variable should have its default value set to the from_ value
+        myvar = Tkinter.DoubleVar(value=20)
+        x = ttk.LabeledScale(variable=myvar)
+        self.failUnlessEqual(x.value, 0)
+        x.destroy()
+        # check that it is really using a DoubleVar
+        x = ttk.LabeledScale(variable=myvar, from_=0.5)
+        self.failUnlessEqual(x.value, 0.5)
+        self.failUnlessEqual(x._variable._name, myvar._name)
+        x.destroy()
+
+        # widget positionment
+        def check_positions(scale, scale_pos, label, label_pos):
+            self.failUnlessEqual(scale.pack_info()['side'], scale_pos)
+            self.failUnlessEqual(label.place_info()['anchor'], label_pos)
+        x = ttk.LabeledScale(compound='top')
+        check_positions(x.scale, 'bottom', x.label, 'n')
+        x.destroy()
+        x = ttk.LabeledScale(compound='bottom')
+        check_positions(x.scale, 'top', x.label, 's')
+        x.destroy()
+        x = ttk.LabeledScale(compound='unknown') # invert default positions
+        check_positions(x.scale, 'top', x.label, 's')
+        x.destroy()
+        x = ttk.LabeledScale() # take default positions
+        check_positions(x.scale, 'bottom', x.label, 'n')
+        x.destroy()
+
+        # extra, and invalid, kwargs
+        self.failUnlessRaises(Tkinter.TclError, ttk.LabeledScale, a='b')
+
+
+    def test_horizontal_range(self):
+        lscale = ttk.LabeledScale(from_=0, to=10)
+        lscale.pack()
+        lscale.wait_visibility()
+        lscale.update()
+
+        linfo_1 = lscale.label.place_info()
+        prev_xcoord = lscale.scale.coords()[0]
+        self.failUnlessEqual(prev_xcoord, int(linfo_1['x']))
+        # change range to: from -5 to 5. This should change the x coord of
+        # the scale widget, since 0 is at the middle of the new
+        # range.
+        lscale.scale.configure(from_=-5, to=5)
+        # The following update is needed since the test doesn't use mainloop,
+        # at the same time this shouldn't affect test outcome
+        lscale.update()
+        curr_xcoord = lscale.scale.coords()[0]
+        self.failUnless(prev_xcoord != curr_xcoord)
+        # the label widget should have been repositioned too
+        linfo_2 = lscale.label.place_info()
+        self.failUnlessEqual(lscale.label['text'], 0)
+        self.failUnlessEqual(curr_xcoord, int(linfo_2['x']))
+        # change the range back
+        lscale.scale.configure(from_=0, to=10)
+        self.failUnless(prev_xcoord != curr_xcoord)
+        self.failUnlessEqual(prev_xcoord, int(linfo_1['x']))
+
+        lscale.destroy()
+
+
+    def test_variable_change(self):
+        x = ttk.LabeledScale()
+        x.pack()
+        x.wait_visibility()
+        x.update()
+
+        curr_xcoord = x.scale.coords()[0]
+        newval = x.value + 1
+        x.value = newval
+        # The following update is needed since the test doesn't use mainloop,
+        # at the same time this shouldn't affect test outcome
+        x.update()
+        self.failUnlessEqual(x.label['text'], newval)
+        self.failUnless(x.scale.coords()[0] > curr_xcoord)
+        self.failUnlessEqual(x.scale.coords()[0],
+            int(x.label.place_info()['x']))
+
+        # value outside range
+        x.value = x.scale['to'] + 1 # no changes shouldn't happen
+        x.update()
+        self.failUnlessEqual(x.label['text'], newval)
+        self.failUnlessEqual(x.scale.coords()[0],
+            int(x.label.place_info()['x']))
+
+        x.destroy()
+
+
+    def test_resize(self):
+        x = ttk.LabeledScale()
+        x.pack(expand=True, fill='both')
+        x.wait_visibility()
+        x.update()
+
+        width, height = x.master.winfo_width(), x.master.winfo_height()
+        width, height = width * 2, height * 2
+
+        x.value = 3
+        x.update()
+        x.master.wm_geometry("%dx%d" % (width, height))
+        self.failUnlessEqual(int(x.label.place_info()['x']),
+            x.scale.coords()[0])
+
+        x.master.wm_geometry("%dx%d" % (width, height))
+        x.destroy()
+
+
+class OptionMenuTest(unittest.TestCase):
+
+    def setUp(self):
+        self.root = support.get_tk_root()
+        self.textvar = Tkinter.StringVar(self.root)
+
+    def tearDown(self):
+        del self.textvar
+        self.root.destroy()
+
+
+    def test_widget_destroy(self):
+        var = Tkinter.StringVar()
+        optmenu = ttk.OptionMenu(None, var)
+        name = var._name
+        optmenu.update_idletasks()
+        optmenu.destroy()
+        self.failUnlessEqual(optmenu.tk.globalgetvar(name), var.get())
+        del var
+        self.failUnlessRaises(Tkinter.TclError, optmenu.tk.globalgetvar, name)
+
+
+    def test_initialization(self):
+        self.failUnlessRaises(Tkinter.TclError,
+            ttk.OptionMenu, None, self.textvar, invalid='thing')
+
+        optmenu = ttk.OptionMenu(None, self.textvar, 'b', 'a', 'b')
+        self.failUnlessEqual(optmenu._variable.get(), 'b')
+
+        self.failUnless(optmenu['menu'])
+        self.failUnless(optmenu['textvariable'])
+
+        optmenu.destroy()
+
+
+    def test_menu(self):
+        items = ('a', 'b', 'c')
+        default = 'a'
+        optmenu = ttk.OptionMenu(None, self.textvar, default, *items)
+        found_default = False
+        for i in range(len(items)):
+            value = optmenu['menu'].entrycget(i, 'value')
+            self.failUnlessEqual(value, items[i])
+            if value == default:
+                found_default = True
+        self.failUnless(found_default)
+        optmenu.destroy()
+
+        # default shouldn't be in menu if it is not part of values
+        default = 'd'
+        optmenu = ttk.OptionMenu(None, self.textvar, default, *items)
+        curr = None
+        i = 0
+        while True:
+            last, curr = curr, optmenu['menu'].entryconfigure(i, 'value')
+            if last == curr:
+                # no more menu entries
+                break
+            self.failIf(curr == default)
+            i += 1
+        self.failUnlessEqual(i, len(items))
+
+        # check that variable is updated correctly
+        optmenu.pack()
+        optmenu.wait_visibility()
+        optmenu['menu'].invoke(0)
+        self.failUnlessEqual(optmenu._variable.get(), items[0])
+
+        # changing to an invalid index shouldn't change the variable
+        self.failUnlessRaises(Tkinter.TclError, optmenu['menu'].invoke, -1)
+        self.failUnlessEqual(optmenu._variable.get(), items[0])
+
+        optmenu.destroy()
+
+        # specifying a callback
+        success = []
+        def cb_test(item):
+            self.failUnlessEqual(item, items[1])
+            success.append(True)
+        optmenu = ttk.OptionMenu(None, self.textvar, 'a', command=cb_test,
+            *items)
+        optmenu['menu'].invoke(1)
+        if not success:
+            self.fail("Menu callback not invoked")
+
+        optmenu.destroy()
+
+
+tests_gui = (LabeledScaleTest, OptionMenuTest)
+
+if __name__ == "__main__":
+    run_unittest(*tests_gui)

Added: python/trunk/Lib/lib-tk/test/test_ttk/test_functions.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/test_ttk/test_functions.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,426 @@
+# -*- encoding: utf-8 -*-
+import sys
+import unittest
+import ttk
+
+class MockTclObj(object):
+    typename = 'test'
+
+    def __init__(self, val):
+        self.val = val
+
+    def __str__(self):
+        return unicode(self.val)
+
+
+class MockStateSpec(object):
+    typename = 'StateSpec'
+
+    def __init__(self, *args):
+        self.val = args
+
+    def __str__(self):
+        return ' '.join(self.val)
+
+
+class InternalFunctionsTest(unittest.TestCase):
+
+    def test_format_optdict(self):
+        def check_against(fmt_opts, result):
+            for i in range(0, len(fmt_opts), 2):
+                self.failUnlessEqual(result.pop(fmt_opts[i]), fmt_opts[i + 1])
+            if result:
+                self.fail("result still got elements: %s" % result)
+
+        # passing an empty dict should return an empty object (tuple here)
+        self.failIf(ttk._format_optdict({}))
+
+        # check list formatting
+        check_against(
+            ttk._format_optdict({'fg': 'blue', 'padding': [1, 2, 3, 4]}),
+            {'-fg': 'blue', '-padding': '1 2 3 4'})
+
+        # check tuple formatting (same as list)
+        check_against(
+            ttk._format_optdict({'test': (1, 2, '', 0)}),
+            {'-test': '1 2 {} 0'})
+
+        # check untouched values
+        check_against(
+            ttk._format_optdict({'test': {'left': 'as is'}}),
+            {'-test': {'left': 'as is'}})
+
+        # check script formatting and untouched value(s)
+        check_against(
+            ttk._format_optdict(
+                {'test': [1, -1, '', '2m', 0], 'nochange1': 3,
+                 'nochange2': 'abc def'}, script=True),
+            {'-test': '{1 -1 {} 2m 0}', '-nochange1': 3,
+             '-nochange2': 'abc def' })
+
+        opts = {u'αβγ': True, u'á': False}
+        orig_opts = opts.copy()
+        # check if giving unicode keys is fine
+        check_against(ttk._format_optdict(opts), {u'-αβγ': True, u'-á': False})
+        # opts should remain unchanged
+        self.failUnlessEqual(opts, orig_opts)
+
+        # passing values with spaces inside a tuple/list
+        check_against(
+            ttk._format_optdict(
+                {'option': ('one two', 'three')}),
+            {'-option': '{one two} three'})
+
+        # ignore an option
+        amount_opts = len(ttk._format_optdict(opts, ignore=(u'á'))) / 2
+        self.failUnlessEqual(amount_opts, len(opts) - 1)
+
+        # ignore non-existing options
+        amount_opts = len(ttk._format_optdict(opts, ignore=(u'á', 'b'))) / 2
+        self.failUnlessEqual(amount_opts, len(opts) - 1)
+
+        # ignore every option
+        self.failIf(ttk._format_optdict(opts, ignore=opts.keys()))
+
+
+    def test_format_mapdict(self):
+        opts = {'a': [('b', 'c', 'val'), ('d', 'otherval'), ('', 'single')]}
+        result = ttk._format_mapdict(opts)
+        self.failUnlessEqual(len(result), len(opts.keys()) * 2)
+        self.failUnlessEqual(result, ('-a', '{b c} val d otherval {} single'))
+        self.failUnlessEqual(ttk._format_mapdict(opts, script=True),
+            ('-a', '{{b c} val d otherval {} single}'))
+
+        self.failUnlessEqual(ttk._format_mapdict({2: []}), ('-2', ''))
+
+        opts = {u'üñíćódè': [(u'á', u'vãl')]}
+        result = ttk._format_mapdict(opts)
+        self.failUnlessEqual(result, (u'-üñíćódè', u'á vãl'))
+
+        # empty states
+        valid = {'opt': [('', u'', 'hi')]}
+        self.failUnlessEqual(ttk._format_mapdict(valid), ('-opt', '{ } hi'))
+
+        # when passing multiple states, they all must be strings
+        invalid = {'opt': [(1, 2, 'valid val')]}
+        self.failUnlessRaises(TypeError, ttk._format_mapdict, invalid)
+        invalid = {'opt': [([1], '2', 'valid val')]}
+        self.failUnlessRaises(TypeError, ttk._format_mapdict, invalid)
+        # but when passing a single state, it can be anything
+        valid = {'opt': [[1, 'value']]}
+        self.failUnlessEqual(ttk._format_mapdict(valid), ('-opt', '1 value'))
+        # special attention to single states which evalute to False
+        for stateval in (None, 0, False, '', set()): # just some samples
+            valid = {'opt': [(stateval, 'value')]}
+            self.failUnlessEqual(ttk._format_mapdict(valid),
+                ('-opt', '{} value'))
+
+        # values must be iterable
+        opts = {'a': None}
+        self.failUnlessRaises(TypeError, ttk._format_mapdict, opts)
+
+        # items in the value must have size >= 2
+        self.failUnlessRaises(IndexError, ttk._format_mapdict,
+            {'a': [('invalid', )]})
+
+
+    def test_format_elemcreate(self):
+        self.failUnless(ttk._format_elemcreate(None), (None, ()))
+
+        ## Testing type = image
+        # image type expects at least an image name, so this should raise
+        # IndexError since it tries to access the index 0 of an empty tuple
+        self.failUnlessRaises(IndexError, ttk._format_elemcreate, 'image')
+
+        # don't format returned values as a tcl script
+        # minimum acceptable for image type
+        self.failUnlessEqual(ttk._format_elemcreate('image', False, 'test'),
+            ("test ", ()))
+        # specifiyng a state spec
+        self.failUnlessEqual(ttk._format_elemcreate('image', False, 'test',
+            ('', 'a')), ("test {} a", ()))
+        # state spec with multiple states
+        self.failUnlessEqual(ttk._format_elemcreate('image', False, 'test',
+            ('a', 'b', 'c')), ("test {a b} c", ()))
+        # state spec and options
+        self.failUnlessEqual(ttk._format_elemcreate('image', False, 'test',
+            ('a', 'b'), a='x', b='y'), ("test a b", ("-a", "x", "-b", "y")))
+        # format returned values as a tcl script
+        # state spec with multiple states and an option with a multivalue
+        self.failUnlessEqual(ttk._format_elemcreate('image', True, 'test',
+            ('a', 'b', 'c', 'd'), x=[2, 3]), ("{test {a b c} d}", "-x {2 3}"))
+
+        ## Testing type = vsapi
+        # vsapi type expects at least a class name and a part_id, so this
+        # should raise an ValueError since it tries to get two elements from
+        # an empty tuple
+        self.failUnlessRaises(ValueError, ttk._format_elemcreate, 'vsapi')
+
+        # don't format returned values as a tcl script
+        # minimum acceptable for vsapi
+        self.failUnlessEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b'),
+            ("a b ", ()))
+        # now with a state spec with multiple states
+        self.failUnlessEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b',
+            ('a', 'b', 'c')), ("a b {a b} c", ()))
+        # state spec and option
+        self.failUnlessEqual(ttk._format_elemcreate('vsapi', False, 'a', 'b',
+            ('a', 'b'), opt='x'), ("a b a b", ("-opt", "x")))
+        # format returned values as a tcl script
+        # state spec with a multivalue and an option
+        self.failUnlessEqual(ttk._format_elemcreate('vsapi', True, 'a', 'b',
+            ('a', 'b', [1, 2]), opt='x'), ("{a b {a b} {1 2}}", "-opt x"))
+
+        # Testing type = from
+        # from type expects at least a type name
+        self.failUnlessRaises(IndexError, ttk._format_elemcreate, 'from')
+
+        self.failUnlessEqual(ttk._format_elemcreate('from', False, 'a'),
+            ('a', ()))
+        self.failUnlessEqual(ttk._format_elemcreate('from', False, 'a', 'b'),
+            ('a', ('b', )))
+        self.failUnlessEqual(ttk._format_elemcreate('from', True, 'a', 'b'),
+            ('{a}', 'b'))
+
+
+    def test_format_layoutlist(self):
+        def sample(indent=0, indent_size=2):
+            return ttk._format_layoutlist(
+            [('a', {'other': [1, 2, 3], 'children':
+                [('b', {'children':
+                    [('c', {'children':
+                        [('d', {'nice': 'opt'})], 'something': (1, 2)
+                    })]
+                })]
+            })], indent=indent, indent_size=indent_size)[0]
+
+        def sample_expected(indent=0, indent_size=2):
+            spaces = lambda amount=0: ' ' * (amount + indent)
+            return (
+                "%sa -other {1 2 3} -children {\n"
+                "%sb -children {\n"
+                "%sc -something {1 2} -children {\n"
+                "%sd -nice opt\n"
+                "%s}\n"
+                "%s}\n"
+                "%s}" % (spaces(), spaces(indent_size),
+                    spaces(2 * indent_size), spaces(3 * indent_size),
+                    spaces(2 * indent_size), spaces(indent_size), spaces()))
+
+        # empty layout
+        self.failUnlessEqual(ttk._format_layoutlist([])[0], '')
+
+        # smallest (after an empty one) acceptable layout
+        smallest = ttk._format_layoutlist([('a', None)], indent=0)
+        self.failUnlessEqual(smallest,
+            ttk._format_layoutlist([('a', '')], indent=0))
+        self.failUnlessEqual(smallest[0], 'a')
+
+        # testing indentation levels
+        self.failUnlessEqual(sample(), sample_expected())
+        for i in range(4):
+            self.failUnlessEqual(sample(i), sample_expected(i))
+            self.failUnlessEqual(sample(i, i), sample_expected(i, i))
+
+        # invalid layout format, different kind of exceptions will be
+        # raised
+
+        # plain wrong format
+        self.failUnlessRaises(ValueError, ttk._format_layoutlist,
+            ['bad', 'format'])
+        self.failUnlessRaises(TypeError, ttk._format_layoutlist, None)
+        # _format_layoutlist always expects the second item (in every item)
+        # to act like a dict (except when the value evalutes to False).
+        self.failUnlessRaises(AttributeError,
+            ttk._format_layoutlist, [('a', 'b')])
+        # bad children formatting
+        self.failUnlessRaises(ValueError, ttk._format_layoutlist,
+            [('name', {'children': {'a': None}})])
+
+
+    def test_script_from_settings(self):
+        # empty options
+        self.failIf(ttk._script_from_settings({'name':
+            {'configure': None, 'map': None, 'element create': None}}))
+
+        # empty layout
+        self.failUnlessEqual(
+            ttk._script_from_settings({'name': {'layout': None}}),
+            "ttk::style layout name {\nnull\n}")
+
+        configdict = {u'αβγ': True, u'á': False}
+        self.failUnless(
+            ttk._script_from_settings({'name': {'configure': configdict}}))
+
+        mapdict = {u'üñíćódè': [(u'á', u'vãl')]}
+        self.failUnless(
+            ttk._script_from_settings({'name': {'map': mapdict}}))
+
+        # invalid image element
+        self.failUnlessRaises(IndexError,
+            ttk._script_from_settings, {'name': {'element create': ['image']}})
+
+        # minimal valid image
+        self.failUnless(ttk._script_from_settings({'name':
+            {'element create': ['image', 'name']}}))
+
+        image = {'thing': {'element create':
+            ['image', 'name', ('state1', 'state2', 'val')]}}
+        self.failUnlessEqual(ttk._script_from_settings(image),
+            "ttk::style element create thing image {name {state1 state2} val} ")
+
+        image['thing']['element create'].append({'opt': 30})
+        self.failUnlessEqual(ttk._script_from_settings(image),
+            "ttk::style element create thing image {name {state1 state2} val} "
+            "-opt 30")
+
+        image['thing']['element create'][-1]['opt'] = [MockTclObj(3),
+            MockTclObj('2m')]
+        self.failUnlessEqual(ttk._script_from_settings(image),
+            "ttk::style element create thing image {name {state1 state2} val} "
+            "-opt {3 2m}")
+
+
+    def test_dict_from_tcltuple(self):
+        fakettuple = ('-a', '{1 2 3}', '-something', 'foo')
+
+        self.failUnlessEqual(ttk._dict_from_tcltuple(fakettuple, False),
+            {'-a': '{1 2 3}', '-something': 'foo'})
+
+        self.failUnlessEqual(ttk._dict_from_tcltuple(fakettuple),
+            {'a': '{1 2 3}', 'something': 'foo'})
+
+        # passing a tuple with a single item should return an empty dict,
+        # since it tries to break the tuple by pairs.
+        self.failIf(ttk._dict_from_tcltuple(('single', )))
+
+        sspec = MockStateSpec('a', 'b')
+        self.failUnlessEqual(ttk._dict_from_tcltuple(('-a', (sspec, 'val'))),
+            {'a': [('a', 'b', 'val')]})
+
+        self.failUnlessEqual(ttk._dict_from_tcltuple((MockTclObj('-padding'),
+            [MockTclObj('1'), 2, MockTclObj('3m')])),
+            {'padding': [1, 2, '3m']})
+
+
+    def test_list_from_statespec(self):
+        def test_it(sspec, value, res_value, states):
+            self.failUnlessEqual(ttk._list_from_statespec(
+                (sspec, value)), [states + (res_value, )])
+
+        states_even = tuple('state%d' % i for i in range(6))
+        statespec = MockStateSpec(*states_even)
+        test_it(statespec, 'val', 'val', states_even)
+        test_it(statespec, MockTclObj('val'), 'val', states_even)
+
+        states_odd = tuple('state%d' % i for i in range(5))
+        statespec = MockStateSpec(*states_odd)
+        test_it(statespec, 'val', 'val', states_odd)
+
+        test_it(('a', 'b', 'c'), MockTclObj('val'), 'val', ('a', 'b', 'c'))
+
+
+    def test_list_from_layouttuple(self):
+        # empty layout tuple
+        self.failIf(ttk._list_from_layouttuple(()))
+
+        # shortest layout tuple
+        self.failUnlessEqual(ttk._list_from_layouttuple(('name', )),
+            [('name', {})])
+
+        # not so interesting ltuple
+        sample_ltuple = ('name', '-option', 'value')
+        self.failUnlessEqual(ttk._list_from_layouttuple(sample_ltuple),
+            [('name', {'option': 'value'})])
+
+        # empty children
+        self.failUnlessEqual(ttk._list_from_layouttuple(
+            ('something', '-children', ())),
+            [('something', {'children': []})]
+        )
+
+        # more interesting ltuple
+        ltuple = (
+            'name', '-option', 'niceone', '-children', (
+                ('otherone', '-children', (
+                    ('child', )), '-otheropt', 'othervalue'
+                )
+            )
+        )
+        self.failUnlessEqual(ttk._list_from_layouttuple(ltuple),
+            [('name', {'option': 'niceone', 'children':
+                [('otherone', {'otheropt': 'othervalue', 'children':
+                    [('child', {})]
+                })]
+            })]
+        )
+
+        # bad tuples
+        self.failUnlessRaises(ValueError, ttk._list_from_layouttuple,
+            ('name', 'no_minus'))
+        self.failUnlessRaises(ValueError, ttk._list_from_layouttuple,
+            ('name', 'no_minus', 'value'))
+        self.failUnlessRaises(ValueError, ttk._list_from_layouttuple,
+            ('something', '-children')) # no children
+        self.failUnlessRaises(ValueError, ttk._list_from_layouttuple,
+            ('something', '-children', 'value')) # invalid children
+
+
+    def test_val_or_dict(self):
+        def func(opt, val=None):
+            if val is None:
+                return "test val"
+            return (opt, val)
+
+        options = {'test': None}
+        self.failUnlessEqual(ttk._val_or_dict(options, func), "test val")
+
+        options = {'test': 3}
+        self.failUnlessEqual(ttk._val_or_dict(options, func), options)
+
+
+    def test_convert_stringval(self):
+        tests = (
+            (0, 0), ('09', 9), ('a', 'a'), (u'áÚ', u'áÚ'), ([], '[]'),
+            (None, 'None')
+        )
+        for orig, expected in tests:
+            self.failUnlessEqual(ttk._convert_stringval(orig), expected)
+
+        if sys.getdefaultencoding() == 'ascii':
+            self.failUnlessRaises(UnicodeDecodeError,
+                ttk._convert_stringval, 'á')
+
+
+class TclObjsToPyTest(unittest.TestCase):
+
+    def test_unicode(self):
+        adict = {'opt': u'välúè'}
+        self.failUnlessEqual(ttk.tclobjs_to_py(adict), {'opt': u'välúè'})
+
+        adict['opt'] = MockTclObj(adict['opt'])
+        self.failUnlessEqual(ttk.tclobjs_to_py(adict), {'opt': u'välúè'})
+
+    def test_multivalues(self):
+        adict = {'opt': [1, 2, 3, 4]}
+        self.failUnlessEqual(ttk.tclobjs_to_py(adict), {'opt': [1, 2, 3, 4]})
+
+        adict['opt'] = [1, 'xm', 3]
+        self.failUnlessEqual(ttk.tclobjs_to_py(adict), {'opt': [1, 'xm', 3]})
+
+        adict['opt'] = (MockStateSpec('a', 'b'), u'válũè')
+        self.failUnlessEqual(ttk.tclobjs_to_py(adict),
+            {'opt': [('a', 'b', u'válũè')]})
+
+        self.failUnlessEqual(ttk.tclobjs_to_py({'x': ['y z']}),
+            {'x': ['y z']})
+
+    def test_nosplit(self):
+        self.failUnlessEqual(ttk.tclobjs_to_py({'text': 'some text'}),
+            {'text': 'some text'})
+
+tests_nogui = (InternalFunctionsTest, TclObjsToPyTest)
+
+if __name__ == "__main__":
+    from test.test_support import run_unittest
+    run_unittest(*tests_nogui)

Added: python/trunk/Lib/lib-tk/test/test_ttk/test_style.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/test_ttk/test_style.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,99 @@
+import unittest
+import Tkinter
+import ttk
+from test.test_support import requires, run_unittest
+
+import support
+
+requires('gui')
+
+class StyleTest(unittest.TestCase):
+
+    def setUp(self):
+        self.root = support.get_tk_root()
+        self.style = ttk.Style(self.root)
+
+    def tearDown(self):
+        # As tests have shown, these tests are likely to deliver
+        # <<ThemeChanged>> events after the root is destroyed, so
+        # lets let them happen now.
+        self.root.update_idletasks()
+        self.root.destroy()
+
+
+    def test_configure(self):
+        style = self.style
+        style.configure('TButton', background='yellow')
+        self.failUnlessEqual(style.configure('TButton', 'background'),
+            'yellow')
+        self.failUnless(isinstance(style.configure('TButton'), dict))
+
+
+    def test_map(self):
+        style = self.style
+        style.map('TButton', background=[('active', 'background', 'blue')])
+        self.failUnlessEqual(style.map('TButton', 'background'),
+            [('active', 'background', 'blue')])
+        self.failUnless(isinstance(style.map('TButton'), dict))
+
+
+    def test_lookup(self):
+        style = self.style
+        style.configure('TButton', background='yellow')
+        style.map('TButton', background=[('active', 'background', 'blue')])
+
+        self.failUnlessEqual(style.lookup('TButton', 'background'), 'yellow')
+        self.failUnlessEqual(style.lookup('TButton', 'background',
+            ['active', 'background']), 'blue')
+        self.failUnlessEqual(style.lookup('TButton', 'optionnotdefined',
+            default='iknewit'), 'iknewit')
+
+
+    def test_layout(self):
+        style = self.style
+        self.failUnlessRaises(Tkinter.TclError, style.layout, 'NotALayout')
+        tv_style = style.layout('Treeview')
+
+        # "erase" Treeview layout
+        style.layout('Treeview', '')
+        self.failUnlessEqual(style.layout('Treeview'),
+            [('null', {'sticky': 'nswe'})]
+        )
+
+        # restore layout
+        style.layout('Treeview', tv_style)
+        self.failUnlessEqual(style.layout('Treeview'), tv_style)
+
+        # should return a list
+        self.failUnless(isinstance(style.layout('TButton'), list))
+
+        # correct layout, but "option" doesn't exist as option
+        self.failUnlessRaises(Tkinter.TclError, style.layout, 'Treeview',
+            [('name', {'option': 'inexistant'})])
+
+
+    def test_theme_use(self):
+        self.failUnlessRaises(Tkinter.TclError, self.style.theme_use,
+            'nonexistingname')
+
+        curr_theme = self.style.theme_use()
+        new_theme = None
+        for theme in self.style.theme_names():
+            if theme != curr_theme:
+                new_theme = theme
+                self.style.theme_use(theme)
+                break
+        else:
+            # just one theme available, can't go on with tests
+            return
+
+        self.failIf(curr_theme == new_theme)
+        self.failIf(new_theme != self.style.theme_use())
+
+        self.style.theme_use(curr_theme)
+
+
+tests_gui = (StyleTest, )
+
+if __name__ == "__main__":
+    run_unittest(*tests_gui)

Added: python/trunk/Lib/lib-tk/test/test_ttk/test_widgets.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/test/test_ttk/test_widgets.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,1115 @@
+import unittest
+import Tkinter
+import ttk
+from test.test_support import requires, run_unittest
+
+import support
+from test_functions import MockTclObj, MockStateSpec
+
+requires('gui')
+
+class WidgetTest(unittest.TestCase):
+    """Tests methods available in every ttk widget."""
+
+    def setUp(self):
+        self.widget = ttk.Button()
+        self.widget.pack()
+        self.widget.wait_visibility()
+
+    def tearDown(self):
+        self.widget.destroy()
+
+
+    def test_identify(self):
+        self.widget.update_idletasks()
+        self.failUnlessEqual(self.widget.identify(5, 5), "label")
+        self.failUnlessEqual(self.widget.identify(-1, -1), "")
+
+        self.failUnlessRaises(Tkinter.TclError, self.widget.identify, None, 5)
+        self.failUnlessRaises(Tkinter.TclError, self.widget.identify, 5, None)
+        self.failUnlessRaises(Tkinter.TclError, self.widget.identify, 5, '')
+
+
+    def test_widget_state(self):
+        # XXX not sure about the portability of all these tests
+        self.failUnlessEqual(self.widget.state(), ())
+        self.failUnlessEqual(self.widget.instate(['!disabled']), True)
+
+        # changing from !disabled to disabled
+        self.failUnlessEqual(self.widget.state(['disabled']), ('!disabled', ))
+        # no state change
+        self.failUnlessEqual(self.widget.state(['disabled']), ())
+        # change back to !disable but also active
+        self.failUnlessEqual(self.widget.state(['!disabled', 'active']),
+            ('!active', 'disabled'))
+        # no state changes, again
+        self.failUnlessEqual(self.widget.state(['!disabled', 'active']), ())
+        self.failUnlessEqual(self.widget.state(['active', '!disabled']), ())
+
+        def test_cb(arg1, **kw):
+            return arg1, kw
+        self.failUnlessEqual(self.widget.instate(['!disabled'],
+            test_cb, "hi", **{"msg": "there"}),
+            ('hi', {'msg': 'there'}))
+
+        # attempt to set invalid statespec
+        currstate = self.widget.state()
+        self.failUnlessRaises(Tkinter.TclError, self.widget.instate,
+            ['badstate'])
+        self.failUnlessRaises(Tkinter.TclError, self.widget.instate,
+            ['disabled', 'badstate'])
+        # verify that widget didn't change its state
+        self.failUnlessEqual(currstate, self.widget.state())
+
+        # ensuring that passing None as state doesn't modify current state
+        self.widget.state(['active', '!disabled'])
+        self.failUnlessEqual(self.widget.state(), ('active', ))
+
+
+class ButtonTest(unittest.TestCase):
+
+    def test_invoke(self):
+        success = []
+        btn = ttk.Button(command=lambda: success.append(1))
+        btn.invoke()
+        self.failUnless(success)
+
+
+class CheckbuttonTest(unittest.TestCase):
+
+    def test_invoke(self):
+        success = []
+        def cb_test():
+            success.append(1)
+            return "cb test called"
+
+        cbtn = ttk.Checkbutton(command=cb_test)
+        # the variable automatically created by ttk.Checkbutton is actually
+        # undefined till we invoke the Checkbutton
+        self.failUnlessEqual(cbtn.state(), ('alternate', ))
+        self.failUnlessRaises(Tkinter.TclError, cbtn.tk.globalgetvar,
+            cbtn['variable'])
+
+        res = cbtn.invoke()
+        self.failUnlessEqual(res, "cb test called")
+        self.failUnlessEqual(cbtn['onvalue'],
+            cbtn.tk.globalgetvar(cbtn['variable']))
+        self.failUnless(success)
+
+        cbtn['command'] = ''
+        res = cbtn.invoke()
+        self.failUnlessEqual(res, '')
+        self.failIf(len(success) > 1)
+        self.failUnlessEqual(cbtn['offvalue'],
+            cbtn.tk.globalgetvar(cbtn['variable']))
+
+
+class ComboboxTest(unittest.TestCase):
+
+    def setUp(self):
+        self.combo = ttk.Combobox()
+
+    def tearDown(self):
+        self.combo.destroy()
+
+    def _show_drop_down_listbox(self):
+        width = self.combo.winfo_width()
+        self.combo.event_generate('<ButtonPress-1>', x=width - 5, y=5)
+        self.combo.event_generate('<ButtonRelease-1>', x=width - 5, y=5)
+        self.combo.update_idletasks()
+
+
+    def test_virtual_event(self):
+        success = []
+
+        self.combo['values'] = [1]
+        self.combo.bind('<<ComboboxSelected>>',
+            lambda evt: success.append(True))
+        self.combo.pack()
+        self.combo.wait_visibility()
+
+        height = self.combo.winfo_height()
+        self._show_drop_down_listbox()
+        self.combo.update()
+        self.combo.event_generate('<Return>')
+        self.combo.update()
+
+        self.failUnless(success)
+
+
+    def test_postcommand(self):
+        success = []
+
+        self.combo['postcommand'] = lambda: success.append(True)
+        self.combo.pack()
+        self.combo.wait_visibility()
+
+        self._show_drop_down_listbox()
+        self.failUnless(success)
+
+        # testing postcommand removal
+        self.combo['postcommand'] = ''
+        self._show_drop_down_listbox()
+        self.failUnlessEqual(len(success), 1)
+
+
+    def test_values(self):
+        def check_get_current(getval, currval):
+            self.failUnlessEqual(self.combo.get(), getval)
+            self.failUnlessEqual(self.combo.current(), currval)
+
+        check_get_current('', -1)
+
+        self.combo['values'] = ['a', 1, 'c']
+
+        self.combo.set('c')
+        check_get_current('c', 2)
+
+        self.combo.current(0)
+        check_get_current('a', 0)
+
+        self.combo.set('d')
+        check_get_current('d', -1)
+
+        # testing values with empty string
+        self.combo.set('')
+        self.combo['values'] = (1, 2, '', 3)
+        check_get_current('', 2)
+
+        # testing values with empty string set through configure
+        self.combo.configure(values=[1, '', 2])
+        self.failUnlessEqual(self.combo['values'], ('1', '', '2'))
+
+        # out of range
+        self.failUnlessRaises(Tkinter.TclError, self.combo.current,
+            len(self.combo['values']))
+        # it expects an integer (or something that can be converted to int)
+        self.failUnlessRaises(Tkinter.TclError, self.combo.current, '')
+
+        # testing creating combobox with empty string in values
+        combo2 = ttk.Combobox(values=[1, 2, ''])
+        self.failUnlessEqual(combo2['values'], ('1', '2', ''))
+        combo2.destroy()
+
+
+class EntryTest(unittest.TestCase):
+
+    def setUp(self):
+        self.entry = ttk.Entry()
+
+    def tearDown(self):
+        self.entry.destroy()
+
+
+    def test_bbox(self):
+        self.failUnlessEqual(len(self.entry.bbox(0)), 4)
+        for item in self.entry.bbox(0):
+            self.failUnless(isinstance(item, int))
+
+        self.failUnlessRaises(Tkinter.TclError, self.entry.bbox, 'noindex')
+        self.failUnlessRaises(Tkinter.TclError, self.entry.bbox, None)
+
+
+    def test_identify(self):
+        self.entry.pack()
+        self.entry.wait_visibility()
+        self.entry.update_idletasks()
+
+        self.failUnlessEqual(self.entry.identify(5, 5), "textarea")
+        self.failUnlessEqual(self.entry.identify(-1, -1), "")
+
+        self.failUnlessRaises(Tkinter.TclError, self.entry.identify, None, 5)
+        self.failUnlessRaises(Tkinter.TclError, self.entry.identify, 5, None)
+        self.failUnlessRaises(Tkinter.TclError, self.entry.identify, 5, '')
+
+
+    def test_validation_options(self):
+        success = []
+        test_invalid = lambda: success.append(True)
+
+        self.entry['validate'] = 'none'
+        self.entry['validatecommand'] = lambda: False
+
+        self.entry['invalidcommand'] = test_invalid
+        self.entry.validate()
+        self.failUnless(success)
+
+        self.entry['invalidcommand'] = ''
+        self.entry.validate()
+        self.failUnlessEqual(len(success), 1)
+
+        self.entry['invalidcommand'] = test_invalid
+        self.entry['validatecommand'] = lambda: True
+        self.entry.validate()
+        self.failUnlessEqual(len(success), 1)
+
+        self.entry['validatecommand'] = ''
+        self.entry.validate()
+        self.failUnlessEqual(len(success), 1)
+
+        self.entry['validatecommand'] = True
+        self.failUnlessRaises(Tkinter.TclError, self.entry.validate)
+
+
+    def test_validation(self):
+        validation = []
+        def validate(to_insert):
+            if not 'a' <= to_insert.lower() <= 'z':
+                validation.append(False)
+                return False
+            validation.append(True)
+            return True
+
+        self.entry['validate'] = 'key'
+        self.entry['validatecommand'] = self.entry.register(validate), '%S'
+
+        self.entry.insert('end', 1)
+        self.entry.insert('end', 'a')
+        self.failUnlessEqual(validation, [False, True])
+        self.failUnlessEqual(self.entry.get(), 'a')
+
+
+    def test_revalidation(self):
+        def validate(content):
+            for letter in content:
+                if not 'a' <= letter.lower() <= 'z':
+                    return False
+            return True
+
+        self.entry['validatecommand'] = self.entry.register(validate), '%P'
+
+        self.entry.insert('end', 'avocado')
+        self.failUnlessEqual(self.entry.validate(), True)
+        self.failUnlessEqual(self.entry.state(), ())
+
+        self.entry.delete(0, 'end')
+        self.failUnlessEqual(self.entry.get(), '')
+
+        self.entry.insert('end', 'a1b')
+        self.failUnlessEqual(self.entry.validate(), False)
+        self.failUnlessEqual(self.entry.state(), ('invalid', ))
+
+        self.entry.delete(1)
+        self.failUnlessEqual(self.entry.validate(), True)
+        self.failUnlessEqual(self.entry.state(), ())
+
+
+class PanedwindowTest(unittest.TestCase):
+
+    def setUp(self):
+        self.paned = ttk.Panedwindow()
+
+    def tearDown(self):
+        self.paned.destroy()
+
+
+    def test_add(self):
+        # attempt to add a child that is not a direct child of the paned window
+        label = ttk.Label(self.paned)
+        child = ttk.Label(label)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.add, child)
+        label.destroy()
+        child.destroy()
+        # another attempt
+        label = ttk.Label()
+        child = ttk.Label(label)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.add, child)
+        child.destroy()
+        label.destroy()
+
+        good_child = ttk.Label()
+        self.paned.add(good_child)
+        # re-adding a child is not accepted
+        self.failUnlessRaises(Tkinter.TclError, self.paned.add, good_child)
+
+        other_child = ttk.Label(self.paned)
+        self.paned.add(other_child)
+        self.failUnlessEqual(self.paned.pane(0), self.paned.pane(1))
+        self.failUnlessRaises(Tkinter.TclError, self.paned.pane, 2)
+        good_child.destroy()
+        other_child.destroy()
+        self.failUnlessRaises(Tkinter.TclError, self.paned.pane, 0)
+
+
+    def test_forget(self):
+        self.failUnlessRaises(Tkinter.TclError, self.paned.forget, None)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.forget, 0)
+
+        self.paned.add(ttk.Label())
+        self.paned.forget(0)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.forget, 0)
+
+
+    def test_insert(self):
+        self.failUnlessRaises(Tkinter.TclError, self.paned.insert, None, 0)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.insert, 0, None)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.insert, 0, 0)
+
+        child = ttk.Label()
+        child2 = ttk.Label()
+        child3 = ttk.Label()
+
+        self.failUnlessRaises(Tkinter.TclError, self.paned.insert, 0, child)
+
+        self.paned.insert('end', child2)
+        self.paned.insert(0, child)
+        self.failUnlessEqual(self.paned.panes(), (str(child), str(child2)))
+
+        self.paned.insert(0, child2)
+        self.failUnlessEqual(self.paned.panes(), (str(child2), str(child)))
+
+        self.paned.insert('end', child3)
+        self.failUnlessEqual(self.paned.panes(),
+            (str(child2), str(child), str(child3)))
+
+        # reinserting a child should move it to its current position
+        panes = self.paned.panes()
+        self.paned.insert('end', child3)
+        self.failUnlessEqual(panes, self.paned.panes())
+
+        # moving child3 to child2 position should result in child2 ending up
+        # in previous child position and child ending up in previous child3
+        # position
+        self.paned.insert(child2, child3)
+        self.failUnlessEqual(self.paned.panes(),
+            (str(child3), str(child2), str(child)))
+
+
+    def test_pane(self):
+        self.failUnlessRaises(Tkinter.TclError, self.paned.pane, 0)
+
+        child = ttk.Label()
+        self.paned.add(child)
+        self.failUnless(isinstance(self.paned.pane(0), dict))
+        self.failUnlessEqual(self.paned.pane(0, weight=None), 0)
+        # newer form for querying a single option
+        self.failUnlessEqual(self.paned.pane(0, 'weight'), 0)
+        self.failUnlessEqual(self.paned.pane(0), self.paned.pane(str(child)))
+
+        self.failUnlessRaises(Tkinter.TclError, self.paned.pane, 0,
+            badoption='somevalue')
+
+
+    def test_sashpos(self):
+        self.failUnlessRaises(Tkinter.TclError, self.paned.sashpos, None)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.sashpos, '')
+        self.failUnlessRaises(Tkinter.TclError, self.paned.sashpos, 0)
+
+        child = ttk.Label(self.paned, text='a')
+        self.paned.add(child, weight=1)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.sashpos, 0)
+        child2 = ttk.Label(self.paned, text='b')
+        self.paned.add(child2)
+        self.failUnlessRaises(Tkinter.TclError, self.paned.sashpos, 1)
+
+        self.paned.pack(expand=True, fill='both')
+        self.paned.wait_visibility()
+
+        curr_pos = self.paned.sashpos(0)
+        self.paned.sashpos(0, 1000)
+        self.failUnless(curr_pos != self.paned.sashpos(0))
+        self.failUnless(isinstance(self.paned.sashpos(0), int))
+
+
+class RadiobuttonTest(unittest.TestCase):
+
+    def test_invoke(self):
+        success = []
+        def cb_test():
+            success.append(1)
+            return "cb test called"
+
+        myvar = Tkinter.IntVar()
+        cbtn = ttk.Radiobutton(command=cb_test, variable=myvar, value=0)
+        cbtn2 = ttk.Radiobutton(command=cb_test, variable=myvar, value=1)
+
+        res = cbtn.invoke()
+        self.failUnlessEqual(res, "cb test called")
+        self.failUnlessEqual(cbtn['value'], myvar.get())
+        self.failUnlessEqual(myvar.get(),
+            cbtn.tk.globalgetvar(cbtn['variable']))
+        self.failUnless(success)
+
+        cbtn2['command'] = ''
+        res = cbtn2.invoke()
+        self.failUnlessEqual(res, '')
+        self.failIf(len(success) > 1)
+        self.failUnlessEqual(cbtn2['value'], myvar.get())
+        self.failUnlessEqual(myvar.get(),
+            cbtn.tk.globalgetvar(cbtn['variable']))
+
+        self.failUnlessEqual(str(cbtn['variable']), str(cbtn2['variable']))
+
+
+
+class ScaleTest(unittest.TestCase):
+
+    def setUp(self):
+        self.scale = ttk.Scale()
+        self.scale.pack()
+        self.scale.update()
+
+    def tearDown(self):
+        self.scale.destroy()
+
+
+    def test_custom_event(self):
+        failure = [1, 1, 1] # will need to be empty
+
+        funcid = self.scale.bind('<<RangeChanged>>', lambda evt: failure.pop())
+
+        self.scale['from'] = 10
+        self.scale['from_'] = 10
+        self.scale['to'] = 3
+
+        self.failIf(failure)
+
+        failure = [1, 1, 1]
+        self.scale.configure(from_=2, to=5)
+        self.scale.configure(from_=0, to=-2)
+        self.scale.configure(to=10)
+
+        self.failIf(failure)
+
+
+    def test_get(self):
+        scale_width = self.scale.winfo_width()
+        self.failUnlessEqual(self.scale.get(scale_width, 0), self.scale['to'])
+
+        self.failUnlessEqual(self.scale.get(0, 0), self.scale['from'])
+        self.failUnlessEqual(self.scale.get(), self.scale['value'])
+        self.scale['value'] = 30
+        self.failUnlessEqual(self.scale.get(), self.scale['value'])
+
+        self.failUnlessRaises(Tkinter.TclError, self.scale.get, '', 0)
+        self.failUnlessRaises(Tkinter.TclError, self.scale.get, 0, '')
+
+
+    def test_set(self):
+        # set restricts the max/min values according to the current range
+        max = self.scale['to']
+        new_max = max + 10
+        self.scale.set(new_max)
+        self.failUnlessEqual(self.scale.get(), max)
+        min = self.scale['from']
+        self.scale.set(min - 1)
+        self.failUnlessEqual(self.scale.get(), min)
+
+        # changing directly the variable doesn't impose this limitation tho
+        var = Tkinter.DoubleVar()
+        self.scale['variable'] = var
+        var.set(max + 5)
+        self.failUnlessEqual(self.scale.get(), var.get())
+        self.failUnlessEqual(self.scale.get(), max + 5)
+        del var
+
+        # the same happens with the value option
+        self.scale['value'] = max + 10
+        self.failUnlessEqual(self.scale.get(), max + 10)
+        self.failUnlessEqual(self.scale.get(), self.scale['value'])
+
+        # nevertheless, note that the max/min values we can get specifying
+        # x, y coords are the ones according to the current range
+        self.failUnlessEqual(self.scale.get(0, 0), min)
+        self.failUnlessEqual(self.scale.get(self.scale.winfo_width(), 0), max)
+
+        self.failUnlessRaises(Tkinter.TclError, self.scale.set, None)
+
+
+class NotebookTest(unittest.TestCase):
+
+    def setUp(self):
+        self.nb = ttk.Notebook()
+        self.child1 = ttk.Label()
+        self.child2 = ttk.Label()
+        self.nb.add(self.child1, text='a')
+        self.nb.add(self.child2, text='b')
+
+    def tearDown(self):
+        self.child1.destroy()
+        self.child2.destroy()
+        self.nb.destroy()
+
+
+    def test_tab_identifiers(self):
+        self.nb.forget(0)
+        self.nb.hide(self.child2)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.tab, self.child1)
+        self.failUnlessEqual(self.nb.index('end'), 1)
+        self.nb.add(self.child2)
+        self.failUnlessEqual(self.nb.index('end'), 1)
+        self.nb.select(self.child2)
+
+        self.failUnless(self.nb.tab('current'))
+        self.nb.add(self.child1, text='a')
+
+        self.nb.pack()
+        self.nb.wait_visibility()
+        self.failUnlessEqual(self.nb.tab('@5,5'), self.nb.tab('current'))
+
+        for i in range(5, 100, 5):
+            if self.nb.tab('@%d, 5' % i, text=None) == 'a':
+                break
+        else:
+            self.fail("Tab with text 'a' not found")
+
+
+    def test_add_and_hidden(self):
+        self.failUnlessRaises(Tkinter.TclError, self.nb.hide, -1)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.hide, 'hi')
+        self.failUnlessRaises(Tkinter.TclError, self.nb.hide, None)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.add, None)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.add, ttk.Label(),
+            unknown='option')
+
+        tabs = self.nb.tabs()
+        self.nb.hide(self.child1)
+        self.nb.add(self.child1)
+        self.failUnlessEqual(self.nb.tabs(), tabs)
+
+        child = ttk.Label()
+        self.nb.add(child, text='c')
+        tabs = self.nb.tabs()
+
+        curr = self.nb.index('current')
+        # verify that the tab gets readded at its previous position
+        child2_index = self.nb.index(self.child2)
+        self.nb.hide(self.child2)
+        self.nb.add(self.child2)
+        self.failUnlessEqual(self.nb.tabs(), tabs)
+        self.failUnlessEqual(self.nb.index(self.child2), child2_index)
+        self.failUnless(str(self.child2) == self.nb.tabs()[child2_index])
+        # but the tab next to it (not hidden) is the one selected now
+        self.failUnlessEqual(self.nb.index('current'), curr + 1)
+
+
+    def test_forget(self):
+        self.failUnlessRaises(Tkinter.TclError, self.nb.forget, -1)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.forget, 'hi')
+        self.failUnlessRaises(Tkinter.TclError, self.nb.forget, None)
+
+        tabs = self.nb.tabs()
+        child1_index = self.nb.index(self.child1)
+        self.nb.forget(self.child1)
+        self.failIf(str(self.child1) in self.nb.tabs())
+        self.failUnlessEqual(len(tabs) - 1, len(self.nb.tabs()))
+
+        self.nb.add(self.child1)
+        self.failUnlessEqual(self.nb.index(self.child1), 1)
+        self.failIf(child1_index == self.nb.index(self.child1))
+
+
+    def test_index(self):
+        self.failUnlessRaises(Tkinter.TclError, self.nb.index, -1)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.index, None)
+
+        self.failUnless(isinstance(self.nb.index('end'), int))
+        self.failUnlessEqual(self.nb.index(self.child1), 0)
+        self.failUnlessEqual(self.nb.index(self.child2), 1)
+        self.failUnlessEqual(self.nb.index('end'), 2)
+
+
+    def test_insert(self):
+        # moving tabs
+        tabs = self.nb.tabs()
+        self.nb.insert(1, tabs[0])
+        self.failUnlessEqual(self.nb.tabs(), (tabs[1], tabs[0]))
+        self.nb.insert(self.child1, self.child2)
+        self.failUnlessEqual(self.nb.tabs(), tabs)
+        self.nb.insert('end', self.child1)
+        self.failUnlessEqual(self.nb.tabs(), (tabs[1], tabs[0]))
+        self.nb.insert('end', 0)
+        self.failUnlessEqual(self.nb.tabs(), tabs)
+        # bad moves
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, 2, tabs[0])
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, -1, tabs[0])
+
+        # new tab
+        child3 = ttk.Label()
+        self.nb.insert(1, child3)
+        self.failUnlessEqual(self.nb.tabs(), (tabs[0], str(child3), tabs[1]))
+        self.nb.forget(child3)
+        self.failUnlessEqual(self.nb.tabs(), tabs)
+        self.nb.insert(self.child1, child3)
+        self.failUnlessEqual(self.nb.tabs(), (str(child3), ) + tabs)
+        self.nb.forget(child3)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, 2, child3)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, -1, child3)
+
+        # bad inserts
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, 'end', None)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, None, 0)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.insert, None, None)
+
+
+    def test_select(self):
+        self.nb.pack()
+        self.nb.wait_visibility()
+
+        success = []
+        tab_changed = []
+
+        self.child1.bind('<Unmap>', lambda evt: success.append(True))
+        self.nb.bind('<<NotebookTabChanged>>',
+            lambda evt: tab_changed.append(True))
+
+        self.failUnlessEqual(self.nb.select(), str(self.child1))
+        self.nb.select(self.child2)
+        self.failUnless(success)
+        self.failUnlessEqual(self.nb.select(), str(self.child2))
+
+        self.nb.update()
+        self.failUnless(tab_changed)
+
+
+    def test_tab(self):
+        self.failUnlessRaises(Tkinter.TclError, self.nb.tab, -1)
+        self.failUnlessRaises(Tkinter.TclError, self.nb.tab, 'notab')
+        self.failUnlessRaises(Tkinter.TclError, self.nb.tab, None)
+
+        self.failUnless(isinstance(self.nb.tab(self.child1), dict))
+        self.failUnlessEqual(self.nb.tab(self.child1, text=None), 'a')
+        # newer form for querying a single option
+        self.failUnlessEqual(self.nb.tab(self.child1, 'text'), 'a')
+        self.nb.tab(self.child1, text='abc')
+        self.failUnlessEqual(self.nb.tab(self.child1, text=None), 'abc')
+        self.failUnlessEqual(self.nb.tab(self.child1, 'text'), 'abc')
+
+
+    def test_tabs(self):
+        self.failUnlessEqual(len(self.nb.tabs()), 2)
+
+        self.nb.forget(self.child1)
+        self.nb.forget(self.child2)
+
+        self.failUnlessEqual(self.nb.tabs(), ())
+
+
+    def test_traversal(self):
+        self.nb.pack()
+        self.nb.wait_visibility()
+
+        self.nb.select(0)
+
+        support.simulate_mouse_click(self.nb, 5, 5)
+        self.nb.event_generate('<Control-Tab>')
+        self.failUnlessEqual(self.nb.select(), str(self.child2))
+        self.nb.event_generate('<Shift-Control-Tab>')
+        self.failUnlessEqual(self.nb.select(), str(self.child1))
+        self.nb.event_generate('<Shift-Control-Tab>')
+        self.failUnlessEqual(self.nb.select(), str(self.child2))
+
+        self.nb.tab(self.child1, text='a', underline=0)
+        self.nb.enable_traversal()
+        self.nb.event_generate('<Alt-a>')
+        self.failUnlessEqual(self.nb.select(), str(self.child1))
+
+
+class TreeviewTest(unittest.TestCase):
+
+    def setUp(self):
+        self.tv = ttk.Treeview()
+
+    def tearDown(self):
+        self.tv.destroy()
+
+
+    def test_bbox(self):
+        self.tv.pack()
+        self.failUnlessEqual(self.tv.bbox(''), '')
+        self.tv.wait_visibility()
+        self.tv.update()
+
+        item_id = self.tv.insert('', 'end')
+        children = self.tv.get_children()
+        self.failUnless(children)
+
+        bbox = self.tv.bbox(children[0])
+        self.failUnlessEqual(len(bbox), 4)
+        self.failUnless(isinstance(bbox, tuple))
+        for item in bbox:
+            if not isinstance(item, int):
+                self.fail("Invalid bounding box: %s" % bbox)
+                break
+
+        # compare width in bboxes
+        self.tv['columns'] = ['test']
+        self.tv.column('test', width=50)
+        bbox_column0 = self.tv.bbox(children[0], 0)
+        root_width = self.tv.column('#0', width=None)
+        self.failUnlessEqual(bbox_column0[0], bbox[0] + root_width)
+
+        # verify that bbox of a closed item is the empty string
+        child1 = self.tv.insert(item_id, 'end')
+        self.failUnlessEqual(self.tv.bbox(child1), '')
+
+
+    def test_children(self):
+        # no children yet, should get an empty tuple
+        self.failUnlessEqual(self.tv.get_children(), ())
+
+        item_id = self.tv.insert('', 'end')
+        self.failUnless(isinstance(self.tv.get_children(), tuple))
+        self.failUnlessEqual(self.tv.get_children()[0], item_id)
+
+        # add item_id and child3 as children of child2
+        child2 = self.tv.insert('', 'end')
+        child3 = self.tv.insert('', 'end')
+        self.tv.set_children(child2, item_id, child3)
+        self.failUnlessEqual(self.tv.get_children(child2), (item_id, child3))
+
+        # child3 has child2 as parent, thus trying to set child2 as a children
+        # of child3 should result in an error
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.set_children, child3, child2)
+
+        # remove child2 children
+        self.tv.set_children(child2)
+        self.failUnlessEqual(self.tv.get_children(child2), ())
+
+        # remove root's children
+        self.tv.set_children('')
+        self.failUnlessEqual(self.tv.get_children(), ())
+
+
+    def test_column(self):
+        # return a dict with all options/values
+        self.failUnless(isinstance(self.tv.column('#0'), dict))
+        # return a single value of the given option
+        self.failUnless(isinstance(self.tv.column('#0', width=None), int))
+        # set a new value for an option
+        self.tv.column('#0', width=10)
+        # testing new way to get option value
+        self.failUnlessEqual(self.tv.column('#0', 'width'), 10)
+        self.failUnlessEqual(self.tv.column('#0', width=None), 10)
+        # check read-only option
+        self.failUnlessRaises(Tkinter.TclError, self.tv.column, '#0', id='X')
+
+        self.failUnlessRaises(Tkinter.TclError, self.tv.column, 'invalid')
+        invalid_kws = [
+            {'unknown_option': 'some value'},  {'stretch': 'wrong'},
+            {'anchor': 'wrong'}, {'width': 'wrong'}, {'minwidth': 'wrong'}
+        ]
+        for kw in invalid_kws:
+            self.failUnlessRaises(Tkinter.TclError, self.tv.column, '#0',
+                **kw)
+
+
+    def test_delete(self):
+        self.failUnlessRaises(Tkinter.TclError, self.tv.delete, '#0')
+
+        item_id = self.tv.insert('', 'end')
+        item2 = self.tv.insert(item_id, 'end')
+        self.failUnlessEqual(self.tv.get_children(), (item_id, ))
+        self.failUnlessEqual(self.tv.get_children(item_id), (item2, ))
+
+        self.tv.delete(item_id)
+        self.failIf(self.tv.get_children())
+
+        # reattach should fail
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.reattach, item_id, '', 'end')
+
+        # test multiple item delete
+        item1 = self.tv.insert('', 'end')
+        item2 = self.tv.insert('', 'end')
+        self.failUnlessEqual(self.tv.get_children(), (item1, item2))
+
+        self.tv.delete(item1, item2)
+        self.failIf(self.tv.get_children())
+
+
+    def test_detach_reattach(self):
+        item_id = self.tv.insert('', 'end')
+        item2 = self.tv.insert(item_id, 'end')
+
+        # calling detach without items is valid, although it does nothing
+        prev = self.tv.get_children()
+        self.tv.detach() # this should do nothing
+        self.failUnlessEqual(prev, self.tv.get_children())
+
+        self.failUnlessEqual(self.tv.get_children(), (item_id, ))
+        self.failUnlessEqual(self.tv.get_children(item_id), (item2, ))
+
+        # detach item with children
+        self.tv.detach(item_id)
+        self.failIf(self.tv.get_children())
+
+        # reattach item with children
+        self.tv.reattach(item_id, '', 'end')
+        self.failUnlessEqual(self.tv.get_children(), (item_id, ))
+        self.failUnlessEqual(self.tv.get_children(item_id), (item2, ))
+
+        # move a children to the root
+        self.tv.move(item2, '', 'end')
+        self.failUnlessEqual(self.tv.get_children(), (item_id, item2))
+        self.failUnlessEqual(self.tv.get_children(item_id), ())
+
+        # bad values
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.reattach, 'nonexistant', '', 'end')
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.detach, 'nonexistant')
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.reattach, item2, 'otherparent', 'end')
+        self.failUnlessRaises(Tkinter.TclError,
+            self.tv.reattach, item2, '', 'invalid')
+
+        # multiple detach
+        self.tv.detach(item_id, item2)
+        self.failUnlessEqual(self.tv.get_children(), ())
+        self.failUnlessEqual(self.tv.get_children(item_id), ())
+
+
+    def test_exists(self):
+        self.failUnlessEqual(self.tv.exists('something'), False)
+        self.failUnlessEqual(self.tv.exists(''), True)
+        self.failUnlessEqual(self.tv.exists({}), False)
+
+        # the following will make a tk.call equivalent to
+        # tk.call(treeview, "exists") which should result in an error
+        # in the tcl interpreter since tk requires an item.
+        self.failUnlessRaises(Tkinter.TclError, self.tv.exists, None)
+
+
+    def test_focus(self):
+        # nothing is focused right now
+        self.failUnlessEqual(self.tv.focus(), '')
+
+        item1 = self.tv.insert('', 'end')
+        self.tv.focus(item1)
+        self.failUnlessEqual(self.tv.focus(), item1)
+
+        self.tv.delete(item1)
+        self.failUnlessEqual(self.tv.focus(), '')
+
+        # try focusing inexistant item
+        self.failUnlessRaises(Tkinter.TclError, self.tv.focus, 'hi')
+
+
+    def test_heading(self):
+        # check a dict is returned
+        self.failUnless(isinstance(self.tv.heading('#0'), dict))
+
+        # check a value is returned
+        self.tv.heading('#0', text='hi')
+        self.failUnlessEqual(self.tv.heading('#0', 'text'), 'hi')
+        self.failUnlessEqual(self.tv.heading('#0', text=None), 'hi')
+
+        # invalid option
+        self.failUnlessRaises(Tkinter.TclError, self.tv.heading, '#0',
+            background=None)
+        # invalid value
+        self.failUnlessRaises(Tkinter.TclError, self.tv.heading, '#0',
+            anchor=1)
+
+
+    def test_heading_callback(self):
+        def simulate_heading_click(x, y):
+            support.simulate_mouse_click(self.tv, x, y)
+            self.tv.update_idletasks()
+
+        success = [] # no success for now
+
+        self.tv.pack()
+        self.tv.wait_visibility()
+        self.tv.heading('#0', command=lambda: success.append(True))
+        self.tv.column('#0', width=100)
+        self.tv.update()
+
+        # assuming that the coords (5, 5) fall into heading #0
+        simulate_heading_click(5, 5)
+        if not success:
+            self.fail("The command associated to the treeview heading wasn't "
+                "invoked.")
+
+        success = []
+        commands = self.tv.master._tclCommands
+        self.tv.heading('#0', command=str(self.tv.heading('#0', command=None)))
+        self.failUnlessEqual(commands, self.tv.master._tclCommands)
+        simulate_heading_click(5, 5)
+        if not success:
+            self.fail("The command associated to the treeview heading wasn't "
+                "invoked.")
+
+        # XXX The following raises an error in a tcl interpreter, but not in
+        # Python
+        #self.tv.heading('#0', command='I dont exist')
+        #simulate_heading_click(5, 5)
+
+
+    def test_index(self):
+        # item 'what' doesn't exist
+        self.failUnlessRaises(Tkinter.TclError, self.tv.index, 'what')
+
+        self.failUnlessEqual(self.tv.index(''), 0)
+
+        item1 = self.tv.insert('', 'end')
+        item2 = self.tv.insert('', 'end')
+        c1 = self.tv.insert(item1, 'end')
+        c2 = self.tv.insert(item1, 'end')
+        self.failUnlessEqual(self.tv.index(item1), 0)
+        self.failUnlessEqual(self.tv.index(c1), 0)
+        self.failUnlessEqual(self.tv.index(c2), 1)
+        self.failUnlessEqual(self.tv.index(item2), 1)
+
+        self.tv.move(item2, '', 0)
+        self.failUnlessEqual(self.tv.index(item2), 0)
+        self.failUnlessEqual(self.tv.index(item1), 1)
+
+        # check that index still works even after its parent and siblings
+        # have been detached
+        self.tv.detach(item1)
+        self.failUnlessEqual(self.tv.index(c2), 1)
+        self.tv.detach(c1)
+        self.failUnlessEqual(self.tv.index(c2), 0)
+
+        # but it fails after item has been deleted
+        self.tv.delete(item1)
+        self.failUnlessRaises(Tkinter.TclError, self.tv.index, c2)
+
+
+    def test_insert_item(self):
+        # parent 'none' doesn't exist
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, 'none', 'end')
+
+        # open values
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, '', 'end',
+            open='')
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, '', 'end',
+            open='please')
+        self.failIf(self.tv.delete(self.tv.insert('', 'end', open=True)))
+        self.failIf(self.tv.delete(self.tv.insert('', 'end', open=False)))
+
+        # invalid index
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, '', 'middle')
+
+        # trying to duplicate item id is invalid
+        itemid = self.tv.insert('', 'end', 'first-item')
+        self.failUnlessEqual(itemid, 'first-item')
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, '', 'end',
+            'first-item')
+        self.failUnlessRaises(Tkinter.TclError, self.tv.insert, '', 'end',
+            MockTclObj('first-item'))
+
+        # unicode values
+        value = u'\xe1ba'
+        item = self.tv.insert('', 'end', values=(value, ))
+        self.failUnlessEqual(self.tv.item(item, 'values'), (value, ))
+        self.failUnlessEqual(self.tv.item(item, values=None), (value, ))
+
+        self.tv.item(item, values=list(self.tv.item(item, values=None)))
+        self.failUnlessEqual(self.tv.item(item, values=None), (value, ))
+
+        self.failUnless(isinstance(self.tv.item(item), dict))
+
+        # erase item values
+        self.tv.item(item, values='')
+        self.failIf(self.tv.item(item, values=None))
+
+        # item tags
+        item = self.tv.insert('', 'end', tags=[1, 2, value])
+        self.failUnlessEqual(self.tv.item(item, tags=None), ('1', '2', value))
+        self.tv.item(item, tags=[])
+        self.failIf(self.tv.item(item, tags=None))
+        self.tv.item(item, tags=(1, 2))
+        self.failUnlessEqual(self.tv.item(item, tags=None), ('1', '2'))
+
+        # values with spaces
+        item = self.tv.insert('', 'end', values=('a b c',
+            '%s %s' % (value, value)))
+        self.failUnlessEqual(self.tv.item(item, values=None),
+            ('a b c', '%s %s' % (value, value)))
+
+        # text
+        self.failUnlessEqual(self.tv.item(
+            self.tv.insert('', 'end', text="Label here"), text=None),
+            "Label here")
+        self.failUnlessEqual(self.tv.item(
+            self.tv.insert('', 'end', text=value), text=None),
+            value)
+
+
+    def test_set(self):
+        self.tv['columns'] = ['A', 'B']
+        item = self.tv.insert('', 'end', values=['a', 'b'])
+        self.failUnlessEqual(self.tv.set(item), {'A': 'a', 'B': 'b'})
+
+        self.tv.set(item, 'B', 'a')
+        self.failUnlessEqual(self.tv.item(item, values=None), ('a', 'a'))
+
+        self.tv['columns'] = ['B']
+        self.failUnlessEqual(self.tv.set(item), {'B': 'a'})
+
+        self.tv.set(item, 'B', 'b')
+        self.failUnlessEqual(self.tv.set(item, column='B'), 'b')
+        self.failUnlessEqual(self.tv.item(item, values=None), ('b', 'a'))
+
+        self.tv.set(item, 'B', 123)
+        self.failUnlessEqual(self.tv.set(item, 'B'), 123)
+        self.failUnlessEqual(self.tv.item(item, values=None), (123, 'a'))
+        self.failUnlessEqual(self.tv.set(item), {'B': 123})
+
+        # inexistant column
+        self.failUnlessRaises(Tkinter.TclError, self.tv.set, item, 'A')
+        self.failUnlessRaises(Tkinter.TclError, self.tv.set, item, 'A', 'b')
+
+        # inexistant item
+        self.failUnlessRaises(Tkinter.TclError, self.tv.set, 'notme')
+
+
+    def test_tag_bind(self):
+        events = []
+        item1 = self.tv.insert('', 'end', tags=['call'])
+        item2 = self.tv.insert('', 'end', tags=['call'])
+        self.tv.tag_bind('call', '<ButtonPress-1>',
+            lambda evt: events.append(1))
+        self.tv.tag_bind('call', '<ButtonRelease-1>',
+            lambda evt: events.append(2))
+
+        self.tv.pack()
+        self.tv.wait_visibility()
+        self.tv.update()
+
+        pos_y = set()
+        found = set()
+        for i in range(0, 100, 10):
+            if len(found) == 2: # item1 and item2 already found
+                break
+            item_id = self.tv.identify_row(i)
+            if item_id and item_id not in found:
+                pos_y.add(i)
+                found.add(item_id)
+
+        self.failUnlessEqual(len(pos_y), 2) # item1 and item2 y pos
+        for y in pos_y:
+            support.simulate_mouse_click(self.tv, 0, y)
+
+        # by now there should be 4 things in the events list, since each
+        # item had a bind for two events that were simulated above
+        self.failUnlessEqual(len(events), 4)
+        for evt in zip(events[::2], events[1::2]):
+            self.failUnlessEqual(evt, (1, 2))
+
+
+    def test_tag_configure(self):
+        # Just testing parameter passing for now
+        self.failUnlessRaises(TypeError, self.tv.tag_configure)
+        self.failUnlessRaises(Tkinter.TclError, self.tv.tag_configure,
+            'test', sky='blue')
+        self.tv.tag_configure('test', foreground='blue')
+        self.failUnlessEqual(self.tv.tag_configure('test', 'foreground'),
+            'blue')
+        self.failUnlessEqual(self.tv.tag_configure('test', foreground=None),
+            'blue')
+        self.failUnless(isinstance(self.tv.tag_configure('test'), dict))
+
+
+tests_gui = (
+        WidgetTest, ButtonTest, CheckbuttonTest, RadiobuttonTest,
+        ComboboxTest, EntryTest, PanedwindowTest, ScaleTest, NotebookTest,
+        TreeviewTest
+        )
+
+if __name__ == "__main__":
+    run_unittest(*tests_gui)

Added: python/trunk/Lib/lib-tk/ttk.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/lib-tk/ttk.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,1636 @@
+"""Ttk wrapper.
+
+This module provides classes to allow using Tk themed widget set.
+
+Ttk is based on a revised and enhanced version of
+TIP #48 (http://tip.tcl.tk/48) specified style engine.
+
+Its basic idea is to separate, to the extent possible, the code
+implementing a widget's behavior from the code implementing its
+appearance. Widget class bindings are primarily responsible for
+maintaining the widget state and invoking callbacks, all aspects
+of the widgets appearance lies at Themes.
+"""
+
+__version__ = "0.3.1"
+
+__author__ = "Guilherme Polo <ggpolo at gmail.com>"
+
+__all__ = ["Button", "Checkbutton", "Combobox", "Entry", "Frame", "Label",
+           "Labelframe", "LabelFrame", "Menubutton", "Notebook", "Panedwindow",
+           "PanedWindow", "Progressbar", "Radiobutton", "Scale", "Scrollbar",
+           "Separator", "Sizegrip", "Style", "Treeview",
+           # Extensions
+           "LabeledScale", "OptionMenu",
+           # functions
+           "tclobjs_to_py"]
+
+import Tkinter
+
+_flatten = Tkinter._flatten
+
+# Verify if Tk is new enough to not need Tile checking
+_REQUIRE_TILE = True if Tkinter.TkVersion < 8.5 else False
+
+def _loadttk(loadtk):
+    # This extends the default Tkinter.Tk._loadtk method so we can be
+    # sure that ttk is available for use, or not.
+    def _wrapper(self):
+        loadtk(self)
+
+        if _REQUIRE_TILE:
+            import os
+            tilelib = os.environ.get('TILE_LIBRARY')
+            if tilelib:
+                # append custom tile path to the the list of directories that
+                # Tcl uses when attempting to resolve packages with the package
+                # command
+                self.tk.eval('global auto_path; '
+                             'lappend auto_path {%s}' % tilelib)
+            self.tk.eval('package require tile') # TclError may be raised here
+
+    return _wrapper
+
+# Store the original Tkinter.Tk._loadtk before replacing it just in case
+# someone wants to restore it.
+__loadtk__ = Tkinter.Tk._loadtk
+Tkinter.Tk._loadtk = _loadttk(Tkinter.Tk._loadtk)
+
+
+def _format_optdict(optdict, script=False, ignore=None):
+    """Formats optdict to a tuple to pass it to tk.call.
+
+    E.g. (script=False):
+      {'foreground': 'blue', 'padding': [1, 2, 3, 4]} returns:
+      ('-foreground', 'blue', '-padding', '1 2 3 4')"""
+    format = "%s" if not script else "{%s}"
+
+    opts = []
+    for opt, value in optdict.iteritems():
+        if ignore and opt in ignore:
+            continue
+
+        if isinstance(value, (list, tuple)):
+            v = []
+            for val in value:
+                if isinstance(val, basestring):
+                    v.append(unicode(val) if val else '{}')
+                else:
+                    v.append(str(val))
+
+            # format v according to the script option, but also check for
+            # space in any value in v in order to group them correctly
+            value = format % ' '.join(
+                ('{%s}' if ' ' in val else '%s') % val for val in v)
+
+        if script and value == '':
+            value = '{}' # empty string in Python is equivalent to {} in Tcl
+
+        opts.append(("-%s" % opt, value))
+
+    # Remember: _flatten skips over None
+    return _flatten(opts)
+
+def _format_mapdict(mapdict, script=False):
+    """Formats mapdict to pass it to tk.call.
+
+    E.g. (script=False):
+      {'expand': [('active', 'selected', 'grey'), ('focus', [1, 2, 3, 4])]}
+
+      returns:
+
+      ('-expand', '{active selected} grey focus {1, 2, 3, 4}')"""
+    # if caller passes a Tcl script to tk.call, all the values need to
+    # be grouped into words (arguments to a command in Tcl dialect)
+    format = "%s" if not script else "{%s}"
+
+    opts = []
+    for opt, value in mapdict.iteritems():
+
+        opt_val = []
+        # each value in mapdict is expected to be a sequence, where each item
+        # is another sequence containing a state (or several) and a value
+        for statespec in value:
+            state, val = statespec[:-1], statespec[-1]
+
+            if len(state) > 1: # group multiple states
+                state = "{%s}" % ' '.join(state)
+            else: # single state
+                # if it is empty (something that evaluates to False), then
+                # format it to Tcl code to denote the "normal" state
+                state = state[0] or '{}'
+
+            if isinstance(val, (list, tuple)): # val needs to be grouped
+                val = "{%s}" % ' '.join(map(str, val))
+
+            opt_val.append("%s %s" % (state, val))
+
+        opts.append(("-%s" % opt, format % ' '.join(opt_val)))
+
+    return _flatten(opts)
+
+def _format_elemcreate(etype, script=False, *args, **kw):
+    """Formats args and kw according to the given element factory etype."""
+    spec = None
+    opts = ()
+    if etype in ("image", "vsapi"):
+        if etype == "image": # define an element based on an image
+            # first arg should be the default image name
+            iname = args[0]
+            # next args, if any, are statespec/value pairs which is almost
+            # a mapdict, but we just need the value
+            imagespec = _format_mapdict({None: args[1:]})[1]
+            spec = "%s %s" % (iname, imagespec)
+
+        else:
+            # define an element whose visual appearance is drawn using the
+            # Microsoft Visual Styles API which is responsible for the
+            # themed styles on Windows XP and Vista.
+            # Availability: Tk 8.6, Windows XP and Vista.
+            class_name, part_id = args[:2]
+            statemap = _format_mapdict({None: args[2:]})[1]
+            spec = "%s %s %s" % (class_name, part_id, statemap)
+
+        opts = _format_optdict(kw, script)
+
+    elif etype == "from": # clone an element
+        # it expects a themename and optionally an element to clone from,
+        # otherwise it will clone {} (empty element)
+        spec = args[0] # theme name
+        if len(args) > 1: # elementfrom specified
+            opts = (args[1], )
+
+    if script:
+        spec = '{%s}' % spec
+        opts = ' '.join(map(str, opts))
+
+    return spec, opts
+
+def _format_layoutlist(layout, indent=0, indent_size=2):
+    """Formats a layout list so we can pass the result to ttk::style
+    layout and ttk::style settings. Note that the layout doesn't has to
+    be a list necessarily.
+
+    E.g.:
+      [("Menubutton.background", None),
+       ("Menubutton.button", {"children":
+           [("Menubutton.focus", {"children":
+               [("Menubutton.padding", {"children":
+                [("Menubutton.label", {"side": "left", "expand": 1})]
+               })]
+           })]
+       }),
+       ("Menubutton.indicator", {"side": "right"})
+      ]
+
+      returns:
+
+      Menubutton.background
+      Menubutton.button -children {
+        Menubutton.focus -children {
+          Menubutton.padding -children {
+            Menubutton.label -side left -expand 1
+          }
+        }
+      }
+      Menubutton.indicator -side right"""
+    script = []
+
+    for layout_elem in layout:
+        elem, opts = layout_elem
+        opts = opts or {}
+        fopts = ' '.join(map(str, _format_optdict(opts, True, "children")))
+        head = "%s%s%s" % (' ' * indent, elem, (" %s" % fopts) if fopts else '')
+
+        if "children" in opts:
+            script.append(head + " -children {")
+            indent += indent_size
+            newscript, indent = _format_layoutlist(opts['children'], indent,
+                indent_size)
+            script.append(newscript)
+            indent -= indent_size
+            script.append('%s}' % (' ' * indent))
+        else:
+            script.append(head)
+
+    return '\n'.join(script), indent
+
+def _script_from_settings(settings):
+    """Returns an appropriate script, based on settings, according to
+    theme_settings definition to be used by theme_settings and
+    theme_create."""
+    script = []
+    # a script will be generated according to settings passed, which
+    # will then be evaluated by Tcl
+    for name, opts in settings.iteritems():
+        # will format specific keys according to Tcl code
+        if opts.get('configure'): # format 'configure'
+            s = ' '.join(map(unicode, _format_optdict(opts['configure'], True)))
+            script.append("ttk::style configure %s %s;" % (name, s))
+
+        if opts.get('map'): # format 'map'
+            s = ' '.join(map(unicode, _format_mapdict(opts['map'], True)))
+            script.append("ttk::style map %s %s;" % (name, s))
+
+        if 'layout' in opts: # format 'layout' which may be empty
+            if not opts['layout']:
+                s = 'null' # could be any other word, but this one makes sense
+            else:
+                s, _ = _format_layoutlist(opts['layout'])
+            script.append("ttk::style layout %s {\n%s\n}" % (name, s))
+
+        if opts.get('element create'): # format 'element create'
+            eopts = opts['element create']
+            etype = eopts[0]
+
+            # find where args end, and where kwargs start
+            argc = 1 # etype was the first one
+            while argc < len(eopts) and not hasattr(eopts[argc], 'iteritems'):
+                argc += 1
+
+            elemargs = eopts[1:argc]
+            elemkw = eopts[argc] if argc < len(eopts) and eopts[argc] else {}
+            spec, opts = _format_elemcreate(etype, True, *elemargs, **elemkw)
+
+            script.append("ttk::style element create %s %s %s %s" % (
+                name, etype, spec, opts))
+
+    return '\n'.join(script)
+
+def _dict_from_tcltuple(ttuple, cut_minus=True):
+    """Break tuple in pairs, format it properly, then build the return
+    dict. If cut_minus is True, the supposed '-' prefixing options will
+    be removed.
+
+    ttuple is expected to contain an even number of elements."""
+    opt_start = 1 if cut_minus else 0
+
+    retdict = {}
+    it = iter(ttuple)
+    for opt, val in zip(it, it):
+        retdict[str(opt)[opt_start:]] = val
+
+    return tclobjs_to_py(retdict)
+
+def _list_from_statespec(stuple):
+    """Construct a list from the given statespec tuple according to the
+    accepted statespec accepted by _format_mapdict."""
+    nval = []
+    for val in stuple:
+        typename = getattr(val, 'typename', None)
+        if typename is None:
+            nval.append(val)
+        else: # this is a Tcl object
+            val = str(val)
+            if typename == 'StateSpec':
+                val = val.split()
+            nval.append(val)
+
+    it = iter(nval)
+    return [_flatten(spec) for spec in zip(it, it)]
+
+def _list_from_layouttuple(ltuple):
+    """Construct a list from the tuple returned by ttk::layout, this is
+    somewhat the reverse of _format_layoutlist."""
+    res = []
+
+    indx = 0
+    while indx < len(ltuple):
+        name = ltuple[indx]
+        opts = {}
+        res.append((name, opts))
+        indx += 1
+
+        while indx < len(ltuple): # grab name's options
+            opt, val = ltuple[indx:indx + 2]
+            if not opt.startswith('-'): # found next name
+                break
+
+            opt = opt[1:] # remove the '-' from the option
+            indx += 2
+
+            if opt == 'children':
+                val = _list_from_layouttuple(val)
+
+            opts[opt] = val
+
+    return res
+
+def _val_or_dict(options, func, *args):
+    """Format options then call func with args and options and return
+    the appropriate result.
+
+    If no option is specified, a dict is returned. If a option is
+    specified with the None value, the value for that option is returned.
+    Otherwise, the function just sets the passed options and the caller
+    shouldn't be expecting a return value anyway."""
+    options = _format_optdict(options)
+    res = func(*(args + options))
+
+    if len(options) % 2: # option specified without a value, return its value
+        return res
+
+    return _dict_from_tcltuple(res)
+
+def _convert_stringval(value):
+    """Converts a value to, hopefully, a more appropriate Python object."""
+    value = unicode(value)
+    try:
+        value = int(value)
+    except (ValueError, TypeError):
+        pass
+
+    return value
+
+def tclobjs_to_py(adict):
+    """Returns adict with its values converted from Tcl objects to Python
+    objects."""
+    for opt, val in adict.iteritems():
+        if val and hasattr(val, '__len__') and not isinstance(val, basestring):
+            if getattr(val[0], 'typename', None) == 'StateSpec':
+                val = _list_from_statespec(val)
+            else:
+                val = map(_convert_stringval, val)
+
+        elif hasattr(val, 'typename'): # some other (single) Tcl object
+            val = _convert_stringval(val)
+
+        adict[opt] = val
+
+    return adict
+
+
+class Style(object):
+    """Manipulate style database."""
+
+    _name = "ttk::style"
+
+    def __init__(self, master=None):
+        if master is None:
+            if Tkinter._support_default_root:
+                master = Tkinter._default_root or Tkinter.Tk()
+            else:
+                raise RuntimeError("No master specified and Tkinter is "
+                    "configured to not support default master")
+
+        self.master = master
+        self.tk = self.master.tk
+
+
+    def configure(self, style, query_opt=None, **kw):
+        """Query or sets the default value of the specified option(s) in
+        style.
+
+        Each key in kw is an option and each value is either a string or
+        a sequence identifying the value for that option."""
+        if query_opt is not None:
+            kw[query_opt] = None
+        return _val_or_dict(kw, self.tk.call, self._name, "configure", style)
+
+
+    def map(self, style, query_opt=None, **kw):
+        """Query or sets dynamic values of the specified option(s) in
+        style.
+
+        Each key in kw is an option and each value should be a list or a
+        tuple (usually) containing statespecs grouped in tuples, or list,
+        or something else of your preference. A statespec is compound of
+        one or more states and then a value."""
+        if query_opt is not None:
+            return _list_from_statespec(
+                self.tk.call(self._name, "map", style, '-%s' % query_opt))
+
+        return _dict_from_tcltuple(
+            self.tk.call(self._name, "map", style, *(_format_mapdict(kw))))
+
+
+    def lookup(self, style, option, state=None, default=None):
+        """Returns the value specified for option in style.
+
+        If state is specified it is expected to be a sequence of one
+        or more states. If the default argument is set, it is used as
+        a fallback value in case no specification for option is found."""
+        state = ' '.join(state) if state else ''
+
+        return self.tk.call(self._name, "lookup", style, '-%s' % option,
+            state, default)
+
+
+    def layout(self, style, layoutspec=None):
+        """Define the widget layout for given style. If layoutspec is
+        omitted, return the layout specification for given style.
+
+        layoutspec is expected to be a list or an object different than
+        None that evaluates to False if you want to "turn off" that style.
+        If it is a list (or tuple, or something else), each item should be
+        a tuple where the first item is the layout name and the second item
+        should have the format described below:
+
+        LAYOUTS
+
+            A layout can contain the value None, if takes no options, or
+            a dict of options specifying how to arrange the element.
+            The layout mechanism uses a simplified version of the pack
+            geometry manager: given an initial cavity, each element is
+            allocated a parcel. Valid options/values are:
+
+                side: whichside
+                    Specifies which side of the cavity to place the
+                    element; one of top, right, bottom or left. If
+                    omitted, the element occupies the entire cavity.
+
+                sticky: nswe
+                    Specifies where the element is placed inside its
+                    allocated parcel.
+
+                children: [sublayout... ]
+                    Specifies a list of elements to place inside the
+                    element. Each element is a tuple (or other sequence)
+                    where the first item is the layout name, and the other
+                    is a LAYOUT."""
+        lspec = None
+        if layoutspec:
+            lspec = _format_layoutlist(layoutspec)[0]
+        elif layoutspec is not None: # will disable the layout ({}, '', etc)
+            lspec = "null" # could be any other word, but this may make sense
+                           # when calling layout(style) later
+
+        return _list_from_layouttuple(
+            self.tk.call(self._name, "layout", style, lspec))
+
+
+    def element_create(self, elementname, etype, *args, **kw):
+        """Create a new element in the current theme of given etype."""
+        spec, opts = _format_elemcreate(etype, False, *args, **kw)
+        self.tk.call(self._name, "element", "create", elementname, etype,
+            spec, *opts)
+
+
+    def element_names(self):
+        """Returns the list of elements defined in the current theme."""
+        return self.tk.call(self._name, "element", "names")
+
+
+    def element_options(self, elementname):
+        """Return the list of elementname's options."""
+        return self.tk.call(self._name, "element", "options", elementname)
+
+
+    def theme_create(self, themename, parent=None, settings=None):
+        """Creates a new theme.
+
+        It is an error if themename already exists. If parent is
+        specified, the new theme will inherit styles, elements and
+        layouts from the specified parent theme. If settings are present,
+        they are expected to have the same syntax used for theme_settings."""
+        script = _script_from_settings(settings) if settings else ''
+
+        if parent:
+            self.tk.call(self._name, "theme", "create", themename,
+                "-parent", parent, "-settings", script)
+        else:
+            self.tk.call(self._name, "theme", "create", themename,
+                "-settings", script)
+
+
+    def theme_settings(self, themename, settings):
+        """Temporarily sets the current theme to themename, apply specified
+        settings and then restore the previous theme.
+
+        Each key in settings is a style and each value may contain the
+        keys 'configure', 'map', 'layout' and 'element create' and they
+        are expected to have the same format as specified by the methods
+        configure, map, layout and element_create respectively."""
+        script = _script_from_settings(settings)
+        self.tk.call(self._name, "theme", "settings", themename, script)
+
+
+    def theme_names(self):
+        """Returns a list of all known themes."""
+        return self.tk.call(self._name, "theme", "names")
+
+
+    def theme_use(self, themename=None):
+        """If themename is None, returns the theme in use, otherwise, set
+        the current theme to themename, refreshes all widgets and emits
+        a <<ThemeChanged>> event."""
+        if themename is None:
+            # Starting on Tk 8.6, checking this global is no longer needed
+            # since it allows doing self.tk.call(self._name, "theme", "use")
+            return self.tk.eval("return $ttk::currentTheme")
+
+        # using "ttk::setTheme" instead of "ttk::style theme use" causes
+        # the variable currentTheme to be updated, also, ttk::setTheme calls
+        # "ttk::style theme use" in order to change theme.
+        self.tk.call("ttk::setTheme", themename)
+
+
+class Widget(Tkinter.Widget):
+    """Base class for Tk themed widgets."""
+
+    def __init__(self, master, widgetname, kw=None):
+        """Constructs a Ttk Widget with the parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, takefocus, style
+
+        SCROLLABLE WIDGET OPTIONS
+
+            xscrollcommand, yscrollcommand
+
+        LABEL WIDGET OPTIONS
+
+            text, textvariable, underline, image, compound, width
+
+        WIDGET STATES
+
+            active, disabled, focus, pressed, selected, background,
+            readonly, alternate, invalid
+        """
+        Tkinter.Widget.__init__(self, master, widgetname, kw=kw)
+
+
+    def identify(self, x, y):
+        """Returns the name of the element at position x, y, or the empty
+        string if the point does not lie within any element.
+
+        x and y are pixel coordinates relative to the widget."""
+        return self.tk.call(self._w, "identify", x, y)
+
+
+    def instate(self, statespec, callback=None, *args, **kw):
+        """Test the widget's state.
+
+        If callback is not specified, returns True if the widget state
+        matches statespec and False otherwise. If callback is specified,
+        then it will be invoked with *args, **kw if the widget state
+        matches statespec. statespec is expected to be a sequence."""
+        ret = self.tk.call(self._w, "instate", ' '.join(statespec))
+        if ret and callback:
+            return callback(*args, **kw)
+
+        return bool(ret)
+
+
+    def state(self, statespec=None):
+        """Modify or inquire widget state.
+
+        Widget state is returned if statespec is None, otherwise it is
+        set according to the statespec flags and then a new state spec
+        is returned indicating which flags were changed. statespec is
+        expected to be a sequence."""
+        if statespec is not None:
+            statespec = ' '.join(statespec)
+
+        return self.tk.splitlist(str(self.tk.call(self._w, "state", statespec)))
+
+
+class Button(Widget):
+    """Ttk Button widget, displays a textual label and/or image, and
+    evaluates a command when pressed."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Button widget with the parent master.
+
+        STANDARD OPTIONS
+
+            class, compound, cursor, image, state, style, takefocus,
+            text, textvariable, underline, width
+
+        WIDGET-SPECIFIC OPTIONS
+
+            command, default, width
+        """
+        Widget.__init__(self, master, "ttk::button", kw)
+
+
+    def invoke(self):
+        """Invokes the command associated with the button."""
+        return self.tk.call(self._w, "invoke")
+
+
+class Checkbutton(Widget):
+    """Ttk Checkbutton widget which is either in on- or off-state."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Checkbutton widget with the parent master.
+
+        STANDARD OPTIONS
+
+            class, compound, cursor, image, state, style, takefocus,
+            text, textvariable, underline, width
+
+        WIDGET-SPECIFIC OPTIONS
+
+            command, offvalue, onvalue, variable
+        """
+        Widget.__init__(self, master, "ttk::checkbutton", kw)
+
+
+    def invoke(self):
+        """Toggles between the selected and deselected states and
+        invokes the associated command. If the widget is currently
+        selected, sets the option variable to the offvalue option
+        and deselects the widget; otherwise, sets the option variable
+        to the option onvalue.
+
+        Returns the result of the associated command."""
+        return self.tk.call(self._w, "invoke")
+
+
+class Entry(Widget, Tkinter.Entry):
+    """Ttk Entry widget displays a one-line text string and allows that
+    string to be edited by the user."""
+
+    def __init__(self, master=None, widget=None, **kw):
+        """Constructs a Ttk Entry widget with the parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus, xscrollcommand
+
+        WIDGET-SPECIFIC OPTIONS
+
+            exportselection, invalidcommand, justify, show, state,
+            textvariable, validate, validatecommand, width
+
+        VALIDATION MODES
+
+            none, key, focus, focusin, focusout, all
+        """
+        Widget.__init__(self, master, widget or "ttk::entry", kw)
+
+
+    def bbox(self, index):
+        """Return a tuple of (x, y, width, height) which describes the
+        bounding box of the character given by index."""
+        return self.tk.call(self._w, "bbox", index)
+
+
+    def identify(self, x, y):
+        """Returns the name of the element at position x, y, or the
+        empty string if the coordinates are outside the window."""
+        return self.tk.call(self._w, "identify", x, y)
+
+
+    def validate(self):
+        """Force revalidation, independent of the conditions specified
+        by the validate option. Returns False if validation fails, True
+        if it succeeds. Sets or clears the invalid state accordingly."""
+        return bool(self.tk.call(self._w, "validate"))
+
+
+class Combobox(Entry):
+    """Ttk Combobox widget combines a text field with a pop-down list of
+    values."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Combobox widget with the parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            exportselection, justify, height, postcommand, state,
+            textvariable, values, width
+        """
+        # The "values" option may need special formatting, so leave to
+        # _format_optdict the responsability to format it
+        if "values" in kw:
+            kw["values"] = _format_optdict({'v': kw["values"]})[1]
+
+        Entry.__init__(self, master, "ttk::combobox", **kw)
+
+
+    def __setitem__(self, item, value):
+        if item == "values":
+            value = _format_optdict({item: value})[1]
+
+        Entry.__setitem__(self, item, value)
+
+
+    def configure(self, cnf=None, **kw):
+        """Custom Combobox configure, created to properly format the values
+        option."""
+        if "values" in kw:
+            kw["values"] = _format_optdict({'v': kw["values"]})[1]
+
+        return Entry.configure(self, cnf, **kw)
+
+
+    def current(self, newindex=None):
+        """If newindex is supplied, sets the combobox value to the
+        element at position newindex in the list of values. Otherwise,
+        returns the index of the current value in the list of values
+        or -1 if the current value does not appear in the list."""
+        return self.tk.call(self._w, "current", newindex)
+
+
+    def set(self, value):
+        """Sets the value of the combobox to value."""
+        self.tk.call(self._w, "set", value)
+
+
+class Frame(Widget):
+    """Ttk Frame widget is a container, used to group other widgets
+    together."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Frame with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            borderwidth, relief, padding, width, height
+        """
+        Widget.__init__(self, master, "ttk::frame", kw)
+
+
+class Label(Widget):
+    """Ttk Label widget displays a textual label and/or image."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Label with parent master.
+
+        STANDARD OPTIONS
+
+            class, compound, cursor, image, style, takefocus, text,
+            textvariable, underline, width
+
+        WIDGET-SPECIFIC OPTIONS
+
+            anchor, background, font, foreground, justify, padding,
+            relief, text, wraplength
+        """
+        Widget.__init__(self, master, "ttk::label", kw)
+
+
+class Labelframe(Widget):
+    """Ttk Labelframe widget is a container used to group other widgets
+    together. It has an optional label, which may be a plain text string
+    or another widget."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Labelframe with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+            labelanchor, text, underline, padding, labelwidget, width,
+            height
+        """
+        Widget.__init__(self, master, "ttk::labelframe", kw)
+
+LabelFrame = Labelframe # Tkinter name compatibility
+
+
+class Menubutton(Widget):
+    """Ttk Menubutton widget displays a textual label and/or image, and
+    displays a menu when pressed."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Menubutton with parent master.
+
+        STANDARD OPTIONS
+
+            class, compound, cursor, image, state, style, takefocus,
+            text, textvariable, underline, width
+
+        WIDGET-SPECIFIC OPTIONS
+
+            direction, menu
+        """
+        Widget.__init__(self, master, "ttk::menubutton", kw)
+
+
+class Notebook(Widget):
+    """Ttk Notebook widget manages a collection of windows and displays
+    a single one at a time. Each child window is associated with a tab,
+    which the user may select to change the currently-displayed window."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Notebook with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            height, padding, width
+
+        TAB OPTIONS
+
+            state, sticky, padding, text, image, compound, underline
+
+        TAB IDENTIFIERS (tab_id)
+
+            The tab_id argument found in several methods may take any of
+            the following forms:
+
+                * An integer between zero and the number of tabs
+                * The name of a child window
+                * A positional specification of the form "@x,y", which
+                  defines the tab
+                * The string "current", which identifies the
+                  currently-selected tab
+                * The string "end", which returns the number of tabs (only
+                  valid for method index)
+        """
+        Widget.__init__(self, master, "ttk::notebook", kw)
+
+
+    def add(self, child, **kw):
+        """Adds a new tab to the notebook.
+
+        If window is currently managed by the notebook but hidden, it is
+        restored to its previous position."""
+        self.tk.call(self._w, "add", child, *(_format_optdict(kw)))
+
+
+    def forget(self, tab_id):
+        """Removes the tab specified by tab_id, unmaps and unmanages the
+        associated window."""
+        self.tk.call(self._w, "forget", tab_id)
+
+
+    def hide(self, tab_id):
+        """Hides the tab specified by tab_id.
+
+        The tab will not be displayed, but the associated window remains
+        managed by the notebook and its configuration remembered. Hidden
+        tabs may be restored with the add command."""
+        self.tk.call(self._w, "hide", tab_id)
+
+
+    def identify(self, x, y):
+        """Returns the name of the tab element at position x, y, or the
+        empty string if none."""
+        return self.tk.call(self._w, "identify", x, y)
+
+
+    def index(self, tab_id):
+        """Returns the numeric index of the tab specified by tab_id, or
+        the total number of tabs if tab_id is the string "end"."""
+        return self.tk.call(self._w, "index", tab_id)
+
+
+    def insert(self, pos, child, **kw):
+        """Inserts a pane at the specified position.
+
+        pos is either the string end, an integer index, or the name of
+        a managed child. If child is already managed by the notebook,
+        moves it to the specified position."""
+        self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
+
+
+    def select(self, tab_id=None):
+        """Selects the specified tab.
+
+        The associated child window will be displayed, and the
+        previously-selected window (if different) is unmapped. If tab_id
+        is omitted, returns the widget name of the currently selected
+        pane."""
+        return self.tk.call(self._w, "select", tab_id)
+
+
+    def tab(self, tab_id, option=None, **kw):
+        """Query or modify the options of the specific tab_id.
+
+        If kw is not given, returns a dict of the tab option values. If option
+        is specified, returns the value of that option. Otherwise, sets the
+        options to the corresponding values."""
+        if option is not None:
+            kw[option] = None
+        return _val_or_dict(kw, self.tk.call, self._w, "tab", tab_id)
+
+
+    def tabs(self):
+        """Returns a list of windows managed by the notebook."""
+        return self.tk.call(self._w, "tabs") or ()
+
+
+    def enable_traversal(self):
+        """Enable keyboard traversal for a toplevel window containing
+        this notebook.
+
+        This will extend the bindings for the toplevel window containing
+        this notebook as follows:
+
+            Control-Tab: selects the tab following the currently selected
+                         one
+
+            Shift-Control-Tab: selects the tab preceding the currently
+                               selected one
+
+            Alt-K: where K is the mnemonic (underlined) character of any
+                   tab, will select that tab.
+
+        Multiple notebooks in a single toplevel may be enabled for
+        traversal, including nested notebooks. However, notebook traversal
+        only works properly if all panes are direct children of the
+        notebook."""
+        # The only, and good, difference I see is about mnemonics, which works
+        # after calling this method. Control-Tab and Shift-Control-Tab always
+        # works (here at least).
+        self.tk.call("ttk::notebook::enableTraversal", self._w)
+
+
+class Panedwindow(Widget, Tkinter.PanedWindow):
+    """Ttk Panedwindow widget displays a number of subwindows, stacked
+    either vertically or horizontally."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Panedwindow with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            orient, width, height
+
+        PANE OPTIONS
+
+            weight
+        """
+        Widget.__init__(self, master, "ttk::panedwindow", kw)
+
+
+    forget = Tkinter.PanedWindow.forget # overrides Pack.forget
+
+
+    def insert(self, pos, child, **kw):
+        """Inserts a pane at the specified positions.
+
+        pos is either the string end, and integer index, or the name
+        of a child. If child is already managed by the paned window,
+        moves it to the specified position."""
+        self.tk.call(self._w, "insert", pos, child, *(_format_optdict(kw)))
+
+
+    def pane(self, pane, option=None, **kw):
+        """Query or modify the options of the specified pane.
+
+        pane is either an integer index or the name of a managed subwindow.
+        If kw is not given, returns a dict of the pane option values. If
+        option is specified then the value for that option is returned.
+        Otherwise, sets the options to the correspoding values."""
+        if option is not None:
+            kw[option] = None
+        return _val_or_dict(kw, self.tk.call, self._w, "pane", pane)
+
+
+    def sashpos(self, index, newpos=None):
+        """If newpos is specified, sets the position of sash number index.
+
+        May adjust the positions of adjacent sashes to ensure that
+        positions are monotonically increasing. Sash positions are further
+        constrained to be between 0 and the total size of the widget.
+
+        Returns the new position of sash number index."""
+        return self.tk.call(self._w, "sashpos", index, newpos)
+
+PanedWindow = Panedwindow # Tkinter name compatibility
+
+
+class Progressbar(Widget):
+    """Ttk Progressbar widget shows the status of a long-running
+    operation. They can operate in two modes: determinate mode shows the
+    amount completed relative to the total amount of work to be done, and
+    indeterminate mode provides an animated display to let the user know
+    that something is happening."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Progressbar with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            orient, length, mode, maximum, value, variable, phase
+        """
+        Widget.__init__(self, master, "ttk::progressbar", kw)
+
+
+    def start(self, interval=None):
+        """Begin autoincrement mode: schedules a recurring timer event
+        that calls method step every interval milliseconds.
+
+        interval defaults to 50 milliseconds (20 steps/second) if ommited."""
+        self.tk.call(self._w, "start", interval)
+
+
+    def step(self, amount=None):
+        """Increments the value option by amount.
+
+        amount defaults to 1.0 if omitted."""
+        self.tk.call(self._w, "step", amount)
+
+
+    def stop(self):
+        """Stop autoincrement mode: cancels any recurring timer event
+        initiated by start."""
+        self.tk.call(self._w, "stop")
+
+
+class Radiobutton(Widget):
+    """Ttk Radiobutton widgets are used in groups to show or change a
+    set of mutually-exclusive options."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Radiobutton with parent master.
+
+        STANDARD OPTIONS
+
+            class, compound, cursor, image, state, style, takefocus,
+            text, textvariable, underline, width
+
+        WIDGET-SPECIFIC OPTIONS
+
+            command, value, variable
+        """
+        Widget.__init__(self, master, "ttk::radiobutton", kw)
+
+
+    def invoke(self):
+        """Sets the option variable to the option value, selects the
+        widget, and invokes the associated command.
+
+        Returns the result of the command, or an empty string if
+        no command is specified."""
+        return self.tk.call(self._w, "invoke")
+
+
+class Scale(Widget, Tkinter.Scale):
+    """Ttk Scale widget is typically used to control the numeric value of
+    a linked variable that varies uniformly over some range."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Scale with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            command, from, length, orient, to, value, variable
+        """
+        Widget.__init__(self, master, "ttk::scale", kw)
+
+
+    def configure(self, cnf=None, **kw):
+        """Modify or query scale options.
+
+        Setting a value for any of the "from", "from_" or "to" options
+        generates a <<RangeChanged>> event."""
+        if cnf:
+            kw.update(cnf)
+        Widget.configure(self, **kw)
+        if any(['from' in kw, 'from_' in kw, 'to' in kw]):
+            self.event_generate('<<RangeChanged>>')
+
+
+    def get(self, x=None, y=None):
+        """Get the current value of the value option, or the value
+        corresponding to the coordinates x, y if they are specified.
+
+        x and y are pixel coordinates relative to the scale widget
+        origin."""
+        return self.tk.call(self._w, 'get', x, y)
+
+
+class Scrollbar(Widget, Tkinter.Scrollbar):
+    """Ttk Scrollbar controls the viewport of a scrollable widget."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Scrollbar with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            command, orient
+        """
+        Widget.__init__(self, master, "ttk::scrollbar", kw)
+
+
+class Separator(Widget):
+    """Ttk Separator widget displays a horizontal or vertical separator
+    bar."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Separator with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus
+
+        WIDGET-SPECIFIC OPTIONS
+
+            orient
+        """
+        Widget.__init__(self, master, "ttk::separator", kw)
+
+
+class Sizegrip(Widget):
+    """Ttk Sizegrip allows the user to resize the containing toplevel
+    window by pressing and dragging the grip."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Sizegrip with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, state, style, takefocus
+        """
+        Widget.__init__(self, master, "ttk::sizegrip", kw)
+
+
+class Treeview(Widget):
+    """Ttk Treeview widget displays a hierarchical collection of items.
+
+    Each item has a textual label, an optional image, and an optional list
+    of data values. The data values are displayed in successive columns
+    after the tree label."""
+
+    def __init__(self, master=None, **kw):
+        """Construct a Ttk Treeview with parent master.
+
+        STANDARD OPTIONS
+
+            class, cursor, style, takefocus, xscrollcommand,
+            yscrollcommand
+
+        WIDGET-SPECIFIC OPTIONS
+
+            columns, displaycolumns, height, padding, selectmode, show
+
+        ITEM OPTIONS
+
+            text, image, values, open, tags
+
+        TAG OPTIONS
+
+            foreground, background, font, image
+        """
+        Widget.__init__(self, master, "ttk::treeview", kw)
+
+
+    def bbox(self, item, column=None):
+        """Returns the bounding box (relative to the treeview widget's
+        window) of the specified item in the form x y width height.
+
+        If column is specified, returns the bounding box of that cell.
+        If the item is not visible (i.e., if it is a descendant of a
+        closed item or is scrolled offscreen), returns an empty string."""
+        return self.tk.call(self._w, "bbox", item, column)
+
+
+    def get_children(self, item=None):
+        """Returns a tuple of children belonging to item.
+
+        If item is not specified, returns root children."""
+        return self.tk.call(self._w, "children", item or '') or ()
+
+
+    def set_children(self, item, *newchildren):
+        """Replaces item's child with newchildren.
+
+        Children present in item that are not present in newchildren
+        are detached from tree. No items in newchildren may be an
+        ancestor of item."""
+        self.tk.call(self._w, "children", item, newchildren)
+
+
+    def column(self, column, option=None, **kw):
+        """Query or modify the options for the specified column.
+
+        If kw is not given, returns a dict of the column option values. If
+        option is specified then the value for that option is returned.
+        Otherwise, sets the options to the corresponding values."""
+        if option is not None:
+            kw[option] = None
+        return _val_or_dict(kw, self.tk.call, self._w, "column", column)
+
+
+    def delete(self, *items):
+        """Delete all specified items and all their descendants. The root
+        item may not be deleted."""
+        self.tk.call(self._w, "delete", items)
+
+
+    def detach(self, *items):
+        """Unlinks all of the specified items from the tree.
+
+        The items and all of their descendants are still present, and may
+        be reinserted at another point in the tree, but will not be
+        displayed. The root item may not be detached."""
+        self.tk.call(self._w, "detach", items)
+
+
+    def exists(self, item):
+        """Returns True if the specified item is present in the three,
+        False otherwise."""
+        return bool(self.tk.call(self._w, "exists", item))
+
+
+    def focus(self, item=None):
+        """If item is specified, sets the focus item to item. Otherwise,
+        returns the current focus item, or '' if there is none."""
+        return self.tk.call(self._w, "focus", item)
+
+
+    def heading(self, column, option=None, **kw):
+        """Query or modify the heading options for the specified column.
+
+        If kw is not given, returns a dict of the heading option values. If
+        option is specified then the value for that option is returned.
+        Otherwise, sets the options to the corresponding values.
+
+        Valid options/values are:
+            text: text
+                The text to display in the column heading
+            image: image_name
+                Specifies an image to display to the right of the column
+                heading
+            anchor: anchor
+                Specifies how the heading text should be aligned. One of
+                the standard Tk anchor values
+            command: callback
+                A callback to be invoked when the heading label is
+                pressed.
+
+        To configure the tree column heading, call this with column = "#0" """
+        cmd = kw.get('command')
+        if cmd and not isinstance(cmd, basestring):
+            # callback not registered yet, do it now
+            kw['command'] = self.master.register(cmd, self._substitute)
+
+        if option is not None:
+            kw[option] = None
+
+        return _val_or_dict(kw, self.tk.call, self._w, 'heading', column)
+
+
+    def identify(self, component, x, y):
+        """Returns a description of the specified component under the
+        point given by x and y, or the empty string if no such component
+        is present at that position."""
+        return self.tk.call(self._w, "identify", component, x, y)
+
+
+    def identify_row(self, y):
+        """Returns the item ID of the item at position y."""
+        return self.identify("row", 0, y)
+
+
+    def identify_column(self, x):
+        """Returns the data column identifier of the cell at position x.
+
+        The tree column has ID #0."""
+        return self.identify("column", x, 0)
+
+
+    def identify_region(self, x, y):
+        """Returns one of:
+
+        heading: Tree heading area.
+        separator: Space between two columns headings;
+        tree: The tree area.
+        cell: A data cell.
+
+        * Availability: Tk 8.6"""
+        return self.identify("region", x, y)
+
+
+    def identify_element(self, x, y):
+        """Returns the element at position x, y.
+
+        * Availability: Tk 8.6"""
+        return self.identify("element", x, y)
+
+
+    def index(self, item):
+        """Returns the integer index of item within its parent's list
+        of children."""
+        return self.tk.call(self._w, "index", item)
+
+
+    def insert(self, parent, index, iid=None, **kw):
+        """Creates a new item and return the item identifier of the newly
+        created item.
+
+        parent is the item ID of the parent item, or the empty string
+        to create a new top-level item. index is an integer, or the value
+        end, specifying where in the list of parent's children to insert
+        the new item. If index is less than or equal to zero, the new node
+        is inserted at the beginning, if index is greater than or equal to
+        the current number of children, it is inserted at the end. If iid
+        is specified, it is used as the item identifier, iid must not
+        already exist in the tree. Otherwise, a new unique identifier
+        is generated."""
+        opts = _format_optdict(kw)
+        if iid:
+            res = self.tk.call(self._w, "insert", parent, index,
+                "-id", iid, *opts)
+        else:
+            res = self.tk.call(self._w, "insert", parent, index, *opts)
+
+        return res
+
+
+    def item(self, item, option=None, **kw):
+        """Query or modify the options for the specified item.
+
+        If no options are given, a dict with options/values for the item
+        is returned. If option is specified then the value for that option
+        is returned. Otherwise, sets the options to the corresponding
+        values as given by kw."""
+        if option is not None:
+            kw[option] = None
+        return _val_or_dict(kw, self.tk.call, self._w, "item", item)
+
+
+    def move(self, item, parent, index):
+        """Moves item to position index in parent's list of children.
+
+        It is illegal to move an item under one of its descendants. If
+        index is less than or equal to zero, item is moved to the
+        beginning, if greater than or equal to the number of children,
+        it is moved to the end. If item was detached it is reattached."""
+        self.tk.call(self._w, "move", item, parent, index)
+
+    reattach = move # A sensible method name for reattaching detached items
+
+
+    def next(self, item):
+        """Returns the identifier of item's next sibling, or '' if item
+        is the last child of its parent."""
+        return self.tk.call(self._w, "next", item)
+
+
+    def parent(self, item):
+        """Returns the ID of the parent of item, or '' if item is at the
+        top level of the hierarchy."""
+        return self.tk.call(self._w, "parent", item)
+
+
+    def prev(self, item):
+        """Returns the identifier of item's previous sibling, or '' if
+        item is the first child of its parent."""
+        return self.tk.call(self._w, "prev", item)
+
+
+    def see(self, item):
+        """Ensure that item is visible.
+
+        Sets all of item's ancestors open option to True, and scrolls
+        the widget if necessary so that item is within the visible
+        portion of the tree."""
+        self.tk.call(self._w, "see", item)
+
+
+    def selection(self, selop=None, items=None):
+        """If selop is not specified, returns selected items."""
+        return self.tk.call(self._w, "selection", selop, items)
+
+
+    def selection_set(self, items):
+        """items becomes the new selection."""
+        self.selection("set", items)
+
+
+    def selection_add(self, items):
+        """Add items to the selection."""
+        self.selection("add", items)
+
+
+    def selection_remove(self, items):
+        """Remove items from the selection."""
+        self.selection("remove", items)
+
+
+    def selection_toggle(self, items):
+        """Toggle the selection state of each item in items."""
+        self.selection("toggle", items)
+
+
+    def set(self, item, column=None, value=None):
+        """With one argument, returns a dictionary of column/value pairs
+        for the specified item. With two arguments, returns the current
+        value of the specified column. With three arguments, sets the
+        value of given column in given item to the specified value."""
+        res = self.tk.call(self._w, "set", item, column, value)
+        if column is None and value is None:
+            return _dict_from_tcltuple(res, False)
+        else:
+            return res
+
+
+    def tag_bind(self, tagname, sequence=None, callback=None):
+        """Bind a callback for the given event sequence to the tag tagname.
+        When an event is delivered to an item, the callbacks for each
+        of the item's tags option are called."""
+        self._bind((self._w, "tag", "bind", tagname), sequence, callback, add=0)
+
+
+    def tag_configure(self, tagname, option=None, **kw):
+        """Query or modify the options for the specified tagname.
+
+        If kw is not given, returns a dict of the option settings for tagname.
+        If option is specified, returns the value for that option for the
+        specified tagname. Otherwise, sets the options to the corresponding
+        values for the given tagname."""
+        if option is not None:
+            kw[option] = None
+        return _val_or_dict(kw, self.tk.call, self._w, "tag", "configure",
+            tagname)
+
+
+    def tag_has(self, tagname, item=None):
+        """If item is specified, returns 1 or 0 depending on whether the
+        specified item has the given tagname. Otherwise, returns a list of
+        all items which have the specified tag.
+
+        * Availability: Tk 8.6"""
+        return self.tk.call(self._w, "tag", "has", tagname, item)
+
+
+    def xview(self, *args):
+        """Query or modify horizontal position of the treeview."""
+        return self.tk.call(self._w, "xview", *args)
+
+
+    def yview(self, *args):
+        """Query or modify vertical position of the treeview."""
+        return self.tk.call(self._w, "yview", *args)
+
+
+# Extensions
+
+class LabeledScale(Frame, object):
+    """A Ttk Scale widget with a Ttk Label widget indicating its
+    current value.
+
+    The Ttk Scale can be accessed through instance.scale, and Ttk Label
+    can be accessed through instance.label"""
+
+    def __init__(self, master=None, variable=None, from_=0, to=10, **kw):
+        """Construct an horizontal LabeledScale with parent master, a
+        variable to be associated with the Ttk Scale widget and its range.
+        If variable is not specified, a Tkinter.IntVar is created.
+
+        WIDGET-SPECIFIC OPTIONS
+
+            compound: 'top' or 'bottom'
+                Specifies how to display the label relative to the scale.
+                Defaults to 'top'.
+        """
+        self._label_top = kw.pop('compound', 'top') == 'top'
+
+        Frame.__init__(self, master, **kw)
+        self._variable = variable or Tkinter.IntVar(master)
+        self._variable.set(from_)
+        self._last_valid = from_
+
+        self.label = Label(self)
+        self.scale = Scale(self, variable=self._variable, from_=from_, to=to)
+        self.scale.bind('<<RangeChanged>>', self._adjust)
+
+        # position scale and label according to the compound option
+        scale_side = 'bottom' if self._label_top else 'top'
+        label_side = 'top' if scale_side == 'bottom' else 'bottom'
+        self.scale.pack(side=scale_side, fill='x')
+        tmp = Label(self).pack(side=label_side) # place holder
+        self.label.place(anchor='n' if label_side == 'top' else 's')
+
+        # update the label as scale or variable changes
+        self.__tracecb = self._variable.trace_variable('w', self._adjust)
+        self.bind('<Configure>', self._adjust)
+        self.bind('<Map>', self._adjust)
+
+
+    def destroy(self):
+        """Destroy this widget and possibly its associated variable."""
+        try:
+            self._variable.trace_vdelete('w', self.__tracecb)
+        except AttributeError:
+            # widget has been destroyed already
+            pass
+        else:
+            del self._variable
+            Frame.destroy(self)
+
+
+    def _adjust(self, *args):
+        """Adjust the label position according to the scale."""
+        def adjust_label():
+            self.update_idletasks() # "force" scale redraw
+
+            x, y = self.scale.coords()
+            if self._label_top:
+                y = self.scale.winfo_y() - self.label.winfo_reqheight()
+            else:
+                y = self.scale.winfo_reqheight() + self.label.winfo_reqheight()
+
+            self.label.place_configure(x=x, y=y)
+
+        from_, to = self.scale['from'], self.scale['to']
+        if to < from_:
+            from_, to = to, from_
+        newval = self._variable.get()
+        if not from_ <= newval <= to:
+            # value outside range, set value back to the last valid one
+            self.value = self._last_valid
+            return
+
+        self._last_valid = newval
+        self.label['text'] = newval
+        self.after_idle(adjust_label)
+
+
+    def _get_value(self):
+        """Return current scale value."""
+        return self._variable.get()
+
+
+    def _set_value(self, val):
+        """Set new scale value."""
+        self._variable.set(val)
+
+
+    value = property(_get_value, _set_value)
+
+
+class OptionMenu(Menubutton):
+    """Themed OptionMenu, based after Tkinter's OptionMenu, which allows
+    the user to select a value from a menu."""
+
+    def __init__(self, master, variable, default=None, *values, **kwargs):
+        """Construct a themed OptionMenu widget with master as the parent,
+        the resource textvariable set to variable, the initially selected
+        value specified by the default parameter, the menu values given by
+        *values and additional keywords.
+
+        WIDGET-SPECIFIC OPTIONS
+
+            style: stylename
+                Menubutton style.
+            direction: 'above', 'below', 'left', 'right', or 'flush'
+                Menubutton direction.
+            command: callback
+                A callback that will be invoked after selecting an item.
+        """
+        kw = {'textvariable': variable, 'style': kwargs.pop('style', None),
+              'direction': kwargs.pop('direction', None)}
+        Menubutton.__init__(self, master, **kw)
+        self['menu'] = Tkinter.Menu(self, tearoff=False)
+
+        self._variable = variable
+        self._callback = kwargs.pop('command', None)
+        if kwargs:
+            raise Tkinter.TclError('unknown option -%s' % (
+                kwargs.iterkeys().next()))
+
+        self.set_menu(default, *values)
+
+
+    def __getitem__(self, item):
+        if item == 'menu':
+            return self.nametowidget(Menubutton.__getitem__(self, item))
+
+        return Menubutton.__getitem__(self, item)
+
+
+    def set_menu(self, default=None, *values):
+        """Build a new menu of radiobuttons with *values and optionally
+        a default value."""
+        menu = self['menu']
+        menu.delete(0, 'end')
+        for val in values:
+            menu.add_radiobutton(label=val,
+                command=Tkinter._setit(self._variable, val, self._callback))
+
+        if default:
+            self._variable.set(default)
+
+
+    def destroy(self):
+        """Destroy this widget and its associated variable."""
+        del self._variable
+        Menubutton.destroy(self)

Added: python/trunk/Lib/test/test_tk_guionly.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/test/test_tk_guionly.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,23 @@
+import os
+import sys
+from test import test_support
+
+this_dir = os.path.dirname(os.path.abspath(__file__))
+lib_tk_test = os.path.abspath(os.path.join(this_dir, os.path.pardir,
+    'lib-tk', 'test'))
+if lib_tk_test not in sys.path:
+    sys.path.append(lib_tk_test)
+
+import runtktests
+
+def test_main(enable_gui=False):
+    if enable_gui:
+        if test_support.use_resources is None:
+            test_support.use_resources = ['gui']
+        elif 'gui' not in test_support.use_resources:
+            test_support.use_resources.append('gui')
+
+    test_support.run_unittest(*runtktests.get_tests(text=False))
+
+if __name__ == '__main__':
+    test_main(enable_gui=True)

Added: python/trunk/Lib/test/test_tk_textonly.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/test/test_tk_textonly.py	Wed Jan 28 14:09:03 2009
@@ -0,0 +1,16 @@
+import os
+import sys
+from test import test_support
+
+this_dir = os.path.dirname(os.path.abspath(__file__))
+lib_tk_test = os.path.abspath(os.path.join(this_dir, '..', 'lib-tk', 'test'))
+if lib_tk_test not in sys.path:
+    sys.path.append(lib_tk_test)
+
+import runtktests
+
+def test_main():
+    test_support.run_unittest(*runtktests.get_tests(gui=False))
+
+if __name__ == '__main__':
+    test_main()

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Wed Jan 28 14:09:03 2009
@@ -145,6 +145,8 @@
 Library
 -------
 
+- Added the ttk module. See issue #2983: Ttk support for Tkinter.
+
 - Issue 5021:  doctest.testfile() did not create __name__ and
   collections.namedtuple() relied on __name__ being defined.
 


More information about the Python-checkins mailing list