diff options
Diffstat (limited to 'itcl/iwidgets/generic/watch.itk')
-rw-r--r-- | itcl/iwidgets/generic/watch.itk | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/itcl/iwidgets/generic/watch.itk b/itcl/iwidgets/generic/watch.itk new file mode 100644 index 00000000000..ace2cc94655 --- /dev/null +++ b/itcl/iwidgets/generic/watch.itk @@ -0,0 +1,626 @@ +# +# Watch +# ---------------------------------------------------------------------- +# Implements a a clock widget in a canvas. +# +# ---------------------------------------------------------------------- +# AUTHOR: John A. Tucker EMAIL: jatucker@spd.dsccc.com +# +# ====================================================================== +# Copyright (c) 1997 DSC Technologies Corporation +# ====================================================================== +# Permission to use, copy, modify, distribute and license this software +# and its documentation for any purpose, and without fee or written +# agreement with DSC, is hereby granted, provided that the above copyright +# notice appears in all copies and that both the copyright notice and +# warranty disclaimer below appear in supporting documentation, and that +# the names of DSC Technologies Corporation or DSC Communications +# Corporation not be used in advertising or publicity pertaining to the +# software without specific, written prior permission. +# +# DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON- +# INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE +# AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, +# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL +# DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, +# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +# SOFTWARE. +# ====================================================================== + +# +# Default resources. +# +option add *Watch.labelFont \ + -*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-* widgetDefault + +# +# Usual options. +# +itk::usual Watch { + keep -background -cursor -labelfont -foreground +} + +itcl::class iwidgets::Watch { + + inherit itk::Widget + + itk_option define -hourradius hourRadius Radius .50 + itk_option define -hourcolor hourColor Color red + + itk_option define -minuteradius minuteRadius Radius .80 + itk_option define -minutecolor minuteColor Color yellow + + itk_option define -pivotradius pivotRadius Radius .10 + itk_option define -pivotcolor pivotColor Color white + + itk_option define -secondradius secondRadius Radius .90 + itk_option define -secondcolor secondColor Color black + + itk_option define -clockcolor clockColor Color white + itk_option define -clockstipple clockStipple ClockStipple {} + + itk_option define -state state State normal + itk_option define -showampm showAmPm ShowAmPm true + + itk_option define -tickcolor tickColor Color black + + constructor {args} {} + destructor {} + + # + # Public methods + # + public { + method get {{format "-string"}} + method show {{time "now"}} + method watch {args} + } + + # + # Private methods + # + private { + method _handMotionCB {tag x y} + method _drawHand {tag} + method _handReleaseCB {tag x y} + method _displayClock {{when "later"}} + + variable _interior + variable _radius + variable _theta + variable _extent + variable _reposition "" ;# non-null => _displayClock pending + variable _timeVar + variable _x0 1 + variable _y0 1 + + common _ampmVar + common PI [expr {2*asin(1.0)}] + } +} + +# +# Provide a lowercased access method for the Watch class. +# +proc ::iwidgets::watch {pathName args} { + uplevel ::iwidgets::Watch $pathName $args +} + +# +# Use option database to override default resources of base classes. +# +option add *Watch.width 155 widgetDefault +option add *Watch.height 175 widgetDefault + +# ----------------------------------------------------------------------------- +# CONSTRUCTOR +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::constructor { args } { + # + # Add back to the hull width and height options and make the + # borderwidth zero since we don't need it. + # + set _interior $itk_interior + + itk_option add hull.width hull.height + component hull configure -borderwidth 0 + grid propagate $itk_component(hull) no + + set _ampmVar($this) "AM" + set _radius(outer) 1 + + set _radius(hour) 1 + set _radius(minute) 1 + set _radius(second) 1 + + set _theta(hour) 30 + set _theta(minute) 6 + set _theta(second) 6 + + set _extent(hour) 14 + set _extent(minute) 14 + set _extent(second) 2 + + set _timeVar(hour) 12 + set _timeVar(minute) 0 + set _timeVar(second) 0 + + # + # Create the frame in which the "AM" and "PM" radiobuttons will be drawn + # + itk_component add frame { + frame $itk_interior.frame + } + + # + # Create the canvas in which the clock will be drawn + # + itk_component add canvas { + canvas $itk_interior.canvas + } + bind $itk_component(canvas) <Map> +[itcl::code $this _displayClock] + bind $itk_component(canvas) <Configure> +[itcl::code $this _displayClock] + + # + # Create the "AM" and "PM" radiobuttons to be drawn in the canvas + # + itk_component add am { + radiobutton $itk_component(frame).am \ + -text "AM" \ + -value "AM" \ + -variable [itcl::scope _ampmVar($this)] + } { + usual + rename -font -labelfont labelFont Font + } + + itk_component add pm { + radiobutton $itk_component(frame).pm \ + -text "PM" \ + -value "PM" \ + -variable [itcl::scope _ampmVar($this)] + } { + usual + rename -font -labelfont labelFont Font + } + + # + # Create the canvas item for displaying the main oval which encapsulates + # the entire clock. + # + watch create oval 0 0 2 2 -width 5 -tags clock + + # + # Create the canvas items for displaying the 60 ticks marks around the + # inner perimeter of the watch. + # + set extent 3 + for {set i 0} {$i < 60} {incr i} { + set start [expr {$i*6-1}] + set tag [expr {[expr {$i%5}] == 0 ? "big" : "little"}] + watch create arc 0 0 0 0 \ + -style arc \ + -extent $extent \ + -start $start \ + -tags "tick$i tick $tag" + } + + # + # Create the canvas items for displaying the hour, minute, and second hands + # of the watch. Add bindings to allow the mouse to move and set the + # clock hands. + # + watch create arc 1 1 1 1 -extent 30 -tags minute + watch create arc 1 1 1 1 -extent 30 -tags hour + watch create arc 1 1 1 1 -tags second + + # + # Create the canvas item for displaying the center of the watch in which + # the hour, minute, and second hands will pivot. + # + watch create oval 0 0 1 1 -width 5 -fill black -tags pivot + + # + # Position the "AM/PM" button frame and watch canvas. + # + grid $itk_component(frame) -row 0 -column 0 -sticky new + grid $itk_component(canvas) -row 1 -column 0 -sticky nsew + + grid rowconfigure $itk_interior 0 -weight 0 + grid rowconfigure $itk_interior 1 -weight 1 + grid columnconfigure $itk_interior 0 -weight 1 + + eval itk_initialize $args +} + +# ----------------------------------------------------------------------------- +# DESTURCTOR +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::destructor {} { + if {$_reposition != ""} { + after cancel $_reposition + } +} + +# ----------------------------------------------------------------------------- +# METHODS +# ----------------------------------------------------------------------------- + +# ----------------------------------------------------------------------------- +# METHOD: _handReleaseCB tag x y +# +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::_handReleaseCB {tag x y} { + + set atanab [expr {atan2(double($y-$_y0),double($x-$_x0))*(180/$PI)}] + set degrees [expr {$atanab > 0 ? [expr {360-$atanab}] : abs($atanab)}] + set ticks [expr {round($degrees/$_theta($tag))}] + set _timeVar($tag) [expr {((450-$ticks*$_theta($tag))%360)/$_theta($tag)}] + + if {$tag == "hour" && $_timeVar(hour) == 0} { + set _timeVar($tag) 12 + } + + _drawHand $tag +} + +# ----------------------------------------------------------------------------- +# PROTECTED METHOD: _handMotionCB tag x y +# +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::_handMotionCB {tag x y} { + if {$x == $_x0 || $y == $_y0} { + return + } + + set a [expr {$y-$_y0}] + set b [expr {$x-$_x0}] + set c [expr {hypot($a,$b)}] + + set atanab [expr {atan2(double($a),double($b))*(180/$PI)}] + set degrees [expr {$atanab > 0 ? [expr 360-$atanab] : abs($atanab)}] + + set x2 [expr {$_x0+$_radius($tag)*($b/double($c))}] + set y2 [expr {$_y0+$_radius($tag)*($a/double($c))}] + watch coords $tag \ + [expr {$x2-$_radius($tag)}] \ + [expr {$y2-$_radius($tag)}] \ + [expr {$x2+$_radius($tag)}] \ + [expr {$y2+$_radius($tag)}] + set start [expr {$degrees-180-($_extent($tag)/2)}] + watch itemconfigure $tag -start $start -extent $_extent($tag) +} + +# ----------------------------------------------------------------------------- +# PROTECTED METHOD: get ?format? +# +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::get {{format "-string"}} { + set timestr [format "%02d:%02d:%02d %s" \ + $_timeVar(hour) $_timeVar(minute) \ + $_timeVar(second) $_ampmVar($this)] + + switch -- $format { + "-string" { + return $timestr + } + "-clicks" { + return [clock scan $timestr] + } + default { + error "bad format option \"$format\":\ + should be -string or -clicks" + } + } +} + +# ----------------------------------------------------------------------------- +# METHOD: watch ?args? +# +# Evaluates the specified args against the canvas component. +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::watch {args} { + return [eval $itk_component(canvas) $args] +} + +# ----------------------------------------------------------------------------- +# METHOD: _drawHand tag +# +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::_drawHand {tag} { + + set degrees [expr {abs(450-($_timeVar($tag)*$_theta($tag)))%360}] + set radians [expr {$degrees*($PI/180)}] + set x [expr {$_x0+$_radius($tag)*cos($radians)}] + set y [expr {$_y0+$_radius($tag)*sin($radians)*(-1)}] + watch coords $tag \ + [expr {$x-$_radius($tag)}] \ + [expr {$y-$_radius($tag)}] \ + [expr {$x+$_radius($tag)}] \ + [expr {$y+$_radius($tag)}] + set start [expr {$degrees-180-($_extent($tag)/2)}] + watch itemconfigure $tag -start $start +} + +# ------------------------------------------------------------------ +# PUBLIC METHOD: show time +# +# Changes the currently displayed time to be that of the time +# argument. The time may be specified either as a string or an +# integer clock value. Reference the clock command for more +# information on obtaining times and their formats. +# ------------------------------------------------------------------ +itcl::body iwidgets::Watch::show {{time "now"}} { + if {$time == "now"} { + set seconds [clock seconds] + } elseif {![catch {clock format $time}]} { + set seconds $time + } elseif {[catch {set seconds [clock scan $time]}]} { + error "bad time: \"$time\", must be a valid time\ + string, clock clicks value or the keyword now" + } + + set timestring [clock format $seconds -format "%I %M %S %p"] + set _timeVar(hour) [expr int(1[lindex $timestring 0] - 100)] + set _timeVar(minute) [expr int(1[lindex $timestring 1] - 100)] + set _timeVar(second) [expr int(1[lindex $timestring 2] - 100)] + set _ampmVar($this) [lindex $timestring 3] + + _drawHand hour + _drawHand minute + _drawHand second +} + +# ----------------------------------------------------------------------------- +# PROTECTED METHOD: _displayClock ?when? +# +# Places the hour, minute, and second dials in the canvas. If "when" is "now", +# the change is applied immediately. If it is "later" or it is not specified, +# then the change is applied later, when the application is idle. +# ----------------------------------------------------------------------------- +itcl::body iwidgets::Watch::_displayClock {{when "later"}} { + + if {$when == "later"} { + if {$_reposition == ""} { + set _reposition [after idle [itcl::code $this _displayClock now]] + } + return + } + + # + # Compute the center coordinates for the clock based on the + # with and height of the canvas. + # + set width [winfo width $itk_component(canvas)] + set height [winfo height $itk_component(canvas)] + set _x0 [expr {$width/2}] + set _y0 [expr {$height/2}] + + # + # Set the radius of the watch, pivot, hour, minute and second items. + # + set _radius(outer) [expr {$_x0 < $_y0 ? $_x0 : $_y0}] + set _radius(pivot) [expr {$itk_option(-pivotradius)*$_radius(outer)}] + set _radius(hour) [expr {$itk_option(-hourradius)*$_radius(outer)}] + set _radius(minute) [expr {$itk_option(-minuteradius)*$_radius(outer)}] + set _radius(second) [expr {$itk_option(-secondradius)*$_radius(outer)}] + set outerWidth [watch itemcget clock -width] + + # + # Set the coordinates of the clock item + # + set x1Outer $outerWidth + set y1Outer $outerWidth + set x2Outer [expr {$width-$outerWidth}] + set y2Outer [expr {$height-$outerWidth}] + watch coords clock $x1Outer $y1Outer $x2Outer $y2Outer + + # + # Set the coordinates of the tick items + # + set offset [expr {$outerWidth*2}] + set x1Tick [expr {$x1Outer+$offset}] + set y1Tick [expr {$y1Outer+$offset}] + set x2Tick [expr {$x2Outer-$offset}] + set y2Tick [expr {$y2Outer-$offset}] + for {set i 0} {$i < 60} {incr i} { + watch coords tick$i $x1Tick $y1Tick $x2Tick $y2Tick + } + set maxTickWidth [expr {$_radius(outer)-$_radius(second)+1}] + set minTickWidth [expr {round($maxTickWidth/2)}] + watch itemconfigure big -width $maxTickWidth + watch itemconfigure little -width [expr {round($maxTickWidth/2)}] + + # + # Set the coordinates of the pivot item + # + set x1Center [expr {$_x0-$_radius(pivot)}] + set y1Center [expr {$_y0-$_radius(pivot)}] + set x2Center [expr {$_x0+$_radius(pivot)}] + set y2Center [expr {$_y0+$_radius(pivot)}] + watch coords pivot $x1Center $y1Center $x2Center $y2Center + + # + # Set the coordinates of the hour, minute, and second dial items + # + watch itemconfigure hour -extent $_extent(hour) + _drawHand hour + + watch itemconfigure minute -extent $_extent(minute) + _drawHand minute + + watch itemconfigure second -extent $_extent(second) + _drawHand second + + set _reposition "" +} + +# ----------------------------------------------------------------------------- +# OPTIONS +# ----------------------------------------------------------------------------- + +# ------------------------------------------------------------------ +# OPTION: state +# +# Configure the editable state of the widget. Valid values are +# normal and disabled. In a disabled state, the hands of the +# watch are not selectabled. +# ------------------------------------------------------------------ +itcl::configbody ::iwidgets::Watch::state { + if {$itk_option(-state) == "normal"} { + watch bind minute <B1-Motion> \ + [itcl::code $this _handMotionCB minute %x %y] + watch bind minute <ButtonRelease-1> \ + [itcl::code $this _handReleaseCB minute %x %y] + + watch bind hour <B1-Motion> \ + [itcl::code $this _handMotionCB hour %x %y] + watch bind hour <ButtonRelease-1> \ + [itcl::code $this _handReleaseCB hour %x %y] + + watch bind second <B1-Motion> \ + [itcl::code $this _handMotionCB second %x %y] + watch bind second <ButtonRelease-1> \ + [itcl::code $this _handReleaseCB second %x %y] + + $itk_component(am) configure -state normal + $itk_component(pm) configure -state normal + + } elseif {$itk_option(-state) == "disabled"} { + watch bind minute <B1-Motion> {} + watch bind minute <ButtonRelease-1> {} + + watch bind hour <B1-Motion> {} + watch bind hour <ButtonRelease-1> {} + + watch bind second <B1-Motion> {} + watch bind second <ButtonRelease-1> {} + + $itk_component(am) configure -state disabled \ + -disabledforeground [$itk_component(am) cget -background] + $itk_component(pm) configure -state normal \ + -disabledforeground [$itk_component(am) cget -background] + + } else { + error "bad state option \"$itk_option(-state)\":\ + should be normal or disabled" + } +} + +# ------------------------------------------------------------------ +# OPTION: showampm +# +# Configure the display of the AM/PM radio buttons. +# ------------------------------------------------------------------ +itcl::configbody ::iwidgets::Watch::showampm { + switch -- $itk_option(-showampm) { + 0 - no - false - off { + pack forget $itk_component(am) + pack forget $itk_component(pm) + } + + 1 - yes - true - on { + pack $itk_component(am) -side left -fill both -expand 1 + pack $itk_component(pm) -side right -fill both -expand 1 + } + + default { + error "bad showampm option \"$itk_option(-showampm)\":\ + should be boolean" + } + } +} + +# ------------------------------------------------------------------ +# OPTION: pivotcolor +# +# Configure the color of the clock pivot. +# +itcl::configbody ::iwidgets::Watch::pivotcolor { + watch itemconfigure pivot -fill $itk_option(-pivotcolor) +} + +# ------------------------------------------------------------------ +# OPTION: clockstipple +# +# Configure the stipple pattern for the clock fill color. +# +itcl::configbody ::iwidgets::Watch::clockstipple { + watch itemconfigure clock -stipple $itk_option(-clockstipple) +} + +# ------------------------------------------------------------------ +# OPTION: clockcolor +# +# Configure the color of the clock. +# +itcl::configbody ::iwidgets::Watch::clockcolor { + watch itemconfigure clock -fill $itk_option(-clockcolor) +} + +# ------------------------------------------------------------------ +# OPTION: hourcolor +# +# Configure the color of the hour hand. +# +itcl::configbody ::iwidgets::Watch::hourcolor { + watch itemconfigure hour -fill $itk_option(-hourcolor) +} + +# ------------------------------------------------------------------ +# OPTION: minutecolor +# +# Configure the color of the minute hand. +# +itcl::configbody ::iwidgets::Watch::minutecolor { + watch itemconfigure minute -fill $itk_option(-minutecolor) +} + +# ------------------------------------------------------------------ +# OPTION: secondcolor +# +# Configure the color of the second hand. +# +itcl::configbody ::iwidgets::Watch::secondcolor { + watch itemconfigure second -fill $itk_option(-secondcolor) +} + +# ------------------------------------------------------------------ +# OPTION: tickcolor +# +# Configure the color of the ticks. +# +itcl::configbody ::iwidgets::Watch::tickcolor { + watch itemconfigure tick -outline $itk_option(-tickcolor) +} + +# ------------------------------------------------------------------ +# OPTION: hourradius +# +# Configure the radius of the hour hand. +# +itcl::configbody ::iwidgets::Watch::hourradius { + _displayClock +} + +# ------------------------------------------------------------------ +# OPTION: minuteradius +# +# Configure the radius of the minute hand. +# +itcl::configbody ::iwidgets::Watch::minuteradius { + _displayClock +} + +# ------------------------------------------------------------------ +# OPTION: secondradius +# +# Configure the radius of the second hand. +# +itcl::configbody ::iwidgets::Watch::secondradius { + _displayClock +} + |