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