summaryrefslogtreecommitdiff
path: root/itcl/iwidgets3.0.0/generic/timeentry.itk
blob: 20fb4c7d65feaddde370c19aa78ca2ece888c353 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#
# Timeentry
# ----------------------------------------------------------------------
# Implements a quicken style time entry field with a popup clock
# by combining the timefield and watch widgets together.  This
# allows a user to enter the time via the keyboard or by using the
# mouse by selecting the watch icon which brings up a popup clock.
# ----------------------------------------------------------------------
#   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, UPTIMES, 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.
# ======================================================================

#
# Usual options.
#
itk::usual Timeentry {
    keep -background -borderwidth -cursor -foreground -highlightcolor \
	-highlightthickness -labelfont -textbackground -textfont
}

# ------------------------------------------------------------------
#                              TIMEENTRY
# ------------------------------------------------------------------
class iwidgets::Timeentry {
    inherit iwidgets::Timefield
    
    constructor {args} {}

    itk_option define -grab grab Grab "global"
    itk_option define -icon icon Icon {}
    itk_option define -state state State normal
    itk_option define -closetext closeText Text Close

    #
    # The watch widget isn't created until needed, yet we need
    # its options to be available upon creation of a timeentry widget.
    # So, we'll define them in these class now so they can just be
    # propagated onto the watch later.
    #
    itk_option define -hourradius hourRadius Radius .50
    itk_option define -hourcolor hourColor Color red
    
    itk_option define -minuteradius minuteRadius Radius .80
    itk_option define -minutecolor minuteColor Color yellow
    
    itk_option define -pivotradius pivotRadius Radius .10
    itk_option define -pivotcolor pivotColor Color white
    
    itk_option define -secondradius secondRadius Radius .90
    itk_option define -secondcolor secondColor Color black
    
    itk_option define -clockcolor clockColor Color white
    itk_option define -clockstipple clockStipple ClockStipple {}
    
    itk_option define -tickcolor tickColor Color black

    itk_option define -watchheight watchHeight Height 175
    itk_option define -watchwidth watchWidth Width 155

    protected {
	method _getPopupTime {}
	method _releaseGrab {}
	method _popup {}
	method _getDefaultIcon {}

        common _defaultIcon ""
    }
}

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

#
# Use option database to override default resources of base classes.
#
option add *Timeentry.watchWidth 155 widgetDefault
option add *Timeentry.watchHeight 175 widgetDefault
 
