| # |
| # 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: dateentry.itk,v 1.6 2002/09/05 19:33:58 smithc Exp $ |
| # ---------------------------------------------------------------------- |
| # 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] |
| } |