]>
git.zerfleddert.de Git - micropolis/blob - res/menu.tcl
ea9e13e87901c721dc18c0369cac4525436242c0
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.
7 # $Header: /user6/ouster/wish/scripts/RCS/menu.tcl,v 1.11 92/08/08 14:49:55 ouster Exp $ SPRITE (Berkeley)
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.
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.
29 # Variables used by menu buttons:
30 # $tk_priv(posted@$screen) - keeps track of the menubutton whose menu is
31 # currently posted (or empty string, if none).
32 # $tk_priv(inMenuButton@$screen)-
33 # if non-null, identifies menu button
34 # containing mouse pointer.
35 # $tk_priv(relief@$screen) - keeps track of original relief of posted
36 # menu button, so it can be restored later.
37 # $tk_priv(dragging@$screen) - if non-null, identifies menu button whose
38 # menu is currently being dragged in a tear-off
40 # $tk_priv(focus@$screen) - records old focus window so focus can be
41 # returned there after keyboard traversal
44 # Variables used by menus:
45 # $tk_priv(x@$screen) and $tk_priv(y@$screen) are used to keep
46 # track of the position of the mouse cursor in the menu window
47 # during dragging of tear-off menus. $tk_priv(window) keeps track
48 # of the menu containing the mouse, if any.
50 proc tk_menus
{w args
} {
54 if [catch {set result
[set tk_priv
(menusFor
$w)]}] {
61 catch {unset tk_priv
(menusFor
$w)}
65 append tk_priv
(menusFor
$w) " $args"
68 # The procedure below is publically available. It takes any number of
69 # arguments taht are names of widgets or classes. It sets up bindings
70 # for the widgets or classes so that keyboard menu traversal is possible
71 # when the input focus is in those widgets or classes.
73 proc tk_bindForTraversal args
{
75 bind $w <Alt-KeyPress
> {tk_traverseToMenu
%W
%A
}
76 bind $w <F10
> {tk_firstMenu
%W
}
80 # The procedure below does all of the work of posting a menu (including
81 # unposting any other menu that might currently be posted). The "w"
82 # argument is the name of the menubutton for the menu to be posted.
83 # Note: if $w is disabled then the procedure does nothing.
87 if {[lindex [$w config
-state] 4] == "disabled"} {
90 set screen
[winfo screen
$w]
91 if {![info exists tk_priv
(posted
@$screen)]} {
92 set tk_priv
(posted
@$screen) {}
94 if {![info exists tk_priv
(focus@$screen)]} {
95 set tk_priv
(focus@$screen) {}
97 set cur
$tk_priv(posted
@$screen)
101 if {$cur != ""} {tk_mbUnpost
$w}
102 set tk_priv
(relief
@$screen) [lindex [$w config
-relief] 4]
103 $w config
-relief raised
104 set tk_priv
(cursor
@$screen) [lindex [$w config
-cursor] 4]
105 $w config
-cursor arrow
107 catch {grab -global $w}
108 set tk_priv
(posted
@$screen) $w
109 if {$tk_priv(focus@$screen) == ""} {
110 set tk_priv
(focus@$screen) [focus -query $w]
112 set menu [lindex [$w config
-menu] 4]
116 # The procedure below does all the work of unposting the menubutton that's
117 # currently posted. It takes no arguments.
119 proc tk_mbUnpost
{w
} {
121 set screen
[winfo screen
$w]
122 if {![info exists tk_priv
(posted
@$screen)]} {
123 set tk_priv
(posted
@$screen) {}
125 if {![info exists tk_priv
(focus@$screen)]} {
126 set tk_priv
(focus@$screen) {}
128 set mb
$tk_priv(posted
@$screen)
130 $mb config
-relief $tk_priv(relief
@$screen)
131 $mb config
-cursor $tk_priv(cursor
@$screen)
133 catch {grab -off $mb}
134 set menu [lindex [$mb config
-menu] 4]
135 focus $tk_priv(focus@$screen)
136 set tk_priv
(focus@$screen) ""
137 set tk_priv
(posted
@$screen) {}
141 # The procedure below is invoked to implement keyboard traversal to
142 # a menu button. It takes two arguments: the name of a window where
143 # a keystroke originated, and the ascii character that was typed.
144 # This procedure finds a menu bar by looking upward for a top-level
145 # window, then looking for a window underneath that named "menu".
146 # Then it searches through all the subwindows of "menu" for a menubutton
147 # with an underlined character matching char. If one is found, it
150 proc tk_traverseToMenu
{w char
} {
154 set char
[string tolower
$char]
156 foreach mb
[tk_getMenuButtons
$w] {
157 if {[winfo class
$mb] == "Menubutton"} {
158 set char2
[string index
[lindex [$mb config
-text] 4] \
159 [lindex [$mb config
-underline] 4]]
160 if {[string compare
$char [string tolower
$char2]] == 0} {
162 [lindex [$mb config
-menu] 4] activate
0
169 # The procedure below is used to implement keyboard traversal within
170 # the posted menu. It takes two arguments: the name of the menu to
171 # be traversed within, and an ASCII character. It searches for an
172 # entry in the menu that has that character underlined. If such an
173 # entry is found, it is invoked and the menu is unposted.
175 proc tk_traverseWithinMenu
{w char
} {
179 set char
[string tolower
$char]
180 set last
[$w index last
]
181 for {set i
0} {$i <= $last} {incr i
} {
182 if [catch {set char2
[string index
\
183 [lindex [$w entryconfig
$i -label] 4] \
184 [lindex [$w entryconfig
$i -underline] 4]]}] {
187 if {[string compare
$char [string tolower
$char2]] == 0} {
195 # The procedure below takes a single argument, which is the name of
196 # a window. It returns a list containing path names for all of the
197 # menu buttons associated with that window's top-level window, or an
198 # empty list if there are none.
200 proc tk_getMenuButtons
{w
} {
202 set top
[winfo toplevel $w]
203 if [catch {set buttons
[set tk_priv
(menusFor
$top)]}] {
209 # The procedure below is used to traverse to the next or previous
210 # menu in a menu bar. It takes one argument, which is a count of
211 # how many menu buttons forward or backward (if negative) to move.
212 # If there is no posted menu then this procedure has no effect.
214 proc tk_nextMenu
{w count
} {
216 set screen
[winfo screen
$w]
217 if {![info exists tk_priv
(posted
@$screen)]} {
218 set tk_priv
(posted
@$screen) {}
220 if {$tk_priv(posted
@$screen) == ""} {
223 set buttons
[tk_getMenuButtons
$tk_priv(posted
@$screen)]
224 set length
[llength $buttons]
225 for {set i
0} 1 {incr i
} {
229 if {[lindex $buttons $i] == $tk_priv(posted
@$screen)} {
238 while {$i >= $length} {
241 set mb
[lindex $buttons $i]
242 if {[lindex [$mb configure
-state] 4] != "disabled"} {
249 [lindex [$mb config
-menu] 4] activate
0
252 # The procedure below is used to traverse to the next or previous entry
253 # in the posted menu. It takes one argument, which is 1 to go to the
254 # next entry or -1 to go to the previous entry. Disabled entries are
255 # skipped in this process.
257 proc tk_nextMenuEntry
{w count
} {
259 set screen
[winfo screen
$w]
260 if {![info exists tk_priv
(posted
@$screen)]} {
261 set tk_priv
(posted
@$screen) {}
263 if {$tk_priv(posted
@$screen) == ""} {
266 set menu [lindex [$tk_priv(posted
@$screen) config
-menu] 4]
267 set length
[expr [$menu index last
]+1]
268 set i
[$menu index active
]
278 while {$i >= $length} {
281 if {[catch {$menu entryconfigure
$i -state} state
] == 0} {
282 if {[lindex $state 4] != "disabled"} {
291 # The procedure below invokes the active entry in the posted menu,
292 # if there is one. Otherwise it does nothing.
294 proc tk_invokeMenu
{w
} {
295 set i
[$w index active
]
303 # The procedure below is invoked to keyboard-traverse to the first
304 # menu for a given source window. The source window is passed as
307 proc tk_firstMenu
{w
} {
308 set mb
[lindex [tk_getMenuButtons
$w] 0]
311 [lindex [$mb config
-menu] 4] activate
0
315 # The procedure below is invoked when a button-1-down event is
316 # received by a menu button. If the mouse is in the menu button
317 # then it posts the button's menu. If the mouse isn't in the
318 # button's menu, then it deactivates any active entry in the menu.
319 # Remember, event-sharing can cause this procedure to be invoked
320 # for two different menu buttons on the same event.
322 proc tk_mbButtonDown
{w x y
} {
324 set screen
[winfo screen
$w]
325 if {![info exists tk_priv
(inMenuButton
@$screen)]} {
326 set tk_priv
(inMenuButton
@$screen) {}
328 if {![info exists tk_priv
(posted
@$screen)]} {
329 set tk_priv
(posted
@$screen) {}
331 if {[lindex [$w config
-state] 4] == "disabled"} {
334 if {$tk_priv(inMenuButton
@$screen) == $w} {
337 if {$tk_priv(posted
@$screen) != ""} then
{
338 set menu [lindex [$tk_priv(posted
@$screen) config
-menu] 4]
339 if {![info exists tk_priv
(window
@$screen)]} {
340 set tk_priv
(window
@$screen) {}
342 if {$tk_priv(window
@$screen) != $menu} {
348 proc tk_mbButtonUp
{w x y
} {
350 set screen
[winfo screen
$w]
351 if {![info exists tk_priv
(inMenuButton
@$screen)]} {
352 set tk_priv
(inMenuButton
@$screen) {}
354 if {![info exists tk_priv
(posted
@$screen)]} {
355 set tk_priv
(posted
@$screen) {}
357 if {($tk_priv(inMenuButton
@$screen) != "") &&
358 ($tk_priv(posted
@$screen) != "")} {
359 [lindex [$tk_priv(posted
@$screen) config
-menu] 4] activate
0
365 proc tk_mbButtonEnter
{w m
} {
367 set screen
[winfo screen
$w]
368 set tk_priv
(inMenuButton
@$screen) $w
369 if {[lindex [$w config
-state] 4] != "disabled"} {
370 $w config
-state active
374 proc tk_mbButtonLeave
{w
} {
376 set screen
[winfo screen
$w]
377 set tk_priv
(inMenuButton
@$screen) {}
378 if {[lindex [$w config
-state] 4] != "disabled"} {
379 $w config
-state normal
383 # In the binding below, it's important to ignore grab-related entries
384 # and exits because they lag reality and can cause menus to chase
385 # their own tail, repeatedly posting and unposting.
387 proc tk_mbButton1Enter
{w m
} {
389 set screen
[winfo screen
$w]
390 set tk_priv
(inMenuButton
@$screen) $w
391 if {([lindex [$w config
-state] 4] != "disabled")
392 && ("$m" != "NotifyGrab") && ("$m" != "NotifyUngrab")} {
393 $w config
-state active
399 proc tk_mbButton2Down
{w x y
} {
401 set screen
[winfo screen
$w]
402 if {![info exists tk_priv
(inMenuButton
@$screen)]} {
403 set tk_priv
(inMenuButton
@$screen) {}
405 if {![info exists tk_priv
(posted
@$screen)]} {
406 set tk_priv
(posted
@$screen) {}
408 if {($tk_priv(posted
@$screen) == "")
409 && ([lindex [$w config
-state] 4] != "disabled")} {
410 set tk_priv
(dragging
@$screen) $w
411 [lindex [$w config
-menu] 4] post
$x $y
416 proc tk_mbButton2Motion
{w x y
} {
418 set screen
[winfo screen
$w]
419 if {![info exists tk_priv
(dragging
@$screen)]} {
420 set tk_priv
(dragging
@$screen) {}
422 if {$tk_priv(dragging
@$screen) != ""} {
423 [lindex [$tk_priv(dragging
@$screen) config
-menu] 4] post
$x $y
427 proc tk_mbButton2Up
{w x y
} {
429 set screen
[winfo screen
$w]
430 set tk_priv
(dragging
@$screen) ""
434 proc tk_menuEnter
{w y
} {
436 set screen
[winfo screen
$w]
437 set tk_priv
(window
@$screen) $w
441 proc tk_menuLeave
{w
} {
443 set screen
[winfo screen
$w]
444 set tk_priv
(window
@$screen) {}
448 proc tk_menuMotion
{w y
} {
450 set screen
[winfo screen
$w]
451 if {![info exists tk_priv
(window
@$screen)]} {
452 set tk_priv
(window
@$screen) {}
454 if {$tk_priv(window
@$screen) != ""} {
459 proc tk_menuUp
{w y
} {
464 proc tk_menu2Down
{w x y
} {
466 set screen
[winfo screen
$w]
467 set tk_priv
(x
@$screen) $x
468 set tk_priv
(y
@$screen) $y
471 proc tk_menu2Motion
{w x y
} {
473 set screen
[winfo screen
$w]
474 if {$tk_priv(posted
@$screen) == ""} {
475 $w post
[expr $x-$tk_priv(x
@$screen)] [expr $y-$tk_priv(y
@$screen)]