utils.tcl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. # ------------------------------------------------------------------------------
  2. # utils.tcl
  3. # This file is part of Unifix BWidget Toolkit
  4. # $Id$
  5. # ------------------------------------------------------------------------------
  6. # Index of commands:
  7. # - GlobalVar::exists
  8. # - GlobalVar::setvarvar
  9. # - GlobalVar::getvarvar
  10. # - BWidget::assert
  11. # - BWidget::clonename
  12. # - BWidget::get3dcolor
  13. # - BWidget::XLFDfont
  14. # - BWidget::place
  15. # - BWidget::grab
  16. # - BWidget::focus
  17. # ------------------------------------------------------------------------------
  18. namespace eval GlobalVar {
  19. proc use {} {}
  20. }
  21. namespace eval BWidget {
  22. variable _top
  23. variable _gstack {}
  24. variable _fstack {}
  25. proc use {} {}
  26. }
  27. # ------------------------------------------------------------------------------
  28. # Command GlobalVar::exists
  29. # ------------------------------------------------------------------------------
  30. proc GlobalVar::exists { varName } {
  31. return [uplevel \#0 [list info exists $varName]]
  32. }
  33. # ------------------------------------------------------------------------------
  34. # Command GlobalVar::setvar
  35. # ------------------------------------------------------------------------------
  36. proc GlobalVar::setvar { varName value } {
  37. return [uplevel \#0 [list set $varName $value]]
  38. }
  39. # ------------------------------------------------------------------------------
  40. # Command GlobalVar::getvar
  41. # ------------------------------------------------------------------------------
  42. proc GlobalVar::getvar { varName } {
  43. return [uplevel \#0 [list set $varName]]
  44. }
  45. # ------------------------------------------------------------------------------
  46. # Command GlobalVar::tracevar
  47. # ------------------------------------------------------------------------------
  48. proc GlobalVar::tracevar { cmd varName args } {
  49. return [uplevel \#0 trace $cmd [list $varName] $args]
  50. }
  51. # ------------------------------------------------------------------------------
  52. # Command BWidget::lreorder
  53. # ------------------------------------------------------------------------------
  54. proc BWidget::lreorder { list neworder } {
  55. set pos 0
  56. set newlist {}
  57. foreach e $neworder {
  58. if { [lsearch -exact $list $e] != -1 } {
  59. lappend newlist $e
  60. set tabelt($e) 1
  61. }
  62. }
  63. set len [llength $newlist]
  64. if { !$len } {
  65. return $list
  66. }
  67. if { $len == [llength $list] } {
  68. return $newlist
  69. }
  70. set pos 0
  71. foreach e $list {
  72. if { ![info exists tabelt($e)] } {
  73. set newlist [linsert $newlist $pos $e]
  74. }
  75. incr pos
  76. }
  77. return $newlist
  78. }
  79. # ------------------------------------------------------------------------------
  80. # Command BWidget::assert
  81. # ------------------------------------------------------------------------------
  82. proc BWidget::assert { exp {msg ""}} {
  83. set res [uplevel expr $exp]
  84. if { !$res} {
  85. if { $msg == "" } {
  86. return -code error "Assertion failed: {$exp}"
  87. } else {
  88. return -code error $msg
  89. }
  90. }
  91. }
  92. # ------------------------------------------------------------------------------
  93. # Command BWidget::clonename
  94. # ------------------------------------------------------------------------------
  95. proc BWidget::clonename { menu } {
  96. set path ""
  97. set menupath ""
  98. set found 0
  99. foreach widget [lrange [split $menu "."] 1 end] {
  100. if { $found || [winfo class "$path.$widget"] == "Menu" } {
  101. set found 1
  102. append menupath "#" $widget
  103. append path "." $menupath
  104. } else {
  105. append menupath "#" $widget
  106. append path "." $widget
  107. }
  108. }
  109. return $path
  110. }
  111. # ------------------------------------------------------------------------------
  112. # Command BWidget::getname
  113. # ------------------------------------------------------------------------------
  114. proc BWidget::getname { name } {
  115. if { [string length $name] } {
  116. set text [option get . "${name}Name" ""]
  117. if { [string length $text] } {
  118. return [parsetext $text]
  119. }
  120. }
  121. return {}
  122. }
  123. # ------------------------------------------------------------------------------
  124. # Command BWidget::parsetext
  125. # ------------------------------------------------------------------------------
  126. proc BWidget::parsetext { text } {
  127. set result ""
  128. set index -1
  129. set start 0
  130. while { [string length $text] } {
  131. set idx [string first "&" $text]
  132. if { $idx == -1 } {
  133. append result $text
  134. set text ""
  135. } else {
  136. set char [string index $text [expr {$idx+1}]]
  137. if { $char == "&" } {
  138. append result [string range $text 0 $idx]
  139. set text [string range $text [expr {$idx+2}] end]
  140. set start [expr {$start+$idx+1}]
  141. } else {
  142. append result [string range $text 0 [expr {$idx-1}]]
  143. set text [string range $text [expr {$idx+1}] end]
  144. incr start $idx
  145. set index $start
  146. }
  147. }
  148. }
  149. return [list $result $index]
  150. }
  151. # ------------------------------------------------------------------------------
  152. # Command BWidget::get3dcolor
  153. # ------------------------------------------------------------------------------
  154. proc BWidget::get3dcolor { path bgcolor } {
  155. foreach val [winfo rgb $path $bgcolor] {
  156. lappend dark [expr 60*$val/100]
  157. set tmp1 [expr 14*$val/10]
  158. if { $tmp1 > 65535 } {
  159. set tmp1 65535
  160. }
  161. set tmp2 [expr (65535+$val)/2]
  162. lappend light [expr ($tmp1 > $tmp2) ? $tmp1:$tmp2]
  163. }
  164. return [list [eval format "#%04x%04x%04x" $dark] [eval format "#%04x%04x%04x" $light]]
  165. }
  166. # ------------------------------------------------------------------------------
  167. # Command BWidget::XLFDfont
  168. # ------------------------------------------------------------------------------
  169. proc BWidget::XLFDfont { cmd args } {
  170. switch -- $cmd {
  171. create {
  172. set font "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
  173. }
  174. configure {
  175. set font [lindex $args 0]
  176. set args [lrange $args 1 end]
  177. }
  178. default {
  179. return -code error "XLFDfont: commande incorrecte: $cmd"
  180. }
  181. }
  182. set lfont [split $font "-"]
  183. if { [llength $lfont] != 15 } {
  184. return -code error "XLFDfont: description XLFD incorrecte: $font"
  185. }
  186. foreach {option value} $args {
  187. switch -- $option {
  188. -foundry { set index 1 }
  189. -family { set index 2 }
  190. -weight { set index 3 }
  191. -slant { set index 4 }
  192. -size { set index 7 }
  193. default { return -code error "XLFDfont: option incorrecte: $option" }
  194. }
  195. set lfont [lreplace $lfont $index $index $value]
  196. }
  197. return [join $lfont "-"]
  198. }
  199. # ------------------------------------------------------------------------------
  200. # Command BWidget::place
  201. # ------------------------------------------------------------------------------
  202. proc BWidget::place { path w h args } {
  203. variable _top
  204. update idletasks
  205. set reqw [winfo reqwidth $path]
  206. set reqh [winfo reqheight $path]
  207. if { $w == 0 } {set w $reqw}
  208. if { $h == 0 } {set h $reqh}
  209. set arglen [llength $args]
  210. if { $arglen > 3 } {
  211. return -code error "BWidget::place: bad number of argument"
  212. }
  213. if { $arglen > 0 } {
  214. set where [lindex $args 0]
  215. set idx [lsearch {"at" "center" "left" "right" "above" "below"} $where]
  216. if { $idx == -1 } {
  217. return -code error "BWidget::place: incorrect position \"$where\""
  218. }
  219. if { $idx == 0 } {
  220. set err [catch {
  221. set x [expr {int([lindex $args 1])}]
  222. set y [expr {int([lindex $args 2])}]
  223. }]
  224. if { $err } {
  225. return -code error "BWidget::place: incorrect position"
  226. }
  227. if { $x >= 0 } {
  228. set x "+$x"
  229. }
  230. if { $y >= 0 } {
  231. set y "+$y"
  232. }
  233. } else {
  234. if { $arglen == 2 } {
  235. set widget [lindex $args 1]
  236. if { ![winfo exists $widget] } {
  237. return -code error "BWidget::place: \"$widget\" does not exist"
  238. }
  239. }
  240. set sw [winfo screenwidth $path]
  241. set sh [winfo screenheight $path]
  242. if { $idx == 1 } {
  243. if { $arglen == 2 } {
  244. # center to widget
  245. set x0 [expr [winfo rootx $widget] + ([winfo width $widget] - $w)/2]
  246. set y0 [expr [winfo rooty $widget] + ([winfo height $widget] - $h)/2]
  247. } else {
  248. # center to screen
  249. set x0 [expr ([winfo screenwidth $path] - $w)/2 - [winfo vrootx $path]]
  250. set y0 [expr ([winfo screenheight $path] - $h)/2 - [winfo vrooty $path]]
  251. }
  252. set x "+$x0"
  253. set y "+$y0"
  254. if { $x0+$w > $sw } {set x "-0"; set x0 [expr {$sw-$w}]}
  255. if { $x0 < 0 } {set x "+0"}
  256. if { $y0+$h > $sh } {set y "-0"; set y0 [expr {$sh-$h}]}
  257. if { $y0 < 0 } {set y "+0"}
  258. } else {
  259. set x0 [winfo rootx $widget]
  260. set y0 [winfo rooty $widget]
  261. set x1 [expr {$x0 + [winfo width $widget]}]
  262. set y1 [expr {$y0 + [winfo height $widget]}]
  263. if { $idx == 2 || $idx == 3 } {
  264. set y "+$y0"
  265. if { $y0+$h > $sh } {set y "-0"; set y0 [expr {$sh-$h}]}
  266. if { $y0 < 0 } {set y "+0"}
  267. if { $idx == 2 } {
  268. # try left, then right if out, then 0 if out
  269. if { $x0 >= $w } {
  270. set x [expr {$x0-$sw}]
  271. } elseif { $x1+$w <= $sw } {
  272. set x "+$x1"
  273. } else {
  274. set x "+0"
  275. }
  276. } else {
  277. # try right, then left if out, then 0 if out
  278. if { $x1+$w <= $sw } {
  279. set x "+$x1"
  280. } elseif { $x0 >= $w } {
  281. set x [expr {$x0-$sw}]
  282. } else {
  283. set x "-0"
  284. }
  285. }
  286. } else {
  287. set x "+$x0"
  288. if { $x0+$w > $sw } {set x "-0"; set x0 [expr {$sw-$w}]}
  289. if { $x0 < 0 } {set x "+0"}
  290. if { $idx == 4 } {
  291. # try top, then bottom, then 0
  292. if { $h <= $y0 } {
  293. set y [expr {$y0-$sh}]
  294. } elseif { $y1+$h <= $sh } {
  295. set y "+$y1"
  296. } else {
  297. set y "+0"
  298. }
  299. } else {
  300. # try bottom, then top, then 0
  301. if { $y1+$h <= $sh } {
  302. set y "+$y1"
  303. } elseif { $h <= $y0 } {
  304. set y [expr {$y0-$sh}]
  305. } else {
  306. set y "-0"
  307. }
  308. }
  309. }
  310. }
  311. }
  312. wm geometry $path "${w}x${h}${x}${y}"
  313. } else {
  314. wm geometry $path "${w}x${h}"
  315. }
  316. update idletasks
  317. }
  318. # ------------------------------------------------------------------------------
  319. # Command BWidget::grab
  320. # ------------------------------------------------------------------------------
  321. proc BWidget::grab { option path } {
  322. variable _gstack
  323. if { $option == "release" } {
  324. catch {::grab release $path}
  325. while { [llength $_gstack] } {
  326. set grinfo [lindex $_gstack end]
  327. set _gstack [lreplace $_gstack end end]
  328. foreach {oldg mode} $grinfo {
  329. if { [string compare $oldg $path] && [winfo exists $oldg] } {
  330. if { $mode == "global" } {
  331. catch {::grab -global $oldg}
  332. } else {
  333. catch {::grab $oldg}
  334. }
  335. return
  336. }
  337. }
  338. }
  339. } else {
  340. set oldg [::grab current]
  341. if { $oldg != "" } {
  342. lappend _gstack [list $oldg [::grab status $oldg]]
  343. }
  344. if { $option == "global" } {
  345. ::grab -global $path
  346. } else {
  347. ::grab $path
  348. }
  349. }
  350. }
  351. # ------------------------------------------------------------------------------
  352. # Command BWidget::focus
  353. # ------------------------------------------------------------------------------
  354. proc BWidget::focus { option path } {
  355. variable _fstack
  356. if { $option == "release" } {
  357. while { [llength $_fstack] } {
  358. set oldf [lindex $_fstack end]
  359. set _fstack [lreplace $_fstack end end]
  360. if { [string compare $oldf $path] && [winfo exists $oldf] } {
  361. catch {::focus -force $oldf}
  362. return
  363. }
  364. }
  365. } elseif { $option == "set" } {
  366. lappend _fstack [::focus]
  367. ::focus -force $path
  368. }
  369. }