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