1# Spintime 2# ---------------------------------------------------------------------- 3# Implements a Time spinner widget. A time spinner contains three 4# integer spinners: one for hours, one for minutes and one for 5# seconds. Options exist to manage to behavior, appearance, and 6# format of each component spinner. 7# 8# ---------------------------------------------------------------------- 9# AUTHOR: Sue Yockey EMAIL: yockey@actc.com 10# Mark L. Ulferts mulferts@austin.dsccc.com 11# 12# @(#) $Id: spintime.itk,v 1.3 2001/08/17 19:04:45 smithc Exp $ 13# ---------------------------------------------------------------------- 14# Copyright (c) 1997 DSC Technologies Corporation 15# ====================================================================== 16# Permission to use, copy, modify, distribute and license this software 17# and its documentation for any purpose, and without fee or written 18# agreement with DSC, is hereby granted, provided that the above copyright 19# notice appears in all copies and that both the copyright notice and 20# warranty disclaimer below appear in supporting documentation, and that 21# the names of DSC Technologies Corporation or DSC Communications 22# Corporation not be used in advertising or publicity pertaining to the 23# software without specific, written prior permission. 24# 25# DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 26# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON- 27# INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE 28# AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 29# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 30# DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 31# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 32# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, 33# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 34# SOFTWARE. 35# ====================================================================== 36 37# 38# Default resources. 39# 40option add *Spintime.hourLabel "Hour" widgetDefault 41option add *Spintime.minuteLabel "Minute" widgetDefault 42option add *Spintime.secondLabel "Second" widgetDefault 43option add *Spintime.hourWidth 3 widgetDefault 44option add *Spintime.minuteWidth 3 widgetDefault 45option add *Spintime.secondWidth 3 widgetDefault 46 47# 48# Usual options. 49# 50itk::usual Spintime { 51 keep -background -cursor -foreground -labelfont -textbackground -textfont 52} 53 54# ------------------------------------------------------------------ 55# SPINTIME 56# ------------------------------------------------------------------ 57itcl::class iwidgets::Spintime { 58 inherit itk::Widget 59 60 constructor {args} {} 61 destructor {} 62 63 itk_option define -orient orient Orient vertical 64 itk_option define -labelpos labelPos Position w 65 itk_option define -houron hourOn HourOn true 66 itk_option define -minuteon minuteOn MinuteOn true 67 itk_option define -secondon secondOn SecondOn true 68 itk_option define -timemargin timeMargin Margin 1 69 itk_option define -militaryon militaryOn MilitaryOn true 70 71 public { 72 method get {{format "-string"}} 73 method show {{date now}} 74 } 75 76 protected { 77 method _packTime {{when later}} 78 method _down60 {comp} 79 80 variable _repack {} ;# Reconfiguration flag. 81 variable _interior 82 } 83} 84 85# 86# Provide a lowercased access method for the Spintime class. 87# 88proc ::iwidgets::spintime {pathName args} { 89 uplevel ::iwidgets::Spintime $pathName $args 90} 91 92# ------------------------------------------------------------------ 93# CONSTRUCTOR 94# ------------------------------------------------------------------ 95itcl::body iwidgets::Spintime::constructor {args} { 96 set _interior $itk_interior 97 set clicks [clock seconds] 98 99 # 100 # Create Hour Spinner 101 # 102 itk_component add hour { 103 iwidgets::Spinint $itk_interior.hour -fixed 2 -range {0 23} -justify right 104 } { 105 keep -background -cursor -arroworient -foreground \ 106 -labelfont -labelmargin -relief -textbackground \ 107 -textfont -repeatdelay -repeatinterval 108 109 rename -labeltext -hourlabel hourLabel Text 110 rename -width -hourwidth hourWidth Width 111 } 112 113 # 114 # Take off the default bindings for selction and motion. 115 # 116 bind [$itk_component(hour) component entry] <1> {break} 117 bind [$itk_component(hour) component entry] <Button1-Motion> {break} 118 119 # 120 # Create Minute Spinner 121 # 122 itk_component add minute { 123 iwidgets::Spinint $itk_interior.minute \ 124 -decrement [itcl::code $this _down60 minute] \ 125 -fixed 2 -range {0 59} -justify right 126 } { 127 keep -background -cursor -arroworient -foreground \ 128 -labelfont -labelmargin -relief -textbackground \ 129 -textfont -repeatdelay -repeatinterval 130 131 rename -labeltext -minutelabel minuteLabel Text 132 rename -width -minutewidth minuteWidth Width 133 } 134 135 # 136 # Take off the default bindings for selction and motion. 137 # 138 bind [$itk_component(minute) component entry] <1> {break} 139 bind [$itk_component(minute) component entry] <Button1-Motion> {break} 140 141 # 142 # Create Second Spinner 143 # 144 itk_component add second { 145 iwidgets::Spinint $itk_interior.second \ 146 -decrement [itcl::code $this _down60 second] \ 147 -fixed 2 -range {0 59} -justify right 148 } { 149 keep -background -cursor -arroworient -foreground \ 150 -labelfont -labelmargin -relief -textbackground \ 151 -textfont -repeatdelay -repeatinterval 152 153 rename -labeltext -secondlabel secondLabel Text 154 rename -width -secondwidth secondWidth Width 155 } 156 157 # 158 # Take off the default bindings for selction and motion. 159 # 160 bind [$itk_component(second) component entry] <1> {break} 161 bind [$itk_component(second) component entry] <Button1-Motion> {break} 162 163 # 164 # Initialize the widget based on the command line options. 165 # 166 eval itk_initialize $args 167 168 # 169 # Show the current time. 170 # 171 show now 172} 173 174# ------------------------------------------------------------------ 175# DESTRUCTOR 176# ------------------------------------------------------------------ 177itcl::body iwidgets::Spintime::destructor {} { 178 if {$_repack != ""} {after cancel $_repack} 179} 180 181# ------------------------------------------------------------------ 182# OPTIONS 183# ------------------------------------------------------------------ 184 185# ------------------------------------------------------------------ 186# OPTION: -orient 187# 188# Specifies the orientation of the 3 spinners for Hour, Minute 189# and second. 190# ------------------------------------------------------------------ 191itcl::configbody iwidgets::Spintime::orient { 192 _packTime 193} 194 195# ------------------------------------------------------------------ 196# OPTION: -labelpos 197# 198# Specifies the location of all 3 spinners' labels. 199# Overloaded 200# ------------------------------------------------------------------ 201itcl::configbody iwidgets::Spintime::labelpos { 202 switch $itk_option(-labelpos) { 203 n { 204 $itk_component(hour) configure -labelpos n 205 $itk_component(minute) configure -labelpos n 206 $itk_component(second) configure -labelpos n 207 208 # 209 # Un-align labels 210 # 211 $itk_component(hour) configure -labelmargin 1 212 $itk_component(minute) configure -labelmargin 1 213 $itk_component(second) configure -labelmargin 1 214 } 215 216 s { 217 $itk_component(hour) configure -labelpos s 218 $itk_component(minute) configure -labelpos s 219 $itk_component(second) configure -labelpos s 220 221 # 222 # Un-align labels 223 # 224 $itk_component(hour) configure -labelmargin 1 225 $itk_component(minute) configure -labelmargin 1 226 $itk_component(second) configure -labelmargin 1 227 } 228 229 w { 230 $itk_component(hour) configure -labelpos w 231 $itk_component(minute) configure -labelpos w 232 $itk_component(second) configure -labelpos w 233 } 234 235 e { 236 $itk_component(hour) configure -labelpos e 237 $itk_component(minute) configure -labelpos e 238 $itk_component(second) configure -labelpos e 239 240 # 241 # Un-align labels 242 # 243 $itk_component(hour) configure -labelmargin 1 244 $itk_component(minute) configure -labelmargin 1 245 $itk_component(second) configure -labelmargin 1 246 } 247 248 default { 249 error "bad labelpos option \"$itk_option(-labelpos)\",\ 250 should be n, s, w or e" 251 } 252 } 253 254 _packTime 255} 256 257# ------------------------------------------------------------------ 258# OPTION: -houron 259# 260# Specifies whether or not to display the hour spinner. 261# ------------------------------------------------------------------ 262itcl::configbody iwidgets::Spintime::houron { 263 _packTime 264} 265 266# ------------------------------------------------------------------ 267# OPTION: -minuteon 268# 269# Specifies whether or not to display the minute spinner. 270# ------------------------------------------------------------------ 271itcl::configbody iwidgets::Spintime::minuteon { 272 _packTime 273} 274 275# ------------------------------------------------------------------ 276# OPTION: -secondon 277# 278# Specifies whether or not to display the second spinner. 279# ------------------------------------------------------------------ 280itcl::configbody iwidgets::Spintime::secondon { 281 _packTime 282} 283 284 285# ------------------------------------------------------------------ 286# OPTION: -timemargin 287# 288# Specifies the margin space between the hour and minute spinners 289# and the minute and second spinners. 290# ------------------------------------------------------------------ 291itcl::configbody iwidgets::Spintime::timemargin { 292 _packTime 293} 294 295# ------------------------------------------------------------------ 296# OPTION: -militaryon 297# 298# Specifies 24-hour clock or 12-hour. 299# ------------------------------------------------------------------ 300itcl::configbody iwidgets::Spintime::militaryon { 301 set clicks [clock seconds] 302 303 if {$itk_option(-militaryon)} { 304 $itk_component(hour) configure -range {0 23} 305 $itk_component(hour) delete 0 end 306 $itk_component(hour) insert end [clock format $clicks -format "%H"] 307 } else { 308 $itk_component(hour) configure -range {1 12} 309 $itk_component(hour) delete 0 end 310 $itk_component(hour) insert end [clock format $clicks -format "%I"] 311 } 312} 313 314# ------------------------------------------------------------------ 315# METHODS 316# ------------------------------------------------------------------ 317 318# ------------------------------------------------------------------ 319# METHOD: get ?format? 320# 321# Get the value of the time spinner in one of two formats string or 322# as an integer clock value using the -string and -clicks options 323# respectively. The default is by string. Reference the clock 324# command for more information on obtaining time and its formats. 325# ------------------------------------------------------------------ 326itcl::body iwidgets::Spintime::get {{format "-string"}} { 327 set hour [$itk_component(hour) get] 328 set minute [$itk_component(minute) get] 329 set second [$itk_component(second) get] 330 331 switch -- $format { 332 "-string" { 333 return "$hour:$minute:$second" 334 } 335 "-clicks" { 336 return [clock scan "$hour:$minute:$second"] 337 } 338 default { 339 error "bad format option \"$format\":\ 340 should be -string or -clicks" 341 } 342 } 343} 344 345# ------------------------------------------------------------------ 346# PUBLIC METHOD: show time 347# 348# Changes the currently displayed time to be that of the time 349# argument. The time may be specified either as a string or an 350# integer clock value. Reference the clock command for more 351# information on obtaining time and its format. 352# ------------------------------------------------------------------ 353itcl::body iwidgets::Spintime::show {{time "now"}} { 354 if {$time == "now"} { 355 set seconds [clock seconds] 356 } else { 357 if {[catch {clock format $time}] == 0} { 358 set seconds $time 359 } elseif {[catch {set seconds [clock scan $time]}] != 0} { 360 error "bad time: \"$time\", must be a valid time\ 361 string, clock clicks value or the keyword now" 362 } 363 } 364 365 $itk_component(hour) delete 0 end 366 367 if {$itk_option(-militaryon)} { 368 scan [clock format $seconds -format "%H"] "%d" hour 369 } else { 370 scan hour [clock format $seconds -format "%I"] "%d" hour 371 } 372 373 $itk_component(hour) insert end $hour 374 375 $itk_component(minute) delete 0 end 376 scan [clock format $seconds -format "%M"] "%d" minute 377 $itk_component(minute) insert end $minute 378 379 $itk_component(second) delete 0 end 380 scan [clock format $seconds -format "%S"] "%d" seconds 381 $itk_component(second) insert end $seconds 382 383 return 384} 385 386# ------------------------------------------------------------------ 387# PROTECTED METHOD: _packTime ?when? 388# 389# Pack components of time spinner. If "when" is "now", the change 390# is applied immediately. If it is "later" or it is not specified, 391# then the change is applied later, when the application is idle. 392# ------------------------------------------------------------------ 393itcl::body iwidgets::Spintime::_packTime {{when later}} { 394 if {$when == "later"} { 395 if {$_repack == ""} { 396 set _repack [after idle [itcl::code $this _packTime now]] 397 } 398 return 399 } elseif {$when != "now"} { 400 error "bad option \"$when\": should be now or later" 401 } 402 403 for {set i 0} {$i < 5} {incr i} { 404 grid rowconfigure $_interior $i -minsize 0 405 grid columnconfigure $_interior $i -minsize 0 406 } 407 408 if {$itk_option(-minuteon)} { 409 set minuteon 1 410 } else { 411 set minuteon 0 412 } 413 if {$itk_option(-secondon)} { 414 set secondon 1 415 } else { 416 set secondon 0 417 } 418 419 set _repack "" 420 421 switch $itk_option(-orient) { 422 vertical { 423 set row -1 424 425 if {$itk_option(-houron)} { 426 grid $itk_component(hour) -row [incr row] -column 0 \ 427 -sticky nsew 428 } else { 429 grid forget $itk_component(hour) 430 } 431 432 if {$itk_option(-minuteon)} { 433 if {$itk_option(-houron)} { 434 grid rowconfigure $_interior [incr row] \ 435 -minsize $itk_option(-timemargin) 436 } 437 438 grid $itk_component(minute) -row [incr row] -column 0 \ 439 -sticky nsew 440 } else { 441 grid forget $itk_component(minute) 442 } 443 444 if {$itk_option(-secondon)} { 445 if {$minuteon || $secondon} { 446 grid rowconfigure $_interior [incr row] \ 447 -minsize $itk_option(-timemargin) 448 } 449 450 grid $itk_component(second) -row [incr row] -column 0 \ 451 -sticky nsew 452 } else { 453 grid forget $itk_component(second) 454 } 455 456 if {$itk_option(-labelpos) == "w"} { 457 iwidgets::Labeledwidget::alignlabels $itk_component(hour) \ 458 $itk_component(minute) $itk_component(second) 459 } 460 } 461 462 horizontal { 463 set column -1 464 465 if {$itk_option(-houron)} { 466 grid $itk_component(hour) -row 0 -column [incr column] \ 467 -sticky nsew 468 } else { 469 grid forget $itk_component(hour) 470 } 471 472 if {$itk_option(-minuteon)} { 473 if {$itk_option(-houron)} { 474 grid columnconfigure $_interior [incr column] \ 475 -minsize $itk_option(-timemargin) 476 } 477 478 grid $itk_component(minute) -row 0 -column [incr column] \ 479 -sticky nsew 480 } else { 481 grid forget $itk_component(minute) 482 } 483 484 if {$itk_option(-secondon)} { 485 if {$minuteon || $secondon} { 486 grid columnconfigure $_interior [incr column] \ 487 -minsize $itk_option(-timemargin) 488 } 489 490 grid $itk_component(second) -row 0 -column [incr column] \ 491 -sticky nsew 492 } else { 493 grid forget $itk_component(second) 494 } 495 496 # 497 # Un-align labels 498 # 499 $itk_component(hour) configure -labelmargin 1 500 $itk_component(minute) configure -labelmargin 1 501 $itk_component(second) configure -labelmargin 1 502 } 503 504 default { 505 error "bad orient option \"$itk_option(-orient)\", should\ 506 be \"vertical\" or \"horizontal\"" 507 } 508 } 509} 510 511# ------------------------------------------------------------------ 512# METHOD: down60 513# 514# Down arrow button press event. Decrement value in the minute 515# or second entry. 516# ------------------------------------------------------------------ 517itcl::body iwidgets::Spintime::_down60 {comp} { 518 set step [$itk_component($comp) cget -step] 519 set val [$itk_component($comp) get] 520 521 incr val -$step 522 if {$val < 0} { 523 set val [expr {60-$step}] 524 } 525 $itk_component($comp) delete 0 end 526 $itk_component($comp) insert 0 $val 527} 528