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 / buttonbox.itk next >
Text File  |  1999-02-24  |  18KB  |  567 lines

  1. #
  2. # Buttonbox
  3. # ----------------------------------------------------------------------
  4. # Manages a framed area with Motif style buttons.  The button box can 
  5. # be configured either horizontally or vertically.  
  6. #
  7. # ----------------------------------------------------------------------
  8. #  AUTHOR: Mark L. Ulferts               EMAIL: mulferts@spd.dsccc.com
  9. #          Bret A. Schuhmacher           EMAIL: bas@wn.com
  10. #
  11. #  @(#) $Id: buttonbox.itk,v 1.1 1998/07/27 18:49:21 stanton Exp $
  12. # ----------------------------------------------------------------------
  13. #            Copyright (c) 1995 DSC Technologies Corporation
  14. # ======================================================================
  15. # Permission to use, copy, modify, distribute and license this software 
  16. # and its documentation for any purpose, and without fee or written 
  17. # agreement with DSC, is hereby granted, provided that the above copyright 
  18. # notice appears in all copies and that both the copyright notice and 
  19. # warranty disclaimer below appear in supporting documentation, and that 
  20. # the names of DSC Technologies Corporation or DSC Communications 
  21. # Corporation not be used in advertising or publicity pertaining to the 
  22. # software without specific, written prior permission.
  23. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  24. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  25. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  26. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  27. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  28. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  29. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  30. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  31. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  32. # SOFTWARE.
  33. # ======================================================================
  34.  
  35. #
  36. # Default resources,
  37. #
  38. option add *Buttonbox.padX 5 widgetDefault
  39. option add *Buttonbox.padY 5 widgetDefault
  40. option add *Buttonbox.orient horizontal widgetDefault
  41.  
  42. #
  43. # Usual options.
  44. #
  45. itk::usual Buttonbox {
  46.     keep -background -cursor -foreground
  47. }
  48.  
  49. # ------------------------------------------------------------------
  50. #                            BUTTONBOX
  51. # ------------------------------------------------------------------
  52. class iwidgets::Buttonbox {
  53.     inherit itk::Widget
  54.  
  55.     constructor {args} {}
  56.     destructor {}
  57.  
  58.     itk_option define -pady padY Pad 5
  59.     itk_option define -padx padX Pad 5
  60.     itk_option define -orient orient Orient "horizontal"
  61.     itk_option define -foreground foreground Foreground black
  62.     
  63.     public method index {args}
  64.     public method add {args}
  65.     public method insert {args}
  66.     public method delete {args}
  67.     public method default {args}
  68.     public method hide {args}
  69.     public method show {args}
  70.     public method invoke {args}
  71.     public method buttonconfigure {args}
  72.  
  73.     private method _positionButtons {}
  74.     private method _setBoxSize {{when later}}
  75.     private method _getMaxWidth {}
  76.     private method _getMaxHeight {}
  77.  
  78.     private variable _resizeFlag {}         ;# Flag for resize needed.
  79.     private variable _buttonList {}         ;# List of all buttons in box.
  80.     private variable _displayList {}        ;# List of displayed buttons.
  81. }
  82.  
  83. namespace eval iwidgets::Buttonbox {
  84.     #
  85.     # Set up some class level bindings for map and configure events.
  86.     #
  87.     bind bbox-map <Map> [code %W _setBoxSize]
  88.     bind bbox-config <Configure> [code %W _positionButtons]
  89. }
  90.  
  91. #
  92. # Provide a lowercased access method for the Buttonbox class.
  93. proc ::iwidgets::buttonbox {pathName args} {
  94.     uplevel ::iwidgets::Buttonbox $pathName $args
  95. }
  96.     
  97. # ------------------------------------------------------------------
  98. #                        CONSTRUCTOR
  99. # ------------------------------------------------------------------
  100. body iwidgets::Buttonbox::constructor {args} {
  101.     # 
  102.     # Add Configure bindings for geometry management.  
  103.     #
  104.     bindtags $itk_component(hull) \
  105.         [linsert [bindtags $itk_component(hull)] 0 bbox-map]
  106.     bindtags $itk_component(hull) \
  107.         [linsert [bindtags $itk_component(hull)] 1 bbox-config]
  108.     
  109.     pack propagate $itk_component(hull) no
  110.     
  111.     #
  112.     # Explicitly handle configs that may have been ignored earlier.
  113.     #
  114.     eval itk_initialize $args
  115. }
  116.  
  117. # ------------------------------------------------------------------
  118. #                           DESTRUCTOR
  119. # ------------------------------------------------------------------
  120. body iwidgets::Buttonbox::destructor {} {
  121.     if {$_resizeFlag != ""} {after cancel $_resizeFlag}
  122. }
  123.  
  124. # ------------------------------------------------------------------
  125. #                             OPTIONS
  126. # ------------------------------------------------------------------
  127.  
  128. # ------------------------------------------------------------------
  129. # OPTION: -pady
  130. #
  131. # Pad the y space between the button box frame and the hull.
  132. # ------------------------------------------------------------------
  133. configbody iwidgets::Buttonbox::pady {
  134.     _setBoxSize
  135. }
  136.  
  137. # ------------------------------------------------------------------
  138. # OPTION: -padx
  139. #
  140. # Pad the x space between the button box frame and the hull.
  141. # ------------------------------------------------------------------
  142. configbody iwidgets::Buttonbox::padx {
  143.     _setBoxSize
  144. }
  145.  
  146. # ------------------------------------------------------------------
  147. # OPTION: -orient
  148. #
  149. # Position buttons either horizontally or vertically.
  150. # ------------------------------------------------------------------
  151. configbody iwidgets::Buttonbox::orient {
  152.     switch $itk_option(-orient) {
  153.     "horizontal" -
  154.     "vertical" {
  155.         _setBoxSize
  156.     }
  157.     
  158.     default {
  159.         error "bad orientation option \"$itk_option(-orient)\",\
  160.             should be either horizontal or vertical"
  161.     }
  162.     }
  163. }
  164.  
  165. # ------------------------------------------------------------------
  166. #                            METHODS
  167. # ------------------------------------------------------------------
  168.  
  169. # ------------------------------------------------------------------
  170. # METHOD: index index
  171. #
  172. # Searches the buttons in the box for the one with the requested tag,
  173. # numerical index, keyword "end" or "default".  Returns the button's 
  174. # tag if found, otherwise error.
  175. # ------------------------------------------------------------------    
  176. body iwidgets::Buttonbox::index {index} {
  177.     if {[llength $_buttonList] > 0} {
  178.     if {[regexp {(^[0-9]+$)} $index]} {
  179.         if {$index < [llength $_buttonList]} {
  180.         return $index
  181.         } else {
  182.         error "Buttonbox index \"$index\" is out of range"
  183.         }
  184.         
  185.     } elseif {$index == "end"} {
  186.         return [expr [llength $_buttonList] - 1]
  187.         
  188.     } elseif {$index == "default"} {
  189.         foreach knownButton $_buttonList {
  190.         if {[$itk_component($knownButton) cget -defaultring]} {
  191.             return [lsearch -exact $_buttonList $knownButton]
  192.         }
  193.         }
  194.         
  195.         error "Buttonbox \"$itk_component(hull)\" has no default"
  196.         
  197.     } else {
  198.         if {[set idx [lsearch $_buttonList $index]] != -1} {
  199.         return $idx
  200.         }
  201.         
  202.         error "bad Buttonbox index \"$index\": must be number, end,\
  203.             default, or pattern"
  204.     }
  205.     
  206.     } else {
  207.     error "Buttonbox \"$itk_component(hull)\" has no buttons"
  208.     }
  209. }
  210.  
  211. # ------------------------------------------------------------------
  212. # METHOD: add tag ?option value option value ...?
  213. #
  214. # Add the specified button to the button box.  All PushButton options
  215. # are allowed.  New buttons are added to the list of buttons and the 
  216. # list of displayed buttons.  The PushButton path name is returned.
  217. # ------------------------------------------------------------------
  218. body iwidgets::Buttonbox::add {tag args} {
  219.     itk_component add $tag {
  220.     iwidgets::Pushbutton $itk_component(hull).#auto
  221.     } {
  222.     keep -disabledforeground -highlightthickness -borderwidth \
  223.         -font -highlightcolor -background \
  224.         -foreground -activebackground -cursor -activeforeground 
  225.     rename -highlightbackground -background background Background
  226.     }
  227.     
  228.     if {$args != ""} {
  229.     uplevel $itk_component($tag) configure $args
  230.     }
  231.     
  232.     lappend _buttonList $tag
  233.     lappend _displayList $tag
  234.     
  235.     _setBoxSize
  236. }
  237.  
  238. # ------------------------------------------------------------------
  239. # METHOD: insert index tag ?option value option value ...?
  240. #
  241. # Insert the specified button in the button box just before the one 
  242. # given by index.  All PushButton options are allowed.  New buttons 
  243. # are added to the list of buttons and the list of displayed buttons.
  244. # The PushButton path name is returned.
  245. # ------------------------------------------------------------------
  246. body iwidgets::Buttonbox::insert {index tag args} {
  247.     itk_component add $tag {
  248.     iwidgets::Pushbutton $itk_component(hull).#auto
  249.     } {
  250.     keep -disabledforeground -highlightthickness -borderwidth \
  251.         -font -highlightcolor -background \
  252.         -foreground -activebackground -cursor -activeforeground 
  253.     rename -highlightbackground -background background Background
  254.     }
  255.     
  256.     if {$args != ""} {
  257.     uplevel $itk_component($tag) configure $args
  258.     }
  259.     
  260.     set index [index $index]
  261.     set _buttonList [linsert $_buttonList $index $tag]
  262.     set _displayList [linsert $_displayList $index $tag]
  263.     
  264.     _setBoxSize
  265. }
  266.  
  267. # ------------------------------------------------------------------
  268. # METHOD: delete index
  269. #
  270. # Delete the specified button from the button box.
  271. # ------------------------------------------------------------------
  272. body iwidgets::Buttonbox::delete {index} {
  273.     set index [index $index]
  274.     set tag [lindex $_buttonList $index]
  275.     
  276.     destroy $itk_component($tag)
  277.     
  278.     set _buttonList [lreplace $_buttonList $index $index]
  279.     
  280.     if {[set dind [lsearch $_displayList $tag]] != -1} {
  281.     set _displayList [lreplace $_displayList $dind $dind]
  282.     }
  283.     
  284.     _setBoxSize
  285.     update idletasks
  286. }
  287.  
  288. # ------------------------------------------------------------------
  289. # METHOD: default index
  290. #
  291. # Sets the default to the push button given by index.
  292. # ------------------------------------------------------------------
  293. body iwidgets::Buttonbox::default {index} {
  294.     set index [index $index]
  295.     
  296.     set defbtn [lindex $_buttonList $index]
  297.     
  298.     foreach knownButton $_displayList {
  299.     if {$knownButton == $defbtn} {
  300.         $itk_component($knownButton) configure -defaultring yes
  301.     } else {
  302.         $itk_component($knownButton) configure -defaultring no
  303.     }
  304.     }
  305. }
  306.  
  307. # ------------------------------------------------------------------
  308. # METHOD: hide index
  309. #
  310. # Hide the push button given by index.  This doesn't remove the button 
  311. # permanently from the display list, just inhibits its display.
  312. # ------------------------------------------------------------------
  313. body iwidgets::Buttonbox::hide {index} {
  314.     set index [index $index]
  315.     set tag [lindex $_buttonList $index]
  316.     
  317.     if {[set dind [lsearch $_displayList $tag]] != -1} {
  318.     place forget $itk_component($tag)
  319.     set _displayList [lreplace $_displayList $dind $dind] 
  320.     
  321.     _setBoxSize
  322.     }
  323. }
  324.  
  325. # ------------------------------------------------------------------
  326. # METHOD: show index
  327. #
  328. # Displays a previously hidden push button given by index.  Check if 
  329. # the button is already in the display list.  If not then add it back 
  330. # at it's original location and redisplay.
  331. # ------------------------------------------------------------------
  332. body iwidgets::Buttonbox::show {index} {
  333.     set index [index $index]
  334.     set tag [lindex $_buttonList $index]
  335.     
  336.     if {[lsearch $_displayList $tag] == -1} {
  337.     set _displayList [linsert $_displayList $index $tag]
  338.     
  339.     _setBoxSize
  340.     }
  341. }
  342.  
  343. # ------------------------------------------------------------------
  344. # METHOD: invoke ?index?
  345. #
  346. # Invoke the command associated with a push button.  If no arguments
  347. # are given then the default button is invoked, otherwise the argument
  348. # is expected to be a button index.
  349. # ------------------------------------------------------------------
  350. body iwidgets::Buttonbox::invoke {args} {
  351.     if {[llength $args] == 0} {
  352.     $itk_component([lindex $_buttonList [index default]]) invoke
  353.     
  354.     } else {
  355.     $itk_component([lindex $_buttonList [index [lindex $args 0]]]) \
  356.         invoke
  357.     }
  358. }
  359.  
  360. # ------------------------------------------------------------------
  361. # METHOD: buttonconfigure index ?option? ?value option value ...?
  362. #
  363. # Configure a push button given by index.  This method allows 
  364. # configuration of pushbuttons from the Buttonbox level.  The options
  365. # may have any of the values accepted by the add method.
  366. # ------------------------------------------------------------------
  367. body iwidgets::Buttonbox::buttonconfigure {index args} {
  368.     set tag [lindex $_buttonList [index $index]]
  369.     
  370.     set retstr [uplevel $itk_component($tag) configure $args]
  371.     
  372.     _setBoxSize
  373.     
  374.     return $retstr
  375. }
  376.  
  377. # -----------------------------------------------------------------
  378. # PRIVATE METHOD: _getMaxWidth
  379. #
  380. # Returns the required width of the largest button.
  381. # -----------------------------------------------------------------
  382. body iwidgets::Buttonbox::_getMaxWidth {} {
  383.     set max 0
  384.     
  385.     foreach tag $_displayList {
  386.     set w [winfo reqwidth $itk_component($tag)]
  387.     
  388.     if {$w > $max} {
  389.         set max $w
  390.     }
  391.     }
  392.     
  393.     return $max
  394. }
  395.  
  396. # -----------------------------------------------------------------
  397. # PRIVATE METHOD: _getMaxHeight
  398. #
  399. # Returns the required height of the largest button.
  400. # -----------------------------------------------------------------
  401. body iwidgets::Buttonbox::_getMaxHeight {} {
  402.     set max 0
  403.     
  404.     foreach tag $_displayList {
  405.     set h [winfo reqheight $itk_component($tag)]
  406.     
  407.     if {$h > $max} {
  408.         set max $h
  409.     }
  410.     }
  411.     
  412.     return $max
  413. }
  414.  
  415. # ------------------------------------------------------------------
  416. # METHOD: _setBoxSize ?when?
  417. #
  418. # Sets the proper size of the frame surrounding all the buttons.
  419. # If "when" is "now", the change is applied immediately.  If it is 
  420. # "later" or it is not specified, then the change is applied later, 
  421. # when the application is idle.
  422. # ------------------------------------------------------------------
  423. body iwidgets::Buttonbox::_setBoxSize {{when later}} {
  424.     if {[winfo ismapped $itk_component(hull)]} {
  425.     if {$when == "later"} {
  426.         if {$_resizeFlag == ""} {
  427.         set _resizeFlag [after idle [code $this _setBoxSize now]]
  428.         }
  429.         return
  430.     } elseif {$when != "now"} {
  431.         error "bad option \"$when\": should be now or later"
  432.     }
  433.  
  434.     set _resizeFlag ""
  435.  
  436.     set numBtns [llength $_displayList]
  437.     
  438.     if {$itk_option(-orient) == "horizontal"} {
  439.         set minw [expr $numBtns * [_getMaxWidth] \
  440.             + ($numBtns+1) * $itk_option(-padx)]
  441.         set minh [expr [_getMaxHeight] + 2 * $itk_option(-pady)]
  442.         
  443.     } else {
  444.         set minw [expr [_getMaxWidth] + 2 * $itk_option(-padx)]
  445.         set minh [expr $numBtns * [_getMaxHeight] \
  446.             + ($numBtns+1) * $itk_option(-pady)]
  447.     }
  448.     
  449.     #
  450.     # Remove the configure event bindings on the hull while we adjust the
  451.     # width/height and re-position the buttons.  Once we're through, we'll
  452.     # update and reinstall them.  This prevents double calls to position
  453.     # the buttons.
  454.     #
  455.     set tags [bindtags $itk_component(hull)]
  456.     if {[set i [lsearch $tags bbox-config]] != -1} {
  457.         set tags [lreplace $tags $i $i]
  458.         bindtags $itk_component(hull) $tags
  459.     }
  460.     
  461.     component hull configure -width $minw -height $minh
  462.     
  463.     update idletasks
  464.         
  465.     _positionButtons
  466.     
  467.     bindtags $itk_component(hull) [linsert $tags 0 bbox-config]
  468.     }
  469. }
  470.     
  471. # ------------------------------------------------------------------
  472. # METHOD: _positionButtons
  473. # This method is responsible setting the width/height of all the 
  474. # displayed buttons to the same value and for placing all the buttons
  475. # in equidistant locations.
  476. # ------------------------------------------------------------------
  477. body iwidgets::Buttonbox::_positionButtons {} {
  478.     set bf $itk_component(hull)
  479.     set numBtns [llength $_displayList]
  480.     
  481.     # 
  482.     # First, determine the common width and height for all the 
  483.     # displayed buttons.
  484.     #
  485.     if {$numBtns > 0} {
  486.     set bfWidth [winfo width $itk_component(hull)]
  487.     set bfHeight [winfo height $itk_component(hull)]
  488.     
  489.     if {$bfWidth >= [winfo reqwidth $itk_component(hull)]} {
  490.         set _btnWidth [_getMaxWidth] 
  491.         
  492.     } else {
  493.         if {$itk_option(-orient) == "horizontal"} {
  494.         set _btnWidth [expr $bfWidth / $numBtns]
  495.         } else {
  496.         set _btnWidth $bfWidth
  497.         }
  498.     }        
  499.     
  500.     if {$bfHeight >= [winfo reqheight $itk_component(hull)]} {
  501.         set _btnHeight [_getMaxHeight]
  502.         
  503.     } else {
  504.         if {$itk_option(-orient) == "vertical"} {
  505.         set _btnHeight [expr $bfHeight / $numBtns]
  506.         } else {
  507.         set _btnHeight $bfHeight
  508.         }
  509.     }        
  510.     }
  511.     
  512.     #
  513.     # Place the buttons at the proper locations.
  514.     #
  515.     if {$numBtns > 0} {
  516.     if {$itk_option(-orient) == "horizontal"} {
  517.         set leftover [expr [winfo width $bf] \
  518.             - 2 * $itk_option(-padx) - $_btnWidth * $numBtns]
  519.         
  520.         if {$numBtns > 0} {
  521.         set offset [expr $leftover / ($numBtns + 1)]
  522.         } else {
  523.         set offset 0
  524.         }
  525.         if {$offset < 0} {set offset 0}
  526.         
  527.         set xDist [expr $itk_option(-padx) + $offset]
  528.         set incrAmount [expr $_btnWidth + $offset]
  529.         
  530.         foreach button $_displayList {
  531.         place $itk_component($button) -anchor w \
  532.             -x $xDist -rely .5 -y 0 -relx 0 \
  533.             -width $_btnWidth -height $_btnHeight
  534.         
  535.         set xDist [expr $xDist + $incrAmount]
  536.         }
  537.         
  538.     } else {
  539.         set leftover [expr [winfo height $bf] \
  540.             - 2 * $itk_option(-pady) - $_btnHeight * $numBtns]
  541.         
  542.         if {$numBtns > 0} {
  543.         set offset [expr $leftover / ($numBtns + 1)]
  544.         } else {
  545.         set offset 0
  546.         }
  547.         if {$offset < 0} {set offset 0}
  548.         
  549.         set yDist [expr $itk_option(-pady) + $offset]
  550.         set incrAmount [expr $_btnHeight + $offset]
  551.         
  552.         foreach button $_displayList {
  553.         place $itk_component($button) -anchor n \
  554.             -y $yDist -relx .5 -x 0 -rely 0 \
  555.             -width $_btnWidth -height $_btnHeight
  556.         
  557.         set yDist [expr $yDist + $incrAmount]
  558.         }
  559.     }
  560.     }
  561. }
  562.  
  563.  
  564.