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