# ACTIVESTATE TEAPOT-PKG BEGIN TM -*- tcl -*- # -- Tcl Module # @@ Meta Begin # Package tachometer 0.1 # Meta as::build::date 2015-05-26 # Meta as::origin http://sourceforge.net/projects/tcllib # Meta license BSD # Meta platform tcl # Meta require {Tcl 8.5} # Meta require {Tk 8.5} # Meta require snit # @@ Meta End # ACTIVESTATE TEAPOT-PKG BEGIN DECLARE package provide tachometer 0.1 # ACTIVESTATE TEAPOT-PKG END DECLARE # ACTIVESTATE TEAPOT-PKG END TM # tachometer.tcl -- # # Adapted by Arjen Markus (snitified), july 2010 # # TODO: # motion through the start and end - it can jump through the gap # scaling (scale widget) # deal with sizes of the widget (aspect ratio != 1) # # # Part of: The TCL'ers Wiki # Contents: a tachometer-like widget # Date: Fri Jun 13, 2003 # # Abstract # # # # Copyright (c) 2003 Marco Maggi # # The author hereby grant permission to use, copy, modify, distribute, # and license this software and its documentation for any purpose, # provided that existing copyright notices are retained in all copies # and that this notice is included verbatim in any distributions. No # written agreement, license, or royalty fee is required for any of the # authorized uses. Modifications to this software may be copyrighted by # their authors and need not follow the licensing terms described here, # provided that the new terms are clearly indicated on the first page of # each file where they apply. # # IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY # DERIVATIVES THEREOF, EVEN IF THE AUTHOR HAVE BEEN ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # # THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND # NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, # AND THE AUTHOR AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # # $Id: tachometer.tcl,v 1.4 2010/09/10 17:16:29 andreas_kupries Exp $ # package require Tk 8.5 package require snit package provide tachometer 0.1 namespace eval controlwidget { namespace export tachometer } # tachometer -- # Tachometer-like widget # snit::widget controlwidget::tachometer { # # widget default values # option -borderwidth -default 1 option -title -default speed option -labels -default {} option -resolution -default 1 option -showvalue -default 1 option -variable -default {} -configuremethod VariableName option -min -default 0.0 option -max -default 100.0 option -dangerlevel -default 90.0 option -dangercolor -default red option -dangerwidth -default 3m option -dialcolor -default white option -pincolor -default red option -indexid -default {} option -background -default gray option -width -default 50m option -height -default 50m option -foreground -default black option -highlightthickness -default 0 option -relief -default raised variable pi [expr {3.14159265359/180.0}] variable xc variable yc variable motion constructor args { # # Configure the widget # $self configurelist $args canvas $win.c -background $options(-background) -width $options(-width) -height $options(-height) \ -relief $options(-relief) -borderwidth $options(-borderwidth) grid $win.c -sticky news if {$options(-variable) ne ""} { trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)] } # # Draw the tachometer # set width [$win.c cget -width] set height [$win.c cget -height] set num [llength $options(-labels)] set delta [expr {(360.0-40.0)/($num-1)}] # display set x1 [expr {$width/50.0*2.0}] set y1 [expr {$width/50.0*2.0}] set x2 [expr {$width/50.0*48.0}] set y2 [expr {$width/50.0*48.0}] $win.c create oval $x1 $y1 $x2 $y2 -fill $options(-dialcolor) -width 1 -outline lightgray shadowcircle $win.c $x1 $y1 $x2 $y2 40 0.7m 135.0 # pin set x1 [expr {$width/50.0*23.0}] set y1 [expr {$width/50.0*23.0}] set x2 [expr {$width/50.0*27.0}] set y2 [expr {$width/50.0*27.0}] $win.c create oval $x1 $y1 $x2 $y2 -width 1 -outline lightgray -fill $options(-pincolor) shadowcircle $win.c $x1 $y1 $x2 $y2 40 0.7m -45.0 # danger marker if { $options(-dangerlevel) != {} && $options(-dangerlevel) < $options(-max)} { set deltadanger [expr {(360.0-40.0)*($options(-max)-$options(-dangerlevel))/(1.0*$options(-max)-$options(-min))}] # Transform the thickness into a plain number (if given in mm for instance) set id [$win.c create line 0 0 1 0] $win.c move $id $options(-dangerwidth) 0 set coords [$win.c coords $id] set thickness [expr {[lindex $coords 0]/2.0}] $win.c delete $id # Create the arc for the danger level $win.c create arc \ [expr {$width/50.0*4.0+$thickness}] [expr {$width/50.0*4.0+$thickness}] \ [expr {$width/50.0*46.0-$thickness}] [expr {$width/50.0*46.0-$thickness}] \ -start -70 -extent $deltadanger -style arc \ -outline $options(-dangercolor) -fill $options(-dangercolor) -width $options(-dangerwidth) } # graduate line set x1 [expr {$width/50.0*4.0}] set y1 [expr {$width/50.0*4.0}] set x2 [expr {$width/50.0*46.0}] set y2 [expr {$width/50.0*46.0}] $win.c create arc $x1 $y1 $x2 $y2 \ -start -70 -extent 320 -style arc \ -outline black -width 0.5m set xc [expr {($x2+$x1)/2.0}] set yc [expr {($y2+$y1)/2.0}] set motion 0 bind $win.c [list $self needleRelease %W] bind $win.c [list $self needleMotion %W %x %y] set half [expr {$width/2.0}] set l1 [expr {$half*0.85}] set l2 [expr {$half*0.74}] set l3 [expr {$half*0.62}] set angle 110.0 for {set i 0} {$i < $num} {incr i} \ { set a [expr {($angle+$delta*$i)*$pi}] set x1 [expr {$half+$l1*cos($a)}] set y1 [expr {$half+$l1*sin($a)}] set x2 [expr {$half+$l2*cos($a)}] set y2 [expr {$half+$l2*sin($a)}] $win.c create line $x1 $y1 $x2 $y2 -fill black -width 0.5m set x1 [expr {$half+$l3*cos($a)}] set y1 [expr {$half+$l3*sin($a)}] set label [lindex $options(-labels) $i] if { [string length $label] } \ { $win.c create text $x1 $y1 \ -anchor center -justify center -fill black \ -text $label -font { Helvetica 10 } } } rivet $win.c 10 10 rivet $win.c [expr {$width-10}] 10 rivet $win.c 10 [expr {$height-10}] rivet $win.c [expr {$width-10}] [expr {$height-10}] set value 0 $self drawline $win $value } method destructor { widget } \ { set varname [option get $widget varname {}] trace remove variable $varname write \ [namespace code "tracer $widget $varname"] } # # public methods -- # method set {newValue} { if { $options(-variable) != "" } { set ::$options(-variable) $newValue ;#! This updates the dial too } else { set options(-value) $newValue $self draw $win.c $options(-value) } } method get {} { return $options(-value) } # # private methods -- # 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 tracer $options(-variable)] } # Set new trace if appropriate and update value. set options(-variable) $name if {$options(-variable) ne ""} { trace add variable ::$options(-variable) write [mymethod tracer $options(-variable)] $self drawline $win.c [set ::$options(-variable)] } } method tracer { varname args } \ { set options(-value) [set ::$varname] $self drawline $win [set ::$varname] } method drawline { widget value } \ { set c $widget.c set min $options(-min) set max $options(-max) set id $options(-indexid) set v [expr { ($value <= ($max*1.02))? $value : ($max*1.02) }] set angle [expr {((($v-$min)/($max-$min))*320.0+20.0)*$pi}] set width [$c cget -width] set half [expr {$width/2.0}] set length [expr {$half*0.8}] set xl [expr {$half-$length*sin($angle)}] set yl [expr {$half+$length*cos($angle)}] set xs [expr {$half+0.2*$length*sin($angle)}] set ys [expr {$half-0.2*$length*cos($angle)}] catch {$c delete $id} set id [$c create line $xs $ys $xl $yl -fill $options(-pincolor) -width 0.6m] $c bind $id [list $self needlePress %W] set options(-indexid) $id } method needlePress {w} \ { set motion 1 } method needleRelease {w} \ { set motion 0 } method needleMotion {w x y} \ { if {! $motion} { return } if {$y == $yc && $x == $xc} { return } # # Compute the angle with the positive y-axis - easier to examine! # set angle [expr {atan2($xc - $x,$yc - $y) / $pi}] if { $angle >= 160.0 } { set angle 160.0 } if { $angle < -160.0 } { set angle -160.0 } set ::$options(-variable) [expr {$options(-min) + ($options(-max)-$options(-min))*(160.0-$angle) / 320.0}] } proc rivet { c xc yc } \ { set width 5 set bevel 0.5m set angle -45.0 set ticks 7 shadowcircle $c \ [expr {$xc-$width}] [expr {$yc-$width}] [expr {$xc+$width}] [expr {$yc+$width}] \ $ticks $bevel $angle } proc shadowcircle { canvas x1 y1 x2 y2 ticks width orient } \ { set angle $orient set delta [expr {180.0/$ticks}] for {set i 0} {$i <= $ticks} {incr i} \ { set a [expr {($angle+$i*$delta)}] set b [expr {($angle-$i*$delta)}] set color [expr {40+$i*(200/$ticks)}] set color [format "#%x%x%x" $color $color $color] $canvas create arc $x1 $y1 $x2 $y2 -start $a -extent $delta \ -style arc -outline $color -width $width $canvas create arc $x1 $y1 $x2 $y2 -start $b -extent $delta \ -style arc -outline $color -width $width } } } if {0} { # main -- # Demonstration of the tachometer object # proc main { argc argv } \ { global forever wm withdraw . wm title . "A tachometer-like widget" wm geometry . +10+10 controlwidget::tachometer .t1 -variable ::value1 -labels { 0 10 20 30 40 50 60 70 80 90 100 } \ -pincolor green -dialcolor lightpink scale .s1 -command "set ::value1" -variable ::value1 # # Note: the labels are not used in the scaling of the values # controlwidget::tachometer .t2 -variable ::value2 -labels { 0 {} {} 5 {} {} 10 } -width 100m -height 100m \ -min 0 -max 10 -dangerlevel 3 scale .s2 -command "set ::value2" -variable ::value2 -from 0 -to 10 button .b -text Quit -command "set ::forever 1" grid .t1 .s1 .t2 .s2 .b -padx 2 -pady 2 wm deiconify . console show vwait forever #tachometer::destructor .t1 #tachometer::destructor .t2 exit 0 } main $argc $argv } ### end of file # Local Variables: # mode: tcl # page-delimiter: "^#PAGE" # End: