summaryrefslogtreecommitdiff
path: root/itcl/iwidgets/generic/menubar.itk
diff options
context:
space:
mode:
authorMartin M. Hunt <hunt@redhat.com>2003-01-21 20:42:51 +0000
committerMartin M. Hunt <hunt@redhat.com>2003-01-21 20:42:51 +0000
commit5601295b75f82401817b35387a9843a18a9ae357 (patch)
treefa1af8d7a69fc5757f91d1a9130e5189e6badc3d /itcl/iwidgets/generic/menubar.itk
parent112d7d270bc1e8172fa502c794d7872a27ab5b77 (diff)
downloadgdb-5601295b75f82401817b35387a9843a18a9ae357.tar.gz
imported itcl 3.2.1ITCL3_2_1
Diffstat (limited to 'itcl/iwidgets/generic/menubar.itk')
-rw-r--r--itcl/iwidgets/generic/menubar.itk2267
1 files changed, 2267 insertions, 0 deletions
diff --git a/itcl/iwidgets/generic/menubar.itk b/itcl/iwidgets/generic/menubar.itk
new file mode 100644
index 00000000000..ca2d2001075
--- /dev/null
+++ b/itcl/iwidgets/generic/menubar.itk
@@ -0,0 +1,2267 @@
+#
+# Menubar widget
+# ----------------------------------------------------------------------
+# The Menubar command creates a new window (given by the pathName
+# argument) and makes it into a Pull down menu widget. Additional
+# options, described above may be specified on the command line or
+# in the option database to configure aspects of the Menubar such
+# as its colors and font. The Menubar command returns its pathName
+# argument. At the time this command is invoked, there must not exist
+# a window named pathName, but pathName's parent must exist.
+#
+# A Menubar is a widget that simplifies the task of creating
+# menu hierarchies. It encapsulates a frame widget, as well
+# as menubuttons, menus, and menu entries. The Menubar allows
+# menus to be specified and refer enced in a more consistent
+# manner than using Tk to build menus directly. First, Menubar
+# allows a menu tree to be expressed in a hierachical "language".
+# The Menubar accepts a menuButtons option that allows a list of
+# menubuttons to be added to the Menubar. In turn, each menubutton
+# accepts a menu option that spec ifies a list of menu entries
+# to be added to the menubutton's menu (as well as an option
+# set for the menu). Cascade entries in turn, accept a menu
+# option that specifies a list of menu entries to be added to
+# the cascade's menu (as well as an option set for the menu). In
+# this manner, a complete menu grammar can be expressed to the
+# Menubar. Additionally, the Menubar allows each component of
+# the Menubar system to be referenced by a simple componentPathName
+# syntax. Finally, the Menubar extends the option set of menu
+# entries to include the helpStr option used to implement status
+# bar help.
+#
+# WISH LIST:
+# This section lists possible future enhancements.
+#
+# ----------------------------------------------------------------------
+# AUTHOR: Bill W. Scott
+#
+# CURRENT MAINTAINER: Chad Smith --> csmith@adc.com or itclguy@yahoo.com
+#
+# @(#) $Id$
+# ----------------------------------------------------------------------
+# Copyright (c) 1995 DSC Technologies Corporation
+# ======================================================================
+# Permission to use, copy, modify, distribute and license this software
+# and its documentation for any purpose, and without fee or written
+# agreement with DSC, is hereby granted, provided that the above copyright
+# notice appears in all copies and that both the copyright notice and
+# warranty disclaimer below appear in supporting documentation, and that
+# the names of DSC Technologies Corporation or DSC Communications
+# Corporation not be used in advertising or publicity pertaining to the
+# software without specific, written prior permission.
+#
+# DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
+# INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
+# AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL
+# DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
+# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+# SOFTWARE.
+# ======================================================================
+
+
+#
+# Usual options.
+#
+itk::usual Menubar {
+ keep -activebackground -activeborderwidth -activeforeground \
+ -anchor -background -borderwidth -cursor -disabledforeground \
+ -font -foreground -highlightbackground -highlightthickness \
+ -highlightcolor -justify -padx -pady -wraplength
+}
+
+itcl::class iwidgets::Menubar {
+ inherit itk::Widget
+
+ constructor { args } {}
+
+ itk_option define -foreground foreground Foreground Black
+ itk_option define -activebackground activeBackground Foreground "#ececec"
+ itk_option define -activeborderwidth activeBorderWidth BorderWidth 2
+ itk_option define -activeforeground activeForeground Background black
+ itk_option define -anchor anchor Anchor center
+ itk_option define -borderwidth borderWidth BorderWidth 2
+ itk_option define \
+ -disabledforeground disabledForeground DisabledForeground #a3a3a3
+ itk_option define \
+ -font font Font "-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*"
+ itk_option define \
+ -highlightbackground highlightBackground HighlightBackground #d9d9d9
+ itk_option define -highlightcolor highlightColor HighlightColor Black
+ itk_option define \
+ -highlightthickness highlightThickness HighlightThickness 0
+ itk_option define -justify justify Justify center
+ itk_option define -padx padX Pad 4p
+ itk_option define -pady padY Pad 3p
+ itk_option define -wraplength wrapLength WrapLength 0
+ itk_option define -menubuttons menuButtons MenuButtons {}
+ itk_option define -helpvariable helpVariable HelpVariable {}
+
+ public {
+ method add { type path args } { }
+ method delete { args } { }
+ method index { path } { }
+ method insert { beforeComponent type name args }
+ method invoke { entryPath } { }
+ method menucget { args } { }
+ method menuconfigure { path args } { }
+ method path { args } { }
+ method type { path } { }
+ method yposition { entryPath } { }
+ }
+
+ private {
+ method menubutton { menuName args } { }
+ method options { args } { }
+ method command { cmdName args } { }
+ method checkbutton { chkName args } { }
+ method radiobutton { radName args } { }
+ method separator { sepName args } { }
+ method cascade { casName args } { }
+ method _helpHandler { menuPath } { }
+ method _addMenuButton { buttonName args} { }
+ method _insertMenuButton { beforeMenuPath buttonName args} { }
+ method _makeMenuButton {buttonName args} { }
+ method _makeMenu \
+ { componentName widgetName menuPath menuEvalStr } { }
+ method _substEvalStr { evalStr } { }
+ method _deleteMenu { menuPath {menuPath2 {}} } { }
+ method _deleteAMenu { path } { }
+ method _addEntry { type path args } { }
+ method _addCascade { tkMenuPath path args } { }
+ method _insertEntry { beforeEntryPath type name args } { }
+ method _insertCascade { bfIndex tkMenuPath path args } { }
+ method _deleteEntry { entryPath {entryPath2 {}} } { }
+ method _configureMenu { path tkPath {option {}} args } { }
+ method _configureMenuOption { type path args } { }
+ method _configureMenuEntry { path index {option {}} args } { }
+ method _unsetPaths { parent } { }
+ method _entryPathToTkMenuPath {entryPath} { }
+ method _getTkIndex { tkMenuPath tkIndex} { }
+ method _getPdIndex { tkMenuPath tkIndex } { }
+ method _getMenuList { } { }
+ method _getEntryList { menu } { }
+ method _parsePath { path } { }
+ method _getSymbolicPath { parent segment } { }
+ method _getCallerLevel { }
+
+ variable _parseLevel 0 ;# The parse level depth
+ variable _callerLevel #0 ;# abs level of caller
+ variable _pathMap ;# Array indexed by Menubar's path
+ ;# naming, yields tk menu path
+ variable _entryIndex -1 ;# current entry help is displayed
+ ;# for during help <motion> events
+
+ variable _tkMenuPath ;# last tk menu being added to
+ variable _ourMenuPath ;# our last valid path constructed.
+
+ variable _menuOption ;# The -menu option
+ variable _helpString ;# The -helpstr optio
+ }
+}
+
+#
+# Use option database to override default resources.
+#
+option add *Menubar*Menu*tearOff false widgetDefault
+option add *Menubar*Menubutton*relief flat widgetDefault
+option add *Menubar*Menu*relief raised widgetDefault
+
+#
+# Provide a lowercase access method for the menubar class
+#
+proc ::iwidgets::menubar { args } {
+ uplevel ::iwidgets::Menubar $args
+}
+
+# ------------------------------------------------------------------
+# CONSTRUCTOR
+# ------------------------------------------------------------------
+itcl::body iwidgets::Menubar::constructor { args } {
+ component hull configure -borderwidth 0
+
+ #
+ # Create the Menubar Frame that will hold the menus.
+ #
+ # might want to make -relief and -bd options with defaults
+ itk_component add menubar {
+ frame $itk_interior.menubar -relief raised -bd 2
+ } {
+ keep -cursor -background -width -height
+ }
+ pack $itk_component(menubar) -fill both -expand yes
+
+ # Map our pathname to class to the actual menubar frame
+ set _pathMap(.) $itk_component(menubar)
+
+ eval itk_initialize $args
+
+ #
+ # HACK HACK HACK
+ # Tk expects some variables to be defined and due to some
+ # unknown reason we confuse its normal ordering. So, if
+ # the user creates a menubutton with no menu it will fail
+ # when clicked on with a "Error: can't read $tkPriv(oldGrab):
+ # no such element in array". So by setting it to null we
+ # avoid this error.
+ uplevel #0 "set tkPriv(oldGrab) {}"
+
+}
+
+# ------------------------------------------------------------------
+# OPTIONS
+# ------------------------------------------------------------------
+# This first set of options are for configuring menus and/or menubuttons
+# at the menu level.
+#
+# ------------------------------------------------------------------
+# OPTION -foreground
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::foreground {
+}
+
+# ------------------------------------------------------------------
+# OPTION -activebackground
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::activebackground {
+}
+
+# ------------------------------------------------------------------
+# OPTION -activeborderwidth
+#
+# menu
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::activeborderwidth {
+}
+
+# ------------------------------------------------------------------
+# OPTION -activeforeground
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::activeforeground {
+}
+
+# ------------------------------------------------------------------
+# OPTION -anchor
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::anchor {
+}
+
+# ------------------------------------------------------------------
+# OPTION -borderwidth
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::borderwidth {
+}
+
+# ------------------------------------------------------------------
+# OPTION -disabledforeground
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::disabledforeground {
+}
+
+# ------------------------------------------------------------------
+# OPTION -font
+#
+# menu
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::font {
+}
+
+# ------------------------------------------------------------------
+# OPTION -highlightbackground
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::highlightbackground {
+}
+
+# ------------------------------------------------------------------
+# OPTION -highlightcolor
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::highlightcolor {
+}
+
+# ------------------------------------------------------------------
+# OPTION -highlightthickness
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::highlightthickness {
+}
+
+# ------------------------------------------------------------------
+# OPTION -justify
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::justify {
+}
+
+# ------------------------------------------------------------------
+# OPTION -padx
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::padx {
+}
+
+# ------------------------------------------------------------------
+# OPTION -pady
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::pady {
+}
+
+# ------------------------------------------------------------------
+# OPTION -wraplength
+#
+# menubutton
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::wraplength {
+}
+
+# ------------------------------------------------------------------
+# OPTION -menubuttons
+#
+# The menuButton option is a string which specifies the arrangement
+# of menubuttons on the Menubar frame. Each menubutton entry is
+# delimited by the newline character. Each entry is treated as
+# an add command to the Menubar.
+#
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::menubuttons {
+ if { $itk_option(-menubuttons) != {} } {
+
+ # IF one exists already, delete the old one and create
+ # a new one
+ if { ! [catch {_parsePath .0}] } {
+ delete .0 .last
+ }
+
+ #
+ # Determine the context level to evaluate the option string at
+ #
+ set _callerLevel [_getCallerLevel]
+
+ #
+ # Parse the option string in their scope, then execute it in
+ # our scope.
+ #
+ incr _parseLevel
+ _substEvalStr itk_option(-menubuttons)
+ eval $itk_option(-menubuttons)
+
+ # reset so that we know we aren't parsing in a scope currently.
+ incr _parseLevel -1
+ }
+}
+
+# ------------------------------------------------------------------
+# OPTION -helpvariable
+#
+# Specifies the global variable to update whenever the mouse is in
+# motion over a menu entry. This global variable is updated with the
+# current value of the active menu entry's helpStr. Other widgets
+# can "watch" this variable with the trace command, or as is the
+# case with entry or label widgets, they can set their textVariable
+# to the same global variable. This allows for a simple implementation
+# of a help status bar. Whenever the mouse leaves a menu entry,
+# the helpVariable is set to the empty string {}.
+# ------------------------------------------------------------------
+itcl::configbody iwidgets::Menubar::helpvariable {
+ if {"" != $itk_option(-helpvariable) &&
+ ![string match ::* $itk_option(-helpvariable)] &&
+ ![string match @itcl* $itk_option(-helpvariable)]} {
+ set itk_option(-helpvariable) "::$itk_option(-helpvariable)"
+ }
+}
+
+
+# -------------------------------------------------------------
+#
+# METHOD: add type path args
+#
+# Adds either a menu to the menu bar or a menu entry to a
+# menu pane.
+#
+# If the type is one of cascade, checkbutton, command,
+# radiobutton, or separator it adds a new entry to the bottom
+# of the menu denoted by the menuPath prefix of componentPath-
+# Name. The new entry's type is given by type. If additional
+# arguments are present, they specify options available to
+# component type Entry. See the man pages for menu(n) in the
+# section on Entries. In addition all entries accept an added
+# option, helpStr:
+#
+# -helpstr value
+#
+# Specifes the string to associate with the entry.
+# When the mouse moves over the associated entry, the variable
+# denoted by helpVariable is set. Another widget can bind to
+# the helpVariable and thus display status help.
+#
+# If the type is menubutton, it adds a new menubut-
+# ton to the menu bar. If additional arguments are present,
+# they specify options available to component type MenuButton.
+#
+# If the type is menubutton or cascade, the menu
+# option is available in addition to normal Tk options for
+# these to types.
+#
+# -menu menuSpec
+#
+# This is only valid for componentPathNames of type
+# menubutton or cascade. Specifes an option set and/or a set
+# of entries to place on a menu and associate with the menu-
+# button or cascade. The option keyword allows the menu widget
+# to be configured. Each item in the menuSpec is treated as
+# add commands (each with the possibility of having other
+# -menu options). In this way a menu can be recursively built.
+#
+# The last segment of componentPathName cannot be
+# one of the keywords last, menu, end. Additionally, it may
+# not be a number. However the componentPathName may be refer-
+# enced in this manner (see discussion of Component Path
+# Names).
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::add { type path args } {
+ if ![regexp \
+ {^(menubutton|command|cascade|separator|radiobutton|checkbutton)$} \
+ $type] {
+ error "bad type \"$type\": must be one of the following:\
+ \"command\", \"checkbutton\", \"radiobutton\",\
+ \"separator\", \"cascade\", or \"menubutton\""
+ }
+ regexp {[^.]+$} $path segName
+ if [regexp {^(menu|last|end|[0-9]+)$} $segName] {
+ error "bad name \"$segName\": user created component \
+ path names may not end with \
+ \"end\", \"last\", \"menu\", \
+ or be an integer"
+ }
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # OK, either add a menu
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { $type == "menubutton" } {
+ # grab the last component name (the menu name)
+ eval _addMenuButton $segName $args
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Or add an entry
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ } else {
+ eval _addEntry $type $path $args
+ }
+}
+
+
+# -------------------------------------------------------------
+#
+# METHOD: delete entryPath ?entryPath2?
+#
+# If componentPathName is of component type MenuButton or
+# Menu, delete operates on menus. If componentPathName is of
+# component type Entry, delete operates on menu entries.
+#
+# This command deletes all components between com-
+# ponentPathName and componentPathName2 inclusive. If com-
+# ponentPathName2 is omitted then it defaults to com-
+# ponentPathName. Returns an empty string.
+#
+# If componentPathName is of type Menubar, then all menus
+# and the menu bar frame will be destroyed. In this case com-
+# ponentPathName2 is ignored.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::delete { args } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Handle out of bounds in arg lengths
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [llength $args] > 0 && [llength $args] <=2 } {
+
+ # Path Conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set path [_parsePath [lindex $args 0]]
+
+ set pathOrIndex $_pathMap($path)
+
+ # Menu Entry
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [regexp {^[0-9]+$} $pathOrIndex] } {
+ eval "_deleteEntry $args"
+
+ # Menu
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ } else {
+ eval "_deleteMenu $args"
+ }
+ } else {
+ error "wrong # args: should be \
+ \"$itk_component(hull) delete pathName ?pathName2?\""
+ }
+ return ""
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: index path
+#
+# If componentPathName is of type menubutton or menu, it
+# returns the position of the menu/menubutton on the Menubar
+# frame.
+#
+# If componentPathName is of type command, separator,
+# radiobutton, checkbutton, or cascade, it returns the menu
+# widget's numerical index for the entry corresponding to com-
+# ponentPathName. If path is not found or the Menubar frame is
+# passed in, -1 is returned.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::index { path } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Path conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [catch {set fullPath [_parsePath $path]} ] } {
+ return -1
+ }
+ if { [catch {set tkPathOrIndex $_pathMap($fullPath)} ] } {
+ return -1
+ }
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # If integer, return the value, otherwise look up the menu position
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [regexp {^[0-9]+$} $tkPathOrIndex] } {
+ set index $tkPathOrIndex
+ } else {
+ set index [lsearch [_getMenuList] $fullPath]
+ }
+
+ return $index
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: insert beforeComponent type name ?option value?
+#
+# Insert a new component named name before the component
+# specified by componentPathName.
+#
+# If componentPathName is of type MenuButton or Menu, the
+# new component inserted is of type Menu and given the name
+# name. In this case valid option value pairs are those
+# accepted by menubuttons.
+#
+# If componentPathName is of type Entry, the new com-
+# ponent inserted is of type Entry and given the name name. In
+# this case valid option value pairs are those accepted by
+# menu entries.
+#
+# name cannot be one of the keywords last, menu, end.
+# dditionally, it may not be a number. However the com-
+# ponentPathName may be referenced in this manner (see discus-
+# sion of Component Path Names).
+#
+# Returns -1 if the menubar frame is passed in.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::insert { beforeComponent type name args } {
+ if ![regexp \
+ {^(menubutton|command|cascade|separator|radiobutton|checkbutton)$} \
+ $type] {
+ error "bad type \"$type\": must be one of the following:\
+ \"command\", \"checkbutton\", \"radiobutton\",\
+ \"separator\", \"cascade\", or \"menubutton\""
+ }
+ regexp {[^.]+$} $name segName
+ if [regexp {^(menu|last|end|[0-9]+)$} $segName] {
+ error "bad name \"$name\": user created component \
+ path names may not end with \
+ \"end\", \"last\", \"menu\", \
+ or be an integer"
+ }
+
+ set beforeComponent [_parsePath $beforeComponent]
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Choose menu insertion or entry insertion
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { $type == "menubutton" } {
+ eval _insertMenuButton $beforeComponent $name $args
+ } else {
+ eval _insertEntry $beforeComponent $type $name $args
+ }
+}
+
+
+# -------------------------------------------------------------
+#
+# METHOD: invoke entryPath
+#
+# Invoke the action of the menu entry denoted by
+# entryComponentPathName. See the sections on the individual
+# entries in the menu(n) man pages. If the menu entry is dis-
+# abled then nothing happens. If the entry has a command
+# associated with it then the result of that command is
+# returned as the result of the invoke widget command. Other-
+# wise the result is an empty string.
+#
+# If componentPathName is not a menu entry, an error is
+# issued.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::invoke { entryPath } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Path Conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set entryPath [_parsePath $entryPath]
+ set index $_pathMap($entryPath)
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Error Processing
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ # first verify that beforeEntryPath is actually a path to
+ # an entry and not to menu, menubutton, etc.
+ if { ! [regexp {^[0-9]+$} $index] } {
+ error "bad entry path: beforeEntryPath is not an entry"
+ }
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Call invoke command
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ # get the tk menu path to call
+ set tkMenuPath [_entryPathToTkMenuPath $entryPath]
+
+ # call the menu's invoke command, adjusting index based on tearoff
+ $tkMenuPath invoke [_getTkIndex $tkMenuPath $index]
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: menucget componentPath option
+#
+# Returns the current value of the configuration option
+# given by option. The component type of componentPathName
+# determines the valid available options.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::menucget { path opt } {
+ return [lindex [menuconfigure $path $opt] 4]
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: menuconfigure componentPath ?option? ?value option value...?
+#
+# Query or modify the configuration options of the sub-
+# component of the Menubar specified by componentPathName. If
+# no option is specified, returns a list describing all of the
+# available options for componentPathName (see
+# Tk_ConfigureInfo for information on the format of this
+# list). If option is specified with no value, then the com-
+# mand returns a list describing the one named option (this
+# list will be identical to the corresponding sublist of the
+# value returned if no option is specified). If one or more
+# option-value pairs are specified, then the command modifies
+# the given widget option(s) to have the given value(s); in
+# this case the command returns an empty string. The component
+# type of componentPathName determines the valid available
+# options.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::menuconfigure { path args } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Path Conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set path [_parsePath $path]
+ set tkPathOrIndex $_pathMap($path)
+
+ # Case: Menu entry being configured
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [regexp {^[0-9]+$} $tkPathOrIndex] } {
+ eval "_configureMenuEntry $path $tkPathOrIndex $args"
+
+ # Case: Menu (button and pane) being configured.
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ } else {
+ eval _configureMenu $path $tkPathOrIndex $args
+ }
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: path
+#
+# SYNOPIS: path ?<mode>? <pattern>
+#
+# Returns a fully formed component path that matches pat-
+# tern. If no match is found it returns -1. The mode argument
+# indicates how the search is to be matched against pattern
+# and it must have one of the following values:
+#
+# -glob Pattern is a glob-style pattern which is
+# matched against each component path using the same rules as
+# the string match command.
+#
+# -regexp Pattern is treated as a regular expression
+# and matched against each component path using the same
+# rules as the regexp command.
+#
+# The default mode is -glob.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::path { args } {
+
+ set len [llength $args]
+ if { $len < 1 || $len > 2 } {
+ error "wrong # args: should be \
+ \"$itk_component(hull) path ?mode?> <pattern>\""
+ }
+
+ set pathList [array names _pathMap]
+
+ set len [llength $args]
+ switch -- $len {
+ 1 {
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Case: no search modes given
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set pattern [lindex $args 0]
+ set found [lindex $pathList [lsearch -glob $pathList $pattern]]
+ }
+ 2 {
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Case: search modes present (-glob, -regexp)
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set options [lindex $args 0]
+ set pattern [lindex $args 1]
+ set found \
+ [lindex $pathList [lsearch $options $pathList $pattern]]
+ }
+ default {
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Case: wrong # arguments
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ error "wrong # args: \
+ should be \"$itk_component(hull) path ?-glob? ?-regexp? pattern\""
+ }
+ }
+
+ return $found
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: type path
+#
+# Returns the type of the component given by entryCom-
+# ponentPathName. For menu entries, this is the type argument
+# passed to the add/insert widget command when the entry was
+# created, such as command or separator. Othewise it is either
+# a menubutton or a menu.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::type { path } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Path Conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set path [_parsePath $path]
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Error Handling: does the path exist?
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [catch {set index $_pathMap($path)} ] } {
+ error "bad path \"$path\""
+ }
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # ENTRY, Ask TK for type
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ if { [regexp {^[0-9]+$} $index] } {
+ # get the menu path from the entry path name
+ set tkMenuPath [_entryPathToTkMenuPath $path]
+
+ # call the menu's type command, adjusting index based on tearoff
+ set type [$tkMenuPath type [_getTkIndex $tkMenuPath $index]]
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # MENUBUTTON, MENU, or FRAME
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ } else {
+ # should not happen, but have a path that is not a valid window.
+ if { [catch {set className [winfo class $_pathMap($path)]}] } {
+ error "serious error: \"$path\" is not a valid window"
+ }
+ # get the classname, look it up, get index, us it to look up type
+ set type [ lindex \
+ {frame menubutton menu} \
+ [lsearch { Frame Menubutton Menu } $className] \
+ ]
+ }
+ return $type
+}
+
+# -------------------------------------------------------------
+#
+# METHOD: yposition entryPath
+#
+# Returns a decimal string giving the y-coordinate within
+# the menu window of the topmost pixel in the entry specified
+# by componentPathName. If the componentPathName is not an
+# entry, an error is issued.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::yposition { entryPath } {
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Path Conversions
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ set entryPath [_parsePath $entryPath]
+ set index $_pathMap($entryPath)
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Error Handling
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ # first verify that entryPath is actually a path to
+ # an entry and not to menu, menubutton, etc.
+ if { ! [regexp {^[0-9]+$} $index] } {
+ error "bad value: entryPath is not an entry"
+ }
+
+ # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Call yposition command
+ # '''''''''''''''''''''''''''''''''''''''''''''''''''''
+ # get the menu path from the entry path name
+ set tkMenuPath [_entryPathToTkMenuPath $entryPath]
+
+ # call the menu's yposition command, adjusting index based on tearoff
+ return [$tkMenuPath yposition [_getTkIndex $tkMenuPath $index]]
+
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# PARSING METHODS
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# -------------------------------------------------------------
+#
+# PARSING METHOD: menubutton
+#
+# This method is invoked via an evaluation of the -menubuttons
+# option for the Menubar.
+#
+# It adds a new menubutton and processes any -menu options
+# for creating entries on the menu pane associated with the
+# menubutton
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::menubutton { menuName args } {
+ eval "add menubutton .$menuName $args"
+}
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: options
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton commands.
+#
+# It configures the current menu ($_ourMenuPath) with the options
+# that follow (args)
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::options { args } {
+ eval "$_tkMenuPath configure $args"
+}
+
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: command
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton commands.
+#
+# It adds a new command entry to the current menu, $_ourMenuPath
+# naming it $cmdName. Since this is the most common case when
+# creating menus, streamline it by duplicating some code from
+# the add{} method.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::command { cmdName args } {
+ set path $_ourMenuPath.$cmdName
+
+ # error checking
+ regsub {.*[.]} $path "" segName
+ if [regexp {^(menu|last|end|[0-9]+)$} $segName] {
+ error "bad name \"$segName\": user created component \
+ path names may not end with \
+ \"end\", \"last\", \"menu\", \
+ or be an integer"
+ }
+
+ eval _addEntry command $path $args
+}
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: checkbutton
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton/cascade commands.
+#
+# It adds a new checkbutton entry to the current menu, $_ourMenuPath
+# naming it $chkName.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::checkbutton { chkName args } {
+ eval "add checkbutton $_ourMenuPath.$chkName $args"
+}
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: radiobutton
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton/cascade commands.
+#
+# It adds a new radiobutton entry to the current menu, $_ourMenuPath
+# naming it $radName.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::radiobutton { radName args } {
+ eval "add radiobutton $_ourMenuPath.$radName $args"
+}
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: separator
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton/cascade commands.
+#
+# It adds a new separator entry to the current menu, $_ourMenuPath
+# naming it $sepName.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::separator { sepName args } {
+ eval $_tkMenuPath add separator
+ set _pathMap($_ourMenuPath.$sepName) [_getPdIndex $_tkMenuPath end]
+}
+
+# -------------------------------------------------------------
+#
+# PARSING METHOD: cascade
+#
+# This method is invoked via an evaluation of the -menu
+# option for menubutton/cascade commands.
+#
+# It adds a new cascade entry to the current menu, $_ourMenuPath
+# naming it $casName. It processes the -menu option if present,
+# adding a new menu pane and its associated entries found.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::cascade { casName args } {
+
+ # Save the current menu we are adding to, cascade can change
+ # the current menu through -menu options.
+ set saveOMP $_ourMenuPath
+ set saveTKP $_tkMenuPath
+
+ eval "add cascade $_ourMenuPath.$casName $args"
+
+ # Restore the saved menu states so that the next entries of
+ # the -menu/-menubuttons we are processing will be at correct level.
+ set _ourMenuPath $saveOMP
+ set _tkMenuPath $saveTKP
+}
+
+# ... A P I S U P P O R T M E T H O D S...
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# MENU ADD, INSERT, DELETE
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _addMenuButton
+#
+# Makes a new menubutton & associated -menu, pack appended
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_addMenuButton { buttonName args} {
+
+ eval "_makeMenuButton $buttonName $args"
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Pack at end, adjust for help buttonName
+ # ''''''''''''''''''''''''''''''''''
+ if { $buttonName == "help" } {
+ pack $itk_component($buttonName) -side right
+ } else {
+ pack $itk_component($buttonName) -side left
+ }
+
+ return $itk_component($buttonName)
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _insertMenuButton
+#
+# inserts a menubutton named $buttonName on a menu bar before
+# another menubutton specified by $beforeMenuPath
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_insertMenuButton { beforeMenuPath buttonName args} {
+
+ eval "_makeMenuButton $buttonName $args"
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Pack before the $beforeMenuPath
+ # ''''''''''''''''''''''''''''''''
+ set beforeTkMenu $_pathMap($beforeMenuPath)
+ regsub {[.]menu$} $beforeTkMenu "" beforeTkMenu
+ pack $itk_component(menubar).$buttonName \
+ -side left \
+ -before $beforeTkMenu
+
+ return $itk_component($buttonName)
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _makeMenuButton
+#
+# creates a menubutton named buttonName on the menubar with args.
+# The -menu option if present will trigger attaching a menu pane.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_makeMenuButton {buttonName args} {
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Capture the -menu option if present
+ # '''''''''''''''''''''''''''''''''''
+ array set temp $args
+ if { [::info exists temp(-menu)] } {
+ # We only keep this in case of menuconfigure or menucget
+ set _menuOption(.$buttonName) $temp(-menu)
+ set menuEvalStr $temp(-menu)
+ } else {
+ set menuEvalStr {}
+ }
+
+ # attach the actual menu widget to the menubutton's arg list
+ set temp(-menu) $itk_component(menubar).$buttonName.menu
+ set args [array get temp]
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Create menubutton component
+ # ''''''''''''''''''''''''''''''''
+ itk_component add $buttonName {
+ eval ::menubutton \
+ $itk_component(menubar).$buttonName \
+ $args
+ } {
+ keep \
+ -activebackground \
+ -activeforeground \
+ -anchor \
+ -background \
+ -borderwidth \
+ -cursor \
+ -disabledforeground \
+ -font \
+ -foreground \
+ -highlightbackground \
+ -highlightcolor \
+ -highlightthickness \
+ -justify \
+ -padx \
+ -pady \
+ -wraplength
+ }
+
+ set _pathMap(.$buttonName) $itk_component($buttonName)
+
+ _makeMenu \
+ $buttonName-menu \
+ $itk_component($buttonName).menu \
+ .$buttonName \
+ $menuEvalStr
+
+ return $itk_component($buttonName)
+
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _makeMenu
+#
+# Creates a menu.
+# It then evaluates the $menuEvalStr to create entries on the menu.
+#
+# Assumes the existence of $itk_component($buttonName)
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_makeMenu \
+ { componentName widgetName menuPath menuEvalStr } {
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Create menu component
+ # ''''''''''''''''''''''''''''''''
+ itk_component add $componentName {
+ ::menu $widgetName
+ } {
+ keep \
+ -activebackground \
+ -activeborderwidth \
+ -activeforeground \
+ -background \
+ -borderwidth \
+ -cursor \
+ -disabledforeground \
+ -font \
+ -foreground
+ }
+
+ set _pathMap($menuPath.menu) $itk_component($componentName)
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Attach help handler to this menu
+ # ''''''''''''''''''''''''''''''''
+ bind $itk_component($componentName) <<MenuSelect>> \
+ [itcl::code $this _helpHandler $menuPath.menu]
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Handle -menu
+ #'''''''''''''''''''''''''''''''''
+ set _ourMenuPath $menuPath
+ set _tkMenuPath $itk_component($componentName)
+
+ #
+ # A zero parseLevel says we are at the top of the parse tree,
+ # so get the context scope level and do a subst for the menuEvalStr.
+ #
+ if { $_parseLevel == 0 } {
+ set _callerLevel [_getCallerLevel]
+ }
+
+ #
+ # bump up the parse level, so if we get called via the 'eval $menuEvalStr'
+ # we know to skip the above steps...
+ #
+ incr _parseLevel
+ eval $menuEvalStr
+
+ #
+ # leaving, so done with this parse level, so bump it back down
+ #
+ incr _parseLevel -1
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _substEvalStr
+#
+# This performs the substitution and evaluation of $ [], \ found
+# in the -menubutton/-menus options
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_substEvalStr { evalStr } {
+ upvar $evalStr evalStrRef
+ set evalStrRef [uplevel $_callerLevel [list subst $evalStrRef]]
+}
+
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _deleteMenu
+#
+# _deleteMenu menuPath ?menuPath2?
+#
+# deletes menuPath or from menuPath to menuPath2
+#
+# Menu paths may be formed in one of two ways
+# .MENUBAR.menuName where menuName is the name of the menu
+# .MENUBAR.menuName.menu where menuName is the name of the menu
+#
+# The basic rule is '.menu' is not needed.
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_deleteMenu { menuPath {menuPath2 {}} } {
+
+ if { $menuPath2 == "" } {
+ # get a corrected path (subst for number, last, end)
+ set path [_parsePath $menuPath]
+
+ _deleteAMenu $path
+
+ } else {
+ # gets the list of menus in interface order
+ set menuList [_getMenuList]
+
+ # ... get the start menu and the last menu ...
+
+ # get a corrected path (subst for number, last, end)
+ set menuStartPath [_parsePath $menuPath]
+
+ regsub {[.]menu$} $menuStartPath "" menuStartPath
+
+ set menuEndPath [_parsePath $menuPath2]
+
+ regsub {[.]menu$} $menuEndPath "" menuEndPath
+
+ # get the menu position (0 based) of the start and end menus.
+ set start [lsearch -exact $menuList $menuStartPath]
+ if { $start == -1 } {
+ error "bad menu path \"$menuStartPath\": \
+ should be one of $menuList"
+ }
+ set end [lsearch -exact $menuList $menuEndPath]
+ if { $end == -1 } {
+ error "bad menu path \"$menuEndPath\": \
+ should be one of $menuList"
+ }
+
+ # now create the list from this range of menus
+ set delList [lrange $menuList $start $end]
+
+ # walk thru them deleting each menu.
+ # this list has no .menu on the end.
+ foreach m $delList {
+ _deleteAMenu $m.menu
+ }
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _deleteAMenu
+#
+# _deleteMenu menuPath
+#
+# deletes a single Menu (menubutton and menu pane with entries)
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_deleteAMenu { path } {
+
+ # We will normalize the path to not include the '.menu' if
+ # it is on the path already.
+
+ regsub {[.]menu$} $path "" menuButtonPath
+ regsub {.*[.]} $menuButtonPath "" buttonName
+
+ # Loop through and destroy any cascades, etc on menu.
+ set entryList [_getEntryList $menuButtonPath]
+ foreach entry $entryList {
+ _deleteEntry $entry
+ }
+
+ # Delete the menubutton and menu components...
+ destroy $itk_component($buttonName-menu)
+ destroy $itk_component($buttonName)
+
+ # This is because of some itcl bug that doesn't delete
+ # the component on the destroy in some cases...
+ catch {itk_component delete $buttonName-menu}
+ catch {itk_component delete $buttonName}
+
+ # unset our paths
+ _unsetPaths $menuButtonPath
+
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# ENTRY ADD, INSERT, DELETE
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _addEntry
+#
+# Adds an entry to menu.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_addEntry { type path args } {
+
+ # Error Checking
+ # ''''''''''''''
+ # the path should not end with '.menu'
+ # Not needed -- already checked by add{}
+ # if { [regexp {[.]menu$} $path] } {
+ # error "bad entry path: \"$path\". \
+ # The name \"menu\" is reserved for menu panes"
+ # }
+
+ # get the tkMenuPath
+ set tkMenuPath [_entryPathToTkMenuPath $path]
+ if { $tkMenuPath == "" } {
+ error "bad entry path: \"$path\". The menu path prefix is not valid"
+ }
+
+ # get the -helpstr option if present
+ array set temp $args
+ if { [::info exists temp(-helpstr)] } {
+ set helpStr $temp(-helpstr)
+ unset temp(-helpstr)
+ } else {
+ set helpStr {}
+ }
+ set args [array get temp]
+
+ # Handle CASCADE
+ # ''''''''''''''
+ # if this is a cascade go ahead and add in the menu...
+ if { $type == "cascade" } {
+ eval [list _addCascade $tkMenuPath $path] $args
+ # Handle Non-CASCADE
+ # ''''''''''''''''''
+ } else {
+ # add the entry if one doesn't already exist with the same
+ # command name
+ if [::info exists _pathMap($path)] {
+ set cmdname [lindex [split $path .] end]
+ error "Cannot add $type \"$cmdname\". A menu item already\
+ exists with this name."
+ }
+ eval [list $tkMenuPath add $type] $args
+ set _pathMap($path) [_getPdIndex $tkMenuPath end]
+ }
+
+ # Remember the help string
+ set _helpString($path) $helpStr
+
+ return $_pathMap($path)
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _addCascade
+#
+# Creates a cascade button. Handles the -menu option
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_addCascade { tkMenuPath path args } {
+
+ # get the cascade name from our path
+ regsub {.*[.]} $path "" cascadeName
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Capture the -menu option if present
+ # '''''''''''''''''''''''''''''''''''
+ array set temp $args
+ if { [::info exists temp(-menu)] } {
+ set menuEvalStr $temp(-menu)
+ } else {
+ set menuEvalStr {}
+ }
+
+ # attach the menu pane
+ set temp(-menu) $tkMenuPath.$cascadeName
+ set args [array get temp]
+
+ # Create the cascade entry
+ eval $tkMenuPath add cascade $args
+
+ # Keep the -menu string in case of menuconfigure or menucget
+ if { $menuEvalStr != "" } {
+ set _menuOption($path) $menuEvalStr
+ }
+
+ # update our pathmap
+ set _pathMap($path) [_getPdIndex $tkMenuPath end]
+
+ _makeMenu \
+ $cascadeName-menu \
+ $tkMenuPath.$cascadeName \
+ $path \
+ $menuEvalStr
+
+ #return $itk_component($cascadeName)
+
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _insertEntry
+#
+# inserts an entry on a menu before entry given by beforeEntryPath.
+# The added entry is of type TYPE and its name is NAME. ARGS are
+# passed for customization of the entry.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_insertEntry { beforeEntryPath type name args } {
+
+ # convert entryPath to an index value
+ set bfIndex $_pathMap($beforeEntryPath)
+
+ # first verify that beforeEntryPath is actually a path to
+ # an entry and not to menu, menubutton, etc.
+ if { ! [regexp {^[0-9]+$} $bfIndex] } {
+ error "bad entry path: $beforeEntryPath is not an entry"
+ }
+
+ # get the menu path from the entry path name
+ regsub {[.][^.]*$} $beforeEntryPath "" menuPathPrefix
+ set tkMenuPath $_pathMap($menuPathPrefix.menu)
+
+ # If this entry already exists in the path map, throw an error.
+ if [::info exists _pathMap($menuPathPrefix.$name)] {
+ error "Cannot insert $type \"$name\". A menu item already\
+ exists with this name."
+ }
+
+ # INDEX is zero based at this point.
+
+ # ENTRIES is a zero based list...
+ set entries [_getEntryList $menuPathPrefix]
+
+ #
+ # Adjust the entries after the inserted item, to have
+ # the correct index numbers. Note, we stay zero based
+ # even though tk flips back and forth depending on tearoffs.
+ #
+ for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
+ # path==entry path in numerical order
+ set path [lindex $entries $i]
+
+ # add one to each entry after the inserted one.
+ set _pathMap($path) [expr {$i + 1}]
+ }
+
+ # get the -helpstr option if present
+ array set temp $args
+ if { [::info exists temp(-helpstr)] } {
+ set helpStr $temp(-helpstr)
+ unset temp(-helpstr)
+ } else {
+ set helpStr {}
+ }
+ set args [array get temp]
+
+ set path $menuPathPrefix.$name
+
+ # Handle CASCADE
+ # ''''''''''''''
+ # if this is a cascade go ahead and add in the menu...
+ if { [string match cascade $type] } {
+
+ if { [ catch {eval "_insertCascade \
+ $bfIndex $tkMenuPath $path $args"} errMsg ]} {
+ for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
+ # path==entry path in numerical order
+ set path [lindex $entries $i]
+
+ # sub the one we added earlier.
+ set _pathMap($path) [expr {$_pathMap($path) - 1}]
+ # @@ delete $hs
+ }
+ error $errMsg
+ }
+
+ # Handle Entry
+ # ''''''''''''''
+ } else {
+
+ # give us a zero or 1-based index based on tear-off menu status
+ # invoke the menu's insert command
+ if { [catch {eval "$tkMenuPath insert \
+ [_getTkIndex $tkMenuPath $bfIndex] $type $args"} errMsg]} {
+ for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
+ # path==entry path in numerical order
+ set path [lindex $entries $i]
+
+ # sub the one we added earlier.
+ set _pathMap($path) [expr {$_pathMap($path) - 1}]
+ # @@ delete $hs
+ }
+ error $errMsg
+ }
+
+
+ # add the helpstr option to our options list (attach to entry)
+ set _helpString($path) $helpStr
+
+ # Insert the new entry path into pathmap giving it an index value
+ set _pathMap($menuPathPrefix.$name) $bfIndex
+
+ }
+
+ return [_getTkIndex $tkMenuPath $bfIndex]
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _insertCascade
+#
+# Creates a cascade button. Handles the -menu option
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_insertCascade { bfIndex tkMenuPath path args } {
+
+ # get the cascade name from our path
+ regsub {.*[.]} $path "" cascadeName
+
+ #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+ # Capture the -menu option if present
+ # '''''''''''''''''''''''''''''''''''
+ array set temp $args
+ if { [::info exists temp(-menu)] } {
+ # Keep the -menu string in case of menuconfigure or menucget
+ set _menuOption($path) $temp(-menu)
+ set menuEvalStr $temp(-menu)
+ } else {
+ set menuEvalStr {}
+ }
+
+ # attach the menu pane
+ set temp(-menu) $tkMenuPath.$cascadeName
+ set args [array get temp]
+
+ # give us a zero or 1-based index based on tear-off menu status
+ # invoke the menu's insert command
+ eval "$tkMenuPath insert \
+ [_getTkIndex $tkMenuPath $bfIndex] cascade $args"
+
+ # Insert the new entry path into pathmap giving it an index value
+ set _pathMap($path) $bfIndex
+ _makeMenu \
+ $cascadeName-menu \
+ $tkMenuPath.$cascadeName \
+ $path \
+ $menuEvalStr
+
+ #return $itk_component($cascadeName)
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _deleteEntry
+#
+# _deleteEntry entryPath ?entryPath2?
+#
+# either
+# deletes the entry entryPath
+# or
+# deletes the entries from entryPath to entryPath2
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_deleteEntry { entryPath {entryPath2 {}} } {
+
+ if { $entryPath2 == "" } {
+ # get a corrected path (subst for number, last, end)
+ set path [_parsePath $entryPath]
+
+ set entryIndex $_pathMap($path)
+ if { $entryIndex == -1 } {
+ error "bad value for pathName: \
+ $entryPath in call to delet"
+ }
+
+ # get the type, if cascade, we will want to delete menu
+ set type [type $path]
+
+ # ... munge up the menu name ...
+
+ # the tkMenuPath is looked up with the .menu added to lookup
+ # strip off the entry component
+ regsub {[.][^.]*$} $path "" menuPath
+ set tkMenuPath $_pathMap($menuPath.menu)
+
+ # get the ordered entry list
+ set entries [_getEntryList $menuPath]
+
+ # ... Fix up path entry indices ...
+
+ # delete the path from the map
+ unset _pathMap([lindex $entries $entryIndex])
+
+ # Subtract off 1 for each entry below the deleted one.
+ for {set i [expr {$entryIndex + 1}]} \
+ {$i < [llength $entries]} \
+ {incr i} {
+ set epath [lindex $entries $i]
+ incr _pathMap($epath) -1
+ }
+
+ # ... Delete the menu entry widget ...
+
+ # delete the menu entry, ajusting index for TK
+ $tkMenuPath delete [_getTkIndex $tkMenuPath $entryIndex]
+
+ if { $type == "cascade" } {
+ regsub {.*[.]} $path "" cascadeName
+ destroy $itk_component($cascadeName-menu)
+
+ # This is because of some itcl bug that doesn't delete
+ # the component on the destroy in some cases...
+ catch {itk_component delete $cascadeName-menu}
+
+ _unsetPaths $path
+ }
+
+ } else {
+ # get a corrected path (subst for number, last, end)
+ set path1 [_parsePath $entryPath]
+ set path2 [_parsePath $entryPath2]
+
+ set fromEntryIndex $_pathMap($path1)
+ if { $fromEntryIndex == -1 } {
+ error "bad value for entryPath1: \
+ $entryPath in call to delet"
+ }
+ set toEntryIndex $_pathMap($path2)
+ if { $toEntryIndex == -1 } {
+ error "bad value for entryPath2: \
+ $entryPath2 in call to delet"
+ }
+ # ... munge up the menu name ...
+
+ # the tkMenuPath is looked up with the .menu added to lookup
+ # strip off the entry component
+ regsub {[.][^.]*$} $path1 "" menuPath
+ set tkMenuPath $_pathMap($menuPath.menu)
+
+ # get the ordered entry list
+ set entries [_getEntryList $menuPath]
+
+ # ... Fix up path entry indices ...
+
+ # delete the range from the pathMap list
+ for {set i $fromEntryIndex} {$i <= $toEntryIndex} {incr i} {
+ unset _pathMap([lindex $entries $i])
+ }
+
+ # Subtract off 1 for each entry below the deleted range.
+ # Loop from one below the bottom delete entry to end list
+ for {set i [expr {$toEntryIndex + 1}]} \
+ {$i < [llength $entries]} \
+ {incr i} {
+ # take this path and sets its index back by size of
+ # deleted range.
+ set path [lindex $entries $i]
+ set _pathMap($path) \
+ [expr {$_pathMap($path) - \
+ (($toEntryIndex - $fromEntryIndex) + 1)}]
+ }
+
+ # ... Delete the menu entry widget ...
+
+ # delete the menu entry, ajusting index for TK
+ $tkMenuPath delete \
+ [_getTkIndex $tkMenuPath $fromEntryIndex] \
+ [_getTkIndex $tkMenuPath $toEntryIndex]
+
+ }
+}
+
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# CONFIGURATION SUPPORT
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _configureMenu
+#
+# This configures a menu. A menu is a true tk widget, thus we
+# pass the tkPath variable. This path may point to either a
+# menu button (does not end with the name 'menu', or a menu
+# which ends with the name 'menu'
+#
+# path : our Menubar path name to this menu button or menu pane.
+# if we end with the name '.menu' then it is a menu pane.
+# tkPath : the path to the corresponding Tk menubutton or menu.
+# args : the args for configuration
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_configureMenu { path tkPath {option {}} args } {
+
+ set class [winfo class $tkPath]
+
+ if { $option == "" } {
+ # No arguments: return all options
+ set configList [$tkPath configure]
+
+ if { [info exists _menuOption($path)] } {
+ lappend configList [list -menu menu Menu {} $_menuOption($path)]
+ } else {
+ lappend configList [list -menu menu Menu {} {}]
+ }
+ if { [info exists _helpString($path)] } {
+ lappend configList [list -helpstr helpStr HelpStr {} \
+ $_helpString($path)]
+ } else {
+ lappend configList [list -helpstr helpStr HelpStr {} {}]
+ }
+ return $configList
+
+ } elseif {$args == "" } {
+ if { $option == "-menu" } {
+ if { [info exists _menuOption($path)] } {
+ return [list -menu menu Menu {} $_menuOption($path)]
+ } else {
+ return [list -menu menu Menu {} {}]
+ }
+ } elseif { $option == "-helpstr" } {
+ if { [info exists _helpString($path)] } {
+ return [list -helpstr helpStr HelpStr {} $_helpString($path)]
+ } else {
+ return [list -helpstr helpStr HelpStr {} {}]
+ }
+ } else {
+ # ... OTHERWISE, let Tk get it.
+ return [$tkPath configure $option]
+ }
+ } else {
+ set args [concat $option $args]
+
+ # If this is a menubutton, and has -menu option, process it
+ if { $class == "Menubutton" && [regexp -- {-menu} $args] } {
+ eval _configureMenuOption menubutton $path $args
+ } else {
+ eval $tkPath configure $args
+ }
+ return ""
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _configureMenuOption
+#
+# Allows for configuration of the -menu option on
+# menubuttons and cascades
+#
+# find out if we are the last menu, or are before one.
+# delete the old menu.
+# if we are the last, then add us back at the end
+# if we are before another menu, get the beforePath
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_configureMenuOption { type path args } {
+
+ regsub {[.][^.]*$} $path "" pathPrefix
+
+ if { $type == "menubutton" } {
+ set menuList [_getMenuList]
+ set pos [lsearch $menuList $path]
+ if { $pos == ([llength $menuList] - 1) } {
+ set insert false
+ } else {
+ set insert true
+ }
+ } elseif { $type == "cascade" } {
+ set lastEntryPath [_parsePath $pathPrefix.last]
+ if { $lastEntryPath == $path } {
+ set insert false
+ } else {
+ set insert true
+ }
+ set pos [index $path]
+
+ }
+
+
+ eval "delete $pathPrefix.$pos"
+ if { $insert } {
+ # get name from path...
+ regsub {.*[.]} $path "" name
+
+ eval insert $pathPrefix.$pos $type \
+ $name $args
+ } else {
+ eval add $type $path $args
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _configureMenuEntry
+#
+# This configures a menu entry. A menu entry is either a command,
+# radiobutton, separator, checkbutton, or a cascade. These have
+# a corresponding Tk index value for the corresponding tk menu
+# path.
+#
+# path : our Menubar path name to this menu entry.
+# index : the t
+# args : the args for configuration
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_configureMenuEntry { path index {option {}} args } {
+
+ set type [type $path]
+
+ # set len [llength $args]
+
+ # get the menu path from the entry path name
+ set tkMenuPath [_entryPathToTkMenuPath $path]
+
+ if { $option == "" } {
+ set configList [$tkMenuPath entryconfigure \
+ [_getTkIndex $tkMenuPath $index]]
+
+ if { $type == "cascade" } {
+ if { [info exists _menuOption($path)] } {
+ lappend configList [list -menu menu Menu {} \
+ $_menuOption($path)]
+ } else {
+ lappend configList [list -menu menu Menu {} {}]
+ }
+ }
+ if { [info exists _helpString($path)] } {
+ lappend configList [list -helpstr helpStr HelpStr {} \
+ $_helpString($path)]
+ } else {
+ lappend configList [list -helpstr helpStr HelpStr {} {}]
+ }
+ return $configList
+
+ } elseif { $args == "" } {
+ if { $option == "-menu" } {
+ if { [info exists _menuOption($path)] } {
+ return [list -menu menu Menu {} $_menuOption($path)]
+ } else {
+ return [list -menu menu Menu {} {}]
+ }
+ } elseif { $option == "-helpstr" } {
+ if { [info exists _helpString($path)] } {
+ return [list -helpstr helpStr HelpStr {} \
+ $_helpString($path)]
+ } else {
+ return [list -helpstr helpStr HelpStr {} {}]
+ }
+ } else {
+ # ... OTHERWISE, let Tk get it.
+ return [$tkMenuPath entryconfigure \
+ [_getTkIndex $tkMenuPath $index] $option]
+ }
+ } else {
+ array set temp [concat $option $args]
+
+ # ... Store -helpstr val,strip out -helpstr val from args
+ if { [::info exists temp(-helpstr)] } {
+ set _helpString($path) $temp(-helpstr)
+ unset temp(-helpstr)
+ }
+
+ set args [array get temp]
+ if { $type == "cascade" && [::info exists temp(-menu)] } {
+ eval "_configureMenuOption cascade $path $args"
+ } else {
+ # invoke the menu's entryconfigure command
+ # being careful to ajust the INDEX to be 0 or 1 based
+ # depending on the tearoff status
+ # if the stripping process brought us down to no options
+ # to set, then forget the configure of widget.
+ if { [llength $args] != 0 } {
+ eval $tkMenuPath entryconfigure \
+ [_getTkIndex $tkMenuPath $index] $args
+ }
+ }
+ return ""
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _unsetPaths
+#
+# comment
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_unsetPaths { parent } {
+
+ # first get the complete list of all menu paths
+ set pathList [array names _pathMap]
+
+ # for each path that matches parent prefix, unset it.
+ foreach path $pathList {
+ if { [regexp [subst -nocommands {^$parent}] $path] } {
+ unset _pathMap($path)
+ }
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _entryPathToTkMenuPath
+#
+# Takes an entry path like .mbar.file.new and changes it to
+# .mbar.file.menu and performs a lookup in the pathMap to
+# get the corresponding menu widget name for tk
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_entryPathToTkMenuPath {entryPath} {
+
+ # get the menu path from the entry path name
+ # by stripping off the entry component of the path
+ regsub {[.][^.]*$} $entryPath "" menuPath
+
+ # the tkMenuPath is looked up with the .menu added to lookup
+ if { [catch {set tkMenuPath $_pathMap($menuPath.menu)}] } {
+ return ""
+ } else {
+ return $_pathMap($menuPath.menu)
+ }
+}
+
+
+# -------------------------------------------------------------
+#
+# These two methods address the issue of menu entry indices being
+# zero-based when the menu is not a tearoff menu and 1-based when
+# it is a tearoff menu. Our strategy is to hide this difference.
+#
+# _getTkIndex returns the index as tk likes it: 0 based for non-tearoff
+# and 1 based for tearoff menus.
+#
+# _getPdIndex (get pulldown index) always returns it as 0 based.
+#
+# -------------------------------------------------------------
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getTkIndex
+#
+# give us a zero or 1-based answer depending on the tearoff
+# status of the menu. If the menu denoted by tkMenuPath is a
+# tearoff menu it returns a 1-based result, otherwise a
+# zero-based result.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getTkIndex { tkMenuPath tkIndex} {
+
+ # if there is a tear off make it 1-based index
+ if { [$tkMenuPath cget -tearoff] } {
+ incr tkIndex
+ }
+
+ return $tkIndex
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getPdIndex
+#
+# Take a tk index and give me a zero based numerical index
+#
+# Ask the menu widget for the index of the entry denoted by
+# 'tkIndex'. Then if the menu is a tearoff adjust the value
+# to be zero based.
+#
+# This method returns the index as if tearoffs did not exist.
+# Always returns a zero-based index.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getPdIndex { tkMenuPath tkIndex } {
+
+ # get the index from the tk menu
+ # this 0 based for non-tearoff and 1-based for tearoffs
+ set pdIndex [$tkMenuPath index $tkIndex]
+
+ # if there is a tear off make it 0-based index
+ if { [$tkMenuPath cget -tearoff] } {
+ incr pdIndex -1
+ }
+
+ return $pdIndex
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getMenuList
+#
+# Returns the list of menus in the order they are on the interface
+# returned list is a list of our menu paths
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getMenuList { } {
+ # get the menus that are packed
+ set tkPathList [pack slaves $itk_component(menubar)]
+
+ regsub -- {[.]} $itk_component(hull) "" mbName
+ regsub -all -- "\[.\]$mbName\[.\]menubar\[.\]" $tkPathList "." menuPathList
+
+ return $menuPathList
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getEntryList
+#
+#
+# This method looks at a menupath and gets all the entries and
+# returns a list of all the entry path names in numerical order
+# based on their index values.
+#
+# MENU is the path to a menu, like .mbar.file.menu or .mbar.file
+# we will calculate a menuPath from this: .mbar.file
+# then we will build a list of entries in this menu excluding the
+# path .mbar.file.menu
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getEntryList { menu } {
+
+ # if it ends with menu, clip it off
+ regsub {[.]menu$} $menu "" menuPath
+
+ # first get the complete list of all menu paths
+ set pathList [array names _pathMap]
+
+ set numEntries 0
+ # iterate over the pathList and put on menuPathList those
+ # that match the menuPattern
+ foreach path $pathList {
+ # if this path is on the menuPath's branch
+ if { [regexp [subst -nocommands {$menuPath[.][^.]*$}] $path] } {
+ # if not a menu itself
+ if { ! [regexp {[.]menu$} $path] } {
+ set orderedList($_pathMap($path)) $path
+ incr numEntries
+ }
+ }
+ }
+ set entryList {}
+
+ for {set i 0} {$i < $numEntries} {incr i} {
+ lappend entryList $orderedList($i)
+ }
+
+ return $entryList
+
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _parsePath
+#
+# given path, PATH, _parsePath splits the path name into its
+# component segments. It then puts the name back together one
+# segment at a time and calls _getSymbolicPath to replace the
+# keywords 'last' and 'end' as well as numeric digits.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_parsePath { path } {
+ set segments [split [string trimleft $path .] .]
+
+ set concatPath ""
+ foreach seg $segments {
+
+ set concatPath [_getSymbolicPath $concatPath $seg]
+
+ if { [catch {set _pathMap($concatPath)} ] } {
+ error "bad path: \"$path\" does not exist. \"$seg\" not valid"
+ }
+ }
+ return $concatPath
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getSymbolicPath
+#
+# Given a PATH, _getSymbolicPath looks for the last segment of
+# PATH to contain: a number, the keywords last or end. If one
+# of these it figures out how to get us the actual pathname
+# to the searched widget
+#
+# Implementor's notes:
+# Surely there is a shorter way to do this. The only diff
+# for non-numeric is getting the llength of the correct list
+# It is hard to know this upfront so it seems harder to generalize.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getSymbolicPath { parent segment } {
+
+ # if the segment is a number, then look it up positionally
+ # MATCH numeric index
+ if { [regexp {^[0-9]+$} $segment] } {
+
+ # if we have no parent, then we area menubutton
+ if { $parent == {} } {
+ set returnPath [lindex [_getMenuList] $segment]
+ } else {
+ set returnPath [lindex [_getEntryList $parent.menu] $segment]
+ }
+
+ # MATCH 'end' or 'last' keywords.
+ } elseif { $segment == "end" || $segment == "last" } {
+
+ # if we have no parent, then we are a menubutton
+ if { $parent == {} } {
+ set returnPath [lindex [_getMenuList] end]
+ } else {
+ set returnPath [lindex [_getEntryList $parent.menu] end]
+ }
+ } else {
+ set returnPath $parent.$segment
+ }
+
+ return $returnPath
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _helpHandler
+#
+# Bound to the <Motion> event on a menu pane. This puts the
+# help string associated with the menu entry into the
+# status widget help area. If no help exists for the current
+# entry, the status widget is cleared.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_helpHandler { menuPath } {
+
+ if { $itk_option(-helpvariable) == {} } {
+ return
+ }
+
+ set tkMenuWidget $_pathMap($menuPath)
+
+ set entryIndex [$tkMenuWidget index active]
+
+ # already on this item?
+ if { $entryIndex == $_entryIndex } {
+ return
+ }
+
+ set _entryIndex $entryIndex
+
+ if {"none" != $entryIndex} {
+ set entries [_getEntryList $menuPath]
+
+ set menuEntryHit \
+ [lindex $entries [_getPdIndex $tkMenuWidget $entryIndex]]
+
+ # blank out the old one
+ set $itk_option(-helpvariable) {}
+
+ # if there is a help string for this entry
+ if { [::info exists _helpString($menuEntryHit)] } {
+ set $itk_option(-helpvariable) $_helpString($menuEntryHit)
+ }
+ } else {
+ set $itk_option(-helpvariable) {}
+ set _entryIndex -1
+ }
+}
+
+# -------------------------------------------------------------
+#
+# PRIVATE METHOD: _getCallerLevel
+#
+# Starts at stack frame #0 and works down till we either hit
+# a ::Menubar stack frame or an ::itk::Archetype stack frame
+# (the latter happens when a configure is called via the 'component'
+# method
+#
+# Returns the level of the actual caller of the menubar command
+# in the form of #num where num is the level number caller stack frame.
+#
+# -------------------------------------------------------------
+itcl::body iwidgets::Menubar::_getCallerLevel { } {
+
+ set levelName {}
+ set levelsAreValid true
+ set level 0
+ set callerLevel #$level
+
+ while { $levelsAreValid } {
+ # Hit the end of the stack frame
+ if [catch {uplevel #$level {namespace current}}] {
+ set levelsAreValid false
+ set callerLevel #[expr {$level - 1}]
+ # still going
+ } else {
+ set newLevelName [uplevel #$level {namespace current}]
+ # See if we have run into the first ::Menubar level
+ if { $newLevelName == "::itk::Archetype" || \
+ $newLevelName == "::iwidgets::Menubar" } {
+ # If so, we are done-- set the callerLevel
+ set levelsAreValid false
+ set callerLevel #[expr {$level - 1}]
+ } else {
+ set levelName $newLevelName
+ }
+ }
+ incr level
+ }
+ return $callerLevel
+}
+
+
+#
+# The default tkMenuFind proc in menu.tcl only looks for menubuttons
+# in frames. Since our menubuttons are within the Menubar class, the
+# default proc won't find them during menu traversal. This proc
+# redefines the default proc to remedy the problem.
+#-----------------------------------------------------------
+# BUG FIX: csmith (Chad Smith: csmith@adc.com), 3/30/99
+#-----------------------------------------------------------
+# The line, "set qchild ..." below had a typo. It should be
+# "info command $child" instead of "winfo command $child".
+#-----------------------------------------------------------
+proc tkMenuFind {w char} {
+ global tkPriv
+ set char [string tolower $char]
+
+ # Added by csmith, 5/10/01, to fix a bug reported on the itcl mailing list.
+ if {$w == "."} {
+ foreach child [winfo child $w] {
+ set match [tkMenuFind $child $char]
+ if {$match != ""} {
+ return $match
+ }
+ }
+ return {}
+ }
+
+ foreach child [winfo child $w] {
+ switch [winfo class $child] {
+ Menubutton {
+ set qchild [info command $child]
+ set char2 [string index [$qchild cget -text] \
+ [$qchild cget -underline]]
+ if {([string compare $char [string tolower $char2]] == 0)
+ || ($char == "")} {
+ if {[$qchild cget -state] != "disabled"} {
+ return $child
+ }
+ }
+ }
+ Frame -
+ Menubar {
+ set match [tkMenuFind $child $char]
+ if {$match != ""} {
+ return $match
+ }
+ }
+ }
+ }
+ return {}
+}