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

Last change on this file since 116 was 115, checked in by mmc, 19 years ago

Updated all copyright notices.

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