comdlg.tcl 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. # comdlg.tcl --
  2. #
  3. # Some functions needed for the common dialog boxes. Probably need to go
  4. # in a different file.
  5. #
  6. # Copyright (c) 1996 Sun Microsystems, Inc.
  7. #
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. #
  11. # tclParseConfigSpec --
  12. #
  13. # Parses a list of "-option value" pairs. If all options and
  14. # values are legal, the values are stored in
  15. # $data($option). Otherwise an error message is returned. When
  16. # an error happens, the data() array may have been partially
  17. # modified, but all the modified members of the data(0 array are
  18. # guaranteed to have valid values. This is different than
  19. # Tk_ConfigureWidget() which does not modify the value of a
  20. # widget record if any error occurs.
  21. #
  22. # Arguments:
  23. #
  24. # w = widget record to modify. Must be the pathname of a widget.
  25. #
  26. # specs = {
  27. # {-commandlineswitch resourceName ResourceClass defaultValue verifier}
  28. # {....}
  29. # }
  30. #
  31. # flags = currently unused.
  32. #
  33. # argList = The list of "-option value" pairs.
  34. #
  35. proc tclParseConfigSpec {w specs flags argList} {
  36. upvar #0 $w data
  37. # 1: Put the specs in associative arrays for faster access
  38. #
  39. foreach spec $specs {
  40. if {[llength $spec] < 4} {
  41. return -code error -errorcode {TK VALUE CONFIG_SPEC} \
  42. "\"spec\" should contain 5 or 4 elements"
  43. }
  44. set cmdsw [lindex $spec 0]
  45. set cmd($cmdsw) ""
  46. set rname($cmdsw) [lindex $spec 1]
  47. set rclass($cmdsw) [lindex $spec 2]
  48. set def($cmdsw) [lindex $spec 3]
  49. set verproc($cmdsw) [lindex $spec 4]
  50. }
  51. if {[llength $argList] & 1} {
  52. set cmdsw [lindex $argList end]
  53. if {![info exists cmd($cmdsw)]} {
  54. return -code error -errorcode [list TK LOOKUP OPTION $cmdsw] \
  55. "bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
  56. }
  57. return -code error -errorcode {TK VALUE_MISSING} \
  58. "value for \"$cmdsw\" missing"
  59. }
  60. # 2: set the default values
  61. #
  62. foreach cmdsw [array names cmd] {
  63. set data($cmdsw) $def($cmdsw)
  64. }
  65. # 3: parse the argument list
  66. #
  67. foreach {cmdsw value} $argList {
  68. if {![info exists cmd($cmdsw)]} {
  69. return -code error -errorcode [list TK LOOKUP OPTION $cmdsw] \
  70. "bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
  71. }
  72. set data($cmdsw) $value
  73. }
  74. # Done!
  75. }
  76. proc tclListValidFlags {v} {
  77. upvar $v cmd
  78. set len [llength [array names cmd]]
  79. set i 1
  80. set separator ""
  81. set errormsg ""
  82. foreach cmdsw [lsort [array names cmd]] {
  83. append errormsg "$separator$cmdsw"
  84. incr i
  85. if {$i == $len} {
  86. set separator ", or "
  87. } else {
  88. set separator ", "
  89. }
  90. }
  91. return $errormsg
  92. }
  93. #----------------------------------------------------------------------
  94. #
  95. # Focus Group
  96. #
  97. # Focus groups are used to handle the user's focusing actions inside a
  98. # toplevel.
  99. #
  100. # One example of using focus groups is: when the user focuses on an
  101. # entry, the text in the entry is highlighted and the cursor is put to
  102. # the end of the text. When the user changes focus to another widget,
  103. # the text in the previously focused entry is validated.
  104. #
  105. #----------------------------------------------------------------------
  106. # ::tk::FocusGroup_Create --
  107. #
  108. # Create a focus group. All the widgets in a focus group must be
  109. # within the same focus toplevel. Each toplevel can have only
  110. # one focus group, which is identified by the name of the
  111. # toplevel widget.
  112. #
  113. proc ::tk::FocusGroup_Create {t} {
  114. variable ::tk::Priv
  115. if {[winfo toplevel $t] ne $t} {
  116. return -code error -errorcode [list TK LOOKUP TOPLEVEL $t] \
  117. "$t is not a toplevel window"
  118. }
  119. if {![info exists Priv(fg,$t)]} {
  120. set Priv(fg,$t) 1
  121. set Priv(focus,$t) ""
  122. bind $t <FocusIn> [list tk::FocusGroup_In $t %W %d]
  123. bind $t <FocusOut> [list tk::FocusGroup_Out $t %W %d]
  124. bind $t <Destroy> [list tk::FocusGroup_Destroy $t %W]
  125. }
  126. }
  127. # ::tk::FocusGroup_BindIn --
  128. #
  129. # Add a widget into the "FocusIn" list of the focus group. The $cmd will be
  130. # called when the widget is focused on by the user.
  131. #
  132. proc ::tk::FocusGroup_BindIn {t w cmd} {
  133. variable FocusIn
  134. variable ::tk::Priv
  135. if {![info exists Priv(fg,$t)]} {
  136. return -code error -errorcode [list TK LOOKUP FOCUS_GROUP $t] \
  137. "focus group \"$t\" doesn't exist"
  138. }
  139. set FocusIn($t,$w) $cmd
  140. }
  141. # ::tk::FocusGroup_BindOut --
  142. #
  143. # Add a widget into the "FocusOut" list of the focus group. The
  144. # $cmd will be called when the widget loses the focus (User
  145. # types Tab or click on another widget).
  146. #
  147. proc ::tk::FocusGroup_BindOut {t w cmd} {
  148. variable FocusOut
  149. variable ::tk::Priv
  150. if {![info exists Priv(fg,$t)]} {
  151. return -code error -errorcode [list TK LOOKUP FOCUS_GROUP $t] \
  152. "focus group \"$t\" doesn't exist"
  153. }
  154. set FocusOut($t,$w) $cmd
  155. }
  156. # ::tk::FocusGroup_Destroy --
  157. #
  158. # Cleans up when members of the focus group is deleted, or when the
  159. # toplevel itself gets deleted.
  160. #
  161. proc ::tk::FocusGroup_Destroy {t w} {
  162. variable FocusIn
  163. variable FocusOut
  164. variable ::tk::Priv
  165. if {$t eq $w} {
  166. unset Priv(fg,$t)
  167. unset Priv(focus,$t)
  168. foreach name [array names FocusIn $t,*] {
  169. unset FocusIn($name)
  170. }
  171. foreach name [array names FocusOut $t,*] {
  172. unset FocusOut($name)
  173. }
  174. } else {
  175. if {[info exists Priv(focus,$t)] && ($Priv(focus,$t) eq $w)} {
  176. set Priv(focus,$t) ""
  177. }
  178. unset -nocomplain FocusIn($t,$w) FocusOut($t,$w)
  179. }
  180. }
  181. # ::tk::FocusGroup_In --
  182. #
  183. # Handles the <FocusIn> event. Calls the FocusIn command for the newly
  184. # focused widget in the focus group.
  185. #
  186. proc ::tk::FocusGroup_In {t w detail} {
  187. variable FocusIn
  188. variable ::tk::Priv
  189. if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
  190. # This is caused by mouse moving out&in of the window *or*
  191. # ordinary keypresses some window managers (ie: CDE [Bug: 2960]).
  192. return
  193. }
  194. if {![info exists FocusIn($t,$w)]} {
  195. set FocusIn($t,$w) ""
  196. return
  197. }
  198. if {![info exists Priv(focus,$t)]} {
  199. return
  200. }
  201. if {$Priv(focus,$t) eq $w} {
  202. # This is already in focus
  203. #
  204. return
  205. } else {
  206. set Priv(focus,$t) $w
  207. eval $FocusIn($t,$w)
  208. }
  209. }
  210. # ::tk::FocusGroup_Out --
  211. #
  212. # Handles the <FocusOut> event. Checks if this is really a lose
  213. # focus event, not one generated by the mouse moving out of the
  214. # toplevel window. Calls the FocusOut command for the widget
  215. # who loses its focus.
  216. #
  217. proc ::tk::FocusGroup_Out {t w detail} {
  218. variable FocusOut
  219. variable ::tk::Priv
  220. if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
  221. # This is caused by mouse moving out of the window
  222. return
  223. }
  224. if {![info exists Priv(focus,$t)]} {
  225. return
  226. }
  227. if {![info exists FocusOut($t,$w)]} {
  228. return
  229. } else {
  230. eval $FocusOut($t,$w)
  231. set Priv(focus,$t) ""
  232. }
  233. }
  234. # ::tk::FDGetFileTypes --
  235. #
  236. # Process the string given by the -filetypes option of the file
  237. # dialogs. Similar to the C function TkGetFileFilters() on the Mac
  238. # and Windows platform.
  239. #
  240. proc ::tk::FDGetFileTypes {string} {
  241. foreach t $string {
  242. if {[llength $t] < 2 || [llength $t] > 3} {
  243. return -code error -errorcode {TK VALUE FILE_TYPE} \
  244. "bad file type \"$t\", should be \"typeName {extension ?extensions ...?} ?{macType ?macTypes ...?}?\""
  245. }
  246. lappend fileTypes([lindex $t 0]) {*}[lindex $t 1]
  247. }
  248. set types {}
  249. foreach t $string {
  250. set label [lindex $t 0]
  251. set exts {}
  252. if {[info exists hasDoneType($label)]} {
  253. continue
  254. }
  255. # Validate each macType. This is to agree with the
  256. # behaviour of TkGetFileFilters(). This list may be
  257. # empty.
  258. foreach macType [lindex $t 2] {
  259. if {[string length $macType] != 4} {
  260. return -code error -errorcode {TK VALUE MAC_TYPE} \
  261. "bad Macintosh file type \"$macType\""
  262. }
  263. }
  264. set name "$label \("
  265. set sep ""
  266. set doAppend 1
  267. foreach ext $fileTypes($label) {
  268. if {$ext eq ""} {
  269. continue
  270. }
  271. regsub {^[.]} $ext "*." ext
  272. if {![info exists hasGotExt($label,$ext)]} {
  273. if {$doAppend} {
  274. if {[string length $sep] && [string length $name]>40} {
  275. set doAppend 0
  276. append name $sep...
  277. } else {
  278. append name $sep$ext
  279. }
  280. }
  281. lappend exts $ext
  282. set hasGotExt($label,$ext) 1
  283. }
  284. set sep ","
  285. }
  286. append name "\)"
  287. lappend types [list $name $exts]
  288. set hasDoneType($label) 1
  289. }
  290. return $types
  291. }