Keith Vetter 2008-10-08 : Here's a new time picker mega-widget based on an experimental one at [L1 ]. It works with and without Tile (the demo lets you switch between the two).
Couple of bugs I haven't worked out.
##+##########################################################################
#
# TimePicker.tcl -- another time picking tool
# by Keith Vetter Oct 08, 2008
#
# Based on widget at
# http://haineault.com/media/examples/jquery-utils/demo/ui-timepickr.html
#
# Bugs:
# o better highlighting under Tile (just pressed state isn't enough)
# o when time entry widgets moves or gets raised or lowered, the popup windows
# should follow
# o only one instance allowed at a time (global TC array)
#
package require Tk
package require Ttk
catch {namespace delete timePicker}
namespace eval timePicker {
variable TC
array set TC {
popup,1 ?.__timepicker1
popup,2 ?.__timepicker2
popup,3 ?.__timepicker3
master ?
UseTile 1 theTime "1:00 am"
hour 0 minute 0 ampm 0
selected,hour 0 selected,minute 0 selected,ampm 0
selected,color \#b2b4bf
}
}
##+##########################################################################
#
# timePicker::timePicker -- Creates a new instance of our timepicker widget
#
proc timePicker::timePicker {w {UseTile 0}} {
variable TC
set TC(master) $w
set TC(UseTile) $UseTile
set TC(popup,1) $w.__timepicker1
set TC(popup,2) $w.__timepicker2
set TC(popup,3) $w.__timepicker3
entry $w -width 8 -textvariable timePicker::TC(theTime)
bind $w <Enter> [list timePicker::ButtonEnter theTime -]
return w
}
##+##########################################################################
#
# timePicker::ButtonEnter -- Reacts to entering a button
#
proc timePicker::ButtonEnter {who which} {
variable TC
if {$who eq "theTime"} {
if {! [winfo exists $TC(popup,1)] || ! [winfo ismapped $TC(popup,1)]} {
timePicker::Init
update idletasks
timePicker::ShowHours
}
return
}
set TC($who) $which
timePicker::DoHighlight $who $TC(selected,$who) $which
set TC(selected,$who) $which
set hour [expr {$TC(selected,hour) + 1 + $TC(selected,ampm)*12}]
set minute [expr {$TC(selected,minute) * 15}]
set seconds [expr {$hour * 3600 + $minute * 60}]
set TC(theTime) [clock format $seconds -gmt 1 -format "%I:%M %P"]
if {$who eq "hour"} {
timePicker::ShowMinutes
if {[winfo ismapped $TC(popup,3)]} {
update idletasks
timePicker::ShowAMPM
}
}
if {$who eq "minute"} timePicker::ShowAMPM
}
proc timePicker::Init {} {
variable TC
timePicker::CreatePopup
# Figure current time and hightlight those buttons
foreach {hour minute ampm} {1 0 am} break
set n [catch {
set seconds [clock scan $TC(theTime) -format "%I:%M %P"]
set ttime [clock format $seconds -format "%I %M %P"]
scan $ttime "%d %d %s" hour minute ampm
}]
set minute [expr {int($minute/15)}]
set TC(selected,hour) [expr {$hour-1}]
set TC(selected,minute) $minute
set TC(selected,ampm) [expr {$ampm eq "am" ? 0 : 1}]
timePicker::DoHighlight hour 0 $TC(selected,hour)
timePicker::DoHighlight minute 0 $TC(selected,minute)
timePicker::DoHighlight ampm 0 $TC(selected,ampm)
}
proc timePicker::Done {} {
variable TC
wm withdraw $TC(popup,1)
wm withdraw $TC(popup,2)
wm withdraw $TC(popup,3)
}
##+##########################################################################
#
# timePicker::PlacePopup -- Places a slave window just below master
#
proc timePicker::PlacePopup {master slave} {
variable TC
set x [winfo rootx $master]
set y [winfo rooty $master]
set y [expr {$y + [winfo height $master]}]
wm geom $slave +$x+$y
}
proc timePicker::DoHighlight {who old new} {
variable TC
set id [expr {$who eq "hour" ? 1 : $who eq "minute" ? 2 : 3}]
set w1 $TC(popup,$id).${who}_$old
set w2 $TC(popup,$id).${who}_$new
if {$TC(UseTile)} {
$w1 state !pressed
$w2 state pressed
} else {
$w1 config -bg [lindex [$w1 config -background] 3]
$w2 config -bg $TC(selected,color)
}
}
proc timePicker::ShowHours {} {
variable TC
timePicker::PlacePopup $TC(master) $TC(popup,1)
if {[winfo ismapped $TC(popup,1)]} return
wm deiconify $TC(popup,1)
}
proc timePicker::ShowMinutes {} {
variable TC
set master $TC(popup,1).hour_$TC(selected,hour)
timePicker::PlacePopup $master $TC(popup,2)
if {[winfo ismapped $TC(popup,2)]} return
wm deiconify $TC(popup,2)
}
proc timePicker::ShowAMPM {} {
variable TC
timePicker::PlacePopup $TC(popup,2) $TC(popup,3)
if {[winfo ismapped $TC(popup,3)]} return
wm deiconify $TC(popup,3)
}
proc timePicker::CreatePopup {} {
variable TC
if {[winfo exists $TC(popup,1)]} {
timePicker::Done
return
}
foreach id {1 2 3} {
toplevel $TC(popup,$id)
wm withdraw $TC(popup,$id)
wm overrideredirect $TC(popup,$id) 1
wm transient $TC(popup,$id) [winfo toplevel $TC(master)]
catch { wm attributes $TC(popup,$id) -topmost 1 }
}
set button [expr {$TC(UseTile) ? "::ttk::button" : "button"}]
set bw 3
for {set hour 0} {$hour < 12} {incr hour} {
set h [format %02d [expr {$hour+1}]]
set w $TC(popup,1).hour_$hour
$button $w -text $h -width $bw -command timePicker::Done
bind $w <Enter> [list timePicker::ButtonEnter hour $hour]
grid $w -row 1 -column $hour
}
for {set minute 0} {$minute < 4} {incr minute} {
set m [format %02d [expr {$minute * 15}]]
set w $TC(popup,2).minute_$minute
$button $w -text $m -width $bw -command timePicker::Done
bind $w <Enter> [list timePicker::ButtonEnter minute $minute]
grid $w -row 2 -column $minute
}
set w1 $TC(popup,3).ampm_0
set w2 $TC(popup,3).ampm_1
$button $w1 -text "am" -width $bw -command timePicker::Done
bind $w1 <Enter> [list timePicker::ButtonEnter ampm 0]
$button $w2 -text "pm" -width $bw -command timePicker::Done
bind $w2 <Enter> [list timePicker::ButtonEnter ampm 1]
grid $w1 $w2 -row 0
}
##+##########################################################################
#
# Demo Code
#
set UseTile 0
proc ReDemo {} {
destroy .time
timePicker::timePicker .time $::UseTile
grid .time -row 2
}
timePicker::timePicker .time $UseTile
label .title -text "Time Picker Demo" -font {Times 48 bold}
label .l1 -text "Here's a new timePicker widget\nmouse into and play" \
-font {Times 18 bold}
frame .buttons
checkbutton .tile -text "Tile" -variable ::UseTile -command ReDemo
::ttk::button .done -text Close -command exit
grid .title -row 0
grid .l1 -row 1
grid .buttons -row 3 -pady {.75i 30} -sticky ew
pack .tile .done -in .buttons -side left -expand 1
ReDemo
return