# Spintime 
# ----------------------------------------------------------------------
# Implements a Time spinner widget.  A time spinner contains three
# integer spinners:  one for hours, one for minutes and one for
# seconds.  Options exist to manage to behavior, appearance, and
# format of each component spinner.
#
# ----------------------------------------------------------------------
#   AUTHOR:  Sue Yockey               Phone: (214) 519-2517
#                                     E-mail: syockey@spd.dsccc.com
#                                             yockey@actc.com
#
#   @(#) $Id: spintime.itk,v 1.1.1.1 1999/03/31 20:39:39 damon Exp $
# ----------------------------------------------------------------------
#            Copyright (c) 1995 DSC Technologies Corporation
# ======================================================================
# Permission to use, copy, modify, distribute and license this software 
# and its documentation for any purpose, and without fee or written 
# agreement with DSC, is hereby granted, provided that the above copyright 
# notice appears in all copies and that both the copyright notice and 
# warranty disclaimer below appear in supporting documentation, and that 
# the names of DSC Technologies Corporation or DSC Communications 
# Corporation not be used in advertising or publicity pertaining to the 
# software without specific, written prior permission.
# 
# DSC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, AND NON-
# INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE
# AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, 
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. IN NO EVENT SHALL 
# DSC BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 
# ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 
# SOFTWARE.
# ======================================================================

#
# Default resources.
#
option add *Spintime.hourLabel "Hour" widgetDefault
option add *Spintime.minuteLabel "Minute" widgetDefault
option add *Spintime.secondLabel "Second" widgetDefault
option add *Spintime.hourWidth 3 widgetDefault
option add *Spintime.minuteWidth 3 widgetDefault
option add *Spintime.secondWidth 3 widgetDefault

#
# Usual options.
#
itk::usual Spintime {
    keep -background -cursor -foreground -highlightcolor -highlightthickness \
	 -labelfont -selectbackground -selectborderwidth -selectforeground \
	 -textbackground -textfont
}

# ------------------------------------------------------------------
#                            SPINTIME
# ------------------------------------------------------------------
class iwidgets::Spintime {
    inherit itk::Widget 
    
    constructor {args} {}
    destructor {}

    itk_option define -orient orient Orient vertical 
    itk_option define -labelpos labelPos Position w 
    itk_option define -houron hourOn HourOn true 
    itk_option define -minuteon minuteOn MinuteOn true 
    itk_option define -secondon secondOn SecondOn true 
    itk_option define -timemargin timeMargin Margin 1 
    itk_option define -militaryon militaryOn MilitaryOn true 

    public method get {{component all}}
    public method insert {component index string} 
    public method delete {component first {last {}}} 

    public method clear {} 
    
    protected method _packTime {{when later}} 
    
    protected variable _repack {}             ;# Reconfiguration flag.
}

#
# Provide a lowercased access method for the Spintime class.
# 
proc ::iwidgets::spintime {pathName args} {
    uplevel ::iwidgets::Spintime $pathName $args
}

# ------------------------------------------------------------------
#                        CONSTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Spintime::constructor {args} {
    #
    # Create Hour Spinner
    #
    itk_component add hour {
	iwidgets::Spinint $itk_interior.hour -fixed 2 -range {0 23}
    } {
	keep -background -cursor -arroworient -foreground \
		-highlightcolor -highlightthickness \
		-labelfont -labelmargin -relief -step -selectbackground \
		-selectborderwidth -selectforeground -textbackground \
		-textfont -repeatdelay -repeatinterval

	rename -labeltext -hourlabel hourLabel Text
	rename -width -hourwidth hourWidth Width
    }
    pack $itk_component(hour) -fill x
    
    #
    # Create Margin Frame 
    #
    itk_component add hr_min_marg {
	frame $itk_interior.hr_min_marg
    } {
	keep -background -cursor
    }
    pack $itk_component(hr_min_marg)
    
    #
    # Create Minute Spinner
    #
    itk_component add minute {
	iwidgets::Spinint $itk_interior.minute -fixed 2 -range {0 59}
    } {
	keep -background -cursor -arroworient -foreground \
		-highlightcolor -highlightthickness \
		-labelfont -labelmargin -relief -step -selectbackground \
		-selectborderwidth -selectforeground -textbackground \
		-textfont -repeatdelay -repeatinterval

	rename -labeltext -minutelabel minuteLabel Text
	rename -width -minutewidth minuteWidth Width
    }
    pack $itk_component(minute) -fill x
    
    #
    # Create Margin Frame 
    #
    itk_component add min_sec_marg {
	frame $itk_interior.min_sec_marg
    } {
	keep -background -cursor
    }
    pack $itk_component(min_sec_marg)
    
    #
    # Create Second Spinner
    #
    itk_component add second {
	iwidgets::Spinint $itk_interior.second -fixed 2 -range {0 59}
    } {
	keep -background -cursor -arroworient -foreground \
		-highlightcolor -highlightthickness \
		-labelfont -labelmargin -relief -step -selectbackground \
		-selectborderwidth -selectforeground -textbackground \
		-textfont -repeatdelay -repeatinterval

	rename -labeltext -secondlabel secondLabel Text
	rename -width -secondwidth secondWidth Width
    }
    pack $itk_component(second) -fill x

    #
    # Explicitly handle configs that may have been ignored earlier.
    #
    eval itk_initialize $args
    # 

    # When idle, pack the time spinner.
    #
    _packTime
}
	