# ------------------------------------------------------------------
#                        CONSTRUCTOR
# ------------------------------------------------------------------
body iwidgets::Timeentry::constructor {args} {
    #
    # Create an icon label to act as a button to bring up the 
    # watch 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 clock icon image to be used in the time entry.  
# Should one not be provided, then a default pixmap will be used
# if possible, bitmap otherwise.
# ------------------------------------------------------------------
configbody iwidgets::Timeentry::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 watch.  The default is global.
# ------------------------------------------------------------------
configbody iwidgets::Timeentry::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 time field
# or time icon button.
# ------------------------------------------------------------------
configbody iwidgets::Timeentry::state {
    switch -- $itk_option(-state) {
	normal {
	    bind $itk_component(iconbutton) <Button-1> [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.
# ------------------------------------------------------------------
body iwidgets::Timeentry::_getDefaultIcon {} {

  if {[lsearch [image types] pixmap] != -1} {
	set _defaultIcon [image create pixmap -data {
		    /* XPM */
		    static char *watch1a[] = {
			/* width height num_colors chars_per_pixel */
			"    20    20        8            1",
			/* colors */
			". c #000000",
			"# c #000099",
			"a c #009999",
			"b c #999999",
			"c c #cccccc",
			"d c #ffff00",
			"e c #d9d9d9",
			"f c #ffffff",
			/* pixels */
			"eeeeebbbcccccbbbeeee",
			"eeeee...#####..beeee",
			"eeeee#aacccccaabeeee",
			"eeee#accccccccc##eee",
			"eee#ccc#cc#ccdcff#ee",
			"ee#accccccccccfcca#e",
			"eeaccccccc.cccfcccae",
			"eeac#cccfc.cccc##cae",
			"e#cccccffc.cccccccc#",
			"e#ccccfffc.cccccccc#",
			"e#cc#ffcc......c#cc#",
			"e#ccfffccc.cccccccc#",
			"e#cffccfcc.cccccccc#",
			"eeafdccfcccccccd#cae",
			"eeafcffcccccccccccae",
			"eee#fcc#cccccdccc#ee",
			"eee#fcc#cc#cc#ccc#ee",
			"eeee#accccccccc##eee",
			"eeeee#aacccccaabeeee",
			"eeeee...#####..beeee"
		    };
		}]
    } else {
	set _defaultIcon [image create bitmap -data {
		    #define watch1a_width 20
		    #define watch1a_height 20
		    static char watch1a_bits[] = {
			0x40,0x40,0xf0,0xe0,0x7f,0xf0,0xe0,0xe0,0xf0,0x30,
			0x80,0xf1,0x88,0x04,0xf2,0x0c,0x00,0xf6,0x04,0x04,
			0xf4,0x94,0x84,0xf5,0x02,0x06,0xf8,0x02,0x0c,0xf8,
			0x12,0x7e,0xf9,0x02,0x04,0xf8,0x02,0x24,0xf8,0x04,
			0x00,0xf5,0x04,0x00,0xf4,0x88,0x02,0xf2,0x88,0x64,
			0xf2,0x30,0x80,0xf1,0xe0,0x60,0xf0,0xe0,0xff,0xf0};
		}]
    }

    #
    # Since this image will only need to be created once, we redefine
    # this method to just return the image name for subsequent calls.
    #
    body ::iwidgets::Timeentry::_getDefaultIcon {} {
	return $_defaultIcon
    }

    return $_defaultIcon
}


# ------------------------------------------------------------------
# PROTECTED METHOD: _popup
#
# This method is invoked upon selection of the icon button.  It 
# creates a watch widget within a toplevel popup, calculates 
# the position at which to display the watch, performs a grab
# and displays the watch.
# ------------------------------------------------------------------
body iwidgets::Timeentry::_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 for Escape to always release the grab.
    #
    bind $itk_component(popup) <KeyPress-Escape> [code $this _releaseGrab]

    #
    # Create the watch widget.
    #
    itk_component add watch {
	iwidgets::Watch $itk_component(popup).watch
    } {
	usual

	rename -width -watchwidth watchWidth Width 
	rename -height -watchheight watchHeight Height 

	keep -hourradius -minuteradius -minutecolor -pivotradius -pivotcolor \
	    -secondradius -secondcolor -clockcolor -clockstipple -tickcolor 
    }
    grid $itk_component(watch) -row 0 -column 0
    $itk_component(watch) configure -cursor top_left_arrow

    #
    # Create a button widget so the user can say they are done.
    #
    itk_component add close {
	button $itk_component(popup).close -command [code $this _getPopupTime]
    } {
	usual
	rename -text -closetext closeText Text
    }
    grid $itk_component(close) -row 1 -column 0 -sticky ew
    $itk_component(close) 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 [cget -watchwidth]
    set popupheight [expr [cget -watchheight] + \
			 [winfo reqheight $itk_component(close)]]

    set popupx [expr $rootx + 3 + \
		    [winfo width $itk_component(iconbutton)]]
    set popupy [expr $rooty + 3 + \
		    [winfo height $itk_component(iconbutton)]]

    if {([expr $popupx + $popupwidth] > [winfo screenwidth .]) || \
	    ([expr $popupy + $popupheight] > [winfo screenheight .])} {
	set popupx [expr $rootx - 3 - $popupwidth]
	set popupy [expr $rooty - 3 - $popupheight]
    }
    
    #
    # Get the current time from the timefield widget and both
    # show and select it on the watch.
    #
    $itk_component(watch) show [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(watch)
}

# ------------------------------------------------------------------
# PROTECTED METHOD: _popupGetTime
#
# This method is the callback for selection of a time on the 
# watch.  It releases the grab and sets the time in the
# timefield widget.
# ------------------------------------------------------------------
body iwidgets::Timeentry::_getPopupTime {} {
    show [$itk_component(watch) get -clicks]
    _releaseGrab 
}

# ------------------------------------------------------------------
# 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.
# ------------------------------------------------------------------
body iwidgets::Timeentry::_releaseGrab {} {
    grab release $itk_component(popup)
    $itk_component(iconbutton) configure -relief raised
    destroy $itk_component(popup) 
    unset itk_component(popup)
    bind $itk_component(iconbutton) <Button-1> [code $this _popup]
}