summaryrefslogtreecommitdiffstats
path: root/library/demos
diff options
context:
space:
mode:
Diffstat (limited to 'library/demos')
-rw-r--r--library/demos/ttk_demo.tcl883
-rw-r--r--library/demos/ttk_iconlib.tcl110
-rw-r--r--library/demos/ttk_repeater.tcl117
3 files changed, 1110 insertions, 0 deletions
diff --git a/library/demos/ttk_demo.tcl b/library/demos/ttk_demo.tcl
new file mode 100644
index 0000000..0686b62
--- /dev/null
+++ b/library/demos/ttk_demo.tcl
@@ -0,0 +1,883 @@
+#
+# $Id: ttk_demo.tcl,v 1.1 2006/10/31 01:42:26 hobbs Exp $
+#
+# Tile widget set -- widget demo
+#
+package require Tk 8.5
+
+eval destroy [winfo children .] ;# in case script is re-sourced
+
+### Load auxilliary scripts.
+#
+variable demodir [file dirname [info script]]
+lappend auto_path . $demodir
+
+source [file join $demodir ttk_iconlib.tcl]
+source [file join $demodir ttk_repeater.tcl]
+
+# This forces an update of the available packages list.
+# It's required for package names to find the themes in demos/themes/*.tcl
+eval [package unknown] Tcl [package provide Tcl]
+
+### Global options and bindings.
+#
+option add *Button.default normal
+option add *Text.background white
+option add *Entry.background white
+option add *tearOff false
+
+# See toolbutton.tcl.
+#
+option add *Toolbar.relief groove
+option add *Toolbar.borderWidth 2
+option add *Toolbar.Button.Pad 2
+option add *Toolbar.Button.default disabled
+option add *Toolbar*takeFocus 0
+
+# ... for debugging:
+bind all <ButtonPress-3> { set ::W %W }
+bind all <Control-ButtonPress-3> { focus %W }
+
+# Stealth feature:
+#
+if {![catch {package require Img 1.3}]} {
+ bind all <Control-Shift-Alt-KeyPress-S> screenshot
+ proc screenshot {} {
+ image create photo ScreenShot -format window -data .
+ bell
+ # Gamma looks off if we use PNG ...
+ # Looks even worse if we use GIF ...
+ ScreenShot write screenshot.png -format png
+ image delete ScreenShot
+ bell
+ }
+}
+
+### Global data.
+#
+
+# The descriptive names of the builtin themes:
+#
+set ::THEMELIST {
+ default "Default"
+ classic "Classic"
+ alt "Revitalized"
+ winnative "Windows native"
+ xpnative "XP Native"
+ aqua "Aqua"
+}
+array set ::THEMES $THEMELIST;
+
+# Add in any available loadable themes:
+#
+foreach name [ttk::themes] {
+ if {![info exists ::THEMES($name)]} {
+ lappend THEMELIST $name [set ::THEMES($name) [string totitle $name]]
+ }
+}
+
+# Generate icons (see also: iconlib.tcl):
+#
+foreach {icon data} [array get ::ImgData] {
+ set ::ICON($icon) [image create photo -data $data]
+}
+
+variable ROOT "."
+variable BASE [ttk::frame .base]
+pack $BASE -side top -expand true -fill both
+
+array set ::V {
+ COMPOUND top
+ CONSOLE 0
+ MENURADIO1 One
+ PBMODE determinate
+ SELECTED 1
+ CHOICE 2
+ SCALE 50
+ VSCALE 0
+}
+
+### Utilities.
+#
+
+## foreachWidget varname widget script --
+# Execute $script with $varname set to each widget in the hierarchy.
+#
+proc foreachWidget {varname Q script} {
+ upvar 1 $varname w
+ while {[llength $Q]} {
+ set QN [list]
+ foreach w $Q {
+ uplevel 1 $script
+ foreach child [winfo children $w] {
+ lappend QN $child
+ }
+ }
+ set Q $QN
+ }
+}
+
+## sbstub $sb -- stub -command option for a scrollbar.
+# Updates the scrollbar's position.
+#
+proc sbstub {sb cmd number {units units}} { sbstub.$cmd $sb $number $units }
+proc sbstub.moveto {sb number _} { $sb set $number [expr {$number + 0.5}] }
+proc sbstub.scroll {sb number units} {
+ if {$units eq "pages"} {
+ set delta 0.2
+ } else {
+ set delta 0.05
+ }
+ set current [$sb get]
+ set new0 [expr {[lindex $current 0] + $delta*$number}]
+ set new1 [expr {[lindex $current 1] + $delta*$number}]
+ $sb set $new0 $new1
+}
+
+## sbset $sb -- auto-hide scrollbar
+# Scrollable widget -[xy]scrollcommand prefix.
+# Sets the scrollbar, auto-hides/shows.
+# Scrollbar must be controlled by the grid geometry manager.
+#
+proc sbset {sb first last} {
+ if {$first <= 0 && $last >= 1} {
+ grid remove $sb
+ } else {
+ grid $sb
+ }
+ $sb set $first $last
+}
+
+## scrolled -- create a widget with attached scrollbars.
+#
+proc scrolled {class w args} {
+ set sf "${w}_sf"
+
+ frame $sf
+ eval [linsert $args 0 $class $w]
+ scrollbar $sf.hsb -orient horizontal -command [list $w xview]
+ scrollbar $sf.vsb -orient vertical -command [list $w yview]
+
+ configure.scrolled $sf $w
+ return $sf
+}
+
+## ttk::scrolled -- create a widget with attached Ttk scrollbars.
+#
+proc ttk::scrolled {class w args} {
+ set sf "${w}_sf"
+
+ ttk::frame $sf
+ eval [linsert $args 0 $class $w]
+ ttk::scrollbar $sf.hsb -orient horizontal -command [list $w xview]
+ ttk::scrollbar $sf.vsb -orient vertical -command [list $w yview]
+
+ configure.scrolled $sf $w
+ return $sf
+}
+
+## configure.scrolled -- common factor of [scrolled] and [ttk::scrolled]
+#
+proc configure.scrolled {sf w} {
+ $w configure -xscrollcommand [list $sf.hsb set]
+ $w configure -yscrollcommand [list $sf.vsb set]
+
+ grid $w -in $sf -row 0 -column 0 -sticky nwse
+ grid $sf.hsb -row 1 -column 0 -sticky we
+ grid $sf.vsb -row 0 -column 1 -sticky ns
+
+ grid columnconfigure $sf 0 -weight 1
+ grid rowconfigure $sf 0 -weight 1
+}
+
+### Toolbars.
+#
+proc makeToolbars {} {
+ set buttons [list open new save]
+ set checkboxes [list bold italic]
+
+ #
+ # Ttk toolbar:
+ #
+ set tb [ttk::frame $::BASE.tbar_styled -class Toolbar]
+ set i 0
+ foreach icon $buttons {
+ set b [ttk::button $tb.tb[incr i] \
+ -text $icon -image $::ICON($icon) -compound $::V(COMPOUND) \
+ -style Toolbutton]
+ grid $b -row 0 -column $i -sticky news
+ }
+ ttk::separator $tb.sep -orient vertical
+ grid $tb.sep -row 0 -column [incr i] -sticky news -padx 2 -pady 2
+ foreach icon $checkboxes {
+ set b [ttk::checkbutton $tb.cb[incr i] \
+ -variable ::V($icon) \
+ -text $icon -image $::ICON($icon) -compound $::V(COMPOUND) \
+ -style Toolbutton]
+ grid $b -row 0 -column $i -sticky news
+ }
+
+ ttk::menubutton $tb.compound \
+ -text "toolbar" -image $::ICON(file) -compound $::V(COMPOUND)
+ $tb.compound configure -menu [makeCompoundMenu $tb.compound.menu]
+ grid $tb.compound -row 0 -column [incr i] -sticky news
+
+ grid columnconfigure $tb [incr i] -weight 1
+
+ #
+ # Standard toolbar:
+ #
+ set tb [frame $::BASE.tbar_orig -class Toolbar]
+ set i 0
+ foreach icon $buttons {
+ set b [button $tb.tb[incr i] \
+ -text $icon -image $::ICON($icon) -compound $::V(COMPOUND) \
+ -relief flat -overrelief raised]
+ grid $b -row 0 -column $i -sticky news
+ }
+ frame $tb.sep -borderwidth 1 -width 2 -relief sunken
+ grid $tb.sep -row 0 -column [incr i] -sticky news -padx 2 -pady 2
+ foreach icon $checkboxes {
+ set b [checkbutton $tb.cb[incr i] -variable ::V($icon) \
+ -text $icon -image $::ICON($icon) -compound $::V(COMPOUND) \
+ -indicatoron false \
+ -selectcolor {} \
+ -relief flat \
+ -overrelief raised \
+ -offrelief flat]
+ grid $b -row 0 -column $i -sticky news
+ }
+
+ menubutton $tb.compound \
+ -text "toolbar" -image $::ICON(file) -compound $::V(COMPOUND) \
+ -indicatoron true
+ $tb.compound configure -menu [makeCompoundMenu $tb.compound.menu]
+ grid $tb.compound -row 0 -column [incr i] -sticky news
+
+ grid columnconfigure $tb [incr i] -weight 1
+}
+
+#
+# Toolbar -compound control:
+#
+proc makeCompoundMenu {menu} {
+ variable compoundStrings {text image none top bottom left right center}
+ menu $menu
+ foreach string $compoundStrings {
+ $menu add radiobutton \
+ -label [string totitle $string] \
+ -variable ::V(COMPOUND) -value $string \
+ -command changeToolbars ;
+ }
+ return $menu
+}
+
+proc changeToolbars {} {
+ foreachWidget w [list $::BASE.tbar_styled $::BASE.tbar_orig] {
+ catch { $w configure -compound $::V(COMPOUND) }
+ }
+}
+
+makeToolbars
+
+### Theme control panel.
+#
+proc makeThemeControl {c} {
+ ttk::labelframe $c -text "Theme"
+ foreach {theme name} $::THEMELIST {
+ set b [ttk::radiobutton $c.s$theme -text $name \
+ -variable ::ttk::currentTheme -value $theme \
+ -command [list ttk::setTheme $theme]]
+ pack $b -side top -expand false -fill x
+ if {[lsearch -exact [package names] ttk::theme::$theme] == -1} {
+ $c.s$theme state disabled
+ }
+ }
+ return $c
+}
+makeThemeControl $::BASE.control
+
+### Notebook widget.
+#
+set nb [ttk::notebook $::BASE.nb]
+ttk::notebook::enableTraversal $nb
+
+### Main demo pane.
+#
+# Side-by comparison of Ttk vs. core widgets.
+#
+
+
+set pw [ttk::panedwindow $nb.client -orient horizontal]
+$nb add $pw -text "Demo" -underline 0 -padding 6
+set l [ttk::labelframe $pw.l -text "Themed" -padding 6 -underline 1]
+set r [labelframe $pw.r -text "Standard" -padx 6 -pady 6]
+$pw add $l -weight 1; $pw add $r -weight 1
+
+## menubuttonMenu -- demo menu for menubutton widgets.
+#
+proc menubuttonMenu {menu} {
+ menu $menu
+ foreach dir {above below left right flush} {
+ $menu add command -label [string totitle $dir] \
+ -command [list [winfo parent $menu] configure -direction $dir]
+ }
+ $menu add cascade -label "Submenu" -menu [set submenu [menu $menu.submenu]]
+ $submenu add command -label "Subcommand 1"
+ $submenu add command -label "Subcommand 2"
+ $submenu add command -label "Subcommand 3"
+ $menu add separator
+ $menu add command -label "Quit" -command [list destroy .]
+
+ return $menu
+}
+
+## Main demo pane - themed widgets.
+#
+ttk::checkbutton $l.cb -text "Checkbutton" -variable ::V(SELECTED) -underline 2
+ttk::radiobutton $l.rb1 -text "One" -variable ::V(CHOICE) -value 1 -underline 0
+ttk::radiobutton $l.rb2 -text "Two" -variable ::V(CHOICE) -value 2
+ttk::radiobutton $l.rb3 -text "Three" -variable ::V(CHOICE) -value 3 -under 0
+ttk::button $l.button -text "Button" -underline 0
+
+ttk::menubutton $l.mb -text "Menubutton" -underline 2
+$l.mb configure -menu [menubuttonMenu $l.mb.menu]
+
+set ::entryText "Entry widget"
+ttk::entry $l.e -textvariable ::entryText
+$l.e selection range 6 end
+
+set ltext [ttk::scrolled text $l.t -width 12 -height 5 -wrap none]
+
+grid $l.cb -sticky ew
+grid $l.rb1 -sticky ew
+grid $l.rb2 -sticky ew
+grid $l.rb3 -sticky ew
+grid $l.button -sticky ew -padx 2 -pady 2
+grid $l.mb -sticky ew -padx 2 -pady 2
+grid $l.e -sticky ew -padx 2 -pady 2
+grid $ltext -sticky news
+
+grid columnconfigure $l 0 -weight 1
+grid rowconfigure $l 7 -weight 1 ; # text widget (grid is a PITA)
+
+## Main demo pane - core widgets.
+#
+checkbutton $r.cb -text "Checkbutton" -variable ::V(SELECTED)
+radiobutton $r.rb1 -text "One" -variable ::V(CHOICE) -value 1
+radiobutton $r.rb2 -text "Two" -variable ::V(CHOICE) -value 2 -underline 1
+radiobutton $r.rb3 -text "Three" -variable ::V(CHOICE) -value 3
+button $r.button -text "Button"
+menubutton $r.mb -text "Menubutton" -underline 3 -takefocus 1
+$r.mb configure -menu [menubuttonMenu $r.mb.menu]
+# Add -indicatoron control:
+set ::V(rmbIndicatoron) [$r.mb cget -indicatoron]
+$r.mb.menu insert 0 checkbutton -label "Indicator?" \
+ -variable ::V(rmbIndicatoron) \
+ -command "$r.mb configure -indicatoron \$::V(rmbIndicatoron)" ;
+$r.mb.menu insert 1 separator
+
+entry $r.e -textvariable ::entryText
+
+set rtext [scrolled text $r.t -width 12 -height 5 -wrap none]
+
+grid $r.cb -sticky ew
+grid $r.rb1 -sticky ew
+grid $r.rb2 -sticky ew
+grid $r.rb3 -sticky ew
+grid $r.button -sticky ew -padx 2 -pady 2
+grid $r.mb -sticky ew -padx 2 -pady 2
+grid $r.e -sticky ew -padx 2 -pady 2
+grid $rtext -sticky news
+
+grid columnconfigure $r 0 -weight 1
+grid rowconfigure $r 7 -weight 1 ; # text widget
+
+#
+# Add some text to the text boxes:
+#
+
+set cb $::BASE.tbar_orig.cb5
+set txt "checkbutton $cb \\\n"
+foreach copt [$cb configure] {
+ if {[llength $copt] == 5} {
+ append txt " [lindex $copt 0] [lindex $copt 4] \\\n"
+ }
+}
+append txt " ;\n"
+
+$l.t insert end $txt
+$r.t insert end $txt
+
+### Scales and sliders pane.
+#
+proc scales.pane {scales} {
+ ttk::frame $scales
+
+ ttk::panedwindow $scales.pw -orient horizontal
+ set l [ttk::labelframe $scales.styled -text "Themed" -padding 6]
+ set r [labelframe $scales.orig -text "Standard" -padx 6 -pady 6]
+
+ ttk::scale $l.scale -orient horizontal -from 0 -to 100 -variable ::V(SCALE)
+ ttk::scale $l.vscale -orient vertical -from 100 -to 0 -variable ::V(VSCALE)
+ ttk::progressbar $l.progress -orient horizontal -maximum 100
+ ttk::progressbar $l.vprogress -orient vertical -maximum 100
+ if {1} {
+ $l.scale configure -command [list $l.progress configure -value]
+ $l.vscale configure -command [list $l.vprogress configure -value]
+ } else {
+ # This would also work, but the Tk scale widgets
+ # in the right hand pane cause some interference when
+ # in autoincrement/indeterminate mode.
+ #
+ $l.progress configure -variable ::V(SCALE)
+ $l.vprogress configure -variable ::V(VSCALE)
+ }
+
+ $l.scale set 50
+ $l.vscale set 50
+
+ ttk::label $l.lmode -text "Progress bar mode:"
+ ttk::radiobutton $l.pbmode0 -variable ::V(PBMODE) \
+ -text determinate -value determinate -command [list pbMode $l]
+ ttk::radiobutton $l.pbmode1 -variable ::V(PBMODE) \
+ -text indeterminate -value indeterminate -command [list pbMode $l]
+ proc pbMode {l} {
+ variable V
+ $l.progress configure -mode $V(PBMODE)
+ $l.vprogress configure -mode $V(PBMODE)
+ }
+
+ ttk::button $l.start -text "Start" -command [list pbStart $l]
+ proc pbStart {l} {
+ set ::V(PBMODE) indeterminate; pbMode $l
+ $l.progress start 10
+ $l.vprogress start
+ }
+
+ ttk::button $l.stop -text "Stop" -command [list pbStop $l]
+ proc pbStop {l} {
+ $l.progress stop
+ $l.vprogress stop
+ }
+
+ grid $l.scale -columnspan 2 -sticky ew
+ grid $l.progress -columnspan 2 -sticky ew
+ grid $l.vscale $l.vprogress -sticky nws
+
+ grid $l.lmode -sticky we -columnspan 2
+ grid $l.pbmode0 -sticky we -columnspan 2
+ grid $l.pbmode1 -sticky we -columnspan 2
+ grid $l.start -sticky we -columnspan 2
+ grid $l.stop -sticky we -columnspan 2
+
+ grid columnconfigure $l 0 -weight 1
+ grid columnconfigure $l 1 -weight 1
+
+ grid rowconfigure $l 99 -weight 1
+
+ scale $r.scale -orient horizontal -from 0 -to 100 -variable ::V(SCALE)
+ scale $r.vscale -orient vertical -from 100 -to 0 -variable ::V(VSCALE)
+ grid $r.scale -sticky news
+ grid $r.vscale -sticky nws
+
+ grid rowconfigure $r 99 -weight 1
+ grid columnconfigure $r 0 -weight 1
+
+ ##
+ $scales.pw add $l -weight 1
+ $scales.pw add $r -weight 1
+ pack $scales.pw -expand true -fill both
+
+ return $scales
+}
+$nb add [scales.pane $nb.scales] -text Scales -sticky nwes -padding 6
+
+### Combobox demo pane.
+#
+proc combobox.pane {cbf} {
+ ttk::frame $cbf
+ set values [list abc def ghi jkl mno pqr stu vwx yz]
+ pack \
+ [ttk::combobox $cbf.cb1 -values $values -textvariable ::COMBO] \
+ [ttk::combobox $cbf.cb2 -values $values -textvariable ::COMBO ] \
+ -side top -padx 2 -pady 2 -expand false -fill x;
+ $cbf.cb2 configure -state readonly
+ $cbf.cb1 current 3
+ return $cbf
+}
+$nb add [combobox.pane $nb.combos] -text "Combobox" -underline 7
+
+### Treeview widget demo pane.
+#
+proc tree.pane {w} {
+ ttk::frame $w
+ ttk::scrollbar $w.vsb -command [list $w.t yview]
+ ttk::treeview $w.t -columns [list Class] \
+ -padding 4 \
+ -yscrollcommand [list sbset $w.vsb]
+
+ grid $w.t $w.vsb -sticky nwse
+ grid columnconfigure $w 0 -weight 1
+ grid rowconfigure $w 0 -weight 1
+ grid propagate $w 0
+
+ #
+ # Add initial tree node:
+ # Later nodes will be added in <<TreeviewOpen>> binding.
+ #
+ $w.t insert {} 0 -id . -text "Main Window" -open 0 \
+ -values [list [winfo class .]]
+ $w.t heading \#0 -text "Widget"
+ $w.t heading Class -text "Class"
+ bind $w.t <<TreeviewOpen>> [list fillTree $w.t]
+
+ return $w
+}
+
+# fillTree -- <<TreeviewOpen>> binding for tree widget.
+#
+proc fillTree {tv} {
+ set id [$tv focus]
+ if {![winfo exists $id]} {
+ $tv delete $id
+ return
+ }
+
+ #
+ # Replace tree item children with current list of child windows.
+ #
+ $tv delete [$tv children $id]
+ set children [winfo children $id]
+ foreach child $children {
+ $tv insert $id end -id $child -text [winfo name $child] -open 0 \
+ -values [list [winfo class $child]]
+ if {[llength [winfo children $child]]} {
+ # insert dummy child to show [+] indicator
+ $tv insert $child end
+ }
+ }
+}
+
+if {[llength [info commands ttk::treeview]]} {
+ $nb add [tree.pane $nb.tree] -text "Tree" -sticky news
+}
+
+### Other demos.
+#
+$nb add [ttk::frame $nb.others] -text "Others" -underline 4
+
+set Timers(StateMonitor) {}
+set Timers(FocusMonitor) {}
+
+set others $::BASE.nb.others
+
+ttk::label $others.m -justify left -wraplength 300
+bind ShowDescription <Enter> { $BASE.nb.others.m configure -text $Desc(%W) }
+bind ShowDescription <Leave> { $BASE.nb.others.m configure -text "" }
+
+foreach {command label description} {
+ trackStates "Widget states..."
+ "Display/modify widget state bits"
+
+ scrollbarResizeDemo "Scrollbar resize behavior..."
+ "Shows how Ttk and standard scrollbars differ when they're sized too large"
+
+ trackFocus "Track keyboard focus..."
+ "Display the name of the widget that currently has focus"
+
+ repeatDemo "Repeating buttons"
+ "Demonstrates custom classes (see demos/repeater.tcl)"
+
+} {
+ set b [ttk::button $others.$command -text $label -command $command]
+ set Desc($b) $description
+ bindtags $b [lreplace [bindtags $b] end 0 ShowDescription]
+
+ pack $b -side top -expand false -fill x -padx 6 -pady 6
+}
+
+pack $others.m -side bottom -expand true -fill both
+
+
+### Scrollbar resize demo.
+#
+proc scrollbarResizeDemo {} {
+ set t .scrollbars
+ destroy $t
+ toplevel $t ; wm geometry $t 200x200
+ frame $t.f -height 200
+ grid \
+ [ttk::scrollbar $t.f.tsb -command [list sbstub $t.f.tsb]] \
+ [scrollbar $t.f.sb -command [list sbstub $t.f.sb]] \
+ -sticky news
+
+ $t.f.sb set 0 0.5 ;# prevent backwards-compatibility mode for old SB
+
+ grid columnconfigure $t.f 0 -weight 1
+ grid columnconfigure $t.f 1 -weight 1
+ grid rowconfigure $t.f 0 -weight 1
+ pack $t.f -expand true -fill both
+}
+
+### Track focus demo.
+#
+proc trackFocus {} {
+ global Focus
+ set t .focus
+ destroy $t
+ toplevel $t
+ wm title $t "Keyboard focus"
+ set i 0
+ foreach {label variable} {
+ "Focus widget:" Focus(Widget)
+ "Class:" Focus(WidgetClass)
+ "Next:" Focus(WidgetNext)
+ "Grab:" Focus(Grab)
+ "Status:" Focus(GrabStatus)
+ } {
+ grid [ttk::label $t.l$i -text $label -anchor e] \
+ [ttk::label $t.v$i -textvariable $variable \
+ -width 40 -anchor w -relief groove] \
+ -sticky ew;
+ incr i
+ }
+ grid columnconfigure $t 1 -weight 1
+ grid rowconfigure $t $i -weight 1
+
+ bind $t <Destroy> {after cancel $Timers(FocusMonitor)}
+ FocusMonitor
+}
+
+proc FocusMonitor {} {
+ global Focus
+
+ set Focus(Widget) [focus]
+ if {$::Focus(Widget) ne ""} {
+ set Focus(WidgetClass) [winfo class $Focus(Widget)]
+ set Focus(WidgetNext) [tk_focusNext $Focus(Widget)]
+ } else {
+ set Focus(WidgetClass) [set Focus(WidgetNext) ""]
+ }
+
+ set Focus(Grab) [grab current]
+ if {$Focus(Grab) ne ""} {
+ set Focus(GrabStatus) [grab status $Focus(Grab)]
+ } else {
+ set Focus(GrabStatus) ""
+ }
+
+ set ::Timers(FocusMonitor) [after 200 FocusMonitor]
+}
+
+### Widget states demo.
+#
+variable Widget .tbar_styled.tb1
+
+bind all <Control-Shift-ButtonPress-1> { TrackWidget %W ; break }
+
+proc TrackWidget {w} {
+ set ::Widget $w ;
+ if {[winfo exists .states]} {
+ UpdateStates
+ } else {
+ trackStates
+ }
+}
+
+variable states [list \
+ active disabled focus pressed selected readonly \
+ background alternate invalid]
+
+proc trackStates {} {
+ variable states
+ set t .states
+ destroy $t; toplevel $t ; wm title $t "Widget states"
+
+ set tf [ttk::frame $t.f] ; pack $tf -expand true -fill both
+
+ ttk::label $tf.info -text "Press Control-Shift-Button-1 on any widget"
+
+ ttk::label $tf.lw -text "Widget:" -anchor e -relief groove
+ ttk::label $tf.w -textvariable ::Widget -anchor w -relief groove
+
+ grid $tf.info - -sticky ew -padx 6 -pady 6
+ grid $tf.lw $tf.w -sticky ew
+
+ foreach state $states {
+ ttk::checkbutton $tf.s$state \
+ -text $state \
+ -variable ::State($state) \
+ -command [list ChangeState $state] ;
+ grid x $tf.s$state -sticky nsew
+ }
+
+ grid columnconfigure $tf 1 -weight 1
+
+ grid x [ttk::frame $tf.cmd] -sticky nse
+ grid x \
+ [ttk::button $tf.cmd.close -text Close -command [list destroy $t]] \
+ -padx 4 -pady {6 4};
+ grid columnconfigure $tf.cmd 0 -weight 1
+
+ bind $t <KeyPress-Escape> [list event generate $tf.cmd.close <<Invoke>>]
+ bind $t <Destroy> { after cancel $::Timers(StateMonitor) }
+ StateMonitor
+}
+
+proc StateMonitor {} {
+ if {$::Widget ne ""} { UpdateStates }
+ set ::Timers(StateMonitor) [after 200 StateMonitor]
+}
+
+proc UpdateStates {} {
+ variable states
+ variable State
+ variable Widget
+
+ foreach state $states {
+ if {[catch {set State($state) [$Widget instate $state]}]} {
+ # Not a Ttk widget:
+ .states.f.s$state state disabled
+ } else {
+ .states.f.s$state state !disabled
+ }
+ }
+}
+
+proc ChangeState {state} {
+ variable State
+ variable Widget
+ if {$Widget ne ""} {
+ if {$State($state)} {
+ $Widget state $state
+ } else {
+ $Widget state !$state
+ }
+ }
+}
+
+### Repeating button demo.
+#
+
+proc repeatDemo {} {
+ set top .repeatDemo
+ if {![catch { wm deiconify $top ; raise $top }]} { return }
+ toplevel $top
+ wm title $top "Repeating button"
+ keynav::enableMnemonics $top
+
+ set f [ttk::frame .repeatDemo.f]
+ ttk::button $f.b -class Repeater -text "Press and hold" \
+ -command [list $f.p step]
+ ttk::progressbar $f.p -orient horizontal -maximum 10
+
+ ttk::separator $f.sep -orient horizontal
+ set cmd [ttk::frame $f.cmd]
+ pack \
+ [ttk::button $cmd.close -text Close -command [list destroy $top]] \
+ -side right -padx 6;
+
+ pack $f.cmd -side bottom -expand false -fill x -padx 6 -pady 6
+ pack $f.sep -side bottom -expand false -fill x -padx 6 -pady 6
+ pack $f.b -side left -expand false -fill none -padx 6 -pady 6
+ pack $f.p -side right -expand true -fill x -padx 6 -pady 6
+
+ $f.b configure -underline 0
+ $cmd.close configure -underline 0
+ bind $top <KeyPress-Escape> [list event generate $cmd.close <<Invoke>>]
+
+ pack $f -expand true -fill both
+}
+
+
+### Command box.
+#
+set cmd [ttk::frame $::BASE.command]
+ttk::button $cmd.close -text Close -underline 0 -command [list destroy .]
+ttk::button $cmd.help -text Help -command showHelp
+
+proc showHelp {} {
+ if {![winfo exists .helpDialog]} {
+ lappend detail "Tk version $::tk_version"
+ lappend detail "Ttk library: $::ttk::library"
+ ttk::dialog .helpDialog -type ok -icon info \
+ -message "Ttk demo" -detail [join $detail \n]
+ }
+}
+
+grid x $cmd.close $cmd.help -pady 6 -padx 6
+grid columnconfigure $cmd 0 -weight 1
+
+## Status bar (to demonstrate size grip)
+#
+set statusbar [ttk::frame $BASE.statusbar]
+pack [ttk::sizegrip $statusbar.grip] -side right -anchor se
+
+## Accelerators:
+#
+bind $::ROOT <KeyPress-Escape> [list event generate $cmd.close <<Invoke>>]
+bind $::ROOT <<Help>> [list event generate $cmd.help <<Invoke>>]
+keynav::enableMnemonics $::ROOT
+keynav::defaultButton $cmd.help
+
+### Menubar.
+#
+set menu [menu $::BASE.menu]
+$::ROOT configure -menu $menu
+$menu add cascade -label "File" -underline 0 -menu [menu $menu.file]
+$menu.file add command -label "Open" -underline 0 \
+ -compound left -image $::ICON(open)
+$menu.file add command -label "Save" -underline 0 \
+ -compound left -image $::ICON(save)
+$menu.file add separator
+$menu.file add checkbutton -label "Checkbox" -underline 0 \
+ -variable ::V(SELECTED)
+$menu.file add cascade -label "Choices" -underline 1 \
+ -menu [menu $menu.file.choices]
+foreach {label value} {One 1 Two 2 Three 3} {
+ $menu.file.choices add radiobutton \
+ -label $label -variable ::V(CHOICE) -value $value
+}
+
+$menu.file insert end separator
+if {[tk windowingsystem] ne "x11"} {
+ $menu.file insert end checkbutton -label Console -underline 5 \
+ -variable ::V(CONSOLE) -command toggleconsole
+ proc toggleconsole {} {
+ if {$::V(CONSOLE)} {console show} else {console hide}
+ }
+}
+$menu.file add command -label "Exit" -underline 1 \
+ -command [list event generate $cmd.close <<Invoke>>]
+
+# Add Theme menu.
+#
+proc makeThemeMenu {menu} {
+ menu $menu
+ foreach {theme name} $::THEMELIST {
+ $menu add radiobutton -label $name \
+ -variable ::ttk::currentTheme -value $theme \
+ -command [list ttk::setTheme $theme]
+ if {[lsearch -exact [package names] ttk::theme::$theme] == -1} {
+ $menu entryconfigure end -state disabled
+ }
+ }
+ return $menu
+}
+
+$menu add cascade -label "Theme" -underline 3 -menu [makeThemeMenu $menu.theme]
+
+### Main window layout.
+#
+
+pack $BASE.statusbar -side bottom -expand false -fill x
+pack $BASE.command -side bottom -expand false -fill x
+pack $BASE.tbar_styled -side top -expand false -fill x
+pack $BASE.tbar_orig -side top -expand false -fill x
+pack $BASE.control -side left -expand false -fill y -padx 6 -pady 6
+pack $BASE.nb -side left -expand true -fill both -padx 6 -pady 6
+
+wm title $ROOT "Ttk demo"
+wm iconname $ROOT "Ttk demo"
+update; wm deiconify $ROOT
diff --git a/library/demos/ttk_iconlib.tcl b/library/demos/ttk_iconlib.tcl
new file mode 100644
index 0000000..9a93ece
--- /dev/null
+++ b/library/demos/ttk_iconlib.tcl
@@ -0,0 +1,110 @@
+array set ImgData {
+bold {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI6hI+py60U3wj+
+RYQFJYRvEWFBCeFbRFhQQvhG8YPgX0RYUEL4FhEWlBC+RYQFJYQPFN8IPqYut/8hBQA7}
+copy {R0lGODlhEAAQAJEAANnZ2QAAAP///wAAhCH5BAEAAAAALAAAAAAQABAAAAJUhI8JFJ/gY4iI
+UEL4FyIiFIXgW0iEUDgfACBI9pzMAAGRiIghWSMDECR7JEKGtkFIRFBG+TIQKDQxtgzcDcmX
+IfgwQrFlCD4MyZch+EDzj+Bj6mYBADs=}
+cut {R0lGODlhEAAQAJEAANnZ2QAAAAAAhP///yH5BAEAAAAALAAAAAAQABAAAAJFhI+pcUHwEeIi
+E0gACIKPEAFBIXy0gMg8EhM+YmQiKSL4eAIiJMI/EQEhQGYGYiQIQAg+iAkIATIzECMBIgT/
+RBARERlSADs=}
+dragfile {R0lGODlhGAAYAKIAANnZ2TMzM////wAAAJmZmf///////////yH5BAEAAAAALAAAAAAYABgA
+AAPACBi63IqgC4GiyxwogaAbKLrMgSKBoBoousyBogEACIGiyxwoKgGAECI4uiyCExMTOACB
+osuNpDoAGCI4uiyCIkREOACBosutSDoAgSI4usyCIjQAGCi63Iw0ACEoOLrMgiI0ABgoutyM
+NAAhKDi6zIIiNAAYKLrcjDQAISg4usyCIjQAGCi63Iw0AIGiiqPLIyhCA4CBosvNSAMQKKo4
+ujyCIjQAGCi63Iw0AIGiy81IAxCBpMu9GAMAgKPL3QgJADs=}
+dragicon {R0lGODlhGAAYALMAANnZ2TMzM/////8zM8zMzGYAAAAAAJmZmQCZMwAzZgCZzGZmZv//////
+/////////yH5BAEAAAAALAAAAAAYABgAAAT/EMAgJ60SAjlBgEJOSoMIEMgZoJCT0iADBFIG
+KOSkNMwAAABhwiHnIEKIIIQQAQIZhBBwyDmKEMIEE0yABoAghIBDzlGEENDIaQAIQgg45BwF
+CinPOccAECYcUiKEEBFCiHPgMQAEIcQYYyABBUGIQCHlMQCEScZAAhKEEApCECGOARAEIQQp
+BRGIpAyCJCGOASBAISdEcqJAVBLiGABggELOAJGUKyiVhDgGABigkJMEhNAKSqkEhTgGgCCl
+FCQEGIJSSiUhjgEgQCEnJVBJmYQ4BoAAhZyTQCVnEuIYAAIUckoCk5xSiGMACFDISSs9BoBg
+rRXQMQAEKOSklR4DEUAI8MhJ6wwGAACgkZNWCkAEADs=}
+error {R0lGODlhIAAgAKIAANnZ2YQAAP8AAISEhP///////////////yH5BAEAAAAALAAAAAAgACAA
+AAP/CLoMGLqKoMvtGIqiqxEYCLrcioGiyxwIusyBgaLLLRiBoMsQKLrcjYGgu4Giy+2CAkFX
+A0WX2wXFIOgGii7trkCEohsDCACBoktEKLpKhISiGwAIECiqSKooukiqKKoxgACBooukKiIo
+SKooujGDECi6iqQqsopEV2MQAkV3kXQZRXdjEAJFl5F0FUWXY3ACRZcFSRdFlyVwJlB0WZB0
+UXRZAmcCRZeRdBVFl2NwAkV3kXQZRXdjcAJFV5FURVaR6GoMDgSKLpKqiKAgqaLoxgwOBIoq
+kiqKLpIqimrM4ECg6BIRiq4SIaHoxgyCBoou7a5AhKIbMzgAAIGiy+2CTWJmBhAAAkWX2wXF
+zCDoBooud2PMDIKuRqDocgtGzMwg6O4Eii5z4Kgi6DIMhqLoagQGjiqCLvPgYOgqji6CLrfi
+6DIj6HI7jq4i6DIkADs=}
+file {R0lGODlhCwANAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAALAA0AAAIyhI9G8Q0AguSH
+AMQdxQgxEyEFQfItICQokYgEBMm3gBCKLRIQJN8CQii2SECQfAug+FgAOw==}
+folder {R0lGODlhEAANAKIAANnZ2YSEhMbGxv//AP///wAAAP///////yH5BAEAAAAALAAAAAAQAA0A
+AANjCIqhiqDLITgyEgi6GoIjIyMYugCBpMsaWBA0giMjIzgyUYBBMjIoIyODEgVBODIygiMj
+E1gQJIMyMjIoI1GAQSMjODIyghMFQSgjI4MyMhJYEDSCIyMjODJRgKHLXAiApcucADs=}
+hourglass {R0lGODlhIAAgAKIAANnZ2YAAAAAAAP8AAP///8DAwICAgP///yH5BAEAAAAALAAAAAAgACAA
+AAPZCLrc/jDKSau9OGcUuqyCoMvNGENVhaMrCLrcjaLLgqDL7WhFVIVVZoKgy+1oRUSFVWaC
+oMvtaEVEhVVmgqDL7WhFRIVVZoKgy+1oVVaCJWaCoMvtgKxISrBMEHS5fZEVSRkKgi63NzIq
+EwRdbndkVCYIutzeyIqqDAVBl9sXWRFJYZkg6HI7ICsiKqwyEwRdbkcrIhKsMhMEXW5HKyIp
+lDITBF1uRysyEiwxEwRdbkcrIyuUEhMEXW5H0WVB0OVujKGqwtEVBF1uRtHlRdDl9odRTlrt
+xRmjBAA7}
+info {R0lGODlhIAAgAKIAANnZ2YSEhMbGxv///wAA/wAAAP///////yH5BAEAAAAALAAAAAAgACAA
+AAP/CLoMGLqKoMvtGCo4uhKBgaDLDRghOLqsghEIuryBgqPLPSiBoMsQOLojhEQkOLpTCLob
+OLqKpIujq4WgC4Gju0i6OLpbCKohOLorhEQkOLorhaAQOLrc3qgCIARHl9sbSQUEji4j6RKO
+Lk9hQODosiKp4ujyFIbi6LIiqeLo8hSG4uiyIqni6PIUhuLosiKp4ujyFIYKji4PkiqOLkth
+BASOLg+SKo4uV2AEhODoMpIqju5KYShA4Ogqku7i6E4FRgAAYOHocvugiohAUC0cXe7GiohA
+0IUSHF3uQamICATdrULB0WUVrIqIQNBlCCwVHF2pwsJQRdDlDYyoKsHRPMLQDQRdbsDQqBmc
+wlBF0OV2jJqZwggEXW5vVDMVgaDL7Y5qKgJBl9sfVUUg6HL7AxSKoMvtr1AEgi5DAgA7}
+italic {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAIrhI+py+1A4hN8
+hIjINBITPlpEZBqJCR8tIjKNxISPFhGZQOITfExdbv9FCgA7}
+new {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAJFhI95FN8IvgXJ
+jyD4ECQ/JAh+kPyICIIdJP+CYAfJvyDYQfIvCHaQ/AuCHST/gmAHyb8g2EHyLwh2kPwLgk3x
+MQg+pu4WADs=}
+open {R0lGODlhEAAQAKIAANnZ2QAAAP//AP///4SEAP///////////yH5BAEAAAAALAAAAAAQABAA
+AANZCLrczigUQZc1EDQgEHSZAwMgIhB0NQIDQkYwdANBNUZwZGQEJxBUQwZlZGRQAkE1RnAE
+Q5dVcCSQdDcAYySQdDcAISSQdDcAASKQdDcAAQBDlwNBl9sfApQAOw==}
+openfold {R0lGODlhEAANAKIAANnZ2YSEhP///8bGxv//AAAAAP///////yH5BAEAAAAALAAAAAAQAA0A
+AANgCIqhiqDLgaIaCLoagkNDIxi6AIFCQ0M4KKpRgCFDQzg0NIQThaHLSxgVKLochRMVMkhD
+Q4M0VBFYEDKEQ0NDOFFRgCE0NEhDQ4MVBRAoNDSEQ0NRWAAYuqyFBQBYurwJADs=}
+overstrike {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI3hI+py80Uh+Aj
+RFhQCP8iMILgWwRGEHyLwAiCbxEYQfCB4iPBhwiMIPgXYREEHyEiguBj6nI7FQA7}
+palette {R0lGODlhEAAQAKIAANnZ2QAAAP//AP////8A/4QAhP8AAAD//yH5BAEAAAAALAAAAAAQABAA
+AANtCLrcjqGBoMsRKCMTgaALMSgDAYMSCKoxgAFBITgSAIAQEhUIARCAEgAQOBAwghMQEwga
+MoIjIxAIEgCAEBEyKBAgg4GgGxAIYTGCgaALcRgQIIGgCwEYICODgaALITgyEoGguxiqCLrc
+/lChBAA7}
+passwd {R0lGODlhIAAgAMQAANnZ2QAAAICAgICAAP///7CwsMDAwMjIAPjIAOjo6Pj4AODg4HBwcMj4
+ANjY2JiYANDQ0MjIyPj4yKCgoMiYAMjImDAwAMjIMJiYmJCQkP//////////////////////
+/yH5BAEAAAAALAAAAAAgACAAAAX/ICCOIhiIIgiII1maZSCMQnCeJyAIQiAIAiAMwxCcJwkk
+EAQRCIUwGMSBDEEAAuJIlgKRJEEgGAMRBIGiDENQlqNAJAsYCEwgEEEgBAHSIEMAAuJIAgKR
+LEsgGEMgCEJgBMqhHENQlgJILMsSCMRABEFgGAESHMcRgIA4kgKxOIsTBAOhKAITKEGDHMhD
+kqIAEqAjisJAgIooBkpwNMcTgIA4jgLhOBAkEAOhKIoSKEGDIMcTkKQICgQEQQIxEIqiBEpw
+IMdxPAEIiCMJCEQUMUQ0EIqiHIfSIM3xBGUpCiABCUQyEMqhHMiBHMjxBCAgjuQoEAKxRANB
+HMqhHM1x/zxDUJajQIACsUTDQBAEIR3IcQRDAALiSIoCYQiEE03gII7HQR3BEICAOJICYRSC
+QDjRNE1CAAzVQR3WE5AkAAqEUQiFQEARBAUAAAzHQR3BEICAOI4CUQhFIBAREwXjUFUHdQRD
+QJJAABbCFAhEJBgBAADAMAwXdQRDAALiCAhEIRQCYRiCEZDjUFFHMAQkIBAFOAmTQBiFUAQg
+II7AUFXUEQwBCQjEJExBkBRCEZCjMIBD9RxDAALiGEzCFBBYIRTBOI7AQB1DMIoCMQkYGAjL
+JEwBCIgjOVDDEJCAQGACJiTTJEwBSY5BEJAiSCCwTAiCZBKmAATEkSzNQBCCYCDBJgELTNMk
+g0AMEgwTAhAQR7I0zYARgvM8TyAIznMMAQA7}
+paste {R0lGODlhEAAQAKIAANnZ2QAAAP//AISEAISEhP///wAAhP///yH5BAEAAAAALAAAAAAQABAA
+AANwCLrcjqGBoKsYqiKrCDSGBkMiJJCGAgCDKBB0gwYDIKYwdJUIAyBokIaGBmloAhBiaAgH
+TdcCEIKGBsmwVM0AIYaGcAxL1coQgoYGySoisMzMAoeGxrB01QJpaMiwMHTLAEPVsHTVEHTR
+dBlBlxswAQA7}
+print {R0lGODlhEAAQAKIAANnZ2QAAAP///4SEhP//AP///////////yH5BAEAAAAALAAAAAAQABAA
+AANZCLrcjqG7CLqBoquBoBuCoSqBoBsouhoIuiEYqrKBoIGiqwEYEIChyxAIEYGgywEYgKHL
+DAgRCLozgwABARgIukSEABEBGLq8gAEQCLobgAEAgKHLgaDLzZgAOw==}
+question {R0lGODlhIAAgAKIAANnZ2YSEhMbGxv///wAAAAAA/////////yH5BAEAAAAALAAAAAAgACAA
+AAP/CLoMGLqKoMvtGCo4uhKBgaDLDRghOLqsghEIuryBgqPLPSiBoMsQOLrcjYSgu4GjO4Kl
+Kzi6Qwi6EDi6I4UyU1VYgqM7hKAagqM7VTg6VYWFoztCCAqBo6tVWDVThVU4ukqBACE4ulqF
+VSNVWIWjq0IYEDi6K4UlU1VYOLpMgRA4uryCpTi6PIShOLq8hVU4uqyEoTi6vIUlOLqshKE4
+uryFhaPLSxgqOLrc3kgoAgJHl0ewSnB0eQhDIQRHl6uwCkeXhTAUIHB0uQqrcHSZAiMAAJBw
+dFcKS3B0lwIjAkGVcHS5GykiAkEXSHB0uQeFIiIQdJcIBUeXVZAoIgJBT5chkFRwdIUICUMV
+QZc3MIKIBEcJQzcQdLkBQ4NmcAhDFUGX2zFoZggjEHS5vRHNUASCLrc7oqEIBF1uf0QUgaDL
+7Q9QKIIut79CEQi6DAkAOw==}
+redo {R0lGODlhEAAQAJEAANnZ2QAAhP///////yH5BAEAAAAALAAAAAAQABAAAAIvhI+py+1vSByC
+jxAYQXDMwsyAggQAQBB8iwgMgg8REQgUwqbYBDsIPqYutz+MgBQAOw==}
+save {R0lGODlhEAAQAJEAANnZ2QAAAISEAP///yH5BAEAAAAALAAAAAAQABAAAAJWhI9pFB8RIIRC
++BYQFqQQvkWEBSmEbyFhQQrhW0hYkEL4FhIWpBC+hYQFSYxvIgFAoXy0AAiSGP8kAIIkxgcI
+CSBEQvEBQgIIkVB8gJAAAhgfj+BjWgEAOw==}
+underline {R0lGODlhEAAQAJEAANnZ2QAAAP///////yH5BAEAAAAALAAAAAAQABAAAAI3hI+py60UBy4I
+vkVcBMG/iIsg+BdxEQT/Ii6C4F/ERRD8i7gIgn8RF0HwkWITfExFin8EH1OXCwA7}
+undo {R0lGODlhEAAQAJEAANnZ2QAAhP///////yH5BAEAAAAALAAAAAAQABAAAAIuhI+py+2vSByC
+HxdxQCHsCIg7oAAAEUHwLTAiKIQPgRSbYMfd3VEIH1OX2x8mUgA7}
+warning {R0lGODlhIAAgAKIAANnZ2YSEAP//AMbGxgAAAISEhP///////yH5BAEAAAAALAAAAAAgACAA
+AAP/CLq8gREIutz+KESGEHS5vVGIiAxSIehy+6JAUaUqBF1uBxQoukOFhaDL7RgoukKFhaDL
+3RgoujqEVQi63IyBortUWAi63IuBostDWIWgy60YIjKERCMiSFUIutyAISKCpCoiOFSFoMsd
+KCpIqiKCQlUIusyBooqkKiIoQ1UIuryBooqkiqJKVQi6rIGii6SKojpUWAi6DIGiG0RIgaJL
+VQi6HCi6MoREg6I7VFgIuhsoukqEhKKrVFgIuhoouhuEgaKrQ1iFoAuBortDOCi6S4WFoBso
+uiyEostDWIWgGii63K6IqgAAIVB0WQaJBkV3h7AKAAJFl4WQiFB0mQoLRyBQdFkJiQhFl4ew
+CgJFl3WQaFB0WQirIFB0ud0RVVWg6HJ7o6GqAgwUXW5fNFRVhQCBpMvti0oVABCwdLndEehi
+6XI7I4AEADs=}
+}
diff --git a/library/demos/ttk_repeater.tcl b/library/demos/ttk_repeater.tcl
new file mode 100644
index 0000000..b515ed4
--- /dev/null
+++ b/library/demos/ttk_repeater.tcl
@@ -0,0 +1,117 @@
+#
+# $Id: ttk_repeater.tcl,v 1.1 2006/10/31 01:42:26 hobbs Exp $
+#
+# Demonstration of custom classes.
+#
+# The Ttk button doesn't have built-in support for autorepeat.
+# Instead of adding -repeatdelay and -repeatinterval options,
+# and all the extra binding scripts required to deal with them,
+# we create a custom widget class for autorepeating buttons.
+#
+# Usage:
+# ttk::button .b -class Repeater [... other options ...]
+#
+# TODO:
+# Use system settings for repeat interval and initial delay.
+#
+# Notes:
+# Repeater buttons work more like scrollbar arrows than
+# Tk repeating buttons: they fire once immediately when
+# first pressed, and $State(delay) specifies the initial
+# interval before the button starts autorepeating.
+#
+
+namespace eval ttk::Repeater {
+ variable State
+ set State(timer) {} ;# [after] id of repeat script
+ set State(interval) 100 ;# interval between repetitions
+ set State(delay) 300 ;# delay after initial invocation
+}
+
+### Class bindings.
+#
+
+bind Repeater <Enter> { %W state active }
+bind Repeater <Leave> { %W state !active }
+
+bind Repeater <Key-space> { ttk::Repeater::Activate %W }
+bind Repeater <<Invoke>> { ttk::Repeater::Activate %W }
+
+bind Repeater <ButtonPress-1> { ttk::Repeater::Press %W }
+bind Repeater <ButtonRelease-1> { ttk::Repeater::Release %W }
+bind Repeater <B1-Leave> { ttk::Repeater::Pause %W }
+bind Repeater <B1-Enter> { ttk::Repeater::Resume %W } ;# @@@ see below
+
+# @@@ Workaround for metacity-induced bug:
+bind Repeater <B1-Enter> \
+ { if {"%d" ne "NotifyUngrab"} { ttk::Repeater::Resume %W } }
+
+### Binding procedures.
+#
+
+## Activate -- Keyboard activation binding.
+# Simulate clicking the button, and invoke the command once.
+#
+proc ttk::Repeater::Activate {w} {
+ $w instate disabled { return }
+ set oldState [$w state pressed]
+ update idletasks; after 100
+ $w state $oldState
+ after idle [list $w invoke]
+}
+
+## Press -- ButtonPress-1 binding.
+# Invoke the command once and start autorepeating after
+# $State(delay) milliseconds.
+#
+proc ttk::Repeater::Press {w} {
+ variable State
+ $w instate disabled { return }
+ $w state pressed
+ $w invoke
+ after cancel $State(timer)
+ set State(timer) [after $State(delay) [list ttk::Repeater::Repeat $w]]
+}
+
+## Release -- ButtonRelease binding.
+# Stop repeating.
+#
+proc ttk::Repeater::Release {w} {
+ variable State
+ $w state !pressed
+ after cancel $State(timer)
+}
+
+## Pause -- B1-Leave binding
+# Temporarily suspend autorepeat.
+#
+proc ttk::Repeater::Pause {w} {
+ variable State
+ $w state !pressed
+ after cancel $State(timer)
+}
+
+## Resume -- B1-Enter binding
+# Resume autorepeat.
+#
+proc ttk::Repeater::Resume {w} {
+ variable State
+ $w instate disabled { return }
+ $w state pressed
+ $w invoke
+ after cancel $State(timer)
+ set State(timer) [after $State(interval) [list ttk::Repeater::Repeat $w]]
+}
+
+## Repeat -- Timer script
+# Invoke the command and reschedule another repetition
+# after $State(interval) milliseconds.
+#
+proc ttk::Repeater::Repeat {w} {
+ variable State
+ $w instate disabled { return }
+ $w invoke
+ set State(timer) [after $State(interval) [list ttk::Repeater::Repeat $w]]
+}
+
+#*EOF*