# # Selectionbox # ---------------------------------------------------------------------- # Implements a selection box composed of a scrolled list of items and # a selection entry field. The user may choose any of the items displayed # in the scrolled list of alternatives and the selection field will be # filled with the choice. The user is also free to enter a new value in # the selection entry field. Both the list and entry areas have labels. # A child site is also provided in which the user may create other widgets # to be used in conjunction with the selection box. # # ---------------------------------------------------------------------- # AUTHOR: Mark L. Ulferts EMAIL: mulferts@spd.dsccc.com # # @(#) $Id: selectionbox.itk,v 1.3 2006/09/11 20:35:56 irby Exp $ # ---------------------------------------------------------------------- # Copyright (c) 1995 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 *Selectionbox.borderWidth 2 widgetDefault option add *Selectionbox.itemsLabel Items widgetDefault option add *Selectionbox.itemsLabelPos nw widgetDefault option add *Selectionbox.itemsOn yes widgetDefault option add *Selectionbox.selectionLabel Selection widgetDefault option add *Selectionbox.selectionLabelPos nw widgetDefault option add *Selectionbox.selectionOn yes widgetDefault option add *Selectionbox.vscrollMode static widgetDefault option add *Selectionbox.hscrollMode none widgetDefault option add *Selectionbox.scrollMargin 3 widgetDefault option add *Selectionbox.margin 7 widgetDefault option add *Selectionbox.width 260 widgetDefault option add *Selectionbox.height 320 widgetDefault # # Usual options. # itk::usual Selectionbox { keep -activebackground -activerelief -background -borderwidth -cursor \ -elementborderwidth -foreground -highlightcolor -highlightthickness \ -insertbackground -insertborderwidth -insertofftime -insertontime \ -insertwidth -jump -labelfont -selectbackground -selectborderwidth \ -selectforeground -textbackground -textfont -troughcolor } # ------------------------------------------------------------------ # SELECTIONBOX # ------------------------------------------------------------------ class iwidgets::Selectionbox { inherit itk::Widget constructor {args} {} destructor {} itk_option define -childsitepos childSitePos Position center itk_option define -margin margin Margin 7 itk_option define -itemson itemsOn ItemsOn true itk_option define -selectionon selectionOn SelectionOn true itk_option define -width width Width 260 itk_option define -height height Height 320 public method childsite {} public method get {} public method curselection {} public method clear {component} public method insert {component index args} public method delete {first {last {}}} public method size {} public method scan {option args} public method nearest {y} public method index {index} public method selection {option args} public method selectitem {} private method _packComponents {{when later}} private variable _repacking {} ;# non-null => _packComponents pending } # # Provide a lowercased access method for the Selectionbox class. # proc ::iwidgets::selectionbox {pathName args} { uplevel ::iwidgets::Selectionbox $pathName $args } # ------------------------------------------------------------------ # CONSTRUCTOR # ------------------------------------------------------------------ body iwidgets::Selectionbox::constructor {args} { component hull configure -borderwidth 0 # # Create an internal frame to contain the components. # itk_component add frame { frame $itk_interior.frame } { keep -background -cursor } pack $itk_component(frame) -fill both -expand yes pack propagate $itk_component(frame) no # # Create the child site widget. # itk_component add childsite { frame $itk_interior.sbchildsite } { keep -background -cursor } set itk_interior $itk_component(childsite) # # Create the items list. # itk_component add items { iwidgets::Scrolledlistbox $itk_component(frame).items -selectmode single \ -visibleitems 1x1 } { keep -activebackground -activerelief -background -borderwidth \ -cursor -dblclickcommand -elementborderwidth -exportselection \ -foreground -highlightcolor \ -highlightthickness -hscrollmode -items -jump -labelfont \ -labelmargin -relief -repeatdelay -repeatinterval \ -sbwidth -scrollmargin -selectbackground -selectborderwidth \ -selectforeground -textbackground -textfont -troughcolor \ -vscrollmode rename -labeltext -itemslabel itemsLabel Text rename -labelpos -itemslabelpos itemsLabelPos Position rename -selectioncommand -itemscommand itemsCommand Command } configure -itemscommand [code $this selectitem] itk_component add margin { frame $itk_component(frame).margin } { keep -background -cursor } # # Create the selection entry. # itk_component add selection { iwidgets::Entryfield $itk_component(frame).selection } { keep -background -borderwidth -cursor -exportselection \ -foreground -highlightcolor \ -highlightthickness -insertbackground -insertborderwidth \ -insertofftime -insertontime -insertwidth -labelfont \ -labelmargin -relief -selectbackground -selectborderwidth \ -selectforeground -textbackground -textfont rename -labeltext -selectionlabel selectionLabel Text rename -labelpos -selectionlabelpos selectionLabelPos Position rename -command -selectioncommand selectionCommand Command } # # Explicitly handle configs that may have been ignored earlier. # eval itk_initialize $args # # When idle, pack the components. # _packComponents } # ------------------------------------------------------------------ # DESTRUCTOR # ------------------------------------------------------------------ body iwidgets::Selectionbox::destructor {} { if {$_repacking != ""} {after cancel $_repacking} } # ------------------------------------------------------------------ # OPTIONS # ------------------------------------------------------------------ # ------------------------------------------------------------------ # OPTION: -childsitepos # # Specifies the position of the child site in the selection box. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::childsitepos { _packComponents } # ------------------------------------------------------------------ # OPTION: -margin # # Specifies distance between the items list and selection entry. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::margin { set pixels [winfo pixels $itk_component(margin) \ $itk_option(-margin)] $itk_component(margin) configure -width $pixels -height $pixels } # ------------------------------------------------------------------ # OPTION: -itemson # # Specifies whether or not to display the items list. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::itemson { if {$itk_option(-itemson)} { _packComponents } else { pack forget $itk_component(items) } } # ------------------------------------------------------------------ # OPTION: -selectionon # # Specifies whether or not to display the selection entry widget. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::selectionon { if {$itk_option(-selectionon)} { _packComponents } else { pack forget $itk_component(selection) } } # ------------------------------------------------------------------ # OPTION: -width # # Specifies the width of the selection box. The value may be # specified in any of the forms acceptable to Tk_GetPixels. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::width { set pixels \ [winfo pixels $itk_component(frame) $itk_option(-width)] $itk_component(frame) config -width $pixels } # ------------------------------------------------------------------ # OPTION: -height # # Specifies the height of the selection box. The value may be # specified in any of the forms acceptable to Tk_GetPixels. # ------------------------------------------------------------------ configbody iwidgets::Selectionbox::height { set pixels \ [winfo pixels $itk_component(frame) $itk_option(-height)] $itk_component(frame) config -height $pixels } # ------------------------------------------------------------------ # METHODS # ------------------------------------------------------------------ # ------------------------------------------------------------------ # METHOD: childsite # # Returns the path name of the child site widget. # ------------------------------------------------------------------ body iwidgets::Selectionbox::childsite {} { return $itk_component(childsite) } # ------------------------------------------------------------------ # METHOD: get # # Returns the current selection. # ------------------------------------------------------------------ body iwidgets::Selectionbox::get {} { return [$itk_component(selection) get] } # ------------------------------------------------------------------ # METHOD: curselection # # Returns the current selection index. # ------------------------------------------------------------------ body iwidgets::Selectionbox::curselection {} { return [$itk_component(items) curselection] } # ------------------------------------------------------------------ # METHOD: clear component # # Delete the contents of either the selection entry widget or items # list. # ------------------------------------------------------------------ body iwidgets::Selectionbox::clear {component} { switch $component { selection { $itk_component(selection) clear } items { delete 0 end } default { error "bad clear argument \"$component\": should be\ selection or items" } } } # ------------------------------------------------------------------ # METHOD: insert component index args # # Insert element(s) into either the selection or items list widget. # ------------------------------------------------------------------ body iwidgets::Selectionbox::insert {component index args} { switch $component { selection { eval $itk_component(selection) insert $index $args } items { set index [index $index] configure -items [eval linsert {$itk_option(-items)} $index $args] } default { error "bad insert argument \"$component\": should be\ selection or items" } } } # ------------------------------------------------------------------ # METHOD: delete first ?last? # # Delete one or more elements from the items list box. The default # is to delete by indexed range. If an item is to be removed by name, # it must be preceeded by the keyword "item". Only index numbers can # be used to delete a range of items. # ------------------------------------------------------------------ body iwidgets::Selectionbox::delete {first {last {}}} { set first [index $first] if {$last != {}} { set last [index $last] } else { set last $first } if {[llength $itk_option(-items)] > 0} { if {$first <= $last} { configure -items [lreplace $itk_option(-items) $first $last] } else { error "first index must not be greater than second" } } } # ------------------------------------------------------------------ # METHOD: size # # Returns a decimal string indicating the total number of elements # in the items list. # ------------------------------------------------------------------ body iwidgets::Selectionbox::size {} { return [$itk_component(items) size] } # ------------------------------------------------------------------ # METHOD: scan option args # # Implements scanning on items list. # ------------------------------------------------------------------ body iwidgets::Selectionbox::scan {option args} { eval $itk_component(items) scan $option $args } # ------------------------------------------------------------------ # METHOD: nearest y # # Returns the index to the nearest listbox item given a y coordinate. # ------------------------------------------------------------------ body iwidgets::Selectionbox::nearest {y} { return [$itk_component(items) nearest $y] } # ------------------------------------------------------------------ # METHOD: index index # # Returns the decimal string giving the integer index corresponding # to index. # ------------------------------------------------------------------ body iwidgets::Selectionbox::index {index} { return [$itk_component(items) index $index] } # ------------------------------------------------------------------ # METHOD: selection option args # # Adjusts the selection within the items list. # ------------------------------------------------------------------ body iwidgets::Selectionbox::selection {option args} { eval $itk_component(items) selection $option $args selectitem } # ------------------------------------------------------------------ # METHOD: selectitem # # Replace the selection entry field contents with the currently # selected items value. # ------------------------------------------------------------------ body iwidgets::Selectionbox::selectitem {} { $itk_component(selection) clear set numSelected [$itk_component(items) selecteditemcount] if {$numSelected == 1} { $itk_component(selection) insert end \ [$itk_component(items) getcurselection] } elseif {$numSelected > 1} { $itk_component(selection) insert end \ [lindex [$itk_component(items) getcurselection] 0] } $itk_component(selection) icursor end } # ------------------------------------------------------------------ # PRIVATE METHOD: _packComponents ?when? # # Pack the selection, items, and child site widgets based on options. # If "when" is "now", the change is applied immediately. If it is # "later" or it is not specified, then the change is applied later, # when the application is idle. # ------------------------------------------------------------------ body iwidgets::Selectionbox::_packComponents {{when later}} { if {$when == "later"} { if {$_repacking == ""} { set _repacking [after idle [code $this _packComponents now]] } return } elseif {$when != "now"} { error "bad option \"$when\": should be now or later" } set _repacking "" switch $itk_option(-childsitepos) { n { pack configure $itk_component(childsite) -side top \ -in $itk_component(frame) pack configure $itk_component(items) -side top \ -after $itk_component(childsite) pack configure $itk_component(margin) -side top \ -after $itk_component(items) pack configure $itk_component(selection) -side top \ -after $itk_component(margin) } w { pack configure $itk_component(frame) -side right pack configure $itk_component(childsite) -side left \ -before $itk_component(frame) \ -in $itk_component(hull) pack configure $itk_component(items) -side top pack configure $itk_component(margin) -side top \ -after $itk_component(items) pack configure $itk_component(selection) -side top \ -after $itk_component(margin) } s { pack configure $itk_component(items) -side top pack configure $itk_component(margin) -side top \ -after $itk_component(items) pack configure $itk_component(selection) -side top \ -after $itk_component(margin) pack configure $itk_component(childsite) -side top \ -after $itk_component(selection) \ -in $itk_component(frame) } e { pack configure $itk_component(frame) -side left pack configure $itk_component(childsite) -side right \ -before $itk_component(frame) \ -in $itk_component(hull) pack configure $itk_component(items) -side top pack configure $itk_component(margin) -side top \ -after $itk_component(items) pack configure $itk_component(selection) -side top \ -after $itk_component(margin) } center { pack configure $itk_component(items) -side top pack configure $itk_component(childsite) -side top \ -after $itk_component(items) \ -in $itk_component(frame) pack configure $itk_component(margin) -side top \ -after $itk_component(childsite) pack configure $itk_component(selection) -side top \ -after $itk_component(margin) } default { error "bad childsitepos option \"$itk_option(-childsitepos)\":\ should be n, e, s, w, or center" } } if {$itk_option(-itemson)} { pack configure $itk_component(items) -fill both -expand yes } else { pack forget $itk_component(items) } if {$itk_option(-selectionon)} { pack configure $itk_component(selection) -fill x } else { pack forget $itk_component(selection) } raise $itk_component(childsite) }