# ------------------------------------------------------------------
#                           DESTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Spintime::destructor {} {
    if {$_repack != ""} {after cancel $_repack}
}

# ------------------------------------------------------------------
#                             OPTIONS
# ------------------------------------------------------------------

# ------------------------------------------------------------------
# OPTION: -orient
# 
# Specifies the orientation of the 3 spinners for Hour, Minute 
# and second.
# ------------------------------------------------------------------
configbody iwidgets::Spintime::orient {
    _packTime
}

# ------------------------------------------------------------------
# OPTION: -labelpos
# 
# Specifies the location of all 3 spinners' labels. 
# Overloaded 
# ------------------------------------------------------------------
configbody iwidgets::Spintime::labelpos {
    switch $itk_option(-labelpos) {
	n {
	    $itk_component(hour) configure -labelpos n
	    $itk_component(minute) configure -labelpos n
	    $itk_component(second) configure -labelpos n
	    
	    #
	    # Un-align labels
	    #
	    $itk_component(hour) configure -labelmargin 1
	    $itk_component(minute) configure -labelmargin 1
	    $itk_component(second) configure -labelmargin 1
	}
	
	s {
	    $itk_component(hour) configure -labelpos s
	    $itk_component(minute) configure -labelpos s
	    $itk_component(second) configure -labelpos s
	    
	    #
	    # Un-align labels
	    #
	    $itk_component(hour) configure -labelmargin 1
	    $itk_component(minute) configure -labelmargin 1
	    $itk_component(second) configure -labelmargin 1
	}
	
	w {
	    $itk_component(hour) configure -labelpos w
	    $itk_component(minute) configure -labelpos w
	    $itk_component(second) configure -labelpos w
	}
	
	e {
	    $itk_component(hour) configure -labelpos e
	    $itk_component(minute) configure -labelpos e
	    $itk_component(second) configure -labelpos e
	    
	    #
	    # Un-align labels
	    #
	    $itk_component(hour) configure -labelmargin 1
	    $itk_component(minute) configure -labelmargin 1
	    $itk_component(second) configure -labelmargin 1
	}
	
	default {
	    error "bad labelpos option \"$itk_option(-labelpos)\",\
		    should be n, s, w or e"
	    
	}
    }

    _packTime
}

# ------------------------------------------------------------------
# OPTION: -houron
# 
# Specifies whether or not to display the hour spinner.
# ------------------------------------------------------------------
configbody iwidgets::Spintime::houron {
    if {$itk_option(-houron)} {
	_packTime
    } else {
	pack forget $itk_component(hour)
    }
}

# ------------------------------------------------------------------
# OPTION: -minuteon
# 
# Specifies whether or not to display the minute spinner.
# ------------------------------------------------------------------
configbody iwidgets::Spintime::minuteon {
    if {$itk_option(-minuteon)} {
	_packTime
    } else {
	pack forget $itk_component(minute)
    }
}

# ------------------------------------------------------------------
# OPTION: -secondon
# 
# Specifies whether or not to display the second spinner.
# ------------------------------------------------------------------
configbody iwidgets::Spintime::secondon {
    if {$itk_option(-secondon)} {
	_packTime
    } else {
	pack forget $itk_component(second)
    }
}


# ------------------------------------------------------------------
# OPTION: -timemargin
# 
# Specifies the margin space between the hour and minute spinners 
# and the minute and second spinners. 
# ------------------------------------------------------------------
configbody iwidgets::Spintime::timemargin {
    _packTime
}

# ------------------------------------------------------------------
# OPTION: -militaryon
#
# Specifies 24-hour clock or 12-hour.
# ------------------------------------------------------------------
configbody iwidgets::Spintime::militaryon {
    if {$itk_option(-militaryon)} {
	$itk_component(hour) configure -range {0 23}
    } else {
	$itk_component(hour) configure -range {1 12}
    }
}

# ------------------------------------------------------------------
#                            METHODS
# ------------------------------------------------------------------

