widget.tcl 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973
  1. # ------------------------------------------------------------------------------
  2. # widget.tcl
  3. # This file is part of Unifix BWidget Toolkit
  4. # $Id$
  5. # ------------------------------------------------------------------------------
  6. # Index of commands:
  7. # - Widget::tkinclude
  8. # - Widget::bwinclude
  9. # - Widget::declare
  10. # - Widget::addmap
  11. # - Widget::init
  12. # - Widget::destroy
  13. # - Widget::setoption
  14. # - Widget::configure
  15. # - Widget::cget
  16. # - Widget::subcget
  17. # - Widget::hasChanged
  18. # - Widget::_get_tkwidget_options
  19. # - Widget::_test_tkresource
  20. # - Widget::_test_bwresource
  21. # - Widget::_test_synonym
  22. # - Widget::_test_string
  23. # - Widget::_test_flag
  24. # - Widget::_test_enum
  25. # - Widget::_test_int
  26. # - Widget::_test_boolean
  27. # ------------------------------------------------------------------------------
  28. namespace eval Widget {
  29. variable _optiontype
  30. variable _class
  31. variable _tk_widget
  32. array set _optiontype {
  33. TkResource Widget::_test_tkresource
  34. BwResource Widget::_test_bwresource
  35. Enum Widget::_test_enum
  36. Int Widget::_test_int
  37. Boolean Widget::_test_boolean
  38. String Widget::_test_string
  39. Flag Widget::_test_flag
  40. Synonym Widget::_test_synonym
  41. }
  42. proc use {} {}
  43. }
  44. # ------------------------------------------------------------------------------
  45. # Command Widget::tkinclude
  46. # Includes tk widget resources to BWidget widget.
  47. # class class name of the BWidget
  48. # tkwidget tk widget to include
  49. # subpath subpath to configure
  50. # args additionnal args for included options
  51. # ------------------------------------------------------------------------------
  52. proc Widget::tkinclude { class tkwidget subpath args } {
  53. foreach {cmd lopt} $args {
  54. # cmd can be
  55. # include options to include lopt = {opt ...}
  56. # remove options to remove lopt = {opt ...}
  57. # rename options to rename lopt = {opt newopt ...}
  58. # prefix options to prefix lopt = {prefix opt opt ...}
  59. # initialize set default value for options lopt = {opt value ...}
  60. # readonly set readonly flag for options lopt = {opt flag ...}
  61. switch -- $cmd {
  62. remove {
  63. foreach option $lopt {
  64. set remove($option) 1
  65. }
  66. }
  67. include {
  68. foreach option $lopt {
  69. set include($option) 1
  70. }
  71. }
  72. prefix {
  73. set prefix [lindex $lopt 0]
  74. foreach option [lrange $lopt 1 end] {
  75. set rename($option) "-$prefix[string range $option 1 end]"
  76. }
  77. }
  78. rename -
  79. readonly -
  80. initialize {
  81. array set $cmd $lopt
  82. }
  83. default {
  84. return -code error "invalid argument \"$cmd\""
  85. }
  86. }
  87. }
  88. namespace eval $class {}
  89. upvar 0 ${class}::opt classopt
  90. upvar 0 ${class}::map classmap
  91. # create resources informations from tk widget resources
  92. foreach optdesc [_get_tkwidget_options $tkwidget] {
  93. set option [lindex $optdesc 0]
  94. if { (![info exists include] || [info exists include($option)]) &&
  95. ![info exists remove($option)] } {
  96. if { [llength $optdesc] == 3 } {
  97. # option is a synonym
  98. set syn [lindex $optdesc 1]
  99. if { ![info exists remove($syn)] } {
  100. # original option is not removed
  101. if { [info exists rename($syn)] } {
  102. set classopt($option) [list Synonym $rename($syn)]
  103. } else {
  104. set classopt($option) [list Synonym $syn]
  105. }
  106. }
  107. } else {
  108. if { [info exists rename($option)] } {
  109. set realopt $option
  110. set option $rename($option)
  111. } else {
  112. set realopt $option
  113. }
  114. if { [info exists initialize($option)] } {
  115. set value $initialize($option)
  116. } else {
  117. set value [lindex $optdesc 1]
  118. }
  119. if { [info exists readonly($option)] } {
  120. set ro $readonly($option)
  121. } else {
  122. set ro 0
  123. }
  124. set classopt($option) [list TkResource $value $ro [list $tkwidget $realopt]]
  125. lappend classmap($option) $subpath "" $realopt
  126. }
  127. }
  128. }
  129. }
  130. # ------------------------------------------------------------------------------
  131. # Command Widget::bwinclude
  132. # Includes BWidget resources to BWidget widget.
  133. # class class name of the BWidget
  134. # subclass BWidget class to include
  135. # subpath subpath to configure
  136. # args additionnal args for included options
  137. # ------------------------------------------------------------------------------
  138. proc Widget::bwinclude { class subclass subpath args } {
  139. foreach {cmd lopt} $args {
  140. # cmd can be
  141. # include options to include lopt = {opt ...}
  142. # remove options to remove lopt = {opt ...}
  143. # rename options to rename lopt = {opt newopt ...}
  144. # prefix options to prefix lopt = {prefix opt opt ...}
  145. # initialize set default value for options lopt = {opt value ...}
  146. # readonly set readonly flag for options lopt = {opt flag ...}
  147. switch -- $cmd {
  148. remove {
  149. foreach option $lopt {
  150. set remove($option) 1
  151. }
  152. }
  153. include {
  154. foreach option $lopt {
  155. set include($option) 1
  156. }
  157. }
  158. prefix {
  159. set prefix [lindex $lopt 0]
  160. foreach option [lrange $lopt 1 end] {
  161. set rename($option) "-$prefix[string range $option 1 end]"
  162. }
  163. }
  164. rename -
  165. readonly -
  166. initialize {
  167. array set $cmd $lopt
  168. }
  169. default {
  170. return -code error "invalid argument \"$cmd\""
  171. }
  172. }
  173. }
  174. namespace eval $class {}
  175. upvar 0 ${class}::opt classopt
  176. upvar 0 ${class}::map classmap
  177. upvar 0 ${subclass}::opt subclassopt
  178. # create resources informations from BWidget resources
  179. foreach {option optdesc} [array get subclassopt] {
  180. if { (![info exists include] || [info exists include($option)]) &&
  181. ![info exists remove($option)] } {
  182. set type [lindex $optdesc 0]
  183. if { ![string compare $type "Synonym"] } {
  184. # option is a synonym
  185. set syn [lindex $optdesc 1]
  186. if { ![info exists remove($syn)] } {
  187. if { [info exists rename($syn)] } {
  188. set classopt($option) [list Synonym $rename($syn)]
  189. } else {
  190. set classopt($option) [list Synonym $syn]
  191. }
  192. }
  193. } else {
  194. if { [info exists rename($option)] } {
  195. set realopt $option
  196. set option $rename($option)
  197. } else {
  198. set realopt $option
  199. }
  200. if { [info exists initialize($option)] } {
  201. set value $initialize($option)
  202. } else {
  203. set value [lindex $optdesc 1]
  204. }
  205. if { [info exists readonly($option)] } {
  206. set ro $readonly($option)
  207. } else {
  208. set ro [lindex $optdesc 2]
  209. }
  210. set classopt($option) [list $type $value $ro [lindex $optdesc 3]]
  211. lappend classmap($option) $subpath $subclass $realopt
  212. }
  213. }
  214. }
  215. }
  216. # ------------------------------------------------------------------------------
  217. # Command Widget::declare
  218. # Declares new options to BWidget class.
  219. # ------------------------------------------------------------------------------
  220. proc Widget::declare { class optlist } {
  221. variable _optiontype
  222. namespace eval $class {}
  223. upvar 0 ${class}::opt classopt
  224. foreach optdesc $optlist {
  225. set option [lindex $optdesc 0]
  226. set optdesc [lrange $optdesc 1 end]
  227. set type [lindex $optdesc 0]
  228. if { ![info exists _optiontype($type)] } {
  229. # invalid resource type
  230. return -code error "invalid option type \"$type\""
  231. }
  232. if { ![string compare $type "Synonym"] } {
  233. # test existence of synonym option
  234. set syn [lindex $optdesc 1]
  235. if { ![info exists classopt($syn)] } {
  236. return -code error "unknow option \"$syn\" for Synonym \"$option\""
  237. }
  238. set classopt($option) [list Synonym $syn]
  239. continue
  240. }
  241. # all other resource may have default value, readonly flag and
  242. # optional arg depending on type
  243. set value [lindex $optdesc 1]
  244. set ro [lindex $optdesc 2]
  245. set arg [lindex $optdesc 3]
  246. if { ![string compare $type "BwResource"] } {
  247. # We don't keep BwResource. We simplify to type of sub BWidget
  248. set subclass [lindex $arg 0]
  249. set realopt [lindex $arg 1]
  250. if { ![string length $realopt] } {
  251. set realopt $option
  252. }
  253. upvar 0 ${subclass}::opt subclassopt
  254. if { ![info exists subclassopt($realopt)] } {
  255. return -code error "unknow option \"$realopt\""
  256. }
  257. set suboptdesc $subclassopt($realopt)
  258. if { $value == "" } {
  259. # We initialize default value
  260. set value [lindex $suboptdesc 1]
  261. }
  262. set type [lindex $suboptdesc 0]
  263. set ro [lindex $suboptdesc 2]
  264. set arg [lindex $suboptdesc 3]
  265. set classopt($option) [list $type $value $ro $arg]
  266. continue
  267. }
  268. # retreive default value for TkResource
  269. if { ![string compare $type "TkResource"] } {
  270. set tkwidget [lindex $arg 0]
  271. set realopt [lindex $arg 1]
  272. if { ![string length $realopt] } {
  273. set realopt $option
  274. }
  275. set tkoptions [_get_tkwidget_options $tkwidget]
  276. if { ![string length $value] } {
  277. # We initialize default value
  278. set value [lindex [lindex $tkoptions [lsearch $tkoptions [list $realopt *]]] end]
  279. }
  280. set classopt($option) [list TkResource $value $ro [list $tkwidget $realopt]]
  281. continue
  282. }
  283. # for any other resource type, we keep original optdesc
  284. set classopt($option) [list $type $value $ro $arg]
  285. }
  286. }
  287. # ------------------------------------------------------------------------------
  288. # Command Widget::addmap
  289. # ------------------------------------------------------------------------------
  290. proc Widget::addmap { class subclass subpath options } {
  291. upvar 0 ${class}::map classmap
  292. foreach {option realopt} $options {
  293. if { ![string length $realopt] } {
  294. set realopt $option
  295. }
  296. lappend classmap($option) $subpath $subclass $realopt
  297. }
  298. }
  299. # ------------------------------------------------------------------------------
  300. # Command Widget::syncoptions
  301. # ------------------------------------------------------------------------------
  302. proc Widget::syncoptions { class subclass subpath options } {
  303. upvar 0 ${class}::sync classync
  304. foreach {option realopt} $options {
  305. if { ![string length $realopt] } {
  306. set realopt $option
  307. }
  308. set classync($option) [list $subpath $subclass $realopt]
  309. }
  310. }
  311. # ------------------------------------------------------------------------------
  312. # Command Widget::init
  313. # ------------------------------------------------------------------------------
  314. proc Widget::init { class path options } {
  315. variable _class
  316. variable _optiontype
  317. upvar 0 ${class}::opt classopt
  318. upvar 0 ${class}::map classmap
  319. upvar 0 ${class}::$path:opt pathopt
  320. upvar 0 ${class}::$path:mod pathmod
  321. catch {unset pathopt}
  322. catch {unset pathmod}
  323. set fpath ".#BWidgetClass#$class"
  324. regsub -all "::" $class "" rdbclass
  325. if { ![winfo exists $fpath] } {
  326. frame $fpath -class $rdbclass
  327. }
  328. foreach {option optdesc} [array get classopt] {
  329. set type [lindex $optdesc 0]
  330. if { ![string compare $type "Synonym"] } {
  331. set option [lindex $optdesc 1]
  332. set optdesc $classopt($option)
  333. set type [lindex $optdesc 0]
  334. }
  335. if { ![string compare $type "TkResource"] } {
  336. set alt [lindex [lindex $optdesc 3] 1]
  337. } else {
  338. set alt ""
  339. }
  340. set optdb [lindex [_configure_option $option $alt] 0]
  341. set def [option get $fpath $optdb $rdbclass]
  342. if { [string length $def] } {
  343. set pathopt($option) $def
  344. } else {
  345. set pathopt($option) [lindex $optdesc 1]
  346. }
  347. set pathmod($option) 0
  348. }
  349. set _class($path) $class
  350. foreach {option value} $options {
  351. if { ![info exists classopt($option)] } {
  352. unset pathopt
  353. unset pathmod
  354. return -code error "unknown option \"$option\""
  355. }
  356. set optdesc $classopt($option)
  357. set type [lindex $optdesc 0]
  358. if { ![string compare $type "Synonym"] } {
  359. set option [lindex $optdesc 1]
  360. set optdesc $classopt($option)
  361. set type [lindex $optdesc 0]
  362. }
  363. set pathopt($option) [$_optiontype($type) $option $value [lindex $optdesc 3]]
  364. }
  365. }
  366. # ------------------------------------------------------------------------------
  367. # Command Widget::destroy
  368. # ------------------------------------------------------------------------------
  369. proc Widget::destroy { path } {
  370. variable _class
  371. set class $_class($path)
  372. upvar 0 ${class}::$path:opt pathopt
  373. upvar 0 ${class}::$path:mod pathmod
  374. catch {unset pathopt}
  375. catch {unset pathmod}
  376. }
  377. # ------------------------------------------------------------------------------
  378. # Command Widget::configure
  379. # ------------------------------------------------------------------------------
  380. proc Widget::configure { path options } {
  381. set len [llength $options]
  382. if { $len <= 1 } {
  383. return [_get_configure $path $options]
  384. } elseif { $len % 2 == 1 } {
  385. return -code error "incorrect number of arguments"
  386. }
  387. variable _class
  388. variable _optiontype
  389. set class $_class($path)
  390. upvar 0 ${class}::opt classopt
  391. upvar 0 ${class}::map classmap
  392. upvar 0 ${class}::$path:opt pathopt
  393. upvar 0 ${class}::$path:mod pathmod
  394. set window [_get_window $class $path]
  395. foreach {option value} $options {
  396. if { ![info exists classopt($option)] } {
  397. return -code error "unknown option \"$option\""
  398. }
  399. set optdesc $classopt($option)
  400. set type [lindex $optdesc 0]
  401. if { ![string compare $type "Synonym"] } {
  402. set option [lindex $optdesc 1]
  403. set optdesc $classopt($option)
  404. set type [lindex $optdesc 0]
  405. }
  406. if { ![lindex $optdesc 2] } {
  407. set curval $pathopt($option)
  408. set newval [$_optiontype($type) $option $value [lindex $optdesc 3]]
  409. if { [info exists classmap($option)] } {
  410. foreach {subpath subclass realopt} $classmap($option) {
  411. if { [string length $subclass] } {
  412. ${subclass}::configure $window$subpath $realopt $newval
  413. } else {
  414. $window$subpath configure $realopt $newval
  415. }
  416. }
  417. }
  418. set pathopt($option) $newval
  419. set pathmod($option) [expr {[string compare $newval $curval] != 0}]
  420. }
  421. }
  422. return {}
  423. }
  424. # ------------------------------------------------------------------------------
  425. # Command Widget::cget
  426. # ------------------------------------------------------------------------------
  427. proc Widget::cget { path option } {
  428. variable _class
  429. if { ![info exists _class($path)] } {
  430. return -code error "unknown widget $path"
  431. }
  432. set class $_class($path)
  433. upvar 0 ${class}::opt classopt
  434. upvar 0 ${class}::sync classync
  435. upvar 0 ${class}::$path:opt pathopt
  436. if { ![info exists classopt($option)] } {
  437. return -code error "unknown option \"$option\""
  438. }
  439. set optdesc $classopt($option)
  440. set type [lindex $optdesc 0]
  441. if { ![string compare $type "Synonym"] } {
  442. set option [lindex $optdesc 1]
  443. }
  444. if { [info exists classync($option)] } {
  445. set window [_get_window $class $path]
  446. foreach {subpath subclass realopt} $classync($option) {
  447. if { [string length $subclass] } {
  448. set pathopt($option) [${subclass}::cget $window$subpath $realopt]
  449. } else {
  450. set pathopt($option) [$window$subpath cget $realopt]
  451. }
  452. }
  453. }
  454. return $pathopt($option)
  455. }
  456. # ------------------------------------------------------------------------------
  457. # Command Widget::subcget
  458. # ------------------------------------------------------------------------------
  459. proc Widget::subcget { path subwidget } {
  460. variable _class
  461. set class $_class($path)
  462. upvar 0 ${class}::map classmap
  463. upvar 0 ${class}::$path:opt pathopt
  464. set result {}
  465. foreach {option map} [array get classmap] {
  466. foreach {subpath subclass realopt} $map {
  467. if { ![string compare $subpath $subwidget] } {
  468. lappend result $realopt $pathopt($option)
  469. }
  470. }
  471. }
  472. return $result
  473. }
  474. # ------------------------------------------------------------------------------
  475. # Command Widget::hasChanged
  476. # ------------------------------------------------------------------------------
  477. proc Widget::hasChanged { path option pvalue } {
  478. upvar $pvalue value
  479. variable _class
  480. set class $_class($path)
  481. upvar 0 ${class}::$path:opt pathopt
  482. upvar 0 ${class}::$path:mod pathmod
  483. set value $pathopt($option)
  484. set result $pathmod($option)
  485. set pathmod($option) 0
  486. return $result
  487. }
  488. # ------------------------------------------------------------------------------
  489. # Command Widget::setoption
  490. # ------------------------------------------------------------------------------
  491. proc Widget::setoption { path option value } {
  492. variable _class
  493. set class $_class($path)
  494. upvar 0 ${class}::$path:opt pathopt
  495. set pathopt($option) $value
  496. }
  497. # ------------------------------------------------------------------------------
  498. # Command Widget::getoption
  499. # ------------------------------------------------------------------------------
  500. proc Widget::getoption { path option } {
  501. variable _class
  502. set class $_class($path)
  503. upvar 0 ${class}::$path:opt pathopt
  504. return $pathopt($option)
  505. }
  506. # ------------------------------------------------------------------------------
  507. # Command Widget::_get_window
  508. # returns the window corresponding to widget path
  509. # ------------------------------------------------------------------------------
  510. proc Widget::_get_window { class path } {
  511. set idx [string last "#" $path]
  512. if { $idx != -1 && ![string compare [string range $path [expr {$idx+1}] end] $class] } {
  513. return [string range $path 0 [expr {$idx-1}]]
  514. } else {
  515. return $path
  516. }
  517. }
  518. # ------------------------------------------------------------------------------
  519. # Command Widget::_get_configure
  520. # returns the configuration list of options
  521. # (as tk widget do - [$w configure ?option?])
  522. # ------------------------------------------------------------------------------
  523. proc Widget::_get_configure { path options } {
  524. variable _class
  525. set class $_class($path)
  526. upvar 0 ${class}::opt classopt
  527. upvar 0 ${class}::map classmap
  528. upvar 0 ${class}::$path:opt pathopt
  529. upvar 0 ${class}::$path:mod pathmod
  530. set len [llength $options]
  531. if { !$len } {
  532. set result {}
  533. foreach option [lsort [array names classopt]] {
  534. set optdesc $classopt($option)
  535. set type [lindex $optdesc 0]
  536. if { ![string compare $type "Synonym"] } {
  537. set syn $option
  538. set option [lindex $optdesc 1]
  539. set optdesc $classopt($option)
  540. set type [lindex $optdesc 0]
  541. } else {
  542. set syn ""
  543. }
  544. if { ![string compare $type "TkResource"] } {
  545. set alt [lindex [lindex $optdesc 3] 1]
  546. } else {
  547. set alt ""
  548. }
  549. set res [_configure_option $option $alt]
  550. if { $syn == "" } {
  551. lappend result [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
  552. } else {
  553. lappend result [list $syn [lindex $res 0]]
  554. }
  555. }
  556. return $result
  557. } elseif { $len == 1 } {
  558. set option [lindex $options 0]
  559. if { ![info exists classopt($option)] } {
  560. return -code error "unknown option \"$option\""
  561. }
  562. set optdesc $classopt($option)
  563. set type [lindex $optdesc 0]
  564. if { ![string compare $type "Synonym"] } {
  565. set option [lindex $optdesc 1]
  566. set optdesc $classopt($option)
  567. set type [lindex $optdesc 0]
  568. }
  569. if { ![string compare $type "TkResource"] } {
  570. set alt [lindex [lindex $optdesc 3] 1]
  571. } else {
  572. set alt ""
  573. }
  574. set res [_configure_option $option $alt]
  575. return [concat $option $res [list [lindex $optdesc 1]] [list [cget $path $option]]]
  576. }
  577. }
  578. # ------------------------------------------------------------------------------
  579. # Command Widget::_configure_option
  580. # ------------------------------------------------------------------------------
  581. proc Widget::_configure_option { option altopt } {
  582. variable _optiondb
  583. variable _optionclass
  584. if { [info exists _optiondb($option)] } {
  585. set optdb $_optiondb($option)
  586. } else {
  587. set optdb [string range $option 1 end]
  588. }
  589. if { [info exists _optionclass($option)] } {
  590. set optclass $_optionclass($option)
  591. } elseif { [string length $altopt] } {
  592. if { [info exists _optionclass($altopt)] } {
  593. set optclass $_optionclass($altopt)
  594. } else {
  595. set optclass [string range $altopt 1 end]
  596. }
  597. } else {
  598. set optclass [string range $option 1 end]
  599. }
  600. return [list $optdb $optclass]
  601. }
  602. # ------------------------------------------------------------------------------
  603. # Command Widget::_get_tkwidget_options
  604. # ------------------------------------------------------------------------------
  605. proc Widget::_get_tkwidget_options { tkwidget } {
  606. variable _tk_widget
  607. variable _optiondb
  608. variable _optionclass
  609. if { ![info exists _tk_widget($tkwidget)] } {
  610. set widget [$tkwidget ".#BWidget#$tkwidget"]
  611. set config [$widget configure]
  612. foreach optlist $config {
  613. set opt [lindex $optlist 0]
  614. if { [llength $optlist] == 2 } {
  615. set refsyn [lindex $optlist 1]
  616. # search for class
  617. set idx [lsearch $config [list * $refsyn *]]
  618. if { $idx == -1 } {
  619. if { [string index $refsyn 0] == "-" } {
  620. # search for option (tk8.1b1 bug)
  621. set idx [lsearch $config [list $refsyn * *]]
  622. } else {
  623. # last resort
  624. set idx [lsearch $config [list -[string tolower $refsyn] * *]]
  625. }
  626. if { $idx == -1 } {
  627. # fed up with "can't read classopt()"
  628. return -code error "can't find option of synonym $opt"
  629. }
  630. }
  631. set syn [lindex [lindex $config $idx] 0]
  632. set def [lindex [lindex $config $idx] 3]
  633. lappend _tk_widget($tkwidget) [list $opt $syn $def]
  634. } else {
  635. set def [lindex $optlist 3]
  636. lappend _tk_widget($tkwidget) [list $opt $def]
  637. set _optiondb($opt) [lindex $optlist 1]
  638. set _optionclass($opt) [lindex $optlist 2]
  639. }
  640. }
  641. }
  642. return $_tk_widget($tkwidget)
  643. }
  644. # ------------------------------------------------------------------------------
  645. # Command Widget::_test_tkresource
  646. # ------------------------------------------------------------------------------
  647. proc Widget::_test_tkresource { option value arg } {
  648. set tkwidget [lindex $arg 0]
  649. set realopt [lindex $arg 1]
  650. set path ".#BWidget#$tkwidget"
  651. set old [$path cget $realopt]
  652. $path configure $realopt $value
  653. set res [$path cget $realopt]
  654. $path configure $realopt $old
  655. return $res
  656. }
  657. # ------------------------------------------------------------------------------
  658. # Command Widget::_test_bwresource
  659. # ------------------------------------------------------------------------------
  660. proc Widget::_test_bwresource { option value arg } {
  661. return -code error "bad option type BwResource in widget"
  662. }
  663. # ------------------------------------------------------------------------------
  664. # Command Widget::_test_synonym
  665. # ------------------------------------------------------------------------------
  666. proc Widget::_test_synonym { option value arg } {
  667. return -code error "bad option type Synonym in widget"
  668. }
  669. # ------------------------------------------------------------------------------
  670. # Command Widget::_test_string
  671. # ------------------------------------------------------------------------------
  672. proc Widget::_test_string { option value arg } {
  673. return $value
  674. }
  675. # ------------------------------------------------------------------------------
  676. # Command Widget::_test_flag
  677. # ------------------------------------------------------------------------------
  678. proc Widget::_test_flag { option value arg } {
  679. set len [string length $value]
  680. set res ""
  681. for {set i 0} {$i < $len} {incr i} {
  682. set c [string index $value $i]
  683. if { [string first $c $arg] == -1 } {
  684. return -code error "bad [string range $option 1 end] value \"$value\": characters must be in \"$arg\""
  685. }
  686. if { [string first $c $res] == -1 } {
  687. append res $c
  688. }
  689. }
  690. return $res
  691. }
  692. # ------------------------------------------------------------------------------
  693. # Command Widget::_test_enum
  694. # ------------------------------------------------------------------------------
  695. proc Widget::_test_enum { option value arg } {
  696. if { [lsearch $arg $value] == -1 } {
  697. set last [lindex $arg end]
  698. set sub [lreplace $arg end end]
  699. if { [llength $sub] } {
  700. set str "[join $sub ", "] or $last"
  701. } else {
  702. set str $last
  703. }
  704. return -code error "bad [string range $option 1 end] value \"$value\": must be $str"
  705. }
  706. return $value
  707. }
  708. # ------------------------------------------------------------------------------
  709. # Command Widget::_test_int
  710. # ------------------------------------------------------------------------------
  711. proc Widget::_test_int { option value arg } {
  712. set binf [lindex $arg 0]
  713. set bsup [lindex $arg 1]
  714. if { $binf != "" } {set binf ">$binf"}
  715. if { $bsup != "" } {set bsup "<$bsup"}
  716. if { [catch {expr $value}] || $value != int($value) ||
  717. !($binf == "" || [expr $value$binf]) ||
  718. !($bsup == "" || [expr $value$bsup]) } {
  719. return -code error "bad [string range $option 1 end] value \"$value\": must be integer $binf $bsup"
  720. }
  721. return $value
  722. }
  723. # ------------------------------------------------------------------------------
  724. # Command Widget::_test_boolean
  725. # ------------------------------------------------------------------------------
  726. proc Widget::_test_boolean { option value arg } {
  727. if { $value == 1 ||
  728. ![string compare $value "true"] ||
  729. ![string compare $value "yes"] } {
  730. set value 1
  731. } elseif { $value == 0 ||
  732. ![string compare $value "false"] ||
  733. ![string compare $value "no"] } {
  734. set value 0
  735. } else {
  736. return -code error "bad [string range $option 1 end] value \"$value\": must be boolean"
  737. }
  738. return $value
  739. }
  740. # ------------------------------------------------------------------------------
  741. # Command Widget::focusNext
  742. # Same as tk_focusNext, but call Widget::focusOK
  743. # ------------------------------------------------------------------------------
  744. proc Widget::focusNext { w } {
  745. set cur $w
  746. while 1 {
  747. # Descend to just before the first child of the current widget.
  748. set parent $cur
  749. set children [winfo children $cur]
  750. set i -1
  751. # Look for the next sibling that isn't a top-level.
  752. while 1 {
  753. incr i
  754. if {$i < [llength $children]} {
  755. set cur [lindex $children $i]
  756. if {[winfo toplevel $cur] == $cur} {
  757. continue
  758. } else {
  759. break
  760. }
  761. }
  762. # No more siblings, so go to the current widget's parent.
  763. # If it's a top-level, break out of the loop, otherwise
  764. # look for its next sibling.
  765. set cur $parent
  766. if {[winfo toplevel $cur] == $cur} {
  767. break
  768. }
  769. set parent [winfo parent $parent]
  770. set children [winfo children $parent]
  771. set i [lsearch -exact $children $cur]
  772. }
  773. if {($cur == $w) || [focusOK $cur]} {
  774. return $cur
  775. }
  776. }
  777. }
  778. # ------------------------------------------------------------------------------
  779. # Command Widget::focusPrev
  780. # Same as tk_focusPrev, but call Widget::focusOK
  781. # ------------------------------------------------------------------------------
  782. proc Widget::focusPrev { w } {
  783. set cur $w
  784. while 1 {
  785. # Collect information about the current window's position
  786. # among its siblings. Also, if the window is a top-level,
  787. # then reposition to just after the last child of the window.
  788. if {[winfo toplevel $cur] == $cur} {
  789. set parent $cur
  790. set children [winfo children $cur]
  791. set i [llength $children]
  792. } else {
  793. set parent [winfo parent $cur]
  794. set children [winfo children $parent]
  795. set i [lsearch -exact $children $cur]
  796. }
  797. # Go to the previous sibling, then descend to its last descendant
  798. # (highest in stacking order. While doing this, ignore top-levels
  799. # and their descendants. When we run out of descendants, go up
  800. # one level to the parent.
  801. while {$i > 0} {
  802. incr i -1
  803. set cur [lindex $children $i]
  804. if {[winfo toplevel $cur] == $cur} {
  805. continue
  806. }
  807. set parent $cur
  808. set children [winfo children $parent]
  809. set i [llength $children]
  810. }
  811. set cur $parent
  812. if {($cur == $w) || [focusOK $cur]} {
  813. return $cur
  814. }
  815. }
  816. }
  817. # ------------------------------------------------------------------------------
  818. # Command Widget::focusOK
  819. # Same as tk_focusOK, but handles -editable option and whole tags list.
  820. # ------------------------------------------------------------------------------
  821. proc Widget::focusOK { w } {
  822. set code [catch {$w cget -takefocus} value]
  823. if { $code == 1 } {
  824. return 0
  825. }
  826. if {($code == 0) && ($value != "")} {
  827. if {$value == 0} {
  828. return 0
  829. } elseif {$value == 1} {
  830. return [winfo viewable $w]
  831. } else {
  832. set value [uplevel \#0 $value $w]
  833. if {$value != ""} {
  834. return $value
  835. }
  836. }
  837. }
  838. if {![winfo viewable $w]} {
  839. return 0
  840. }
  841. set code [catch {$w cget -state} value]
  842. if {($code == 0) && ($value == "disabled")} {
  843. return 0
  844. }
  845. set code [catch {$w cget -editable} value]
  846. if {($code == 0) && !$value} {
  847. return 0
  848. }
  849. set top [winfo toplevel $w]
  850. foreach tags [bindtags $w] {
  851. if { [string compare $tags $top] &&
  852. [string compare $tags "all"] &&
  853. [regexp Key [bind $tags]] } {
  854. return 1
  855. }
  856. }
  857. return 0
  858. }