1# 2# $Id: repeater.tcl 31689 2011-05-22 09:26:02Z nobu $ 3# 4# Demonstration of custom classes. 5# 6# The Tile button doesn't have built-in support for autorepeat. 7# Instead of adding -repeatdelay and -repeatinterval options, 8# and all the extra binding scripts required to deal with them, 9# we create a custom widget class for autorepeating buttons. 10# 11# Usage: 12# ttk::button .b -class Repeater [... other options ...] 13# 14# TODO: 15# Use system settings for repeat interval and initial delay. 16# 17# Notes: 18# Repeater buttons work more like scrollbar arrows than 19# Tk repeating buttons: they fire once immediately when 20# first pressed, and $State(delay) specifies the initial 21# interval before the button starts autorepeating. 22# 23 24namespace eval tile::Repeater { 25 variable State 26 set State(timer) {} ;# [after] id of repeat script 27 set State(interval) 100 ;# interval between repetitions 28 set State(delay) 300 ;# delay after initial invocation 29} 30 31### Class bindings. 32# 33 34bind Repeater <Enter> { %W state active } 35bind Repeater <Leave> { %W state !active } 36 37bind Repeater <Key-space> { tile::Repeater::Activate %W } 38bind Repeater <<Invoke>> { tile::Repeater::Activate %W } 39 40bind Repeater <ButtonPress-1> { tile::Repeater::Press %W } 41bind Repeater <ButtonRelease-1> { tile::Repeater::Release %W } 42bind Repeater <B1-Leave> { tile::Repeater::Pause %W } 43bind Repeater <B1-Enter> { tile::Repeater::Resume %W } ;# @@@ see below 44 45# @@@ Workaround for metacity-induced bug: 46bind Repeater <B1-Enter> \ 47 { if {"%d" ne "NotifyUngrab"} { tile::Repeater::Resume %W } } 48 49### Binding procedures. 50# 51 52## Activate -- Keyboard activation binding. 53# Simulate clicking the button, and invoke the command once. 54# 55proc tile::Repeater::Activate {w} { 56 $w instate disabled { return } 57 set oldState [$w state pressed] 58 update idletasks; after 100 59 $w state $oldState 60 after idle [list $w invoke] 61} 62 63## Press -- ButtonPress-1 binding. 64# Invoke the command once and start autorepeating after 65# $State(delay) milliseconds. 66# 67proc tile::Repeater::Press {w} { 68 variable State 69 $w instate disabled { return } 70 $w state pressed 71 $w invoke 72 after cancel $State(timer) 73 set State(timer) [after $State(delay) [list tile::Repeater::Repeat $w]] 74} 75 76## Release -- ButtonRelease binding. 77# Stop repeating. 78# 79proc tile::Repeater::Release {w} { 80 variable State 81 $w state !pressed 82 after cancel $State(timer) 83} 84 85## Pause -- B1-Leave binding 86# Temporarily suspend autorepeat. 87# 88proc tile::Repeater::Pause {w} { 89 variable State 90 $w state !pressed 91 after cancel $State(timer) 92} 93 94## Resume -- B1-Enter binding 95# Resume autorepeat. 96# 97proc tile::Repeater::Resume {w} { 98 variable State 99 $w instate disabled { return } 100 $w state pressed 101 $w invoke 102 after cancel $State(timer) 103 set State(timer) [after $State(interval) [list tile::Repeater::Repeat $w]] 104} 105 106## Repeat -- Timer script 107# Invoke the command and reschedule another repetition 108# after $State(interval) milliseconds. 109# 110proc tile::Repeater::Repeat {w} { 111 variable State 112 $w instate disabled { return } 113 $w invoke 114 set State(timer) [after $State(interval) [list tile::Repeater::Repeat $w]] 115} 116 117#*EOF* 118