# # Collapsablewidget # ---------------------------------------------------------------------- # Implements a collapsable widget which contains a label and child site. # The child site is a frame which can filled with any widget via a # derived itcl::class or though the use of the childSite method. # # Clicking on the button/arrow indicator will collapse/reveal the # child-site # # ---------------------------------------------------------------------- # AUTHOR: Vince Darley EMAIL: vince@biosgroup.com # # Based upon the labelledwidget distributed under the copyright # below, under which all my modifications are also distributed. # # ---------------------------------------------------------------------- # Copyright (c) 1995-1999 DSC Technologies Corporation # ====================================================================== # Permission to use, copy, modify, distribute and license this software # and its documentation for any purpose, and without fee or written # agreement with DSC, is hereby granted, provided that the above copyright # notice appears in all copies and that both the copyright notice and # warranty disclaimer below appear in supporting documentation, and that # the names of DSC Technologies Corporation or DSC Communications # Corporation not be used in advertising or publicity pertaining to the # software without specific, written prior permission. # # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON- # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS # SOFTWARE. # ====================================================================== # # Default resources. # option add *Collapsablewidget.labelMargin 1 widgetDefault package require Itk # # Usual options. # itk::usual Collapsablewidget { keep -background -cursor -foreground -labelfont } # Define the right pointing and down-pointing triangles # for collapsed and expanded entries. if {[lsearch [image names] closedNode] == -1} { image create bitmap closedNode -data { #define closednode_width 13 #define closednode_height 13 static char closednode_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x30, 0x10, 0x70, 0x10, 0xf0, 0x10, 0xf0, 0x11, 0xf0, 0x13, 0xf0, 0x11, 0xf0, 0x10, 0x70, 0x10, 0x30, 0x10, 0x10, 0x10}; } } if {[lsearch [image names] openNode] == -1} { image create bitmap openNode -data { #define opennode_width 13 #define opennode_height 13 static char opennode_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00}; } } # ------------------------------------------------------------------ # COLLAPSABLEWIDGET # ------------------------------------------------------------------ itcl::class iwidgets::Collapsablewidget { inherit itk::Widget constructor {args} {} destructor {} itk_option define -labelmargin labelMargin Margin 1 itk_option define -labeltext labelText Text {} itk_option define -labelvariable labelVariable Variable {} itk_option define -labelbitmap labelBitmap Bitmap {} itk_option define -labelimage labelImage Image {} itk_option define -collapsed collapsed Collapsed 1 public method childsite public method collapse public method reveal public method toggle protected method _positionLabel {when} proc alignlabels {args} {} protected variable _reposition "" ;# non-null => _positionLabel pending } # # Provide a lowercased access method for the Collapsablewidget class. # proc ::iwidgets::collapsablewidget {pathName args} { uplevel ::iwidgets::Collapsablewidget $pathName $args } # ------------------------------------------------------------------ # CONSTRUCTOR # ------------------------------------------------------------------ itcl::body iwidgets::Collapsablewidget::constructor {args} { # # Create the outermost frame to maintain geometry. # itk_component add shell { frame $itk_interior.shell -relief ridge -bd 2 } { keep -background -cursor } pack $itk_component(shell) -fill both -expand yes itk_component add frame { frame $itk_component(shell).frame } { } pack $itk_component(frame) -fill x -expand no -side top itk_component add trigger { button $itk_component(shell).frame.trigger -command "$this toggle" \ -relief flat \ -image closedNode } { } pack $itk_component(trigger) -side left # # Create label. # itk_component add label { label $itk_component(shell).frame.label } { keep -background -foreground -cursor rename -font -labelfont labelFont Font } pack $itk_component(label) -side right -fill x -expand yes # # Create margin between label and the child site. # itk_component add labmargin { frame $itk_component(shell).labmargin } { keep -background -cursor } pack $itk_component(labmargin) -side bottom # # Create a frame for the childsite widget. # itk_component add lwchildsite { frame $itk_component(shell).lwchildsite } { keep -background -cursor } #pack $itk_component(lwchildsite) -fill both -expand yes set itk_interior $itk_component(lwchildsite) ## # Explicitly handle configs that may have been ignored earlier. # eval itk_initialize $args # # When idle, position the label. # } # ------------------------------------------------------------------ # DESTURCTOR # ------------------------------------------------------------------ itcl::body iwidgets::Collapsablewidget::destructor {} { if {$_reposition != ""} {after cancel $_reposition} } itcl::body iwidgets::Collapsablewidget::toggle {} { set itk_option(-collapsed) [expr 1 - $itk_option(-collapsed)] if {$itk_option(-collapsed)} { collapse } else { reveal } } itcl::body iwidgets::Collapsablewidget::collapse {} { pack forget $itk_component(lwchildsite) $itk_component(trigger) configure -image closedNode } itcl::body iwidgets::Collapsablewidget::reveal {} { pack $itk_component(lwchildsite) -side bottom -fill both -expand yes $itk_component(trigger) configure -image openNode } # ------------------------------------------------------------------ # OPTIONS # ------------------------------------------------------------------ itcl::configbody iwidgets::Collapsablewidget::collapsed { if {$itk_option(-collapsed)} { collapse } else { reveal } } # ------------------------------------------------------------------ # OPTION: -labeltext # # Specifies the label text. # ------------------------------------------------------------------ itcl::configbody iwidgets::Collapsablewidget::labeltext { $itk_component(label) configure -text $itk_option(-labeltext) } # ------------------------------------------------------------------ # OPTION: -labelvariable # # Specifies the label text variable. # ------------------------------------------------------------------ itcl::configbody iwidgets::Collapsablewidget::labelvariable { $itk_component(label) configure -textvariable $itk_option(-labelvariable) } # ------------------------------------------------------------------ # OPTION: -labelbitmap # # Specifies the label bitmap. # ------------------------------------------------------------------ itcl::configbody iwidgets::Collapsablewidget::labelbitmap { $itk_component(label) configure -bitmap $itk_option(-labelbitmap) } # ------------------------------------------------------------------ # OPTION: -labelimage # # Specifies the label image. # ------------------------------------------------------------------ itcl::configbody iwidgets::Collapsablewidget::labelimage { $itk_component(label) configure -image $itk_option(-labelimage) } # ------------------------------------------------------------------ # METHODS # ------------------------------------------------------------------ # ------------------------------------------------------------------ # METHOD: childsite # # Returns the path name of the child site widget. # ------------------------------------------------------------------ itcl::body iwidgets::Collapsablewidget::childsite {} { return $itk_component(lwchildsite) } # ------------------------------------------------------------------ # PROCEDURE: alignlabels widget ?widget ...? # # The alignlabels procedure takes a list of widgets derived from # the Collapsablewidget itcl::class and adjusts the label margin to align # the labels. # ------------------------------------------------------------------ itcl::body iwidgets::Collapsablewidget::alignlabels {args} { update set maxLabelWidth 0 # # Verify that all the widgets are of type Collapsablewidget and # determine the size of the maximum length label string. # foreach iwid $args { if {[catch {$iwid isa iwidgets::Collapsablewidget} ret] || $ret == 0} { error "$iwid is not a \"Collapsablewidget\": $ret" } set csWidth [winfo reqwidth $iwid.shell.lwchildsite] set shellWidth [winfo reqwidth $iwid.shell] if {[expr $shellWidth - $csWidth] > $maxLabelWidth} { set maxLabelWidth [expr $shellWidth - $csWidth] } } # # Adjust the margins for the labels such that the child sites and # labels line up. # foreach iwid $args { set csWidth [winfo reqwidth $iwid.shell.lwchildsite] set shellWidth [winfo reqwidth $iwid.shell] set labelSize [expr $shellWidth - $csWidth] if {$maxLabelWidth > $labelSize} { set dist [expr $maxLabelWidth - \ ($labelSize - [winfo reqwidth $iwid.shell.labmargin])] $iwid configure -labelmargin $dist } } }