home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / timefield.itk < prev    next >
Text File  |  2003-09-01  |  31KB  |  1,019 lines

  1. #
  2. # Timefield
  3. # ----------------------------------------------------------------------
  4. # Implements a time entry field with adjustable built-in intelligence
  5. # levels.
  6. # ----------------------------------------------------------------------
  7. #   AUTHOR:  John A. Tucker          E-mail: jatucker@austin.dsccc.com
  8. #
  9. #   @(#) $Id: timefield.itk,v 1.6 2001/08/17 19:05:44 smithc Exp $
  10. # ----------------------------------------------------------------------
  11. #            Copyright (c) 1997 DSC Technologies Corporation
  12. # ======================================================================
  13. # Permission to use, copy, modify, distribute and license this software 
  14. # and its documentation for any purpose, and without fee or written 
  15. # agreement with DSC, is hereby granted, provided that the above copyright 
  16. # notice appears in all copies and that both the copyright notice and 
  17. # warranty disclaimer below appear in supporting documentation, and that 
  18. # the names of DSC Technologies Corporation or DSC Communications 
  19. # Corporation not be used in advertising or publicity pertaining to the 
  20. # software without specific, written prior permission.
  21. # DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
  22. # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
  23. # INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
  24. # AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
  25. # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
  26. # DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
  27. # ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
  28. # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
  29. # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
  30. # SOFTWARE.
  31. # ======================================================================
  32.  
  33. #
  34. # Use option database to override default resources of base classes.
  35. #
  36. option add *Timefield.justify center widgetDefault
  37.  
  38.  
  39. #
  40. # Usual options.
  41. #
  42. itk::usual Timefield {
  43.     keep -background -borderwidth -cursor -foreground -highlightcolor \
  44.        -highlightthickness -labelfont -textbackground -textfont
  45. }
  46.  
  47. # ------------------------------------------------------------------
  48. #                               TIMEFIELD
  49. # ------------------------------------------------------------------
  50. itcl::class iwidgets::Timefield {
  51.  
  52.     inherit iwidgets::Labeledwidget 
  53.     
  54.     constructor {args} {}
  55.  
  56.     itk_option define -childsitepos childSitePos Position e
  57.     itk_option define -command command Command {}
  58.     itk_option define -seconds seconds Seconds on
  59.     itk_option define -format format Format civilian
  60.     itk_option define -iq iq Iq high
  61.     itk_option define -gmt gmt GMT no
  62.     itk_option define -state state State normal
  63.  
  64.     public {
  65.       method get {{format "-string"}}
  66.       method isvalid {}
  67.       method show {{time "now"}}
  68.     }
  69.  
  70.     protected {
  71.       method _backwardCivilian {}
  72.       method _backwardMilitary {}
  73.       method _focusIn {}
  74.       method _forwardCivilian {}
  75.       method _forwardMilitary {}
  76.       method _keyPress {char sym state}
  77.       method _moveField {direction}
  78.       method _setField {field}
  79.       method _whichField {}
  80.       method _toggleAmPm {}
  81.  
  82.       variable _cfield hour
  83.       variable _formatString "%r"
  84.       variable _fields {}
  85.       variable _numFields 4
  86.       variable _forward {}
  87.       variable _backward {}
  88.       variable _timeVar ""
  89.  
  90.       common _militaryFields {hour minute second}
  91.       common _civilianFields {hour minute second ampm}
  92.     }
  93. }
  94.  
  95. #
  96. # Provide a lowercased access method for the timefield class.
  97. proc iwidgets::timefield {pathName args} {
  98.     uplevel iwidgets::Timefield $pathName $args
  99. }
  100.  
  101. # ------------------------------------------------------------------
  102. #                        CONSTRUCTOR
  103. # ------------------------------------------------------------------
  104. itcl::body iwidgets::Timefield::constructor {args} {
  105.     component hull configure -borderwidth 0
  106.     
  107.     #
  108.     # Create an entry field for entering the time.
  109.     #
  110.     itk_component add time {
  111.       entry $itk_interior.time
  112.     } {
  113.       keep -borderwidth -cursor -exportselection \
  114.           -foreground -highlightcolor -highlightthickness \
  115.           -insertbackground -justify -relief -textvariable
  116.       
  117.       rename -font -textfont textFont Font
  118.       rename -highlightbackground -background background Background
  119.       rename -background -textbackground textBackground Background
  120.     }
  121.  
  122.     #
  123.     # Create the child site widget.
  124.     #
  125.     itk_component add -protected dfchildsite {
  126.       frame $itk_interior.dfchildsite
  127.     } 
  128.     set itk_interior $itk_component(dfchildsite)
  129.     
  130.     #
  131.     # Add timefield event bindings for focus in and keypress events.
  132.     #
  133.     bind $itk_component(time) <FocusIn>   [itcl::code $this _focusIn]
  134.     bind $itk_component(time) <KeyPress>  [itcl::code $this _keyPress %A %K %s]
  135.     bind $itk_component(time) <1> "focus $itk_component(time); break"
  136.  
  137.     #
  138.     # Disable some mouse button event bindings:
  139.     #   Button Motion
  140.     #   Double-Clicks
  141.     #   Triple-Clicks
  142.     #   Button2
  143.     #
  144.     bind $itk_component(time) <Button1-Motion>    break
  145.     bind $itk_component(time) <Button2-Motion>    break
  146.     bind $itk_component(time) <Double-Button>    break
  147.     bind $itk_component(time) <Triple-Button>    break
  148.     bind $itk_component(time) <2>        break
  149.  
  150.     #
  151.     # Initialize the widget based on the command line options.
  152.     #
  153.     eval itk_initialize $args
  154.  
  155.     #
  156.     # Initialize the time to the current time.
  157.     #
  158.     show
  159. }
  160.  
  161. # ------------------------------------------------------------------
  162. #                             OPTIONS
  163. # ------------------------------------------------------------------
  164.  
  165. # ------------------------------------------------------------------
  166. # OPTION: -childsitepos
  167. #
  168. # Specifies the position of the child site in the widget.  Valid
  169. # locations are n, s, e, and w.
  170. # ------------------------------------------------------------------
  171. itcl::configbody iwidgets::Timefield::childsitepos {
  172.     set parent [winfo parent $itk_component(time)]
  173.  
  174.     switch $itk_option(-childsitepos) {
  175.       n {
  176.           grid $itk_component(dfchildsite) -row 0 -column 0 -sticky ew
  177.           grid $itk_component(time) -row 1 -column 0 -sticky nsew
  178.  
  179.           grid rowconfigure $parent 0 -weight 0
  180.           grid rowconfigure $parent 1 -weight 1
  181.           grid columnconfigure $parent 0 -weight 1
  182.           grid columnconfigure $parent 1 -weight 0
  183.       }
  184.       
  185.       e {
  186.           grid $itk_component(dfchildsite) -row 0 -column 1 -sticky ns
  187.           grid $itk_component(time) -row 0 -column 0 -sticky nsew
  188.  
  189.           grid rowconfigure $parent 0 -weight 1
  190.           grid rowconfigure $parent 1 -weight 0
  191.           grid columnconfigure $parent 0 -weight 1
  192.           grid columnconfigure $parent 1 -weight 0
  193.       }
  194.       
  195.       s {
  196.           grid $itk_component(dfchildsite) -row 1 -column 0 -sticky ew
  197.           grid $itk_component(time) -row 0 -column 0 -sticky nsew
  198.  
  199.           grid rowconfigure $parent 0 -weight 1
  200.           grid rowconfigure $parent 1 -weight 0
  201.           grid columnconfigure $parent 0 -weight 1
  202.           grid columnconfigure $parent 1 -weight 0
  203.       }
  204.       
  205.       w {
  206.           grid $itk_component(dfchildsite) -row 0 -column 0 -sticky ns
  207.           grid $itk_component(time) -row 0 -column 1 -sticky nsew
  208.  
  209.           grid rowconfigure $parent 0 -weight 1
  210.           grid rowconfigure $parent 1 -weight 0
  211.           grid columnconfigure $parent 0 -weight 0
  212.           grid columnconfigure $parent 1 -weight 1
  213.       }
  214.       
  215.       default {
  216.           error "bad childsite option\
  217.                 \"$itk_option(-childsitepos)\":\
  218.                 should be n, e, s, or w"
  219.       }
  220.     }
  221. }
  222.  
  223. # ------------------------------------------------------------------
  224. # OPTION: -command
  225. #
  226. # Command invoked upon detection of return key press event.
  227. # ------------------------------------------------------------------
  228. itcl::configbody iwidgets::Timefield::command {}
  229.  
  230. # ------------------------------------------------------------------
  231. # OPTION: -iq
  232. #
  233. # Specifies the level of intelligence to be shown in the actions
  234. # taken by the time field during the processing of keypress events.
  235. # Valid settings include high or low.  With a high iq,
  236. # the time prevents the user from typing in an invalid time.  For 
  237. # example, if the current time is 05/31/1997 and the user changes
  238. # the hour to 04, then the minute will be instantly modified for them 
  239. # to be 30.  In addition, leap seconds are fully taken into account.
  240. # A setting of low iq instructs the widget to do no validity checking
  241. # at all during time entry.  With a low iq level, it is assumed that
  242. # the validity will be determined at a later time using the time's
  243. # isvalid command.
  244. # ------------------------------------------------------------------
  245. itcl::configbody iwidgets::Timefield::iq {
  246.  
  247.   switch $itk_option(-iq) {
  248.     high - low {
  249.  
  250.     }
  251.     default {
  252.       error "bad iq option \"$itk_option(-iq)\": should be high or low"
  253.     }
  254.   }
  255. }
  256.  
  257. # ------------------------------------------------------------------
  258. # OPTION: -format
  259. #
  260. # Specifies the time format displayed in the entry widget.
  261. # ------------------------------------------------------------------
  262. itcl::configbody iwidgets::Timefield::format {
  263.  
  264.   switch $itk_option(-format) {
  265.     civilian {
  266.       set _backward _backwardCivilian
  267.       set _forward _forwardCivilian
  268.       set _fields $_civilianFields
  269.       set _numFields 4
  270.       set _formatString "%r"
  271.       $itk_component(time) config -width 11
  272.     }
  273.     military {
  274.       set _backward _backwardMilitary
  275.       set _forward _forwardMilitary
  276.       set _fields $_militaryFields
  277.       set _numFields 3
  278.       set _formatString "%T"
  279.       $itk_component(time) config -width 8
  280.     }
  281.     default {
  282.       error "bad iq option \"$itk_option(-iq)\":\
  283.              should be civilian or military"
  284.     }
  285.   }
  286.  
  287.   #
  288.   # Update the current contents of the entry field to reflect
  289.   # the configured format.
  290.   #
  291.   show $_timeVar
  292. }
  293.  
  294. # ------------------------------------------------------------------
  295. # OPTION: -gmt
  296. #
  297. # This option is used for GMT time.  Must be a boolean value.
  298. # ------------------------------------------------------------------
  299. itcl::configbody iwidgets::Timefield::gmt {
  300.   switch $itk_option(-gmt) {
  301.     0 - no - false - off { }
  302.     1 - yes - true - on { }
  303.     default {
  304.       error "bad gmt option \"$itk_option(-gmt)\": should be boolean"
  305.     }
  306.   }
  307. }
  308.  
  309. # ------------------------------------------------------------------
  310. # OPTION: -state
  311. #
  312. # Disable the 
  313. # ------------------------------------------------------------------
  314. itcl::configbody iwidgets::Timefield::state {
  315.   switch -- $itk_option(-state) {
  316.     normal {
  317.       $itk_component(time) configure -state normal
  318.     }
  319.     disabled {
  320.       focus $itk_component(hull)
  321.       $itk_component(time) configure -state disabled
  322.     }
  323.     default {
  324.       error "Invalid value for -state: $itk_option(-state).  Should be\
  325.         \"normal\" or \"disabled\"."
  326.     }
  327.   }
  328. }
  329.  
  330.  
  331. # ------------------------------------------------------------------
  332. #                            METHODS
  333. # ------------------------------------------------------------------
  334.  
  335. # ------------------------------------------------------------------
  336. # PUBLIC METHOD: get ?format?
  337. #
  338. # Return the current contents of the timefield in one of two formats
  339. # string or as an integer clock value using the -string and -clicks
  340. # options respectively.  The default is by string.  Reference the 
  341. # clock command for more information on obtaining times and their 
  342. # formats.
  343. # ------------------------------------------------------------------
  344. itcl::body iwidgets::Timefield::get {{format "-string"}} {
  345.   set _timeVar [$itk_component(time) get]
  346.  
  347.   switch -- $format {
  348.     "-string" {
  349.       return $_timeVar
  350.     }
  351.     "-clicks" {
  352.       return [::clock scan $_timeVar -gmt $itk_option(-gmt)]
  353.     }
  354.     default {
  355.       error "bad format option \"$format\":\
  356.                should be -string or -clicks"
  357.     }
  358.   }
  359. }
  360.  
  361. # ------------------------------------------------------------------
  362. # PUBLIC METHOD: show time
  363. #
  364. # Changes the currently displayed time to be that of the time 
  365. # argument.  The time may be specified either as a string or an
  366. # integer clock value.  Reference the clock command for more 
  367. # information on obtaining times and their formats.
  368. # ------------------------------------------------------------------
  369. itcl::body iwidgets::Timefield::show {{time "now"}} {
  370.   set icursor [$itk_component(time) index insert]
  371.  
  372.   if {$time == {}} {
  373.     set time "now"
  374.   }
  375.  
  376.   switch -regexp -- $time {
  377.  
  378.     {^now$} {
  379.       set seconds [::clock seconds]
  380.     }
  381.  
  382.     {^[0-9]+$} {
  383.       if { [catch {::clock format $time -gmt $itk_option(-gmt)}] } {
  384.         error "bad time: \"$time\", must be a valid time \
  385.            string, clock clicks value or the keyword now"
  386.       }
  387.       set seconds $time
  388.     }
  389.  
  390.     default {
  391.       if {[catch {set seconds [::clock scan $time -gmt $itk_option(-gmt)]}]} {
  392.         error "bad time: \"$time\", must be a valid time \
  393.            string, clock clicks value or the keyword now"
  394.       }
  395.     }
  396.   }
  397.  
  398.   set _timeVar [::clock format $seconds -format $_formatString \
  399.     -gmt $itk_option(-gmt)]
  400.  
  401.   $itk_component(time) delete 0 end
  402.   $itk_component(time) insert end $_timeVar
  403.   $itk_component(time) icursor $icursor
  404.  
  405.   return $_timeVar
  406. }
  407.  
  408. # ------------------------------------------------------------------
  409. # PUBLIC METHOD: isvalid
  410. #
  411. # Returns a boolean indication of the validity of the currently
  412. # displayed time value.  For example, 09:59::59 is valid whereas
  413. # 26:59:59 is invalid.
  414. # ------------------------------------------------------------------
  415. itcl::body iwidgets::Timefield::isvalid {} {
  416.   set _timeVar [$itk_component(time) get]
  417.   return [expr {([catch {::clock scan $_timeVar -gmt $itk_option(-gmt)}] == 0)}]
  418. }
  419.  
  420. # ------------------------------------------------------------------
  421. # PROTECTED METHOD: _focusIn
  422. #
  423. # This method is bound to the <FocusIn> event.  It resets the 
  424. # insert cursor and field settings to be back to their last known
  425. # positions.
  426. # ------------------------------------------------------------------
  427. itcl::body iwidgets::Timefield::_focusIn {} {
  428.   _setField $_cfield
  429. }
  430.  
  431. # ------------------------------------------------------------------
  432. # PROTECTED METHOD: _keyPress 
  433. #
  434. # This method is the workhorse of the class.  It is bound to the
  435. # <KeyPress> event and controls the processing of all key strokes.
  436. # ------------------------------------------------------------------
  437. itcl::body iwidgets::Timefield::_keyPress {char sym state} {
  438.  
  439.   #
  440.   #  Determine which field we are in currently.  This is needed
  441.   # since the user may have moved to this position via a mouse
  442.   # selection and so it would not be in the position we last 
  443.   # knew it to be.
  444.   #
  445.   set _cfield [_whichField ]
  446.  
  447.   #
  448.   # Set up a few basic variables we'll be needing throughout the
  449.   # rest of the method such as the position of the insert cursor
  450.   # and the currently displayed minute, hour, and second.
  451.   #
  452.   set inValid 0
  453.   set icursor [$itk_component(time) index insert]
  454.   set lastField [lindex $_fields end]
  455.  
  456.   set prevtime $_timeVar
  457.   regexp {^([0-9])([0-9]):([0-9])([0-9]):([0-9])([0-9]).*$} \
  458.         $_timeVar dummy \
  459.         hour1 hour2 minute1 minute2 second1 second2
  460.   set hour    "$hour1$hour2"
  461.   set minute    "$minute1$minute2"
  462.   set second    "$second1$second2"
  463.  
  464.   #
  465.   # Process numeric keystrokes.  This involes a fair amount of 
  466.   # processing with step one being to check and make sure we
  467.   # aren't attempting to insert more that 6 characters.  If
  468.   # so ring the bell and break.
  469.   #
  470.   if {![catch {expr {int($char)}}]} {
  471.  
  472.     # If we are currently in the hour field then we process the
  473.     # number entered based on the cursor position.  If we are at
  474.     # at the first position and our iq is low, then accept any 
  475.     # input.  
  476.     #
  477.     # if the current format is military, then
  478.     # validate the hour field which can be [00 - 23]
  479.     #
  480.     switch $_cfield {
  481.       hour {
  482.         if {$itk_option(-iq) == "low"} {
  483.           $itk_component(time) delete $icursor
  484.           $itk_component(time) insert $icursor $char
  485.  
  486.         } elseif {$itk_option(-format) == "military"} {
  487.           if {$icursor == 0}  {
  488.             #
  489.             # if the digit is less than 2, then 
  490.             # the second hour digit is valid for 0-9
  491.             #
  492.             if {$char < 2} {
  493.               $itk_component(time) delete 0 1
  494.               $itk_component(time) insert 0 $char
  495.  
  496.             #
  497.             # if the digit is equal to 2, then 
  498.             # the second hour digit is valid for 0-3
  499.             #
  500.             } elseif {$char == 2} {
  501.               $itk_component(time) delete 0 1
  502.               $itk_component(time) insert 0 $char
  503.  
  504.               if {$hour2 > 3} {
  505.                 $itk_component(time) delete 1 2
  506.                 $itk_component(time) insert 1 "0"
  507.                 $itk_component(time) icursor 1
  508.               }
  509.  
  510.             #
  511.             # if the digit is greater than 2, then 
  512.             # set the first hour digit to 0 and the
  513.             # second hour digit to the value.
  514.             #
  515.             } elseif {$char > 2}  {
  516.               $itk_component(time) delete 0 2
  517.               $itk_component(time) insert 0 "0$char"
  518.               set icursor 1
  519.             } else {
  520.               set inValid 1
  521.             }
  522.  
  523.           #
  524.           # if the insertion cursor is for the second hour digit, then
  525.           # format is military, then it can only be valid if the first
  526.           # hour digit is less than 2 or the new digit is less than 4
  527.           #
  528.           } else {
  529.             if {$hour1 < 2 || $char < 4} {
  530.               $itk_component(time) delete 1 2
  531.               $itk_component(time) insert 1 $char
  532.             } else {
  533.               set inValid 1
  534.             }
  535.           }
  536.  
  537.         #
  538.         # The format is civilian, so we need to
  539.         # validate the hour field which can be [01 - 12]
  540.         #
  541.         } else {
  542.           if {$icursor == 0}  {
  543.             #
  544.             # if the digit is 0, then 
  545.             #   the second hour digit is valid for 1-9
  546.             #   so just insert it.
  547.             #
  548.             if {$char == 0 && $hour2 != 0} {
  549.               $itk_component(time) delete 0 1
  550.               $itk_component(time) insert 0 $char
  551.  
  552.             #
  553.             # if the digit is equal to 1, then 
  554.             #   the second hour digit is valid for 0-2
  555.             #
  556.             } elseif {$char == 1} {
  557.               $itk_component(time) delete 0 1
  558.               $itk_component(time) insert 0 $char
  559.  
  560.               if {$hour2 > 2} {
  561.                 $itk_component(time) delete 1 2
  562.                 $itk_component(time) insert 1 0
  563.                 set icursor 1
  564.               }
  565.  
  566.             #
  567.             # if the digit is greater than 1, then 
  568.             #   set the first hour digit to 0 and the
  569.             #   second hour digit to the value.
  570.             #
  571.             } elseif {$char > 1}  {
  572.               $itk_component(time) delete 0 2
  573.               $itk_component(time) insert 0 "0$char"
  574.               set icursor 1
  575.  
  576.             } else {
  577.               set inValid 1
  578.             }
  579.  
  580.           #
  581.           # The insertion cursor is at the second hour digit, so
  582.           # it can only be valid if the firs thour digit is 0
  583.           # or the new digit is less than or equal to 2
  584.           #
  585.           } else {
  586.             if {$hour1 == 0 || $char <= 2} {
  587.               $itk_component(time) delete 1 2
  588.               $itk_component(time) insert 1 $char
  589.             } else {
  590.               set inValid 1
  591.             }
  592.           }
  593.         }
  594.  
  595.         if {$inValid} {
  596.           bell
  597.         } elseif {$icursor == 1} {
  598.           _setField minute
  599.         }
  600.       }
  601.  
  602.       minute {
  603.         if {$itk_option(-iq) == "low" || $char < 6 || $icursor == 4} {
  604.           $itk_component(time) delete $icursor
  605.           $itk_component(time) insert $icursor $char
  606.         } elseif {$itk_option(-iq) == "high"} {
  607.           if {$char > 5} {
  608.             $itk_component(time) delete 3 5
  609.             $itk_component(time) insert 3 "0$char"
  610.             set icursor 4
  611.           }
  612.         }
  613.  
  614.         if {$icursor == 4} {
  615.           _setField second
  616.         }
  617.       }
  618.  
  619.       second {
  620.         if {$itk_option(-iq) == "low" || $char < 6 || $icursor == 7} {
  621.           $itk_component(time) delete $icursor
  622.           $itk_component(time) insert $icursor $char
  623.  
  624.         } elseif {$itk_option(-iq) == "high"} {
  625.           if {$char > 5} {
  626.             $itk_component(time) delete 6 8
  627.             $itk_component(time) insert 6 "0$char"
  628.             set icursor 7
  629.           }
  630.         }
  631.  
  632.         if {$icursor == 7} {
  633.           _moveField forward
  634.         }
  635.       }
  636.     }
  637.  
  638.     set _timeVar [$itk_component(time) get]
  639.     return -code break
  640.   }
  641.  
  642.   #
  643.   # Process the plus and the up arrow keys.  They both yield the same
  644.   # effect, they increment the minute by one.
  645.   #
  646.   switch $sym {
  647.     p - P {
  648.       if {$itk_option(-format) == "civilian"} {
  649.         $itk_component(time) delete 9 10
  650.         $itk_component(time) insert 9 P
  651.         _setField hour
  652.       }
  653.     }
  654.  
  655.     a - A {
  656.       if {$itk_option(-format) == "civilian"} {
  657.         $itk_component(time) delete 9 10
  658.         $itk_component(time) insert 9 A
  659.         _setField hour
  660.       }
  661.     }
  662.  
  663.     plus - Up {
  664.       if {$_cfield == "ampm"} {
  665.         _toggleAmPm
  666.       } else {
  667.         set newclicks [::clock scan "$prevtime 1 $_cfield"]
  668.         show [::clock format $newclicks -format $_formatString]
  669.       }
  670.     }
  671.  
  672.     minus - Down {
  673.       #
  674.       # Process the minus and the down arrow keys which decrement the value
  675.       # of the field in which the cursor is currently positioned.
  676.       #
  677.       if {$_cfield == "ampm"} {
  678.         _toggleAmPm
  679.       } else {
  680.         set newclicks [::clock scan "$prevtime 1 $_cfield ago"]
  681.         show [::clock format $newclicks -format $_formatString]
  682.       }
  683.     }
  684.  
  685.     Tab {
  686.       #
  687.       # A tab key moves the "hour:minute:second" field forward by one unless
  688.       # the current field is the second.  In that case we'll let tab
  689.       # do what is supposed to and pass the focus onto the next widget.
  690.       #
  691.       if {$state == 0} {
  692.  
  693.         if {($itk_option(-format) == "civilian" && $_cfield == $lastField)} {
  694.           _setField hour
  695.           return -code continue
  696.         }
  697.         _moveField forward
  698.  
  699.       #
  700.       # A ctrl-tab key moves the hour:minute:second field backwards by one 
  701.       # unless the current field is the hour.  In that case we'll let 
  702.       # tab take the focus to a previous widget.
  703.       #
  704.       } elseif {$state == 4} {
  705.         if {$_cfield == "hour"} {
  706.           _setField hour
  707.           return -code continue
  708.         }
  709.         _moveField backward
  710.       }
  711.     }
  712.  
  713.     Right {
  714.       #
  715.       # A right arrow key moves the insert cursor to the right one.
  716.       #
  717.       $_forward
  718.     }
  719.  
  720.     Left - BackSpace - Delete {
  721.       #
  722.       # A left arrow, backspace, or delete key moves the insert cursor 
  723.       # to the left one.  This is what you expect for the left arrow
  724.       # and since the whole widget always operates in overstrike mode,
  725.       # it makes the most sense for backspace and delete to do the same.
  726.       #
  727.       $_backward
  728.     }
  729.  
  730.     Return {
  731.       #
  732.       # A Return key invokes the optionally specified command option.
  733.       #
  734.       uplevel #0 $itk_option(-command)
  735.     }
  736.       
  737.     default {
  738.  
  739.     }
  740.   }
  741.  
  742.   return -code break
  743. }
  744.  
  745. # ------------------------------------------------------------------
  746. # PROTECTED METHOD: _toggleAmPm
  747. #
  748. # Internal method which toggles the displayed time
  749. # between "AM" and "PM" when format is "civilian".
  750. # ------------------------------------------------------------------
  751. itcl::body iwidgets::Timefield::_toggleAmPm {} {
  752.   set firstChar  [string index $_timeVar 9]
  753.   $itk_component(time) delete 9 10
  754.   $itk_component(time) insert 9 [expr {($firstChar == "A") ? "P" : "A"}]
  755.   $itk_component(time) icursor 9
  756.   set _timeVar [$itk_component(time) get]
  757. }
  758.  
  759. # ------------------------------------------------------------------
  760. # PROTECTED METHOD: _setField field
  761. #
  762. # Adjusts the current field to be that of the argument, setting the
  763. # insert cursor appropriately.
  764. # ------------------------------------------------------------------
  765. itcl::body iwidgets::Timefield::_setField {field} {
  766.  
  767.   # Move the position of the cursor to the first character of the
  768.   # field given by the argument:
  769.   #
  770.   # Field   First Character Index
  771.   # -----   ---------------------
  772.   # hour    0
  773.   # minute  3
  774.   # second  6
  775.   # ampm    9
  776.   #
  777.   switch $field {
  778.     hour {
  779.       $itk_component(time) icursor 0
  780.     }
  781.     minute {
  782.       $itk_component(time) icursor 3
  783.     }
  784.     second {
  785.       $itk_component(time) icursor 6
  786.     }
  787.     ampm {
  788.       if {$itk_option(-format) == "military"} {
  789.         error "bad field: \"$field\", must be hour, minute or second"
  790.       }
  791.       $itk_component(time) icursor 9
  792.     }
  793.     default {
  794.       if {$itk_option(-format) == "military"} {
  795.         error "bad field: \"$field\", must be hour, minute or second"
  796.       } else {
  797.         error "bad field: \"$field\", must be hour, minute, second or ampm"
  798.       }
  799.     }
  800.   }
  801.  
  802.   set _cfield $field
  803.  
  804.   return $_cfield
  805. }
  806.  
  807. # ------------------------------------------------------------------
  808. # PROTECTED METHOD: _moveField
  809. #
  810. # Moves the cursor one field forward or backward.
  811. # ------------------------------------------------------------------
  812. itcl::body iwidgets::Timefield::_moveField {direction} {
  813.  
  814.   # Since the value "_fields" list variable is always either value:
  815.   #   military => {hour minute second}
  816.   #   civilian => {hour minute second ampm}
  817.   #
  818.   # the index of the previous or next field index can be determined
  819.   # by subtracting or adding 1 to current the index, respectively.
  820.   # 
  821.   set index [lsearch $_fields $_cfield]
  822.   expr {($direction == "forward") ? [incr index] : [incr index -1]}
  823.  
  824.   if {$index == $_numFields} {
  825.     set index 0
  826.   } elseif {$index < 0} {
  827.     set index [expr {$_numFields-1}]
  828.   }
  829.  
  830.   _setField [lindex $_fields $index]
  831. }
  832.  
  833. # ------------------------------------------------------------------
  834. # PROTECTED METHOD: _whichField
  835. #
  836. # Returns the current field that the cursor is positioned within.
  837. # ------------------------------------------------------------------
  838. itcl::body iwidgets::Timefield::_whichField {} {
  839.  
  840.   # Return the current field based on the position of the cursor.
  841.   #
  842.   # Field   Index
  843.   # -----   -----
  844.   # hour    0,1
  845.   # minute  3,4
  846.   # second  6,7
  847.   # ampm    9,10
  848.   #
  849.   set icursor [$itk_component(time) index insert]
  850.   switch $icursor {
  851.     0 - 1 {
  852.       set _cfield hour
  853.     }
  854.     3 - 4 {
  855.       set _cfield minute
  856.     }
  857.     6 - 7 {
  858.       set _cfield second
  859.     }
  860.     9 - 10 {
  861.       set _cfield ampm
  862.     }
  863.   }
  864.  
  865.   return $_cfield
  866. }
  867.  
  868. # ------------------------------------------------------------------
  869. # PROTECTED METHOD: _forwardCivilian
  870. #
  871. # Internal method which moves the cursor forward by one character
  872. # jumping over the slashes and wrapping.
  873. # ------------------------------------------------------------------
  874. itcl::body iwidgets::Timefield::_forwardCivilian {} {
  875.  
  876.   #
  877.   # If the insertion cursor is at the second digit
  878.   # of either the hour, minute or second field, then
  879.   # move the cursor to the first digit of the right-most field.
  880.   #
  881.   # else move the insertion cursor right one character
  882.   #
  883.   set icursor [$itk_component(time) index insert]
  884.   switch $icursor {
  885.     1 {
  886.       _setField minute
  887.     }
  888.     4 {
  889.       _setField second
  890.     }
  891.     7 {
  892.       _setField ampm
  893.     }
  894.     9 - 10 {
  895.       _setField hour
  896.     }
  897.     default {
  898.       $itk_component(time) icursor [expr {$icursor+1}]
  899.     }
  900.   }
  901. }
  902.  
  903. # ------------------------------------------------------------------
  904. # PROTECTED METHOD: _forwardMilitary
  905. #
  906. # Internal method which moves the cursor forward by one character
  907. # jumping over the slashes and wrapping.
  908. # ------------------------------------------------------------------
  909. itcl::body iwidgets::Timefield::_forwardMilitary {} {
  910.  
  911.   #
  912.   # If the insertion cursor is at the second digit of either
  913.   # the hour, minute or second field, then move the cursor to
  914.   # the first digit of the right-most field.
  915.   #
  916.   # else move the insertion cursor right one character
  917.   #
  918.   set icursor [$itk_component(time) index insert]
  919.   switch $icursor {
  920.     1 {
  921.       _setField minute
  922.     }
  923.     4 {
  924.       _setField second
  925.     }
  926.     7 {
  927.       _setField hour
  928.     }
  929.     default {
  930.       $itk_component(time) icursor [expr {$icursor+1}]
  931.     }
  932.   }
  933. }
  934.  
  935. # ------------------------------------------------------------------
  936. # PROTECTED METHOD: _backwardCivilian
  937. #
  938. # Internal method which moves the cursor backward by one character
  939. # jumping over the ":" and wrapping.
  940. # ------------------------------------------------------------------
  941. itcl::body iwidgets::Timefield::_backwardCivilian {} {
  942.  
  943.   #
  944.   # If the insertion cursor is at the first character
  945.   # of either the minute or second field or at the ampm
  946.   # field, then move the cursor to the second character
  947.   # of the left-most field.
  948.   #
  949.   # else if the insertion cursor is at the first digit of the
  950.   # hour field, then move the cursor to the first character
  951.   # of the ampm field.
  952.   #
  953.   # else move the insertion cursor left one character
  954.   #
  955.   set icursor [$itk_component(time) index insert]
  956.   switch $icursor {
  957.     9 {
  958.       _setField second
  959.       $itk_component(time) icursor 7
  960.     }
  961.     6 {
  962.       _setField minute
  963.       $itk_component(time) icursor 4
  964.     }
  965.     3 {
  966.       _setField hour
  967.       $itk_component(time) icursor 1
  968.     }
  969.     0 {
  970.       _setField ampm
  971.       $itk_component(time) icursor 9
  972.     }
  973.     default {
  974.       $itk_component(time) icursor [expr {$icursor-1}]
  975.     }
  976.   }
  977. }
  978.  
  979. # ------------------------------------------------------------------
  980. # PROTECTED METHOD: _backwardMilitary
  981. #
  982. # Internal method which moves the cursor backward by one character
  983. # jumping over the slashes and wrapping.
  984. # ------------------------------------------------------------------
  985. itcl::body iwidgets::Timefield::_backwardMilitary {} {
  986.  
  987.   #
  988.   # If the insertion cursor is at the first digit of either
  989.   # the minute or second field, then move the cursor to the
  990.   # second character of the left-most field.
  991.   #
  992.   # else if the insertion cursor is at the first digit of the
  993.   # hour field, then move the cursor to the second digit
  994.   # of the second field.
  995.   #
  996.   # else move the insertion cursor left one character
  997.   #
  998.   set icursor [$itk_component(time) index insert]
  999.   switch $icursor {
  1000.     6 {
  1001.       _setField minute
  1002.       $itk_component(time) icursor 4
  1003.     }
  1004.     3 {
  1005.       _setField hour
  1006.       $itk_component(time) icursor 1
  1007.     }
  1008.     0 {
  1009.       _setField second
  1010.       $itk_component(time) icursor 7
  1011.     }
  1012.     default {
  1013.       $itk_component(time) icursor [expr {$icursor-1}]
  1014.     }
  1015.   }
  1016. }
  1017.