home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2000 December
/
PCWorld_2000-12_cd.bin
/
Komunikace
/
Comanche
/
comanche.exe
/
lib
/
iwidgets2.2.0
/
scripts
/
combobox.itk
< prev
next >
Wrap
Text File
|
1999-02-24
|
37KB
|
1,138 lines
#
# 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.
# - determine clean way to have a state for listbox/canvas.
# - add completion functionality when typing in the entry.
# - add grab option: global, local, none.
#
# ----------------------------------------------------------------------
# AUTHOR: John S. Sigler EMAIL: jsigler@spd.dsccc.com
# sigler@onramp.net
# @(#) $Id: combobox.itk,v 1.1 1998/07/27 18:49:23 stanton Exp $
# ----------------------------------------------------------------------
# Copyright (c) 1995 John S. Sigler
# ======================================================================
# 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 w 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 -autoclear autoClear AutoClear true
itk_option define -arrowrelief arrowRelief Relief raised
itk_option define -dropdown dropdown Dropdown true
itk_option define -editable editable Editable true
itk_option define -fliparrow flipArrow FlipArrow false
itk_option define -items items Items ""
itk_option define -labelpos labelPos Position w
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 -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 {{mode normal}}
protected method _dropdownBtnRelease {{window {}} {x 1} {y 1}}
protected method _ignoreNextBtnRelease {ignore}
protected method _insertText {index string}
protected method _next {}
protected method _packArrow {labelpos}
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 _slbListbox {}
private variable _currItem {}; ;# current selected item.
private variable _ignoreRelease true ;# next button release ignored.
private variable _isPosted false; ;# is the dropdown popped up.
private variable _repacking {} ;# non-null => _packComponents pending.
private common _listShowing
}
#
# 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.
_doLayout
}
# ------------------------------------------------------------------
# DESTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Combobox::destructor {} {
# catch any repacking that may be waiting for idle time
if {$_repacking != ""} {
after cancel $_repacking
}
}
# ================================================================
# OPTIONS
# ================================================================
# --------------------------------------------------------------------
# OPTION: -autoclear
#
# Specifies wheather or not to clear the entry field as items are
# added to the list. The default is true.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::autoclear {}
# --------------------------------------------------------------------
# OPTION: -arrowrelief
#
# Relief style used on the arrow button.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::arrowrelief {}
# --------------------------------------------------------------------
# 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 {
if {$itk_option(-dropdown)} {
if {[winfo exists $itk_interior.list]} {
destroy $itk_component(list)
_doLayout
}
} else {
if {[winfo exists $itk_interior.popup.list]} {
destroy $itk_component(margin)
destroy $itk_component(arrowBtn)
destroy $itk_component(popup) ;# this deletes the list too
_doLayout
}
}
}
# --------------------------------------------------------------------
# OPTION: -editable
#
# Boolean which allows/disallows user input to the entry field area.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::editable {
if {$itk_option(-editable)} {
configure -state normal -command [code $this _addToList]
bind $itk_component(entry) <1> ""
} else {
configure -state disabled
bind $itk_component(entry) <1> [code $this _toggleList]
}
}
# --------------------------------------------------------------------
# OPTION: -fliparrow
#
# Boolean which causes dropdown comboboxes to have their arrow point
# up when the listbox is displayed.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::fliparrow {
# boolean error check
if {$itk_option(-fliparrow)} {
}
}
# --------------------------------------------------------------------
# OPTION: -items
#
# Set/get the current list of items in the listbox.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::items {
# clear out what was in entry field before
if {$itk_option(-autoclear)} {
delete entry 0 end
}
if {[winfo exists $itk_interior.popup.list]} {
_drawArrow normal
}
}
# --------------------------------------------------------------------
# OPTION: -labelpos
#
# Labelpos. Overrides the labelpos of the labeledwidget. This doesn't
# work as positionalLabel seems to get called after this routine is called!
# --------------------------------------------------------------------
configbody iwidgets::Combobox::labelpos {
iwidgets::Labeledwidget::_positionLabel
switch -- $itk_option(-labelpos) {
e -
w {
pack configure $itk_component(label) -anchor n
}
}
}
# --------------------------------------------------------------------
# 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 {}
# --------------------------------------------------------------------
# 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: -unique
#
# Boolean which disallows/allows adding duplicate items to the listbox.
# --------------------------------------------------------------------
configbody iwidgets::Combobox::unique {
# boolean error check
if {$itk_option(-unique)} {
}
}
# =================================================================
# 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} {
if {$args == {}} {
error "no value given for parameter \"string\" in function\
\"Combobox::insert\""
}
switch -- $component {
entry {
if { [llength $args] > 1} {
error "called function \"Combobox::insert entry\" with too\
many arguments"
} else {
eval iwidgets::Entryfield::insert $index $args
}
}
list {
configure -items [eval linsert {$itk_option(-items)} $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
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}} {
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_option(-items) $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 and clear the text area
insert list end $input
if {$itk_option(-autoclear)} {
delete entry 0 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 and margin childsite's be on the right hand side
configure -childsitepos e
# add spacer between arrow and the entry component
itk_component add margin {
frame $itk_interior.margin -width $itk_option(-margin)
} {
rename -width -margin margin Margin
}
# arrow button to popup the list
itk_component add arrowBtn {
canvas $itk_interior.arrowBtn -borderwidth 2 \
-width 16 -height 16
} {
keep -background -borderwidth -cursor \
-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
wm overrideredirect $itk_interior.popup 1
# the listbox
itk_component add list {
iwidgets::Scrolledlistbox $itk_interior.popup.list -exportselection no \
-vscrollmode dynamic -hscrollmode dynamic
} {
keep -background -borderwidth -cursor -foreground \
-highlightcolor -highlightthickness \
-hscrollmode -items -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 -items -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
}
configure -items [eval lreplace {$itk_option(-items)} $first $last]
# remove the item if it is no longer in the list
set text [$this get]
if {$text != ""} {
set index [lsearch -exact $itk_option(-items) $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]
if {$itk_option(-editable)} {
} else {
$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 ?mode?
#
# Draw the arrow button. Determines packing according to
# -labelpos.
#
# ------------------------------------------------------
body iwidgets::Combobox::_drawArrow {{mode normal}} {
set flip false
switch -- $mode {
normal {
set fg [cget -foreground]
$itk_component(arrowBtn) configure -relief $itk_option(-arrowrelief)
bind $itk_component(arrowBtn) <1> [code $this _toggleList]
if {$_isPosted} {
if {$itk_option(-fliparrow)} {
set flip true
}
}
}
disabled {
set fg grey65
$itk_component(arrowBtn) configure -relief $itk_option(-arrowrelief)
bind $itk_component(arrowBtn) <1> ""
}
depressed {
set fg [cget -foreground]
$itk_component(arrowBtn) configure -relief sunken
# update
}
}
# undraw the old arrow polygon
$itk_component(arrowBtn) delete arrow
# draw new arrow
set bw [expr ([$itk_component(arrowBtn) cget -borderwidth] + \
[$itk_component(arrowBtn) cget -highlightthickness]) / 2]
set h [expr [$itk_component(arrowBtn) cget -height] + (2*$bw)]
set w [expr [$itk_component(arrowBtn) cget -width] + (2*$bw)]
if {$flip} {
$itk_component(arrowBtn) create polygon \
[expr .25*$w+$bw] [expr .75*$h+$bw] \
[expr .75*$w+$bw] [expr .75*$h+$bw] \
[expr .5*$w+$bw] [expr .25*$h+$bw-1] -fill $fg -tag arrow
} else {
$itk_component(arrowBtn) create polygon \
[expr .25*$w+$bw] [expr .25*$h+$bw] \
[expr .75*$w+$bw] [expr .25*$h+$bw] \
[expr .5*$w+$bw] [expr .75*$h+$bw] \
-fill $fg -tag arrow
}
}
# ------------------------------------------------------
# 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]])} {
_selectCmd
}
_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 {[$this size] <= 1} {
return
}
set i [$this curselection]
if {($i == {}) || ($i == [expr [$this size]-1]) } {
set i 0
} else {
incr i
}
$this selection clear 0 end
$this selection set $i $i
$this see $i
set _currItem $i
}
# ------------------------------------------------------
# PROTECTED METHOD: _packArrow labelpos
#
# Pack the arrowbutton according to the label position.
#
# ------------------------------------------------------
body iwidgets::Combobox::_packArrow {labelpos} {
pack $itk_component(arrowBtn) -side right -anchor center
}
# ------------------------------------------------------
# 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)} {
pack $itk_component(margin) -side left
pack configure $itk_component(list) -expand yes -fill both
_resizeArrow
pack $itk_component(arrowBtn) -side right
} else {
# size and pack list hack
set w [winfo reqwidth $itk_component(hull)]
$itk_component(list) configure -width $w
pack configure $itk_component(entry) -fill x -side top -expand no
pack configure $itk_component(efchildsite) -side top \
-after $itk_component(entry) -fill both -expand yes
pack configure $itk_component(list) -side top -fill both -expand yes
}
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 geometry $itk_component(popup) +$x+$y
}
# ------------------------------------------------------
# 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
_drawArrow depressed ;# sad button
_positionList
# map window and do a grab
wm deiconify $itk_component(popup)
_listShowing -wait
grab -global $itk_component(popup)
raise $itk_component(popup)
focus $itk_component(popup)
_drawArrow normal
set _ignoreRelease true
}
# ------------------------------------------------------
# PROTECTED METHOD: _previous
#
# Select the previous item in the list. Wraps at front
# and end of list.
#
# ------------------------------------------------------
body iwidgets::Combobox::_previous {} {
if {[$this size] <= 1} {
return
}
set i [$this curselection]
if {$i == "" || $i == 0} {
set i [expr [$this size] - 1]
} else {
incr i -1
}
$this selection clear 0 end
$this selection set $i $i
$this 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)]
$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
if {$itk_option(-editable)} {
} else {
$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
_drawArrow normal
$itk_component(list) selection clear 0 end
if {$_currItem != {}} {
$itk_component(list) selection set $_currItem $_currItem
$itk_component(list) activate $_currItem
}
if {$itk_option(-editable)} {
$itk_component(entry) configure -state normal
} else {
$itk_component(entry) configure -state disabled
}
}
# ------------------------------------------------------
# PROTECTED METHOD: _commonBindings
#
# Bindings that are used by both simple and dropdown
# style Comboboxes.
#
# ------------------------------------------------------
body iwidgets::Combobox::_commonBindings {} {
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 _selectCmd]; [code $this _unpostList]"
bind $itk_component(popup) <Return> \
"[code $this _selectCmd]; [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) <Configure> [code $this _drawArrow]
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 _selectCmd]
bind [_slbListbox] <space> [code $this _selectCmd]
bind [_slbListbox] <Return> [code $this _selectCmd]
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]
}
# ... emacs mode recognition ...
# Local Variables:
# mode: tcl
# End: