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