summaryrefslogtreecommitdiff
path: root/itcl/iwidgets3.0.0/generic/combobox.itk
diff options
context:
space:
mode:
Diffstat (limited to 'itcl/iwidgets3.0.0/generic/combobox.itk')
-rw-r--r--itcl/iwidgets3.0.0/generic/combobox.itk1339
1 files changed, 1339 insertions, 0 deletions
diff --git a/itcl/iwidgets3.0.0/generic/combobox.itk b/itcl/iwidgets3.0.0/generic/combobox.itk
new file mode 100644
index 00000000000..45b79b037b6
--- /dev/null
+++ b/itcl/iwidgets3.0.0/generic/combobox.itk
@@ -0,0 +1,1339 @@
+# Combobox
+# ----------------------------------------------------------------------
+# Implements a Combobox widget. A Combobox has 2 basic styles: simple and
+# dropdown. Dropdowns display an entry field with an arrow button to the
+# right of it. When the arrow button is pressed a selectable list of
+# items is popped up. A simple Combobox displays an entry field and a listbox
+# just beneath it which is always displayed. In both types, if the user
+# selects an item in the listbox, the contents of the entry field are
+# replaced with the text from the selected item. If the Combobox is
+# editable, the user can type in the entry field and when <Return> is
+# pressed the item will be inserted into the list.
+#
+# WISH LIST:
+# This section lists possible future enhancements.
+#
+# Combobox 1.x:
+# - convert bindings to bindtags.
+#
+# ----------------------------------------------------------------------
+# ORIGINAL AUTHOR: John S. Sigler EMAIL: jsigler@spd.dsccc.com
+# sigler@onramp.net
+# ----------------------------------------------------------------------
+# CURRENT MAINTAINER: Mitch Gorman EMAIL: logain@erols.com
+# Copyright (c) 1995 John S. Sigler
+# Copyright (c) 1997 Mitch Gorman
+# ======================================================================
+# Permission is hereby granted, without written agreement and without
+# license or royalty fees, to use, copy, modify, and distribute this
+# software and its documentation for any purpose, provided that the
+# above copyright notice and the following two paragraphs appear in
+# all copies of this software.
+#
+# IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+# ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+# IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+# ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+# PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+# ======================================================================
+
+#
+# Default resources.
+#
+option add *Combobox.borderWidth 2 widgetDefault
+option add *Combobox.labelPos wn widgetDefault
+option add *Combobox.listHeight 150 widgetDefault
+option add *Combobox.hscrollMode dynamic widgetDefault
+option add *Combobox.vscrollMode dynamic widgetDefault
+
+#
+# Usual options.
+#
+itk::usual Combobox {
+ keep -background -borderwidth -cursor -foreground -highlightcolor \
+ -highlightthickness -insertbackground -insertborderwidth \
+ -insertofftime -insertontime -insertwidth -labelfont -popupcursor \
+ -selectbackground -selectborderwidth -selectforeground \
+ -textbackground -textfont
+}
+
+# ------------------------------------------------------------------
+# COMBOBOX
+# ------------------------------------------------------------------
+class iwidgets::Combobox {
+ inherit iwidgets::Entryfield
+
+ constructor {args} {}
+ destructor {}
+
+ itk_option define -arrowrelief arrowRelief Relief raised
+ itk_option define -completion completion Completion true
+ itk_option define -dropdown dropdown Dropdown true
+ itk_option define -editable editable Editable true
+ itk_option define -grab grab Grab local
+ itk_option define -listheight listHeight Height 150
+ itk_option define -margin margin Margin 1
+ itk_option define -popupcursor popupCursor Cursor arrow
+ itk_option define -selectioncommand selectionCommand SelectionCommand {}
+ itk_option define -state state State normal
+ itk_option define -unique unique Unique true
+
+ public method clear {{component all}}
+ public method curselection {}
+ public method delete {component first {last {}}}
+ public method get {{index {}}}
+ public method getcurselection {}
+ public method insert {component index args}
+ public method invoke {}
+ public method justify {direction}
+ public method see {index}
+ public method selection {option first {last {}}}
+ public method size {}
+ public method sort {{mode ascending}}
+ public method xview {args}
+ public method yview {args}
+
+ protected method _addToList {}
+ protected method _createComponents {}
+ protected method _deleteList {first {last {}}}
+ protected method _deleteText {first {last {}}}
+ protected method _doLayout {{when later}}
+ protected method _drawArrow {}
+ protected method _dropdownBtnRelease {{window {}} {x 1} {y 1}}
+ protected method _ignoreNextBtnRelease {ignore}
+ protected method _next {}
+ protected method _packComponents {{when later}}
+ protected method _positionList {}
+ protected method _postList {}
+ protected method _previous {}
+ protected method _resizeArrow {}
+ protected method _selectCmd {}
+ protected method _toggleList {}
+ protected method _unpostList {}
+ protected method _commonBindings {}
+ protected method _dropdownBindings {}
+ protected method _simpleBindings {}
+ protected method _listShowing {{val ""}}
+
+ private method _bs {}
+ private method _lookup {key}
+ private method _slbListbox {}
+ private method _stateSelect {}
+
+ private variable _doit 0;
+ private variable _inbs 0;
+ private variable _inlookup 0;
+ private variable _currItem {}; ;# current selected item.
+ private variable _ignoreRelease false ;# next button release ignored.
+ private variable _isPosted false; ;# is the dropdown popped up.
+ private variable _repacking {} ;# non-null => _packComponents pending.
+ private common _listShowing
+ private common count 0
+}
+
+#
+# Provide a lowercase access method for the Combobox class.
+#
+proc ::iwidgets::combobox {pathName args} {
+ uplevel ::iwidgets::Combobox $pathName $args
+}
+
+# ------------------------------------------------------------------
+# CONSTRUCTOR
+# ------------------------------------------------------------------
+body iwidgets::Combobox::constructor {args} {
+ set _listShowing($this) 0
+
+ # combobox is different as all components are created
+ # after determining what the dropdown style is...
+
+ # configure args
+ eval itk_initialize $args
+
+ # create components that are dependent on options
+ # (Scrolledlistbox, arrow button) and pack them.
+ if {$count == 0} {
+ image create bitmap downarrow -data {
+ #define down_width 16
+ #define down_height 16
+ static unsigned char down_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0xf8, 0x3f,
+ 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ }
+ image create bitmap uparrow -data {
+ #define up_width 16
+ #define up_height 16
+ static unsigned char up_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+ 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f,
+ 0xfc, 0x1f, 0xfe, 0x3f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ }
+ }
+ incr count
+ _doLayout
+}
+
+# ------------------------------------------------------------------
+# DESTRUCTOR
+# ------------------------------------------------------------------
+body iwidgets::Combobox::destructor {} {
+ # catch any repacking that may be waiting for idle time
+ if {$_repacking != ""} {
+ after cancel $_repacking
+ }
+ incr count -1
+ if {$count == 0} {
+ image delete uparrow
+ image delete downarrow
+ }
+}
+
+# ================================================================
+# OPTIONS
+# ================================================================
+
+# --------------------------------------------------------------------
+# OPTION: -arrowrelief
+#
+# Relief style used on the arrow button.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::arrowrelief {}
+
+# --------------------------------------------------------------------
+# OPTION: -completion
+#
+# Relief style used on the arrow button.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::completion {
+ switch -- $itk_option(-completion) {
+ 0 - no - false - off { }
+ 1 - yes - true - on { }
+ default {
+ error "bad completion option \"$itk_option(-completion)\":\
+ should be boolean"
+ }
+ }
+}
+
+# --------------------------------------------------------------------
+# OPTION: -dropdown
+#
+# Boolean which determines the Combobox style: dropdown or simple.
+# Because the two style's lists reside in different toplevel widgets
+# this is more complicated than it should be.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::dropdown {
+ switch -- $itk_option(-dropdown) {
+ 1 - yes - true - on {
+ if {[winfo exists $itk_interior.list]} {
+ set vals [$itk_component(list) get 0 end]
+ destroy $itk_component(list)
+ _doLayout
+ if [llength $vals] {
+ eval insert list end $vals
+ }
+ }
+ }
+ 0 - no - false - off {
+ if {[winfo exists $itk_interior.popup.list]} {
+ set vals [$itk_component(list) get 0 end]
+ catch {destroy $itk_component(arrowBtn)}
+ destroy $itk_component(popup) ;# this deletes the list too
+ _doLayout
+ if [llength $vals] {
+ eval insert list end $vals
+ }
+ }
+ }
+ default {
+ error "bad dropdown option \"$itk_option(-dropdown)\":\
+ should be boolean"
+ }
+ }
+}
+
+# --------------------------------------------------------------------
+# OPTION: -editable
+#
+# Boolean which allows/disallows user input to the entry field area.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::editable {
+ switch -- $itk_option(-editable) {
+ 1 - true - yes - on {
+ switch -- $itk_option(-state) {
+ normal {
+ $itk_component(entry) configure -state normal
+ }
+ }
+ }
+ 0 - false - no - off {
+ $itk_component(entry) configure -state disabled
+ }
+ default {
+ error "bad editable option \"$itk_option(-editable)\":\
+ should be boolean"
+ }
+ }
+}
+
+# --------------------------------------------------------------------
+# OPTION: -grab
+#
+# grab-state of megawidget
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::grab {
+ switch -- $itk_option(-grab) {
+ local { }
+ global { }
+ default {
+ error "bad grab value \"$itk_option(-grab)\":\
+ must be global or local"
+ }
+ }
+}
+
+# --------------------------------------------------------------------
+# OPTION: -listheight
+#
+# Listbox height in pixels. (Need to integrate the scrolledlistbox
+# -visibleitems option here - at least for simple listbox.)
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::listheight {}
+
+# --------------------------------------------------------------------
+# OPTION: -margin
+#
+# Spacer between the entry field and arrow button of dropdown style
+# Comboboxes.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::margin {
+ grid columnconfigure $itk_interior 0 -minsize $itk_option(-margin)
+}
+
+# --------------------------------------------------------------------
+# OPTION: -popupcursor
+#
+# Set the cursor for the popup list.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::popupcursor {}
+
+# --------------------------------------------------------------------
+# OPTION: -selectioncommand
+#
+# Defines the proc to be called when an item is selected in the list.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::selectioncommand {}
+
+# --------------------------------------------------------------------
+# OPTION: -state
+#
+# overall state of megawidget
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::state {
+ switch -- $itk_option(-state) {
+ disabled {
+ $itk_component(entry) configure -state disabled
+ }
+ normal {
+ switch -- $itk_option(-editable) {
+ 1 - true - yes - on {
+ $itk_component(entry) configure -state normal
+ }
+ 0 - false - no - off {
+ $itk_component(entry) configure -state disabled
+ }
+ }
+ }
+ default {
+ error "bad state value \"$itk_option(-state)\":\
+ must be normal or disabled"
+ }
+ }
+ if {[info exists itk_component(arrowBtn)]} {
+ $itk_component(arrowBtn) configure -state $itk_option(-state)
+ }
+}
+
+# --------------------------------------------------------------------
+# OPTION: -unique
+#
+# Boolean which disallows/allows adding duplicate items to the listbox.
+# --------------------------------------------------------------------
+configbody iwidgets::Combobox::unique {
+ # boolean error check
+ switch -- $itk_option(-unique) {
+ 1 - true - yes - on { }
+ 0 - false - no - off { }
+ default {
+ error "bad unique value \"$itk_option(-unique)\":\
+ should be boolean"
+ }
+ }
+}
+
+# =================================================================
+# METHODS
+# =================================================================
+
+# ------------------------------------------------------
+# PUBLIC METHOD: clear ?component?
+#
+# Remove all elements from the listbox, all contents
+# from the entry component, or both (if all).
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::clear {{component all}} {
+ switch -- $component {
+ entry {
+ iwidgets::Entryfield::clear
+ }
+ list {
+ delete list 0 end
+ }
+ all {
+ delete list 0 end
+ iwidgets::Entryfield::clear
+ }
+ default {
+ error "bad Combobox component \"$component\":\
+ must be entry, list, or all."
+ }
+ }
+ return
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: curselection
+#
+# Return the current selection index.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::curselection {} {
+ return [$itk_component(list) curselection]
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: delete component first ?last?
+#
+# Delete an item or items from the listbox OR delete
+# text from the entry field. First argument determines
+# which component deletion occurs in - valid values are
+# entry or list.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::delete {component first {last {}}} {
+ switch -- $component {
+ entry {
+ iwidgets::Entryfield::delete $first $last
+ }
+ list {
+ _deleteList $first $last
+ }
+ default {
+ error "bad Combobox component \"$component\":\
+ must be entry or list."
+ }
+ }
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: get ?index?
+#
+#
+# Retrieve entry contents if no args OR use args as list
+# index and retrieve list item at index .
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::get {{index {}}} {
+ # no args means to get the current text in the entry field area
+ if {$index == {}} {
+ iwidgets::Entryfield::get
+ } else {
+ eval $itk_component(list) get $index
+ }
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: getcurselection
+#
+# Return currently selected item in the listbox. Shortcut
+# version of get curselection command combination.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::getcurselection {} {
+ return [$itk_component(list) getcurselection]
+}
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: ivoke
+#
+# Pops up or down a dropdown combobox.
+#
+# ------------------------------------------------------------------
+body iwidgets::Combobox::invoke {} {
+ if {$itk_option(-dropdown)} {
+ return [_toggleList]
+ }
+ return
+}
+
+# ------------------------------------------------------------
+# PUBLIC METHOD: insert comonent index string ?string ...?
+#
+# Insert an item into the listbox OR text into the entry area.
+# Valid component names are entry or list.
+#
+# ------------------------------------------------------------
+body iwidgets::Combobox::insert {component index args} {
+ set nargs [llength $args]
+
+ if {$nargs == 0} {
+ error "no value given for parameter \"string\" in function\
+ \"Combobox::insert\""
+ }
+
+ switch -- $component {
+ entry {
+ if { $nargs > 1} {
+ error "called function \"Combobox::insert entry\"\
+ with too many arguments"
+ } else {
+ if {$itk_option(-state) == "normal"} {
+ eval iwidgets::Entryfield::insert $index $args
+ [code $this _lookup ""]
+ }
+ }
+ }
+ list {
+ if {$itk_option(-state) == "normal"} {
+ eval $itk_component(list) insert $index $args
+ }
+ }
+ default {
+ error "bad Combobox component \"$component\": must\
+ be entry or list."
+ }
+ }
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: justify direction
+#
+# Wrapper for justifying the listbox items in one of
+# 4 directions: top, bottom, left, or right.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::justify {direction} {
+ return [$itk_component(list) justify $direction]
+}
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: see index
+#
+# Adjusts the view such that the element given by index is visible.
+# ------------------------------------------------------------------
+body iwidgets::Combobox::see {index} {
+ return [$itk_component(list) see $index]
+}
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: selection option first ?last?
+#
+# Adjusts the selection within the listbox and changes the contents
+# of the entry component to be the value of the selected list item.
+# ------------------------------------------------------------------
+body iwidgets::Combobox::selection {option first {last {}}} {
+ # thin wrap
+ if {$option == "set"} {
+ $itk_component(list) selection clear 0 end
+ $itk_component(list) selection set $first
+ set rtn ""
+ } else {
+ set rtn [eval $itk_component(list) selection $option $first $last]
+ }
+ set _currItem $first
+
+ # combobox additions
+ set theText [getcurselection]
+ if {$theText != [$itk_component(entry) get]} {
+ clear entry
+ if {$theText != ""} {
+ insert entry 0 $theText
+ }
+ }
+ return $rtn
+}
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: size
+#
+# Returns a decimal string indicating the total number of elements
+# in the listbox.
+# ------------------------------------------------------------------
+body iwidgets::Combobox::size {} {
+ return [$itk_component(list) size]
+}
+
+# ------------------------------------------------------
+# PUBLIC METHOD: sort ?mode?
+#
+# Sort the current list in either "ascending" or "descending" order.
+#
+# jss: how should i handle selected items?
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::sort {{mode ascending}} {
+ $itk_component(list) sort $mode
+ # return [$itk_component(list) sort $mode]
+}
+
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: xview ?arg arg ...?
+#
+# Change or query the vertical position of the text in the list box.
+# ------------------------------------------------------------------
+body iwidgets::Combobox::xview {args} {
+ return [eval $itk_component(list) xview $args]
+}
+
+# ------------------------------------------------------------------
+# PUBLIC METHOD: yview ?arg arg ...?
+#
+# Change or query the horizontal position of the text in the list box.
+# ------------------------------------------------------------------
+body iwidgets::Combobox::yview {args} {
+ return [eval $itk_component(list) yview $args]
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _addToList
+#
+# Add the current item in the entry to the listbox.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_addToList {} {
+ set input [get]
+ if {$input != ""} {
+ if {$itk_option(-unique)} {
+ # if item is already in list, select it and exit
+ set item [lsearch -exact [$itk_component(list) get 0 end] $input]
+ if {$item != -1} {
+ selection clear 0 end
+ if {$item != {}} {
+ selection set $item $item
+ set _currItem $item
+ }
+ return
+ }
+ }
+ # add the item to end of list
+ selection clear 0 end
+ insert list end $input
+ selection set end end
+ }
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _createComponents
+#
+# Create deferred combobox components and add bindings.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_createComponents {} {
+ if {$itk_option(-dropdown)} {
+ # --- build a dropdown combobox ---
+
+ # make the arrow childsite be on the right hand side
+ configure -childsitepos e -command [code $this _addToList]
+
+ # arrow button to popup the list
+ itk_component add arrowBtn {
+ button $itk_interior.arrowBtn -borderwidth 2 \
+ -width 15 -height 15 -image downarrow \
+ -command [code $this _toggleList] -state $itk_option(-state)
+ } {
+ keep -background -borderwidth -cursor -state \
+ -highlightcolor -highlightthickness
+ rename -relief -arrowrelief arrowRelief Relief
+ rename -highlightbackground -background background Background
+ }
+
+ # popup list container
+ itk_component add popup {
+ toplevel $itk_interior.popup
+ } {
+ keep -background -cursor
+ }
+ wm withdraw $itk_interior.popup
+
+ # the listbox
+ itk_component add list {
+ iwidgets::Scrolledlistbox $itk_interior.popup.list -exportselection no \
+ -vscrollmode dynamic -hscrollmode dynamic -selectmode browse
+ } {
+ keep -background -borderwidth -cursor -foreground \
+ -highlightcolor -highlightthickness \
+ -hscrollmode -selectbackground \
+ -selectborderwidth -selectforeground -textbackground \
+ -textfont -vscrollmode
+ rename -height -listheight listHeight Height
+ rename -cursor -popupcursor popupCursor Cursor
+ }
+ # mode specific bindings
+ _dropdownBindings
+
+ # Ugly hack to avoid tk buglet revealed in _dropdownBtnRelease where
+ # relief is used but not set in scrollbar.tcl.
+ global tkPriv
+ set tkPriv(relief) raise
+
+ } else {
+ # --- build a simple combobox ---
+ configure -childsitepos s
+ itk_component add list {
+ iwidgets::Scrolledlistbox $itk_interior.list -exportselection no \
+ -vscrollmode dynamic -hscrollmode dynamic
+ } {
+ keep -background -borderwidth -cursor -foreground \
+ -highlightcolor -highlightthickness \
+ -hscrollmode -selectbackground \
+ -selectborderwidth -selectforeground -textbackground \
+ -textfont -visibleitems -vscrollmode
+ rename -height -listheight listHeight Height
+ }
+ # add mode specific bindings
+ _simpleBindings
+ }
+
+ # popup cursor applies only to the list within the combobox
+ configure -popupcursor $itk_option(-popupcursor)
+
+ # add mode independent bindings
+ _commonBindings
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _deleteList first ?last?
+#
+# Delete an item or items from the listbox. Called via
+# "delete list args".
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_deleteList {first {last {}}} {
+
+ if {$last == {}} {
+ set last $first
+ }
+ $itk_component(list) delete $first $last
+
+ # remove the item if it is no longer in the list
+ set text [$this get]
+ if {$text != ""} {
+ set index [lsearch -exact [$itk_component(list) get 0 end] $text ]
+ if {$index == -1} {
+ clear entry
+ }
+ }
+ return
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _deleteText first ?last?
+#
+# Renamed Entryfield delete method. Called via "delete entry args".
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_deleteText {first {last {}}} {
+ $itk_component(entry) configure -state normal
+ set rtrn [delete $first $last]
+ switch -- $itk_option(-editable) {
+ 0 - false - no - off {
+ $itk_component(entry) configure -state disabled
+ }
+ }
+ return $rtrn
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _doLayout ?when?
+#
+# Call methods to create and pack the Combobox components.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_doLayout {{when later}} {
+ _createComponents
+ _packComponents $when
+}
+
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _drawArrow
+#
+# Draw the arrow button. Determines packing according to
+# -labelpos.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_drawArrow {} {
+ set flip false
+ set relief ""
+ set fg [cget -foreground]
+ if {$_isPosted} {
+ set flip true
+ set relief "-relief sunken"
+ } else {
+ set relief "-relief $itk_option(-arrowrelief)"
+ }
+
+ if {$flip} {
+ #
+ # draw up arrow
+ #
+ eval $itk_component(arrowBtn) configure -image uparrow $relief
+ } else {
+ #
+ # draw down arrow
+ #
+ eval $itk_component(arrowBtn) configure -image downarrow $relief
+ }
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _dropdownBtnRelease window x y
+#
+# Event handler for button releases while a dropdown list
+# is posted.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_dropdownBtnRelease {{window {}} {x 1} {y 1}} {
+
+ # if it's a scrollbar then ignore the release
+ if {($window == [$itk_component(list) component vertsb]) ||
+ ($window == [$itk_component(list) component horizsb])} {
+ return
+ }
+
+ # 1st release allows list to stay up unless we are in listbox
+ if {$_ignoreRelease} {
+ _ignoreNextBtnRelease false
+ return
+ }
+
+ # should I use just the listbox or also include the scrollbars
+ if { ($x >= 0) && ($x < [winfo width [_slbListbox]])
+ && ($y >= 0) && ($y < [winfo height [_slbListbox]])} {
+ _stateSelect
+ }
+
+ _unpostList
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _ignoreNextBtnRelease ignore
+#
+# Set private variable _ignoreRelease. If this variable
+# is true then the next button release will not remove
+# a dropdown list.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_ignoreNextBtnRelease {ignore} {
+ set _ignoreRelease $ignore
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _next
+#
+# Select the next item in the list.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_next {} {
+ if {[size] <= 1} {
+ return
+ }
+ set i [curselection]
+ if {($i == {}) || ($i == [expr [size]-1]) } {
+ set i 0
+ } else {
+ incr i
+ }
+ selection clear 0 end
+ selection set $i $i
+ see $i
+ set _currItem $i
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _packComponents ?when?
+#
+# Pack the components of the combobox and add bindings.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_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"
+ }
+
+ if {$itk_option(-dropdown)} {
+ grid configure $itk_component(list) -row 1 -column 0 -sticky news
+ _resizeArrow
+ grid config $itk_component(arrowBtn) -row 0 -column 1 -sticky nsew
+ } else {
+ # size and pack list hack
+ grid configure $itk_component(entry) -row 0 -column 0 -sticky ew
+ grid configure $itk_component(efchildsite) -row 1 -column 0 -sticky nsew
+ grid configure $itk_component(list) -row 0 -column 0 -sticky nsew
+
+ grid rowconfigure $itk_component(efchildsite) 1 -weight 1
+ grid columnconfigure $itk_component(efchildsite) 0 -weight 1
+ }
+ set _repacking ""
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _positionList
+#
+# Determine the position (geometry) for the popped up list
+# and map it to the screen.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_positionList {} {
+
+ set x [winfo rootx $itk_component(entry) ]
+ set y [expr [winfo rooty $itk_component(entry) ] + \
+ [winfo height $itk_component(entry) ]]
+ set w [winfo width $itk_component(entry) ]
+ set h [winfo height [_slbListbox] ]
+ set sh [winfo screenheight .]
+
+ if {([expr $y+$h] > $sh) && ($y > [expr $sh/2])} {
+ set y [expr [winfo rooty $itk_component(entry) ] - $h]
+ }
+
+ $itk_component(list) configure -width $w
+ wm overrideredirect $itk_component(popup) 0
+ wm geometry $itk_component(popup) +$x+$y
+ wm overrideredirect $itk_component(popup) 1
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _postList
+#
+# Pop up the list in a dropdown style Combobox.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_postList {} {
+ if {[$itk_component(list) size] == ""} {
+ return
+ }
+
+ set _isPosted true
+ _positionList
+
+ # map window and do a grab
+ wm deiconify $itk_component(popup)
+ _listShowing -wait
+ if {$itk_option(-grab) == "global"} {
+ grab -global $itk_component(popup)
+ } else {
+ grab $itk_component(popup)
+ }
+ raise $itk_component(popup)
+ focus $itk_component(popup)
+ _drawArrow
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _previous
+#
+# Select the previous item in the list. Wraps at front
+# and end of list.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_previous {} {
+ if {[size] <= 1} {
+ return
+ }
+ set i [curselection]
+ if {$i == "" || $i == 0} {
+ set i [expr [size] - 1]
+ } else {
+ incr i -1
+ }
+ selection clear 0 end
+ selection set $i $i
+ see $i
+ set _currItem $i
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _resizeArrow
+#
+# Recalculate the arrow button size and then redraw it.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_resizeArrow {} {
+ set bw [expr [$itk_component(arrowBtn) cget -borderwidth]+ \
+ [$itk_component(arrowBtn) cget -highlightthickness]]
+ set newHeight [expr [winfo reqheight $itk_component(entry) ]-(2*$bw) - 2]
+ $itk_component(arrowBtn) configure -width $newHeight -height $newHeight
+ _drawArrow
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _selectCmd
+#
+# Called when list item is selected to insert new text
+# in entry, and call user -command callback if defined.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_selectCmd {} {
+ $itk_component(entry) configure -state normal
+
+ set _currItem [$itk_component(list) curselection]
+ set item [$itk_component(list) getcurselection]
+ clear entry
+ $itk_component(entry) insert 0 $item
+ switch -- $itk_option(-editable) {
+ 0 - false - no - off {
+ $itk_component(entry) configure -state disabled
+ }
+ }
+
+ # execute user command
+ if {$itk_option(-selectioncommand) != ""} {
+ uplevel #0 $itk_option(-selectioncommand)
+ }
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _toggleList
+#
+# Post or unpost the dropdown listbox (toggle).
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_toggleList {} {
+ if {[winfo ismapped $itk_component(popup)] } {
+ _unpostList
+ } else {
+ _postList
+ }
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _unpostList
+#
+# Unmap the listbox (pop it down).
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_unpostList {} {
+ # Determine if event occured in the scrolledlistbox and, if it did,
+ # don't unpost it. (A selection in the list unposts it correctly and
+ # in the scrollbar we don't want to unpost it.)
+ set x [winfo x $itk_component(list)]
+ set y [winfo y $itk_component(list)]
+ set w [winfo width $itk_component(list)]
+ set h [winfo height $itk_component(list)]
+
+ wm withdraw $itk_component(popup)
+ grab release $itk_component(popup)
+
+ set _isPosted false
+
+ $itk_component(list) selection clear 0 end
+ if {$_currItem != {}} {
+ $itk_component(list) selection set $_currItem $_currItem
+ $itk_component(list) activate $_currItem
+ }
+
+ switch -- $itk_option(-editable) {
+ 1 - true - yes - on {
+ $itk_component(entry) configure -state normal
+ }
+ 0 - false - no - off {
+ $itk_component(entry) configure -state disabled
+ }
+ }
+
+ _drawArrow
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _commonBindings
+#
+# Bindings that are used by both simple and dropdown
+# style Comboboxes.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_commonBindings {} {
+ bind $itk_component(entry) <KeyPress-BackSpace> [code $this _bs]
+ bind $itk_component(entry) <KeyRelease> [code $this _lookup %K]
+ bind $itk_component(entry) <Down> [code $this _next]
+ bind $itk_component(entry) <Up> [code $this _previous]
+ bind $itk_component(entry) <Control-n> [code $this _next]
+ bind $itk_component(entry) <Control-p> [code $this _previous]
+ bind [_slbListbox] <Control-n> [code $this _next]
+ bind [_slbListbox] <Control-p> [code $this _previous]
+}
+
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _dropdownBindings
+#
+# Bindings used only by the dropdown type Combobox.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_dropdownBindings {} {
+ bind $itk_component(popup) <Escape> [code $this _unpostList]
+ bind $itk_component(popup) <space> \
+ "[code $this _stateSelect]; [code $this _unpostList]"
+ bind $itk_component(popup) <Return> \
+ "[code $this _stateSelect]; [code $this _unpostList]"
+ bind $itk_component(popup) <ButtonRelease-1> \
+ [code $this _dropdownBtnRelease %W %x %y]
+
+ bind $itk_component(list) <Map> \
+ [code $this _listShowing 1]
+ bind $itk_component(list) <Unmap> \
+ [code $this _listShowing 0]
+
+ # once in the listbox, we drop on the next release (unless in scrollbar)
+ bind [_slbListbox] <Enter> \
+ [code $this _ignoreNextBtnRelease false]
+
+ bind $itk_component(arrowBtn) <3> [code $this _next]
+ bind $itk_component(arrowBtn) <Shift-3> [code $this _previous]
+ bind $itk_component(arrowBtn) <Down> [code $this _next]
+ bind $itk_component(arrowBtn) <Up> [code $this _previous]
+ bind $itk_component(arrowBtn) <Control-n> [code $this _next]
+ bind $itk_component(arrowBtn) <Control-p> [code $this _previous]
+ bind $itk_component(arrowBtn) <Shift-Down> [code $this _toggleList]
+ bind $itk_component(arrowBtn) <Shift-Up> [code $this _toggleList]
+ bind $itk_component(arrowBtn) <Return> [code $this _toggleList]
+ bind $itk_component(arrowBtn) <space> [code $this _toggleList]
+
+ bind $itk_component(entry) <Configure> [code $this _resizeArrow]
+ bind $itk_component(entry) <Shift-Down> [code $this _toggleList]
+ bind $itk_component(entry) <Shift-Up> [code $this _toggleList]
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _simpleBindings
+#
+# Bindings used only by the simple type Comboboxes.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_simpleBindings {} {
+ bind [_slbListbox] <ButtonRelease-1> [code $this _stateSelect]
+ # "[code $this _stateselect]; [code $this _selectCmd]"
+
+
+ bind [_slbListbox] <space> [code $this _stateSelect]
+ bind [_slbListbox] <Return> [code $this _stateSelect]
+ bind $itk_component(entry) <Escape> ""
+ bind $itk_component(entry) <Shift-Down> ""
+ bind $itk_component(entry) <Shift-Up> ""
+ bind $itk_component(entry) <Configure> ""
+}
+
+# ------------------------------------------------------
+# PROTECTED METHOD: _listShowing ?val?
+#
+# Used instead of "tkwait visibility" to make sure that
+# the dropdown list is visible. Whenever the list gets
+# mapped or unmapped, this method is called to keep
+# track of it. When it is called with the value "-wait",
+# it waits for the list to be mapped.
+# ------------------------------------------------------
+body iwidgets::Combobox::_listShowing {{val ""}} {
+ if {$val == ""} {
+ return $_listShowing($this)
+ } elseif {$val == "-wait"} {
+ while {!$_listShowing($this)} {
+ tkwait variable [scope _listShowing($this)]
+ }
+ return
+ }
+ set _listShowing($this) $val
+}
+
+# ------------------------------------------------------
+# PRIVATE METHOD: _slbListbox
+#
+# Access the tk listbox window out of the scrolledlistbox.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_slbListbox {} {
+ return [$itk_component(list) component listbox]
+}
+
+# ------------------------------------------------------
+# PRIVATE METHOD: _stateSelect
+#
+# only allows a B1 release in the listbox to have an effect if -state is
+# normal.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_stateSelect {} {
+ switch -- $itk_option(-state) {
+ normal {
+ [code $this _selectCmd]
+ }
+ }
+}
+
+# ------------------------------------------------------
+# PRIVATE METHOD: _bs
+#
+# A part of the auto-completion code, this function sets a flag when the
+# Backspace key is hit and there is a selection in the entry field.
+# Note that it's probably buggy to assume that a selection being present
+# means that that selection came from auto-completion.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_bs {} {
+ #
+ # exit if completion is turned off
+ #
+ switch -- $itk_option(-completion) {
+ 0 - no - false - off {
+ return
+ }
+ }
+ #
+ # critical section flag. it ain't perfect, but for most usage it'll
+ # keep us from being in this code "twice" at the same time
+ # (auto-repeated keystrokes are a pain!)
+ #
+ if {$_inbs} {
+ return
+ } else {
+ set _inbs 1
+ }
+
+ #
+ # set the _doit flag if there is a selection set in the entry field
+ #
+ set _doit 0
+ if [$itk_component(entry) selection present] {
+ set _doit 1
+ }
+
+ #
+ # clear the semaphore and return
+ #
+ set _inbs 0
+}
+
+# ------------------------------------------------------
+# PRIVATE METHOD: _lookup
+#
+# handles auto-completion of text typed (or insert'd) into the entry field.
+#
+# ------------------------------------------------------
+body iwidgets::Combobox::_lookup {key} {
+ #
+ # exit if completion is turned off
+ #
+ switch -- $itk_option(-completion) {
+ 0 - no - false - off {
+ return
+ }
+ }
+
+ #
+ # critical section flag. it ain't perfect, but for most usage it'll
+ # keep us from being in this code "twice" at the same time
+ # (auto-repeated keystrokes are a pain!)
+ #
+ if {$_inlookup} {
+ return
+ } else {
+ set _inlookup 1
+ }
+
+ #
+ # if state of megawidget is disabled, or the entry is not editable,
+ # clear the semaphore and exit
+ #
+ if {$itk_option(-state) == "disabled" \
+ || [lsearch {on 1 true yes} $itk_option(-editable)] == -1} {
+ set _inlookup 0
+ return
+ }
+
+ #
+ # okay, *now* we can get to work
+ # the _bs function is called on keyPRESS of BackSpace, and will set
+ # the _doit flag if there's a selection set in the entryfield. If
+ # there is, we're assuming that it's generated by completion itself
+ # (this is probably a Bad Assumption), so we'll want to whack the
+ # selected text, as well as the character immediately preceding the
+ # insertion cursor.
+ #
+ if {$key == "BackSpace"} {
+ if {$_doit} {
+ set first [expr [$itk_component(entry) index insert] -1]
+ $itk_component(entry) delete $first end
+ $itk_component(entry) icursor $first
+ }
+ }
+
+ #
+ # get the text left in the entry field, and its length. if
+ # zero-length, clear the selection in the listbox, clear the
+ # semaphore, and boogie.
+ #
+ set text [get]
+ set len [string length $text]
+ if {$len == 0} {
+ $itk_component(list) selection clear 0 end
+ set _inlookup 0
+ return
+ }
+
+ #
+ # okay, so we have to do a lookup. find the first match in the
+ # listbox to the text we've got in the entry field (glob).
+ # if one exists, clear the current listbox selection, and set it to
+ # the one we just found, making that one visible in the listbox.
+ # then, pick off the text from the listbox entry that hadn't yet been
+ # entered into the entry field. we need to tack that text onto the
+ # end of the entry field, select it, and then set the insertion cursor
+ # back to just before the point where we just added that text.
+ # if one didn't exist, then just clear the listbox selection
+ #
+ set item [lsearch [$itk_component(list) get 0 end] "$text*" ]
+ if {$item != -1} {
+ $itk_component(list) selection clear 0 end
+ $itk_component(list) selection set $item $item
+ see $item
+ set remainder [string range [$itk_component(list) get $item] \
+ $len end]
+ $itk_component(entry) insert end $remainder
+ $itk_component(entry) selection range $len end
+ $itk_component(entry) icursor $len
+ } else {
+ $itk_component(list) selection clear 0 end
+ }
+ #
+ # clear the semaphore and return
+ #
+ set _inlookup 0
+ return
+}