source: trunk/gui/scripts/dropdownlist.tcl @ 1277

Last change on this file since 1277 was 676, checked in by mmc, 17 years ago

Fixed all fonts to set pixelsize instead of pointsize, so that fonts in
the latest X distribution look right.

Added initial Rappture::bugreport::submit command for submitting bug
reports to nanoHUB.org. This isn't tied in yet, but it's a start.

File size: 10.7 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: dropdownlist - drop-down list of items
3#
4#  This is a drop-down listbox, which might be used in conjunction
5#  with a combobox.
6#
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2005  Purdue Research Foundation
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15
16option add *Dropdownlist.textBackground white widgetDefault
17option add *Dropdownlist.outline black widgetDefault
18option add *Dropdownlist.borderwidth 1 widgetDefault
19option add *Dropdownlist.relief flat widgetDefault
20option add *Dropdownlist.font \
21    -*-helvetica-medium-r-normal-*-12-* widgetDefault
22
23itcl::class Rappture::Dropdownlist {
24    inherit Rappture::Dropdown
25
26    constructor {args} { # defined below }
27
28    public method insert {pos args}
29    public method delete {first {last ""}}
30    public method index {args}
31    public method get {args}
32    public method size {}
33    public method select {option args}
34    public method current {{what -value}}
35
36    private variable _values ""  ;# values for all elems in list
37    private variable _labels ""  ;# labels for each of the _values
38
39    protected method _adjust {{widget ""}}
40    protected method _react {}
41}
42
43itk::usual Dropdownlist {
44    keep -background -outline -cursor -font
45}
46
47# ----------------------------------------------------------------------
48# CONSTRUCTOR
49# ----------------------------------------------------------------------
50itcl::body Rappture::Dropdownlist::constructor {args} {
51    itk_component add scroller {
52        Rappture::Scroller $itk_interior.sc \
53            -xscrollmode off -yscrollmode auto
54    }
55    pack $itk_component(scroller) -expand yes -fill both
56
57    itk_component add list {
58        listbox $itk_component(scroller).list \
59            -selectmode single -exportselection no \
60            -highlightthickness 0
61    } {
62        usual
63        rename -background -textbackground textBackground Background
64        rename -foreground -textforeground textForeground Foreground
65        ignore -highlightthickness -highlightbackground -highlightcolor
66        keep -relief
67    }
68    $itk_component(scroller) contents $itk_component(list)
69
70    # add bindings so the listbox can react to selections
71    bind RapptureDropdownlist-$this <ButtonRelease> [itcl::code $this _react]
72    bind RapptureDropdownlist-$this <KeyPress-Return> [itcl::code $this _react]
73    bind RapptureDropdownlist-$this <KeyPress-space> [itcl::code $this _react]
74    bind RapptureDropdownlist-$this <KeyPress-Escape> [itcl::code $this unpost]
75
76    set btags [bindtags $itk_component(list)]
77    set i [lsearch $btags [winfo class $itk_component(list)]]
78    if {$i < 0} {
79        set i end
80    }
81    set btags [linsert $btags [expr {$i+1}] RapptureDropdownlist-$this]
82    bindtags $itk_component(list) $btags
83
84    eval itk_initialize $args
85}
86
87# ----------------------------------------------------------------------
88# USAGE: insert <pos> ?<value1> <label1> <value2> <label2> ...?
89#
90# Inserts one or more values into this drop-down list.  Each value
91# has a keyword (computer-friendly value) and a label (human-friendly
92# value).  The labels appear in the listbox.  If the label is "--",
93# then the value is used as the label.
94# ----------------------------------------------------------------------
95itcl::body Rappture::Dropdownlist::insert {pos args} {
96    if {"end" == $pos} {
97        set pos [llength $_values]
98    } elseif {![string is integer -strict $pos]} {
99        error "bad index \"$pos\": should be integer or \"end\""
100    }
101
102    if {[llength $args] == 1} {
103        set args [lindex $args 0]
104    }
105    if {[llength $args] % 2 != 0} {
106        error "wrong # args: should be \"insert pos ?value label ...?\""
107    }
108
109    foreach {val label} $args {
110        if {$label == "--"} {
111            set label $val
112        }
113        set _values [linsert $_values $pos $val]
114        set _labels [linsert $_labels $pos $label]
115        $itk_component(list) insert $pos $label
116        incr pos
117    }
118}
119
120# ----------------------------------------------------------------------
121# USAGE: delete <first> ?<last>?
122#
123# Deletes one or more values from this drop-down list.  The indices
124# <first> and <last> should be integers from 0 or the keyword "end".
125# All values in the specified range are deleted.
126# ----------------------------------------------------------------------
127itcl::body Rappture::Dropdownlist::delete {first {last ""}} {
128    if {$last == ""} {
129        set last $first
130    }
131    if {![regexp {^[0-9]+|end$} $first]} {
132        error "bad index \"$first\": should be integer or \"end\""
133    }
134    if {![regexp {^[0-9]+|end$} $last]} {
135        error "bad index \"$last\": should be integer or \"end\""
136    }
137
138    set _values [lreplace $_values $first $last]
139    set _labels [lreplace $_labels $first $last]
140    $itk_component(list) delete $first $last
141}
142
143# ----------------------------------------------------------------------
144# USAGE: index ?-value|-label? <value>
145#
146# Returns the integer index for the position of the specified <value>
147# in the list.  Returns -1 if the value is not recognized.
148# ----------------------------------------------------------------------
149itcl::body Rappture::Dropdownlist::index {args} {
150    set format -value
151    set first [lindex $args 0]
152    if {$first == "-value" || $first == "-label"} {
153        set format $first
154        set args [lrange $args 1 end]
155    } elseif {[llength $args] > 1} {
156        error "bad option \"$first\": should be -value or -label"
157    }
158    if {[llength $args] != 1} {
159        error "wrong # args: should be \"index ?-value? ?-label? string\""
160    }
161    set value [lindex $args 0]
162
163    switch -- $format {
164        -value { return [lsearch -exact $_values $value] }
165        -label { return [lsearch -exact $_labels $value] }
166    }
167    return -1
168}
169
170# ----------------------------------------------------------------------
171# USAGE: get ?-value|-label|-both? ?<index>?
172#
173# Queries one or more values from the drop-down list.  With no args,
174# it returns a list of all values and labels in the list.  If the
175# index is specified, then it returns the value or label (or both)
176# for the specified index.
177# ----------------------------------------------------------------------
178itcl::body Rappture::Dropdownlist::get {args} {
179    set format -both
180    set first [lindex $args 0]
181    if {[string index $first 0] == "-"} {
182        set choices {-value -label -both}
183        if {[lsearch $choices $first] < 0} {
184            error "bad option \"$first\": should be [join [lsort $choices] {, }]"
185        }
186        set format $first
187        set args [lrange $args 1 end]
188    }
189
190    # return the whole list or just a single value
191    if {[llength $args] > 1} {
192        error "wrong # args: should be \"get ?-value|-label|-both? ?index?\""
193    }
194    if {[llength $args] == 0} {
195        set vlist $_values
196        set llist $_labels
197        set op lappend
198    } else {
199        set i [lindex $args 0]
200        set vlist [list [lindex $_values $i]]
201        set llist [list [lindex $_labels $i]]
202        set op set
203    }
204
205    # scan through and build up the return list
206    set rlist ""
207    foreach v $vlist l $llist {
208        switch -- $format {
209            -value { $op rlist $v }
210            -label { $op rlist $l }
211            -both  { lappend rlist $v $l }
212        }
213    }
214    return $rlist
215}
216
217# ----------------------------------------------------------------------
218# USAGE: size
219#
220# Returns the number of choices in this list.
221# ----------------------------------------------------------------------
222itcl::body Rappture::Dropdownlist::size {} {
223    return [llength $_values]
224}
225
226# ----------------------------------------------------------------------
227# USAGE: select <option> ?<arg> ...?
228#
229# Used to manipulate the selection in the listbox.  All options and
230# args are passed along to the underlying listbox.
231# ----------------------------------------------------------------------
232itcl::body Rappture::Dropdownlist::select {option args} {
233    if {$option == "set"} {
234        $itk_component(list) activate [lindex $args 0]
235    }
236    eval $itk_component(list) selection $option $args
237}
238
239# ----------------------------------------------------------------------
240# USAGE: current ?-value|-label|-both?
241#
242# Clients use this to query the current selection from the listbox.
243# Returns the value, label, or both, according to the option.
244# ----------------------------------------------------------------------
245itcl::body Rappture::Dropdownlist::current {{what -value}} {
246    set i [$itk_component(list) curselection]
247    if {$i != ""} {
248        switch -- $what {
249            -value { return [lindex $_values $i] }
250            -label { return [lindex $_labels $i] }
251            -both  { return [list [lindex $_values $i] [lindex $_labels $i]] }
252            default {
253                error "bad option \"$what\": should be -value, -label, -both"
254            }
255        }
256    }
257    return ""
258}
259
260# ----------------------------------------------------------------------
261# USAGE: _adjust ?<widget>?
262#
263# This method is invoked each time the dropdown is posted to adjust
264# its size and contents.  If the <widget> is specified, it is the
265# controlling widget.
266# ----------------------------------------------------------------------
267itcl::body Rappture::Dropdownlist::_adjust {{widget ""}} {
268    chain $widget
269
270    set fnt [$itk_component(list) cget -font]
271    set maxw 0
272    foreach str $_labels {
273        set w [font measure $fnt $str]
274        if {$w > $maxw} { set maxw $w }
275    }
276    if {$widget != ""} {
277        if {$maxw < [winfo width $widget]} { set maxw [winfo width $widget] }
278    }
279    set avg [font measure $fnt "n"]
280    $itk_component(list) configure -width [expr {round($maxw/double($avg))+1}]
281
282    if {$widget != ""} {
283        set y [expr {[winfo rooty $widget]+[winfo height $widget]}]
284        set h [font metrics $fnt -linespace]
285        set lines [expr {double([winfo screenheight $widget]-$y)/$h}]
286        if {[llength $_labels] < $lines} {
287            $itk_component(list) configure -height [llength $_labels]
288        } else {
289            $itk_component(list) configure -height 10
290        }
291    }
292
293    focus $itk_component(list)
294}
295
296# ----------------------------------------------------------------------
297# USAGE: _react
298#
299# Invoked automatically when the user has selected something from
300# the listbox.  Unposts the drop-down and generates an event letting
301# the client know that the selection has changed.
302# ----------------------------------------------------------------------
303itcl::body Rappture::Dropdownlist::_react {} {
304    unpost
305    event generate $itk_component(hull) <<DropdownlistSelect>>
306}
Note: See TracBrowser for help on using the repository browser.