OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / tix / library / Control.tcl
1 # Control.tcl --
2 #
3 #       Implements the TixControl Widget. It is called the "SpinBox"
4 #       in other toolkits.
5 #
6 # Copyright (c) 1996, Expert Interface Technologies
7 #
8 # See the file "license.terms" for information on usage and redistribution
9 # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 #
11
12 tixWidgetClass tixControl {
13     -classname  TixControl
14     -superclass tixLabelWidget
15     -method {
16         incr decr invoke update
17     }
18     -flag {
19         -allowempty -autorepeat -command -decrcmd -disablecallback
20         -disabledforeground -incrcmd -initwait -integer -llimit
21         -repeatrate -max -min -selectmode -step -state -validatecmd
22         -value -variable -ulimit
23     }
24     -forcecall {
25         -variable -state
26     }
27     -configspec {
28         {-allowempty allowEmpty AllowEmpty false}
29         {-autorepeat autoRepeat AutoRepeat true}
30         {-command command Command ""}
31         {-decrcmd decrCmd DecrCmd ""}
32         {-disablecallback disableCallback DisableCallback 0 tixVerifyBoolean}
33         {-disabledforeground disabledForeground DisabledForeground #303030}
34         {-incrcmd incrCmd IncrCmd ""}
35         {-initwait initWait InitWait 500}
36         {-integer integer Integer false}
37         {-max max Max ""}
38         {-min min Min ""}
39         {-repeatrate repeatRate RepeatRate 50}
40         {-step step Step 1}
41         {-state state State normal}
42         {-selectmode selectMode SelectMode normal}
43         {-validatecmd validateCmd ValidateCmd ""}
44         {-value value Value 0}
45         {-variable variable Variable ""}
46     }
47     -alias {
48         {-llimit -min}
49         {-ulimit -max}
50     }
51     -default {
52         {.borderWidth                   0}
53         {*entry.relief                  sunken}
54         {*entry.width                   5}
55         {*label.anchor                  e}
56         {*label.borderWidth             0}
57         {*Label.font                   -Adobe-Helvetica-Bold-R-Normal--*-120-*}
58         {*Button.anchor                 c}
59         {*Button.borderWidth            2}
60         {*Button.highlightThickness     1}
61         {*Button.takeFocus              0}
62         {*Entry.background              #c3c3c3}
63     }
64 }
65
66 proc tixControl:InitWidgetRec {w} {
67     upvar #0 $w data
68
69     tixChainMethod $w InitWidgetRec
70
71     set data(varInited)   0
72     set data(serial)    0
73 }
74
75 proc tixControl:ConstructFramedWidget {w frame} {
76     upvar #0 $w data
77
78     tixChainMethod $w ConstructFramedWidget $frame
79
80     set data(w:entry)  [entry $frame.entry]
81
82     set data(w:incr) [button $frame.incr -bitmap [tix getbitmap incr] \
83         -takefocus 0]
84     set data(w:decr) [button $frame.decr -bitmap [tix getbitmap decr] \
85         -takefocus 0]
86
87 #    tixForm $data(w:entry) -left 0 -top 0 -bottom -1 -right $data(w:decr) 
88 #    tixForm $data(w:incr) -right -1 -top 0 -bottom %50
89 #    tixForm $data(w:decr) -right -1 -top $data(w:incr) -bottom -1
90
91     pack $data(w:entry) -side left   -expand yes -fill both
92     pack $data(w:decr)  -side bottom -fill both -expand yes
93     pack $data(w:incr)  -side top    -fill both -expand yes
94
95     $data(w:entry) delete 0 end
96     $data(w:entry) insert 0 $data(-value)
97
98     # This value is used to configure the disable/normal fg of the ebtry
99     set data(entryfg) [$data(w:entry) cget -fg]
100     set data(labelfg) [$data(w:label) cget -fg]
101 }
102
103 proc tixControl:SetBindings {w} {
104     upvar #0 $w data
105
106     tixChainMethod $w SetBindings
107
108     if {$data(-autorepeat)} {
109         bind $data(w:incr) <ButtonPress-1> \
110                 [format {after idle tixControl:StartRepeat %s  1} $w]
111         bind $data(w:decr) <ButtonPress-1> \
112                 [format {after idle tixControl:StartRepeat %s  -1} $w]
113
114         # These bindings will stop the button autorepeat when the 
115         # mouse button is up
116         foreach btn "$data(w:incr) $data(w:decr)" amt {1 -1} {
117             bind $btn <ButtonRelease-1> "tixControl:StopRepeat $w $amt"
118         }
119     } else {
120         # Force the non-autorepeat case to use the normal
121         # tk button class bindings
122         $data(w:incr) configure -command "tixControl:incr $w"
123         $data(w:decr) configure -command "tixControl:decr $w"
124     }
125
126     tixSetMegaWidget $data(w:entry) $w
127
128     # If user press <return>, verify the value and call the -command
129     #
130     tixAddBindTag $data(w:entry) TixControl:Entry 
131 }
132
133 proc tixControlBind {} {
134     tixBind TixControl:Entry <Return> {
135         tixControl:Invoke [tixGetMegaWidget %W] 1
136     }
137     tixBind TixControl:Entry <Escape> {
138         tixControl:Escape [tixGetMegaWidget %W]
139     }
140     tixBind TixControl:Entry <Up> {
141         [tixGetMegaWidget %W] incr
142     }
143     tixBind TixControl:Entry <Down> {
144         [tixGetMegaWidget %W] decr
145     }
146     tixBind TixControl:Entry <FocusOut> {
147         if {"%d" == "NotifyNonlinear" || "%d" == "NotifyNonlinearVirtual"} {
148             tixControl:Tab [tixGetMegaWidget %W] %d
149         }
150     }
151     tixBind TixControl:Entry <Any-KeyPress> {
152         tixControl:KeyPress [tixGetMegaWidget %W]
153     }
154     tixBind TixControl:Entry <Any-Tab> {
155         # This has a higher priority than the <Any-KeyPress>  binding
156         # --> so that data(edited) is not set
157     }
158 }
159
160 #----------------------------------------------------------------------
161 #                           CONFIG OPTIONS
162 #----------------------------------------------------------------------
163 proc tixControl:config-state {w arg} {
164     upvar #0 $w data
165
166     if {$arg == "normal"} {
167         $data(w:incr)  config -state $arg
168         $data(w:decr)  config -state $arg
169         catch {
170             $data(w:label) config -fg $data(labelfg)
171         }
172         $data(w:entry) config -state $arg -fg $data(entryfg)
173         tixControl:SetBindings $w
174     } else {
175         $data(w:incr)  config -state $arg
176         $data(w:decr)  config -state $arg
177         catch {
178             $data(w:label) config -fg $data(-disabledforeground)
179         }
180         $data(w:entry) config -state $arg -fg $data(-disabledforeground)
181         bind $data(w:incr) <ButtonPress-1> {}
182         bind $data(w:decr) <ButtonPress-1> {}
183     }
184 }
185
186 proc tixControl:config-value {w value} {
187     upvar #0 $w data
188
189     tixControl:SetValue $w $value 0 1
190
191     # This will tell the Intrinsics: "Please use this value"
192     # because "value" might be altered by SetValues
193     #
194     return $data(-value)
195 }
196
197 proc tixControl:config-variable {w arg} {
198     upvar #0 $w data
199
200     if [tixVariable:ConfigVariable $w $arg] {
201        # The value of data(-value) is changed if tixVariable:ConfigVariable 
202        # returns true
203        tixControl:SetValue $w $data(-value) 1 1
204     }
205     catch {
206         unset data(varInited)
207     }
208     set data(-variable) $arg
209 }
210
211 #----------------------------------------------------------------------
212 #                         User Commands
213 #----------------------------------------------------------------------
214 proc tixControl:incr {w {by 1}} {
215     upvar #0 $w data
216
217     if {$data(-state) != "disabled"} {
218         if {[catch {$data(w:entry) index sel.first}] == 0} {
219             $data(w:entry) select from end
220             $data(w:entry) select to   end
221         }
222         # CYGNUS LOCAL - why set value before changing it?
223         #tixControl:SetValue $w [$data(w:entry) get] 0 1
224         tixControl:AdjustValue $w $by
225     }
226 }
227
228 proc tixControl:decr {w {by 1}} {
229     upvar #0 $w data
230
231     if {$data(-state) != "disabled"} {
232         if {[catch {$data(w:entry) index sel.first}] == 0} {
233             $data(w:entry) select from end
234             $data(w:entry) select to   end
235         }
236         # CYGNUS LOCAL - why set value before changing it?
237         #tixControl:SetValue $w [$data(w:entry) get] 0 1
238         tixControl:AdjustValue $w [expr 0 - $by]
239     }
240 }
241
242 proc tixControl:invoke {w} {
243     upvar #0 $w data
244
245     tixControl:Invoke $w 0
246 }
247
248 proc tixControl:update {w} {
249     upvar #0 $w data
250
251     if [info exists data(edited)] {
252         tixControl:invoke $w
253     }
254 }
255
256 #----------------------------------------------------------------------
257 #                       Internal Commands
258 #----------------------------------------------------------------------
259
260 # Change the value by a multiple of the data(-step)
261 #
262 proc tixControl:AdjustValue {w amount} {
263     upvar #0 $w data
264
265     if {$amount == 1 && $data(-incrcmd) != ""} {
266         set newValue [tixEvalCmdBinding $w $data(-incrcmd) "" $data(-value)]
267     } elseif {$amount == -1 && $data(-decrcmd) != ""} {
268         set newValue [tixEvalCmdBinding $w $data(-decrcmd) "" $data(-value)]
269     } else {
270         set newValue [expr $data(-value) + $amount * $data(-step)]
271     }
272
273     if {$data(-state) != "disabled"} {
274         tixControl:SetValue $w $newValue 0 1
275     }
276 }
277
278 proc tixControl:SetValue {w newvalue noUpdate forced} {
279     upvar #0 $w data
280
281     if {[$data(w:entry) selection present]} {
282         set oldSelection \
283             "[$data(w:entry) index sel.first] [$data(w:entry) index sel.last]"
284     }
285
286     set oldvalue $data(-value)
287     set oldCursor [$data(w:entry) index insert]
288     set changed 0
289
290
291     if {$data(-validatecmd) != ""} {
292         # Call the user supplied validation command
293         #
294        set data(-value) [tixEvalCmdBinding $w $data(-validatecmd) "" $newvalue]
295     } else {
296         # Here we only allow int or floating numbers
297         #
298         # If the new value is not a valid number, the old value will be
299         # kept due to the "catch" statements
300         #
301         if [catch {expr 0+$newvalue}] {
302             set newvalue 0
303             set data(-value) 0
304             set changed 1
305         }
306
307         if {$newvalue == ""} {
308             if {![tixGetBoolean -nocomplain $data(-allowempty)]} {
309                 set newvalue 0
310                 set changed 1
311             } else {
312                 set data(-value) ""
313             }
314         }
315
316         if {$newvalue != ""} {
317             # Change this to a valid decimal string (trim leading 0)
318             #
319             regsub {^[0]*} $newvalue "" newvalue
320             if [catch {expr 0+$newvalue}] {
321                 set newvalue 0
322                 set data(-value) 0
323                 set changed 1
324             }
325             if {$newvalue == ""} {
326                 set newvalue 0
327             }
328
329             if [tixGetBoolean -nocomplain $data(-integer)] {
330                 set data(-value) [tixGetInt -nocomplain $newvalue]
331             } else {
332                 if [catch {set data(-value) [format "%d" $newvalue]}] {
333                     if [catch {set data(-value) [expr $newvalue+0.0]}] {
334                         set data(-value) $oldvalue
335                     }
336                 }
337             }
338             
339             # Now perform boundary checking
340             #
341             if {$data(-max) != "" && $data(-value) > $data(-max)} {
342                 set data(-value) $data(-max)
343             }
344             if {$data(-min) != "" && $data(-value) < $data(-min)} {
345                 set data(-value) $data(-min)
346             }
347         }
348     }
349
350     if {! $noUpdate} {
351         tixVariable:UpdateVariable $w
352     }
353
354     if {$forced || "x$newvalue" != "x$data(-value)" || $changed} {
355         $data(w:entry) delete 0 end
356         $data(w:entry) insert 0 $data(-value)
357         $data(w:entry) icursor $oldCursor
358         if {[info exists oldSelection]} {
359             eval $data(w:entry) selection range $oldSelection
360         }
361     }
362
363     if {!$data(-disablecallback) && $data(-command) != ""} {
364         if {![info exists data(varInited)]} {
365             set bind(specs) ""
366             tixEvalCmdBinding $w $data(-command) bind $data(-value)
367         }
368     }
369 }
370
371 proc tixControl:Invoke {w forced} {
372     upvar #0 $w data
373
374     catch {
375         unset data(edited)
376     }
377
378     if {[catch {$data(w:entry) index sel.first}] == 0} {
379         # THIS ENTRY OWNS SELECTION --> TURN IT OFF
380         #
381         $data(w:entry) select from end
382         $data(w:entry) select to   end
383     }
384
385     tixControl:SetValue $w [$data(w:entry) get] 0 $forced
386 }
387
388 #----------------------------------------------------------------------
389 # The three functions StartRepeat, Repeat and StopRepeat make use of the
390 # data(serial) variable to discard spurious repeats: If a button is clicked
391 # repeatedly but is not hold down, the serial counter will increase
392 # successively and all "after" time event handlers will be discarded
393 #----------------------------------------------------------------------
394 proc tixControl:StartRepeat {w amount} {
395     if {![winfo exists $w]} {
396         return
397     }
398
399     upvar #0 $w data
400
401     incr data(serial)
402     # CYGNUS LOCAL bug fix
403     # Need to set a local variable because otherwise the buttonrelease
404     # callback could change the value of data(serial) between now and
405     # the time the repeat is scheduled.
406     set serial $data(serial)
407
408     if {$data(-autorepeat)} {
409         tixControl:doAdjustValue $w $amount
410         after $data(-initwait) tixControl:Repeat $w $amount $serial
411     }
412
413     focus $data(w:entry)
414 }
415
416 proc tixControl:doAdjustValue {w amount} {
417
418     upvar #0 $w data
419
420     if {[catch {$data(w:entry) index sel.first}] == 0} {
421         $data(w:entry) select from end
422         $data(w:entry) select to   end
423     }
424
425     if [info exists data(edited)] {
426         unset data(edited)
427         tixControl:SetValue $w [$data(w:entry) get] 0 1
428     }
429
430     tixControl:AdjustValue $w $amount
431 }
432
433 proc tixControl:Repeat {w amount serial} {
434     if {![winfo exists $w]} {
435         return
436     }
437     upvar #0 $w data
438
439     if {$serial == $data(serial)} {
440         tixControl:AdjustValue $w $amount
441
442         if {$data(-autorepeat)} {
443            after $data(-repeatrate) tixControl:Repeat $w $amount $serial
444         }
445     }
446 }
447
448 proc tixControl:StopRepeat {w amount} {
449     upvar #0 $w data
450
451     if {$data(-autorepeat) == "false" } {
452         tixControl:doAdjustValue $w $amount
453     }
454
455     incr data(serial)
456 }
457
458 proc tixControl:Destructor {w} {
459
460     tixVariable:DeleteVariable $w
461
462     # Chain this to the superclass
463     #
464     tixChainMethod $w Destructor
465 }
466
467 # ToDo: maybe should return -code break if the value is not good ...
468 #
469 proc tixControl:Tab {w detail} {
470     upvar #0 $w data
471
472     if {![info exists data(edited)]} {
473         return
474     } else {
475         unset data(edited)
476     }
477
478     tixControl:invoke $w
479 }
480
481 proc tixControl:Escape {w} {
482     upvar #0 $w data
483
484     $data(w:entry) delete 0 end
485     $data(w:entry) insert 0 $data(-value)
486 }
487
488 proc tixControl:KeyPress {w} {
489     upvar #0 $w data
490
491     if {$data(-selectmode) == "normal"} {
492         set data(edited) 0
493         return
494     } else {
495         # == "immediate"
496         after 1 tixControl:invoke $w
497     }
498 }