home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / comanche.exe / lib / iwidgets2.2.0 / scripts / menubar.itk < prev    next >
Text File  |  1999-02-24  |  76KB  |  2,531 lines

  1. #
  2. # Menubar widget
  3. # ----------------------------------------------------------------------
  4. # The Menubar command creates a new window (given by the pathName 
  5. # argument) and makes it into a Pull down menu widget. Additional 
  6. # options, described above may be specified on the command line or 
  7. # in the option database to configure aspects of the Menubar such 
  8. # as its colors and font. The Menubar command returns its pathName 
  9. # argument. At the time this command is invoked, there must not exist 
  10. # a window named pathName, but pathName's parent must exist.
  11. # A Menubar is a widget that simplifies the task of creating 
  12. # menu hierarchies. It encapsulates a frame widget, as well 
  13. # as menubuttons, menus, and menu entries. The Menubar allows 
  14. # menus to be specified and refer enced in a more consistent 
  15. # manner than using Tk to build menus directly. First, Menubar
  16. # allows a menu tree to be expressed in a hierachical "language". 
  17. # The Menubar accepts a menuButtons option that allows a list of 
  18. # menubuttons to be added to the Menubar. In turn, each menubutton
  19. # accepts a menu option that spec ifies a list of menu entries 
  20. # to be added to the menubutton's menu (as well as an option 
  21. # set for the menu).   Cascade entries in turn, accept a menu 
  22. # option that specifies a list of menu entries to be added to 
  23. # the cascade's menu (as well as an option set for the menu). In 
  24. # this manner, a complete menu grammar can be expressed to the 
  25. # Menubar. Additionally, the Menubar allows each component of 
  26. # the Menubar system to be referenced by a simple componentPathName 
  27. # syntax. Finally, the Menubar extends the option set of menu 
  28. # entries to include the helpStr option used to implement status 
  29. # bar help.
  30. #
  31. # WISH LIST:
  32. #   This section lists possible future enhancements.
  33. #
  34. # ----------------------------------------------------------------------
  35. #  AUTHOR: Bill W. Scott                 EMAIL: bscott@spd.dsccc.com
  36. #
  37. #  @(#) $Id: menubar.itk,v 1.1 1998/07/27 18:49:34 stanton Exp $
  38. # ----------------------------------------------------------------------
  39. #            Copyright (c) 1995 DSC Technologies Corporation
  40. # ======================================================================
  41. # Permission to use, copy, modify, distribute and license this software 
  42. # and its documentation for any purpose, and without fee or written 
  43. # agreement with DSC, is hereby granted, provided that the above copyright 
  44. # notice appears in all copies and that both the copyright notice and 
  45. # warranty disclaimer below appear in supporting documentation, and that 
  46. # the names of DSC Technologies Corporation or DSC Communications 
  47. # Corporation not be used in advertising or publicity pertaining to the 
  48. # software without specific, written prior permission.
  49. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  50. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  51. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  52. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  53. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  54. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  55. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  56. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  57. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  58. # SOFTWARE.
  59. # ======================================================================
  60.  
  61.  
  62. #
  63. # Option database default resources:
  64. #
  65. option add *Menubar*Menu*tearOff         false        widgetDefault
  66. option add *Menubar*activeBorderWidth 2               widgetDefault
  67. option add *Menubar*activeForeground black            widgetDefault
  68. option add *Menubar*anchor center                     widgetDefault
  69. option add *Menubar*borderWidth 2                     widgetDefault
  70. option add *Menubar*disabledForeground #a3a3a3        widgetDefault
  71. option add *Menubar*font \
  72.     "-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*" widgetDefault
  73. option add *Menubar*highlightBackground #d9d9d9       widgetDefault
  74. option add *Menubar*highlightColor Black              widgetDefault
  75. option add *Menubar*highlightThickness 0              widgetDefault
  76. option add *Menubar*justify center                    widgetDefault
  77. option add *Menubar*padX 4p                           widgetDefault
  78. option add *Menubar*padY 3p                           widgetDefault
  79. option add *Menubar*Menubutton*relief flat            widgetDefault
  80. option add *Menubar*Menu*relief raised                widgetDefault
  81. option add *Menubar*wrapLength 0                      widgetDefault
  82.  
  83. #
  84. # Usual options.
  85. #
  86. itk::usual Menubar {
  87.     keep -activebackground -activeborderwidth -activeforeground
  88.     keep -background -cursor -disabledforeground -foreground
  89.     keep -font
  90. }
  91.  
  92. #
  93. # The Option class
  94. #
  95. # This class implements the concept of an option.
  96. #
  97. class iwidgets::Option {
  98.  
  99.     #
  100.     # CONSTRUCTOR
  101.     #
  102.     constructor { args } {
  103.  
  104.         if { $args != "" } {
  105.             uplevel $this configure $args
  106.         }
  107.  
  108.     }
  109.  
  110.     #==============================================================
  111.     # O P T I O N S
  112.     #==============================================================
  113.     public variable switch {} { }
  114.     public variable name {} { }
  115.     public variable class {} { }
  116.     public variable default {} { }
  117.     public variable value {} { }
  118.  
  119.     #==============================================================
  120.     # P U B L I C    I N T E R F A C E
  121.     #==============================================================
  122.     public method set { args } { }
  123.     public method get { args } { }
  124.  
  125.  
  126.     #==============================================================
  127.     # D E S T R U C T O R
  128.     #==============================================================
  129.     destructor {
  130.     }
  131. }
  132.  
  133. #==============================================================
  134. # P U B L I C    I M P L E M E N T A T I O N
  135. #==============================================================
  136.  
  137. #
  138. # OPTION -switch
  139. #
  140. # This option specifies the switch name for the option
  141. #
  142. configbody iwidgets::Option::switch {
  143. }
  144.  
  145. #
  146. # OPTION -name
  147. #
  148. # This option specifies the resource name for the option
  149. #
  150. configbody iwidgets::Option::name {
  151. }
  152.  
  153. #
  154. # OPTION -class
  155. #
  156. # This option specifies the resource class for the option
  157. #
  158. configbody iwidgets::Option::class {
  159. }
  160.  
  161. #
  162. # OPTION -default
  163. #
  164. # This option specifies the default value for the option
  165. #
  166. configbody iwidgets::Option::default {
  167. }
  168.  
  169. #
  170. # OPTION -value
  171. #
  172. # This option specifies the current value for the option
  173. #
  174. configbody iwidgets::Option::value {
  175. }
  176.  
  177.  
  178. body iwidgets::Option::get { args } {
  179.  
  180.     upvar $args argsRef
  181.  
  182.     ::set len [llength $args]
  183.  
  184.     switch $len {
  185.         0 {
  186.             return [list $switch $name $class $default $value]
  187.         }
  188.         1 {
  189.             if { [string match $args $switch] } {
  190.                 return [list $switch $name $class $default $value]
  191.                 #::set argsRef {}
  192.                 #return $value
  193.             } else {
  194.                 return {}
  195.             }
  196.         }
  197.         default {
  198.             error "wrong # arguments: \
  199.                     should be \"$itk_component(hull) get ?option?\""
  200.         }
  201.     }
  202.  
  203. }
  204.  
  205. body iwidgets::Option::set { args } {
  206.     # scan args for our switch.
  207.     # if found, set our -value option and strip args.
  208.     # else do nothing.
  209.  
  210.     upvar args argsRef
  211.  
  212.     ::set success false
  213.  
  214.     # check for 'option' in the 'args' list
  215.     ::set optPos [lsearch $args $switch]
  216.  
  217.     # ... found it
  218.     if { $optPos != -1 } {
  219.         # set our -value switch
  220.         ::set value [lindex $args [expr $optPos + 1]]
  221.  
  222.         # remove the option argument and value from the arg list
  223.         ::set argsRef [lreplace $args $optPos [expr $optPos + 1]]
  224.         ::set success true
  225.     }
  226.  
  227.     return $success
  228. }
  229.  
  230. class iwidgets::MenuOption {
  231.     inherit iwidgets::Option
  232.     constructor { args } {}
  233. }
  234. body iwidgets::MenuOption::constructor { args } {
  235.     uplevel $this configure \
  236.             -switch -menu -name menu -class Menu -default {} -value {}
  237. }
  238.  
  239. class iwidgets::HelpStrOption {
  240.     inherit iwidgets::Option
  241.     constructor { args } {}
  242. }
  243. body iwidgets::HelpStrOption::constructor { args } {
  244.     uplevel $this configure \
  245.         -switch -helpstr -name helpStr -class HelpStr -default {{}} -value {{}}
  246. }
  247.  
  248. class iwidgets::Menubar {
  249.     inherit itk::Widget
  250.  
  251.     constructor { args } {}
  252.  
  253.     itk_option define -foreground foreground Foreground Black
  254.     itk_option define -activebackground activeBackground Foreground "#ececec"
  255.     itk_option define -activeborderwidth activeBorderWidth BorderWidth 2 
  256.     itk_option define -activeforeground activeForeground Background black
  257.     itk_option define -anchor anchor Anchor {}
  258.     itk_option define -borderwidth borderWidth BorderWidth {} 
  259.     itk_option define \
  260.         -disabledforeground disabledForeground DisabledForeground #a3a3a3 
  261.     itk_option define \
  262.         -font font Font "-Adobe-Helvetica-Bold-R-Normal--*-120-*-*-*-*-*-*"
  263.     itk_option define \
  264.         -highlightbackground highlightBackground HighlightBackground #d9d9d9
  265.     itk_option define -highlightcolor highlightColor HighlightColor Black
  266.     itk_option define \
  267.         -highlightthickness highlightThickness HighlightThickness {}
  268.     itk_option define -justify justify Justify {}
  269.     itk_option define -padx padX Pad {}
  270.     itk_option define -pady padY Pad {}
  271.     itk_option define -wraplength wrapLength WrapLength {}
  272.     itk_option define -menubuttons menuButtons MenuButtons {}
  273.     itk_option define -helpvariable helpVariable HelpVariable {}
  274.  
  275.     public method add { type path args } { }
  276.     public method delete { args } { }
  277.     public method index { path } { }
  278.     public method insert { beforeComponent type name args }
  279.     public method invoke { entryPath } { }
  280.     public method menucget { args } { }
  281.     public method menuconfigure { path args } { }
  282.     public method path { args } { }
  283.     public method type { path } { }
  284.     public method yposition { entryPath } { }
  285.  
  286.     public method _leaveHandler { menuPath } { }
  287.     public method _helpHandler { menuPath menuY } { }
  288.  
  289.     private method menubutton { menuName args } { }
  290.     private method options { args } { }
  291.     private method command { cmdName args } { }
  292.     private method checkbutton { chkName args } { }
  293.     private method radiobutton { radName args } { }
  294.     private method separator { sepName args } { }
  295.     private method cascade { casName args } { }
  296.     private method _addMenuButton { buttonName args} { }
  297.     private method _insertMenuButton { beforeMenuPath buttonName args} { }
  298.     private method _makeMenuButton {buttonName args} { }
  299.     private method _makeMenu { buttonName menuEvalStr } { }
  300.     private method _substEvalStr { evalStr } { }
  301.     private method _deleteMenu { args } { }
  302.     private method _deleteAMenu { path } { }
  303.     private method _addEntry { type path args } { }
  304.     private method _addCascade { tkMenuPath path args } { }
  305.     private method _makeCascadeMenu \
  306.                     { tkMenuPath parentPath cascadeName menuEvalStr } { }
  307.     private method _insertEntry { beforeEntryPath type name args } { }
  308.     private method _insertCascade { bfIndex tkMenuPath path args } { }
  309.     private method _deleteEntry { args } { }
  310.     private method _configureMenu { path tkPath args } { }
  311.     private method _configureMenuOption { type path args } { }
  312.     private method _configureMenuEntry { path index args } { }
  313.     private method _unsetPaths { parent } { }
  314.     private method _entryPathToTkMenuPath {entryPath} { }
  315.     private method _getTkIndex { tkMenuPath tkIndex} { }
  316.     private method _getPdIndex { tkMenuPath tkIndex } { }
  317.     private method _getMenuList { } { }
  318.     private method _getEntryList { menu } { }
  319.     private method _parsePath { path } { }
  320.     private method _getSymbolicPath { path } { }
  321.     private method _getCallerLevel { }
  322.  
  323.     private variable _parseLevel 0        ;# The parse level depth
  324.     private variable _callerLevel #0      ;# abs level of caller
  325.     private variable _pathMap             ;# Array indexed by Menubar's path
  326.                                           ;# naming, yields tk menu path
  327.     private variable _entryIndex -1       ;# current entry help is displayed
  328.                                           ;# for during help <motion> events
  329.     private variable _options             ;# New options for entry widgets
  330.  
  331.     private variable _tkMenuPath          ;# last tk menu being added to
  332.     private variable _ourMenuPath         ;# our last valid path constructed.
  333. }
  334.  
  335. # ------------------------------------------------------------------
  336. #                           CONSTRUCTOR
  337. # ------------------------------------------------------------------
  338. body iwidgets::Menubar::constructor { args } {
  339.  
  340.     #
  341.     # Create the Menubar Frame that will hold the menus.
  342.     #
  343.     # might want to make -relief and -bd options with defaults
  344.     itk_component add menubar {
  345.         frame $itk_interior.menubar -relief raised -bd 2
  346.     } {
  347.         keep -cursor -background -width -height
  348.     }
  349.     pack $itk_component(menubar) -fill both -expand yes
  350.  
  351.     # Map our pathname to class to the actual menubar frame
  352.     set _pathMap(.) $itk_component(menubar)
  353.  
  354.     eval itk_initialize $args
  355.  
  356.     #
  357.     # HACK HACK HACK
  358.     # Tk expects some variables to be defined and due to some
  359.     # unknown reason we confuse its normal ordering. So, if
  360.     # the user creates a menubutton with no menu it will fail
  361.     # when clicked on with a "Error: can't read $tkPriv(oldGrab):
  362.     # no such element in array". So by setting it to null we
  363.     # avoid this error.
  364.     uplevel #0 "set tkPriv(oldGrab) {}"
  365.  
  366. }
  367.  
  368. #
  369. # Provide a lowercase access method for the Tabset class
  370. #
  371. proc ::iwidgets::menubar { args } {
  372.     uplevel ::iwidgets::Menubar $args
  373. }
  374.  
  375.  
  376. # ------------------------------------------------------------------
  377. #                           OPTIONS
  378. # ------------------------------------------------------------------
  379. # This first set of options are for configuring menus and/or menubuttons
  380. # at the menu level.
  381. #
  382. # ------------------------------------------------------------------
  383. # OPTION -foreground
  384. #
  385. # menu
  386. # menubutton
  387. # ------------------------------------------------------------------
  388. configbody iwidgets::Menubar::foreground {
  389. }
  390.  
  391. # ------------------------------------------------------------------
  392. # OPTION -activebackground
  393. #
  394. # menu
  395. # menubutton
  396. # ------------------------------------------------------------------
  397. configbody iwidgets::Menubar::activebackground {
  398. }
  399.  
  400. # ------------------------------------------------------------------
  401. # OPTION -activeborderwidth
  402. #
  403. # menu
  404. # ------------------------------------------------------------------
  405. configbody iwidgets::Menubar::activeborderwidth {
  406. }
  407.  
  408. # ------------------------------------------------------------------
  409. # OPTION -activeforeground
  410. #
  411. # menu
  412. # menubutton
  413. # ------------------------------------------------------------------
  414. configbody iwidgets::Menubar::activeforeground {
  415. }
  416.  
  417. # ------------------------------------------------------------------
  418. # OPTION -anchor
  419. #
  420. # menubutton
  421. # ------------------------------------------------------------------
  422. configbody iwidgets::Menubar::anchor {
  423. }
  424.  
  425. # ------------------------------------------------------------------
  426. # OPTION -borderwidth
  427. #
  428. # menu
  429. # menubutton
  430. # ------------------------------------------------------------------
  431. configbody iwidgets::Menubar::borderwidth {
  432. }
  433.  
  434. # ------------------------------------------------------------------
  435. # OPTION -disabledforeground
  436. #
  437. # menu
  438. # menubutton
  439. # ------------------------------------------------------------------
  440. configbody iwidgets::Menubar::disabledforeground {
  441. }
  442.  
  443. # ------------------------------------------------------------------
  444. # OPTION -font
  445. #
  446. # menu
  447. # menubutton
  448. # ------------------------------------------------------------------
  449. configbody iwidgets::Menubar::font {
  450. }
  451.  
  452. # ------------------------------------------------------------------
  453. # OPTION -highlightbackground
  454. #
  455. # menubutton
  456. # ------------------------------------------------------------------
  457. configbody iwidgets::Menubar::highlightbackground {
  458. }
  459.  
  460. # ------------------------------------------------------------------
  461. # OPTION -highlightcolor
  462. #
  463. # menubutton
  464. # ------------------------------------------------------------------
  465. configbody iwidgets::Menubar::highlightcolor {
  466. }
  467.  
  468. # ------------------------------------------------------------------
  469. # OPTION -highlightthickness
  470. #
  471. # menubutton
  472. # ------------------------------------------------------------------
  473. configbody iwidgets::Menubar::highlightthickness {
  474. }
  475.  
  476. # ------------------------------------------------------------------
  477. # OPTION -justify
  478. #
  479. # menubutton
  480. # ------------------------------------------------------------------
  481. configbody iwidgets::Menubar::justify {
  482. }
  483.  
  484. # ------------------------------------------------------------------
  485. # OPTION -padx
  486. #
  487. # menubutton
  488. # ------------------------------------------------------------------
  489. configbody iwidgets::Menubar::padx {
  490. }
  491.  
  492. # ------------------------------------------------------------------
  493. # OPTION -pady
  494. #
  495. # menubutton
  496. # ------------------------------------------------------------------
  497. configbody iwidgets::Menubar::pady {
  498. }
  499.  
  500. # ------------------------------------------------------------------
  501. # OPTION -wraplength
  502. #
  503. # menubutton
  504. # ------------------------------------------------------------------
  505. configbody iwidgets::Menubar::wraplength {
  506. }
  507.  
  508. # ------------------------------------------------------------------
  509. # OPTION -menubuttons
  510. #
  511. # The menuButton option is a string which specifies the arrangement 
  512. # of menubuttons on the Menubar frame. Each menubutton entry is 
  513. # delimited by the newline character. Each entry is treated as 
  514. # an add command to the Menubar. 
  515. #
  516. # ------------------------------------------------------------------
  517. configbody iwidgets::Menubar::menubuttons {
  518.     if { $itk_option(-menubuttons) != {} } {
  519.  
  520.         # IF one exists already, delete the old one and create
  521.         # a new one
  522.         if { ! [catch {_parsePath .0}] } {
  523.             delete .0 .last
  524.         } 
  525.  
  526.         #
  527.         # Determine the context level to evaluate the option string at
  528.         #
  529.         set _callerLevel [_getCallerLevel]
  530.  
  531.         #
  532.         # Parse the option string in their scope, then execute it in
  533.         # our scope.
  534.         #
  535.         incr _parseLevel
  536.         _substEvalStr itk_option(-menubuttons)
  537.         eval $itk_option(-menubuttons)
  538.  
  539.         # reset so that we know we aren't parsing in a scope currently.
  540.         incr _parseLevel -1
  541.     }
  542. }
  543.  
  544. # ------------------------------------------------------------------
  545. # OPTION -helpvariable
  546. #
  547. # Specifies the global variable to update whenever the mouse is in 
  548. # motion over a menu entry. This global variable is updated with the 
  549. # current value of the active menu entry's helpStr. Other widgets 
  550. # can "watch" this variable with the trace command, or as is the 
  551. # case with entry or label widgets, they can set their textVariable 
  552. # to the same global variable. This allows for a simple implementation 
  553. # of a help status bar. Whenever the mouse leaves a menu entry, 
  554. # the helpVariable is set to the empty string {}.
  555. #
  556. # ------------------------------------------------------------------
  557. configbody iwidgets::Menubar::helpvariable {
  558.     if {"" != $itk_option(-helpvariable) &&
  559.         ![string match ::* $itk_option(-helpvariable)]} {
  560.         set itk_option(-helpvariable) "::$itk_option(-helpvariable)"
  561.     }
  562. }
  563.  
  564.  
  565. # -------------------------------------------------------------
  566. #
  567. # METHOD: add type path args
  568. #
  569. # Adds either a menu to the menu bar or a menu entry to a
  570. # menu pane.
  571. #
  572. # If the type is one of  cascade,  checkbutton,  command,
  573. # radiobutton,  or separator it adds a new entry to the bottom
  574. # of the menu denoted by the menuPath prefix of componentPath-
  575. # Name.  The  new entry's type is given by type. If additional
  576. # arguments are present, they  specify  options  available  to
  577. # component  type  Entry. See the man pages for menu(n) in the
  578. # section on Entries. In addition all entries accept an  added
  579. # option, helpStr:
  580. #
  581. #     -helpstr value
  582. #
  583. # Specifes the string to associate with  the  entry.
  584. # When the mouse moves over the associated entry, the variable
  585. # denoted by helpVariable is set. Another widget can  bind  to
  586. # the helpVariable and thus display status help.
  587. #
  588. # If the type is menubutton, it adds a new  menubut-
  589. # ton  to  the  menu bar. If additional arguments are present,
  590. # they specify options available to component type MenuButton.
  591. #
  592. # If the type is menubutton  or  cascade,  the  menu
  593. # option  is  available  in  addition to normal Tk options for
  594. # these to types.
  595. #
  596. #      -menu menuSpec
  597. #
  598. # This is only valid for componentPathNames of  type
  599. # menubutton  or  cascade. Specifes an option set and/or a set
  600. # of entries to place on a menu and associate with  the  menu-
  601. # button or cascade. The option keyword allows the menu widget
  602. # to be configured. Each item in the menuSpec  is  treated  as
  603. # add  commands  (each  with  the  possibility of having other
  604. # -menu options). In this way a menu can be recursively built.
  605. #
  606. # The last segment of  componentPathName  cannot  be
  607. # one  of  the  keywords last, menu, end. Additionally, it may
  608. # not be a number. However the componentPathName may be refer-
  609. # enced  in  this  manner  (see  discussion  of Component Path
  610. # Names).
  611. #
  612. # -------------------------------------------------------------
  613. body iwidgets::Menubar::add { type path args } {
  614.  
  615.     if { $type != "menubutton" && \
  616.          $type != "command" && \
  617.          $type != "cascade" && \
  618.          $type != "separator" && \
  619.          $type != "radiobutton" && \
  620.          $type != "checkbutton" } {
  621.         error "bad type \"$type\": must be one of the following:\
  622.                 \"command\", \"checkbutton\", \"radiobutton\",\
  623.                 \"separator\", \"cascacde\", or \"menubutton\""
  624.     }
  625.  
  626.     regsub {.*[.]} $path "" segName
  627.     if { $segName == "menu" || $segName == "last" || $segName == "end" || \
  628.                 [regexp {^[0-9]+$} $segName] } {
  629.         error "bad name \"$segName\": user created component \
  630.                 path names may not end with \
  631.                 \"end\", \"last\", \"menu\", \
  632.                 or be an integer"
  633.     }
  634.  
  635.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  636.     # OK, either add a menu
  637.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  638.     if { $type == "menubutton" } {
  639.         # grab the last component name (the menu name)
  640.         return [eval "_addMenuButton $segName $args"]
  641.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  642.     # Or add an entry
  643.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  644.     } else {
  645.         return [eval _addEntry $type $path $args]
  646.     }
  647. }
  648.  
  649.  
  650.     
  651. # -------------------------------------------------------------
  652. #
  653. # METHOD: delete entryPath ?entryPath2?
  654. #
  655. # If componentPathName is of component type MenuButton or
  656. # Menu,  delete  operates  on menus. If componentPathName is of
  657. # component type Entry, delete operates on menu entries.
  658. #
  659. # This  command  deletes  all  components  between   com-
  660. # ponentPathName  and  componentPathName2  inclusive.  If com-
  661. # ponentPathName2  is  omitted  then  it  defaults   to   com-
  662. # ponentPathName. Returns an empty string.
  663. #
  664. # If componentPathName is of type Menubar, then all menus
  665. # and  the menu bar frame will be destroyed. In this case com-
  666. # ponentPathName2 is ignored.
  667. #
  668. # -------------------------------------------------------------
  669. body iwidgets::Menubar::delete { args } {
  670.  
  671.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  672.     # Handle out of bounds in arg lengths
  673.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  674.     if { [llength $args] > 0 && [llength $args] <=2 } {
  675.  
  676.         # Path Conversions
  677.         # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  678.         set path [_parsePath [lindex $args 0]]
  679.  
  680.         set pathOrIndex $_pathMap($path)
  681.  
  682.         # Menu Entry
  683.         # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  684.         if { [regexp {^[0-9]+$} $pathOrIndex] } {
  685.             eval "_deleteEntry $args"
  686.  
  687.         # Menu
  688.         # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  689.         } else {
  690.             eval "_deleteMenu $args"
  691.         }
  692.     } else {
  693.         error "wrong # args: should be \
  694.                 \"$itk_component(hull) delete pathName ?pathName2?\""
  695.     }
  696. return ""
  697. }
  698.  
  699. # -------------------------------------------------------------
  700. #
  701. # METHOD: index path
  702. #
  703. # If componentPathName is of type menubutton or menu,  it
  704. # returns  the  position of the menu/menubutton on the Menubar
  705. # frame.
  706. #
  707. # If componentPathName is  of  type  command,  separator,
  708. # radiobutton,  checkbutton,  or  cascade, it returns the menu
  709. # widget's numerical index for the entry corresponding to com-
  710. # ponentPathName. If path is not found or the Menubar frame is
  711. # passed in, -1 is returned.
  712. #
  713. # -------------------------------------------------------------
  714. body iwidgets::Menubar::index { path } {
  715.  
  716.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  717.     # Path conversions
  718.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  719.     if { [catch {set fullPath [_parsePath $path]} ] } {
  720.         return -1
  721.     }
  722.     if { [catch {set tkPathOrIndex $_pathMap($fullPath)} ] } {
  723.         return -1
  724.     }
  725.  
  726.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  727.     # If integer, return the value, otherwise look up the menu position
  728.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  729.     if { [regexp {^[0-9]+$} $tkPathOrIndex] } {
  730.         set index $tkPathOrIndex
  731.     } else {
  732.         set index [lsearch [_getMenuList] $fullPath]
  733.     }
  734.  
  735.     return $index
  736. }
  737.     
  738. # -------------------------------------------------------------
  739. #
  740. # METHOD: insert beforeComponent type name ?option value?
  741. #
  742. # Insert a new component named name before the  component
  743. # specified by componentPathName.
  744. #
  745. # If componentPathName is of type MenuButton or Menu, the
  746. # new  component  inserted  is of type Menu and given the name
  747. # name. In this  case  valid  option  value  pairs  are  those
  748. # accepted by menubuttons.
  749. #
  750. # If componentPathName is of type  Entry,  the  new  com-
  751. # ponent inserted is of type Entry and given the name name. In
  752. # this case valid option value pairs  are  those  accepted  by
  753. # menu entries.
  754. #
  755. # name cannot be one of the  keywords  last,  menu,  end.
  756. # dditionally,  it  may  not  be  a  number. However the com-
  757. # ponentPathName may be referenced in this manner (see discus-
  758. # sion of Component Path Names).
  759. #
  760. # Returns -1 if the menubar frame is passed in.
  761. #
  762. # -------------------------------------------------------------
  763. body iwidgets::Menubar::insert { beforeComponent type name args } {
  764.  
  765.     if { $type != "menubutton" && \
  766.          $type != "command" && \
  767.          $type != "cascade" && \
  768.          $type != "separator" && \
  769.          $type != "radiobutton" && \
  770.          $type != "checkbutton" } {
  771.         error "bad type \"$type\": must be one of the following:\
  772.                 \"command\", \"checkbutton\", \"radiobutton\",\
  773.                 \"separator\", \"cascacde\", or \"menubutton\""
  774.     }
  775.  
  776.     if { $name == "menu" || $name == "last" || $name == "end" || \
  777.                 [regexp {^[0-9]+$} $name] } {
  778.         error "bad name \"$name\": user created component \
  779.                 path names may not end with \
  780.                 \"end\", \"last\", \"menu\", \
  781.                 or be an integer"
  782.     }
  783.  
  784.     set beforeComponent [_parsePath $beforeComponent]
  785.  
  786.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  787.     # Choose menu insertion or entry insertion
  788.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  789.     if { $type == "menubutton" } {
  790.         return [eval _insertMenuButton $beforeComponent $name $args]
  791.     } else {
  792.         return [eval _insertEntry $beforeComponent $type $name $args]
  793.     }
  794. }
  795.  
  796.  
  797. # -------------------------------------------------------------
  798. #
  799. # METHOD: invoke entryPath
  800. #
  801. # Invoke  the  action  of  the  menu  entry  denoted   by
  802. # entryComponentPathName.  See  the sections on the individual
  803. # entries in the menu(n) man pages. If the menu entry is  dis-
  804. # abled  then  nothing  happens.  If  the  entry has a command
  805. # associated with it  then  the  result  of  that  command  is
  806. # returned  as the result of the invoke widget command. Other-
  807. # wise the result is an empty string.
  808. #
  809. # If componentPathName is not a menu entry, an  error  is
  810. # issued.
  811. #
  812. # -------------------------------------------------------------
  813. body iwidgets::Menubar::invoke { entryPath } {
  814.  
  815.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  816.     # Path Conversions
  817.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  818.     set entryPath [_parsePath $entryPath]
  819.     set index $_pathMap($entryPath)
  820.  
  821.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  822.     # Error Processing
  823.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  824.     # first verify that beforeEntryPath is actually a path to
  825.     # an entry and not to menu, menubutton, etc.
  826.     if { ! [regexp {^[0-9]+$} $index] } {
  827.         error "bad entry path: beforeEntryPath is not an entry"
  828.     }
  829.  
  830.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  831.     # Call invoke command
  832.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  833.     # get the tk menu path to call
  834.     set tkMenuPath [_entryPathToTkMenuPath $entryPath]
  835.  
  836.     # call the menu's invoke command, adjusting index based on tearoff
  837.     $tkMenuPath invoke [_getTkIndex $tkMenuPath $index]
  838. }
  839.  
  840. # -------------------------------------------------------------
  841. #
  842. # METHOD: menucget componentPath option
  843. #
  844. # Returns the current value of the  configuration  option
  845. # given  by  option.  The  component type of componentPathName
  846. # determines the valid available options.
  847. #
  848. # -------------------------------------------------------------
  849. body iwidgets::Menubar::menucget { args } {
  850.  
  851.     return [lindex [eval menuconfigure $args] 4]
  852.  
  853. }
  854.     
  855. # -------------------------------------------------------------
  856. #
  857. # METHOD: menuconfigure componentPath ?option? ?value option value...?
  858. #
  859. # Query or modify the configuration options of  the  sub-
  860. # component  of the Menubar specified by componentPathName. If
  861. # no option is specified, returns a list describing all of the
  862. # available     options     for     componentPathName     (see
  863. # Tk_ConfigureInfo for  information  on  the  format  of  this
  864. # list).  If  option is specified with no value, then the com-
  865. # mand returns a list describing the one  named  option  (this
  866. # list  will  be identical to the corresponding sublist of the
  867. # value returned if no option is specified). If  one  or  more
  868. # option-value  pairs are specified, then the command modifies
  869. # the given widget option(s) to have the  given  value(s);  in
  870. # this case the command returns an empty string. The component
  871. # type of componentPathName  determines  the  valid  available
  872. # options.
  873. #
  874. # -------------------------------------------------------------
  875. body iwidgets::Menubar::menuconfigure { path args } {
  876.  
  877.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  878.     # Path Conversions
  879.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  880.     set path [_parsePath $path]
  881.     set tkPathOrIndex $_pathMap($path)
  882.  
  883.     # Case: Menu entry being configured
  884.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  885.     if { [regexp {^[0-9]+$} $tkPathOrIndex] } {
  886.         return [eval "_configureMenuEntry $path $tkPathOrIndex $args"]
  887.  
  888.     # Case: Menu (button and pane) being configured.
  889.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  890.     } else {
  891.         set result [eval _configureMenu $path $tkPathOrIndex $args]
  892.         return $result
  893.  
  894.  
  895.     }
  896.  
  897. }
  898. # -------------------------------------------------------------
  899. #
  900. # METHOD: path
  901. #
  902. # SYNOPIS: path ?<mode>? <pattern>
  903. #
  904. # Returns a fully formed component path that matches pat-
  905. # tern.  If no match is found it returns -1. The mode argument
  906. # indicates how the search is to be  matched  against  pattern
  907. # and it must have one of the following values:
  908. #
  909. #     -glob     Pattern is a glob-style pattern which is
  910. #       matched  against each component path using the same rules as
  911. #       the string match command.
  912. #
  913. #     -regexp   Pattern is treated as a regular  expression  
  914. #       and matched against each component path using the same
  915. #       rules as the regexp command.
  916. #
  917. # The default mode is -glob.
  918. #
  919. # -------------------------------------------------------------
  920. body iwidgets::Menubar::path { args } {
  921.  
  922.     set len [llength $args]
  923.     if { $len < 1 || $len > 2 } {
  924.         error "wrong # args: should be \
  925.                 \"$itk_component(hull) path ?mode?> <pattern>\""
  926.     }
  927.  
  928.     set pathList [array names _pathMap]
  929.  
  930.     set len [llength $args]
  931.     switch -- $len {
  932.         1 {
  933.             # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  934.             # Case: no search modes given
  935.             # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  936.             set pattern [lindex $args 0]
  937.             set found [lindex $pathList [lsearch -glob $pathList $pattern]]
  938.         } 
  939.         2 {
  940.             # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  941.             # Case: search modes present (-glob, -regexp)
  942.             # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  943.             set options [lindex $args 0]
  944.             set pattern [lindex $args 1]
  945.             set found \
  946.                 [lindex $pathList [lsearch $options $pathList $pattern]]
  947.         }
  948.         default {
  949.             # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  950.             # Case: wrong # arguments
  951.             # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  952.             error "wrong # args: \
  953.                 should be \"$itk_component(hull) path ?-glob? ?-regexp? pattern\""
  954.         }
  955.     }
  956.  
  957.     return $found
  958. }
  959.  
  960. # -------------------------------------------------------------
  961. #
  962. # METHOD: type path
  963. #
  964. # Returns the type of the component  given  by  entryCom-
  965. # ponentPathName.  For menu entries, this is the type argument
  966. # passed to the add/insert widget command when the  entry  was
  967. # created, such as command or separator. Othewise it is either
  968. # a menubutton or a menu.
  969. #
  970. # -------------------------------------------------------------
  971. body iwidgets::Menubar::type { path } {
  972.  
  973.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  974.     # Path Conversions
  975.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  976.     set path [_parsePath $path]
  977.  
  978.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  979.     # Error Handling: does the path exist?
  980.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  981.     if { [catch {set index $_pathMap($path)} ] } {
  982.         error "bad path \"$path\""
  983.     }
  984.  
  985.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  986.     # ENTRY, Ask TK for type
  987.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  988.     if { [regexp {^[0-9]+$} $index] } {
  989.         # get the menu path from the entry path name
  990.         set tkMenuPath [_entryPathToTkMenuPath $path]
  991.  
  992.         # call the menu's type command, adjusting index based on tearoff
  993.         set type [$tkMenuPath type [_getTkIndex $tkMenuPath $index]]
  994.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  995.     # MENUBUTTON, MENU, or FRAME
  996.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  997.     } else {
  998.         # should not happen, but have a path that is not a valid window.
  999.         if { [catch {set className [winfo class $_pathMap($path)]}] } {
  1000.             error "serious error: \"$path\" is not a valid window"
  1001.         }
  1002.         # get the classname, look it up, get index, us it to look up type
  1003.         set type [ lindex \
  1004.                     {frame menubutton menu} \
  1005.                     [lsearch { Frame Menubutton Menu } $className] \
  1006.                  ]
  1007.     }
  1008.     return $type
  1009. }
  1010.  
  1011. # -------------------------------------------------------------
  1012. #
  1013. # METHOD: yposition entryPath
  1014. #
  1015. # Returns a decimal string giving the y-coordinate within
  1016. # the  menu window of the topmost pixel in the entry specified
  1017. # by componentPathName. If the  componentPathName  is  not  an
  1018. # entry, an error is issued.
  1019. #
  1020. # -------------------------------------------------------------
  1021. body iwidgets::Menubar::yposition { entryPath } {
  1022.  
  1023.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1024.     # Path Conversions
  1025.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  1026.     set entryPath [_parsePath $entryPath]
  1027.     set index $_pathMap($entryPath)
  1028.  
  1029.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1030.     # Error Handling
  1031.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  1032.     # first verify that entryPath is actually a path to
  1033.     # an entry and not to menu, menubutton, etc.
  1034.     if { ! [regexp {^[0-9]+$} $index] } {
  1035.         error "bad value: entryPath is not an entry"
  1036.     }
  1037.  
  1038.     # ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1039.     # Call yposition command
  1040.     # '''''''''''''''''''''''''''''''''''''''''''''''''''''
  1041.     # get the menu path from the entry path name
  1042.     set tkMenuPath [_entryPathToTkMenuPath $entryPath]
  1043.  
  1044.     # call the menu's yposition command, adjusting index based on tearoff
  1045.     return [$tkMenuPath yposition [_getTkIndex $tkMenuPath $index]]
  1046.  
  1047. }
  1048.  
  1049. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1050. # PARSING METHODS
  1051. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1052. # -------------------------------------------------------------
  1053. #
  1054. # PARSING METHOD: menubutton
  1055. #
  1056. # This method is invoked via an evaluation of the -menubuttons
  1057. # option for the Menubar.
  1058. #
  1059. # It adds a new menubutton and processes any -menu options
  1060. # for creating entries on the menu pane associated with the 
  1061. # menubutton
  1062. # -------------------------------------------------------------
  1063. body iwidgets::Menubar::menubutton { menuName args } {
  1064.     eval "add menubutton .$menuName $args"
  1065. }
  1066.  
  1067. # -------------------------------------------------------------
  1068. #
  1069. # PARSING METHOD: options
  1070. #
  1071. # This method is invoked via an evaluation of the -menu
  1072. # option for menubutton commands.
  1073. #
  1074. # It configures the current menu ($_ourMenuPath) with the options
  1075. # that follow (args)
  1076. #
  1077. # -------------------------------------------------------------
  1078. body iwidgets::Menubar::options { args } {
  1079.     eval "$_tkMenuPath configure $args"
  1080. }
  1081.  
  1082.  
  1083. # -------------------------------------------------------------
  1084. #
  1085. # PARSING METHOD: command
  1086. #
  1087. # This method is invoked via an evaluation of the -menu
  1088. # option for menubutton commands.
  1089. #
  1090. # It adds a new command entry to the current menu, $_ourMenuPath
  1091. # naming it $cmdName.
  1092. #
  1093. # -------------------------------------------------------------
  1094. body iwidgets::Menubar::command { cmdName args } {
  1095.     eval "add command $_ourMenuPath.$cmdName $args"
  1096. }
  1097.  
  1098. # -------------------------------------------------------------
  1099. #
  1100. # PARSING METHOD: checkbutton
  1101. #
  1102. # This method is invoked via an evaluation of the -menu
  1103. # option for menubutton/cascade commands.
  1104. #
  1105. # It adds a new checkbutton entry to the current menu, $_ourMenuPath
  1106. # naming it $chkName.
  1107. #
  1108. # -------------------------------------------------------------
  1109. body iwidgets::Menubar::checkbutton { chkName args } {
  1110.     eval "add checkbutton $_ourMenuPath.$chkName $args"
  1111. }
  1112.  
  1113. # -------------------------------------------------------------
  1114. #
  1115. # PARSING METHOD: radiobutton
  1116. #
  1117. # This method is invoked via an evaluation of the -menu
  1118. # option for menubutton/cascade commands.
  1119. #
  1120. # It adds a new radiobutton entry to the current menu, $_ourMenuPath
  1121. # naming it $radName.
  1122. #
  1123. # -------------------------------------------------------------
  1124. body iwidgets::Menubar::radiobutton { radName args } {
  1125.     eval "add radiobutton $_ourMenuPath.$radName $args"
  1126. }
  1127.  
  1128. # -------------------------------------------------------------
  1129. #
  1130. # PARSING METHOD: separator
  1131. #
  1132. # This method is invoked via an evaluation of the -menu
  1133. # option for menubutton/cascade commands.
  1134. #
  1135. # It adds a new separator entry to the current menu, $_ourMenuPath
  1136. # naming it $sepName.
  1137. #
  1138. # -------------------------------------------------------------
  1139. body iwidgets::Menubar::separator { sepName args } {
  1140.     eval $_tkMenuPath add separator
  1141.     set _pathMap($_ourMenuPath.$sepName) [_getPdIndex $_tkMenuPath end]
  1142. }
  1143.  
  1144. # -------------------------------------------------------------
  1145. #
  1146. # PARSING METHOD: cascade
  1147. #
  1148. # This method is invoked via an evaluation of the -menu
  1149. # option for menubutton/cascade commands.
  1150. #
  1151. # It adds a new cascade entry to the current menu, $_ourMenuPath
  1152. # naming it $casName. It processes the -menu option if present,
  1153. # adding a new menu pane and its associated entries found.
  1154. #
  1155. # -------------------------------------------------------------
  1156. body iwidgets::Menubar::cascade { casName args } {
  1157.     
  1158.     # Save the current menu we are adding to, cascade can change
  1159.     # the current menu through -menu options.
  1160.     set saveOMP $_ourMenuPath
  1161.     set saveTKP $_tkMenuPath
  1162.  
  1163.     eval "add cascade $_ourMenuPath.$casName $args"
  1164.  
  1165.     # Restore the saved menu states so that the next entries of
  1166.     # the -menu/-menubuttons we are processing will be at correct level.
  1167.     set _ourMenuPath $saveOMP
  1168.     set _tkMenuPath $saveTKP
  1169. }
  1170.  
  1171. # ... A P I   S U P P O R T   M E T H O D S...
  1172.  
  1173. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1174. # MENU ADD, INSERT, DELETE
  1175. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1176. # -------------------------------------------------------------
  1177. #
  1178. # PRIVATE METHOD: _addMenuButton
  1179. #
  1180. # Makes a new menubutton & associated -menu, pack appended
  1181. #
  1182. # -------------------------------------------------------------
  1183. body iwidgets::Menubar::_addMenuButton { buttonName args} {
  1184.  
  1185.     eval "_makeMenuButton $buttonName $args"
  1186.  
  1187.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1188.     # Pack at end, adjust for help buttonName
  1189.     # ''''''''''''''''''''''''''''''''''
  1190.     if { $buttonName == "help" } {
  1191.         pack $itk_component($buttonName) -side right
  1192.     } else {
  1193.         pack $itk_component($buttonName) -side left
  1194.     }
  1195.  
  1196.     return $itk_component($buttonName)
  1197. }
  1198.  
  1199. # -------------------------------------------------------------
  1200. #
  1201. # PRIVATE METHOD: _insertMenuButton
  1202. #
  1203. # inserts a menubutton named $buttonName on a menu bar before 
  1204. # another menubutton specified by $beforeMenuPath
  1205. #
  1206. # -------------------------------------------------------------
  1207. body iwidgets::Menubar::_insertMenuButton { beforeMenuPath buttonName args} {
  1208.  
  1209.     eval "_makeMenuButton $buttonName $args"
  1210.  
  1211.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1212.     # Pack before the $beforeMenuPath
  1213.     # ''''''''''''''''''''''''''''''''
  1214.     set beforeTkMenu $_pathMap($beforeMenuPath)
  1215.     regsub {[.]menu$} $beforeTkMenu "" beforeTkMenu
  1216.     pack $itk_component(menubar).$buttonName \
  1217.             -side left \
  1218.             -before $beforeTkMenu
  1219.  
  1220.     return $itk_component($buttonName)
  1221. }
  1222.  
  1223. # -------------------------------------------------------------
  1224. #
  1225. # PRIVATE METHOD: _makeMenuButton
  1226. #
  1227. # creates a menubutton named buttonName on the menubar with args.
  1228. # The -menu option if present will trigger attaching a menu pane.
  1229. #
  1230. # -------------------------------------------------------------
  1231. body iwidgets::Menubar::_makeMenuButton {buttonName args} {
  1232.  
  1233.     set menuEvalStr {}
  1234.  
  1235.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1236.     # Capture the -menu option if present
  1237.     # '''''''''''''''''''''''''''''''''''
  1238.     # does the -menu switch exist in the args list??
  1239.     if { [regexp -- {-menu} $args] } {
  1240.         # Make a menu Option
  1241.         set menuOpt [iwidgets::MenuOption #auto]
  1242.  
  1243.         # set the -menu value (if present in args)
  1244.         eval "$menuOpt set $args"
  1245.  
  1246.         set menuEvalStr [$menuOpt cget -value]
  1247.  
  1248.         # add the -menu option to our options list (attach to menu)
  1249.         lappend _options(.$buttonName) $menuOpt
  1250.  
  1251.     }
  1252.  
  1253.     # attach the menu to the menubutton's arg list
  1254.     lappend args -menu $itk_component(menubar).$buttonName.menu
  1255.  
  1256.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1257.     # Create menubutton component
  1258.     # ''''''''''''''''''''''''''''''''
  1259.     itk_component add $buttonName {
  1260.         eval ::menubutton \
  1261.                 $itk_component(menubar).$buttonName \
  1262.                 $args 
  1263.     } {
  1264.         keep \
  1265.             -activebackground \
  1266.             -activeforeground \
  1267.             -anchor \
  1268.             -background \
  1269.             -borderwidth \
  1270.             -cursor \
  1271.             -disabledforeground \
  1272.             -font \
  1273.             -foreground \
  1274.             -highlightbackground \
  1275.             -highlightcolor \
  1276.             -highlightthickness \
  1277.             -justify \
  1278.             -padx \
  1279.             -pady \
  1280.             -wraplength
  1281.     }
  1282.  
  1283.     set _pathMap(.$buttonName) $itk_component($buttonName)
  1284.  
  1285.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1286.     # Adjust for Help Menus
  1287.     # ''''''''''''''''''''''''''''''''
  1288.     if { $buttonName == "help" } {
  1289.         pack $itk_component($buttonName) -side right
  1290.     } else {
  1291.         pack $itk_component($buttonName) -side left
  1292.     }
  1293.  
  1294.     _makeMenu $buttonName $menuEvalStr
  1295.  
  1296.     return $itk_component($buttonName)
  1297.         
  1298. }
  1299.  
  1300. # -------------------------------------------------------------
  1301. #
  1302. # PRIVATE METHOD: _makeMenu
  1303. #
  1304. # Creates a menu.
  1305. # It then evaluates the $menuEvalStr to create entries on the menu.
  1306. #
  1307. # Assumes the existence of $itk_component($buttonName)
  1308. #
  1309. # -------------------------------------------------------------
  1310. body iwidgets::Menubar::_makeMenu { buttonName menuEvalStr } {
  1311.  
  1312.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1313.     # Create menu component
  1314.     # ''''''''''''''''''''''''''''''''
  1315.     itk_component add $buttonName-menu {
  1316.         ::menu $itk_component($buttonName).menu
  1317.     } {
  1318.         keep \
  1319.             -activebackground \
  1320.             -activeborderwidth \
  1321.             -activeforeground \
  1322.             -background \
  1323.             -borderwidth \
  1324.             -cursor \
  1325.             -disabledforeground \
  1326.             -font \
  1327.             -foreground 
  1328.     }
  1329.  
  1330.     set _pathMap(.$buttonName.menu) $itk_component($buttonName-menu)
  1331.  
  1332.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1333.     # Attach help handler to this menu
  1334.     # ''''''''''''''''''''''''''''''''
  1335.     #bind $itk_component($buttonName-menu) <Motion> \
  1336.             [code $this _helpHandler $itk_component(hull).$buttonName.menu %y]
  1337.     bind $itk_component($buttonName-menu) <Motion> \
  1338.             [code $this _helpHandler .$buttonName.menu %y]
  1339.     #bind $itk_component($buttonName-menu) <Leave> \
  1340.             "+[code $this _leaveHandler $itk_component(hull).$buttonName.menu]"
  1341.     bind $itk_component($buttonName-menu) <Leave> \
  1342.             "+[code $this _leaveHandler .$buttonName.menu]"
  1343.  
  1344.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1345.     # Handle -menu
  1346.     #'''''''''''''''''''''''''''''''''
  1347.     set _ourMenuPath .$buttonName
  1348.     set _tkMenuPath $itk_component($buttonName-menu)
  1349.  
  1350.     #
  1351.     # A zero parseLevel says we are at the top of the parse tree,
  1352.     # so get the context scope level and do a subst for the menuEvalStr.
  1353.     #
  1354.     if { $_parseLevel == 0 } {
  1355.         set _callerLevel [_getCallerLevel]
  1356.         _substEvalStr menuEvalStr
  1357.     }
  1358.  
  1359.     #
  1360.     # bump up the parse level, so if we get called via the 'eval $menuEvalStr'
  1361.     # we know to skip the above steps...
  1362.     #
  1363.     incr _parseLevel
  1364.     eval $menuEvalStr
  1365.  
  1366.     #
  1367.     # leaving, so done with this parse level, so bump it back down 
  1368.     #
  1369.     incr _parseLevel -1
  1370. }
  1371.  
  1372. # -------------------------------------------------------------
  1373. #
  1374. # PRIVATE METHOD: _substEvalStr
  1375. #
  1376. # This performs the substitution and evaluation of $ [], \ found
  1377. # in the -menubutton/-menus options
  1378. #
  1379. # -------------------------------------------------------------
  1380. body iwidgets::Menubar::_substEvalStr { evalStr } {
  1381.     upvar $evalStr evalStrRef
  1382.     set evalStrRef [uplevel $_callerLevel [list subst $evalStrRef]]
  1383. }
  1384.  
  1385.  
  1386. # -------------------------------------------------------------
  1387. #
  1388. # PRIVATE METHOD: _deleteMenu
  1389. #
  1390. # _deleteMenu menuPath ?menuPath2?
  1391. #
  1392. # deletes menuPath or from menuPath to menuPath2
  1393. #
  1394. # Menu paths may be formed in one of two ways
  1395. #    .MENUBAR.menuName  where menuName is the name of the menu
  1396. #    .MENUBAR.menuName.menu  where menuName is the name of the menu
  1397. #
  1398. # The basic rule is '.menu' is not needed.
  1399. # -------------------------------------------------------------
  1400. body iwidgets::Menubar::_deleteMenu { args } {
  1401.  
  1402.     set len [llength $args]
  1403.     switch -- $len {
  1404.         1 {
  1405.             # get a corrected path (subst for number, last, end)
  1406.             set path [_parsePath [lindex $args 0]]
  1407.  
  1408.             _deleteAMenu $path
  1409.         }
  1410.  
  1411.         2 {
  1412.             # gets the list of menus in interface order
  1413.             set menuList [_getMenuList]
  1414.  
  1415.             # ... get the start menu and the last menu ...
  1416.  
  1417.             # get a corrected path (subst for number, last, end)
  1418.             set menuStartPath [_parsePath [lindex $args 0]]
  1419.  
  1420.             regsub {[.]menu$} $menuStartPath "" menuStartPath
  1421.  
  1422.             set menuEndPath [_parsePath [lindex $args 1]]
  1423.  
  1424.             regsub {[.]menu$} $menuEndPath "" menuEndPath
  1425.             
  1426.             # get the menu position (0 based) of the start and end menus.
  1427.             set start [lsearch -exact $menuList $menuStartPath]
  1428.             if { $start == -1 } {
  1429.                 error "bad menu path \"$menuStartPath\": \
  1430.                     should be one of $menuList"
  1431.             }
  1432.             set end [lsearch -exact $menuList $menuEndPath]
  1433.             if { $end == -1 } {
  1434.                 error "bad menu path \"$menuEndPath\": \
  1435.                     should be one of $menuList"
  1436.             }
  1437.  
  1438.             # now create the list from this range of menus
  1439.             set delList [lrange $menuList $start $end]
  1440.  
  1441.             # walk thru them deleting each menu.
  1442.             # this list has no .menu on the end.
  1443.             foreach m $delList {
  1444.                 _deleteAMenu $m.menu
  1445.             }
  1446.         }
  1447.         default {
  1448.         }    
  1449.     }
  1450.  
  1451. }
  1452.  
  1453. # -------------------------------------------------------------
  1454. #
  1455. # PRIVATE METHOD: _deleteAMenu
  1456. #
  1457. # _deleteMenu menuPath 
  1458. #
  1459. # deletes a single Menu (menubutton and menu pane with entries)
  1460. #
  1461. # -------------------------------------------------------------
  1462. body iwidgets::Menubar::_deleteAMenu { path } {
  1463.  
  1464.     # We will normalize the path to not include the '.menu' if
  1465.     # it is on the path already.
  1466.  
  1467.     regsub {[.]menu$} $path "" menuButtonPath
  1468.     regsub {.*[.]} $menuButtonPath "" buttonName
  1469.  
  1470.     # Loop through and destroy any cascades, etc on menu.
  1471.     set entryList [_getEntryList $menuButtonPath]
  1472.     foreach entry $entryList {
  1473.         _deleteEntry $entry
  1474.     }
  1475.  
  1476.     # Delete the menubutton and menu components...
  1477.     destroy $itk_component($buttonName-menu)
  1478.     destroy $itk_component($buttonName)
  1479.  
  1480.     # This is because of some itcl bug that doesn't delete
  1481.     # the component on the destroy in some cases...
  1482.     catch {itk_component delete $buttonName-menu}
  1483.     catch {itk_component delete $buttonName}
  1484.     
  1485.     # unset our paths
  1486.     _unsetPaths $menuButtonPath
  1487.  
  1488. }
  1489.  
  1490. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1491. # ENTRY ADD, INSERT, DELETE
  1492. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1493.  
  1494. # -------------------------------------------------------------
  1495. #
  1496. # PRIVATE METHOD: _addEntry
  1497. #
  1498. # Adds an entry to menu.
  1499. #
  1500. # -------------------------------------------------------------
  1501. body iwidgets::Menubar::_addEntry { type path args } {
  1502.  
  1503.     # Error Checking
  1504.     # ''''''''''''''
  1505.     # the path should not end with '.menu'
  1506.     if { [regexp {[.]menu$} $path] } {
  1507.         error "bad entry path: \"$path\". \
  1508.                 The name \"menu\" is reserved for menu panes"
  1509.     }
  1510.  
  1511.     # get the tkMenuPath
  1512.     set tkMenuPath [_entryPathToTkMenuPath $path]
  1513.     if { $tkMenuPath == "" } {
  1514.         error "bad entry path: \"$path\". The menu path prefix is not valid"
  1515.     }
  1516.  
  1517.     # ... Store -helpstr value and strip out -helpstr value from args
  1518.     # create a helpstr option 
  1519.     set hs [iwidgets::HelpStrOption #auto]
  1520.  
  1521.     # set the -value switch from an args list
  1522.     eval "$hs set $args"
  1523.  
  1524.     # add the helpstr option to our options list (attach to entry)
  1525.     lappend _options($path) $hs
  1526.  
  1527.     # Handle CASCADE
  1528.     # ''''''''''''''
  1529.     # if this is a cascade go ahead and add in the menu...
  1530.     if { [string match cascade $type] } {
  1531.         # Catch addCascade errors
  1532.         if { [ catch {eval "_addCascade $tkMenuPath $path $args"} errMsg]} {
  1533.             # delete  $hs: @@ 2.0
  1534.             #delete $hs
  1535.             # remove $hs from _options($path)
  1536.             set lastIndex [expr [llength $_options($path)]-1]
  1537.             lreplace $_options($path) $lastIndex $lastIndex ""
  1538.             error $errMsg
  1539.         }
  1540.     # Handle Non-CASCADE
  1541.     # ''''''''''''''''''
  1542.     } else {
  1543.         # add the entry
  1544.         if { [ catch {eval "$tkMenuPath add $type $args"} errMsg] } {
  1545.             # delete  $hs: @@ 2.0
  1546.             #delete $hs
  1547.             # remove $hs from _options($path)
  1548.             set lastIndex [expr [llength $_options($path)]-1]
  1549.             lreplace $_options($path) $lastIndex $lastIndex ""
  1550.             error $errMsg
  1551.         } else {
  1552.             # update our pathmap
  1553.             set _pathMap($path) [_getPdIndex $tkMenuPath end]
  1554.         }
  1555.     }
  1556.  
  1557.     return $_pathMap($path)
  1558. }
  1559.  
  1560. # -------------------------------------------------------------
  1561. #
  1562. # PRIVATE METHOD: _addCascade
  1563. #
  1564. # Creates a cascade button.  Handles the -menu option
  1565. #
  1566. # -------------------------------------------------------------
  1567. body iwidgets::Menubar::_addCascade { tkMenuPath path args } {
  1568.  
  1569.     set menuEvalStr {}
  1570.  
  1571.     # get the cascade name from our path
  1572.     regsub {.*[.]} $path "" cascadeName
  1573.  
  1574.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1575.     # Capture the -menu option if present
  1576.     # '''''''''''''''''''''''''''''''''''
  1577.     # does the -menu switch exist in the args list??
  1578.     if { [regexp -- {-menu} $args] } {
  1579.         # Make a menu Option
  1580.         set menuOpt [iwidgets::MenuOption #auto]
  1581.  
  1582.         # set the -menu value (if present in args)
  1583.         eval "$menuOpt set $args"
  1584.  
  1585.         set menuEvalStr [$menuOpt cget -value]
  1586.  
  1587.         # add the -menu option to our options list (attach to menu)
  1588.         lappend _options($path) $menuOpt
  1589.  
  1590.     }
  1591.  
  1592.     # attach the menu pane
  1593.     lappend args -menu $tkMenuPath.$cascadeName
  1594.  
  1595.     # Catch error on adding cascade (could be bad option list, etc.)
  1596.     if { [ catch {eval "$tkMenuPath add cascade $args"} errMsg ] } {
  1597.         # if we appended $menuOpt, then remove it from _options
  1598.         if { [info exists menuOpt] } {
  1599.             # delete  menuOpt, if it exists. ( @@ fix for 2.0 )
  1600.             #delete $menuOpt
  1601.             set lastIndex [expr [llength $_options($path)]-1]
  1602.             lreplace $_options($path) $lastIndex $lastIndex ""
  1603.         }
  1604.         # signal error (for catching above)
  1605.         error $errMsg
  1606.     }
  1607.  
  1608.     # update our pathmap
  1609.     set _pathMap($path) [_getPdIndex $tkMenuPath end]
  1610.  
  1611.     regsub {[.][^.]*$} $path "" cascadePrefix
  1612.     _makeCascadeMenu $tkMenuPath $cascadePrefix $cascadeName $menuEvalStr
  1613.  
  1614.     #return $itk_component($cascadeName)
  1615.  
  1616. }
  1617.  
  1618. # -------------------------------------------------------------
  1619. #
  1620. # PRIVATE METHOD: _makeCascadeMenu
  1621. #
  1622. # Creates a menu.
  1623. # It then evaluates the $menuEvalStr to create entries on the menu.
  1624. #
  1625. # -------------------------------------------------------------
  1626. body iwidgets::Menubar::_makeCascadeMenu { tkMenuPath parentPath cascadeName menuEvalStr } {
  1627.  
  1628.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1629.     # Create menu component
  1630.     # ''''''''''''''''''''''''''''''''
  1631.     itk_component add $cascadeName-menu {
  1632.         ::menu $tkMenuPath.$cascadeName 
  1633.     } {
  1634.         keep \
  1635.             -activebackground \
  1636.             -activeborderwidth \
  1637.             -activeforeground \
  1638.             -background \
  1639.             -borderwidth \
  1640.             -cursor \
  1641.             -disabledforeground \
  1642.             -font \
  1643.             -foreground 
  1644.     }
  1645.  
  1646.     set _pathMap($parentPath.$cascadeName.menu) \
  1647.             $itk_component($cascadeName-menu)
  1648.  
  1649.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1650.     # Attach help handler to this menu
  1651.     # ''''''''''''''''''''''''''''''''
  1652.     bind $itk_component($cascadeName-menu) <Motion> \
  1653.             [code $this _helpHandler $parentPath.$cascadeName.menu %y]
  1654.     bind $itk_component($cascadeName-menu) <Leave> \
  1655.             "+[code $this _leaveHandler $parentPath.$cascadeName.menu]"
  1656.  
  1657.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1658.     # Handle -menu
  1659.     #'''''''''''''''''''''''''''''''''
  1660.     set _ourMenuPath $parentPath.$cascadeName
  1661.     set _tkMenuPath $itk_component($cascadeName-menu)
  1662.  
  1663.     #
  1664.     # A zero parseLevel says we are at the top of the parse tree,
  1665.     # so get the context scope level and do a subst for the menuEvalStr.
  1666.     #
  1667.     if { $_parseLevel == 0 } {
  1668.         set _callerLevel [_getCallerLevel]
  1669.         _substEvalStr menuEvalStr
  1670.     }
  1671.  
  1672.     #
  1673.     # bump up the parse level, so if we get called via the 'eval $menuEvalStr'
  1674.     # we know to skip the above steps...
  1675.     #
  1676.     incr _parseLevel
  1677.     eval $menuEvalStr
  1678.  
  1679.     #
  1680.     # leaving, so done with this parse level, so bump it back down 
  1681.     #
  1682.     incr _parseLevel -1
  1683. }
  1684.  
  1685. # -------------------------------------------------------------
  1686. #
  1687. # PRIVATE METHOD: _insertEntry
  1688. #
  1689. # inserts an entry on a menu before entry given by beforeEntryPath.
  1690. # The added entry is of type TYPE and its name is NAME. ARGS are
  1691. # passed for customization of the entry.
  1692. #
  1693. # -------------------------------------------------------------
  1694. body iwidgets::Menubar::_insertEntry { beforeEntryPath type name args } {
  1695.  
  1696.     # convert entryPath to an index value
  1697.     set bfIndex $_pathMap($beforeEntryPath)
  1698.  
  1699.     # first verify that beforeEntryPath is actually a path to
  1700.     # an entry and not to menu, menubutton, etc.
  1701.     if { ! [regexp {^[0-9]+$} $bfIndex] } {
  1702.         error "bad entry path: beforeEntryPath is not an entry"
  1703.     }
  1704.  
  1705.     # get the menu path from the entry path name
  1706.     regsub {[.][^.]*$} $beforeEntryPath "" menuPathPrefix
  1707.     set tkMenuPath $_pathMap($menuPathPrefix.menu)
  1708.  
  1709.     # INDEX is zero based at this point.
  1710.  
  1711.     # ENTRIES is a zero based list...
  1712.     set entries [_getEntryList $menuPathPrefix]
  1713.  
  1714.     # 
  1715.     # Adjust the entries after the inserted item, to have
  1716.     # the correct index numbers. Note, we stay zero based 
  1717.     # even though tk flips back and forth depending on tearoffs.
  1718.     #
  1719.     for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
  1720.         # path==entry path in numerical order
  1721.         set path [lindex $entries $i]
  1722.  
  1723.         # add one to each entry after the inserted one.
  1724.         set _pathMap($path) [expr $i + 1]
  1725.     }
  1726.  
  1727.     # ... Store -helpstr value and strip out -helpstr value from args
  1728.     # create a helpstr option 
  1729.     set hs [iwidgets::HelpStrOption #auto]
  1730.  
  1731.     # set the -value switch from an args list
  1732.     eval "$hs set $args"
  1733.  
  1734.     set path $menuPathPrefix.$name
  1735.  
  1736.  
  1737.     # Handle CASCADE
  1738.     # ''''''''''''''
  1739.     # if this is a cascade go ahead and add in the menu...
  1740.     if { [string match cascade $type] } {
  1741.  
  1742.         if { [ catch {eval "_insertCascade \
  1743.                 $bfIndex $tkMenuPath $path $args"} errMsg ]} {
  1744.             for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
  1745.                 # path==entry path in numerical order
  1746.                 set path [lindex $entries $i]
  1747.  
  1748.                 # sub the one we added earlier.
  1749.                 set _pathMap($path) [expr $_pathMap($path) - 1]
  1750.                 # @@ delete $hs
  1751.             }
  1752.             error $errMsg
  1753.         }
  1754.  
  1755.     # Handle Entry
  1756.     # ''''''''''''''
  1757.     } else {
  1758.  
  1759.         # give us a zero or 1-based index based on tear-off menu status
  1760.         # invoke the menu's insert command
  1761.         if { [catch {eval "$tkMenuPath insert \
  1762.                 [_getTkIndex $tkMenuPath $bfIndex] $type $args"} errMsg]} {
  1763.             for {set i $bfIndex} {$i < [llength $entries]} {incr i} {
  1764.                 # path==entry path in numerical order
  1765.                 set path [lindex $entries $i]
  1766.  
  1767.                 # sub the one we added earlier.
  1768.                 set _pathMap($path) [expr $_pathMap($path) - 1]
  1769.                 # @@ delete $hs
  1770.             }
  1771.             error $errMsg
  1772.         }
  1773.         
  1774.  
  1775.         # add the helpstr option to our options list (attach to entry)
  1776.         lappend _options($path) $hs
  1777.  
  1778.         # Insert the new entry path into pathmap giving it an index value
  1779.         set _pathMap($menuPathPrefix.$name) $bfIndex
  1780.     
  1781.     }
  1782.  
  1783.     return [_getTkIndex $tkMenuPath $bfIndex]
  1784. }
  1785.  
  1786. # -------------------------------------------------------------
  1787. #
  1788. # PRIVATE METHOD: _insertCascade
  1789. #
  1790. # Creates a cascade button.  Handles the -menu option
  1791. #
  1792. # -------------------------------------------------------------
  1793. body iwidgets::Menubar::_insertCascade { bfIndex tkMenuPath path args } {
  1794.  
  1795.     set menuEvalStr {}
  1796.  
  1797.     # get the cascade name from our path
  1798.     regsub {.*[.]} $path "" cascadeName
  1799.  
  1800.     #,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
  1801.     # Capture the -menu option if present
  1802.     # '''''''''''''''''''''''''''''''''''
  1803.     # does the -menu switch exist in the args list??
  1804.     if { [regexp -- {-menu} $args] } {
  1805.         # Make a menu Option
  1806.         set menuOpt [iwidgets::MenuOption #auto]
  1807.  
  1808.         # set the -menu value (if present in args)
  1809.         eval "$menuOpt set $args"
  1810.  
  1811.         set menuEvalStr [$menuOpt cget -value]
  1812.  
  1813.         # add the -menu option to our options list (attach to menu)
  1814.         lappend _options($path) $menuOpt
  1815.  
  1816.     }
  1817.  
  1818.     # attach the menu pane
  1819.     lappend args -menu $tkMenuPath.$cascadeName
  1820.  
  1821.     # give us a zero or 1-based index based on tear-off menu status
  1822.     # invoke the menu's insert command
  1823.     eval "$tkMenuPath insert \
  1824.             [_getTkIndex $tkMenuPath $bfIndex] cascade $args"
  1825.     
  1826.     # Insert the new entry path into pathmap giving it an index value
  1827.     set _pathMap($path) $bfIndex
  1828.  
  1829.     regsub {[.][^.]*$} $path "" cascadePrefix
  1830.     _makeCascadeMenu $tkMenuPath $cascadePrefix $cascadeName $menuEvalStr
  1831.  
  1832.     #return $itk_component($cascadeName)
  1833. }
  1834.  
  1835. # -------------------------------------------------------------
  1836. #
  1837. # PRIVATE METHOD: _deleteEntry
  1838. #
  1839. # _deleteEntry entryPath ?entryPath2?
  1840. #
  1841. #   either
  1842. # deletes the entry entryPath
  1843. #   or
  1844. # deletes the entries from entryPath to entryPath2 
  1845. #
  1846. # -------------------------------------------------------------
  1847. body iwidgets::Menubar::_deleteEntry { args } {
  1848.  
  1849.     set len [llength $args]
  1850.     switch $len {
  1851.         1 {
  1852.             # get a corrected path (subst for number, last, end)
  1853.             set path [_parsePath [lindex $args 0]]
  1854.  
  1855.             set entryIndex $_pathMap($path)
  1856.             if { $entryIndex == -1 } {
  1857.                 error "bad value for pathName: \
  1858.                         [lindex $args 0] in call to delet"
  1859.             }
  1860.  
  1861.             # get the type, if cascade, we will want to delete menu
  1862.             set type [type $path]
  1863.  
  1864.             # ... munge up the menu name ...
  1865.  
  1866.             # the tkMenuPath is looked up with the .menu added to lookup
  1867.             # strip off the entry component
  1868.             regsub {[.][^.]*$} $path "" menuPath
  1869.             set tkMenuPath $_pathMap($menuPath.menu)
  1870.  
  1871.             # get the ordered entry list
  1872.             set entries [_getEntryList $menuPath]
  1873.  
  1874.             # ... Fix up path entry indices ...
  1875.  
  1876.             # delete the path from the map
  1877.             unset _pathMap([lindex $entries $entryIndex])
  1878.  
  1879.             # Subtract off 1 for each entry below the deleted one.
  1880.             for {set i [expr $entryIndex + 1]} \
  1881.                             {$i < [llength $entries]} \
  1882.                             {incr i} {
  1883.                 set epath [lindex $entries $i]
  1884.                 incr _pathMap($epath) -1
  1885.             }
  1886.  
  1887.             # ... Delete the menu entry widget ...
  1888.  
  1889.             # delete the menu entry, ajusting index for TK
  1890.             $tkMenuPath delete [_getTkIndex $tkMenuPath $entryIndex]
  1891.  
  1892.             if { $type == "cascade" } {
  1893.                 regsub {.*[.]} $path "" cascadeName
  1894.                 destroy $itk_component($cascadeName-menu)
  1895.  
  1896.                 # This is because of some itcl bug that doesn't delete
  1897.                 # the component on the destroy in some cases...
  1898.                 catch {itk_component delete $cascadeName-menu}
  1899.  
  1900.                 _unsetPaths $path
  1901.             }
  1902.  
  1903.         }
  1904.  
  1905.         2 {
  1906.             # get a corrected path (subst for number, last, end)
  1907.             set path1 [_parsePath [lindex $args 0]]
  1908.             set path2 [_parsePath [lindex $args 1]]
  1909.  
  1910.             set fromEntryIndex $_pathMap($path1)
  1911.             if { $fromEntryIndex == -1 } {
  1912.                 error "bad value for entryPath1: \
  1913.                         [lindex $args 0] in call to delet"
  1914.             }
  1915.             set toEntryIndex $_pathMap($path2)
  1916.             if { $toEntryIndex == -1 } {
  1917.                 error "bad value for entryPath2: \
  1918.                         [lindex $args 1] in call to delet"
  1919.             }
  1920.             # ... munge up the menu name ...
  1921.  
  1922.             # the tkMenuPath is looked up with the .menu added to lookup
  1923.             # strip off the entry component
  1924.             regsub {[.][^.]*$} $path1 "" menuPath
  1925.             set tkMenuPath $_pathMap($menuPath.menu)
  1926.  
  1927.             # get the ordered entry list
  1928.             set entries [_getEntryList $menuPath]
  1929.  
  1930.             # ... Fix up path entry indices ...
  1931.  
  1932.             # delete the range from the pathMap list
  1933.             for {set i $fromEntryIndex} {$i <= $toEntryIndex} {incr i} {
  1934.                 unset _pathMap([lindex $entries $i])
  1935.             }
  1936.  
  1937.             # Subtract off 1 for each entry below the deleted range.
  1938.             # Loop from one below the bottom delete entry to end list
  1939.             for {set i [expr $toEntryIndex + 1]} \
  1940.                     {$i < [llength $entries]} \
  1941.                     {incr i} {
  1942.                 # take this path and sets its index back by size of
  1943.                 # deleted range.
  1944.                 set path [lindex $entries $i]
  1945.                 set _pathMap($path) \
  1946.                     [expr $_pathMap($path) - \
  1947.                     (($toEntryIndex - $fromEntryIndex) + 1)]
  1948.             }
  1949.  
  1950.             # ... Delete the menu entry widget ...
  1951.  
  1952.             # delete the menu entry, ajusting index for TK
  1953.             $tkMenuPath delete \
  1954.                         [_getTkIndex $tkMenuPath $fromEntryIndex] \
  1955.                         [_getTkIndex $tkMenuPath $toEntryIndex]
  1956.  
  1957.         }
  1958.  
  1959.         default {
  1960.             error "wrong # args: should be \
  1961.                     \"$itk_component(hull) delete pathName ?pathName2?\""
  1962.         }
  1963.     }
  1964. }
  1965.  
  1966. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1967. # CONFIGURATION SUPPORT
  1968. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1969. # -------------------------------------------------------------
  1970. #
  1971. # PRIVATE METHOD: _configureMenu
  1972. #
  1973. # This configures a menu. A menu is a true tk widget, thus we
  1974. # pass the tkPath variable. This path may point to either a 
  1975. # menu button (does not end with the name 'menu', or a menu
  1976. # which ends with the name 'menu'
  1977. #
  1978. # path : our Menubar path name to this menu button or menu pane.
  1979. #        if we end with the name '.menu' then it is a menu pane.
  1980. # tkPath : the path to the corresponding Tk menubutton or menu.
  1981. # args   : the args for configuration
  1982. #
  1983. # -------------------------------------------------------------
  1984. body iwidgets::Menubar::_configureMenu { path tkPath args } {
  1985.  
  1986.     set class [winfo class $tkPath]
  1987.  
  1988.     set len [llength $args]
  1989.     switch $len {
  1990.         0 {
  1991.             set configList [$tkPath configure]
  1992.  
  1993.             if { ! [catch {set _options($path)} ] } {
  1994.                 foreach option $_options($path) {
  1995.                     lappend configList [$option get]
  1996.                 }
  1997.             }
  1998.  
  1999.             return $configList
  2000.         }
  2001.         1 {
  2002.             # ... a get of one config item
  2003.             if { ! [catch {set _options($path)} ] } {
  2004.                 foreach option $_options($path) {
  2005.                     set val [$option get $args]
  2006.                     if { $val != {} } {
  2007.                         return $val
  2008.                     }
  2009.                 }
  2010.             }
  2011.                     
  2012.             # ... OTHERWISE, let Tk get it.
  2013.             return [eval "$tkPath configure $args"]
  2014.         }
  2015.         default {
  2016.             # If this is a menubutton, and has -menu option, process it
  2017.             if { $class == "Menubutton" && [regexp -- {-menu} $args] } {
  2018.                 eval "_configureMenuOption menubutton $path $args"
  2019.             } else {
  2020.                 eval "$tkPath configure $args"
  2021.             }
  2022.             return ""
  2023.         }
  2024.     }
  2025.  
  2026. }
  2027.  
  2028. # -------------------------------------------------------------
  2029. #
  2030. # PRIVATE METHOD: _configureMenuOption
  2031. #
  2032. # Allows for configuration of the -menu option on
  2033. # menubuttons and cascades
  2034. #
  2035. # find out if we are the last menu, or are before one.
  2036. # delete the old menu.
  2037. # if we are the last, then add us back at the end
  2038. # if we are before another menu, get the beforePath
  2039. #
  2040. # -------------------------------------------------------------
  2041. body iwidgets::Menubar::_configureMenuOption { type path args } {
  2042.  
  2043.     regsub {[.][^.]*$} $path "" pathPrefix
  2044.  
  2045.     if { $type == "menubutton" } {
  2046.         set menuList [_getMenuList]
  2047.         set pos [lsearch $menuList $path]
  2048.         if { $pos == [expr [llength $menuList] - 1] } {
  2049.             set insert false
  2050.         } else {
  2051.             set insert true
  2052.         }
  2053.     } elseif { $type == "cascade" } {
  2054.         set lastEntryPath [_parsePath $pathPrefix.last]
  2055.         if { $lastEntryPath == $path } {
  2056.             set insert false
  2057.         } else {
  2058.             set insert true
  2059.         }
  2060.         set pos [index $path]
  2061.  
  2062.     }
  2063.  
  2064.  
  2065.     eval "delete $pathPrefix.$pos"
  2066.     if { $insert } {
  2067.         # get name from path...
  2068.         regsub {.*[.]} $path "" name
  2069.  
  2070.         eval "insert $pathPrefix.$pos $type \
  2071.             $name $args"
  2072.     } else {
  2073.         eval "add $type $path $args"
  2074.     }
  2075. }
  2076.  
  2077. # -------------------------------------------------------------
  2078. #
  2079. # PRIVATE METHOD: _configureMenuEntry
  2080. #
  2081. # This configures a menu entry. A menu entry is either a command,
  2082. # radiobutton, separator, checkbutton, or a cascade. These have
  2083. # a corresponding Tk index value for the corresponding tk menu
  2084. # path.
  2085. #
  2086. # path   : our Menubar path name to this menu entry.
  2087. # index  : the t
  2088. # args   : the args for configuration
  2089. #
  2090. # -------------------------------------------------------------
  2091. body iwidgets::Menubar::_configureMenuEntry { path index args } {
  2092.  
  2093.     set type [type $path]
  2094.  
  2095.     set len [llength $args]
  2096.  
  2097.     # get the menu path from the entry path name
  2098.     set tkMenuPath [_entryPathToTkMenuPath $path]
  2099.  
  2100.     switch $len {
  2101.         0 {
  2102.             set configList [$tkMenuPath entryconfigure \
  2103.                     [_getTkIndex $tkMenuPath $index]]
  2104.  
  2105.             if { ! [catch {set _options($path)} ] } {
  2106.                 foreach option $_options($path) {
  2107.                     lappend configList [$option get]
  2108.                 }
  2109.             }
  2110.  
  2111.             return $configList
  2112.         }
  2113.         1 {
  2114.             # ... a get of one config item
  2115.             if { ! [catch {set _options($path)} ] } {
  2116.                 foreach option $_options($path) {
  2117.                     set val [$option get $args]
  2118.                     if { $val != {} } {
  2119.                         return $val
  2120.                     }
  2121.                 }
  2122.             }
  2123.                     
  2124.             # ... OTHERWISE, let Tk get it.
  2125.             return [eval $tkMenuPath entryconfigure \
  2126.                     [_getTkIndex $tkMenuPath $index] $args]
  2127.         }
  2128.         default {
  2129.             # ... Store -helpstr val,strip out -helpstr val from args
  2130.  
  2131.             # list of options for this widget
  2132.             foreach option $_options($path) {
  2133.                 if { [$option cget -switch] == "-helpstr" } {
  2134.                     eval "$option set $args"
  2135.                 }
  2136.             }
  2137.  
  2138.             if { $type == "cascade" && [regexp -- {-menu} $args] } {
  2139.                 eval "_configureMenuOption cascade $path $args"
  2140.             } else {
  2141.                 # invoke the menu's entryconfigure command
  2142.                 # being careful to ajust the INDEX to be 0 or 1 based 
  2143.                 # depending on the tearoff status
  2144.                 # if the stripping process brought us down to no options
  2145.                 # to set, then forget the configure of widget.
  2146.                 if { [llength $args] != 0 } {
  2147.                     eval "$tkMenuPath entryconfigure \
  2148.                                 [_getTkIndex $tkMenuPath $index] $args"
  2149.                 }
  2150.             }
  2151.             return ""
  2152.  
  2153.         }
  2154.     }
  2155. }
  2156.  
  2157. # -------------------------------------------------------------
  2158. #
  2159. # PRIVATE METHOD: _unsetPaths
  2160. #
  2161. # comment
  2162. #
  2163. # -------------------------------------------------------------
  2164. body iwidgets::Menubar::_unsetPaths { parent } {
  2165.  
  2166.     # first get the complete list of all menu paths
  2167.     set pathList [array names _pathMap]
  2168.  
  2169.     # for each path that matches parent prefix, unset it.
  2170.     foreach path $pathList {
  2171.         if { [regexp [subst -nocommands {^$parent}] $path] } {
  2172.             unset _pathMap($path)
  2173.         }
  2174.     }
  2175. }
  2176.     
  2177. # -------------------------------------------------------------
  2178. #
  2179. # PRIVATE METHOD: _entryPathToTkMenuPath
  2180. #
  2181. # Takes an entry path like .mbar.file.new and changes it to
  2182. # .mbar.file.menu and performs a lookup in the pathMap to
  2183. # get the corresponding menu widget name for tk
  2184. #
  2185. # -------------------------------------------------------------
  2186. body iwidgets::Menubar::_entryPathToTkMenuPath {entryPath} {
  2187.  
  2188.     # get the menu path from the entry path name
  2189.     # by stripping off the entry component of the path
  2190.     regsub {[.][^.]*$} $entryPath "" menuPath
  2191.  
  2192.     # the tkMenuPath is looked up with the .menu added to lookup
  2193.     if { [catch {set tkMenuPath $_pathMap($menuPath.menu)}] } {
  2194.         return ""
  2195.     } else {
  2196.         return $_pathMap($menuPath.menu)
  2197.     }
  2198. }
  2199.  
  2200.  
  2201. # -------------------------------------------------------------
  2202. #
  2203. # These two methods address the issue of menu entry indices being
  2204. # zero-based when the menu is not a tearoff menu and 1-based when
  2205. # it is a tearoff menu. Our strategy is to hide this difference.
  2206. # _getTkIndex returns the index as tk likes it: 0 based for non-tearoff
  2207. # and 1 based for tearoff menus.
  2208. # _getPdIndex (get pulldown index) always returns it as 0 based.
  2209. # -------------------------------------------------------------
  2210.  
  2211. # -------------------------------------------------------------
  2212. # PRIVATE METHOD: _getTkIndex
  2213. #
  2214. # give us a zero or 1-based answer depending on the tearoff
  2215. # status of the menu. If the menu denoted by tkMenuPath is a
  2216. # tearoff menu it returns a 1-based result, otherwise a 
  2217. # zero-based result.
  2218. # -------------------------------------------------------------
  2219. body iwidgets::Menubar::_getTkIndex { tkMenuPath tkIndex} {
  2220.  
  2221.     # if there is a tear off make it 1-based index
  2222.     if { [$tkMenuPath cget -tearoff] } {
  2223.         incr tkIndex
  2224.     }
  2225.  
  2226.     return $tkIndex
  2227. }
  2228.     
  2229. # -------------------------------------------------------------
  2230. # PRIVATE METHOD: _getPdIndex
  2231. #
  2232. # Take a tk index and give me a zero based numerical index
  2233. #
  2234. # Ask the menu widget for the index of the entry denoted by
  2235. # 'tkIndex'. Then if the menu is a tearoff adjust the value
  2236. # to be zero based.
  2237. #
  2238. # This method returns the index as if tearoffs did not exist.
  2239. # Always returns a zero-based index.
  2240. #
  2241. # -------------------------------------------------------------
  2242. body iwidgets::Menubar::_getPdIndex { tkMenuPath tkIndex } {
  2243.  
  2244.     # get the index from the tk menu
  2245.     # this 0 based for non-tearoff and 1-based for tearoffs
  2246.     set pdIndex [$tkMenuPath index $tkIndex]
  2247.  
  2248.     # if there is a tear off make it 0-based index
  2249.     if { [$tkMenuPath cget -tearoff] } {
  2250.         incr pdIndex -1
  2251.     }
  2252.  
  2253.     return $pdIndex
  2254. }
  2255.  
  2256. # -------------------------------------------------------------
  2257. # PRIVATE METHOD: _getMenuList
  2258. #
  2259. # Returns the list of menus in the order they are on the interface
  2260. # returned list is a list of our menu paths
  2261. #
  2262. # -------------------------------------------------------------
  2263. body iwidgets::Menubar::_getMenuList { } {
  2264.  
  2265.     # get the menus that are packed
  2266.     set tkPathList [pack slaves $itk_component(menubar)]
  2267.  
  2268.     regsub -- {[.]} $itk_component(hull) "" mbName
  2269.     regsub -all -- "\[.\]$mbName\[.\]menubar\[.\]" $tkPathList "." menuPathList
  2270.     return $menuPathList
  2271.     
  2272. }
  2273.  
  2274. # -------------------------------------------------------------
  2275. # PRIVATE METHOD: _getEntryList
  2276. #
  2277. #
  2278. # This method looks at a menupath and gets all the entries and
  2279. # returns a list of all the entry path names in numerical order
  2280. # based on their index values.
  2281. #
  2282. # MENU is the path to a menu, like .mbar.file.menu or .mbar.file
  2283. # we will calculate a menuPath from this: .mbar.file
  2284. # then we will build a list of entries in this menu excluding the
  2285. # path .mbar.file.menu
  2286. #
  2287. # -------------------------------------------------------------
  2288. body iwidgets::Menubar::_getEntryList { menu } {
  2289.  
  2290.     # if it ends with menu, clip it off
  2291.     regsub {[.]menu$} $menu "" menuPath
  2292.  
  2293.     # first get the complete list of all menu paths
  2294.     set pathList [array names _pathMap]
  2295.  
  2296.     set numEntries 0
  2297.     # iterate over the pathList and put on menuPathList those
  2298.     # that match the menuPattern
  2299.     foreach path $pathList {
  2300.         # if this path is on the menuPath's branch
  2301.         if { [regexp [subst -nocommands {$menuPath[.][^.]*$}] $path] } {
  2302.             # if not a menu itself
  2303.             if { ! [regexp {[.]menu$} $path] } {
  2304.                 set orderedList($_pathMap($path)) $path
  2305.                 incr numEntries
  2306.             }
  2307.         }
  2308.     }
  2309.     set entryList {}
  2310.  
  2311.     for {set i 0} {$i < $numEntries} {incr i} {
  2312.         lappend entryList $orderedList($i)
  2313.     }
  2314.  
  2315.     return $entryList
  2316.  
  2317. }
  2318.     
  2319. # -------------------------------------------------------------
  2320. # PRIVATE METHOD: _parsePath
  2321. #
  2322. # given path, PATH, _parsePath splits the path name into its
  2323. # component segments. It then puts the name back together one
  2324. # segment at a time and calls _getSymbolicPath to replace the
  2325. # keywords 'last' and 'end' as well as numeric digits.
  2326. #
  2327. # -------------------------------------------------------------
  2328. body iwidgets::Menubar::_parsePath { path } {
  2329.  
  2330.     set segments [split $path .]
  2331.  
  2332.     set concatPath ""
  2333.     foreach seg $segments {
  2334.         if {$seg == ""} {
  2335.             continue
  2336.         }
  2337.         set concatPath $concatPath.$seg
  2338.  
  2339.         set concatPath [_getSymbolicPath $concatPath]
  2340.  
  2341.         if { [catch {set _pathMap($concatPath)} ] } {
  2342.             error "bad path: \"$path\" does not exist. \"$seg\" not valid"
  2343.         }
  2344.     }
  2345.  
  2346.     return $concatPath
  2347. }
  2348.  
  2349. # -------------------------------------------------------------
  2350. # PRIVATE METHOD: _getSymbolicPath
  2351. #
  2352. # Given a PATH, _getSymbolicPath looks for the last segment of
  2353. # PATH to contain: a number, the keywords last or end. If one
  2354. # of these it figures out how to get us the actual pathname
  2355. # to the searched widget
  2356. #
  2357. # Implementor's notes:
  2358. #    Surely there is a shorter way to do this. The only diff
  2359. #    for non-numeric is getting the llength of the correct list
  2360. #    It is hard to know this upfront so it seems harder to generalize.
  2361. #
  2362. # -------------------------------------------------------------
  2363. body iwidgets::Menubar::_getSymbolicPath { path } {
  2364.  
  2365.     # get the last segment name of the path name
  2366.     regsub {.*[.]} $path "" segment
  2367.  
  2368.     set returnPath $path
  2369.  
  2370.     # if the segment is a number, then look it up positionally
  2371.     # MATCH numeric index
  2372.     if { [regexp {^[0-9]+$} $segment] } {
  2373.  
  2374.         # get the parent prefix
  2375.         regsub {[.][^.]*$} $path "" parent
  2376.  
  2377.         # if we have no parent, then we area menubutton
  2378.         if { $parent == {} } {
  2379.             set menuList [_getMenuList]
  2380.             set returnPath [lindex $menuList $segment]
  2381.         } else {
  2382.             set entryList [_getEntryList $parent.menu]
  2383.             set returnPath [lindex $entryList $segment]
  2384.         }
  2385.  
  2386.     # MATCH 'end' or 'last' keywords.
  2387.     } elseif { [string match end $segment] || \
  2388.                 [string match last $segment]} {
  2389.         # get the parent prefix
  2390.         regsub {[.][^.]*$} $path "" parent
  2391.  
  2392.         # if we have no parent, then we area menubutton
  2393.         if { $parent == {} } {
  2394.             set menuList [_getMenuList]
  2395.             set returnPath [lindex $menuList [expr [llength $menuList] - 1]]
  2396.         } else {
  2397.             set entryList [_getEntryList $parent.menu]
  2398.             set returnPath [lindex $entryList [expr [llength $entryList] - 1]]
  2399.         }
  2400.     }
  2401.  
  2402.     return $returnPath
  2403. }
  2404.  
  2405. # -------------------------------------------------------------
  2406. # PROTECTED METHOD: _leaveHandler
  2407. #
  2408. # Bound to the <Leave> event on a menu pane. This clears the
  2409. # status widget help area and resets the help entry.
  2410. #
  2411. # -------------------------------------------------------------
  2412. body iwidgets::Menubar::_leaveHandler { menuPath } {
  2413.  
  2414.     if { $itk_option(-helpvariable) == {} } {
  2415.         return
  2416.     }
  2417.  
  2418.     set $itk_option(-helpvariable) {}
  2419.     set _entryIndex -1
  2420. }
  2421.  
  2422. # -------------------------------------------------------------
  2423. # PROTECTED METHOD: _helpHandler
  2424. #
  2425. # Bound to the <Motion> event on a menu pane. This puts the
  2426. # help string associated with the menu entry into the 
  2427. # status widget help area. If no help exists for the current
  2428. # entry, the status widget is cleared.
  2429. #
  2430. # -------------------------------------------------------------
  2431. body iwidgets::Menubar::_helpHandler { menuPath menuY } {
  2432.  
  2433.     if { $itk_option(-helpvariable) == {} } {
  2434.         return
  2435.     }
  2436.  
  2437.     set tkMenuWidget $_pathMap($menuPath)
  2438.     set entryIndex [$tkMenuWidget index @$menuY]
  2439.  
  2440.     # already on this item?
  2441.     if { $entryIndex == $_entryIndex } {
  2442.         return
  2443.     }
  2444.  
  2445.     set _entryIndex $entryIndex
  2446.  
  2447.     set entries [_getEntryList $menuPath]
  2448.  
  2449.     set menuEntryHit \
  2450.             [lindex $entries [_getPdIndex $tkMenuWidget $entryIndex]]
  2451.  
  2452.     # helpvariable set for our Menubar?
  2453.     if { $itk_option(-helpvariable) != {} } {
  2454.  
  2455.         # blank out the old one
  2456.         set $itk_option(-helpvariable) {}
  2457.  
  2458.         # if there are options for this entry
  2459.         if { ! [catch {set _options($menuEntryHit)} ] } {
  2460.             foreach option $_options($menuEntryHit) {
  2461.                 # if we find the -helpstr option for this widget.
  2462.                 set args "-helpstr"
  2463.                 if { [string match [$option cget -switch] $args] } {
  2464.                     set val [lindex [$option get $args] 4]
  2465.                     if { $val != {} } {
  2466.                         set $itk_option(-helpvariable) $val
  2467.                     }
  2468.                 }
  2469.             }
  2470.         }
  2471.  
  2472.     }
  2473. }
  2474.  
  2475. # -------------------------------------------------------------
  2476. #
  2477. # PRIVATE METHOD: _getCallerLevel
  2478. #
  2479. # Starts at stack frame #0 and works down till we either hit
  2480. # a ::Menubar stack frame or an ::itk::Archetype stack frame 
  2481. # (the latter happens when a configure is called via the 'component'
  2482. # method
  2483. #
  2484. # Returns the level of the actual caller of the menubar command
  2485. # in the form of #num where num is the level number caller stack frame.
  2486. #
  2487. # -------------------------------------------------------------
  2488. body iwidgets::Menubar::_getCallerLevel { } {
  2489.  
  2490.     set levelName {}
  2491.     set levelsAreValid true
  2492.     set level 0
  2493.     set callerLevel #$level
  2494.  
  2495.     while { $levelsAreValid } {
  2496.         # Hit the end of the stack frame
  2497.         if [catch {uplevel #$level {namespace current}}] {
  2498.             set levelsAreValid false
  2499.             set callerLevel #[expr $level - 1]
  2500.         # still going
  2501.         } else {
  2502.             set newLevelName [uplevel #$level {namespace current}]
  2503.             # See if we have run into the first ::Menubar level
  2504.             if { $newLevelName == "::itk::Archetype" || \
  2505.                             $newLevelName == "::iwidgets::Menubar" } {
  2506.                 # If so, we are done-- set the callerLevel
  2507.                 set levelsAreValid false
  2508.                 set callerLevel #[expr $level - 1]
  2509.             } else {
  2510.                 set levelName $newLevelName
  2511.             }
  2512.         }
  2513.         incr level
  2514.     }
  2515.     return $callerLevel
  2516. }
  2517.