Annotation of micropolis/res/menu.tcl, revision 1.1

1.1     ! root        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: # 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
        !            39: #                              operation.
        !            40: # $tk_priv(focus@$screen) -    records old focus window so focus can be
        !            41: #                              returned there after keyboard traversal
        !            42: #                              to menu.
        !            43: #
        !            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.
        !            49: 
        !            50: proc tk_menus {w args} {
        !            51:     global tk_priv
        !            52: 
        !            53:     if {$args == ""} {
        !            54:        if [catch {set result [set tk_priv(menusFor$w)]}] {
        !            55:            return ""
        !            56:        }
        !            57:        return $result
        !            58:     }
        !            59: 
        !            60:     if {$args == "{}"} {
        !            61:        catch {unset tk_priv(menusFor$w)}
        !            62:        return ""
        !            63:     }
        !            64: 
        !            65:     append tk_priv(menusFor$w) " $args"
        !            66: }
        !            67: 
        !            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.
        !            72: 
        !            73: proc tk_bindForTraversal args {
        !            74:     foreach w $args {
        !            75:        bind $w <Alt-KeyPress> {tk_traverseToMenu %W %A}
        !            76:        bind $w <F10> {tk_firstMenu %W}
        !            77:     }
        !            78: }
        !            79: 
        !            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.
        !            84: 
        !            85: proc tk_mbPost {w} {
        !            86:     global tk_priv
        !            87:     if {[lindex [$w config -state] 4] == "disabled"} {
        !            88:        return
        !            89:     }
        !            90:     set screen [winfo screen $w]
        !            91:     if {![info exists tk_priv(posted@$screen)]} {
        !            92:        set tk_priv(posted@$screen) {}
        !            93:     }
        !            94:     if {![info exists tk_priv(focus@$screen)]} {
        !            95:        set tk_priv(focus@$screen) {}
        !            96:     }
        !            97:     set cur $tk_priv(posted@$screen)
        !            98:     if {$cur == $w} {
        !            99:        return
        !           100:     }
        !           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
        !           106:     $w post
        !           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]
        !           111:     }
        !           112:     set menu [lindex [$w config -menu] 4]
        !           113:     focus $menu
        !           114: }
        !           115: 
        !           116: # The procedure below does all the work of unposting the menubutton that's
        !           117: # currently posted.  It takes no arguments.
        !           118: 
        !           119: proc tk_mbUnpost {w} {
        !           120:     global tk_priv
        !           121:     set screen [winfo screen $w]
        !           122:     if {![info exists tk_priv(posted@$screen)]} {
        !           123:        set tk_priv(posted@$screen) {}
        !           124:     }
        !           125:     if {![info exists tk_priv(focus@$screen)]} {
        !           126:        set tk_priv(focus@$screen) {}
        !           127:     }
        !           128:     set mb $tk_priv(posted@$screen)
        !           129:     if {$mb != ""} {
        !           130:        $mb config -relief $tk_priv(relief@$screen)
        !           131:        $mb config -cursor $tk_priv(cursor@$screen)
        !           132:        $mb unpost
        !           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) {}
        !           138:     }
        !           139: }
        !           140: 
        !           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
        !           148: # posts that menu.
        !           149: 
        !           150: proc tk_traverseToMenu {w char} {
        !           151:     if {$char == ""} {
        !           152:        return
        !           153:     }
        !           154:     set char [string tolower $char]
        !           155: 
        !           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} {
        !           161:                tk_mbPost $mb
        !           162:                [lindex [$mb config -menu] 4] activate 0
        !           163:                return
        !           164:            }
        !           165:        }
        !           166:     }
        !           167: }
        !           168: 
        !           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.
        !           174: 
        !           175: proc tk_traverseWithinMenu {w char} {
        !           176:     if {$char == ""} {
        !           177:        return
        !           178:     }
        !           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]]}] {
        !           185:            continue
        !           186:        }
        !           187:        if {[string compare $char [string tolower $char2]] == 0} {
        !           188:            tk_mbUnpost $w
        !           189:            $w invoke $i
        !           190:            return
        !           191:        }
        !           192:     }
        !           193: }
        !           194: 
        !           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.
        !           199: 
        !           200: proc tk_getMenuButtons {w} {
        !           201:     global tk_priv
        !           202:     set top [winfo toplevel $w]
        !           203:     if [catch {set buttons [set tk_priv(menusFor$top)]}] {
        !           204:        return ""
        !           205:     }
        !           206:     return $buttons
        !           207: }
        !           208: 
        !           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.
        !           213: 
        !           214: proc tk_nextMenu {w count} {
        !           215:     global tk_priv
        !           216:     set screen [winfo screen $w]
        !           217:     if {![info exists tk_priv(posted@$screen)]} {
        !           218:        set tk_priv(posted@$screen) {}
        !           219:     }
        !           220:     if {$tk_priv(posted@$screen) == ""} {
        !           221:        return
        !           222:     }
        !           223:     set buttons [tk_getMenuButtons $tk_priv(posted@$screen)]
        !           224:     set length [llength $buttons]
        !           225:     for {set i 0} 1 {incr i} {
        !           226:        if {$i >= $length} {
        !           227:            return
        !           228:        }
        !           229:        if {[lindex $buttons $i] == $tk_priv(posted@$screen)} {
        !           230:            break
        !           231:        }
        !           232:     }
        !           233:     incr i $count
        !           234:     while 1 {
        !           235:        while {$i < 0} {
        !           236:            incr i $length
        !           237:        }
        !           238:        while {$i >= $length} {
        !           239:            incr i -$length
        !           240:        }
        !           241:        set mb [lindex $buttons $i]
        !           242:        if {[lindex [$mb configure -state] 4] != "disabled"} {
        !           243:            break
        !           244:        }
        !           245:        incr i $count
        !           246:     }
        !           247:     tk_mbUnpost $w
        !           248:     tk_mbPost $mb
        !           249:     [lindex [$mb config -menu] 4] activate 0
        !           250: }
        !           251: 
        !           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.
        !           256: 
        !           257: proc tk_nextMenuEntry {w count} {
        !           258:     global tk_priv
        !           259:     set screen [winfo screen $w]
        !           260:     if {![info exists tk_priv(posted@$screen)]} {
        !           261:        set tk_priv(posted@$screen) {}
        !           262:     }
        !           263:     if {$tk_priv(posted@$screen) == ""} {
        !           264:        return
        !           265:     }
        !           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]
        !           269:     if {$i == "none"} {
        !           270:        set i 0
        !           271:     } else {
        !           272:        incr i $count
        !           273:     }
        !           274:     while 1 {
        !           275:        while {$i < 0} {
        !           276:            incr i $length
        !           277:        }
        !           278:        while {$i >= $length} {
        !           279:            incr i -$length
        !           280:        }
        !           281:        if {[catch {$menu entryconfigure $i -state} state] == 0} {
        !           282:            if {[lindex $state 4] != "disabled"} {
        !           283:                break
        !           284:            }
        !           285:        }
        !           286:        incr i $count
        !           287:     }
        !           288:     $menu activate $i
        !           289: }
        !           290: 
        !           291: # The procedure below invokes the active entry in the posted menu,
        !           292: # if there is one.  Otherwise it does nothing.
        !           293: 
        !           294: proc tk_invokeMenu {w} {
        !           295:     set i [$w index active]
        !           296:     if {$i != "none"} {
        !           297:        tk_mbUnpost $w
        !           298:        update idletasks
        !           299:        $w invoke $i
        !           300:     }
        !           301: }
        !           302: 
        !           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
        !           305: # parameter.
        !           306: 
        !           307: proc tk_firstMenu {w} {
        !           308:     set mb [lindex [tk_getMenuButtons $w] 0]
        !           309:     if {$mb != ""} {
        !           310:        tk_mbPost $mb
        !           311:        [lindex [$mb config -menu] 4] activate 0
        !           312:     }
        !           313: }
        !           314: 
        !           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.
        !           321: 
        !           322: proc tk_mbButtonDown {w x y} {
        !           323:     global tk_priv
        !           324:     set screen [winfo screen $w]
        !           325:     if {![info exists tk_priv(inMenuButton@$screen)]} {
        !           326:        set tk_priv(inMenuButton@$screen) {}
        !           327:     }
        !           328:     if {![info exists tk_priv(posted@$screen)]} {
        !           329:        set tk_priv(posted@$screen) {}
        !           330:     }
        !           331:     if {[lindex [$w config -state] 4] == "disabled"} {
        !           332:        return
        !           333:     } 
        !           334:     if {$tk_priv(inMenuButton@$screen) == $w} {
        !           335:        tk_mbPost $w
        !           336:     }
        !           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) {}
        !           341:        }
        !           342:        if {$tk_priv(window@$screen) != $menu} {
        !           343:            $menu activate none
        !           344:        }
        !           345:     }
        !           346: }
        !           347: 
        !           348: proc tk_mbButtonUp {w x y} {
        !           349:     global tk_priv
        !           350:     set screen [winfo screen $w]
        !           351:     if {![info exists tk_priv(inMenuButton@$screen)]} {
        !           352:        set tk_priv(inMenuButton@$screen) {}
        !           353:     }
        !           354:     if {![info exists tk_priv(posted@$screen)]} {
        !           355:        set tk_priv(posted@$screen) {}
        !           356:     }
        !           357:     if {($tk_priv(inMenuButton@$screen) != "") &&
        !           358:        ($tk_priv(posted@$screen) != "")} {
        !           359:        [lindex [$tk_priv(posted@$screen) config -menu] 4] activate 0
        !           360:     } else {
        !           361:        tk_mbUnpost $w
        !           362:     }
        !           363: }
        !           364: 
        !           365: proc tk_mbButtonEnter {w m} {
        !           366:     global tk_priv
        !           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
        !           371:     }
        !           372: }
        !           373: 
        !           374: proc tk_mbButtonLeave {w} {
        !           375:     global tk_priv
        !           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
        !           380:     }
        !           381: }
        !           382: 
        !           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.
        !           386: 
        !           387: proc tk_mbButton1Enter {w m} {
        !           388:     global tk_priv
        !           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
        !           394:        tk_mbPost $w
        !           395:     }
        !           396: }
        !           397: 
        !           398: 
        !           399: proc tk_mbButton2Down {w x y} {
        !           400:     global tk_priv
        !           401:     set screen [winfo screen $w]
        !           402:     if {![info exists tk_priv(inMenuButton@$screen)]} {
        !           403:        set tk_priv(inMenuButton@$screen) {}
        !           404:     }
        !           405:     if {![info exists tk_priv(posted@$screen)]} {
        !           406:        set tk_priv(posted@$screen) {}
        !           407:     }
        !           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
        !           412:     }
        !           413: }
        !           414: 
        !           415: 
        !           416: proc tk_mbButton2Motion {w x y} {
        !           417:     global tk_priv
        !           418:     set screen [winfo screen $w]
        !           419:     if {![info exists tk_priv(dragging@$screen)]} {
        !           420:        set tk_priv(dragging@$screen) {}
        !           421:     }
        !           422:     if {$tk_priv(dragging@$screen) != ""} {
        !           423:        [lindex [$tk_priv(dragging@$screen) config -menu] 4] post $x $y
        !           424:     }
        !           425: }
        !           426: 
        !           427: proc tk_mbButton2Up {w x y} {
        !           428:     global tk_priv
        !           429:     set screen [winfo screen $w]
        !           430:     set tk_priv(dragging@$screen) ""
        !           431: }
        !           432: 
        !           433: 
        !           434: proc tk_menuEnter {w y} {
        !           435:     global tk_priv
        !           436:     set screen [winfo screen $w]
        !           437:     set tk_priv(window@$screen) $w
        !           438:     $w activate @$y
        !           439: }
        !           440: 
        !           441: proc tk_menuLeave {w} {
        !           442:     global tk_priv
        !           443:     set screen [winfo screen $w]
        !           444:     set tk_priv(window@$screen) {}
        !           445:     $w activate none
        !           446: }
        !           447: 
        !           448: proc tk_menuMotion {w y} {
        !           449:     global tk_priv
        !           450:     set screen [winfo screen $w]
        !           451:     if {![info exists tk_priv(window@$screen)]} {
        !           452:        set tk_priv(window@$screen) {}
        !           453:     }
        !           454:     if {$tk_priv(window@$screen) != ""} {
        !           455:        $w activate @$y
        !           456:     }
        !           457: }
        !           458: 
        !           459: proc tk_menuUp {w y} {
        !           460:     tk_menuMotion $w $y
        !           461:     tk_invokeMenu $w
        !           462: }
        !           463: 
        !           464: proc tk_menu2Down {w x y} {
        !           465:     global tk_priv
        !           466:     set screen [winfo screen $w]
        !           467:     set tk_priv(x@$screen) $x
        !           468:     set tk_priv(y@$screen) $y
        !           469: }
        !           470: 
        !           471: proc tk_menu2Motion {w x y} {
        !           472:     global tk_priv
        !           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)]
        !           476:     }
        !           477: }
        !           478: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.