itclWidget.tcl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #
  2. # itclWidget.tcl
  3. # ----------------------------------------------------------------------
  4. # Invoked automatically upon startup to customize the interpreter
  5. # for [incr Tcl] when one of ::itcl::widget or ::itcl::widgetadaptor is called.
  6. # ----------------------------------------------------------------------
  7. # AUTHOR: Arnulf P. Wiedemann
  8. #
  9. # ----------------------------------------------------------------------
  10. # Copyright (c) 2008 Arnulf P. Wiedemann
  11. # ======================================================================
  12. # See the file "license.terms" for information on usage and
  13. # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14. package require Tk 8.6
  15. # package require itclwidget [set ::itcl::version]
  16. namespace eval ::itcl {
  17. proc widget {name args} {
  18. set result [uplevel 1 ::itcl::internal::commands::genericclass widget $name $args]
  19. # we handle create by owerselfs !! allow classunknown to handle that
  20. oo::objdefine $result unexport create
  21. return $result
  22. }
  23. proc widgetadaptor {name args} {
  24. set result [uplevel 1 ::itcl::internal::commands::genericclass widgetadaptor $name $args]
  25. # we handle create by owerselfs !! allow classunknown to handle that
  26. oo::objdefine $result unexport create
  27. return $result
  28. }
  29. } ; # end ::itcl
  30. namespace eval ::itcl::internal::commands {
  31. proc initWidgetOptions {varNsName widgetName className} {
  32. set myDict [set ::itcl::internal::dicts::classOptions]
  33. if {$myDict eq ""} {
  34. return
  35. }
  36. if {![dict exists $myDict $className]} {
  37. return
  38. }
  39. set myDict [dict get $myDict $className]
  40. foreach option [dict keys $myDict] {
  41. set infos [dict get $myDict $option]
  42. set resource [dict get $infos -resource]
  43. set class [dict get $infos -class]
  44. set value [::option get $widgetName $resource $class]
  45. if {$value eq ""} {
  46. if {[dict exists $infos -default]} {
  47. set defaultValue [dict get $infos -default]
  48. uplevel 1 set ${varNsName}::itcl_options($option) $defaultValue
  49. }
  50. } else {
  51. uplevel 1 set ${varNsName}::itcl_options($option) $value
  52. }
  53. }
  54. }
  55. proc initWidgetDelegatedOptions {varNsName widgetName className args} {
  56. set myDict [set ::itcl::internal::dicts::classDelegatedOptions]
  57. if {$myDict eq ""} {
  58. return
  59. }
  60. if {![dict exists $myDict $className]} {
  61. return
  62. }
  63. set myDict [dict get $myDict $className]
  64. foreach option [dict keys $myDict] {
  65. set infos [dict get $myDict $option]
  66. if {![dict exists $infos -resource]} {
  67. # this is the case when delegating "*"
  68. continue
  69. }
  70. if {![dict exists $infos -component]} {
  71. # nothing to do
  72. continue
  73. }
  74. # check if not in the command line options
  75. # these have higher priority
  76. set myOption $option
  77. if {[dict exists $infos -as]} {
  78. set myOption [dict get $infos -as]
  79. }
  80. set noOptionSet 0
  81. foreach {optName optVal} $args {
  82. if {$optName eq $myOption} {
  83. set noOptionSet 1
  84. break
  85. }
  86. }
  87. if {$noOptionSet} {
  88. continue
  89. }
  90. set resource [dict get $infos -resource]
  91. set class [dict get $infos -class]
  92. set component [dict get $infos -component]
  93. set value [::option get $widgetName $resource $class]
  94. if {$component ne ""} {
  95. if {$value ne ""} {
  96. set compVar [namespace eval ${varNsName}${className} "set $component"]
  97. if {$compVar ne ""} {
  98. uplevel 1 $compVar configure $myOption $value
  99. }
  100. }
  101. }
  102. }
  103. }
  104. proc widgetinitobjectoptions {varNsName widgetName className} {
  105. #puts stderr "initWidgetObjectOptions!$varNsName!$widgetName!$className!"
  106. }
  107. proc deletehull {newName oldName what} {
  108. if {$what eq "delete"} {
  109. set name [namespace tail $newName]
  110. regsub {hull[0-9]+} $name {} name
  111. rename $name {}
  112. }
  113. if {$what eq "rename"} {
  114. set name [namespace tail $newName]
  115. regsub {hull[0-9]+} $name {} name
  116. rename $name {}
  117. }
  118. }
  119. proc hullandoptionsinstall {objectName className widgetClass hulltype args} {
  120. if {$hulltype eq ""} {
  121. set hulltype frame
  122. }
  123. set idx 0
  124. set found 0
  125. foreach {optName optValue} $args {
  126. if {$optName eq "-class"} {
  127. set found 1
  128. set widgetClass $optValue
  129. break
  130. }
  131. incr idx
  132. }
  133. if {$found} {
  134. set args [lreplace $args $idx [expr {$idx + 1}]]
  135. }
  136. if {$widgetClass eq ""} {
  137. set widgetClass $className
  138. set widgetClass [string totitle $widgetClass]
  139. }
  140. set cmd "set win $objectName; ::itcl::builtin::installhull using $hulltype -class $widgetClass $args"
  141. uplevel 2 $cmd
  142. }
  143. } ; # end ::itcl::internal::commands
  144. namespace eval ::itcl::builtin {
  145. proc installhull {args} {
  146. set cmdPath ::itcl::internal::commands
  147. set className [uplevel 1 info class]
  148. set replace 0
  149. switch -- [llength $args] {
  150. 0 {
  151. return -code error\
  152. "wrong # args: should be \"[lindex [info level 0] 0]\
  153. name|using <widgetType> ?arg ...?\""
  154. }
  155. 1 {
  156. set widgetName [lindex $args 0]
  157. set varNsName $::itcl::internal::varNsName($widgetName)
  158. }
  159. default {
  160. upvar win win
  161. set widgetName $win
  162. set varNsName $::itcl::internal::varNsName($widgetName)
  163. set widgetType [lindex $args 1]
  164. incr replace
  165. if {[llength $args] > 3 && [lindex $args 2] eq "-class"} {
  166. set classNam [lindex $args 3]
  167. incr replace 2
  168. } else {
  169. set classNam [string totitle $widgetType]
  170. }
  171. uplevel 1 [lreplace $args 0 $replace $widgetType $widgetName -class $classNam]
  172. uplevel 1 [list ${cmdPath}::initWidgetOptions $varNsName $widgetName $className]
  173. }
  174. }
  175. # initialize the itcl_hull variable
  176. set i 0
  177. set nam ::itcl::internal::widgets::hull
  178. while {1} {
  179. incr i
  180. set hullNam ${nam}${i}$widgetName
  181. if {[::info command $hullNam] eq ""} {
  182. break
  183. }
  184. }
  185. uplevel 1 [list ${cmdPath}::sethullwindowname $widgetName]
  186. uplevel 1 [list ::rename $widgetName $hullNam]
  187. uplevel 1 [list ::trace add command $hullNam {delete rename} ::itcl::internal::commands::deletehull]
  188. catch {${cmdPath}::checksetitclhull [list] 0}
  189. namespace eval ${varNsName}${className} "set itcl_hull $hullNam"
  190. catch {${cmdPath}::checksetitclhull [list] 2}
  191. uplevel 1 [lreplace $args 0 $replace ${cmdPath}::initWidgetDelegatedOptions $varNsName $widgetName $className]
  192. }
  193. proc installcomponent {args} {
  194. upvar win win
  195. set className [uplevel 1 info class]
  196. set myType [${className}::info types [namespace tail $className]]
  197. set isType 0
  198. if {$myType ne ""} {
  199. set isType 1
  200. }
  201. set numArgs [llength $args]
  202. set usage "usage: installcomponent <componentName> using <widgetType> <widgetPath> ?-option value ...?"
  203. if {$numArgs < 4} {
  204. error $usage
  205. }
  206. foreach {componentName using widgetType widgetPath} $args break
  207. set opts [lrange $args 4 end]
  208. if {$using ne "using"} {
  209. error $usage
  210. }
  211. if {!$isType} {
  212. set hullExists [uplevel 1 ::info exists itcl_hull]
  213. if {!$hullExists} {
  214. error "cannot install \"$componentName\" before \"itcl_hull\" exists"
  215. }
  216. set hullVal [uplevel 1 set itcl_hull]
  217. if {$hullVal eq ""} {
  218. error "cannot install \"$componentName\" before \"itcl_hull\" exists"
  219. }
  220. }
  221. # check for delegated option and ask the option database for the values
  222. # first check for number of delegated options
  223. set numOpts 0
  224. set starOption 0
  225. set myDict [set ::itcl::internal::dicts::classDelegatedOptions]
  226. if {[dict exists $myDict $className]} {
  227. set myDict [dict get $myDict $className]
  228. foreach option [dict keys $myDict] {
  229. if {$option eq "*"} {
  230. set starOption 1
  231. }
  232. incr numOpts
  233. }
  234. }
  235. set myOptionDict [set ::itcl::internal::dicts::classOptions]
  236. if {[dict exists $myOptionDict $className]} {
  237. set myOptionDict [dict get $myOptionDict $className]
  238. }
  239. set cmd [list $widgetPath configure]
  240. set cmd1 "set $componentName \[$widgetType $widgetPath\]"
  241. uplevel 1 $cmd1
  242. if {$starOption} {
  243. upvar $componentName compName
  244. set cmd1 [list $compName configure]
  245. set configInfos [uplevel 1 $cmd1]
  246. foreach entry $configInfos {
  247. if {[llength $entry] > 2} {
  248. foreach {optName resource class defaultValue} $entry break
  249. set val ""
  250. catch {
  251. set val [::option get $win $resource $class]
  252. }
  253. if {$val ne ""} {
  254. set addOpt 1
  255. if {[dict exists $myDict $$optName]} {
  256. set addOpt 0
  257. } else {
  258. set starDict [dict get $myDict "*"]
  259. if {[dict exists $starDict -except]} {
  260. set exceptions [dict get $starDict -except]
  261. if {[lsearch $exceptions $optName] >= 0} {
  262. set addOpt 0
  263. }
  264. }
  265. if {[dict exists $myOptionDict $optName]} {
  266. set addOpt 0
  267. }
  268. }
  269. if {$addOpt} {
  270. lappend cmd $optName $val
  271. }
  272. }
  273. }
  274. }
  275. } else {
  276. foreach optName [dict keys $myDict] {
  277. set optInfos [dict get $myDict $optName]
  278. set resource [dict get $optInfos -resource]
  279. set class [namespace tail $className]
  280. set class [string totitle $class]
  281. set val ""
  282. catch {
  283. set val [::option get $win $resource $class]
  284. }
  285. if {$val ne ""} {
  286. if {[dict exists $optInfos -as] } {
  287. set optName [dict get $optInfos -as]
  288. }
  289. lappend cmd $optName $val
  290. }
  291. }
  292. }
  293. lappend cmd {*}$opts
  294. uplevel 1 $cmd
  295. }
  296. } ; # end ::itcl::builtin
  297. set ::itcl::internal::dicts::hullTypes [list \
  298. frame \
  299. toplevel \
  300. labelframe \
  301. ttk:frame \
  302. ttk:toplevel \
  303. ttk:labelframe \
  304. ]
  305. namespace eval ::itcl::builtin::Info {
  306. proc hulltypes {args} {
  307. namespace upvar ::itcl::internal::dicts hullTypes hullTypes
  308. set numArgs [llength $args]
  309. if {$numArgs > 1} {
  310. error "wrong # args should be: info hulltypes ?<pattern>?"
  311. }
  312. set pattern ""
  313. if {$numArgs > 0} {
  314. set pattern [lindex $args 0]
  315. }
  316. if {$pattern ne ""} {
  317. return [lsearch -all -inline -glob $hullTypes $pattern]
  318. }
  319. return $hullTypes
  320. }
  321. proc widgetclasses {args} {
  322. set numArgs [llength $args]
  323. if {$numArgs > 1} {
  324. error "wrong # args should be: info widgetclasses ?<pattern>?"
  325. }
  326. set pattern ""
  327. if {$numArgs > 0} {
  328. set pattern [lindex $args 0]
  329. }
  330. set myDict [set ::itcl::internal::dicts::classes]
  331. if {![dict exists $myDict widget]} {
  332. return [list]
  333. }
  334. set myDict [dict get $myDict widget]
  335. set result [list]
  336. if {$pattern ne ""} {
  337. foreach key [dict keys $myDict] {
  338. set myInfo [dict get $myDict $key]
  339. set value [dict get $myInfo -widget]
  340. if {[string match $pattern $value]} {
  341. lappend result $value
  342. }
  343. }
  344. } else {
  345. foreach key [dict keys $myDict] {
  346. set myInfo [dict get $myDict $key]
  347. lappend result [dict get $myInfo -widget]
  348. }
  349. }
  350. return $result
  351. }
  352. proc widgets {args} {
  353. set numArgs [llength $args]
  354. if {$numArgs > 1} {
  355. error "wrong # args should be: info widgets ?<pattern>?"
  356. }
  357. set pattern ""
  358. if {$numArgs > 0} {
  359. set pattern [lindex $args 0]
  360. }
  361. set myDict [set ::itcl::internal::dicts::classes]
  362. if {![dict exists $myDict widget]} {
  363. return [list]
  364. }
  365. set myDict [dict get $myDict widget]
  366. set result [list]
  367. if {$pattern ne ""} {
  368. foreach key [dict keys $myDict] {
  369. set myInfo [dict get $myDict $key]
  370. set value [dict get $myInfo -name]
  371. if {[string match $pattern $value]} {
  372. lappend result $value
  373. }
  374. }
  375. } else {
  376. foreach key [dict keys $myDict] {
  377. set myInfo [dict get $myDict $key]
  378. lappend result [dict get $myInfo -name]
  379. }
  380. }
  381. return $result
  382. }
  383. proc widgetadaptors {args} {
  384. set numArgs [llength $args]
  385. if {$numArgs > 1} {
  386. error "wrong # args should be: info widgetadaptors ?<pattern>?"
  387. }
  388. set pattern ""
  389. if {$numArgs > 0} {
  390. set pattern [lindex $args 0]
  391. }
  392. set myDict [set ::itcl::internal::dicts::classes]
  393. if {![dict exists $myDict widgetadaptor]} {
  394. return [list]
  395. }
  396. set myDict [dict get $myDict widgetadaptor]
  397. set result [list]
  398. if {$pattern ne ""} {
  399. foreach key [dict keys $myDict] {
  400. set myInfo [dict get $myDict $key]
  401. set value [dict get $myInfo -name]
  402. if {[string match $pattern $value]} {
  403. lappend result $value
  404. }
  405. }
  406. } else {
  407. foreach key [dict keys $myDict] {
  408. set myInfo [dict get $myDict $key]
  409. lappend result [dict get $myInfo -name]
  410. }
  411. }
  412. return $result
  413. }
  414. } ; # end ::itcl::builtin::Info