PageRenderTime 62ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/tkabber-0.11.1/ifacetk/buttonbar.tcl

#
TCL | 610 lines | 409 code | 109 blank | 92 comment | 76 complexity | ef82e69be8ccac605c7a15ddb04ae3f5 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause
  1. # ----------------------------------------------------------------------------
  2. # ButtonBar.tcl
  3. # ----------------------------------------------------------------------------
  4. # Index of commands:
  5. # - ButtonBar::create
  6. # - ButtonBar::configure
  7. # - ButtonBar::cget
  8. # - ButtonBar::insert
  9. # - ButtonBar::delete
  10. # - ButtonBar::move
  11. # - ButtonBar::itemconfigure
  12. # - ButtonBar::itemcget
  13. # - ButtonBar::setfocus
  14. # - ButtonBar::index
  15. # ----------------------------------------------------------------------------
  16. namespace eval ButtonBar {
  17. Widget::define ButtonBar ButtonBar Button
  18. Widget::declare ButtonBar {
  19. {-background TkResource "" 0 frame}
  20. {-orient Enum horizontal 0 {horizontal vertical}}
  21. {-minwidth Int 0 0 "%d >= 0"}
  22. {-maxwidth Int 200 0 "%d >= 0"}
  23. {-padx TkResource "" 0 button}
  24. {-pady TkResource "" 0 button}
  25. {-command String "" 0}
  26. {-bg Synonym -background}
  27. {-pages String "" 0}
  28. }
  29. Widget::addmap ButtonBar "" :cmd {-background {}}
  30. bind ButtonBar <Destroy> [list [namespace current]::_destroy %W]
  31. }
  32. # ----------------------------------------------------------------------------
  33. # Command ButtonBar::create
  34. # ----------------------------------------------------------------------------
  35. proc ButtonBar::create {path args} {
  36. Widget::init ButtonBar $path $args
  37. variable $path
  38. upvar 0 $path data
  39. eval [list frame $path] [Widget::subcget $path :cmd] \
  40. [list -class ButtonBar -takefocus 0 -highlightthickness 0]
  41. # For 8.4+ we don't want to inherit the padding
  42. catch {$path configure -padx 0 -pady 0}
  43. frame $path.spacer -width [winfo screenwidth $path]
  44. bind $path <Configure> [list [namespace current]::_configure %W]
  45. set data(buttons) [list]
  46. set data(active) ""
  47. set data(bindtabs) [list]
  48. return [Widget::create ButtonBar $path]
  49. }
  50. # ----------------------------------------------------------------------------
  51. # Command ButtonBar::configure
  52. # ----------------------------------------------------------------------------
  53. proc ButtonBar::configure {path args} {
  54. variable $path
  55. upvar 0 $path data
  56. set res [Widget::configure $path $args]
  57. if {[Widget::hasChanged $path -orient val] || \
  58. [Widget::hasChanged $path -minwidth val] || \
  59. [Widget::hasChanged $path -maxwidth val]} {
  60. _redraw $path
  61. }
  62. return $res
  63. }
  64. # ----------------------------------------------------------------------------
  65. # Command ButtonBar::cget
  66. # ----------------------------------------------------------------------------
  67. proc ButtonBar::cget {path option} {
  68. return [Widget::cget $path $option]
  69. }
  70. # ----------------------------------------------------------------------------
  71. # Command ButtonBar::_option
  72. # ----------------------------------------------------------------------------
  73. proc ButtonBar::_itemoption {path name option} {
  74. return [lindex [Button::configure [_but $path $name] $option] 4]
  75. }
  76. # ----------------------------------------------------------------------------
  77. # Command ButtonBar::insert
  78. # ----------------------------------------------------------------------------
  79. proc ButtonBar::insert {path idx name args} {
  80. variable $path
  81. upvar 0 $path data
  82. set but [_but $path $name]
  83. set data(buttons) [linsert $data(buttons) $idx $name]
  84. set newargs {}
  85. foreach {key val} $args {
  86. switch -- $key {
  87. -raisecmd {
  88. set data(raisecmd,$name) $val
  89. }
  90. default { lappend newargs $key $val }
  91. }
  92. }
  93. eval [list Button::create $but \
  94. -padx [Widget::getoption $path -padx] \
  95. -pady [Widget::getoption $path -pady] \
  96. -anchor w \
  97. -command [list [namespace current]::activate $path $name]] \
  98. $newargs
  99. _calc_text $path $name
  100. bind $but <Configure> [list [namespace current]::_itemconfigure \
  101. [_escape $path] [_escape $name]]
  102. foreach {event script} $data(bindtabs) {
  103. bind $but $event [linsert $script end [_escape $name]]
  104. }
  105. DragSite::register $but \
  106. -draginitcmd [list [namespace current]::_draginitcmd $path $name]
  107. DropSite::register $but \
  108. -dropcmd [list [namespace current]::_dropcmd $path $name] \
  109. -droptypes [list ButtonBar:$path]
  110. _redraw $path
  111. if {![string equal [Widget::getoption $path -pages] ""]} {
  112. set res [[Widget::getoption $path -pages] add $name]
  113. } else {
  114. set res $but
  115. }
  116. if {[llength $data(buttons)] == 1} {
  117. activate $path $name -nocmd
  118. }
  119. return $res
  120. }
  121. proc ButtonBar::_draginitcmd {path name target x y top} {
  122. activate $path $name
  123. return [list ButtonBar:$path {move} $name]
  124. }
  125. proc ButtonBar::_dropcmd {path tname target source X Y op type name} {
  126. move $path $name [index $path $tname]
  127. }
  128. # ----------------------------------------------------------------------------
  129. # Command ButtonBar::move
  130. # ----------------------------------------------------------------------------
  131. proc ButtonBar::move {path name idx} {
  132. variable $path
  133. upvar 0 $path data
  134. set i [lsearch -exact $data(buttons) $name]
  135. if {$i >= 0} {
  136. set data(buttons) [linsert [lreplace $data(buttons) $i $i] $idx $name]
  137. _redraw $path
  138. }
  139. }
  140. # ----------------------------------------------------------------------------
  141. # Command ButtonBar::delete
  142. # ----------------------------------------------------------------------------
  143. proc ButtonBar::delete {path name {destroyframe 1}} {
  144. variable $path
  145. upvar 0 $path data
  146. set i [lsearch -exact $data(buttons) $name]
  147. if {$i >= 0} {
  148. set data(buttons) [lreplace $data(buttons) $i $i]
  149. destroy [_but $path $name]
  150. if {![string equal [Widget::getoption $path -pages] ""]} {
  151. [Widget::getoption $path -pages] delete $name
  152. }
  153. if {[llength $data(buttons)] == 0} {
  154. set data(active) ""
  155. }
  156. catch {unset data(raisecmd,$name)}
  157. catch {unset data(text,$name)}
  158. catch {unset data(width,$name)}
  159. catch {unset data(height,$name)}
  160. _redraw $path
  161. }
  162. }
  163. # ----------------------------------------------------------------------------
  164. # Command ButtonBar::activate
  165. # ----------------------------------------------------------------------------
  166. proc ButtonBar::activate {path name {nocmd ""}} {
  167. variable $path
  168. upvar 0 $path data
  169. set active ""
  170. foreach n $data(buttons) {
  171. set but [_but $path $n]
  172. if {[string equal $n $name]} {
  173. Button::configure $but -relief sunken -state active
  174. set active $n
  175. } else {
  176. Button::configure $but -relief raised -state normal
  177. }
  178. }
  179. if {![string equal [Widget::getoption $path -pages] ""]} {
  180. [Widget::getoption $path -pages] raise $active
  181. }
  182. if {$nocmd != "-nocmd" && $active != $data(active)} {
  183. if {[info exists data(raisecmd,$name)]} {
  184. uplevel #0 $data(raisecmd,$name)
  185. }
  186. set cmd [Widget::getoption $path -command]
  187. if {$cmd != ""} {
  188. uplevel #0 $cmd [list $active]
  189. }
  190. }
  191. set data(active) $active
  192. }
  193. # ----------------------------------------------------------------------------
  194. # Command ButtonBar::itemconfigure
  195. # ----------------------------------------------------------------------------
  196. proc ButtonBar::itemconfigure {path name args} {
  197. variable $path
  198. upvar 0 $path data
  199. set but [_but $path $name]
  200. set res [eval [list Button::configure $but] $args]
  201. if {[llength $args] == 1} {
  202. switch -- [lindex $args 0] {
  203. -text {
  204. set res $data(text,$name)
  205. }
  206. }
  207. } else {
  208. set tf 0
  209. foreach {key val} $args {
  210. switch -- $key {
  211. -text -
  212. -font {
  213. set tf 1
  214. }
  215. }
  216. }
  217. if {$tf} {
  218. _calc_text $path $name
  219. _reconfigure_text $path $name
  220. }
  221. }
  222. return $res
  223. }
  224. # ----------------------------------------------------------------------------
  225. # Command ButtonBar::itemcget
  226. # ----------------------------------------------------------------------------
  227. proc ButtonBar::itemcget {path name option} {
  228. variable $path
  229. upvar 0 $path data
  230. set res [Button::cget [_but $path $name] $option]
  231. switch -- $option {
  232. -text {
  233. set res $data(text,$name)
  234. }
  235. }
  236. return $res
  237. }
  238. # ----------------------------------------------------------------------------
  239. # Command ButtonBar::setfocus
  240. # ----------------------------------------------------------------------------
  241. proc ButtonBar::setfocus {path name} {
  242. set but [_but $path $name]
  243. if { [winfo exists $but] } {
  244. focus $but
  245. }
  246. }
  247. # ----------------------------------------------------------------------------
  248. # Command ButtonBar::index
  249. # ----------------------------------------------------------------------------
  250. proc ButtonBar::index {path name} {
  251. variable $path
  252. upvar 0 $path data
  253. return [lsearch -exact $data(buttons) $name]
  254. }
  255. # ----------------------------------------------------------------------------
  256. # Command ButtonBar::_configure
  257. # ----------------------------------------------------------------------------
  258. proc ButtonBar::_configure {path} {
  259. variable $path
  260. upvar 0 $path data
  261. set w [winfo width $path]
  262. set h [winfo height $path]
  263. if {![info exists data(width)] || $data(width) != $w || \
  264. ![info exists data(height)] || $data(height) != $h} {
  265. set data(width) $w
  266. set data(height) $h
  267. _redraw $path
  268. }
  269. }
  270. # ----------------------------------------------------------------------------
  271. # Command ButtonBar::_redraw
  272. # ----------------------------------------------------------------------------
  273. proc ButtonBar::_redraw {path} {
  274. variable $path
  275. upvar 0 $path data
  276. array unset data configured,*
  277. $path:cmd configure -width 0
  278. grid forget $path.spacer
  279. set cols [lindex [grid size $path] 0]
  280. set rows [lindex [grid size $path] 1]
  281. for {set c 0} {$c < $cols} {incr c} {
  282. grid columnconfigure $path $c -weight 0 -minsize 0
  283. catch {grid columnconfigure $path $c -uniform {}}
  284. }
  285. for {set r 0} {$r < $rows} {incr r} {
  286. grid rowconfigure $path $r -weight 0 -minsize 0
  287. catch {grid rowconfigure $path $r -uniform {}}
  288. }
  289. set num [llength $data(buttons)]
  290. if {$num == 0} return
  291. # Change buttons stacking order
  292. foreach name $data(buttons) {
  293. ::raise [_but $path $name]
  294. }
  295. set min [Widget::getoption $path -minwidth]
  296. set max [Widget::getoption $path -maxwidth]
  297. if {$min > $max} {
  298. set max $min
  299. }
  300. if {[string equal [Widget::getoption $path -orient] "horizontal"]} {
  301. set w [winfo width $path]
  302. if {$min == 0} {
  303. set cols $num
  304. } else {
  305. set cols [expr {int($w / $min)}]
  306. if {$cols > $num} {
  307. set cols $num
  308. }
  309. }
  310. if {[expr {$max * $cols}] < $w} {
  311. set weight 2
  312. set minsize $max
  313. grid $path.spacer -column $cols -row 0
  314. grid columnconfigure $path $cols -weight 1 -minsize 0
  315. } else {
  316. set weight 1
  317. set minsize $min
  318. }
  319. set c 0
  320. set r 0
  321. foreach name $data(buttons) {
  322. grid [_but $path $name] -column $c -row $r -sticky nsew
  323. grid columnconfigure $path $c -weight $weight -minsize $minsize
  324. catch {grid columnconfigure $path $c -uniform 1}
  325. incr c
  326. if {$c >= $cols} {
  327. set c 0
  328. incr r
  329. }
  330. }
  331. } else {
  332. set h [winfo height $path]
  333. set c 0
  334. set r 0
  335. set th 0
  336. set num 0
  337. foreach name $data(buttons) {
  338. _reconfigure_text $path $name
  339. }
  340. foreach name $data(buttons) {
  341. set but [_but $path $name]
  342. if {[info exists data(height,$name)]} {
  343. incr th $data(height,$name)
  344. } else {
  345. incr th [winfo reqheight $but]
  346. }
  347. if {($c > 0 && $r >= $num) || ($c == 0 && $th > $h)} {
  348. set r 0
  349. incr c
  350. } elseif {$c == 0} {
  351. incr num
  352. }
  353. grid $but -column $c -row $r -sticky nsew
  354. grid rowconfigure $path $r -weight 0 -minsize 0
  355. grid columnconfigure $path $c -weight 0 -minsize $max
  356. incr r
  357. }
  358. grid rowconfigure $path $num -weight 10000000 -minsize 0
  359. }
  360. }
  361. # ----------------------------------------------------------------------------
  362. # Command ButtonBar::_destroy
  363. # ----------------------------------------------------------------------------
  364. proc ButtonBar::_destroy {path} {
  365. variable $path
  366. upvar 0 $path data
  367. Widget::destroy $path
  368. unset data
  369. }
  370. # ----------------------------------------------------------------------------
  371. # Command ButtonBar::_but
  372. # ----------------------------------------------------------------------------
  373. proc ButtonBar::_but {path name} {
  374. return $path.b:$name
  375. }
  376. # ----------------------------------------------------------------------------
  377. # Command ButtonBar::pages
  378. # ----------------------------------------------------------------------------
  379. proc ButtonBar::pages {path {first ""} {last ""}} {
  380. variable $path
  381. upvar 0 $path data
  382. if {[string equal $first ""]} {
  383. return $data(buttons)
  384. } elseif {[string equal $last ""]} {
  385. return [lindex $data(buttons) $first]
  386. } else {
  387. return [lrange $data(buttons) $first $last]
  388. }
  389. }
  390. # ----------------------------------------------------------------------------
  391. # Command ButtonBar::raise
  392. # ----------------------------------------------------------------------------
  393. proc ButtonBar::raise {path {name ""}} {
  394. variable $path
  395. upvar 0 $path data
  396. if {[string equal $name ""]} {
  397. return $data(active)
  398. } else {
  399. activate $path $name
  400. }
  401. }
  402. # ----------------------------------------------------------------------------
  403. # Command ButtonBar::getframe
  404. # ----------------------------------------------------------------------------
  405. proc ButtonBar::getframe {path name} {
  406. if {![string equal [Widget::getoption $path -pages] ""]} {
  407. return [[Widget::getoption $path -pages] getframe $name]
  408. } else {
  409. return ""
  410. }
  411. }
  412. # ----------------------------------------------------------------------------
  413. # Command ButtonBar::bindtabs
  414. # ----------------------------------------------------------------------------
  415. proc ButtonBar::bindtabs {path event script} {
  416. variable $path
  417. upvar 0 $path data
  418. lappend data(bindtabs) $event $script
  419. foreach name $data(buttons) {
  420. bind [_but $path $name] $event [linsert $script end [_escape $name]]
  421. }
  422. }
  423. # ----------------------------------------------------------------------------
  424. # Command ButtonBar::see
  425. # ----------------------------------------------------------------------------
  426. proc ButtonBar::see {path name} {
  427. return ""
  428. }
  429. # ----------------------------------------------------------------------------
  430. # Command ButtonBar::_itemconfigure
  431. # ----------------------------------------------------------------------------
  432. proc ButtonBar::_itemconfigure {path name} {
  433. variable $path
  434. upvar 0 $path data
  435. if {[info exists data(configured,$name)]} return
  436. set data(configured,$name) 1
  437. set but [_but $path $name]
  438. set w [winfo width $but]
  439. if {![info exists data(text,$name)] ||
  440. ![info exists data(width,$name)] || $data(width,$name) != $w} {
  441. set data(width,$name) $w
  442. _reconfigure_text $path $name
  443. }
  444. set data(height,$name) [winfo height $but]
  445. }
  446. # ----------------------------------------------------------------------------
  447. # Command ButtonBar::_calc_text
  448. # ----------------------------------------------------------------------------
  449. proc ButtonBar::_calc_text {path name} {
  450. variable $path
  451. upvar 0 $path data
  452. set text [_itemoption $path $name -text]
  453. set font [_itemoption $path $name -font]
  454. set data(text,$name) [list $text [font measure $font $text]]
  455. set len [string length $text]
  456. for {set ind 0} {$ind < $len} {incr ind} {
  457. lappend data(text,$name) \
  458. [font measure $font [string range $text 0 $ind]\u2026]
  459. }
  460. }
  461. # ----------------------------------------------------------------------------
  462. # Command ButtonBar::_reconfigure_text
  463. # ----------------------------------------------------------------------------
  464. proc ButtonBar::_reconfigure_text {path name} {
  465. variable $path
  466. upvar 0 $path data
  467. if {![info exists data(text,$name)]} return
  468. set but [_but $path $name]
  469. set padx [_itemoption $path $name -padx]
  470. set bd [_itemoption $path $name -bd]
  471. set hl [_itemoption $path $name -highlightthickness]
  472. set w [winfo width $but]
  473. set min [Widget::getoption $path -minwidth]
  474. set max [Widget::getoption $path -maxwidth]
  475. if {$min > $max} {
  476. set max $min
  477. }
  478. set tw [expr {$w - 2*($padx + $bd + $hl + 1)}]
  479. set mw [expr {$max - 2*($padx + $bd + $hl + 1)}]
  480. set text [lindex $data(text,$name) 0]
  481. set textw [lindex $data(text,$name) 1]
  482. Button::configure $but -text $text -helptext ""
  483. if {$textw <= $tw && $textw <= $mw} {
  484. return
  485. }
  486. set i -1
  487. foreach textw [lrange $data(text,$name) 2 end] {
  488. if {$textw > $tw || $textw > $mw} {
  489. Button::configure $but -text [string range $text 0 $i]\u2026 \
  490. -helptext $text
  491. return
  492. }
  493. incr i
  494. }
  495. }
  496. # ----------------------------------------------------------------------------
  497. # Command ButtonBar::_escape
  498. # ----------------------------------------------------------------------------
  499. proc ButtonBar::_escape {str} {
  500. string map {% %%} $str
  501. }