diff options
Diffstat (limited to 'iwidgets/generic/dateentry.itk')
-rw-r--r-- | iwidgets/generic/dateentry.itk | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/iwidgets/generic/dateentry.itk b/iwidgets/generic/dateentry.itk new file mode 100644 index 00000000000..0e8c146e7bf --- /dev/null +++ b/iwidgets/generic/dateentry.itk @@ -0,0 +1,424 @@ +# +# Dateentry +# ---------------------------------------------------------------------- +# Implements a quicken style date entry field with a popup calendar +# by combining the datefield and calendar widgets together. This +# allows a user to enter the date via the keyboard or by using the +# mouse by selecting the calendar icon which brings up a popup calendar. +# ---------------------------------------------------------------------- +# AUTHOR: Mark L. Ulferts E-mail: mulferts@austin.dsccc.com +# +# @(#) $Id$ +# ---------------------------------------------------------------------- +# Copyright (c) 1997 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. +# ====================================================================== +# +# ---------------------------------------------------------------------- +# +# Modified 2001-10-23 by Mark Alston to pass options to the datefield +# constructor. Needed to allow use of new option -int which lets the +# user use dates in YYYY-MM-DD format as well as MM/DD/YYYY format. +# +# option -int yes sets dates to YYYY-MM-DD format +# -int no sets dates to MM/DD/YYYY format. +# +# ---------------------------------------------------------------------- +# +# Usual options. +# +itk::usual Dateentry { + keep -background -borderwidth -currentdatefont -cursor \ + -datefont -dayfont -foreground -highlightcolor \ + -highlightthickness -labelfont -textbackground -textfont \ + -titlefont -int +} + +# ------------------------------------------------------------------ +# DATEENTRY +# ------------------------------------------------------------------ +itcl::class iwidgets::Dateentry { + inherit iwidgets::Datefield + + constructor {args} { + eval Datefield::constructor $args + } {} + + itk_option define -grab grab Grab "global" + itk_option define -icon icon Icon {} + + # + # The calendar widget isn't created until needed, yet we need + # its options to be available upon creation of a dateentry widget. + # So, we'll define them in these class now so they can just be + # propagated onto the calendar later. + # + itk_option define -days days Days {Su Mo Tu We Th Fr Sa} + itk_option define -forwardimage forwardImage Image {} + itk_option define -backwardimage backwardImage Image {} + itk_option define -weekdaybackground weekdayBackground Background \#d9d9d9 + itk_option define -weekendbackground weekendBackground Background \#d9d9d9 + itk_option define -outline outline Outline \#d9d9d9 + itk_option define -buttonforeground buttonForeground Foreground blue + itk_option define -foreground foreground Foreground black + itk_option define -selectcolor selectColor Foreground red + itk_option define -selectthickness selectThickness SelectThickness 3 + itk_option define -titlefont titleFont Font \ + -*-helvetica-bold-r-normal--*-140-* + itk_option define -dayfont dayFont Font \ + -*-helvetica-medium-r-normal--*-120-* + itk_option define -datefont dateFont Font \ + -*-helvetica-medium-r-normal--*-120-* + itk_option define -currentdatefont currentDateFont Font \ + -*-helvetica-bold-r-normal--*-120-* + itk_option define -startday startDay Day sunday + itk_option define -height height Height 165 + itk_option define -width width Width 200 + itk_option define -state state State normal + + protected { + method _getPopupDate {date} + method _releaseGrab {} + method _releaseGrabCheck {rootx rooty} + method _popup {} + method _getDefaultIcon {} + + common _defaultIcon "" + } +} + +# +# Provide a lowercased access method for the dateentry class. +# +proc ::iwidgets::dateentry {pathName args} { + uplevel ::iwidgets::Dateentry $pathName $args +} + +# ------------------------------------------------------------------ +# CONSTRUCTOR +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::constructor {args} { + # + # Create an icon label to act as a button to bring up the + # calendar popup. + # + itk_component add iconbutton { + label $itk_interior.iconbutton -relief raised + } { + keep -borderwidth -cursor -foreground + } + grid $itk_component(iconbutton) -row 0 -column 0 -sticky ns + + # + # Initialize the widget based on the command line options. + # + eval itk_initialize $args +} + +# ------------------------------------------------------------------ +# OPTIONS +# ------------------------------------------------------------------ + +# ------------------------------------------------------------------ +# OPTION: -icon +# +# Specifies the calendar icon image to be used in the date. +# Should one not be provided, then a default pixmap will be used +# if possible, bitmap otherwise. +# ------------------------------------------------------------------ +itcl::configbody iwidgets::Dateentry::icon { + if {$itk_option(-icon) == {}} { + $itk_component(iconbutton) configure -image [_getDefaultIcon] + } else { + if {[lsearch [image names] $itk_option(-icon)] == -1} { + error "bad icon option \"$itk_option(-icon)\":\ + should be an existing image" + } else { + $itk_component(iconbutton) configure -image $itk_option(-icon) + } + } +} + +# ------------------------------------------------------------------ +# OPTION: -grab +# +# Specifies the grab level, local or global, to be obtained when +# bringing up the popup calendar. The default is global. +# ------------------------------------------------------------------ +itcl::configbody iwidgets::Dateentry::grab { + switch -- $itk_option(-grab) { + "local" - "global" {} + default { + error "bad grab option \"$itk_option(-grab)\":\ + should be local or global" + } + } +} + +# ------------------------------------------------------------------ +# OPTION: -state +# +# Specifies the state of the widget which may be disabled or +# normal. A disabled state prevents selection of the date field +# or date icon button. +# ------------------------------------------------------------------ +itcl::configbody iwidgets::Dateentry::state { + switch -- $itk_option(-state) { + normal { + bind $itk_component(iconbutton) <Button-1> [itcl::code $this _popup] + } + disabled { + bind $itk_component(iconbutton) <Button-1> {} + } + } +} + +# ------------------------------------------------------------------ +# METHODS +# ------------------------------------------------------------------ + +# ------------------------------------------------------------------ +# PROTECTED METHOD: _getDefaultIcon +# +# This method is invoked uto retrieve the name of the default icon +# image displayed in the icon button. +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::_getDefaultIcon {} { + if {[lsearch [image types] pixmap] != -1} { + set _defaultIcon [image create pixmap -data { + /* XPM */ + static char *calendar[] = { + /* width height num_colors chars_per_pixel */ + " 25 20 6 1", + /* colors */ + ". c #808080", + "# c #040404", + "a c #848484", + "b c #fc0404", + "c c #fcfcfc", + "d c #c0c0c0", + /* pixels */ + "d##########d###########dd", + "d#ccccccccc##ccccccccca#d", + "##ccccccccc.#ccccccccc..#", + "##cccbbcccca#cccbbbccca.#", + "##cccbbcccc.#ccbbbbbcc..#", + "##cccbbccc####ccccbbcc..#", + "##cccbbcccca#ccccbbbcca.#", + "##cccbbcccc.#cccbbbccc..#", + "##cccbbcccca#ccbbbcccca.#", + "##cccbbbccc.#ccbbbbbcc..#", + "##ccccccccc.#ccccccccc..#", + "##ccccccccca#ccccccccca.#", + "##cc#####c#cd#c#####cc..#", + "##cccccccc####cccccccca.#", + "##cc#####cc.#cc#####cc..#", + "##ccccccccc.#ccccccccc..#", + "##ccccccccc.#ccccccccc..#", + "##..........#...........#", + "###..........#..........#", + "#########################" + }; + }] + } else { + set _defaultIcon [image create bitmap -data { + #define calendr2_width 25 + #define calendr2_height 20 + static char calendr2_bits[] = { + 0xfe,0xf7,0x7f,0xfe,0x02,0x18,0xc0,0xfe,0x03, + 0x18,0x80,0xff,0x63,0x10,0x47,0xff,0x43,0x98, + 0x8a,0xff,0x63,0x3c,0x4c,0xff,0x43,0x10,0x8a, + 0xff,0x63,0x18,0x47,0xff,0x23,0x90,0x81,0xff, + 0xe3,0x98,0x4e,0xff,0x03,0x10,0x80,0xff,0x03, + 0x10,0x40,0xff,0xf3,0xa5,0x8f,0xff,0x03,0x3c, + 0x40,0xff,0xf3,0x99,0x8f,0xff,0x03,0x10,0x40, + 0xff,0x03,0x18,0x80,0xff,0x57,0x55,0x55,0xff, + 0x57,0xb5,0xaa,0xff,0xff,0xff,0xff,0xff}; + }] + } + + # + # Since this image will only need to be created once, we redefine + # this method to just return the image name for subsequent calls. + # + itcl::body ::iwidgets::Dateentry::_getDefaultIcon {} { + return $_defaultIcon + } + + return $_defaultIcon +} + +# ------------------------------------------------------------------ +# PROTECTED METHOD: _popup +# +# This method is invoked upon selection of the icon button. It +# creates a calendar widget within a toplevel popup, calculates +# the position at which to display the calendar, performs a grab +# and displays the calendar. +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::_popup {} { + # + # First, let's nullify the icon binding so that any another + # selections are ignored until were done with this one. Next, + # change the relief of the icon. + # + bind $itk_component(iconbutton) <Button-1> {} + $itk_component(iconbutton) configure -relief sunken + + # + # Create a withdrawn toplevel widget and remove the window + # decoration via override redirect. + # + itk_component add -private popup { + toplevel $itk_interior.popup + } + $itk_component(popup) configure -borderwidth 2 -background black + wm withdraw $itk_component(popup) + wm overrideredirect $itk_component(popup) 1 + + # + # Add a binding to button 1 events in order to detect mouse + # clicks off the calendar in which case we'll release the grab. + # Also add a binding for Escape to always release. + # + bind $itk_component(popup) <1> [itcl::code $this _releaseGrabCheck %X %Y] + bind $itk_component(popup) <KeyPress-Escape> [itcl::code $this _releaseGrab] + + # + # Create the calendar widget and set its cursor properly. + # + itk_component add calendar { + iwidgets::Calendar $itk_component(popup).calendar \ + -command [itcl::code $this _getPopupDate %d] \ + -int $itk_option(-int) + } { + usual + keep -days -forwardimage -backwardimage -weekdaybackground \ + -weekendbackground -outline -buttonforeground -selectcolor \ + -selectthickness -titlefont -dayfont -datefont \ + -currentdatefont -startday -width -height + } + grid $itk_component(calendar) -row 0 -column 0 + $itk_component(calendar) configure -cursor top_left_arrow + + # + # The icon button will be used as the basis for the position of the + # popup on the screen. We'll always attempt to locate the popup + # off the lower right corner of the button. If that would put + # the popup off the screen, then we'll put above the upper left. + # + set rootx [winfo rootx $itk_component(iconbutton)] + set rooty [winfo rooty $itk_component(iconbutton)] + set popupwidth [winfo reqwidth $itk_component(popup)] + set popupheight [winfo reqheight $itk_component(popup)] + + set popupx [expr {$rootx + 3 + \ + [winfo width $itk_component(iconbutton)]}] + set popupy [expr {$rooty + 3 + \ + [winfo height $itk_component(iconbutton)]}] + + if {(($popupx + $popupwidth) > [winfo screenwidth .]) || \ + (($popupy + $popupheight) > [winfo screenheight .])} { + set popupx [expr {$rootx - 3 - $popupwidth}] + set popupy [expr {$rooty - 3 - $popupheight}] + } + + # + # Get the current date from the datefield widget and both + # show and select it on the calendar. + # + # Added catch for bad dates. Calendar then shows current date. + if [catch "$itk_component(calendar) show [get]" err] { + $itk_component(calendar) show now + $itk_component(calendar) select now + } else { + $itk_component(calendar) select [get] + } + # + # Display the popup at the calculated position. + # + wm geometry $itk_component(popup) +$popupx+$popupy + wm deiconify $itk_component(popup) + tkwait visibility $itk_component(popup) + + # + # Perform either a local or global grab based on the -grab option. + # + if {$itk_option(-grab) == "local"} { + grab $itk_component(popup) + } else { + grab -global $itk_component(popup) + } + + # + # Make sure the widget is above all others and give it focus. + # + raise $itk_component(popup) + focus $itk_component(calendar) +} + +# ------------------------------------------------------------------ +# PROTECTED METHOD: _popupGetDate +# +# This method is the callback for selection of a date on the +# calendar. It releases the grab and sets the date in the +# datefield widget. +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::_getPopupDate {date} { + _releaseGrab + show $date +} + +# ------------------------------------------------------------------ +# PROTECTED METHOD: _releaseGrabCheck rootx rooty +# +# This method handles mouse button 1 events. If the selection +# occured within the bounds of the calendar, then return normally +# and let the calendar handle the event. Otherwise, we'll drop +# the calendar and release the grab. +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::_releaseGrabCheck {rootx rooty} { + set calx [winfo rootx $itk_component(calendar)] + set caly [winfo rooty $itk_component(calendar)] + set calwidth [winfo reqwidth $itk_component(calendar)] + set calheight [winfo reqheight $itk_component(calendar)] + + if {($rootx < $calx) || ($rootx > ($calx + $calwidth)) || \ + ($rooty < $caly) || ($rooty > ($caly + $calheight))} { + _releaseGrab + return -code break + } +} + +# ------------------------------------------------------------------ +# PROTECTED METHOD: _releaseGrab +# +# This method releases the grab, destroys the popup, changes the +# relief of the button back to raised and reapplies the binding +# to the icon button that engages the popup action. +# ------------------------------------------------------------------ +itcl::body iwidgets::Dateentry::_releaseGrab {} { + grab release $itk_component(popup) + $itk_component(iconbutton) configure -relief raised + destroy $itk_component(popup) + bind $itk_component(iconbutton) <Button-1> [itcl::code $this _popup] +} |