]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/library/menu.tcl
1ddf0ed96cc571ec0a4b2f1f71b6edf26e03ffa4
[micropolis] / src / tk / library / menu.tcl
1 # menu.tcl --
2 #
3 # This file contains Tcl procedures used to manage Tk menus and
4 # menubuttons. Most of the code here is dedicated to support for
5 # menu traversal via the keyboard.
6 #
7 # $Header: /user6/ouster/wish/scripts/RCS/menu.tcl,v 1.11 92/08/08 14:49:55 ouster Exp $ SPRITE (Berkeley)
8 #
9 # Copyright 1992 Regents of the University of California
10 # Permission to use, copy, modify, and distribute this
11 # software and its documentation for any purpose and without
12 # fee is hereby granted, provided that this copyright
13 # notice appears in all copies. The University of California
14 # makes no representations about the suitability of this
15 # software for any purpose. It is provided "as is" without
16 # express or implied warranty.
17 #
18
19 # The procedure below is publically available. It is used to indicate
20 # the menus associated with a particular top-level window, for purposes
21 # of keyboard menu traversal. Its first argument is the path name of
22 # a top-level window, and any additional arguments are the path names of
23 # the menu buttons associated with that top-level window, in the order
24 # they should be traversed. If no menu buttons are named, the procedure
25 # returns the current list of menus for w. If a single empty string is
26 # supplied, then the menu list for w is cancelled. Otherwise, tk_menus
27 # sets the menu list for w to the menu buttons.
28
29 proc tk_menus {w args} {
30 global tk_priv
31
32 if {$args == ""} {
33 if [catch {set result [set tk_priv(menusFor$w)]}] {
34 return ""
35 }
36 return $result
37 }
38
39 if {$args == "{}"} {
40 catch {unset tk_priv(menusFor$w)}
41 return ""
42 }
43
44 set tk_priv(menusFor$w) $args
45 }
46
47 # The procedure below is publically available. It takes any number of
48 # arguments taht are names of widgets or classes. It sets up bindings
49 # for the widgets or classes so that keyboard menu traversal is possible
50 # when the input focus is in those widgets or classes.
51
52 proc tk_bindForTraversal args {
53 foreach w $args {
54 bind $w <Alt-KeyPress> {tk_traverseToMenu %W %A}
55 bind $w <F10> {tk_firstMenu %W}
56 }
57 }
58
59 # The procedure below does all of the work of posting a menu (including
60 # unposting any other menu that might currently be posted). The "w"
61 # argument is the name of the menubutton for the menu to be posted.
62 # Note: if $w is disabled then the procedure does nothing.
63
64 proc tk_mbPost {w} {
65 global tk_priv tk_strictMotif
66 if {[lindex [$w config -state] 4] == "disabled"} {
67 return
68 }
69 set cur $tk_priv(posted)
70 if {$cur == $w} {
71 return
72 }
73 if {$cur != ""} tk_mbUnpost
74 set tk_priv(relief) [lindex [$w config -relief] 4]
75 $w config -relief raised
76 set tk_priv(cursor) [lindex [$w config -cursor] 4]
77 $w config -cursor arrow
78 $w post
79 grab -global $w
80 set tk_priv(posted) $w
81 if {$tk_priv(focus) == ""} {
82 set tk_priv(focus) [focus]
83 }
84 set menu [lindex [$w config -menu] 4]
85 set tk_priv(activeBg) [lindex [$menu config -activebackground] 4]
86 set tk_priv(activeFg) [lindex [$menu config -activeforeground] 4]
87 if $tk_strictMotif {
88 $menu config -activebackground [lindex [$menu config -background] 4]
89 $menu config -activeforeground [lindex [$menu config -foreground] 4]
90 }
91 focus $menu
92 }
93
94 # The procedure below does all the work of unposting the menubutton that's
95 # currently posted. It takes no arguments.
96
97 proc tk_mbUnpost {} {
98 global tk_priv
99 if {$tk_priv(posted) != ""} {
100 $tk_priv(posted) config -relief $tk_priv(relief)
101 $tk_priv(posted) config -cursor $tk_priv(cursor)
102 $tk_priv(posted) config -activebackground $tk_priv(activeBg)
103 $tk_priv(posted) config -activeforeground $tk_priv(activeFg)
104 $tk_priv(posted) unpost
105 # deh multi display bug fix
106 # grab none
107 set menu [lindex [$tk_priv(posted) config -menu] 4]
108 grab -off $menu
109 focus $tk_priv(focus)
110 set tk_priv(focus) ""
111 $menu config -activebackground $tk_priv(activeBg)
112 $menu config -activeforeground $tk_priv(activeFg)
113 set tk_priv(posted) {}
114 }
115 }
116
117 # The procedure below is invoked to implement keyboard traversal to
118 # a menu button. It takes two arguments: the name of a window where
119 # a keystroke originated, and the ascii character that was typed.
120 # This procedure finds a menu bar by looking upward for a top-level
121 # window, then looking for a window underneath that named "menu".
122 # Then it searches through all the subwindows of "menu" for a menubutton
123 # with an underlined character matching char. If one is found, it
124 # posts that menu.
125
126 proc tk_traverseToMenu {w char} {
127 global tk_priv
128 if {$char == ""} {
129 return
130 }
131 set char [string tolower $char]
132
133 foreach mb [tk_getMenuButtons $w] {
134 if {[winfo class $mb] == "Menubutton"} {
135 set char2 [string index [lindex [$mb config -text] 4] \
136 [lindex [$mb config -underline] 4]]
137 if {[string compare $char [string tolower $char2]] == 0} {
138 tk_mbPost $mb
139 [lindex [$mb config -menu] 4] activate 0
140 return
141 }
142 }
143 }
144 }
145
146 # The procedure below is used to implement keyboard traversal within
147 # the posted menu. It takes two arguments: the name of the menu to
148 # be traversed within, and an ASCII character. It searches for an
149 # entry in the menu that has that character underlined. If such an
150 # entry is found, it is invoked and the menu is unposted.
151
152 proc tk_traverseWithinMenu {w char} {
153 if {$char == ""} {
154 return
155 }
156 set char [string tolower $char]
157 set last [$w index last]
158 for {set i 0} {$i <= $last} {incr i} {
159 if [catch {set char2 [string index \
160 [lindex [$w entryconfig $i -label] 4] \
161 [lindex [$w entryconfig $i -underline] 4]]}] {
162 continue
163 }
164 if {[string compare $char [string tolower $char2]] == 0} {
165 tk_mbUnpost
166 $w invoke $i
167 return
168 }
169 }
170 }
171
172 # The procedure below takes a single argument, which is the name of
173 # a window. It returns a list containing path names for all of the
174 # menu buttons associated with that window's top-level window, or an
175 # empty list if there are none.
176
177 proc tk_getMenuButtons w {
178 global tk_priv
179 set top [winfo toplevel $w]
180 if [catch {set buttons [set tk_priv(menusFor$top)]}] {
181 return ""
182 }
183 return $buttons
184 }
185
186 # The procedure below is used to traverse to the next or previous
187 # menu in a menu bar. It takes one argument, which is a count of
188 # how many menu buttons forward or backward (if negative) to move.
189 # If there is no posted menu then this procedure has no effect.
190
191 proc tk_nextMenu count {
192 global tk_priv
193 if {$tk_priv(posted) == ""} {
194 return
195 }
196 set buttons [tk_getMenuButtons $tk_priv(posted)]
197 set length [llength $buttons]
198 for {set i 0} 1 {incr i} {
199 if {$i >= $length} {
200 return
201 }
202 if {[lindex $buttons $i] == $tk_priv(posted)} {
203 break
204 }
205 }
206 incr i $count
207 while 1 {
208 while {$i < 0} {
209 incr i $length
210 }
211 while {$i >= $length} {
212 incr i -$length
213 }
214 set mb [lindex $buttons $i]
215 if {[lindex [$mb configure -state] 4] != "disabled"} {
216 break
217 }
218 incr i $count
219 }
220 tk_mbUnpost
221 tk_mbPost $mb
222 [lindex [$mb config -menu] 4] activate 0
223 }
224
225 # The procedure below is used to traverse to the next or previous entry
226 # in the posted menu. It takes one argument, which is 1 to go to the
227 # next entry or -1 to go to the previous entry. Disabled entries are
228 # skipped in this process.
229
230 proc tk_nextMenuEntry count {
231 global tk_priv
232 if {$tk_priv(posted) == ""} {
233 return
234 }
235 set menu [lindex [$tk_priv(posted) config -menu] 4]
236 set length [expr [$menu index last]+1]
237 set i [$menu index active]
238 if {$i == "none"} {
239 set i 0
240 } else {
241 incr i $count
242 }
243 while 1 {
244 while {$i < 0} {
245 incr i $length
246 }
247 while {$i >= $length} {
248 incr i -$length
249 }
250 if {[catch {$menu entryconfigure $i -state} state] == 0} {
251 if {[lindex $state 4] != "disabled"} {
252 break
253 }
254 }
255 incr i $count
256 }
257 $menu activate $i
258 }
259
260 # The procedure below invokes the active entry in the posted menu,
261 # if there is one. Otherwise it does nothing.
262
263 proc tk_invokeMenu {menu} {
264 set i [$menu index active]
265 if {$i != "none"} {
266 tk_mbUnpost
267 update idletasks
268 $menu invoke $i
269 }
270 }
271
272 # The procedure below is invoked to keyboard-traverse to the first
273 # menu for a given source window. The source window is passed as
274 # parameter.
275
276 proc tk_firstMenu w {
277 set mb [lindex [tk_getMenuButtons $w] 0]
278 if {$mb != ""} {
279 tk_mbPost $mb
280 [lindex [$mb config -menu] 4] activate 0
281 }
282 }
283
284 # The procedure below is invoked when a button-1-down event is
285 # received by a menu button. If the mouse is in the menu button
286 # then it posts the button's menu. If the mouse isn't in the
287 # button's menu, then it deactivates any active entry in the menu.
288 # Remember, event-sharing can cause this procedure to be invoked
289 # for two different menu buttons on the same event.
290
291 proc tk_mbButtonDown w {
292 global tk_priv
293 if {[lindex [$w config -state] 4] == "disabled"} {
294 return
295 }
296 if {$tk_priv(inMenuButton) == $w} {
297 tk_mbPost $w
298 }
299 set menu [lindex [$tk_priv(posted) config -menu] 4]
300 if {$tk_priv(window) != $menu} {
301 $menu activate none
302 }
303 }
Impressum, Datenschutz