comdlg.tcl 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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. error "\"spec\" should contain 5 or 4 elements"
  42. }
  43. set cmdsw [lindex $spec 0]
  44. set cmd($cmdsw) ""
  45. set rname($cmdsw) [lindex $spec 1]
  46. set rclass($cmdsw) [lindex $spec 2]
  47. set def($cmdsw) [lindex $spec 3]
  48. set verproc($cmdsw) [lindex $spec 4]
  49. }
  50. if {[llength $argList] & 1} {
  51. set cmdsw [lindex $argList end]
  52. if {![info exists cmd($cmdsw)]} {
  53. error "bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
  54. }
  55. error "value for \"$cmdsw\" missing"
  56. }
  57. # 2: set the default values
  58. #
  59. foreach cmdsw [array names cmd] {
  60. set data($cmdsw) $def($cmdsw)
  61. }
  62. # 3: parse the argument list
  63. #
  64. foreach {cmdsw value} $argList {
  65. if {![info exists cmd($cmdsw)]} {
  66. error "bad option \"$cmdsw\": must be [tclListValidFlags cmd]"
  67. }
  68. set data($cmdsw) $value
  69. }
  70. # Done!
  71. }
  72. proc tclListValidFlags {v} {
  73. upvar $v cmd
  74. set len [llength [array names cmd]]
  75. set i 1
  76. set separator ""
  77. set errormsg ""
  78. foreach cmdsw [lsort [array names cmd]] {
  79. append errormsg "$separator$cmdsw"
  80. incr i
  81. if {$i == $len} {
  82. set separator ", or "
  83. } else {
  84. set separator ", "
  85. }
  86. }
  87. return $errormsg
  88. }
  89. #----------------------------------------------------------------------
  90. #
  91. # Focus Group
  92. #
  93. # Focus groups are used to handle the user's focusing actions inside a
  94. # toplevel.
  95. #
  96. # One example of using focus groups is: when the user focuses on an
  97. # entry, the text in the entry is highlighted and the cursor is put to
  98. # the end of the text. When the user changes focus to another widget,
  99. # the text in the previously focused entry is validated.
  100. #
  101. #----------------------------------------------------------------------
  102. # ::tk::FocusGroup_Create --
  103. #
  104. # Create a focus group. All the widgets in a focus group must be
  105. # within the same focus toplevel. Each toplevel can have only
  106. # one focus group, which is identified by the name of the
  107. # toplevel widget.
  108. #
  109. proc ::tk::FocusGroup_Create {t} {
  110. variable ::tk::Priv
  111. if {[winfo toplevel $t] ne $t} {
  112. error "$t is not a toplevel window"
  113. }
  114. if {![info exists Priv(fg,$t)]} {
  115. set Priv(fg,$t) 1
  116. set Priv(focus,$t) ""
  117. bind $t <FocusIn> [list tk::FocusGroup_In $t %W %d]
  118. bind $t <FocusOut> [list tk::FocusGroup_Out $t %W %d]
  119. bind $t <Destroy> [list tk::FocusGroup_Destroy $t %W]
  120. }
  121. }
  122. # ::tk::FocusGroup_BindIn --
  123. #
  124. # Add a widget into the "FocusIn" list of the focus group. The $cmd will be
  125. # called when the widget is focused on by the user.
  126. #
  127. proc ::tk::FocusGroup_BindIn {t w cmd} {
  128. variable FocusIn
  129. variable ::tk::Priv
  130. if {![info exists Priv(fg,$t)]} {
  131. error "focus group \"$t\" doesn't exist"
  132. }
  133. set FocusIn($t,$w) $cmd
  134. }
  135. # ::tk::FocusGroup_BindOut --
  136. #
  137. # Add a widget into the "FocusOut" list of the focus group. The
  138. # $cmd will be called when the widget loses the focus (User
  139. # types Tab or click on another widget).
  140. #
  141. proc ::tk::FocusGroup_BindOut {t w cmd} {
  142. variable FocusOut
  143. variable ::tk::Priv
  144. if {![info exists Priv(fg,$t)]} {
  145. error "focus group \"$t\" doesn't exist"
  146. }
  147. set FocusOut($t,$w) $cmd
  148. }
  149. # ::tk::FocusGroup_Destroy --
  150. #
  151. # Cleans up when members of the focus group is deleted, or when the
  152. # toplevel itself gets deleted.
  153. #
  154. proc ::tk::FocusGroup_Destroy {t w} {
  155. variable FocusIn
  156. variable FocusOut
  157. variable ::tk::Priv
  158. if {$t eq $w} {
  159. unset Priv(fg,$t)
  160. unset Priv(focus,$t)
  161. foreach name [array names FocusIn $t,*] {
  162. unset FocusIn($name)
  163. }
  164. foreach name [array names FocusOut $t,*] {
  165. unset FocusOut($name)
  166. }
  167. } else {
  168. if {[info exists Priv(focus,$t)] && ($Priv(focus,$t) eq $w)} {
  169. set Priv(focus,$t) ""
  170. }
  171. unset -nocomplain FocusIn($t,$w) FocusOut($t,$w)
  172. }
  173. }
  174. # ::tk::FocusGroup_In --
  175. #
  176. # Handles the <FocusIn> event. Calls the FocusIn command for the newly
  177. # focused widget in the focus group.
  178. #
  179. proc ::tk::FocusGroup_In {t w detail} {
  180. variable FocusIn
  181. variable ::tk::Priv
  182. if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
  183. # This is caused by mouse moving out&in of the window *or*
  184. # ordinary keypresses some window managers (ie: CDE [Bug: 2960]).
  185. return
  186. }
  187. if {![info exists FocusIn($t,$w)]} {
  188. set FocusIn($t,$w) ""
  189. return
  190. }
  191. if {![info exists Priv(focus,$t)]} {
  192. return
  193. }
  194. if {$Priv(focus,$t) eq $w} {
  195. # This is already in focus
  196. #
  197. return
  198. } else {
  199. set Priv(focus,$t) $w
  200. eval $FocusIn($t,$w)
  201. }
  202. }
  203. # ::tk::FocusGroup_Out --
  204. #
  205. # Handles the <FocusOut> event. Checks if this is really a lose
  206. # focus event, not one generated by the mouse moving out of the
  207. # toplevel window. Calls the FocusOut command for the widget
  208. # who loses its focus.
  209. #
  210. proc ::tk::FocusGroup_Out {t w detail} {
  211. variable FocusOut
  212. variable ::tk::Priv
  213. if {$detail ne "NotifyNonlinear" && $detail ne "NotifyNonlinearVirtual"} {
  214. # This is caused by mouse moving out of the window
  215. return
  216. }
  217. if {![info exists Priv(focus,$t)]} {
  218. return
  219. }
  220. if {![info exists FocusOut($t,$w)]} {
  221. return
  222. } else {
  223. eval $FocusOut($t,$w)
  224. set Priv(focus,$t) ""
  225. }
  226. }
  227. # ::tk::FDGetFileTypes --
  228. #
  229. # Process the string given by the -filetypes option of the file
  230. # dialogs. Similar to the C function TkGetFileFilters() on the Mac
  231. # and Windows platform.
  232. #
  233. proc ::tk::FDGetFileTypes {string} {
  234. foreach t $string {
  235. if {[llength $t] < 2 || [llength $t] > 3} {
  236. error "bad file type \"$t\", should be \"typeName {extension ?extensions ...?} ?{macType ?macTypes ...?}?\""
  237. }
  238. lappend fileTypes([lindex $t 0]) {*}[lindex $t 1]
  239. }
  240. set types {}
  241. foreach t $string {
  242. set label [lindex $t 0]
  243. set exts {}
  244. if {[info exists hasDoneType($label)]} {
  245. continue
  246. }
  247. # Validate each macType. This is to agree with the
  248. # behaviour of TkGetFileFilters(). This list may be
  249. # empty.
  250. foreach macType [lindex $t 2] {
  251. if {[string length $macType] != 4} {
  252. error "bad Macintosh file type \"$macType\""
  253. }
  254. }
  255. set name "$label \("
  256. set sep ""
  257. set doAppend 1
  258. foreach ext $fileTypes($label) {
  259. if {$ext eq ""} {
  260. continue
  261. }
  262. regsub {^[.]} $ext "*." ext
  263. if {![info exists hasGotExt($label,$ext)]} {
  264. if {$doAppend} {
  265. if {[string length $sep] && [string length $name]>40} {
  266. set doAppend 0
  267. append name $sep...
  268. } else {
  269. append name $sep$ext
  270. }
  271. }
  272. lappend exts $ext
  273. set hasGotExt($label,$ext) 1
  274. }
  275. set sep ","
  276. }
  277. append name "\)"
  278. lappend types [list $name $exts]
  279. set hasDoneType($label) 1
  280. }
  281. return $types
  282. }