home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / panedwindow.itk < prev    next >
Text File  |  2003-09-01  |  31KB  |  943 lines

  1. #
  2. # Panedwindow
  3. # ----------------------------------------------------------------------
  4. # Implements a multiple paned window widget capable of orienting the panes
  5. # either vertically or horizontally.  Each pane is itself a frame acting
  6. # as a child site for other widgets.  The border separating each pane 
  7. # contains a sash which allows user positioning of the panes relative to
  8. # one another.  
  9. #
  10. # ----------------------------------------------------------------------
  11. #  AUTHOR: Mark L. Ulferts              EMAIL: mulferts@austin.dsccc.com
  12. #
  13. #  @(#) $Id: panedwindow.itk,v 1.7 2001/09/06 15:12:46 smithc Exp $
  14. # ----------------------------------------------------------------------
  15. #            Copyright (c) 1995 DSC Technologies Corporation
  16. # ======================================================================
  17. # Permission to use, copy, modify, distribute and license this software 
  18. # and its documentation for any purpose, and without fee or written 
  19. # agreement with DSC, is hereby granted, provided that the above copyright 
  20. # notice appears in all copies and that both the copyright notice and 
  21. # warranty disclaimer below appear in supporting documentation, and that 
  22. # the names of DSC Technologies Corporation or DSC Communications 
  23. # Corporation not be used in advertising or publicity pertaining to the 
  24. # software without specific, written prior permission.
  25. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  26. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  27. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  28. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  29. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  30. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  31. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  32. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  33. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  34. # SOFTWARE.
  35. # ======================================================================
  36.  
  37. #
  38. # Usual options.
  39. #
  40. itk::usual Panedwindow {
  41.     keep -background -cursor -sashcursor
  42. }
  43.  
  44. # ------------------------------------------------------------------
  45. #                            PANEDWINDOW
  46. # ------------------------------------------------------------------
  47. itcl::class iwidgets::Panedwindow {
  48.     inherit itk::Widget
  49.  
  50.     constructor {args} {}
  51.  
  52.     itk_option define -orient orient Orient horizontal 
  53.     itk_option define -sashborderwidth sashBorderWidth SashBorderWidth 2
  54.     itk_option define -sashcursor sashCursor SashCursor crosshair
  55.     itk_option define -sashwidth sashWidth SashWidth 10
  56.     itk_option define -sashheight sashHeight SashHeight 10
  57.     itk_option define -thickness thickness Thickness 3
  58.     itk_option define -sashindent sashIndent SashIndent -10
  59.     itk_option define -showhandle showHandle ShowHandle 1
  60.  
  61.     public method index {index} 
  62.     public method childsite {args} 
  63.     public method fraction {args}
  64.     public method add {tag args} 
  65.     public method insert {index tag args} 
  66.     public method delete {index} 
  67.     public method hide {index}    
  68.     public method show {index} 
  69.     public method paneconfigure {index args} 
  70.     public method reset {} 
  71.  
  72.     protected method _pwConfigureEventHandler {width height} 
  73.     protected method _startGrip {where num} 
  74.     protected method _endGrip {where num} 
  75.     protected method _configGrip {where num} 
  76.     protected method _handleGrip {where num} 
  77.     protected method _moveSash {where num} 
  78.  
  79.     private method _setFracArray {} 
  80.     private method _setActivePanes {} 
  81.     private method _calcFraction {where num} 
  82.     private method _makeSashes {} 
  83.     private method _placeSash {i} 
  84.     private method _placePanes {{start 0} {end end}} 
  85.     
  86.     private variable _initialized 0    ;# Denotes initialized state.
  87.     private variable _panes {}         ;# List of panes.
  88.     private variable _activePanes {}   ;# List of active panes.
  89.     private variable _sashes {}        ;# List of sashes.
  90.     private variable _separators {}    ;# List of separators.
  91.     private variable _frac             ;# Array of fraction percentages.
  92.     private variable _lowerlimit       ;# Margin distance above/left of sash.
  93.     private variable _upperlimit       ;# Margin distance below/right of sash.
  94.     private variable _dimension        ;# Width/Height at start of drag.
  95.     private variable _sashloc          ;# Array of dist of sash from above/left.
  96.     private variable _pixels           ;# Array of dist of sash from above/left.
  97.     private variable _minheight        ;# Array of min heights for panes.
  98.     private variable _minsashmoved     ;# Lowest sash moved during dragging.
  99.     private variable _maxsashmoved     ;# Highest sash moved during dragging.
  100.     private variable _dragging 0       ;# Boolean for dragging enabled.
  101.     private variable _movecount 0      ;# Kludge counter to get sashes to
  102.                                        ;# display without calling update 
  103.                                        ;# idletasks too often.
  104.     private variable _width 0          ;# hull's width.
  105.     private variable _height 0         ;# hull's height.
  106.     private variable _unique -1         ;# Unique number for pane names.
  107.  
  108.     private variable _relief          ;# relief for -showhandle
  109. }
  110.  
  111. #
  112. # Provide a lowercased access method for the Panedwindow class.
  113. proc ::iwidgets::panedwindow {pathName args} {
  114.     uplevel ::iwidgets::Panedwindow $pathName $args
  115. }
  116.  
  117. #
  118. # Use option database to override default resources of base classes.
  119. #
  120. option add *Panedwindow.width 10 widgetDefault
  121. option add *Panedwindow.height 10 widgetDefault
  122.  
  123. # ------------------------------------------------------------------
  124. #                        CONSTRUCTOR
  125. # ------------------------------------------------------------------
  126. itcl::body iwidgets::Panedwindow::constructor {args} {
  127.     itk_option add hull.width hull.height
  128.  
  129.     pack propagate $itk_component(hull) no
  130.     
  131.     #
  132.     # Add binding for the configure event.
  133.     #
  134.     bind pw-config-$this <Configure> [itcl::code $this _pwConfigureEventHandler %w %h]
  135.     bindtags $itk_component(hull) \
  136.         [linsert [bindtags $itk_component(hull)] 0 pw-config-$this]
  137.     
  138.     array set _relief {0 sunken 1 raised}
  139.  
  140.     eval itk_initialize $args
  141. }
  142.  
  143. # ------------------------------------------------------------------
  144. #                             OPTIONS
  145. # ------------------------------------------------------------------
  146.  
  147. # ------------------------------------------------------------------
  148. # OPTION: -orient
  149. #
  150. # Specifies the orientation of the sashes.  Once the paned window
  151. # has been mapped, set the sash bindings and place the panes.
  152. # ------------------------------------------------------------------
  153. itcl::configbody iwidgets::Panedwindow::orient {
  154.     if {$_initialized} {
  155.     switch $itk_option(-orient) {
  156.         vertical {
  157.         for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  158.             bind $itk_component(sash$i) <Button-1> \
  159.                 [itcl::code $this _startGrip %x $i]
  160.             bind $itk_component(sash$i) <B1-Motion> \
  161.                 [itcl::code $this _handleGrip %x $i]
  162.             bind $itk_component(sash$i) <B1-ButtonRelease-1> \
  163.                 [itcl::code $this _endGrip %x $i]
  164.             bind $itk_component(sash$i) <Configure> \
  165.                 [itcl::code $this _configGrip %x $i]
  166.         }
  167.         
  168.         _setFracArray
  169.         _makeSashes
  170.         _placePanes
  171.         }
  172.         
  173.         horizontal {
  174.         for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  175.             bind $itk_component(sash$i) <Button-1> \
  176.                 [itcl::code $this _startGrip %y $i]
  177.             bind $itk_component(sash$i) <B1-Motion> \
  178.                 [itcl::code $this _handleGrip %y $i]
  179.             bind $itk_component(sash$i) <B1-ButtonRelease-1> \
  180.                 [itcl::code $this _endGrip %y $i]
  181.             bind $itk_component(sash$i) <Configure> \
  182.                 [itcl::code $this _configGrip %y $i]
  183.         }
  184.         
  185.         _setFracArray
  186.         _makeSashes
  187.         _placePanes
  188.         }
  189.         
  190.         default {
  191.         error "bad orientation option \"$itk_option(-orient)\":\
  192.             should be horizontal or vertical"
  193.         }
  194.     }
  195.     }
  196. }
  197.  
  198. # ------------------------------------------------------------------
  199. # OPTION: -sashborderwidth
  200. #
  201. # Specifies a non-negative value indicating the width of the 3-D
  202. # border to draw around the outside of the sash.
  203. # ------------------------------------------------------------------
  204. itcl::configbody iwidgets::Panedwindow::sashborderwidth {
  205.     set pixels [winfo pixels $itk_component(hull) \
  206.         $itk_option(-sashborderwidth)]
  207.     set itk_option(-sashborderwidth) $pixels
  208.     
  209.     if {$_initialized} {
  210.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  211.         $itk_component(sash$i) configure \
  212.             -borderwidth $itk_option(-sashborderwidth)
  213.     }
  214.     }
  215. }
  216.  
  217. # ------------------------------------------------------------------
  218. # OPTION: -sashcursor
  219. #
  220. # Specifies the type of cursor to be used when over the sash.
  221. # ------------------------------------------------------------------
  222. itcl::configbody iwidgets::Panedwindow::sashcursor {
  223.     if {$_initialized} {
  224.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  225.         $itk_component(sash$i) configure -cursor $itk_option(-sashcursor)
  226.     }
  227.     }
  228. }
  229.  
  230. # ------------------------------------------------------------------
  231. # OPTION: -sashwidth
  232. #
  233. # Specifies the width of the sash.
  234. # ------------------------------------------------------------------
  235. itcl::configbody iwidgets::Panedwindow::sashwidth {
  236.     set pixels [winfo pixels $itk_component(hull) \
  237.         $itk_option(-sashwidth)]
  238.     set itk_option(-sashwidth) $pixels
  239.     
  240.     if {$_initialized} {
  241.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  242.         $itk_component(sash$i) configure \
  243.             -width $itk_option(-sashwidth)
  244.     }
  245.     }
  246. }
  247.  
  248. # ------------------------------------------------------------------
  249. # OPTION: -sashheight
  250. #
  251. # Specifies the height of the sash,
  252. # ------------------------------------------------------------------
  253. itcl::configbody iwidgets::Panedwindow::sashheight {
  254.     set pixels [winfo pixels $itk_component(hull) \
  255.         $itk_option(-sashheight)]
  256.     set itk_option(-sashheight) $pixels
  257.     
  258.     if {$_initialized} {
  259.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  260.         $itk_component(sash$i) configure \
  261.             -height $itk_option(-sashheight)
  262.     }
  263.     }
  264. }
  265.  
  266. # ------------------------------------------------------------------
  267. # OPTION: -showhandle
  268. #
  269. # Specifies whether or not to show the sash handle. If not, then the
  270. # whole separator becomes the handle.  Valid values are 0 or 1.
  271. # ------------------------------------------------------------------
  272. itcl::configbody iwidgets::Panedwindow::showhandle {
  273.   switch $itk_option(-showhandle) {
  274.     0 - 1 {
  275.       # Update the sashes.
  276.       _makeSashes
  277.       _placePanes
  278.     }
  279.     default {
  280.       error "Invalid option for -showhandle: $itk_option(-showhandle).\
  281.         Must be 1 or 0."
  282.     }
  283.   }
  284. }
  285.  
  286.  
  287. # ------------------------------------------------------------------
  288. # OPTION: -thickness
  289. #
  290. # Specifies the thickness of the separators.  It sets the width and
  291. # height of the separator to the thickness value and the borderwidth
  292. # to half the thickness.
  293. # ------------------------------------------------------------------
  294. itcl::configbody iwidgets::Panedwindow::thickness {
  295.     set pixels [winfo pixels $itk_component(hull) \
  296.         $itk_option(-thickness)]
  297.     set itk_option(-thickness) $pixels
  298.     
  299.     if {$_initialized} {
  300.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  301.         $itk_component(separator$i) configure \
  302.             -height $itk_option(-thickness)
  303.         $itk_component(separator$i) configure \
  304.             -width $itk_option(-thickness)
  305.         $itk_component(separator$i) configure \
  306.             -borderwidth [expr {$itk_option(-thickness) / 2}]
  307.     }
  308.     
  309.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  310.         _placeSash $i
  311.     }
  312.     }
  313. }
  314.  
  315. # ------------------------------------------------------------------
  316. # OPTION: -sashindent
  317. #
  318. # Specifies the placement of the sash along the panes.  A positive
  319. # value causes the sash to be offset from the near (left/top) side
  320. # of the pane, and a negative value causes the sash to be offset from
  321. # the far (right/bottom) side.  If the offset is greater than the 
  322. # width, then the sash is placed flush against the side.  
  323. # ------------------------------------------------------------------
  324. itcl::configbody iwidgets::Panedwindow::sashindent {
  325.     set pixels [winfo pixels $itk_component(hull) \
  326.         $itk_option(-sashindent)]
  327.     set itk_option(-sashindent) $pixels
  328.     
  329.     if {$_initialized} {
  330.     for {set i 1} {$i < [llength $_activePanes]} {incr i} {
  331.         _placeSash $i
  332.     }
  333.     }
  334. }
  335.  
  336. # ------------------------------------------------------------------
  337. #                            METHODS
  338. # ------------------------------------------------------------------
  339.  
  340. # ------------------------------------------------------------------
  341. # METHOD: index index
  342. #
  343. # Searches the panes in the paned window for the one with the 
  344. # requested tag, numerical index, or keyword "end".  Returns the pane's 
  345. # numerical index if found, otherwise error.
  346. # ------------------------------------------------------------------    
  347. itcl::body iwidgets::Panedwindow::index {index} {
  348.     if {[llength $_panes] > 0} {
  349.     if {[regexp {(^[0-9]+$)} $index]} {
  350.         if {$index < [llength $_panes]} {
  351.         return $index
  352.         } else {
  353.         error "Panedwindow index \"$index\" is out of range"
  354.         }
  355.         
  356.     } elseif {$index == "end"} {
  357.         return [expr {[llength $_panes] - 1}]
  358.         
  359.     } else {
  360.         if {[set idx [lsearch $_panes $index]] != -1} {
  361.         return $idx
  362.         }
  363.         
  364.         error "bad Panedwindow index \"$index\": must be number, end,\
  365.             or pattern"
  366.     }
  367.     
  368.     } else {
  369.     error "Panedwindow \"$itk_component(hull)\" has no panes"
  370.     }
  371. }
  372.  
  373. # ------------------------------------------------------------------
  374. # METHOD: childsite ?index?
  375. #
  376. # Given an index return the specifc childsite path name.  Invoked 
  377. # without an index return a list of all the child site panes.  The 
  378. # list is ordered from the near side (left/top).
  379. # ------------------------------------------------------------------
  380. itcl::body iwidgets::Panedwindow::childsite {args} {
  381.     if {! $_initialized} {
  382.     set _initialized 1
  383.     reset
  384.     }
  385.  
  386.     if {[llength $args] == 0} {
  387.     set children {}
  388.     
  389.     foreach pane $_panes {
  390.         lappend children [$itk_component($pane) childSite]
  391.     }
  392.     
  393.     return $children
  394.     
  395.     } else {
  396.     set index [index [lindex $args 0]]
  397.     return [$itk_component([lindex $_panes $index]) childSite]
  398.     }
  399. }
  400.  
  401. # ------------------------------------------------------------------
  402. # METHOD: fraction percentage percentage ?percentage ...?
  403. #
  404. # Sets the visible percentage of the panes.  Specifies a list of
  405. # percentages which are applied to the currently visible panes from 
  406. # the near side (left/top).  The number of percentages must be equal 
  407. # to the current number of visible (mapped) panes and add up to 100.
  408. # ------------------------------------------------------------------
  409. itcl::body iwidgets::Panedwindow::fraction {args} {
  410.     #set args [linsert $args 0 $percentage1 $percentage2]
  411.  
  412.     
  413.     if {[llength $args] == [llength $_activePanes]} {
  414.     set sum 0
  415.     
  416.     for {set i 0} {$i < [llength $args]} {incr i} {
  417.         set sum [expr {$sum + [lindex $args $i]}]
  418.     }
  419.     
  420.     if {$sum == 100} {
  421.         set perc 0.0
  422.         
  423.         for {set i 0} {$i < [llength $_activePanes]} {incr i} {
  424.         set _frac($i) $perc
  425.         set perc [expr {$perc + [expr {[lindex $args $i] / 100.0}]}]
  426.         }
  427.         
  428.         set _frac($i) 1.0
  429.         
  430.         if {[winfo ismapped $itk_component(hull)]} {
  431.         _placePanes
  432.         }
  433.         
  434.     } else {
  435.         error "bad fraction arguments \"$args\": they should add\
  436.             up to 100"
  437.     }
  438.     
  439.     } elseif {[llength $args] == 0} {
  440.  
  441.         for {set i 0; set j 1} {$j < [llength $_activePanes]} {incr i; incr j} {
  442.             lappend _ret [expr {round(($_frac($j) - $_frac($i))*100)}]
  443.         }
  444.     lappend _ret [eval expr {100 - ([join $_ret +])}]
  445.  
  446.         return $_ret
  447.     } else {
  448.     error "wrong # args: should be \"$itk_component(hull)\
  449.         fraction percentage percentage ?percentage ...?\",\
  450.         where the number of percentages is\
  451.         [llength $_activePanes] and equal 100
  452.         or \"$itk_component(hull) fraction\"
  453.         which will return a list of the current percentages"
  454.     }
  455. }
  456.  
  457. # ------------------------------------------------------------------
  458. # METHOD: add tag ?option value option value ...?
  459. #
  460. # Add a new pane to the paned window to the far (right/bottom) side.
  461. # The method takes additional options which are passed on to the 
  462. # pane constructor.  These include -margin, and -minimum.  The path 
  463. # of the pane is returned.
  464. # ------------------------------------------------------------------
  465. itcl::body iwidgets::Panedwindow::add {tag args} {
  466.     #
  467.     # Create panes.
  468.     #
  469.     itk_component add $tag {
  470.     eval iwidgets::Pane $itk_interior.pane[incr _unique] $args
  471.     } {
  472.     keep -background -cursor
  473.     }
  474.     
  475.     lappend _panes $tag
  476.     lappend _activePanes $tag
  477.     
  478.     reset
  479.     
  480.     return $itk_component($tag)
  481. }
  482.  
  483. # ------------------------------------------------------------------
  484. # METHOD: insert index tag ?option value option value ...?
  485. #
  486. # Insert the specified pane in the paned window just before the one 
  487. # given by index.  Any additional options which are passed on to the 
  488. # pane constructor.  These include -margin, -minimum.  The path of 
  489. # the pane is returned.
  490. # ------------------------------------------------------------------
  491. itcl::body iwidgets::Panedwindow::insert {index tag args} {
  492.     #
  493.     # Create panes.
  494.     #
  495.     itk_component add $tag {
  496.     eval iwidgets::Pane $itk_interior.pane[incr _unique] $args
  497.     } {
  498.     keep -background -cursor
  499.     }
  500.     
  501.     set index [index $index]
  502.     set _panes [linsert $_panes $index $tag]
  503.     lappend _activePanes $tag
  504.     
  505.     reset
  506.     
  507.     return $itk_component($tag)
  508. }
  509.  
  510. # ------------------------------------------------------------------
  511. # METHOD: delete index
  512. #
  513. # Delete the specified pane.
  514. # ------------------------------------------------------------------
  515. itcl::body iwidgets::Panedwindow::delete {index} {
  516.     set index [index $index]
  517.     set tag [lindex $_panes $index]
  518.     
  519.     destroy $itk_component($tag)
  520.     
  521.     set _panes [lreplace $_panes $index $index]
  522.     
  523.     reset
  524. }
  525.  
  526. # ------------------------------------------------------------------
  527. # METHOD: hide index
  528. #
  529. # Remove the specified pane from the paned window. 
  530. # ------------------------------------------------------------------
  531. itcl::body iwidgets::Panedwindow::hide {index} {
  532.     set index [index $index]
  533.     set tag [lindex $_panes $index]
  534.     
  535.     if {[set idx [lsearch -exact $_activePanes $tag]] != -1} {
  536.     set _activePanes [lreplace $_activePanes $idx $idx]
  537.     }
  538.     
  539.     reset
  540. }   
  541.  
  542. # ------------------------------------------------------------------
  543. # METHOD: show index
  544. #
  545. # Display the specified pane in the paned window.
  546. # ------------------------------------------------------------------
  547. itcl::body iwidgets::Panedwindow::show {index} {
  548.     set index [index $index]
  549.     set tag [lindex $_panes $index]
  550.     
  551.     if {[lsearch -exact $_activePanes $tag] == -1} {
  552.     lappend _activePanes $tag
  553.     }
  554.     
  555.     reset
  556. }   
  557.  
  558. # ------------------------------------------------------------------
  559. # METHOD: paneconfigure index ?option? ?value option value ...?
  560. #
  561. # Configure a specified pane.  This method allows configuration of
  562. # panes from the Panedwindow level.  The options may have any of the 
  563. # values accepted by the add method.
  564. # ------------------------------------------------------------------
  565. itcl::body iwidgets::Panedwindow::paneconfigure {index args} {
  566.     set index [index $index]
  567.     set tag [lindex $_panes $index]
  568.     
  569.     return [uplevel $itk_component($tag) configure $args]
  570. }
  571.  
  572. # ------------------------------------------------------------------
  573. # METHOD: reset
  574. #
  575. # Redisplay the panes based on the default percentages of the panes.
  576. # ------------------------------------------------------------------
  577. itcl::body iwidgets::Panedwindow::reset {} {
  578.     if {$_initialized && [llength $_panes]} {
  579.     _setActivePanes
  580.     _setFracArray
  581.     
  582.     _makeSashes
  583.     _placePanes
  584.     }
  585. }
  586.  
  587. # ------------------------------------------------------------------
  588. # PROTECTED METHOD: _pwConfigureEventHandler
  589. #
  590. # Performs operations necessary following a configure event.  This
  591. # includes placing the panes.
  592. # ------------------------------------------------------------------
  593. itcl::body iwidgets::Panedwindow::_pwConfigureEventHandler {width height} {
  594.     set _width $width
  595.     set _height $height
  596.     if {$_initialized} {
  597.     _placePanes
  598.     } else {
  599.     set _initialized 1
  600.     reset
  601.     }
  602. }
  603.  
  604. # ------------------------------------------------------------------
  605. # PROTECTED METHOD: _startGrip where num
  606. #
  607. # Starts the sash drag and drop operation.  At the start of the drag
  608. # operation all the information is known as for the upper and lower
  609. # limits for sash movement.  The calculation is made at this time and
  610. # stored in protected variables for later access during the drag
  611. # handling routines.
  612. # ------------------------------------------------------------------
  613. itcl::body iwidgets::Panedwindow::_startGrip {where num} {
  614.     if {$itk_option(-orient) == "horizontal"} {
  615.       set _dimension $_height
  616.     } else {
  617.       set _dimension $_width
  618.     }
  619.     
  620.     set _minsashmoved $num
  621.     set _maxsashmoved $num
  622.     set totMinHeight 0
  623.     set cnt [llength $_activePanes]
  624.     set _sashloc(0) 0
  625.     set _pixels($cnt) [expr {int($_dimension)}]
  626.     for {set i 0} {$i < $cnt} {incr i} {
  627.       set _pixels($i) [expr {int($_frac($i) * $_dimension)}]
  628.       set margaft [$itk_component([lindex $_activePanes $i]) cget -margin]
  629.       set minaft [$itk_component([lindex $_activePanes $i]) cget -minimum]
  630.       set _minheight($i) [expr {$minaft + (2 * $margaft)}]
  631.       incr totMinHeight $_minheight($i)
  632.     }
  633.     set _dragging [expr {$_dimension > $totMinHeight}]
  634.  
  635.     grab  $itk_component(sash$num)
  636.     raise $itk_component(separator$num)
  637.     raise $itk_component(sash$num)
  638.     
  639.     $itk_component(sash$num) configure -relief sunken
  640. }
  641.  
  642. # ------------------------------------------------------------------
  643. # PROTECTED METHOD: _endGrip where num
  644. #
  645. # Ends the sash drag and drop operation.
  646. # ------------------------------------------------------------------
  647. itcl::body iwidgets::Panedwindow::_endGrip {where num} {
  648.     $itk_component(sash$num) configure -relief $_relief($itk_option(-showhandle))
  649.     grab release $itk_component(sash$num)
  650.     if {$_dragging} {
  651.       _calcFraction [expr {$_sashloc($num) + $where}] $num
  652.       _placePanes [expr {$_minsashmoved - 1}] $_maxsashmoved
  653.       set _dragging 0
  654.     }
  655. }
  656.  
  657. # ------------------------------------------------------------------
  658. # PROTECTED METHOD: _configGrip where num
  659. #
  660. # Configure  action for sash.
  661. # ------------------------------------------------------------------
  662. itcl::body iwidgets::Panedwindow::_configGrip {where num} {
  663.    set _sashloc($num) $where
  664. }
  665.  
  666. # ------------------------------------------------------------------
  667. # PROTECTED METHOD: _handleGrip where num
  668. #
  669. # Motion action for sash.
  670. # ------------------------------------------------------------------
  671. itcl::body iwidgets::Panedwindow::_handleGrip {where num} {
  672.  if {$_dragging} {
  673.   _moveSash [expr {$where + $_sashloc($num)}] $num
  674.   incr _movecount
  675.   if {$_movecount>4} {
  676.     set _movecount 0
  677.     update idletasks
  678.   }
  679.  }
  680. }
  681.  
  682. # ------------------------------------------------------------------
  683. # PROTECTED METHOD: _moveSash where num
  684. #
  685. # Move the sash to the absolute pixel location
  686. # ------------------------------------------------------------------
  687. itcl::body iwidgets::Panedwindow::_moveSash {where num} {
  688.   set _minsashmoved [expr {($_minsashmoved<$num)?$_minsashmoved:$num}]
  689.   set _maxsashmoved [expr {($_maxsashmoved>$num)?$_maxsashmoved:$num}]
  690.   set oldfrac $_frac($num)
  691.   _calcFraction $where $num
  692.   if {$_frac($num)!=$oldfrac} { _placeSash $num }
  693. }
  694.  
  695. # ------------------------------------------------------------------
  696. # PRIVATE METHOD: _setFracArray
  697. #
  698. # Calculates the percentages for the fraction array which lists the
  699. # percentages for each pane.
  700. # ------------------------------------------------------------------
  701. itcl::body iwidgets::Panedwindow::_setFracArray {} {
  702.     set perc 0.0
  703.     if {[llength $_activePanes] != 0} {
  704.     set percIncr [expr {1.0 / [llength $_activePanes]}]
  705.     }
  706.     
  707.     for {set i 0} {$i < [llength $_activePanes]} {incr i} {
  708.     set _frac($i) $perc
  709.     set perc [expr {$perc + $percIncr}]
  710.     }
  711.     
  712.     set _frac($i) 1.0
  713. }
  714.  
  715. # ------------------------------------------------------------------
  716. # PRIVATE METHOD: _setActivePanes
  717. #
  718. # Resets the active pane list.
  719. # ------------------------------------------------------------------
  720. itcl::body iwidgets::Panedwindow::_setActivePanes {} {
  721.     set _prevActivePanes $_activePanes
  722.  
  723.     set _activePanes {}
  724.     
  725.     foreach pane $_panes {
  726.     if {[lsearch -exact $_prevActivePanes $pane] != -1} {
  727.         lappend _activePanes $pane
  728.     }
  729.     }
  730. }
  731.  
  732. # ------------------------------------------------------------------
  733. # PRIVATE METHOD: _calcFraction where num
  734. #
  735. # Determines the fraction for the sash.  Make sure the fraction does
  736. # not go past the minimum for the pane on each side of the separator.
  737. # ------------------------------------------------------------------
  738. itcl::body iwidgets::Panedwindow::_calcFraction {where num} {
  739.     
  740.     set numi [expr {$num + 1}]
  741.     set numd [expr {$num - 1}]
  742.  
  743.     set _lowerlimit [expr {$_pixels($numd) + $_minheight($numd)}]
  744.     set _upperlimit [expr {$_pixels($numi) - $_minheight($num)}]
  745.  
  746.     set dir [expr {$where - $_pixels($num)}]
  747.  
  748.     if {$where < $_lowerlimit && $dir <= 0} {
  749.      if {$num == 1} {
  750.       set _pixels($num) $_lowerlimit
  751.      } {
  752.       _moveSash [expr {$where - $_minheight($numd)}] $numd
  753.       set _pixels($num) [expr {$_pixels($numd) + $_minheight($numd)}]
  754.      }
  755.     } elseif {$where > $_upperlimit && $dir >= 0} {
  756.      if {$numi == [llength $_activePanes]} {
  757.       set _pixels($num) $_upperlimit
  758.      } {
  759.       _moveSash [expr {$where + $_minheight($num)}] $numi
  760.       set _pixels($num) \
  761.          [expr {$_pixels($numi) - $_minheight($num)}]
  762.      }
  763.     } else {
  764.       set _pixels($num) $where
  765.     }
  766.     set _frac($num) [expr $_pixels($num).0 / $_dimension]
  767. }
  768.  
  769. # ------------------------------------------------------------------
  770. # PRIVATE METHOD: _makeSashes
  771. #
  772. # Removes any previous sashes and separators and creates new one.
  773. # ------------------------------------------------------------------
  774. itcl::body iwidgets::Panedwindow::_makeSashes {} {
  775.     #
  776.     # Remove any existing sashes and separators.
  777.     #
  778.     foreach sash $_sashes {
  779.     destroy $itk_component($sash)
  780.     }
  781.     
  782.     foreach separator $_separators {
  783.     destroy $itk_component($separator)
  784.     }
  785.     
  786.     set _sashes {}
  787.     set _separators {}
  788.     
  789.     #
  790.     # Create one less separator and sash than the number of panes.  
  791.     #
  792.     for {set id 1} {$id < [llength $_activePanes]} {incr id} {
  793.     itk_component add sash$id {
  794.         frame $itk_interior.sash$id -relief $_relief($itk_option(-showhandle)) \
  795.             -borderwidth $itk_option(-sashborderwidth) \
  796.             -cursor $itk_option(-sashcursor) \
  797.             -width $itk_option(-sashwidth) \
  798.             -height $itk_option(-sashheight)
  799.     } {
  800.         keep -background
  801.     }
  802.    
  803.     lappend _sashes sash$id
  804.     
  805.     switch $itk_option(-orient) {
  806.         vertical {
  807.         bind $itk_component(sash$id) <Button-1> \
  808.             [itcl::code $this _startGrip %x $id]
  809.         bind $itk_component(sash$id) <B1-Motion> \
  810.             [itcl::code $this _handleGrip %x $id]
  811.         bind $itk_component(sash$id) <B1-ButtonRelease-1> \
  812.             [itcl::code $this _endGrip %x $id]
  813.         bind $itk_component(sash$id) <Configure> \
  814.                 [itcl::code $this _configGrip %x $id]
  815.         }
  816.         
  817.         horizontal {
  818.         bind $itk_component(sash$id) <Button-1> \
  819.             [itcl::code $this _startGrip %y $id]
  820.         bind $itk_component(sash$id) <B1-Motion> \
  821.             [itcl::code $this _handleGrip %y $id]
  822.         bind $itk_component(sash$id) <B1-ButtonRelease-1> \
  823.             [itcl::code $this _endGrip %y $id]
  824.         bind $itk_component(sash$id) <Configure> \
  825.                 [itcl::code $this _configGrip %y $id]
  826.         }
  827.     }
  828.     
  829.     itk_component add separator$id {
  830.         frame $itk_interior.separator$id -relief sunken \
  831.             -height $itk_option(-thickness) \
  832.             -width $itk_option(-thickness) \
  833.             -borderwidth [expr {$itk_option(-thickness) / 2}]
  834.     } {
  835.         keep -background -cursor
  836.     }
  837.     
  838.     lappend _separators separator$id
  839.     }
  840. }
  841.  
  842. # ------------------------------------------------------------------
  843. # PRIVATE METHOD: _placeSash i
  844. #
  845. # Places the position of the sash and separator.
  846. # ------------------------------------------------------------------
  847. itcl::body iwidgets::Panedwindow::_placeSash {i} {
  848.     if {$itk_option(-orient) == "horizontal"} {
  849.     place $itk_component(separator$i) -in $itk_component(hull) \
  850.         -x 0 -relwidth 1 -rely $_frac($i) -anchor w \
  851.         -height $itk_option(-thickness)
  852.     
  853.     if {$itk_option(-sashindent) < 0} {
  854.         set sashPos [expr {$_width + $itk_option(-sashindent)}]
  855.         set sashAnchor e
  856.     } else {
  857.         set sashPos $itk_option(-sashindent)
  858.         set sashAnchor w
  859.     }
  860.     
  861.     if {$itk_option(-showhandle)} {
  862.         place $itk_component(sash$i) -in $itk_component(hull) \
  863.             -x $sashPos -rely $_frac($i) -anchor $sashAnchor
  864.     } else {
  865.         place $itk_component(sash$i) -in $itk_component(hull) \
  866.             -x 0 -relwidth 1 -rely $_frac($i) -anchor w \
  867.             -height $itk_option(-thickness)
  868.     }
  869.  
  870.     } else {
  871.     place $itk_component(separator$i) -in $itk_component(hull) \
  872.         -y 0 -relheight 1 -relx $_frac($i) -anchor n \
  873.         -width $itk_option(-thickness)
  874.     
  875.     if {$itk_option(-sashindent) < 0} {
  876.         set sashPos [expr {$_height + $itk_option(-sashindent)}]
  877.         set sashAnchor s
  878.     } else {
  879.         set sashPos $itk_option(-sashindent)
  880.         set sashAnchor n
  881.     }
  882.     
  883.     if {$itk_option(-showhandle)} {
  884.  
  885.         place $itk_component(sash$i) -in $itk_component(hull) \
  886.             -y $sashPos -relx $_frac($i) -anchor $sashAnchor
  887.     } else {
  888.         place $itk_component(sash$i) -in $itk_component(hull) \
  889.             -y 0 -relheight 1 -relx $_frac($i) -anchor n \
  890.             -width $itk_option(-thickness)
  891.     }
  892.     }
  893. }
  894.  
  895. # ------------------------------------------------------------------
  896. # PRIVATE METHOD: _placePanes
  897. #
  898. # Resets the panes of the window following movement of the sash.
  899. # ------------------------------------------------------------------
  900. itcl::body iwidgets::Panedwindow::_placePanes {{start 0} {end end}} {
  901.      if {$end=="end"} { set end [expr {[llength $_activePanes] - 1}] }
  902.      set _updatePanes [lrange $_activePanes $start $end]
  903.      if {$_updatePanes == $_activePanes} {
  904.        set _forgetPanes $_panes
  905.      } {
  906.        set _forgetPanes $_updatePanes
  907.      }
  908.     foreach pane $_forgetPanes {
  909.     place forget $itk_component($pane)
  910.     }
  911.    
  912.     
  913.     if {$itk_option(-orient) == "horizontal"} {
  914.     set i $start
  915.     foreach pane $_updatePanes {
  916.         place $itk_component($pane) -in $itk_component(hull) \
  917.             -x 0 -rely $_frac($i) -relwidth 1 \
  918.             -relheight [expr {$_frac([expr {$i + 1}]) - $_frac($i)}]
  919.         incr i
  920.     }
  921.     
  922.     } else {
  923.     set i $start
  924.     foreach pane $_updatePanes {
  925.         place $itk_component($pane) -in $itk_component(hull) \
  926.             -y 0 -relx $_frac($i) -relheight 1 \
  927.             -relwidth [expr {$_frac([expr {$i + 1}]) - $_frac($i)}]
  928.         incr i
  929.     }
  930.     
  931.     }
  932.  
  933.     for {set i [expr {$start+1}]} {$i <= $end} {incr i} {
  934.     if {[array names itk_component separator$i] != ""} {
  935.         _placeSash $i
  936.         raise $itk_component(separator$i)
  937.         raise $itk_component(sash$i)
  938.     }
  939.     }
  940. }
  941.