You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1458 lines
47 KiB
1458 lines
47 KiB
# vertical_meter.tcl -- |
|
# Implement various meter types |
|
# |
|
# This software is Copyright by the Board of Trustees of Michigan |
|
# State University (c) Copyright 2005. |
|
# |
|
# You may use this software under the terms of the GNU public license |
|
# (GPL) ir the Tcl BSD derived license The terms of these licenses |
|
# are described at: |
|
# |
|
# GPL: http://www.gnu.org/licenses/gpl.txt |
|
# Tcl: http://www.tcl.tk/softare/tcltk/license.html |
|
# Start with the second paragraph under the Tcl/Tk License terms |
|
# as ownership is solely by Board of Trustees at Michigan State University. |
|
# |
|
# Author: |
|
# Ron Fox |
|
# NSCL |
|
# Michigan State University |
|
# East Lansing, MI 48824-1321 |
|
# |
|
# Adjusted by Arjen Markus |
|
# |
|
# TODO: |
|
# Add options: |
|
# -readonly, -arrowthickness, -arrowcolor, -background/-bg |
|
# -majorticklength, -minorticklength |
|
# -drawaxle |
|
# |
|
# Add features/TODO: |
|
# - proper update if to/from changes |
|
# - unit tests |
|
# - check behaviour if no variable defined |
|
# |
|
# Add widgets: |
|
# - shiftbar (or what is the best name?) |
|
# - equalizer bars |
|
# |
|
# |
|
# |
|
|
|
# Implements a 'meter' megawidget. A meter is a |
|
# box with a needle that goes up and down between |
|
# two possible limits. |
|
# |
|
# This is drawn in a canvas as follows: |
|
# +-------+ |
|
# | | |
|
# | <----| |
|
# | ... |
|
# +-------+ |
|
# |
|
# |
|
# OPTIONS: |
|
# -from - Value represented by the lower limit of the meter. (dynamic) |
|
# -to - Value represented by the upper limit of the meter. (dynamic) |
|
# -height - Height of the meter. (static) |
|
# -width - Width of the meter. (static) |
|
# -variable - Variable the meter will track. (dynamic) |
|
# -majorticks - Interval between major (labelled) ticks. (dynamic) |
|
# -minorticks - Number of minor ticks drawn between major ticks. (dynamic) |
|
# -log - True if should be log scale (dynamic). |
|
# |
|
# Methods: |
|
# set value - Set the meter to a specific value (if -variable is defined it is modified). |
|
# get - Returns the current value of the meter. |
|
|
|
package provide meter 1.0 |
|
package require Tk |
|
package require snit |
|
package require bindDown |
|
|
|
namespace eval controlwidget { |
|
namespace export meter |
|
namespace export slider |
|
namespace export equalizerBar |
|
namespace export thermometer |
|
} |
|
|
|
# verticalAxis -- |
|
# Private type for handling a vertical axis |
|
# Some options are obligatory |
|
# |
|
snit::type controlwidget::verticalAxis { |
|
|
|
option -canvas {} |
|
option -x {} |
|
option -xright {} |
|
option -ytop {} |
|
option -ybottom {} |
|
option -axisformat -default %.2g -configuremethod SetAxisProperty |
|
option -axisfont -default {fixed} -configuremethod SetAxisProperty |
|
option -axiscolor black |
|
option -drawaxle 1 |
|
option -from -default -1.0 -configuremethod SetAxisRange |
|
option -to -default 1.0 -configuremethod SetAxisRange |
|
option -majorticks -default 1.0 -configuremethod SetAxisProperty |
|
option -minorticks -default 4 -configuremethod SetAxisProperty |
|
option -log -default false -configuremethod SetAxisType |
|
option -axisstyle -default left |
|
|
|
variable majorlength 7 |
|
variable valueRange |
|
|
|
constructor args { |
|
$self configurelist $args |
|
} |
|
|
|
method drawAxis {} { |
|
if { $options(-drawaxle) } { |
|
$options(-canvas) create line $options(-x) $options(-ytop) $options(-x) $options(-ybottom) \ |
|
-fill $options(-axiscolor) -tags axis |
|
} |
|
$self drawTicks |
|
} |
|
|
|
|
|
# Draw the tick marks on the axis face. The major ticks are |
|
# labelled, while the minor ticks are just some length. |
|
# Major ticks extend from the meter left edge to 1/5 the width of the meter |
|
# while minor ticks extend from the meter left edge to 1/10 the width of the meter. |
|
# Tick labels are drawn at x coordinate 0. |
|
# |
|
method drawTicks {} { |
|
|
|
if {!$options(-log)} { |
|
$self drawLinearTicks |
|
} else { |
|
$self drawLogTicks |
|
} |
|
} |
|
# |
|
# Draw the ticks for a log scale. |
|
# |
|
method drawLogTicks {} { |
|
set decades [$self computeDecades]; # Range of axis ... |
|
set majorRight [$self getMajorRight]; # Right end coordinate of major tick. |
|
set minorRight [$self getMinorRight]; # Right end coord of minor tick. |
|
set xleft $options(-x) |
|
|
|
# Major ticks are easy.. they are at the decades. |
|
|
|
set range [expr $options(-ytop) - $options(-ybottom)] |
|
set interval [expr $range/([llength $decades] -1) ]; # Space decades evenly. |
|
|
|
set pos $options(ybottom) |
|
foreach decade $decades { |
|
$options(-canvas) create text $xleft $pos -text $decade -anchor e -font $options(-axisfont) \ |
|
-fill $options(-axiscolor) -tags ticks |
|
$options(-canvas) create line $xleft $pos $majorRight $pos -fill $options(-axiscolor) -tags ticks] |
|
# |
|
# Now the minor ticks... we draw for 1-9. of them in log spacing. |
|
# |
|
foreach mant [list 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0] { |
|
set ht [expr $pos + $interval*log10($mant)] |
|
$options(-canvas) create line $xleft $ht $minorRight $ht -fill $options(-axiscolor) -tags ticks] |
|
} |
|
set pos [expr $pos + $interval] |
|
} |
|
} |
|
# |
|
# Draw the ticks for a linear scale: |
|
# |
|
method drawLinearTicks {} { |
|
set first $options(-from) |
|
set last $options(-to) |
|
set major $options(-majorticks) |
|
set xleft $options(-x) |
|
|
|
|
|
# minor ticks are just given in terms of the # ticks between majors so: |
|
|
|
set minor [expr 1.0*$major/($options(-minorticks)+1)] |
|
|
|
# Figure out the right most coordinates of the tick lines. |
|
|
|
set majorRight [$self getMajorRight] |
|
set minorRight [$self getMinorRight] |
|
|
|
# the for loop is done the way it is in order to reduce |
|
# the cumulative roundoff error from repetitive summing. |
|
# |
|
set majorIndex 0 |
|
for {set m $first} {$m <= $last} {set m [expr $first + $majorIndex*$major]} { |
|
# Draw a major tick label and the tick mark itself |
|
# major ticks are formatted in engineering notation (%.1e). |
|
|
|
set label [format $options(-axisformat) $m] |
|
set height [$self computeHeight $m] |
|
$options(-canvas) create text $xleft $height -text $label -anchor e -font $options(-axisfont) \ |
|
-fill $options(-axiscolor) -tags ticks] |
|
$options(-canvas) create line $xleft $height $majorRight $height \ |
|
-fill $options(-axiscolor) -tags ticks] |
|
|
|
for {set i 1} {$i <= $options(-minorticks)} {incr i} { |
|
set minorH [expr $m + 1.0*$i*$minor] |
|
set minorH [$self computeHeight $minorH] |
|
$options(-canvas) create line $xleft $minorH $minorRight $minorH \ |
|
-fill $options(-axiscolor) -tags ticks] |
|
} |
|
incr majorIndex |
|
} |
|
} |
|
# |
|
# Erase the Tick ids from the meter: |
|
# |
|
method eraseTicks {} { |
|
$options(-canvas) delete ticks |
|
} |
|
# |
|
# Compute the right x coordinate of the major ticks: |
|
# |
|
method getMajorRight {} { |
|
set majorRight [expr {$options(-x) + $majorlength}] |
|
|
|
return $majorRight |
|
} |
|
# |
|
# Compute the right x coordinate of the minor ticks: |
|
# |
|
method getMinorRight {} { |
|
set minorlength [expr $majorlength/2] |
|
set minorRight [expr $options(-x) + $minorlength] |
|
return $minorRight |
|
} |
|
|
|
# compute the decades in the plot. This is also where we will complain if the |
|
# range covers 0 or a negative range as for now we only support positive log scales. |
|
# Returns a list of the decades e.g. {1.0e-9 1.0e-08 1.0e-7} that cover the range. |
|
# The low decade truncates. The high one is a ceil. |
|
# |
|
|
|
method computeDecades {} { |
|
set low $options(-from) |
|
|
|
if {$low <= 0.0} { |
|
return -code error "Log scale with negative or zero -from value is not supported" |
|
} |
|
set high $options(-to) |
|
if {$high <= 0.0} { |
|
return -code error "Log scale with negative or zero -to value no" |
|
} |
|
# |
|
set lowDecade [expr log10($low)] |
|
if {$lowDecade < 0} { |
|
set lowDecade [expr $lowDecade - 0.5] |
|
} |
|
set lowDecade [expr int($lowDecade)] |
|
|
|
set result [format "1.0e%02d" $lowDecade] |
|
set highDecade [expr log10($high)]; # Don't truncate... |
|
while {$lowDecade < $highDecade} { |
|
incr lowDecade |
|
lappend result [format "1.0e%02d" $lowDecade] |
|
} |
|
set decadeLow [lindex $result 0] |
|
set decadeHigh [lindex $result end] |
|
return $result |
|
} |
|
|
|
# Compute the correct height of the needle given |
|
# A new coordinate value for it in needle units: |
|
|
|
method computeHeight needleCoords { |
|
if {$options(-log)} { |
|
return [$self computeLogHeight $needleCoords] |
|
} else { |
|
return [$self computeLinearHeight $needleCoords] |
|
} |
|
} |
|
|
|
# Compute the needle height if the scale is log. |
|
|
|
method computeLogHeight needleCoords { |
|
$self computeDecades |
|
# |
|
# The following protect against range errors as well as |
|
# negative/0 values: |
|
# |
|
if {$needleCoords < $decadeLow} { |
|
set needleCoords $decadeLow |
|
} |
|
if {$needleCoords > $decadeHigh} { |
|
set needleCoords $decadeHigh |
|
} |
|
|
|
# Now it should be safe to do the logs: |
|
# the scaling is just linear in log coords: |
|
|
|
set valueRange [expr {log10($decadeHigh) - log10($decadeLow)}] |
|
set value [expr {log10($needleCoords) - log10($decadeLow)}] |
|
|
|
set pixelRange [expr {1.0*($options(-ybottom) - $options(-ytop)}] |
|
|
|
set height [expr {$value*$pixelRange/$valueRange}] |
|
return [expr {$options(-ybottom) - $height}] |
|
|
|
} |
|
|
|
# Compute the needle height if the scale is linear |
|
# |
|
method computeLinearHeight needleCoords { |
|
|
|
# |
|
# Peg the needle to the limits: |
|
# |
|
if {$needleCoords > $options(-to)} { |
|
return $options(-ytop) |
|
} |
|
if {$needleCoords < $options(-from)} { |
|
return $options(-ybottom) |
|
} |
|
set pixelRange [expr {1.0*($options(-ybottom) - $options(-ytop))}] |
|
|
|
# Transform the coordinates: |
|
|
|
set valueRange [expr {1.0*($options(-to) - $options(-from))}] |
|
set height [expr {($needleCoords - $options(-from))*$pixelRange/$valueRange}] |
|
return [expr {$options(-ybottom) - $height}] |
|
} |
|
|
|
# Compute the correct value of the needle given the position |
|
|
|
method computeValue needleCoords { |
|
if {$options(-log)} { |
|
return [$self computeLogValue $needleCoords] |
|
} else { |
|
return [$self computeLinearValue $needleCoords] |
|
} |
|
} |
|
|
|
# Compute the needle's value if the scale is log. |
|
|
|
method computeLogValue needleCoords { |
|
$self computeDecades |
|
# |
|
# The following protect against range errors as well as |
|
# negative/0 values: |
|
# |
|
if {$needleCoords < $options(-ytop)} { |
|
set needleCoords $options(-ytop) |
|
} |
|
if {$needleCoords > $options(-ybottom)} { |
|
set needleCoords $options(-ybottom) |
|
} |
|
|
|
set logScale [expr {log10($decadeHigh/$decadeLow)}] |
|
set yratio [expr {($y - $ymin) / double($ymax - $ymin)}] |
|
|
|
set value [expr {$decadeLow * pow(10.0,$logScale*$yratio)}] |
|
|
|
return $value |
|
} |
|
|
|
# Compute the needle's value if the scale is linear |
|
# |
|
method computeLinearValue needleCoords { |
|
|
|
# |
|
# Peg the needle to the limits: |
|
# |
|
if {$needleCoords < $options(-ytop)} { |
|
return $options(-to) |
|
} |
|
if {$needleCoords > $options(-ybottom)} { |
|
return $options(-from) |
|
} |
|
|
|
set pixelRange [expr {1.0*($options(-ybottom) - $options(-ytop))}] |
|
|
|
# Transform the coordinates: |
|
|
|
set scaleFactor [expr {($options(-to) - $options(-from)) / $pixelRange}] |
|
set value [expr {$options(-from) + ($options(-ybottom) - $needleCoords)*$scaleFactor}] |
|
|
|
return $value |
|
} |
|
|
|
#------------------------ Configuration handlers for dynamic options ---- |
|
# -from - Value represented by the lower limit of the meter. (dynamic) |
|
# -to - Value represented by the upper limit of the meter. (dynamic) |
|
# -log - Type of axis (linear or logarithmic) (dynamic) |
|
# -majorticks - Interval between major (labelled) ticks. (dynamic) |
|
# -minorticks - Number of minor ticks drawn between major ticks. (dynamic) |
|
|
|
|
|
# Handle configure -to and -from |
|
# Need to set the stuff needed to scale the meter positions and reset the meter position. |
|
# Need to redraw ticks as well. |
|
# |
|
method SetAxisRange {option value} { |
|
set options($option) $value |
|
if {![winfo exists $win.c]} return; # Still constructing. |
|
$self eraseTicks |
|
if { $option == "-from" } { |
|
set valueRange [expr $options(-to) - $value] |
|
} else { |
|
set valueRange [expr $value - $options(-from)] |
|
} |
|
$self drawTicks |
|
|
|
$self needleTo $lastValue |
|
} |
|
|
|
# Handle configure -log |
|
# Set the log flag accordingly and then redraw the ticks and value: |
|
# Note that we must check the -from/-to and figure out the first decade |
|
# and the last decade. |
|
# |
|
method SetAxisType {option value} { |
|
# No change return. |
|
|
|
if {$value == $options(-log)} return; # short cut exit. |
|
|
|
# require booleanness. |
|
|
|
if {![string is boolean $value]} { |
|
return -error "meter.tcl - value of -log flag must be a boolean" |
|
} |
|
# Set the new value and update the meter: |
|
|
|
set options(-log) $value |
|
if {!$constructing} { |
|
$self computeDecades |
|
$self eraseTicks |
|
$self drawTicks |
|
$self needleTo $lastValue |
|
} |
|
} |
|
|
|
# Handle a change in the axis' properties ... we just need to set the option and redraw the ticks. |
|
# |
|
method SetAxisProperty {option value} { |
|
set options($option) $value |
|
if {![winfo exists $options(-canvas)]} return; # Still constructing. |
|
$self eraseTicks |
|
$self drawTicks |
|
} |
|
} |
|
|
|
|
|
# move indicator -- |
|
# Collection of procedures to move an item |
|
# |
|
|
|
# installVerticalMoveBindings -- |
|
# Install the move bindings for a particular set of items |
|
# |
|
# Arguments: |
|
# widget Widget containing the items |
|
# object Snit object controlling the items |
|
# indicatorTag Tag common to the items |
|
# ymin Minimum y coordinate |
|
# ymax Maximum y coordinate |
|
# |
|
# Note: |
|
# The object must define a method NewPosition that takes two arguments: |
|
# The pixel value of the new position and the tag it belongs to |
|
# |
|
proc ::controlwidget::installVerticalMoveBindings {widget object indicatorTag ymin ymax} { |
|
variable grab |
|
|
|
if { [info exists grab($object,$indicatorTag)] } { |
|
unset grab($object,$indicatorTag) |
|
} |
|
|
|
$widget bind $indicatorTag <ButtonPress-1> [list ::controlwidget::GetIndicator $widget $object $indicatorTag $ymin $ymax %y] |
|
$widget bind $indicatorTag <ButtonRelease> [list ::controlwidget::ReleaseIndicator $widget $object $indicatorTag $ymin $ymax %y] |
|
$widget bind $indicatorTag <Motion> [list ::controlwidget::MoveIndicator $widget $object $indicatorTag $ymin $ymax %y] |
|
} |
|
|
|
proc ::controlwidget::GetIndicator {w object tag ymin ymax y} { |
|
variable grab |
|
# console show |
|
# puts "Got needle" |
|
|
|
set readonly 0 |
|
catch { |
|
set readonly [$object cget -readonly] |
|
} |
|
if { ! $readonly } { |
|
set grab($object,$tag) $y |
|
} |
|
} |
|
proc ::controlwidget::ReleaseIndicator {w object tag ymin ymax y} { |
|
variable grab |
|
# puts "Released needle" |
|
unset grab($object,$tag) |
|
} |
|
|
|
proc ::controlwidget::MoveIndicator {w object tag ymin ymax y} { |
|
variable grab |
|
|
|
if { [info exists grab($object,$tag)] } { |
|
# |
|
# Determine the middle of the tagged canvas items |
|
# - we must limit the repositioning |
|
# |
|
set bbox [$w bbox $tag] |
|
set ycentre [expr {([lindex $bbox 1] + [lindex $bbox 3]) / 2}] |
|
|
|
set dy [expr {$y - $grab($object,$tag)}] |
|
|
|
if { $ycentre + $dy < $ymin } { |
|
set dy [expr {$ymin - $ycentre}] |
|
#set y [expr {$y + $dy}] |
|
} |
|
if { $ycentre + $dy > $ymax } { |
|
set dy [expr {$ymax - $ycentre}] |
|
#set y [expr {$y + $dy}] |
|
} |
|
|
|
|
|
# This should be done by the trace procedure ... |
|
# TODO: what if there is no variable? |
|
$w move $tag 0 $dy |
|
set grab($object,$tag) $y |
|
|
|
# puts "move: $dy -- $y -- [$w bbox $tag]" |
|
$object NewPosition $y $tag |
|
} |
|
} |
|
|
|
|
|
# meter -- |
|
# Type for displaying and controlling a vertical meter |
|
# |
|
snit::widget controlwidget::meter { |
|
option -height {2i} |
|
option -width {1.5i} |
|
option -background white |
|
option -arrowthickness -default 1 -configuremethod SetArrow |
|
option -arrowcolor -default black -configuremethod SetArrow |
|
option -variable -default {} -configuremethod VariableName |
|
option -readonly -default 0 -type snit::boolean |
|
|
|
component axis |
|
foreach option {-from -to -majorticks -minorticks -log -axisfont -axiscolor -axisformat} { |
|
delegate option $option to axis |
|
} |
|
|
|
variable constructing 1 |
|
|
|
variable needleId {} |
|
variable topY {} |
|
variable bottomY {} |
|
variable valueRange {} |
|
variable needleLeft {} |
|
variable meterLeft {} |
|
variable majorlength |
|
|
|
variable tickIds {} |
|
variable lastValue 0 |
|
|
|
variable decadeLow 0; # e.g. 1 -10... this is the low end exponent. |
|
variable decadeHigh 1; # e.g. 10-100. |
|
|
|
variable fontList |
|
|
|
# Construct the widget: |
|
|
|
constructor args { |
|
install axis using verticalAxis %AUTO% -canvas $win.c |
|
$self configurelist $args |
|
|
|
# In order to get the font info, we need to create an invisible |
|
# label so we can query the default font.. we'll accept that |
|
# but ensure that the font size is 10. |
|
|
|
label $win.hidden |
|
set fontList [$win.hidden cget -font] |
|
set fontList [font actual $fontList] |
|
set fontList [lreplace $fontList 1 1 10]; # Force size to 10pt. |
|
|
|
# Create the canvas and draw the meter into the canvas. |
|
# The needle is drawn at 1/2 of the rectangle height. |
|
# 3/4 width. |
|
# We'll store the resulting size back in the options asn |
|
# pixels since their much easier to work with: |
|
|
|
canvas $win.c \ |
|
-width $options(-width) \ |
|
-height $options(-height) \ |
|
-background white |
|
|
|
set to [$axis cget -to] |
|
set from [$axis cget -from] |
|
set log [$axis cget -log] |
|
set valueRange [expr {1.0*($to - $from)}] |
|
|
|
|
|
set options(-height) [$win.c cget -height] |
|
set options(-width) [$win.c cget -width] |
|
|
|
# In order to support label we need to create a left margin |
|
# the margin will be 8chars worth of 8's in the font we've used |
|
# and a top/bottom margin of 5pt.. the assumption is that the labels |
|
# will be drawn in 10pt font. |
|
|
|
set leftmargin [font measure $fontList 88888888] |
|
|
|
set leftmargin [$win.c canvasx $leftmargin] |
|
set vmargin [$win.c canvasy 5p] |
|
|
|
# Compute the coordinates of the rectangle and the top/bottom limits |
|
# (for scaling the arrow position). |
|
|
|
set meterLeft $leftmargin |
|
set topY $vmargin |
|
set meterRight $options(-width) |
|
set bottomY [expr $options(-height) - $vmargin] |
|
|
|
$axis configure -x $meterLeft |
|
$axis configure -ybottom $bottomY |
|
$axis configure -ytop $topY |
|
$axis drawAxis |
|
|
|
|
|
# draw the frame of the meter as a rectangle: |
|
|
|
$win.c create rectangle $meterLeft $topY $meterRight $bottomY |
|
|
|
# figure out how to put the needle in the middle of the |
|
# height of the meter allowing 1/4 of the meter for ticks. |
|
# |
|
|
|
set needleWidth [expr {3*($meterRight - $meterLeft)/4}] |
|
set needleHeight [$axis computeHeight \ |
|
[expr {($to + $from)/2}]] |
|
set needleLeft [expr $options(-width) - $needleWidth] |
|
|
|
set needleId [$win.c create line $needleLeft $needleHeight \ |
|
$options(-width) $needleHeight -tags {needle arrow} \ |
|
-arrow first -fill $options(-arrowcolor) -width $options(-arrowthickness)]] |
|
|
|
set needleHalo [$win.c create rectangle $needleLeft [expr {$needleHeight-3}] \ |
|
$options(-width) [expr {$needleHeight+3}] -fill $options(-background) \ |
|
-outline $options(-background) -tags needle] |
|
$win.c lower $needleHalo |
|
|
|
|
|
grid $win.c -sticky nsew |
|
|
|
$axis drawTicks |
|
|
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
if { [info exists ::$options(-variable)] } { |
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
} |
|
bindDown $win $win |
|
|
|
installVerticalMoveBindings $win.c $self needle $topY $bottomY |
|
|
|
set constructing 0 |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# public methods |
|
# |
|
|
|
# Set a new value for the meter... this moves the pointer to a new value. |
|
# if a variable is tracing the meter, it is changed |
|
# |
|
method set newValue { |
|
if {$options(-variable) ne ""} { |
|
set ::$options(-variable) $newValue; # This updates meter too. |
|
} else { |
|
$self needleTo $newValue |
|
} |
|
} |
|
|
|
# Get the last meter value. |
|
# |
|
method get {} { |
|
return $lastValue |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# 'private' methods. |
|
|
|
# trace on -variable being modified. |
|
|
|
method variableChanged {name1 name2 op} { |
|
|
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
|
|
# Set a new position for the needle: |
|
|
|
method needleTo newCoords { |
|
set lastValue $newCoords |
|
|
|
set height [$axis computeHeight $newCoords] |
|
$win.c coords $needleId $needleLeft $height $options(-width) $height |
|
} |
|
|
|
|
|
# Configure the variable for the meter. |
|
# Any prior variable must have its trace removed. |
|
# The new variable gets a trace established and the meter position |
|
# is updated from it. |
|
# Note that if the new variable is "" then the meter will have |
|
# no variable associated with it. |
|
|
|
method VariableName {option name} { |
|
|
|
# Could be still constructing in which case |
|
# $win.c does not exist: |
|
|
|
if {![winfo exists $win.c]} { |
|
set options(-variable) $name |
|
return; |
|
} |
|
|
|
# Remove any old traces |
|
|
|
|
|
if {$options(-variable) ne ""} { |
|
trace remove variable ::$options(-variable) write [mymethod variableChanged] |
|
} |
|
|
|
# Set new trace if appropriate and update value. |
|
|
|
set options(-variable) $name |
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
} |
|
|
|
# Configure the arrow |
|
method SetArrow {option value} { |
|
switch -- $option { |
|
"-arrowthickness" { |
|
$win.c itemconfigure arrow -width $value |
|
} |
|
"-arrowcolor" { |
|
$win.c itemconfigure arrow -fill $value |
|
} |
|
} |
|
} |
|
|
|
# React to the dragging of the needle |
|
method NewPosition {y tag} { |
|
if { $options(-variable) ne "" } { |
|
set ::$options(-variable) [$axis computeValue $y] |
|
} |
|
} |
|
} |
|
|
|
|
|
# slider -- |
|
# Type for displaying and controlling a vertical slider |
|
# (It actually supports one or several sliders at once) |
|
# |
|
snit::widget controlwidget::slider { |
|
option -height 200 |
|
option -width 150 |
|
option -background -default grey |
|
option -sliderthickness -default 10 -readonly true -type snit::double |
|
option -sliderwidth -default 20 -readonly true -type snit::double |
|
option -troughwidth -default 10 -readonly true -type snit::double |
|
option -variable -default {} -configuremethod VariableName |
|
option -number -default 1 -readonly true -type snit::integer |
|
|
|
component axis |
|
foreach option {-from -to -majorticks -minorticks -log -axisfont -axiscolor -axisformat} { |
|
delegate option $option to axis |
|
} |
|
|
|
variable constructing 1 |
|
|
|
variable topY {} |
|
variable bottomY {} |
|
|
|
variable lastValue {} |
|
variable lastHeight {} |
|
|
|
variable decadeLow 0; # e.g. 1 -10... this is the low end exponent. |
|
variable decadeHigh 1; # e.g. 10-100. |
|
|
|
variable fontList |
|
|
|
# Construct the widget: |
|
|
|
constructor args { |
|
install axis using verticalAxis %AUTO% -canvas $win.c |
|
$self configurelist $args |
|
|
|
# In order to get the font info, we need to create an invisible |
|
# label so we can query the default font.. we'll accept that |
|
# but ensure that the font size is 10. |
|
|
|
label $win.hidden |
|
set fontList [$win.hidden cget -font] |
|
set fontList [font actual $fontList] |
|
set fontList [lreplace $fontList 1 1 10]; # Force size to 10pt. |
|
|
|
# Create the canvas and draw the slider(s) into the canvas. |
|
# |
|
# The geometry of the sliders determines the size of the canvas |
|
# |
|
canvas $win.c |
|
|
|
set leftmargin [font measure $fontList 88888888] |
|
|
|
set leftmargin [$win.c canvasx $leftmargin] |
|
set vmargin [$win.c canvasy 5p] |
|
|
|
set height [expr {$options(-height) + $vmargin + $options(-sliderthickness)}] |
|
set width [expr {$leftmargin + $options(-number) * $options(-sliderwidth) * 1.5 + 0.25* $options(-sliderwidth)}] |
|
|
|
$win.c configure \ |
|
-width $width \ |
|
-height $height \ |
|
-background $options(-background) |
|
|
|
set to [$axis cget -to] |
|
set from [$axis cget -from] |
|
set log [$axis cget -log] |
|
set valueRange [expr {1.0*($to - $from)}] |
|
|
|
set meterLeft $leftmargin |
|
set topY [expr {$vmargin + 0.5 * $options(-sliderthickness)}] |
|
set meterRight $options(-width) |
|
set bottomY [expr {$height - $vmargin - 0.5 * $options(-sliderthickness)}] |
|
|
|
$axis configure -x $meterLeft |
|
$axis configure -ybottom $bottomY |
|
$axis configure -ytop $topY |
|
$axis drawAxis |
|
|
|
|
|
# draw the sliders and the troughs |
|
|
|
set sliderThickness $options(-sliderthickness) |
|
set sliderWidth $options(-sliderwidth) |
|
set troughWidth $options(-troughwidth) |
|
set number $options(-number) |
|
|
|
set sliderCentre [expr {($bottomY + $topY)/2.0}] |
|
set sliderTop [expr {$sliderCentre - $sliderThickness/2.0}] |
|
set sliderCentreTop [expr {$sliderCentre - 1}] |
|
set sliderCentreBottom [expr {$sliderCentre + 1}] |
|
set sliderBottom [expr {$sliderCentre + $sliderThickness/2.0}] |
|
|
|
set lastHeight {} |
|
for { set i 0 } { $i < $number } { incr i } { |
|
|
|
set troughLeft [expr {$meterLeft + ($i*1.5+0.75) * $sliderWidth}] |
|
set troughRight [expr {$troughLeft + $troughWidth}] |
|
set sliderLeft [expr {$meterLeft + ($i*1.5+0.5) * $sliderWidth - 1}] |
|
set sliderRight [expr {$sliderLeft + $sliderWidth}] |
|
|
|
# |
|
# Trough holding the slider bar |
|
# |
|
$win.c create rectangle [expr {$troughLeft-2}] [expr {$topY-2}] $troughRight $bottomY -fill black ;# Slightly shifted for shadow effect |
|
$win.c create rectangle $troughLeft $topY $troughRight $bottomY -fill gray40 |
|
|
|
# |
|
# Slider |
|
# |
|
$win.c create rectangle $sliderLeft $sliderTop $sliderRight $sliderCentreTop -fill gray90 -tag slider$i -outline {} |
|
$win.c create rectangle $sliderLeft $sliderCentreBottom $sliderRight $sliderBottom -fill gray30 -tag slider$i -outline {} |
|
$win.c create rectangle $sliderLeft $sliderCentreTop $sliderRight $sliderCentreBottom -fill white -tag slider$i -outline {} |
|
$win.c create rectangle $sliderLeft $sliderTop $sliderRight $sliderBottom -fill {} -tag slider$i -outline black |
|
|
|
installVerticalMoveBindings $win.c $self slider$i $topY $bottomY |
|
|
|
lappend lastHeight $sliderCentre |
|
} |
|
|
|
grid $win.c -sticky nsew |
|
|
|
$axis drawTicks |
|
|
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
if { [info exists ::$options(-variable)] } { |
|
$self sliderTo [set ::$options(-variable)] |
|
} |
|
} |
|
bindDown $win $win |
|
|
|
set constructing 0 |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# public methods |
|
# |
|
|
|
# Set a new value for the meter... this moves the pointer to a new value. |
|
# if a variable is tracing the meter, it is changed |
|
# |
|
method set newValue { |
|
if {$options(-variable) ne ""} { |
|
set ::$options(-variable) $newValue; # This updates meter too. |
|
} else { |
|
$self sliderTo $newValue |
|
} |
|
} |
|
|
|
# Get the last meter value. |
|
# |
|
method get {} { |
|
return $lastValue |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# 'private' methods. |
|
|
|
# trace on -variable being modified. |
|
|
|
method variableChanged {name1 name2 op} { |
|
|
|
$self sliderTo [set ::$options(-variable)] |
|
} |
|
|
|
# Set a new position for the slider: |
|
# |
|
# NOTE: |
|
# Current implementation causes the slider to shift twice as |
|
# fast! That should not happen of course |
|
# |
|
method sliderTo newCoords { |
|
|
|
set move 1 |
|
if { [llength [array names ::controlwidget::grab $self,slider*]] > 0 } { |
|
set move 0 |
|
} |
|
|
|
set idx 0 |
|
set newheight {} |
|
foreach coord $newCoords currentHeight $lastHeight { |
|
set height [$axis computeHeight $coord] |
|
set dy [expr {$height - $currentHeight}] |
|
|
|
if { $move } { |
|
$win.c move slider$idx 0 $dy |
|
} |
|
|
|
lappend newHeight $height |
|
incr idx |
|
} |
|
|
|
set lastValue $newCoords |
|
set lastHeight $newHeight |
|
# puts "sliderTo: [$win.c bbox slider2]" |
|
} |
|
|
|
|
|
# Configure the variable for the meter. |
|
# Any prior variable must have its trace removed. |
|
# The new variable gets a trace established and the meter position |
|
# is updated from it. |
|
# Note that if the new variable is "" then the meter will have |
|
# no variable associated with it. |
|
|
|
method VariableName {option name} { |
|
|
|
# Could be still constructing in which case |
|
# $win.c does not exist: |
|
|
|
if {![winfo exists $win.c]} { |
|
set options(-variable) $name |
|
return; |
|
} |
|
|
|
# Remove any old traces |
|
|
|
|
|
if {$options(-variable) ne ""} { |
|
trace remove variable ::$options(-variable) write [mymethod variableChanged] |
|
} |
|
|
|
# Set new trace if appropriate and update value. |
|
|
|
set options(-variable) $name |
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
} |
|
|
|
# React to the dragging of the needle |
|
method NewPosition {y tag} { |
|
if { $options(-variable) ne "" } { |
|
set idx [string range $tag 6 end] |
|
lset ::$options(-variable) $idx [$axis computeValue $y] |
|
set lastValue [set ::$options(-variable)] |
|
lset lastHeight $idx $y |
|
# puts "$y -- $lastValue -- [$win.c bbox slider2]" |
|
} |
|
} |
|
} |
|
|
|
|
|
# equalizerBar -- |
|
# Type for displaying and controlling a set of coloured bars |
|
# like the ones found on the display of a hifi equalizer |
|
# |
|
snit::widget controlwidget::equalizerBar { |
|
option -height 200 |
|
option -width 150 |
|
option -background -default darkgrey |
|
option -barwidth -default 15 -readonly true -type snit::double |
|
option -segments -default 10 -readonly true -type snit::integer |
|
option -variable -default {} -configuremethod VariableName |
|
option -safecolor -default green |
|
option -warningcolor -default red |
|
option -warninglevel -default 1.0 |
|
option -number -default 1 -readonly true -type snit::integer |
|
|
|
component axis |
|
foreach option {-from -to -majorticks -minorticks -log -axisfont -axiscolor -axisformat} { |
|
delegate option $option to axis |
|
} |
|
|
|
variable constructing 1 |
|
|
|
variable topY {} |
|
variable bottomY {} |
|
|
|
variable lastValue {} |
|
variable lastHeight {} |
|
|
|
variable decadeLow 0; # e.g. 1 -10... this is the low end exponent. |
|
variable decadeHigh 1; # e.g. 10-100. |
|
|
|
variable segmentIds {} |
|
|
|
variable fontList |
|
|
|
# Construct the widget: |
|
|
|
constructor args { |
|
install axis using verticalAxis %AUTO% -canvas $win.c |
|
$self configurelist $args |
|
|
|
# In order to get the font info, we need to create an invisible |
|
# label so we can query the default font.. we'll accept that |
|
# but ensure that the font size is 10. |
|
|
|
label $win.hidden |
|
set fontList [$win.hidden cget -font] |
|
set fontList [font actual $fontList] |
|
set fontList [lreplace $fontList 1 1 10]; # Force size to 10pt. |
|
|
|
# Create the canvas and draw the slider(s) into the canvas. |
|
# |
|
# The geometry of the sliders determines the size of the canvas |
|
# |
|
canvas $win.c |
|
|
|
set leftmargin [font measure $fontList 88888888] |
|
|
|
set leftmargin [$win.c canvasx $leftmargin] |
|
set vmargin [$win.c canvasy 5p] |
|
|
|
set height [expr {$options(-height) + $vmargin}] |
|
set width [expr {$leftmargin + $options(-number) * $options(-barwidth) * 1.2 + $options(-barwidth)}] |
|
|
|
set segmentHeight [expr {$options(-height)/double($options(-segments)) - 2}] |
|
|
|
$win.c configure \ |
|
-width $width \ |
|
-height $height \ |
|
-background $options(-background) |
|
|
|
set to [$axis cget -to] |
|
set from [$axis cget -from] |
|
set log [$axis cget -log] |
|
set valueRange [expr {1.0*($to - $from)}] |
|
|
|
set meterLeft $leftmargin |
|
set topY $vmargin |
|
set meterRight $options(-width) |
|
set bottomY [expr {$height - $vmargin}] |
|
|
|
$axis configure -x $meterLeft |
|
$axis configure -ybottom $bottomY |
|
$axis configure -ytop $topY |
|
$axis drawAxis |
|
|
|
# draw the bar segments - keep track of the IDs |
|
|
|
set barWidth $options(-barwidth) |
|
set numberSegments $options(-segments) |
|
set numberBars $options(-number) |
|
|
|
set lastHeight {} |
|
set segmentIds {} |
|
for { set i 0 } { $i < $numberBars } { incr i } { |
|
|
|
set barLeft [expr {$meterLeft + 10 + $i*1.2 * $barWidth}] |
|
set barRight [expr {$barLeft + $barWidth}] |
|
|
|
set segmentColumn {} |
|
|
|
for { set j 0 } { $j < $numberSegments } { incr j } { |
|
set segmentTop [expr {$bottomY - $j * ($segmentHeight+1)}] |
|
set segmentBottom [expr {$segmentTop - $segmentHeight}] |
|
|
|
lappend segmentColumn \ |
|
[$win.c create rectangle $barLeft $segmentTop $barRight $segmentBottom \ |
|
-fill $options(-background) -outline $options(-background)] |
|
} |
|
|
|
lappend segmentIds $segmentColumn |
|
} |
|
|
|
grid $win.c -sticky nsew |
|
|
|
$axis drawTicks |
|
|
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
if { [info exists ::$options(-variable)] } { |
|
$self barsTo [set ::$options(-variable)] |
|
} |
|
} |
|
bindDown $win $win |
|
|
|
set constructing 0 |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# public methods |
|
# |
|
|
|
# Set a new value for the meter... this moves the pointer to a new value. |
|
# if a variable is tracing the meter, it is changed |
|
# |
|
method set newValue { |
|
if {$options(-variable) ne ""} { |
|
set ::$options(-variable) $newValue; # This updates meter too. |
|
} else { |
|
$self barsTo $newValue |
|
} |
|
} |
|
|
|
# Get the last meter value. |
|
# |
|
method get {} { |
|
return $lastValue |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# 'private' methods. |
|
|
|
# trace on -variable being modified. |
|
|
|
method variableChanged {name1 name2 op} { |
|
|
|
$self barsTo [set ::$options(-variable)] |
|
} |
|
|
|
# Set a new position for the slider: |
|
|
|
method barsTo newCoords { |
|
|
|
set lowerLimit [$axis cget -from] |
|
set valueStep [expr {([$axis cget -to] - $lowerLimit) / double($options(-segments))}] |
|
|
|
set background $options(-background) |
|
|
|
foreach value $newCoords barIds $segmentIds { |
|
|
|
for { set i 0 } { $i < $options(-segments) } { incr i } { |
|
set limitValue [expr {$lowerLimit + ($i+1) * $valueStep}] |
|
|
|
if { $limitValue <= $value } { |
|
set color $options(-safecolor) |
|
if { $limitValue > $options(-warninglevel) } { |
|
set color $options(-warningcolor) |
|
} |
|
|
|
$win.c itemconfigure [lindex $barIds $i] -fill $color -outline black |
|
} else { |
|
$win.c itemconfigure [lindex $barIds $i] -fill $background -outline $background |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
# Configure the variable for the meter. |
|
# Any prior variable must have its trace removed. |
|
# The new variable gets a trace established and the meter position |
|
# is updated from it. |
|
# Note that if the new variable is "" then the meter will have |
|
# no variable associated with it. |
|
|
|
method VariableName {option name} { |
|
|
|
# Could be still constructing in which case |
|
# $win.c does not exist: |
|
|
|
if {![winfo exists $win.c]} { |
|
set options(-variable) $name |
|
return; |
|
} |
|
|
|
# Remove any old traces |
|
|
|
|
|
if {$options(-variable) ne ""} { |
|
trace remove variable ::$options(-variable) write [mymethod variableChanged] |
|
} |
|
|
|
# Set new trace if appropriate and update value. |
|
|
|
set options(-variable) $name |
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
$self barsTo [set ::$options(-variable)] |
|
} |
|
} |
|
} |
|
|
|
|
|
# thermometer -- |
|
# Type for displaying and controlling a thermometer |
|
# |
|
snit::widget controlwidget::thermometer { |
|
option -height 200 |
|
option -width 100 |
|
option -background white |
|
option -linethickness -default 5 -type snit::integer |
|
option -linecolor -default red |
|
option -variable -default {} -configuremethod VariableName |
|
option -readonly -default 1 -type snit::boolean |
|
|
|
component axis |
|
foreach option {-from -to -majorticks -minorticks -log -axisfont -axiscolor -axisformat} { |
|
delegate option $option to axis |
|
} |
|
|
|
variable constructing 1 |
|
|
|
variable topY {} |
|
variable bottomY {} |
|
variable valueRange {} |
|
variable lineId {} |
|
variable lineCentre {} |
|
variable lineBottom {} |
|
variable meterLeft {} |
|
variable meterRight {} |
|
variable majorlength |
|
|
|
variable lastValue 0 |
|
|
|
variable decadeLow 0; # e.g. 1 -10... this is the low end exponent. |
|
variable decadeHigh 1; # e.g. 10-100. |
|
|
|
variable fontList |
|
|
|
# Construct the widget: |
|
|
|
constructor args { |
|
install axis using verticalAxis %AUTO% -canvas $win.c -axisstyle both |
|
$self configurelist $args |
|
|
|
# In order to get the font info, we need to create an invisible |
|
# label so we can query the default font.. we'll accept that |
|
# but ensure that the font size is 10. |
|
|
|
label $win.hidden |
|
set fontList [$win.hidden cget -font] |
|
set fontList [font actual $fontList] |
|
set fontList [lreplace $fontList 1 1 10]; # Force size to 10pt. |
|
|
|
# Create the canvas and draw the thermometer into the canvas. |
|
|
|
canvas $win.c \ |
|
-width $options(-width) \ |
|
-height $options(-height) \ |
|
-background $options(-background) |
|
|
|
set to [$axis cget -to] |
|
set from [$axis cget -from] |
|
set log [$axis cget -log] |
|
set valueRange [expr {1.0*($to - $from)}] |
|
|
|
|
|
set options(-height) [$win.c cget -height] |
|
set options(-width) [$win.c cget -width] |
|
|
|
# In order to support labels we need to create both a left margin |
|
# and a right margin |
|
# the margin will be 8chars worth of 8's in the font we've used |
|
# and a top/bottom margin of 5pt.. the assumption is that the labels |
|
# will be drawn in 10pt font. |
|
|
|
set leftmargin [font measure $fontList 88888888] |
|
|
|
set leftmargin [$win.c canvasx $leftmargin] |
|
set topmargin [expr { 5 + [$win.c canvasy 5p]}] |
|
set bottommargin [expr {10 + [$win.c canvasy 5p]}] |
|
|
|
# Compute the coordinates of the rectangle and the top/bottom limits |
|
# (for scaling the arrow position). |
|
|
|
set meterLeft $leftmargin |
|
set meterRight [expr {$leftmargin + $options(-linethickness) + 2}] |
|
set topY $topmargin |
|
set bottomY [expr $options(-height) - $bottommargin] |
|
|
|
$axis configure -x $meterLeft |
|
$axis configure -ybottom $bottomY |
|
$axis configure -ytop $topY |
|
$axis configure -xright $meterRight |
|
$axis drawAxis |
|
|
|
|
|
# draw the "glass" frame of the thermometer as a double line |
|
# and some curves |
|
|
|
set lineCentre [expr {($meterLeft + $meterRight)/2.0}] |
|
|
|
$win.c create line $meterLeft [expr {$topY - 2}] $meterLeft [expr {$bottomY + 5}] |
|
$win.c create line $meterRight [expr {$topY - 2}] $meterRight [expr {$bottomY + 5}] |
|
$win.c create arc $meterLeft [expr {$topY - 5}] $meterRight [expr {$topY + 3}] \ |
|
-start 0 -extent 180 -style arc |
|
$win.c create oval [expr {$lineCentre - 5}] [expr {$bottomY + 0}] \ |
|
[expr {$lineCentre + 5}] [expr {$bottomY + 10}] \ |
|
-fill $options(-linecolor) -outline black |
|
|
|
|
|
# figure out how to put the needle in the middle of the |
|
# height of the meter allowing 1/4 of the meter for ticks. |
|
# |
|
|
|
set lineBottom [expr {$bottomY + 3}] |
|
set lineTop [$axis computeHeight [expr {($to + $from)/2}]] |
|
|
|
set lineId [$win.c create rectangle [expr {$meterLeft+1}] $lineTop $meterRight $lineBottom \ |
|
-fill $options(-linecolor) -outline {} -tags line] |
|
|
|
set lineHalo [$win.c create rectangle $meterLeft [expr {$lineTop-3}] $meterRight [expr {$lineTop+3}] \ |
|
-fill $options(-background) -outline $options(-background) -tags linetop] |
|
|
|
$win.c lower $lineHalo |
|
|
|
grid $win.c -sticky nsew |
|
|
|
$axis drawTicks |
|
|
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
if { [info exists ::$options(-variable)] } { |
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
} |
|
bindDown $win $win |
|
|
|
# NOT YET |
|
# installVerticalMoveBindings $win.c $self needle $topY $bottomY |
|
|
|
set constructing 0 |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# public methods |
|
# |
|
|
|
# Set a new value for the meter... this moves the pointer to a new value. |
|
# if a variable is tracing the meter, it is changed |
|
# |
|
method set newValue { |
|
if {$options(-variable) ne ""} { |
|
set ::$options(-variable) $newValue; # This updates meter too. |
|
} else { |
|
$self lineTo $newValue |
|
} |
|
} |
|
|
|
# Get the last meter value. |
|
# |
|
method get {} { |
|
return $lastValue |
|
} |
|
|
|
#------------------------------------------------------------------------------- |
|
# 'private' methods. |
|
|
|
# trace on -variable being modified. |
|
|
|
method variableChanged {name1 name2 op} { |
|
|
|
$self lineTo [set ::$options(-variable)] |
|
} |
|
|
|
# Set a new position for the needle: |
|
|
|
method needleTo newCoords { |
|
set lastValue $newCoords |
|
|
|
set height [$axis computeHeight $newCoords] |
|
$win.c coords $lineId [expr {$meterLeft+1}] $lineBottom $meterRight $height |
|
} |
|
|
|
|
|
# Configure the variable for the meter. |
|
# Any prior variable must have its trace removed. |
|
# The new variable gets a trace established and the meter position |
|
# is updated from it. |
|
# Note that if the new variable is "" then the meter will have |
|
# no variable associated with it. |
|
|
|
method VariableName {option name} { |
|
|
|
# Could be still constructing in which case |
|
# $win.c does not exist: |
|
|
|
if {![winfo exists $win.c]} { |
|
set options(-variable) $name |
|
return; |
|
} |
|
|
|
# Remove any old traces |
|
|
|
|
|
if {$options(-variable) ne ""} { |
|
trace remove variable ::$options(-variable) write [mymethod variableChanged] |
|
} |
|
|
|
# Set new trace if appropriate and update value. |
|
|
|
set options(-variable) $name |
|
if {$options(-variable) ne ""} { |
|
trace add variable ::$options(-variable) write [mymethod variableChanged] |
|
$self needleTo [set ::$options(-variable)] |
|
} |
|
} |
|
|
|
# Configure the arrow |
|
method SetArrow {option value} { |
|
switch -- $option { |
|
"-arrowthickness" { |
|
$win.c itemconfigure arrow -width $value |
|
} |
|
"-arrowcolor" { |
|
$win.c itemconfigure arrow -fill $value |
|
} |
|
} |
|
} |
|
|
|
# React to the dragging of the needle |
|
method NewPosition {y tag} { |
|
if { $options(-variable) ne "" } { |
|
set ::$options(-variable) [$axis computeValue $y] |
|
} |
|
} |
|
}
|
|
|