You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1444 lines
45 KiB
Plaintext
1444 lines
45 KiB
Plaintext
# 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
|
|
# ----------------------------------------------------------------------
|
|
# CURRENT MAINTAINER: Chad Smith EMAIL: csmith@adc.com, itclguy@yahoo.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
|
|
# ------------------------------------------------------------------
|
|
itcl::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 variable _grab ;# used to restore grabs
|
|
private variable _next_prevFLAG 0 ;# Used in _lookup to fix SF Bug 501300
|
|
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
|
|
# ------------------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::constructor {args} {
|
|
set _listShowing($this) 0
|
|
set _grab(window) ""
|
|
set _grab(status) ""
|
|
|
|
# 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
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
# --------------------------------------------------------------------
|
|
itcl::configbody iwidgets::Combobox::arrowrelief {}
|
|
|
|
# --------------------------------------------------------------------
|
|
# OPTION: -completion
|
|
#
|
|
# Relief style used on the arrow button.
|
|
# --------------------------------------------------------------------
|
|
itcl::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.
|
|
# --------------------------------------------------------------------
|
|
itcl::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.
|
|
# --------------------------------------------------------------------
|
|
itcl::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
|
|
# --------------------------------------------------------------------
|
|
itcl::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.)
|
|
# --------------------------------------------------------------------
|
|
itcl::configbody iwidgets::Combobox::listheight {}
|
|
|
|
# --------------------------------------------------------------------
|
|
# OPTION: -margin
|
|
#
|
|
# Spacer between the entry field and arrow button of dropdown style
|
|
# Comboboxes.
|
|
# --------------------------------------------------------------------
|
|
itcl::configbody iwidgets::Combobox::margin {
|
|
grid columnconfigure $itk_interior 0 -minsize $itk_option(-margin)
|
|
}
|
|
|
|
# --------------------------------------------------------------------
|
|
# OPTION: -popupcursor
|
|
#
|
|
# Set the cursor for the popup list.
|
|
# --------------------------------------------------------------------
|
|
itcl::configbody iwidgets::Combobox::popupcursor {}
|
|
|
|
# --------------------------------------------------------------------
|
|
# OPTION: -selectioncommand
|
|
#
|
|
# Defines the proc to be called when an item is selected in the list.
|
|
# --------------------------------------------------------------------
|
|
itcl::configbody iwidgets::Combobox::selectioncommand {}
|
|
|
|
# --------------------------------------------------------------------
|
|
# OPTION: -state
|
|
#
|
|
# overall state of megawidget
|
|
# --------------------------------------------------------------------
|
|
itcl::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
|
|
}
|
|
}
|
|
}
|
|
readonly {
|
|
$itk_component(entry) configure -state readonly
|
|
}
|
|
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.
|
|
# --------------------------------------------------------------------
|
|
itcl::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).
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::delete {component first {last {}}} {
|
|
switch -- $component {
|
|
entry {
|
|
if {$last == {}} {
|
|
set last [expr {$first + 1}]
|
|
}
|
|
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 .
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::getcurselection {} {
|
|
return [$itk_component(list) getcurselection]
|
|
}
|
|
|
|
# ------------------------------------------------------------------
|
|
# PUBLIC METHOD: invoke
|
|
#
|
|
# Pops up or down a dropdown combobox.
|
|
#
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------------
|
|
itcl::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
|
|
[itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
# ------------------------------------------------------------------
|
|
itcl::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?
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
# ------------------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_createComponents {} {
|
|
if {$itk_option(-dropdown)} {
|
|
# --- build a dropdown combobox ---
|
|
|
|
# make the arrow childsite be on the right hand side
|
|
|
|
#-------------------------------------------------------------
|
|
# BUG FIX: csmith (Chad Smith: csmith@adc.com), 3/4/99
|
|
#-------------------------------------------------------------
|
|
# The following commented line of code overwrites the -command
|
|
# option when passed into the constructor. The order of calls
|
|
# in the constructor is:
|
|
# 1) eval itk_initalize $args (initializes -command)
|
|
# 2) _doLayout
|
|
# 3) _createComponents (overwrites -command)
|
|
# The solution is to only set the -command option if it hasn't
|
|
# already been set. The following 4 lines of code do this.
|
|
#-------------------------------------------------------------
|
|
# ** configure -childsitepos e -command [code $this _addToList]
|
|
#-------------------------------------------------------------
|
|
configure -childsitepos e
|
|
if ![llength [cget -command]] {
|
|
configure -command [itcl::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 [itcl::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".
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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".
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_doLayout {{when later}} {
|
|
_createComponents
|
|
_packComponents $when
|
|
}
|
|
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _drawArrow
|
|
#
|
|
# Draw the arrow button. Determines packing according to
|
|
# -labelpos.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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
|
|
|
|
# execute user command
|
|
if {$itk_option(-selectioncommand) != ""} {
|
|
uplevel #0 $itk_option(-selectioncommand)
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _ignoreNextBtnRelease ignore
|
|
#
|
|
# Set private variable _ignoreRelease. If this variable
|
|
# is true then the next button release will not remove
|
|
# a dropdown list.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_ignoreNextBtnRelease {ignore} {
|
|
set _ignoreRelease $ignore
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _next
|
|
#
|
|
# Select the next item in the list.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_next {} {
|
|
|
|
set _next_prevFLAG 1
|
|
|
|
if {[size] <= 1} {
|
|
return
|
|
}
|
|
set i [curselection]
|
|
if {($i == {}) || ($i == ([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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_packComponents {{when later}} {
|
|
if {$when == "later"} {
|
|
if {$_repacking == ""} {
|
|
set _repacking [after idle [itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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 {(($y+$h) > $sh) && ($y > ($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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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
|
|
|
|
# Added by csmith, 12/19/00. Thanks to Erik Leunissen for
|
|
# finding this problem. We need to restore any previous
|
|
# grabs after the dropdown listbox is withdrawn. To do this,
|
|
# save the currently grabbed window. It is then restored in
|
|
# the _unpostList method.
|
|
set _grab(window) [::grab current]
|
|
if {$_grab(window) != ""} {
|
|
set _grab(status) [::grab status $_grab(window)]
|
|
}
|
|
|
|
# Now grab the dropdown listbox.
|
|
if {$itk_option(-grab) == "global"} {
|
|
::grab -global $itk_component(popup)
|
|
} else {
|
|
::grab $itk_component(popup)
|
|
}
|
|
raise $itk_component(popup)
|
|
focus $itk_component(popup)
|
|
_drawArrow
|
|
|
|
# Added by csmith, 10/26/00. This binding keeps the listbox
|
|
# from staying mapped if the window in which the combobox
|
|
# is packed is iconified.
|
|
bind $itk_component(entry) <Unmap> [itcl::code $this _unpostList]
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _previous
|
|
#
|
|
# Select the previous item in the list. Wraps at front
|
|
# and end of list.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_previous {} {
|
|
|
|
set _next_prevFLAG 1
|
|
|
|
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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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
|
|
}
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _toggleList
|
|
#
|
|
# Post or unpost the dropdown listbox (toggle).
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_toggleList {} {
|
|
if {[winfo ismapped $itk_component(popup)] } {
|
|
_unpostList
|
|
} else {
|
|
_postList
|
|
}
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _unpostList
|
|
#
|
|
# Unmap the listbox (pop it down).
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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)
|
|
|
|
# Added by csmith, 12/19/00. Thanks to Erik Leunissen for finding
|
|
# this problem. We need to restore any previous grabs when the
|
|
# dropdown listbox is unmapped.
|
|
if {$_grab(window) != ""} {
|
|
if {$_grab(status) == "global"} {
|
|
::grab -global $_grab(window)
|
|
} else {
|
|
::grab $_grab(window)
|
|
}
|
|
set _grab(window) ""
|
|
set _grab(status) ""
|
|
}
|
|
|
|
# Added by csmith, 10/26/00. This binding resets the binding
|
|
# created in _postList - see that method for further details.
|
|
bind $itk_component(entry) <Unmap> {}
|
|
|
|
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
|
|
update
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _commonBindings
|
|
#
|
|
# Bindings that are used by both simple and dropdown
|
|
# style Comboboxes.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_commonBindings {} {
|
|
bind $itk_component(entry) <KeyPress-BackSpace> [itcl::code $this _bs]
|
|
bind $itk_component(entry) <KeyRelease> [itcl::code $this _lookup %K]
|
|
bind $itk_component(entry) <Down> [itcl::code $this _next]
|
|
bind $itk_component(entry) <Up> [itcl::code $this _previous]
|
|
bind $itk_component(entry) <Control-n> [itcl::code $this _next]
|
|
bind $itk_component(entry) <Control-p> [itcl::code $this _previous]
|
|
bind [_slbListbox] <Control-n> [itcl::code $this _next]
|
|
bind [_slbListbox] <Control-p> [itcl::code $this _previous]
|
|
}
|
|
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _dropdownBindings
|
|
#
|
|
# Bindings used only by the dropdown type Combobox.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_dropdownBindings {} {
|
|
bind $itk_component(popup) <Escape> [itcl::code $this _unpostList]
|
|
bind $itk_component(popup) <space> \
|
|
"[itcl::code $this _stateSelect]; [itcl::code $this _unpostList]"
|
|
bind $itk_component(popup) <Return> \
|
|
"[itcl::code $this _stateSelect]; [itcl::code $this _unpostList]"
|
|
bind $itk_component(popup) <ButtonRelease-1> \
|
|
[itcl::code $this _dropdownBtnRelease %W %x %y]
|
|
|
|
bind $itk_component(list) <Map> \
|
|
[itcl::code $this _listShowing 1]
|
|
bind $itk_component(list) <Unmap> \
|
|
[itcl::code $this _listShowing 0]
|
|
|
|
# once in the listbox, we drop on the next release (unless in scrollbar)
|
|
bind [_slbListbox] <Enter> \
|
|
[itcl::code $this _ignoreNextBtnRelease false]
|
|
|
|
bind $itk_component(arrowBtn) <3> [itcl::code $this _next]
|
|
bind $itk_component(arrowBtn) <Shift-3> [itcl::code $this _previous]
|
|
bind $itk_component(arrowBtn) <Down> [itcl::code $this _next]
|
|
bind $itk_component(arrowBtn) <Up> [itcl::code $this _previous]
|
|
bind $itk_component(arrowBtn) <Control-n> [itcl::code $this _next]
|
|
bind $itk_component(arrowBtn) <Control-p> [itcl::code $this _previous]
|
|
bind $itk_component(arrowBtn) <Shift-Down> [itcl::code $this _toggleList]
|
|
bind $itk_component(arrowBtn) <Shift-Up> [itcl::code $this _toggleList]
|
|
bind $itk_component(arrowBtn) <Return> [itcl::code $this _toggleList]
|
|
bind $itk_component(arrowBtn) <space> [itcl::code $this _toggleList]
|
|
|
|
bind $itk_component(entry) <Configure> [itcl::code $this _resizeArrow]
|
|
bind $itk_component(entry) <Shift-Down> [itcl::code $this _toggleList]
|
|
bind $itk_component(entry) <Shift-Up> [itcl::code $this _toggleList]
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PROTECTED METHOD: _simpleBindings
|
|
#
|
|
# Bindings used only by the simple type Comboboxes.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_simpleBindings {} {
|
|
bind [_slbListbox] <ButtonRelease-1> [itcl::code $this _stateSelect]
|
|
bind [_slbListbox] <space> [itcl::code $this _stateSelect]
|
|
bind [_slbListbox] <Return> [itcl::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.
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_listShowing {{val ""}} {
|
|
if {$val == ""} {
|
|
return $_listShowing($this)
|
|
} elseif {$val == "-wait"} {
|
|
while {!$_listShowing($this)} {
|
|
tkwait variable [itcl::scope _listShowing($this)]
|
|
}
|
|
return
|
|
}
|
|
set _listShowing($this) $val
|
|
}
|
|
|
|
# ------------------------------------------------------
|
|
# PRIVATE METHOD: _slbListbox
|
|
#
|
|
# Access the tk listbox window out of the scrolledlistbox.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_stateSelect {} {
|
|
switch -- $itk_option(-state) {
|
|
normal {
|
|
[itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::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.
|
|
#
|
|
# ------------------------------------------------------
|
|
itcl::body iwidgets::Combobox::_lookup {key} {
|
|
|
|
#
|
|
# Don't process auto-completion stuff if navigation key was released
|
|
# Fixes SF bug 501300
|
|
#
|
|
if {$_next_prevFLAG} {
|
|
set _next_prevFLAG 0
|
|
return
|
|
}
|
|
|
|
#
|
|
# 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
|
|
}
|
|
|
|
# No need to do lookups for Shift keys or Arrows. The up/down
|
|
# arrow keys should walk up/down the listbox entries.
|
|
switch $key {
|
|
Shift_L - Shift_R - Up - Down - Left - Right {
|
|
set _inlookup 0
|
|
return
|
|
}
|
|
default { }
|
|
}
|
|
|
|
# Added by csmith 12/11/01 to resolve SF ticket #474817. It's an unusual
|
|
# circumstance, but we need to make sure the character passed into this
|
|
# method matches the last character in the entry's text string. It's
|
|
# possible to type fast enough that the _lookup method gets invoked
|
|
# *after* multiple characters have been typed and *before* the first
|
|
# character has been processed. For example, you can type "bl" very
|
|
# quickly, and by the time the interpreter processes "b", the "l" has
|
|
# already been placed in the entry field. This causes problems as noted
|
|
# in the SF ticket.
|
|
#
|
|
# Thus, if the character currently being processed does not match the
|
|
# last character in the entry field, reset the _inlookup flag and return.
|
|
# Also, note that we're only concerned with single characters here, not
|
|
# keys such as backspace, delete, etc.
|
|
if {$key != [string range $text end end] && [string match ? $key]} {
|
|
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
|
|
}
|