source: branches/r9/gui/scripts/sequencedial.tcl @ 4919

Last change on this file since 4919 was 3656, checked in by gah, 11 years ago

fix assorted automatic tickets: bad data in curve, more trim space, move image creation before errors in constructor

File size: 29.0 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: Sequencedial - selector, like the dial on a car radio
4#
5#  This widget looks like the dial on an old-fashioned car radio.
6#  It draws a series of values along an axis, and allows a selector
7#  to move back and forth to select the values.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16
17option add *SequenceDial.thickness 10 widgetDefault
18option add *SequenceDial.length 2i widgetDefault
19option add *SequenceDial.knobImage knob widgetDefault
20option add *SequenceDial.knobPosition n@middle widgetDefault
21option add *SequenceDial.dialOutlineColor black widgetDefault
22option add *SequenceDial.dialFillColor white widgetDefault
23option add *SequenceDial.lineColor gray widgetDefault
24option add *SequenceDial.activeLineColor black widgetDefault
25option add *SequenceDial.padding 0 widgetDefault
26option add *SequenceDial.valueWidth 10 widgetDefault
27option add *SequenceDial.valuePadding 0.1 widgetDefault
28option add *SequenceDial.foreground black widgetDefault
29option add *SequenceDial.font \
30    -*-helvetica-medium-r-normal-*-12-* widgetDefault
31
32itcl::class Rappture::SequenceDial {
33    inherit itk::Widget
34
35    itk_option define -min min Min ""
36    itk_option define -max max Max ""
37    itk_option define -variable variable Variable ""
38
39    itk_option define -thickness thickness Thickness 0
40    itk_option define -length length Length 0
41    itk_option define -padding padding Padding 0
42
43    itk_option define -foreground foreground Foreground "black"
44    itk_option define -dialoutlinecolor dialOutlineColor Color "black"
45    itk_option define -dialfillcolor dialFillColor Color "white"
46    itk_option define -dialprogresscolor dialProgressColor Color ""
47    itk_option define -linecolor lineColor Color "black"
48    itk_option define -activelinecolor activeLineColor Color "black"
49    itk_option define -knobimage knobImage KnobImage ""
50    itk_option define -knobposition knobPosition KnobPosition ""
51
52    itk_option define -font font Font ""
53    itk_option define -valuewidth valueWidth ValueWidth 0
54    itk_option define -valuepadding valuePadding ValuePadding 0
55
56    itk_option define -interactcommand interactCommand InteractCommand ""
57
58
59    constructor {args} { # defined below }
60    destructor { # defined below }
61
62    public method add {label {value ""}}
63    public method clear {}
64    public method get {args}
65    public method current {args}
66    public method color {value}
67                                                                               
68    protected method _setCurrent {val}
69    protected method _redraw {}
70    protected method _click {x y}
71    protected method _navigate {offset}
72    protected method _limits {}
73    protected method _findLabel {str}
74    protected method _fixSize {}
75    protected method _fixValue {args}
76    protected method _doInteract {}
77
78    private method EventuallyRedraw {}
79    private variable _redrawPending 0
80    private variable _afterId -1
81    private variable _values ""       ;# list of all values on the dial
82    private variable _val2label       ;# maps value => string label(s)
83    private variable _current ""      ;# current value (where pointer is)
84    private variable _variable ""     ;# variable associated with -variable
85
86    private variable _knob ""         ;# image for knob
87    private variable _spectrum ""     ;# width allocated for values
88    private variable _activecolor ""  ;# width allocated for values
89    private variable _vwidth 0        ;# width allocated for values
90}
91                                                                               
92itk::usual SequenceDial {
93    keep -background -foreground -cursor -font
94}
95
96# ----------------------------------------------------------------------
97# CONSTRUCTOR
98# ----------------------------------------------------------------------
99itcl::body Rappture::SequenceDial::constructor {args} {
100    itk_component add dial {
101        canvas $itk_interior.dial
102    }
103    pack $itk_component(dial) -expand yes -fill both
104    bind $itk_component(dial) <Configure> [itcl::code $this EventuallyRedraw]
105
106#    bind $itk_component(dial) <ButtonPress-1> [itcl::code $this _click %x %y]
107    bind $itk_component(dial) <B1-Motion> [itcl::code $this _click %x %y]
108#    bind $itk_component(dial) <ButtonRelease-1> [itcl::code $this _click %x %y]
109
110    bind $itk_component(hull) <KeyPress-Left> [itcl::code $this _navigate -1]
111    bind $itk_component(hull) <KeyPress-Right> [itcl::code $this _navigate 1]
112
113    eval itk_initialize $args
114
115    _fixSize
116}
117
118# ----------------------------------------------------------------------
119# DESTRUCTOR
120# ----------------------------------------------------------------------
121itcl::body Rappture::SequenceDial::destructor {} {
122    configure -variable ""  ;# remove variable trace
123    after cancel $_afterId
124}
125
126# ----------------------------------------------------------------------
127# USAGE: add <label> ?<value>?
128#
129# Clients use this to add new values to the dial.  Values are always
130# sorted in order along the dial.  If the value is not specified,
131# then it is created automatically based on the number of elements
132# on the dial.
133# ----------------------------------------------------------------------
134itcl::body Rappture::SequenceDial::add {label {value ""}} {
135    if {"" == $value} {
136        set value [llength $_values]
137    }
138
139    # Add this value if we've never see it before
140    if {[lsearch -real $_values $value] < 0} {
141        lappend _values $value
142        set _values [lsort -real $_values]
143    }
144
145    # Keep all equivalent strings for this value.
146    # That way, we can later select either "1e18" or "1.0e+18"
147    lappend _val2label($value) $label
148
149    if {"" == $_current} {
150        _setCurrent $value
151    }
152    EventuallyRedraw
153}
154
155itcl::body Rappture::SequenceDial::EventuallyRedraw {} {
156    if { !$_redrawPending } {
157        set _afterId [after 150 [itcl::code $this _redraw]]
158        event generate $itk_component(hull) <<Value>>
159        set _resizePending 1
160    }
161}
162
163# ----------------------------------------------------------------------
164# USAGE: clear
165#
166# Clients use this to remove all existing values from the dial.
167# ----------------------------------------------------------------------
168itcl::body Rappture::SequenceDial::clear {} {
169    set _values ""
170    _setCurrent ""
171    catch {unset _val2label}
172
173    EventuallyRedraw
174}
175
176# ----------------------------------------------------------------------
177# USAGE: get ?-format what? ?current|@index?
178#
179# Clients use this to query values within this radiodial.  With no
180# args, it returns a list of all values stored in the widget.  The
181# "current" arg requests only the current value on the radiodial.
182# The @index syntax can be used to request a particular value at
183# an index within the list of values.
184#
185# By default, this method returns the label for each value.  The
186# format option can be used to request the label, the value, or
187# both.
188# ----------------------------------------------------------------------
189itcl::body Rappture::SequenceDial::get {args} {
190    Rappture::getopts args params {
191        value -format "label"
192    }
193    if {[llength $args] > 1} {
194        error "wrong # args: should be \"get ?-format f? ?current|@index\""
195    }
196    set index [lindex $args 0]
197    if {"" == $index} {
198        set ilist ""
199        for {set i 0} {$i < [llength $_values]} {incr i} {
200            lappend ilist $i
201        }
202    } elseif {"current" == $index} {
203        set ilist [lsearch -exact $_values $_current]
204        if {$ilist < 0} {
205            set ilist ""
206        }
207    } elseif {[regexp {^@([0-9]+|end)$} $index match i]} {
208        set ilist $i
209    }
210    if {[llength $ilist] == 1} {
211        set op set
212    } else {
213        set op lappend
214    }
215
216    set rlist ""
217    foreach i $ilist {
218        switch -- $params(-format) {
219            label {
220                set v [lindex $_values $i]
221                $op rlist [lindex $_val2label($v) 0]
222            }
223            value {
224                $op rlist [lindex $_values $i]
225            }
226            position {
227                foreach {min max} [_limits] break
228                set v [lindex $_values $i]
229                set frac [expr {double($v-$min)/($max-$min)}]
230                $op rlist $frac
231            }
232            all {
233                set v [lindex $_values $i]
234                foreach {min max} [_limits] break
235                set frac [expr {double($v-$min)/($max-$min)}]
236                set l [lindex $_val2label($v) 0]
237                $op rlist [list $l $v $frac]
238            }
239            default {
240                error "bad value \"$v\": should be label, value, position, all"
241            }
242        }
243    }
244    return $rlist
245}
246
247# ----------------------------------------------------------------------
248# USAGE: current ?<newval>?
249#
250# Clients use this to get/set the current value for this widget.
251# ----------------------------------------------------------------------
252itcl::body Rappture::SequenceDial::current {args} {
253    if {[llength $args] == 0} {
254        return $_current
255    } elseif {[llength $args] == 1} {
256        set newval [lindex $args 0]
257        set n [_findLabel $newval]
258
259        # Don't use expr (?:) because it evaluates the resulting string.
260        # For example, it changes -0.020 to -0.02.
261        if { $n >= 0 } {
262            set rawval [lindex $_values $n]
263        } else {
264            set rawval ""
265        }
266        _setCurrent $rawval
267
268        EventuallyRedraw
269        event generate $itk_component(hull) <<Value>>
270
271        return $_current
272    }
273    error "wrong # args: should be \"current ?newval?\""
274}
275
276# ----------------------------------------------------------------------
277# USAGE: color <value>
278#
279# Clients use this to query the color associated with a <value>
280# along the dial.
281# ----------------------------------------------------------------------
282itcl::body Rappture::SequenceDial::color {value} {
283    _findLabel $value  ;# make sure this label is recognized
284
285    if {"" != $_spectrum} {
286        foreach {min max} [_limits] break
287        set frac [expr {double($value-$min)/($max-$min)}]
288        set color [$_spectrum get $frac]
289    } else {
290        if {$value == $_current} {
291            set color $_activecolor
292        } else {
293            set color $itk_option(-linecolor)
294        }
295    }
296    return $color
297}
298
299# ----------------------------------------------------------------------
300# USAGE: _setCurrent <value>
301#
302# Called automatically whenever the widget changes size to redraw
303# all elements within it.
304# ----------------------------------------------------------------------
305itcl::body Rappture::SequenceDial::_setCurrent {value} {
306    set _current $value
307    if {"" != $_variable} {
308        upvar #0 $_variable var
309        if {[info exists _val2label($value)]} {
310            set var [lindex $_val2label($value) 0]
311        } else {
312            set var $value
313        }
314    }
315}
316
317# ----------------------------------------------------------------------
318# USAGE: _redraw
319#
320# Called automatically whenever the widget changes size to redraw
321# all elements within it.
322# ----------------------------------------------------------------------
323itcl::body Rappture::SequenceDial::_redraw {} {
324
325    set _redrawPending 0
326
327    set c $itk_component(dial)
328    $c delete all
329
330    set fg $itk_option(-foreground)
331
332    set w [winfo width $c]
333    set h [winfo height $c]
334    set p [winfo pixels $c $itk_option(-padding)]
335    set t [expr {$itk_option(-thickness)+1}]
336    set y1 [expr {$h-1}]
337
338    if {"" != $_knob} {
339        set kw [image width $_knob]
340        set kh [image height $_knob]
341
342        switch -- $itk_option(-knobposition) {
343            n@top - nw@top - ne@top {
344                set extra [expr {$t-$kh}]
345                if {$extra < 0} {set extra 0}
346                set y1 [expr {$h-$extra-1}]
347            }
348            n@middle - nw@middle - ne@middle {
349                set extra [expr {int(ceil($kh-0.5*$t))}]
350                if {$extra < 0} {set extra 0}
351                set y1 [expr {$h-$extra-1}]
352            }
353            n@bottom - nw@bottom - ne@bottom {
354                set y1 [expr {$h-$kh-1}]
355            }
356
357            e@top - w@top - center@top -
358            e@bottom - w@bottom - center@bottom {
359                set extra [expr {int(ceil(0.5*$kh))}]
360                set y1 [expr {$h-$extra-1}]
361            }
362            e@middle - w@middle - center@middle {
363                set extra [expr {int(ceil(0.5*($kh-$t)))}]
364                if {$extra < 0} {set extra 0}
365                set y1 [expr {$h-$extra-1}]
366            }
367
368            s@top - sw@top - se@top -
369            s@middle - sw@middle - se@middle -
370            s@bottom - sw@bottom - se@bottom {
371                set y1 [expr {$h-2}]
372            }
373        }
374    }
375    set y0 [expr {$y1-$t}]
376    set x0 [expr {$p+1}]
377    set x1 [expr {$w-$_vwidth-$p-4}]
378    foreach {min max} [_limits] break
379
380    # draw the background rectangle
381    $c create rectangle $x0 $y0 $x1 $y1 \
382        -outline $itk_option(-dialoutlinecolor) \
383        -fill $itk_option(-dialfillcolor) -tags "range"
384
385    # draw the optional progress bar, from start to current
386    if {"" != $itk_option(-dialprogresscolor)
387          && [llength $_values] > 0 && "" != $_current} {
388        if {$max != $min} {
389            set frac [expr {double($_current-$min)/($max-$min)}]
390        } else {
391            set frac 0.
392        }
393        set xx1 [expr {$frac*($x1-$x0) + $x0}]
394        $c create rectangle [expr {$x0+1}] [expr {$y0+3}] $xx1 [expr {$y1-2}] \
395            -outline "" -fill $itk_option(-dialprogresscolor)
396    }
397
398    $c create rectangle $x0 $y0 $x1 $y1 -outline "" -fill "" -tags "range"
399
400    # draw lines for all values
401    if {$max > $min} {
402        foreach v $_values {
403            set frac [expr {double($v-$min)/($max-$min)}]
404            if {"" != $_spectrum} {
405                set color [$_spectrum get $frac]
406            } else {
407                if {$v == $_current} {
408                    set color $_activecolor
409                } else {
410                    set color $itk_option(-linecolor)
411                }
412            }
413            set thick [expr {($v == $_current) ? 3 : 1}]
414
415            if {"" != $color} {
416                set x [expr {$frac*($x1-$x0) + $x0}]
417                $c create line $x [expr {$y0+1}] $x $y1 \
418                    -fill $color -width $thick
419            }
420        }
421
422        if {"" != $_current} {
423            set x [expr {double($_current-$min)/($max-$min)*($x1-$x0) + $x0}]
424            regexp {([nsew]+|center)@} $itk_option(-knobposition) match anchor
425            switch -glob -- $itk_option(-knobposition) {
426                *@top    { set kpos $y0 }
427                *@middle { set kpos [expr {int(ceil(0.5*($y1+$y0)))}] }
428                *@bottom { set kpos $y1 }
429            }
430            $c create image $x $kpos -anchor $anchor -image $_knob -tags "knob"
431        }
432    }
433
434    $c bind range <ButtonPress-1> [itcl::code $this _click %x %y]
435    $c bind range <ButtonRelease-1> [itcl::code $this _click %x %y]
436
437    # Only need release event for knob.
438    $c bind knob <ButtonRelease-1> [itcl::code $this _click %x %y]
439
440    # if the -valuewidth is > 0, then make room for the value
441    set vw $itk_option(-valuewidth)
442    if {$vw > 0 && "" != $_current} {
443        set str [lindex $_val2label($_current) 0]
444        if {[string length $str] >= $vw} {
445            set str "[string range $str 0 [expr {$vw-3}]]..."
446        }
447
448        set dy [expr {([font metrics $itk_option(-font) -linespace]
449                        - [font metrics $itk_option(-font) -ascent])/2}]
450
451        set id [$c create text [expr {$x1+4}] [expr {($y1+$y0)/2+$dy}] \
452            -anchor w -text $str -font $itk_option(-font) -foreground $fg]
453        foreach {x0 y0 x1 y1} [$c bbox $id] break
454        set x0 [expr {$x0 + 10}]
455
456        # set up a tooltip so you can mouse over truncated values
457        Rappture::Tooltip::text $c [lindex $_val2label($_current) 0]
458        $c bind $id <Enter> \
459            [list ::Rappture::Tooltip::tooltip pending %W +$x0,$y1]
460        $c bind $id <Leave> \
461            [list ::Rappture::Tooltip::tooltip cancel]
462        $c bind $id <ButtonPress> \
463            [list ::Rappture::Tooltip::tooltip cancel]
464        $c bind $id <KeyPress> \
465            [list ::Rappture::Tooltip::tooltip cancel]
466    }
467}
468
469# ----------------------------------------------------------------------
470# USAGE: _click <x> <y>
471#
472# Called automatically whenever the user clicks or drags on the widget
473# to select a value.  Moves the current value to the one nearest the
474# click point.  If the value actually changes, it generates a <<Value>>
475# event to notify clients.
476# ----------------------------------------------------------------------
477itcl::body Rappture::SequenceDial::_click {x y} {
478    set c $itk_component(dial)
479    set w [winfo width $c]
480    set h [winfo height $c]
481    set x0 1
482    set x1 [expr {$w-$_vwidth-4}]
483
484    focus $itk_component(hull)
485
486    # draw lines for all values
487    foreach {min max} [_limits] break
488    if {$max > $min && $x >= $x0 && $x <= $x1} {
489        set dmin $w
490        set xnearest 0
491        set vnearest ""
492        foreach v $_values {
493            set xv [expr {double($v-$min)/($max-$min)*($x1-$x0) + $x0}]
494            if {abs($xv-$x) < $dmin} {
495                set dmin [expr {abs($xv-$x)}]
496                set xnearest $xv
497                set vnearest $v
498            }
499        }
500
501        if {$vnearest != $_current} {
502            _setCurrent $vnearest
503            EventuallyRedraw
504
505            #event generate $itk_component(hull) <<Value>>
506            _doInteract
507        }
508    }
509}
510
511# ----------------------------------------------------------------------
512# USAGE: _navigate <offset>
513#
514# Called automatically whenever the user presses left/right keys
515# to nudge the current value left or right by some <offset>.  If the
516# value actually changes, it generates a <<Value>> event to notify
517# clients.
518# ----------------------------------------------------------------------
519itcl::body Rappture::SequenceDial::_navigate {offset} {
520    set index [lsearch -exact $_values $_current]
521    if {$index >= 0} {
522        incr index $offset
523        if {$index >= [llength $_values]} {
524            set index [expr {[llength $_values]-1}]
525        } elseif {$index < 0} {
526            set index 0
527        }
528
529        set newval [lindex $_values $index]
530        if {$newval != $_current} {
531            _setCurrent $newval
532            EventuallyRedraw
533
534            event generate $itk_component(hull) <<Value>>
535            _doInteract
536        }
537    }
538}
539
540# ----------------------------------------------------------------------
541# USAGE: _limits
542#
543# Used internally to compute the overall min/max limits for the
544# radio dial.  Returns {min max}, representing the end values for
545# the scale.
546# ----------------------------------------------------------------------
547itcl::body Rappture::SequenceDial::_limits {} {
548    if {[llength $_values] == 0} {
549        set min 0
550        set max 0
551    } else {
552        set min [lindex $_values 0]
553        set max $min
554        foreach v [lrange $_values 1 end] {
555            if {$v < $min} { set min $v }
556            if {$v > $max} { set max $v }
557        }
558        set del [expr {$max-$min}]
559        set min [expr {$min-$itk_option(-valuepadding)*$del}]
560        set max [expr {$max+$itk_option(-valuepadding)*$del}]
561    }
562
563    if {"" != $itk_option(-min)} {
564        set min $itk_option(-min)
565    }
566    if {"" != $itk_option(-max)} {
567        set max $itk_option(-max)
568    }
569    return [list $min $max]
570}
571
572# ----------------------------------------------------------------------
573# USAGE: _findLabel <string>
574#
575# Used internally to search for the given <string> label among the
576# known values.  Returns an index into the _values list, or throws
577# an error if the string is not recognized.  Given the null string,
578# it returns -1, indicating that the value is not in _values, but
579# it is valid.
580# ----------------------------------------------------------------------
581itcl::body Rappture::SequenceDial::_findLabel {str} {
582    if {"" == $str} {
583        return -1
584    }
585    for {set nv 0} {$nv < [llength $_values]} {incr nv} {
586        set v [lindex $_values $nv]
587        if {[lsearch -exact $_val2label($v) $str] >= 0} {
588            return $nv
589        }
590    }
591
592    # didn't match -- build a return string of possible values
593    set labels ""
594    foreach vlist $_values {
595        foreach v $vlist {
596            lappend labels "\"$_val2label($v)\""
597        }
598    }
599    error "bad value \"$str\": should be one of [join $labels ,]"
600}
601
602# ----------------------------------------------------------------------
603# USAGE: _fixSize
604#
605# Used internally to compute the overall size of the widget based
606# on the -thickness and -length options.
607# ----------------------------------------------------------------------
608itcl::body Rappture::SequenceDial::_fixSize {} {
609    set h [winfo pixels $itk_component(hull) $itk_option(-thickness)]
610
611    if {"" != $_knob} {
612        set kh [image height $_knob]
613
614        switch -- $itk_option(-knobposition) {
615            n@top - nw@top - ne@top -
616            s@bottom - sw@bottom - se@bottom {
617                if {$kh > $h} { set h $kh }
618            }
619            n@middle - nw@middle - ne@middle -
620            s@middle - sw@middle - se@middle {
621                set h [expr {int(ceil(0.5*$h + $kh))}]
622            }
623            n@bottom - nw@bottom - ne@bottom -
624            s@top - sw@top - se@top {
625                set h [expr {$h + $kh}]
626            }
627            e@middle - w@middle - center@middle {
628                set h [expr {(($h > $kh) ? $h : $kh) + 1}]
629            }
630            n@middle - ne@middle - nw@middle -
631            s@middle - se@middle - sw@middle {
632                set extra [expr {int(ceil($kh-0.5*$h))}]
633                if {$extra < 0} { set extra 0 }
634                set h [expr {$h+$extra}]
635            }
636        }
637    }
638    incr h 1
639
640    set w [winfo pixels $itk_component(hull) $itk_option(-length)]
641
642    # if the -valuewidth is > 0, then make room for the value
643    if {$itk_option(-valuewidth) > 0} {
644        set charw [font measure $itk_option(-font) "n"]
645        set _vwidth [expr {$itk_option(-valuewidth)*$charw}]
646        set w [expr {$w+$_vwidth+4}]
647    } else {
648        set _vwidth 0
649    }
650
651    $itk_component(dial) configure -width $w -height $h
652}
653
654# ----------------------------------------------------------------------
655# USAGE: _fixValue ?<name1> <name2> <op>?
656#
657# Invoked automatically whenever the -variable associated with this
658# widget is modified.  Copies the value to the current settings for
659# the widget.
660# ----------------------------------------------------------------------
661itcl::body Rappture::SequenceDial::_fixValue {args} {
662    if {"" == $itk_option(-variable)} {
663        return
664    }
665    upvar #0 $itk_option(-variable) var
666
667    set newval $var
668    set n [_findLabel $newval]
669    set rawval [expr {($n >= 0) ? [lindex $_values $n] : ""}]
670    set _current $rawval  ;# set current directly, so we don't trigger again
671
672    EventuallyRedraw
673    event generate $itk_component(hull) <<Value>>
674}
675
676# ----------------------------------------------------------------------
677# USAGE: _doInteract
678#
679# Used internally to call the -interactcommand code whenever the user
680# changes the value of the widget.  This is different from the <<Value>>
681# event, which gets invoked whenever the value changes for any reason,
682# including programmatic changes.  If there is no command code, then
683# this does nothing.
684# ----------------------------------------------------------------------
685itcl::body Rappture::SequenceDial::_doInteract {} {
686    if {[string length $itk_option(-interactcommand)] > 0} {
687        uplevel #0 $itk_option(-interactcommand)
688    }
689}
690
691# ----------------------------------------------------------------------
692# CONFIGURE: -thickness
693# ----------------------------------------------------------------------
694itcl::configbody Rappture::SequenceDial::thickness {
695    _fixSize
696}
697
698# ----------------------------------------------------------------------
699# CONFIGURE: -length
700# ----------------------------------------------------------------------
701itcl::configbody Rappture::SequenceDial::length {
702    _fixSize
703}
704
705# ----------------------------------------------------------------------
706# CONFIGURE: -font
707# ----------------------------------------------------------------------
708itcl::configbody Rappture::SequenceDial::font {
709    _fixSize
710}
711
712# ----------------------------------------------------------------------
713# CONFIGURE: -valuewidth
714# ----------------------------------------------------------------------
715itcl::configbody Rappture::SequenceDial::valuewidth {
716    if {![string is integer $itk_option(-valuewidth)]} {
717        error "bad value \"$itk_option(-valuewidth)\": should be integer"
718    }
719    _fixSize
720    EventuallyRedraw
721}
722
723# ----------------------------------------------------------------------
724# CONFIGURE: -foreground
725# ----------------------------------------------------------------------
726itcl::configbody Rappture::SequenceDial::foreground {
727    EventuallyRedraw
728}
729
730# ----------------------------------------------------------------------
731# CONFIGURE: -dialoutlinecolor
732# ----------------------------------------------------------------------
733itcl::configbody Rappture::SequenceDial::dialoutlinecolor {
734    EventuallyRedraw
735}
736
737# ----------------------------------------------------------------------
738# CONFIGURE: -dialfillcolor
739# ----------------------------------------------------------------------
740itcl::configbody Rappture::SequenceDial::dialfillcolor {
741    EventuallyRedraw
742}
743
744# ----------------------------------------------------------------------
745# CONFIGURE: -dialprogresscolor
746# ----------------------------------------------------------------------
747itcl::configbody Rappture::SequenceDial::dialprogresscolor {
748    EventuallyRedraw
749}
750
751# ----------------------------------------------------------------------
752# CONFIGURE: -linecolor
753# ----------------------------------------------------------------------
754itcl::configbody Rappture::SequenceDial::linecolor {
755    EventuallyRedraw
756}
757
758# ----------------------------------------------------------------------
759# CONFIGURE: -activelinecolor
760# ----------------------------------------------------------------------
761itcl::configbody Rappture::SequenceDial::activelinecolor {
762    set val $itk_option(-activelinecolor)
763    if {[catch {$val isa ::Rappture::Spectrum} valid] == 0 && $valid} {
764        set _spectrum $val
765        set _activecolor ""
766    } elseif {[catch {winfo rgb $itk_component(hull) $val}] == 0} {
767        set _spectrum ""
768        set _activecolor $val
769    } elseif {"" != $val} {
770        error "bad value \"$val\": should be Spectrum object or color"
771    }
772    EventuallyRedraw
773}
774
775# ----------------------------------------------------------------------
776# CONFIGURE: -knobimage
777# ----------------------------------------------------------------------
778itcl::configbody Rappture::SequenceDial::knobimage {
779    if {[regexp {^image[0-9]+$} $itk_option(-knobimage)]} {
780        set _knob $itk_option(-knobimage)
781    } elseif {"" != $itk_option(-knobimage)} {
782        set _knob [Rappture::icon $itk_option(-knobimage)]
783    } else {
784        set _knob ""
785    }
786    _fixSize
787
788    EventuallyRedraw
789}
790
791# ----------------------------------------------------------------------
792# CONFIGURE: -knobposition
793# ----------------------------------------------------------------------
794itcl::configbody Rappture::SequenceDial::knobposition {
795    if {![regexp {^([nsew]+|center)@(top|middle|bottom)$} $itk_option(-knobposition)]} {
796        error "bad value \"$itk_option(-knobposition)\": should be anchor@top|middle|bottom"
797    }
798    _fixSize
799
800    EventuallyRedraw
801}
802
803# ----------------------------------------------------------------------
804# CONFIGURE: -padding
805# This adds padding on left/right side of dial background.
806# ----------------------------------------------------------------------
807itcl::configbody Rappture::SequenceDial::padding {
808    if {[catch {winfo pixels $itk_component(hull) $itk_option(-padding)}]} {
809        error "bad value \"$itk_option(-padding)\": should be size in pixels"
810    }
811}
812
813# ----------------------------------------------------------------------
814# CONFIGURE: -valuepadding
815# This shifts min/max limits in by a fraction of the overall size.
816# ----------------------------------------------------------------------
817itcl::configbody Rappture::SequenceDial::valuepadding {
818    if {![string is double $itk_option(-valuepadding)]
819          || $itk_option(-valuepadding) < 0} {
820        error "bad value \"$itk_option(-valuepadding)\": should be >= 0.0"
821    }
822}
823
824# ----------------------------------------------------------------------
825# CONFIGURE: -variable
826# ----------------------------------------------------------------------
827itcl::configbody Rappture::SequenceDial::variable {
828    if {"" != $_variable} {
829        upvar #0 $_variable var
830        trace remove variable var write [itcl::code $this _fixValue]
831    }
832
833    set _variable $itk_option(-variable)
834
835    if {"" != $_variable} {
836        upvar #0 $_variable var
837        trace add variable var write [itcl::code $this _fixValue]
838
839        # sync to the current value of this variable
840        if {[info exists var]} {
841            _fixValue
842        }
843    }
844}
Note: See TracBrowser for help on using the repository browser.