source: trunk/gui/scripts/switch.tcl @ 438

Last change on this file since 438 was 437, checked in by mmc, 19 years ago

Added a new <enable> parameter to all inputs. Controls can now be
enabled/disabled based on the status of other controls. If a group
is disabled, it disappears entirely. If a parameter is enabled to
a hard-coded "off" value, then it acts like a hidden (secret)
parameter.

File size: 14.2 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: switch - on/off switch
3#
4#  This widget is used to control a (boolean) on/off value.  It shows
5#  a little light with the state of the switch, and offers a combobox
6#  to control the values.
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
15package require BLT
16
17option add *Switch.width 30 widgetDefault
18option add *Switch.height 20 widgetDefault
19option add *Switch.onColor red widgetDefault
20option add *Switch.offColor gray widgetDefault
21option add *Switch.valuePosition "right" widgetDefault
22option add *Switch.textBackground #cccccc widgetDefault
23
24itcl::class Rappture::Switch {
25    inherit itk::Widget
26
27    itk_option define -valueposition valuePosition ValuePosition ""
28    itk_option define -oncolor onColor Color ""
29    itk_option define -offcolor offColor Color ""
30    itk_option define -onimage onImage Image ""
31    itk_option define -offimage offImage Image ""
32    itk_option define -width width Width 0
33    itk_option define -height height Height 0
34    itk_option define -state state State "normal"
35
36    constructor {args} { # defined below }
37
38    public method value {args}
39
40    protected method _redraw {}
41    protected method _fixState {}
42    protected method _resize {}
43    protected method _hilite {comp state}
44    protected method _presets {option}
45
46    private variable _value "no"  ;# value for this widget
47
48    blt::bitmap define SwitchArrow {
49        #define arrow_width 9
50        #define arrow_height 4
51        static unsigned char arrow_bits[] = {
52           0x7f, 0x00, 0x3e, 0x00, 0x1c, 0x00, 0x08, 0x00};
53    }
54}
55                                                                               
56itk::usual Switch {
57    keep -cursor -font -foreground -background
58    keep -selectbackground -selectforeground -selectborderwidth
59}
60
61# ----------------------------------------------------------------------
62# CONSTRUCTOR
63# ----------------------------------------------------------------------
64itcl::body Rappture::Switch::constructor {args} {
65    itk_component add icon {
66        canvas $itk_interior.icon -borderwidth 0 -highlightthickness 0
67    } {
68        usual
69        ignore -highlightthickness -highlightbackground -highlightcolor
70    }
71    pack $itk_component(icon) -side left
72    bind $itk_component(icon) <Configure> [itcl::code $this _redraw]
73
74    itk_component add -protected vframe {
75        frame $itk_interior.vframe
76    }
77
78    itk_component add value {
79        label $itk_component(vframe).value -borderwidth 1 -width 7 \
80            -textvariable [itcl::scope _value]
81    } {
82        rename -background -textbackground textBackground Background
83    }
84    pack $itk_component(value) -side left -expand yes -fill both
85
86    bind $itk_component(value) <Enter> [itcl::code $this _hilite value on]
87    bind $itk_component(value) <Leave> [itcl::code $this _hilite value off]
88
89    itk_component add presets {
90        button $itk_component(vframe).psbtn -bitmap SwitchArrow \
91            -borderwidth 1 -highlightthickness 0 -relief flat
92    } {
93        usual
94        ignore -borderwidth -relief -highlightthickness
95        rename -background -textbackground textBackground Background
96    }
97
98    bind $itk_component(presets) <Enter> [itcl::code $this _hilite presets on]
99    bind $itk_component(presets) <Leave> [itcl::code $this _hilite presets off]
100
101    itk_component add presetlist {
102        Rappture::Dropdownlist $itk_component(presets).plist \
103            -postcommand [itcl::code $this _presets post] \
104            -unpostcommand [itcl::code $this _presets unpost] \
105    }
106    $itk_component(presetlist) insert end 1 yes 0 no
107
108    bind $itk_component(presetlist) <<DropdownlistSelect>> \
109        [itcl::code $this _presets select]
110
111    bind $itk_component(value) <ButtonPress> \
112        [itcl::code $this _presets dropdown]
113    $itk_component(presets) configure -command \
114        [itcl::code $this _presets dropdown]
115
116    eval itk_initialize $args
117}
118
119# ----------------------------------------------------------------------
120# USAGE: value ?-check? ?<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.  If the -check flag is included, the
126# new value is not actually applied, but just checked for correctness.
127# ----------------------------------------------------------------------
128itcl::body Rappture::Switch::value {args} {
129    set onlycheck 0
130    set i [lsearch -exact $args -check]
131    if {$i >= 0} {
132        set onlycheck 1
133        set args [lreplace $args $i $i]
134    }
135
136    if {[llength $args] == 1} {
137        set newval [lindex $args 0]
138        if {![string is boolean -strict $newval]} {
139            error "Should be a boolean value"
140        }
141        set newval [expr {($newval) ? "yes" : "no"}]
142
143        if {$onlycheck} {
144            return
145        }
146        set _value $newval
147        _fixState
148        event generate $itk_component(hull) <<Value>>
149
150    } elseif {[llength $args] != 0} {
151        error "wrong # args: should be \"value ?-check? ?newval?\""
152    }
153    return $_value
154}
155
156# ----------------------------------------------------------------------
157# USAGE: _redraw
158#
159# Used internally to redraw the gauge on the internal canvas based
160# on the current value and the size of the widget.  In this simple
161# base class, the gauge is drawn as a colored block, with an optional
162# image in the middle of it.
163# ----------------------------------------------------------------------
164itcl::body Rappture::Switch::_redraw {} {
165    set c $itk_component(icon)
166    set w [winfo width $c]
167    set h [winfo height $c]
168    set s [expr {($w < $h) ? $w : $h}]
169    set r [expr {0.5*$s-3}]
170    set wm [expr {0.5*$w}]
171    set hm [expr {0.5*$h}]
172
173    $c delete all
174
175    if {$itk_option(-onimage) == "" && $itk_option(-offimage) == ""} {
176        $c create oval [expr {$wm-$r+2}] [expr {$hm-$r+2}] \
177            [expr {$wm+$r+1}] [expr {$hm+$r+1}] -fill gray -outline ""
178        $c create oval [expr {$wm-$r}] [expr {$hm-$r}] \
179            [expr {$wm+$r+1}] [expr {$hm+$r+1}] -fill gray -outline ""
180        $c create oval [expr {$wm-$r}] [expr {$hm-$r}] \
181            [expr {$wm+$r}] [expr {$hm+$r}] -fill "" -outline black \
182            -tags main
183
184        $c create arc [expr {$wm-$r+2}] [expr {$hm-$r+2}] \
185            [expr {$wm+$r-2}] [expr {$hm+$r-2}] -fill "" -outline "" \
186            -start 90 -extent -60 -style arc -tags hilite
187
188        $c create arc [expr {$wm-$r+2}] [expr {$hm-$r+2}] \
189            [expr {$wm+$r-2}] [expr {$hm+$r-2}] -fill "" -outline "" \
190            -start -90 -extent -60 -style arc -tags lolite
191    } else {
192        $c create image [expr {0.5*$w}] [expr {0.5*$h}] \
193            -anchor center -image "" -tags bimage
194    }
195    _fixState
196}
197
198# ----------------------------------------------------------------------
199# USAGE: _fixState
200#
201# Used internally to fix the colors associated with the on/off
202# control.  This has an effect only if there is no -onimage or
203# -offimage.
204# ----------------------------------------------------------------------
205itcl::body Rappture::Switch::_fixState {} {
206    set c $itk_component(icon)
207
208    if {$_value} {
209        if {$itk_option(-onimage) != "" || $itk_option(-offimage) != ""} {
210            $c itemconfigure bimage -image $itk_option(-onimage)
211        } else {
212            set color $itk_option(-oncolor)
213            $c itemconfigure main -fill $color
214            $c itemconfigure hilite -outline \
215                [Rappture::color::brightness $color 1.0]
216            $c itemconfigure lolite -outline \
217                [Rappture::color::brightness $color -0.3]
218        }
219    } else {
220        if {$itk_option(-onimage) != "" || $itk_option(-offimage) != ""} {
221            $c itemconfigure bimage -image $itk_option(-offimage)
222        } else {
223            set color $itk_option(-offcolor)
224            $c itemconfigure main -fill $color
225            $c itemconfigure hilite -outline \
226                [Rappture::color::brightness $color 1.0]
227            $c itemconfigure lolite -outline \
228                [Rappture::color::brightness $color -0.3]
229        }
230    }
231}
232
233# ----------------------------------------------------------------------
234# USAGE: _resize
235#
236# Used internally to resize the internal canvas based on the -onimage
237# or -offimage options, or the size of the text.
238# ----------------------------------------------------------------------
239itcl::body Rappture::Switch::_resize {} {
240    if {$itk_option(-width) > 0} {
241        set w $itk_option(-width)
242    } else {
243        set w 0
244        foreach opt {-onimage -offimage} {
245            if {$itk_option($opt) != ""} {
246                set wi [expr {[image width $itk_option($opt)]+4}]
247                if {$wi > $w} { set w $wi }
248            }
249        }
250        if {$w <= 0} {
251            set w [winfo reqheight $itk_component(value)]
252        }
253    }
254
255    if {$itk_option(-height) > 0} {
256        set h $itk_option(-height)
257    } else {
258        set h 0
259        foreach opt {-onimage -offimage} {
260            if {$itk_option($opt) != ""} {
261                set hi [expr {[image height $itk_option($opt)]+4}]
262                if {$hi > $h} { set h $hi }
263            }
264        }
265        if {$h <= 0} {
266            set h [winfo reqheight $itk_component(value)]
267        }
268    }
269
270    $itk_component(icon) configure -width $w -height $h
271}
272
273# ----------------------------------------------------------------------
274# USAGE: _hilite <component> <state>
275#
276# Used internally to resize the internal canvas based on the -onimage
277# and -offimage options or the size of the text.
278# ----------------------------------------------------------------------
279itcl::body Rappture::Switch::_hilite {comp state} {
280    if {$itk_option(-state) == "disabled"} {
281        set state 0  ;# never hilite when disabled
282    }
283    if {$comp == "value"} {
284        if {$state} {
285            $itk_component(value) configure -relief solid
286        } else {
287            $itk_component(value) configure -relief flat
288        }
289        return
290    }
291    if {$state} {
292        $itk_component($comp) configure -relief solid
293    } else {
294        $itk_component($comp) configure -relief flat
295    }
296}
297
298# ----------------------------------------------------------------------
299# USAGE: _presets post
300# USAGE: _presets unpost
301# USAGE: _presets select
302#
303# Used internally to handle the list of presets for this gauge.  The
304# post/unpost options are invoked when the list is posted or unposted
305# to manage the relief of the controlling button.  The select option
306# is invoked whenever there is a selection from the list, to assign
307# the value back to the gauge.
308# ----------------------------------------------------------------------
309itcl::body Rappture::Switch::_presets {option} {
310    if {$itk_option(-state) != "normal"} {
311        return  ;# disabled? then bail out!
312    }
313    switch -- $option {
314        dropdown {
315            $itk_component(presetlist) post $itk_component(vframe) left
316        }
317        post {
318            set i [$itk_component(presetlist) index $_value]
319            if {$i >= 0} {
320                $itk_component(presetlist) select clear 0 end
321                $itk_component(presetlist) select set $i
322            }
323            after 10 [list $itk_component(presets) configure -relief sunken]
324        }
325        unpost {
326            $itk_component(presets) configure -relief flat
327        }
328        select {
329            set val [$itk_component(presetlist) current]
330            if {"" != $val} {
331                value $val
332            }
333        }
334        default {
335            error "bad option \"$option\": should be dropdown, post, unpost, select"
336        }
337    }
338}
339
340# ----------------------------------------------------------------------
341# CONFIGURATION OPTION: -onimage
342# ----------------------------------------------------------------------
343itcl::configbody Rappture::Switch::onimage {
344    if {$itk_option(-onimage) != ""
345          && [catch {image width $itk_option(-onimage)}]} {
346        error "bad value \"$itk_option(-onimage)\": should be Tk image"
347    }
348    _resize
349
350    if {$_value} {
351        # if the off state? then redraw to show this change
352        _redraw
353    }
354}
355
356# ----------------------------------------------------------------------
357# CONFIGURATION OPTION: -offimage
358# ----------------------------------------------------------------------
359itcl::configbody Rappture::Switch::offimage {
360    if {$itk_option(-offimage) != ""
361          && [catch {image width $itk_option(-offimage)}]} {
362        error "bad value \"$itk_option(-offimage)\": should be Tk image"
363    }
364    _resize
365
366    if {!$_value} {
367        # if the off state? then redraw to show this change
368        _redraw
369    }
370}
371
372# ----------------------------------------------------------------------
373# CONFIGURATION OPTION: -state
374# ----------------------------------------------------------------------
375itcl::configbody Rappture::Switch::state {
376    set valid {normal disabled}
377    if {[lsearch -exact $valid $itk_option(-state)] < 0} {
378        error "bad value \"$itk_option(-state)\": should be [join $valid {, }]"
379    }
380    $itk_component(value) configure -state $itk_option(-state)
381    $itk_component(presets) configure -state $itk_option(-state)
382}
383
384# ----------------------------------------------------------------------
385# CONFIGURATION OPTION: -valueposition
386# ----------------------------------------------------------------------
387itcl::configbody Rappture::Switch::valueposition {
388    array set side2anchor {
389        left   e
390        right  w
391        top    s
392        bottom n
393    }
394    set pos $itk_option(-valueposition)
395    if {![info exists side2anchor($pos)]} {
396        error "bad value \"$pos\": should be [join [lsort [array names side2anchor]] {, }]"
397    }
398    pack $itk_component(vframe) -before $itk_component(icon) \
399        -side $pos -expand yes -fill both -ipadx 2
400    $itk_component(value) configure -anchor $side2anchor($pos)
401
402    set s [expr {($pos == "left") ? "left" : "right"}]
403    pack $itk_component(presets) -before $itk_component(value) \
404        -side $s -fill y
405}
Note: See TracBrowser for help on using the repository browser.