source: trunk/gui/scripts/combobox.tcl @ 1929

Last change on this file since 1929 was 1929, checked in by gah, 14 years ago
File size: 12.3 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: combobox - entry widget with a drop-down list of values
4#
5#  This widget is a typical combobox, an entry widget with a drop-down
6#  list of values.  If the -editable option is turned off, then the
7#  value can be set only from the drop-down list.  Otherwise, the
8#  drop-down is treated as a list of preset choices, but the user can
9#  type anything in the entry area.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005  Purdue Research Foundation
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require Itk
18package require BLT
19
20option add *Combobox.borderWidth 2 widgetDefault
21option add *Combobox.relief sunken widgetDefault
22option add *Combobox.width 10 widgetDefault
23option add *Combobox.editable yes widgetDefault
24option add *Combobox.textBackground white widgetDefault
25option add *Combobox.textForeground black widgetDefault
26option add *Combobox.disabledBackground white widgetDefault
27option add *Combobox.disabledForeground gray widgetDefault
28option add *Combobox.font -*-helvetica-medium-r-normal-*-12-* widgetDefault
29
30itcl::class Rappture::Combobox {
31    inherit itk::Widget
32
33    itk_option define -editable editable Editable ""
34    itk_option define -state state State "normal"
35    itk_option define -width width Width 0
36    itk_option define -disabledbackground disabledBackground DisabledBackground ""
37    itk_option define -disabledforeground disabledForeground DisabledForeground ""
38
39    constructor {args} { # defined below }
40
41    public method value {args}
42    public method translate {value {defValue ""}}
43    public method label {value}
44    public method current {}
45    public method choices {option args}
46
47    protected method _entry {option}
48    protected method _dropdown {option}
49    protected method _fixState {}
50
51    blt::bitmap define ComboboxArrow {
52        #define arrow_width 8
53        #define arrow_height 4
54        static unsigned char arrow_bits[] = {
55           0xfe, 0x7c, 0x38, 0x10};
56    }
57    private variable _value2label
58    private variable _label2value
59}
60                                                                               
61itk::usual Combobox {
62    keep -cursor -font
63    keep -foreground -background
64    keep -textforeground -textbackground
65    keep -selectbackground -selectforeground -selectborderwidth
66}
67
68# ----------------------------------------------------------------------
69# CONSTRUCTOR
70# ----------------------------------------------------------------------
71itcl::body Rappture::Combobox::constructor {args} {
72    itk_option add hull.borderwidth hull.relief
73
74    itk_component add button {
75        button $itk_interior.btn -bitmap ComboboxArrow -padx 0 \
76            -borderwidth 1 -relief raised -highlightthickness 0
77    } {
78        usual
79        ignore -highlightthickness -highlightbackground -highlightcolor
80        ignore -borderwidth -relief
81    }
82    pack $itk_component(button) -side right -fill y
83
84    itk_component add entry {
85        entry $itk_interior.entry -borderwidth 0 -relief flat
86    } {
87        usual
88        keep -width
89        rename -highlightbackground -textbackground textBackground Background
90        rename -background -textbackground textBackground Background
91        rename -foreground -textforeground textForeground Foreground
92        rename -disabledbackground -textbackground textBackground Background
93        rename -disabledforeground -textforeground textForeground Foreground
94        ignore -borderwidth -relief
95    }
96    pack $itk_component(entry) -side left -expand yes -fill both
97
98    bind $itk_component(entry) <KeyPress-Return> \
99        [itcl::code $this _entry apply]
100    bind $itk_component(entry) <ButtonPress> \
101        [itcl::code $this _entry click]
102
103    itk_component add ddlist {
104        Rappture::Dropdownlist $itk_component(button).ddlist \
105            -postcommand [itcl::code $this _dropdown post] \
106            -unpostcommand [itcl::code $this _dropdown unpost] \
107    }
108
109    bind $itk_component(ddlist) <<DropdownlistSelect>> \
110        [itcl::code $this _dropdown select]
111
112    $itk_component(button) configure -command \
113        [list $itk_component(ddlist) post $itk_component(hull) left]
114
115    eval itk_initialize $args
116}
117
118# ----------------------------------------------------------------------
119# USAGE: value ?<newval>?
120#
121# Clients use this to query/set the value for this widget.  With
122# no args, it returns the current value for the widget.  If the
123# <newval> is specified, it sets the value of the widget and
124# sends a <<Value>> event.
125# ----------------------------------------------------------------------
126itcl::body Rappture::Combobox::value {args} {
127    if {[llength $args] == 1} {
128        set newval [lindex $args 0]
129
130        $itk_component(entry) configure -state normal
131        $itk_component(entry) delete 0 end
132        $itk_component(entry) insert 0 $newval
133        if {!$itk_option(-editable)} {
134            $itk_component(entry) configure -state disabled
135        }
136
137        after 10 [list catch [list event generate $itk_component(hull) <<Value>>]]
138    } elseif {[llength $args] != 0} {
139        error "wrong # args: should be \"value ?newval?\""
140    }
141    return [$itk_component(entry) get]
142}
143
144# ----------------------------------------------------------------------
145# USAGE: translate <value>
146#
147# Clients use this to translate a value from the entry part of the
148# combobox to one of the underlying values in the combobox.  If the
149# <value> string matches one of the labels for the choices, this
150# method returns the corresponding value.  Otherwise, it returns "".
151# ----------------------------------------------------------------------
152itcl::body Rappture::Combobox::translate {value {defValue ""}} {
153    foreach {val label} [choices get -both] {
154        if {$label == $value} {
155            return $val
156        }
157    }
158    return $defValue
159}
160
161# ----------------------------------------------------------------------
162# USAGE: label <value>
163#
164# Clients use this to translate a value to a label.
165# ----------------------------------------------------------------------
166itcl::body Rappture::Combobox::label { myValue } {
167    foreach {val label} [choices get -both] {
168        if {$myValue == $val} {
169            return $label
170        }
171    }
172    return ""
173}
174
175# ----------------------------------------------------------------------
176# USAGE: getValue <value>
177#
178# Clients use this to translate a value to a label.
179# ----------------------------------------------------------------------
180itcl::body Rappture::Combobox::current {} {
181    set raw [$itk_component(entry) get]
182    set value [translate $raw "badValue"]
183    if { $value != "badValue" } {
184        return $value
185    }
186    return $raw
187}
188
189# ----------------------------------------------------------------------
190# USAGE: choices insert <pos> ?<value1> <label1> ...?
191# USAGE: choices delete <first> ?<last>?
192# USAGE: choices get ?-value|-label|-both? ?<index>?
193# USAGE: choices index <value>
194#
195# Clients use this to manipulate the list of choices in the drop-down
196# list.  Each choice is represented by a (computer-friendly) value
197# and its corresponding (human-friendly) label.  The "get" option
198# returns information about options on the list, including the value,
199# the label, or both.
200# ----------------------------------------------------------------------
201itcl::body Rappture::Combobox::choices {option args} {
202    eval $itk_component(ddlist) $option $args
203}
204
205# ----------------------------------------------------------------------
206# USAGE: _entry apply
207# USAGE: _entry click
208#
209# Used internally to handle the dropdown list for this combobox.  The
210# post/unpost options are invoked when the list is posted or unposted
211# to manage the relief of the controlling button.  The select option
212# is invoked whenever there is a selection from the list, to assign
213# the value back to the gauge.
214# ----------------------------------------------------------------------
215itcl::body Rappture::Combobox::_entry {option} {
216    switch -- $option {
217        apply {
218            if {$itk_option(-editable) && $itk_option(-state) == "normal"} {
219                event generate $itk_component(hull) <<Value>>
220            }
221        }
222        click {
223            if {!$itk_option(-editable) && $itk_option(-state) == "normal"} {
224                $itk_component(button) configure -relief sunken
225                update idletasks; after 100
226                $itk_component(button) configure -relief raised
227
228                $itk_component(ddlist) post $itk_component(hull) left
229            }
230        }
231        default {
232            error "bad option \"$option\": should be apply, click"
233        }
234    }
235}
236
237# ----------------------------------------------------------------------
238# USAGE: _dropdown post
239# USAGE: _dropdown unpost
240# USAGE: _dropdown select
241#
242# Used internally to handle the dropdown list for this combobox.  The
243# post/unpost options are invoked when the list is posted or unposted
244# to manage the relief of the controlling button.  The select option
245# is invoked whenever there is a selection from the list, to assign
246# the value back to the gauge.
247# ----------------------------------------------------------------------
248itcl::body Rappture::Combobox::_dropdown {option} {
249    switch -- $option {
250        post {
251            set value [$itk_component(entry) get]
252            set i [$itk_component(ddlist) index -label $value]
253            if {$i >= 0} {
254                $itk_component(ddlist) select clear 0 end
255                $itk_component(ddlist) select set $i
256            }
257        }
258        unpost {
259            if {$itk_option(-editable)} {
260                focus $itk_component(entry)
261            }
262        }
263        select {
264            set val [$itk_component(ddlist) current -label]
265            if {"" != $val} {
266                value $val
267            }
268        }
269        default {
270            error "bad option \"$option\": should be post, unpost, select"
271        }
272    }
273}
274
275# ----------------------------------------------------------------------
276# USAGE: _fixState
277#
278# Used internally to fix the widget state when the -editable/-state
279# options change.
280# ----------------------------------------------------------------------
281itcl::body Rappture::Combobox::_fixState {} {
282    if {$itk_option(-state) == "normal"} {
283        $itk_component(button) configure -state normal
284        $itk_component(entry) configure \
285            -background $itk_option(-textbackground) \
286            -foreground $itk_option(-textforeground) \
287            -disabledbackground $itk_option(-textbackground) \
288            -disabledforeground $itk_option(-textforeground)
289    } else {
290        $itk_component(button) configure -state disabled
291        $itk_component(entry) configure \
292            -background $itk_option(-disabledbackground) \
293            -foreground $itk_option(-disabledforeground) \
294            -disabledbackground $itk_option(-disabledbackground) \
295            -disabledforeground $itk_option(-disabledforeground)
296    }
297
298    if {$itk_option(-editable)} {
299        if {$itk_option(-state) == "normal"} {
300            $itk_component(entry) configure -state normal
301        } else {
302            $itk_component(entry) configure -state disabled
303        }
304    } else {
305        $itk_component(entry) configure -state disabled
306    }
307
308    if {!$itk_option(-editable) || $itk_option(-state) != "normal"} {
309        # can't keep focus here -- move it along to the next widget
310        if {[focus] == $itk_component(entry)} {
311            focus [tk_focusNext [focus]]
312        }
313    }
314}
315
316# ----------------------------------------------------------------------
317# CONFIGURATION OPTION: -editable
318# ----------------------------------------------------------------------
319itcl::configbody Rappture::Combobox::editable {
320    if {![string is boolean -strict $itk_option(-editable)]} {
321        error "bad value \"$itk_option(-editable)\": should be boolean"
322    }
323    _fixState
324}
325
326# ----------------------------------------------------------------------
327# CONFIGURATION OPTION: -state
328# ----------------------------------------------------------------------
329itcl::configbody Rappture::Combobox::state {
330    set valid {normal disabled}
331    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
332        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
333    }
334    _fixState
335}
Note: See TracBrowser for help on using the repository browser.