2 ## Copyright 1996 Jeffrey Hobbs
5 ##------------------------------------------------------------------------
10 ## Implements a Combobox mega-widget
13 ## combobox <window pathname> <options>
16 ## (Any entry widget option may be used in addition to these)
18 ## -command script DEFAULT: {}
19 ## Script to evaluate when a selection is made.
21 ## -editable TCL_BOOLEAN DEFAULT: 1
22 ## Whether to allow the user to edit the entry widget contents
24 ## -grab type DEFAULT: local
25 ## Type of grab (local, none, global) to use when listbox appears.
27 ## -labelanchor anchor DEFAULT: c
28 ## Anchor for the label. Reasonable values are c, w and e.
30 ## -labeltext string DEFAULT: {}
33 ## -labelwidth # DEFAULT: 0 (self-sizing)
34 ## Width for the label
36 ## -list list DEFAULT: {}
37 ## List for the listbox
39 ## -listheight # DEFAULT: 5
40 ## Height of the listbox. If the number of items exceeds this
41 ## height, a scrollbar will automatically be added.
43 ## -postcommand script DEFAULT: {}
44 ## A command which is evaluated before the listbox pops up.
46 ## -prunelist TCL_BOOLEAN DEFAULT: 0
47 ## Whether to prevent duplicate listbox items
49 ## -tabexpand TCL_BOOLEAN DEFAULT: 1
50 ## Whether to allow tab expansion in entry widget (uses listbox items)
52 ## RETURNS: the window pathname
54 ## BINDINGS (in addition to default widget bindings)
56 ## <Double-1> or <Escape> in the entry widget, or selecting the
57 ## button will toggle the listbox portion.
59 ## <Escape> will close the listbox without a selection.
61 ## <Tab> in the entry widget searches the listbox for a unique match.
63 ## <Double-1> in the listbox selects that item.
66 ## These are the methods that the Combobox recognizes. Aside from
67 ## those listed here, it accepts what is valid for entry widgets.
69 ## configure ?option? ?value option value ...?
71 ## Standard tk widget routines.
74 ## Adds the string to the listbox.
75 ## If string is not specified, it uses what's in the entry widget.
78 ## Expands the string based on the contents of the listbox.
79 ## If string is not specified, it uses what's in the entry widget.
82 ## Toggles whether the listbox is mapped or not.
85 ## Sets the entry widget (or its textvariable, if it exists) to
86 ## the value of string.
89 ## Returns the true widget path of the specified widget. Valid
90 ## widgets are label, listbox, entry, toplevel, scrollbar.
93 ## The megawidget creates a global array with the classname, and a
94 ## global array which is the name of each megawidget created. The latter
95 ## array is deleted when the megawidget is destroyed.
96 ## The procedure combobox and those beginning with Combobox are
97 ## used. Also, when a widget is created, commands named .$widgetname
98 ## and Combobox$widgetname are created.
102 ## pack [combobox .combo -label "Hello: "]
103 ## pack [combobox .combo -width 15 -textvariable myvar]
105 ##------------------------------------------------------------------------
109 ## single - not double click
110 ## -listheight should be *max height*, not strict height
112 package require Widget 1.0
113 package provide Combobox 1.1
120 {button button button {-image Combobox:Image \
121 -command [list Combobox_popup $w]}}
122 {toplevel toplevel drop {-cursor arrow}}
123 {listbox listbox drop.lbox {-selectmode single \
124 -width 5 -height $data(-listheight) \
125 -yscrollcommand [list $data(scrollbar) set]}}
126 {scrollbar scrollbar drop.sy {-orient vertical \
127 -command [list $data(listbox) yview]}}
131 -borderwidth {borderWidth BorderWidth 0}
133 -background {ALIAS entry -background}
134 -command {command Command {}}
135 -editable {editable Editable 1}
136 -grab {grab Grab local}
137 -labeltext {labelText Text {}}
138 -labelwidth {labelWidth Width 0}
139 -labelanchor {ALIAS label -anchor labelAnchor Anchor}
141 -listheight {listHeight ListHeight 5}
142 -postcommand {postCommand Command {}}
143 -prunelist {pruneList PruneList 0}
144 -relief {relief Relief flat}
145 -tabexpand {tabExpand TabExpand 1}
147 # Create this to make sure there are registered in auto_mkindex
148 # these must come before the [widget create ...]
149 proc Combobox args {}
150 proc combobox args {}
151 widget create Combobox
153 ;proc Combobox:construct {w args} {
156 ## Removable List Box
157 wm overrideredirect $data(toplevel) 1
158 wm transient $data(toplevel) [winfo toplevel $w]
159 wm group $data(toplevel) [winfo toplevel $w]
161 bind $w <Unmap> { catch {grab release %W} }
162 bind $w <Destroy> { catch {grab release %W} }
163 bind $data(toplevel) <Unmap> "catch {grab release {$w}}"
165 grid $data(label) $data(entry) $data(button) -in $w -sticky news
166 grid config $data(button) -sticky ns
167 grid columnconfig $w 1 -weight 1
168 grid $data(listbox) $data(scrollbar) -in $data(toplevel) -sticky ns
169 grid config $data(listbox) -sticky news
170 grid remove $data(scrollbar) $data(label)
171 grid columnconfig $data(toplevel) 0 -weight 1
172 grid rowconfig $data(toplevel) 0 -weight 1
174 bind $data(listbox) <Escape> [list $w popup]
175 bind $data(listbox) <Double-1> "Combobox:get [list $w] \[%W get \[%W nearest %y\]\]"
176 bind $data(listbox) <Return> "Combobox:get [list $w] \[%W get active\]"
179 ;proc Combobox:configure { w args } {
182 set truth {^(1|yes|true|on)$}
183 foreach {key val} $args {
185 -borderwidth - -relief { .$w configure $key $val }
187 $data(basecmd) configure -bg $val
188 $data(listbox) configure -bg $val
191 if {[set val [regexp $truth $val]]} {
192 $data(basecmd) configure -state normal
194 $data(basecmd) configure -state disabled
198 if {![regexp {^(local|global|none)$} $val junk val]} {
199 return -code error "bad $key option \"$val\": must be\
200 local, grab, or none"
204 $data(listbox) delete 0 end
205 eval $data(listbox) insert end $val
208 -prunelist { set val [regexp $truth $val] }
209 -labelanchor { $data(label) configure -anchor $val }
211 $data(label) configure -text $val
212 if {[string compare {} $val]} {
215 grid remove $data(label)
218 -labelwidth { $data(label) configure -width $val }
219 -listheight { $data(listbox) configure -height $val }
225 bind Combobox <Double-1> { %W popup }
226 bind Combobox <Escape> { %W popup }
227 bind Combobox <Tab> { %W expand [%W get]; break }
229 ;proc Combobox_popup {w} {
231 if {[winfo ismapped $data(toplevel)]} {
232 wm withdraw $data(toplevel)
233 catch {grab release $w}
236 uplevel \#0 $data(-postcommand)
238 set size [$data(listbox) size]
239 if {$size > $data(-listheight)} {
240 $data(listbox) configure -height $data(-listheight)
241 grid $data(scrollbar)
243 $data(listbox) configure -height $size
244 grid remove $data(scrollbar)
246 wm geometry $data(toplevel) [winfo width $data(entry)]x[winfo \
247 reqheight $data(toplevel)]+[winfo rootx $data(entry)]+[expr \
248 [winfo rooty $data(entry)]+[winfo reqheight $data(entry)]]
250 wm deiconify $data(toplevel)
251 if {[string match local $data(-grab)]} {
253 } elseif {[string match global $data(-grab)]} {
257 raise $data(toplevel)
261 ;proc Combobox_expand {w {str {}}} {
263 if {!$data(-tabexpand)} return
264 if {[string match {} $str]} { set str [$data(basecmd) get] }
266 foreach item [$data(listbox) get 0 end] {
267 if {[string match ${str}* $item]} {
273 set state [$data(basecmd) cget -state]
274 $data(basecmd) config -state normal
275 $data(basecmd) delete 0 end
277 set match [$data(class):BestMatch $match]
279 set match [lindex $match 0]
281 $data(basecmd) insert end $match
282 $data(basecmd) config -state $state
286 ;proc Combobox_add {w {str {}}} {
288 if {[string match {} $str]} { set str [$data(basecmd) get] }
290 if {!$data(-prunelist)} {
291 foreach l [$data(listbox) get 0 end] {
292 if {![string compare $l $str]} { set i 0 ; break }
295 if {$i} { $data(listbox) insert end $str }
298 ;proc Combobox_set {w str} {
300 set var [$data(basecmd) cget -textvar]
301 if {[string compare {} $var] && [uplevel \#0 info exists [list $var]]} {
305 set state [$data(basecmd) cget -state]
306 $data(basecmd) config -state normal
307 $data(basecmd) delete 0 end
308 $data(basecmd) insert 0 $str
309 $data(basecmd) config -state $state
313 ;proc Combobox:get {w i} {
316 if {[$data(listbox) size]} {
317 set state [$e cget -state]
318 $e config -state normal
321 $e config -state $state
322 if {[string compare $data(-command) {}]} {
323 uplevel \#0 $data(-command) $i
326 wm withdraw $data(toplevel)
330 ;proc Combobox:BestMatch l {
332 if {[llength $l]>1} {
333 set i [expr [string length $s]-1]
335 while {$i>=0 && [string first $s $l]} {
336 set s [string range $s 0 [incr i -1]]
345 image create bitmap Combobox:Image -data {#define downbut_width 14
346 #define downbut_height 14
347 static char downbut_bits[] = {
348 0x00, 0x00, 0xe0, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xfc, 0x0f,
349 0xf8, 0x07, 0xf0, 0x03, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xfe, 0x1f,
350 0xfe, 0x1f, 0x00, 0x00};