home *** CD-ROM | disk | FTP | other *** search
/ PC World 2000 December / PCWorld_2000-12_cd.bin / Komunikace / Comanche / comanche.exe / lib / iwidgets3.0.0 / scripts / watch.itk < prev   
Text File  |  1999-02-24  |  19KB  |  627 lines

  1. #
  2. # Watch
  3. # ----------------------------------------------------------------------
  4. # Implements a a clock widget in a canvas.
  5. #
  6. # ----------------------------------------------------------------------
  7. #  AUTHOR: John A. Tucker               EMAIL: jatucker@spd.dsccc.com
  8. #
  9. # ======================================================================
  10. #            Copyright (c) 1997 DSC Technologies Corporation
  11. # ======================================================================
  12. # Permission to use, copy, modify, distribute and license this software 
  13. # and its documentation for any purpose, and without fee or written 
  14. # agreement with DSC, is hereby granted, provided that the above copyright 
  15. # notice appears in all copies and that both the copyright notice and 
  16. # warranty disclaimer below appear in supporting documentation, and that 
  17. # the names of DSC Technologies Corporation or DSC Communications 
  18. # Corporation not be used in advertising or publicity pertaining to the 
  19. # software without specific, written prior permission.
  20. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  21. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  22. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  23. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  24. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  25. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  26. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  27. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  28. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  29. # SOFTWARE.
  30. # ======================================================================
  31.  
  32. #
  33. # Default resources.
  34. #
  35. option add *Watch.labelFont        \
  36.     -*-Courier-Medium-R-Normal--*-120-*-*-*-*-*-*    widgetDefault
  37.  
  38. #
  39. # Usual options.
  40. #
  41. itk::usual Watch {
  42.     keep -background -cursor -labelfont -foreground
  43. }
  44.  
  45. class iwidgets::Watch {
  46.  
  47.     inherit itk::Widget
  48.  
  49.     itk_option define -hourradius hourRadius Radius .50
  50.     itk_option define -hourcolor hourColor Color red
  51.  
  52.     itk_option define -minuteradius minuteRadius Radius .80
  53.     itk_option define -minutecolor minuteColor Color yellow
  54.  
  55.     itk_option define -pivotradius pivotRadius Radius .10
  56.     itk_option define -pivotcolor pivotColor Color white
  57.  
  58.     itk_option define -secondradius secondRadius Radius .90
  59.     itk_option define -secondcolor secondColor Color black
  60.  
  61.     itk_option define -clockcolor clockColor Color white
  62.     itk_option define -clockstipple clockStipple ClockStipple {}
  63.  
  64.     itk_option define -state state State normal
  65.     itk_option define -showampm showAmPm ShowAmPm true
  66.  
  67.     itk_option define -tickcolor tickColor Color black
  68.  
  69.     constructor {args} {}
  70.     destructor {}
  71.  
  72.     #
  73.     # Public methods
  74.     #
  75.     public {
  76.     method get {{format "-string"}}
  77.     method show {{time "now"}}
  78.     method watch {args}
  79.     }
  80.  
  81.     #
  82.     # Private methods
  83.     #
  84.     private {
  85.     method _handMotionCB {tag x y}
  86.     method _drawHand {tag}
  87.     method _handReleaseCB {tag x y}
  88.     method _displayClock {{when "later"}}
  89.  
  90.     variable _interior
  91.     variable _radius
  92.     variable _theta
  93.     variable _extent
  94.     variable _reposition ""  ;# non-null => _displayClock pending
  95.     variable _timeVar
  96.     variable _x0 1
  97.     variable _y0 1
  98.  
  99.     common _ampmVar
  100.     common PI [expr 2*asin(1.0)]
  101.     }
  102. }
  103.  
  104. #
  105. # Provide a lowercased access method for the Watch class.
  106. proc ::iwidgets::watch {pathName args} {
  107.     uplevel ::iwidgets::Watch $pathName $args
  108. }
  109.  
  110. #
  111. # Use option database to override default resources of base classes.
  112. #
  113. option add *Watch.width 155 widgetDefault
  114. option add *Watch.height 175 widgetDefault
  115.  
  116. # -----------------------------------------------------------------------------
  117. #                        CONSTRUCTOR
  118. # -----------------------------------------------------------------------------
  119. body iwidgets::Watch::constructor { args } {
  120.     #
  121.     # Add back to the hull width and height options and make the
  122.     # borderwidth zero since we don't need it.
  123.     #
  124.     set _interior $itk_interior
  125.  
  126.     itk_option add hull.width hull.height
  127.     component hull configure -borderwidth 0
  128.     grid propagate $itk_component(hull) no
  129.  
  130.     set _ampmVar($this) "AM"
  131.     set _radius(outer) 1
  132.  
  133.     set _radius(hour) 1
  134.     set _radius(minute) 1
  135.     set _radius(second) 1
  136.  
  137.     set _theta(hour) 30
  138.     set _theta(minute) 6
  139.     set _theta(second) 6
  140.  
  141.     set _extent(hour) 14
  142.     set _extent(minute) 14
  143.     set _extent(second) 2
  144.  
  145.     set _timeVar(hour) 12
  146.     set _timeVar(minute) 0
  147.     set _timeVar(second) 0
  148.  
  149.     #
  150.     # Create the frame in which the "AM" and "PM" radiobuttons will be drawn
  151.     #
  152.     itk_component add frame {
  153.     frame $itk_interior.frame
  154.     } 
  155.  
  156.     #
  157.     # Create the canvas in which the clock will be drawn
  158.     #
  159.     itk_component add canvas {
  160.     canvas $itk_interior.canvas
  161.     }
  162.     bind $itk_component(canvas) <Map> +[code $this _displayClock]
  163.     bind $itk_component(canvas) <Configure> +[code $this _displayClock]
  164.  
  165.     #
  166.     # Create the "AM" and "PM" radiobuttons to be drawn in the canvas
  167.     #
  168.     itk_component add am {
  169.     radiobutton $itk_component(frame).am \
  170.         -text "AM" \
  171.         -value "AM" \
  172.         -variable [scope _ampmVar($this)]
  173.     } {
  174.     usual
  175.     rename -font -labelfont labelFont Font
  176.     }
  177.  
  178.     itk_component add pm {
  179.     radiobutton $itk_component(frame).pm \
  180.         -text "PM" \
  181.         -value "PM" \
  182.         -variable [scope _ampmVar($this)]
  183.     } {
  184.     usual
  185.     rename -font -labelfont labelFont Font
  186.     }
  187.  
  188.     #
  189.     # Create the canvas item for displaying the main oval which encapsulates
  190.     # the entire clock.
  191.     #
  192.     watch create oval 0 0 2 2 -width 5 -tags clock
  193.  
  194.     #
  195.     # Create the canvas items for displaying the 60 ticks marks around the
  196.     # inner perimeter of the watch.
  197.     #
  198.     set extent 3
  199.     for {set i 0} {$i < 60} {incr i} {
  200.     set start [expr $i*6-1]
  201.     set tag [expr {[expr $i%5] == 0 ? "big" : "little"}]
  202.     watch create arc 0 0 0 0 \
  203.         -style arc \
  204.         -extent $extent \
  205.         -start $start \
  206.         -tags "tick$i tick $tag"
  207.     }
  208.  
  209.     #
  210.     # Create the canvas items for displaying the hour, minute, and second hands
  211.     # of the watch.  Add bindings to allow the mouse to move and set the
  212.     # clock hands.
  213.     #
  214.     watch create arc 1 1 1 1 -extent 30 -tags minute
  215.     watch create arc 1 1 1 1 -extent 30 -tags hour
  216.     watch create arc 1 1 1 1 -tags second
  217.  
  218.     #
  219.     # Create the canvas item for displaying the center of the watch in which
  220.     # the hour, minute, and second hands will pivot.
  221.     #
  222.     watch create oval 0 0 1 1 -width 5 -fill black -tags pivot
  223.  
  224.     #
  225.     # Position the "AM/PM" button frame and watch canvas.
  226.     #
  227.     grid $itk_component(frame) -row 0 -column 0 -sticky new
  228.     grid $itk_component(canvas) -row 1 -column 0 -sticky nsew
  229.  
  230.     grid rowconfigure    $itk_interior 0 -weight 0
  231.     grid rowconfigure    $itk_interior 1 -weight 1
  232.     grid columnconfigure $itk_interior 0 -weight 1
  233.  
  234.     eval itk_initialize $args
  235. }
  236.  
  237. # -----------------------------------------------------------------------------
  238. #                           DESTURCTOR
  239. # -----------------------------------------------------------------------------
  240. body iwidgets::Watch::destructor {} {
  241.     if {$_reposition != ""} {
  242.     after cancel $_reposition
  243.     }
  244. }
  245.  
  246. # -----------------------------------------------------------------------------
  247. #                            METHODS
  248. # -----------------------------------------------------------------------------
  249.  
  250. # -----------------------------------------------------------------------------
  251. # METHOD: _handReleaseCB tag x y
  252. #
  253. # -----------------------------------------------------------------------------
  254. body iwidgets::Watch::_handReleaseCB {tag x y} {
  255.  
  256.     set atanab [expr atan2(double($y-$_y0),double($x-$_x0))*(180/$PI)]
  257.     set degrees [expr {$atanab > 0 ? [expr 360-$atanab] : abs($atanab)}]
  258.     set ticks [expr round($degrees/$_theta($tag))]
  259.     set _timeVar($tag) [expr ((450-$ticks*$_theta($tag))%360)/$_theta($tag)]
  260.  
  261.     if {$tag == "hour" && $_timeVar(hour) == 0} {
  262.     set _timeVar($tag) 12
  263.     }
  264.  
  265.     _drawHand $tag
  266. }
  267.  
  268. # -----------------------------------------------------------------------------
  269. # PROTECTED METHOD: _handMotionCB tag x y
  270. #
  271. # -----------------------------------------------------------------------------
  272. body iwidgets::Watch::_handMotionCB {tag x y} {
  273.     if {$x == $_x0 || $y == $_y0} {
  274.     return
  275.     }
  276.  
  277.     set a [expr $y-$_y0]
  278.     set b [expr $x-$_x0]
  279.     set c [expr hypot($a,$b)]
  280.  
  281.     set atanab [expr atan2(double($a),double($b))*(180/$PI)]
  282.     set degrees [expr {$atanab > 0 ? [expr 360-$atanab] : abs($atanab)}]
  283.  
  284.     set x2 [expr $_x0+$_radius($tag)*($b/double($c))]
  285.     set y2 [expr $_y0+$_radius($tag)*($a/double($c))]
  286.     watch coords $tag \
  287.     [expr $x2-$_radius($tag)] \
  288.     [expr $y2-$_radius($tag)] \
  289.     [expr $x2+$_radius($tag)] \
  290.     [expr $y2+$_radius($tag)]
  291.     set start [expr $degrees-180-($_extent($tag)/2)]
  292.     watch itemconfigure $tag -start $start -extent $_extent($tag)
  293. }
  294.  
  295. # -----------------------------------------------------------------------------
  296. # PROTECTED METHOD: get ?format?
  297. #
  298. # -----------------------------------------------------------------------------
  299. body iwidgets::Watch::get {{format "-string"}} {
  300.     set timestr [format "%02d:%02d:%02d %s" \
  301.              $_timeVar(hour) $_timeVar(minute) \
  302.              $_timeVar(second) $_ampmVar($this)]
  303.  
  304.     switch -- $format {
  305.     "-string" {
  306.         return $timestr
  307.     }
  308.     "-clicks" {
  309.         return [clock scan $timestr]
  310.     }
  311.     default {
  312.         error "bad format option \"$format\":\
  313.                    should be -string or -clicks"
  314.     }
  315.     }
  316. }
  317.  
  318. # -----------------------------------------------------------------------------
  319. # METHOD: watch ?args?
  320. #
  321. # Evaluates the specified args against the canvas component.
  322. # -----------------------------------------------------------------------------
  323. body iwidgets::Watch::watch {args} {
  324.     return [eval $itk_component(canvas) $args]
  325. }
  326.  
  327. # -----------------------------------------------------------------------------
  328. # METHOD: _drawHand tag
  329. #
  330. # -----------------------------------------------------------------------------
  331. body iwidgets::Watch::_drawHand {tag} {
  332.  
  333.     set degrees [expr abs(450-($_timeVar($tag)*$_theta($tag)))%360]
  334.     set radians [expr $degrees*($PI/180)]
  335.     set x [expr $_x0+$_radius($tag)*cos($radians)]
  336.     set y [expr $_y0+$_radius($tag)*sin($radians)*(-1)]
  337.     watch coords $tag \
  338.     [expr $x-$_radius($tag)] \
  339.     [expr $y-$_radius($tag)] \
  340.     [expr $x+$_radius($tag)] \
  341.     [expr $y+$_radius($tag)]
  342.     set start [expr $degrees-180-($_extent($tag)/2)]
  343.     watch itemconfigure $tag -start $start
  344. }
  345.  
  346. # ------------------------------------------------------------------
  347. # PUBLIC METHOD: show time
  348. #
  349. # Changes the currently displayed time to be that of the time
  350. # argument.  The time may be specified either as a string or an
  351. # integer clock value.  Reference the clock command for more 
  352. # information on obtaining times and their formats.
  353. # ------------------------------------------------------------------
  354. body iwidgets::Watch::show {{time "now"}} {
  355.     if {$time == "now"} {
  356.     set seconds [clock seconds]
  357.     } elseif {![catch {clock format $time}]} {
  358.     set seconds $time
  359.     } elseif {[catch {set seconds [clock scan $time]}]} {
  360.     error "bad time: \"$time\", must be a valid time\
  361.                string, clock clicks value or the keyword now"
  362.     }
  363.  
  364.     set timestring [clock format $seconds -format "%I %M %S %p"]
  365.     set _timeVar(hour)   [expr int(1[lindex $timestring 0] - 100)]
  366.     set _timeVar(minute) [expr int(1[lindex $timestring 1] - 100)]
  367.     set _timeVar(second) [expr int(1[lindex $timestring 2] - 100)]
  368.     set _ampmVar($this) [lindex $timestring 3]
  369.  
  370.     _drawHand hour
  371.     _drawHand minute
  372.     _drawHand second
  373. }
  374.  
  375. # -----------------------------------------------------------------------------
  376. # PROTECTED METHOD: _displayClock ?when?
  377. #
  378. # Places the hour, minute, and second dials in the canvas.  If "when" is "now",
  379. # the change is applied immediately.  If it is "later" or it is not specified,
  380. # then the change is applied later, when the application is idle.
  381. # -----------------------------------------------------------------------------
  382. body iwidgets::Watch::_displayClock {{when "later"}} {
  383.  
  384.     if {$when == "later"} {
  385.     if {$_reposition == ""} {
  386.         set _reposition [after idle [code $this _displayClock now]]
  387.     }
  388.     return
  389.     }
  390.  
  391.     #
  392.     # Compute the center coordinates for the clock based on the
  393.     # with and height of the canvas.
  394.     #
  395.     set width [winfo width $itk_component(canvas)]
  396.     set height [winfo height $itk_component(canvas)]
  397.     set _x0 [expr $width/2]
  398.     set _y0 [expr $height/2]
  399.  
  400.     #
  401.     # Set the radius of the watch, pivot, hour, minute and second items.
  402.     #
  403.     set _radius(outer) [expr {$_x0 < $_y0 ? $_x0 : $_y0}]
  404.     set _radius(pivot) [expr $itk_option(-pivotradius)*$_radius(outer)]
  405.     set _radius(hour) [expr $itk_option(-hourradius)*$_radius(outer)]
  406.     set _radius(minute) [expr $itk_option(-minuteradius)*$_radius(outer)]
  407.     set _radius(second) [expr $itk_option(-secondradius)*$_radius(outer)]
  408.     set outerWidth [watch itemcget clock -width]
  409.  
  410.     #
  411.     # Set the coordinates of the clock item
  412.     #
  413.     set x1Outer $outerWidth
  414.     set y1Outer $outerWidth
  415.     set x2Outer [expr $width-$outerWidth]
  416.     set y2Outer [expr $height-$outerWidth]
  417.     watch coords clock $x1Outer $y1Outer $x2Outer $y2Outer
  418.  
  419.     #
  420.     # Set the coordinates of the tick items
  421.     #
  422.     set offset [expr $outerWidth*2]
  423.     set x1Tick [expr $x1Outer+$offset]
  424.     set y1Tick [expr $y1Outer+$offset]
  425.     set x2Tick [expr $x2Outer-$offset]
  426.     set y2Tick [expr $y2Outer-$offset]
  427.     for {set i 0} {$i < 60} {incr i} {
  428.     watch coords tick$i $x1Tick $y1Tick $x2Tick $y2Tick
  429.     }
  430.     set maxTickWidth [expr $_radius(outer)-$_radius(second)+1]
  431.     set minTickWidth [expr round($maxTickWidth/2)]
  432.     watch itemconfigure big -width $maxTickWidth
  433.     watch itemconfigure little -width [expr round($maxTickWidth/2)]
  434.  
  435.     #
  436.     # Set the coordinates of the pivot item
  437.     #
  438.     set x1Center [expr $_x0-$_radius(pivot)]
  439.     set y1Center [expr $_y0-$_radius(pivot)]
  440.     set x2Center [expr $_x0+$_radius(pivot)]
  441.     set y2Center [expr $_y0+$_radius(pivot)]
  442.     watch coords pivot $x1Center $y1Center $x2Center $y2Center        
  443.  
  444.     #
  445.     # Set the coordinates of the hour, minute, and second dial items
  446.     #
  447.     watch itemconfigure hour -extent $_extent(hour)
  448.     _drawHand hour
  449.  
  450.     watch itemconfigure minute -extent $_extent(minute)
  451.     _drawHand minute
  452.  
  453.     watch itemconfigure second -extent $_extent(second)
  454.     _drawHand second
  455.  
  456.     set _reposition ""
  457. }
  458.  
  459. # -----------------------------------------------------------------------------
  460. #                             OPTIONS
  461. # -----------------------------------------------------------------------------
  462.  
  463. # ------------------------------------------------------------------
  464. # OPTION: state
  465. #
  466. # Configure the editable state of the widget.  Valid values are
  467. # normal and disabled.  In a disabled state, the hands of the 
  468. # watch are not selectabled.
  469. # ------------------------------------------------------------------
  470. configbody ::iwidgets::Watch::state {
  471.     if {$itk_option(-state) == "normal"} {
  472.     watch bind minute <B1-Motion> \
  473.         [code $this _handMotionCB minute %x %y]
  474.     watch bind minute <ButtonRelease-1> \
  475.         [code $this _handReleaseCB minute %x %y]
  476.  
  477.     watch bind hour <B1-Motion> \
  478.         [code $this _handMotionCB hour %x %y]
  479.     watch bind hour <ButtonRelease-1> \
  480.         [code $this _handReleaseCB hour %x %y]
  481.  
  482.     watch bind second <B1-Motion> \
  483.         [code $this _handMotionCB second %x %y]
  484.     watch bind second <ButtonRelease-1> \
  485.         [code $this _handReleaseCB second %x %y]
  486.  
  487.     $itk_component(am) configure -state normal
  488.     $itk_component(pm) configure -state normal
  489.  
  490.     } elseif {$itk_option(-state) == "disabled"} {
  491.     watch bind minute <B1-Motion> {}
  492.     watch bind minute <ButtonRelease-1> {}
  493.  
  494.     watch bind hour <B1-Motion> {}
  495.     watch bind hour <ButtonRelease-1> {}
  496.  
  497.     watch bind second <B1-Motion> {}
  498.     watch bind second <ButtonRelease-1> {}
  499.  
  500.     $itk_component(am) configure -state disabled \
  501.         -disabledforeground [$itk_component(am) cget -background]
  502.     $itk_component(pm) configure -state normal \
  503.         -disabledforeground [$itk_component(am) cget -background]
  504.  
  505.     } else {
  506.     error "bad state option \"$itk_option(-state)\":\
  507.                    should be normal or disabled"
  508.     }
  509. }
  510.  
  511. # ------------------------------------------------------------------
  512. # OPTION: showampm
  513. #
  514. # Configure the display of the AM/PM radio buttons.
  515. # ------------------------------------------------------------------
  516. configbody ::iwidgets::Watch::showampm {
  517.     switch -- $itk_option(-showampm) {
  518.         0 - no - false - off { 
  519.         pack forget $itk_component(am)
  520.         pack forget $itk_component(pm)
  521.     }
  522.  
  523.         1 - yes - true - on { 
  524.         pack $itk_component(am) -side left -fill both -expand 1
  525.         pack $itk_component(pm) -side right -fill both -expand 1 
  526.     }
  527.  
  528.         default {
  529.             error "bad showampm option \"$itk_option(-showampm)\":\
  530.                    should be boolean"
  531.         }
  532.     }
  533. }
  534.  
  535. # ------------------------------------------------------------------
  536. # OPTION: pivotcolor
  537. #
  538. # Configure the color of the clock pivot.
  539. #
  540. configbody ::iwidgets::Watch::pivotcolor {
  541.     watch itemconfigure pivot -fill $itk_option(-pivotcolor)
  542. }
  543.  
  544. # ------------------------------------------------------------------
  545. # OPTION: clockstipple
  546. #
  547. # Configure the stipple pattern for the clock fill color.
  548. #
  549. configbody ::iwidgets::Watch::clockstipple {
  550.     watch itemconfigure clock -stipple $itk_option(-clockstipple)
  551. }
  552.  
  553. # ------------------------------------------------------------------
  554. # OPTION: clockcolor
  555. #
  556. # Configure the color of the clock.
  557. #
  558. configbody ::iwidgets::Watch::clockcolor {
  559.     watch itemconfigure clock -fill $itk_option(-clockcolor)
  560. }
  561.  
  562. # ------------------------------------------------------------------
  563. # OPTION: hourcolor
  564. #
  565. # Configure the color of the hour hand.
  566. #
  567. configbody ::iwidgets::Watch::hourcolor {
  568.     watch itemconfigure hour -fill $itk_option(-hourcolor)
  569. }
  570.  
  571. # ------------------------------------------------------------------
  572. # OPTION: minutecolor
  573. #
  574. # Configure the color of the minute hand.
  575. #
  576. configbody ::iwidgets::Watch::minutecolor {
  577.     watch itemconfigure minute -fill $itk_option(-minutecolor)
  578. }
  579.  
  580. # ------------------------------------------------------------------
  581. # OPTION: secondcolor
  582. #
  583. # Configure the color of the second hand.
  584. #
  585. configbody ::iwidgets::Watch::secondcolor {
  586.     watch itemconfigure second -fill $itk_option(-secondcolor)
  587. }
  588.  
  589. # ------------------------------------------------------------------
  590. # OPTION: tickcolor
  591. #
  592. # Configure the color of the ticks.
  593. #
  594. configbody ::iwidgets::Watch::tickcolor {
  595.     watch itemconfigure tick -fill $itk_option(-tickcolor)
  596. }
  597.  
  598. # ------------------------------------------------------------------
  599. # OPTION: hourradius
  600. #
  601. # Configure the radius of the hour hand.
  602. #
  603. configbody ::iwidgets::Watch::hourradius {
  604.     _displayClock
  605. }
  606.  
  607. # ------------------------------------------------------------------
  608. # OPTION: minuteradius
  609. #
  610. # Configure the radius of the minute hand.
  611. #
  612. configbody ::iwidgets::Watch::minuteradius {
  613.     _displayClock
  614. }
  615.  
  616. # ------------------------------------------------------------------
  617. # OPTION: secondradius
  618. #
  619. # Configure the radius of the second hand.
  620. #
  621. configbody ::iwidgets::Watch::secondradius {
  622.     _displayClock
  623. }
  624.  
  625.