source: branches/uq/gui/scripts/combobox.tcl @ 5679

Last change on this file since 5679 was 5679, checked in by ldelgass, 9 years ago

Full merge 1.3 branch to uq branch to sync. Fixed partial subdirectory merge
by removing mergeinfo from lang/python/Rappture directory.

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