# ------------------------------------------------------------------
# METHOD: get ?component?
#
# Get the value of the time spinner.  A specific component value
# may be obtained via component name hour, minute, or second.  Without
# component name the command returns the time in a list, formatted
# {HH MM SS}.
# ------------------------------------------------------------------
body iwidgets::Spintime::get {{component all}} {
    switch $component {
	all {
	    return [list [$itk_component(hour) get] \
		    [$itk_component(minute) get] \
		    [$itk_component(second) get]]
	}
	
	hour {
	    return [$itk_component(hour) get]
	}
	
	minute {
	    return [$itk_component(minute) get]
	}
	
	second {
	    return [$itk_component(second) get]
	}

	default {
	    error "bad get argument \"$component\": should\
		    be hour, minute or second"
	}
    }
}


# ------------------------------------------------------------------
# METHOD: insert component index string
#
# Insert value into hour, minute or second EntryFields.
# ------------------------------------------------------------------
body iwidgets::Spintime::insert {component index string} {
    switch $component {
	hour {
	    return [$itk_component(hour) insert $index $string]
	}
	minute {
	    return [$itk_component(minute) insert $index $string]
	}
	second {
	    return [$itk_component(second) insert $index $string]
	}
	default {
	    error "bad insert argument \"$component\": should\
		    be hour, minute or second"
	}
    }
}

# ------------------------------------------------------------------
# METHOD: delete component first ?last?
#
# Delete value in hour, minute or second EntryFields
# ------------------------------------------------------------------
body iwidgets::Spintime::delete {component first {last {}}} {
    if {$last == {}} {
	set last $first
    } 
    
    switch $component {
	hour {
	    return [$itk_component(hour) delete $first $last]
	}
	minute {
	    return [$itk_component(minute) delete $first $last]
	}
	second {
	    return [$itk_component(second) delete $first $last]
	}
	default {
	    error "bad delete argument \"$component\": should\
		    be hour, minute or second"
	}
    }
}


# ------------------------------------------------------------------
# METHOD: clear
#
# clear values in all 3 EntryFields
# Note: clear returns an empty string
# ------------------------------------------------------------------
body iwidgets::Spintime::clear {} {
    $itk_component(hour) clear
    $itk_component(minute) clear
    $itk_component(second) clear
}

# ------------------------------------------------------------------
# PROTECTED METHOD: _packTime ?when?
#
# Pack components of time spinner.  If "when" is "now", the change 
# is applied immediately.  If it is "later" or it is not specified,
# then the change is applied later, when the application is idle.
# ------------------------------------------------------------------
body iwidgets::Spintime::_packTime {{when later}} {
    if {$when == "later"} {
	if {$_repack == ""} {
	    set _repack [after idle [code $this _packTime now]]
	}
	return
    } elseif {$when != "now"} {
	error "bad option \"$when\": should be now or later"
    }

    set _repack ""

    switch $itk_option(-orient) {
	vertical {
	    pack forget $itk_component(hour) $itk_component(minute)
	    pack forget $itk_component(second) $itk_component(hr_min_marg) 
	    pack forget $itk_component(min_sec_marg)
	    
	    if {$itk_option(-houron)} {
		pack $itk_component(hour) -side top
		pack $itk_component(hr_min_marg) -side top
		$itk_component(hr_min_marg) configure -height \
			$itk_option(-timemargin) -width 1
	    }
	    
	    if {$itk_option(-minuteon)} {
		pack $itk_component(minute) -side top 
		pack $itk_component(min_sec_marg) -side top
		$itk_component(min_sec_marg) configure -height \
			$itk_option(-timemargin) -width 1
	    }
	    
	    if {$itk_option(-secondon)} {
		pack $itk_component(second) -side top
	    }
	    
	    if {$itk_option(-labelpos) != "n"} {
		iwidgets::Labeledwidget::alignlabels $itk_component(hour) \
			$itk_component(minute) $itk_component(second)
	    }
	}
	
	horizontal {
	    pack forget $itk_component(hour) $itk_component(minute)
	    pack forget $itk_component(second) $itk_component(hr_min_marg)
	    pack forget $itk_component(min_sec_marg)
	    
	    if {$itk_option(-houron)} {
		pack $itk_component(hour) -side left
		pack $itk_component(hr_min_marg) -side left
		$itk_component(hr_min_marg) configure -height 1 \
			-width $itk_option(-timemargin)
	    }
	    
	    if {$itk_option(-minuteon)} {
		pack $itk_component(minute) -side left
		pack $itk_component(min_sec_marg) -side left
		$itk_component(min_sec_marg) configure -height 1 \
			-width $itk_option(-timemargin)
	    }
	    
	    if {$itk_option(-secondon)} {
		pack $itk_component(second) -side left
	    }
	    
	    #
	    # Un-align labels
	    #
	    $itk_component(hour) configure -labelmargin 1
	    $itk_component(minute) configure -labelmargin 1
	    $itk_component(second) configure -labelmargin 1
	}
	
	default {
	    error "bad orient option \"$itk_option(-orient)\", should\
		    be \"vertical\" or \"horizontal\""
	}
    } 
} 


