button.tcl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. # ------------------------------------------------------------------------------
  2. # button.tcl
  3. # This file is part of Unifix BWidget Toolkit
  4. # ------------------------------------------------------------------------------
  5. # Index of commands:
  6. # Public commands
  7. # - Button::create
  8. # - Button::configure
  9. # - Button::cget
  10. # - Button::invoke
  11. # Private commands (event bindings)
  12. # - Button::_destroy
  13. # - Button::_enter
  14. # - Button::_leave
  15. # - Button::_press
  16. # - Button::_release
  17. # - Button::_repeat
  18. # ------------------------------------------------------------------------------
  19. namespace eval Button {
  20. Widget::tkinclude Button button :cmd \
  21. remove {-command -relief -text -textvariable -underline}
  22. Widget::declare Button {
  23. {-name String "" 0}
  24. {-text String "" 0}
  25. {-textvariable String "" 0}
  26. {-underline Int -1 0 {=-1}}
  27. {-armcommand String "" 0}
  28. {-disarmcommand String "" 0}
  29. {-command String "" 0}
  30. {-repeatdelay Int 0 0 {=0 ""}}
  31. {-repeatinterval Int 0 0 {=0 ""}}
  32. {-relief Enum raised 0 {raised sunken flat ridge solid groove link}}
  33. }
  34. DynamicHelp::include Button balloon
  35. Widget::syncoptions Button "" :cmd {-text {} -underline {}}
  36. variable _current ""
  37. variable _pressed ""
  38. bind BwButton <Enter> {Button::_enter %W}
  39. bind BwButton <Leave> {Button::_leave %W}
  40. bind BwButton <ButtonPress-1> {Button::_press %W}
  41. bind BwButton <ButtonRelease-1> {Button::_release %W}
  42. bind BwButton <Key-space> {Button::invoke %W; break}
  43. bind BwButton <Return> {Button::invoke %W; break}
  44. bind BwButton <Destroy> {Widget::destroy %W; rename %W {}}
  45. proc ::Button { path args } { return [eval Button::create $path $args] }
  46. proc use {} {}
  47. }
  48. # ------------------------------------------------------------------------------
  49. # Command Button::create
  50. # ------------------------------------------------------------------------------
  51. proc Button::create { path args } {
  52. Widget::init Button $path $args
  53. set relief [Widget::getoption $path -relief]
  54. if { ![string compare $relief "link"] } {
  55. set relief "flat"
  56. }
  57. set var [Widget::getoption $path -textvariable]
  58. if { ![string length $var] } {
  59. set desc [BWidget::getname [Widget::getoption $path -name]]
  60. if { [llength $desc] } {
  61. set text [lindex $desc 0]
  62. set under [lindex $desc 1]
  63. Widget::setoption $path -text $text
  64. Widget::setoption $path -underline $under
  65. } else {
  66. set text [Widget::getoption $path -text]
  67. set under [Widget::getoption $path -underline]
  68. }
  69. } else {
  70. set under -1
  71. set text ""
  72. Widget::setoption $path -underline $under
  73. }
  74. eval button $path [Widget::subcget $path :cmd] \
  75. [list -relief $relief -text $text -underline $under -textvariable $var]
  76. bindtags $path [list $path BwButton [winfo toplevel $path] all]
  77. set accel [string tolower [string index $text $under]]
  78. if { $accel != "" } {
  79. bind [winfo toplevel $path] <Alt-$accel> "Button::invoke $path"
  80. }
  81. DynamicHelp::sethelp $path $path 1
  82. rename $path ::$path:cmd
  83. proc ::$path { cmd args } "return \[eval Button::\$cmd $path \$args\]"
  84. return $path
  85. }
  86. # ------------------------------------------------------------------------------
  87. # Command Button::configure
  88. # ------------------------------------------------------------------------------
  89. proc Button::configure { path args } {
  90. set oldunder [$path:cmd cget -underline]
  91. if { $oldunder != -1 } {
  92. set oldaccel [string tolower [string index [$path:cmd cget -text] $oldunder]]
  93. } else {
  94. set oldaccel ""
  95. }
  96. set res [Widget::configure $path $args]
  97. set rc [Widget::hasChanged $path -relief relief]
  98. set sc [Widget::hasChanged $path -state state]
  99. if { $rc || $sc } {
  100. if { ![string compare $relief "link"] } {
  101. if { ![string compare $state "active"] } {
  102. set relief "raised"
  103. } else {
  104. set relief "flat"
  105. }
  106. }
  107. $path:cmd configure -relief $relief -state $state
  108. }
  109. set cv [Widget::hasChanged $path -textvariable var]
  110. set cn [Widget::hasChanged $path -name name]
  111. set ct [Widget::hasChanged $path -text text]
  112. set cu [Widget::hasChanged $path -underline under]
  113. if { $cv || $cn || $ct || $cu } {
  114. if { ![string length $var] } {
  115. set desc [BWidget::getname $name]
  116. if { [llength $desc] } {
  117. set text [lindex $desc 0]
  118. set under [lindex $desc 1]
  119. }
  120. } else {
  121. set under -1
  122. set text ""
  123. }
  124. set top [winfo toplevel $path]
  125. bind $top <Alt-$oldaccel> {}
  126. set accel [string tolower [string index $text $under]]
  127. if { $accel != "" } {
  128. bind $top <Alt-$accel> "Button::invoke $path"
  129. }
  130. $path:cmd configure -text $text -underline $under -textvariable $var
  131. }
  132. DynamicHelp::sethelp $path $path
  133. return $res
  134. }
  135. # ------------------------------------------------------------------------------
  136. # Command Button::cget
  137. # ------------------------------------------------------------------------------
  138. proc Button::cget { path option } {
  139. return [Widget::cget $path $option]
  140. }
  141. # ------------------------------------------------------------------------------
  142. # Command Button::invoke
  143. # ------------------------------------------------------------------------------
  144. proc Button::invoke { path } {
  145. if { [string compare [$path:cmd cget -state] "disabled"] } {
  146. $path:cmd configure -state active -relief sunken
  147. update idletasks
  148. if { [set cmd [Widget::getoption $path -armcommand]] != "" } {
  149. uplevel \#0 $cmd
  150. }
  151. after 100
  152. set relief [Widget::getoption $path -relief]
  153. if { ![string compare $relief "link"] } {
  154. set relief flat
  155. }
  156. $path:cmd configure \
  157. -state [Widget::getoption $path -state] \
  158. -relief $relief
  159. if { [set cmd [Widget::getoption $path -disarmcommand]] != "" } {
  160. uplevel \#0 $cmd
  161. }
  162. if { [set cmd [Widget::getoption $path -command]] != "" } {
  163. uplevel \#0 $cmd
  164. }
  165. }
  166. }
  167. # ------------------------------------------------------------------------------
  168. # Command Button::_enter
  169. # ------------------------------------------------------------------------------
  170. proc Button::_enter { path } {
  171. variable _current
  172. variable _pressed
  173. set _current $path
  174. if { [string compare [$path:cmd cget -state] "disabled"] } {
  175. $path:cmd configure -state active
  176. if { $_pressed == $path } {
  177. $path:cmd configure -relief sunken
  178. } elseif { ![string compare [Widget::getoption $path -relief] "link"] } {
  179. $path:cmd configure -relief raised
  180. }
  181. }
  182. }
  183. # ------------------------------------------------------------------------------
  184. # Command Button::_leave
  185. # ------------------------------------------------------------------------------
  186. proc Button::_leave { path } {
  187. variable _current
  188. variable _pressed
  189. set _current ""
  190. if { [string compare [$path:cmd cget -state] "disabled"] } {
  191. $path:cmd configure -state [Widget::getoption $path -state]
  192. set relief [Widget::getoption $path -relief]
  193. if { $_pressed == $path } {
  194. if { ![string compare $relief "link"] } {
  195. set relief raised
  196. }
  197. $path:cmd configure -relief $relief
  198. } elseif { ![string compare $relief "link"] } {
  199. $path:cmd configure -relief flat
  200. }
  201. }
  202. }
  203. # ------------------------------------------------------------------------------
  204. # Command Button::_press
  205. # ------------------------------------------------------------------------------
  206. proc Button::_press { path } {
  207. variable _pressed
  208. if { [string compare [$path:cmd cget -state] "disabled"] } {
  209. set _pressed $path
  210. $path:cmd configure -relief sunken
  211. if { [set cmd [Widget::getoption $path -armcommand]] != "" } {
  212. uplevel \#0 $cmd
  213. if { [set delay [Widget::getoption $path -repeatdelay]] > 0 ||
  214. [set delay [Widget::getoption $path -repeatinterval]] > 0 } {
  215. after $delay "Button::_repeat $path"
  216. }
  217. }
  218. }
  219. }
  220. # ------------------------------------------------------------------------------
  221. # Command Button::_release
  222. # ------------------------------------------------------------------------------
  223. proc Button::_release { path } {
  224. variable _current
  225. variable _pressed
  226. if { $_pressed == $path } {
  227. set _pressed ""
  228. set relief [Widget::getoption $path -relief]
  229. if { ![string compare $relief "link"] } {
  230. set relief raised
  231. }
  232. $path:cmd configure -relief $relief
  233. if { [set cmd [Widget::getoption $path -disarmcommand]] != "" } {
  234. uplevel \#0 $cmd
  235. }
  236. if { $_current == $path &&
  237. [string compare [$path:cmd cget -state] "disabled"] &&
  238. [set cmd [Widget::getoption $path -command]] != "" } {
  239. uplevel \#0 $cmd
  240. }
  241. }
  242. }
  243. # ------------------------------------------------------------------------------
  244. # Command Button::_repeat
  245. # ------------------------------------------------------------------------------
  246. proc Button::_repeat { path } {
  247. variable _current
  248. variable _pressed
  249. if { $_current == $path && $_pressed == $path &&
  250. [string compare [$path:cmd cget -state] "disabled"] &&
  251. [set cmd [Widget::getoption $path -armcommand]] != "" } {
  252. uplevel \#0 $cmd
  253. }
  254. if { $_pressed == $path &&
  255. ([set delay [Widget::getoption $path -repeatinterval]] > 0 ||
  256. [set delay [Widget::getoption $path -repeatdelay]] > 0) } {
  257. after $delay "Button::_repeat $path"
  258. }
  259. }