483 lines
12 KiB
Tcl
483 lines
12 KiB
Tcl
|
# -*- mode: TCL; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*-
|
||
|
#
|
||
|
# $Id: Control.tcl,v 1.9 2004/03/28 02:44:57 hobbs Exp $
|
||
|
#
|
||
|
# Control.tcl --
|
||
|
#
|
||
|
# Implements the TixControl Widget. It is called the "SpinBox"
|
||
|
# in other toolkits.
|
||
|
#
|
||
|
# Copyright (c) 1993-1999 Ioi Kim Lam.
|
||
|
# Copyright (c) 2000-2001 Tix Project Group.
|
||
|
# Copyright (c) 2004 ActiveState
|
||
|
#
|
||
|
# See the file "license.terms" for information on usage and redistribution
|
||
|
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
|
#
|
||
|
|
||
|
tixWidgetClass tixControl {
|
||
|
-classname TixControl
|
||
|
-superclass tixLabelWidget
|
||
|
-method {
|
||
|
incr decr invoke update
|
||
|
}
|
||
|
-flag {
|
||
|
-allowempty -autorepeat -command -decrcmd -disablecallback
|
||
|
-disabledforeground -incrcmd -initwait -integer -llimit
|
||
|
-repeatrate -max -min -selectmode -step -state -validatecmd
|
||
|
-value -variable -ulimit
|
||
|
}
|
||
|
-forcecall {
|
||
|
-variable -state
|
||
|
}
|
||
|
-configspec {
|
||
|
{-allowempty allowEmpty AllowEmpty false}
|
||
|
{-autorepeat autoRepeat AutoRepeat true}
|
||
|
{-command command Command ""}
|
||
|
{-decrcmd decrCmd DecrCmd ""}
|
||
|
{-disablecallback disableCallback DisableCallback 0 tixVerifyBoolean}
|
||
|
{-disabledforeground disabledForeground DisabledForeground #303030}
|
||
|
{-incrcmd incrCmd IncrCmd ""}
|
||
|
{-initwait initWait InitWait 500}
|
||
|
{-integer integer Integer false}
|
||
|
{-max max Max ""}
|
||
|
{-min min Min ""}
|
||
|
{-repeatrate repeatRate RepeatRate 50}
|
||
|
{-step step Step 1}
|
||
|
{-state state State normal}
|
||
|
{-selectmode selectMode SelectMode normal}
|
||
|
{-validatecmd validateCmd ValidateCmd ""}
|
||
|
{-value value Value 0}
|
||
|
{-variable variable Variable ""}
|
||
|
}
|
||
|
-alias {
|
||
|
{-llimit -min}
|
||
|
{-ulimit -max}
|
||
|
}
|
||
|
-default {
|
||
|
{.borderWidth 0}
|
||
|
{*entry.relief sunken}
|
||
|
{*entry.width 5}
|
||
|
{*label.anchor e}
|
||
|
{*label.borderWidth 0}
|
||
|
{*Button.anchor c}
|
||
|
{*Button.borderWidth 2}
|
||
|
{*Button.highlightThickness 1}
|
||
|
{*Button.takeFocus 0}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:InitWidgetRec {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
tixChainMethod $w InitWidgetRec
|
||
|
|
||
|
set data(varInited) 0
|
||
|
set data(serial) 0
|
||
|
}
|
||
|
|
||
|
proc tixControl:ConstructFramedWidget {w frame} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
tixChainMethod $w ConstructFramedWidget $frame
|
||
|
|
||
|
set data(w:entry) [entry $frame.entry]
|
||
|
|
||
|
set data(w:incr) \
|
||
|
[button $frame.incr -bitmap [tix getbitmap incr] -takefocus 0]
|
||
|
set data(w:decr) \
|
||
|
[button $frame.decr -bitmap [tix getbitmap decr] -takefocus 0]
|
||
|
|
||
|
# tixForm $data(w:entry) -left 0 -top 0 -bottom -1 -right $data(w:decr)
|
||
|
# tixForm $data(w:incr) -right -1 -top 0 -bottom %50
|
||
|
# tixForm $data(w:decr) -right -1 -top $data(w:incr) -bottom -1
|
||
|
|
||
|
pack $data(w:entry) -side left -expand yes -fill both
|
||
|
pack $data(w:decr) -side bottom -fill both -expand yes
|
||
|
pack $data(w:incr) -side top -fill both -expand yes
|
||
|
|
||
|
$data(w:entry) delete 0 end
|
||
|
$data(w:entry) insert 0 $data(-value)
|
||
|
|
||
|
# This value is used to configure the disable/normal fg of the ebtry
|
||
|
set data(entryfg) [$data(w:entry) cget -fg]
|
||
|
set data(labelfg) [$data(w:label) cget -fg]
|
||
|
}
|
||
|
|
||
|
proc tixControl:SetBindings {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
tixChainMethod $w SetBindings
|
||
|
|
||
|
bind $data(w:incr) <ButtonPress-1> \
|
||
|
[list after idle tixControl:StartRepeat $w 1]
|
||
|
bind $data(w:decr) <ButtonPress-1> \
|
||
|
[list after idle tixControl:StartRepeat $w -1]
|
||
|
|
||
|
# These bindings will stop the button autorepeat when the
|
||
|
# mouse button is up
|
||
|
foreach btn [list $data(w:incr) $data(w:decr)] {
|
||
|
bind $btn <ButtonRelease-1> [list tixControl:StopRepeat $w]
|
||
|
}
|
||
|
|
||
|
tixSetMegaWidget $data(w:entry) $w
|
||
|
|
||
|
# If user press <return>, verify the value and call the -command
|
||
|
#
|
||
|
tixAddBindTag $data(w:entry) TixControl:Entry
|
||
|
}
|
||
|
|
||
|
proc tixControlBind {} {
|
||
|
tixBind TixControl:Entry <Return> {
|
||
|
tixControl:Invoke [tixGetMegaWidget %W] 1
|
||
|
}
|
||
|
tixBind TixControl:Entry <Escape> {
|
||
|
tixControl:Escape [tixGetMegaWidget %W]
|
||
|
}
|
||
|
tixBind TixControl:Entry <Up> {
|
||
|
[tixGetMegaWidget %W] incr
|
||
|
}
|
||
|
tixBind TixControl:Entry <Down> {
|
||
|
[tixGetMegaWidget %W] decr
|
||
|
}
|
||
|
tixBind TixControl:Entry <FocusOut> {
|
||
|
if {"%d" eq "NotifyNonlinear" || "%d" eq "NotifyNonlinearVirtual"} {
|
||
|
tixControl:Tab [tixGetMegaWidget %W] %d
|
||
|
}
|
||
|
}
|
||
|
tixBind TixControl:Entry <Any-KeyPress> {
|
||
|
tixControl:KeyPress [tixGetMegaWidget %W]
|
||
|
}
|
||
|
tixBind TixControl:Entry <Any-Tab> {
|
||
|
# This has a higher priority than the <Any-KeyPress> binding
|
||
|
# --> so that data(edited) is not set
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
# CONFIG OPTIONS
|
||
|
#----------------------------------------------------------------------
|
||
|
proc tixControl:config-state {w arg} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$arg eq "normal"} {
|
||
|
$data(w:incr) config -state $arg
|
||
|
$data(w:decr) config -state $arg
|
||
|
catch {
|
||
|
$data(w:label) config -fg $data(labelfg)
|
||
|
}
|
||
|
$data(w:entry) config -state $arg -fg $data(entryfg)
|
||
|
} else {
|
||
|
$data(w:incr) config -state $arg
|
||
|
$data(w:decr) config -state $arg
|
||
|
catch {
|
||
|
$data(w:label) config -fg $data(-disabledforeground)
|
||
|
}
|
||
|
$data(w:entry) config -state $arg -fg $data(-disabledforeground)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:config-value {w value} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
tixControl:SetValue $w $value 0 1
|
||
|
|
||
|
# This will tell the Intrinsics: "Please use this value"
|
||
|
# because "value" might be altered by SetValues
|
||
|
#
|
||
|
return $data(-value)
|
||
|
}
|
||
|
|
||
|
proc tixControl:config-variable {w arg} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {[tixVariable:ConfigVariable $w $arg]} {
|
||
|
# The value of data(-value) is changed if tixVariable:ConfigVariable
|
||
|
# returns true
|
||
|
tixControl:SetValue $w $data(-value) 1 1
|
||
|
}
|
||
|
catch {
|
||
|
unset data(varInited)
|
||
|
}
|
||
|
set data(-variable) $arg
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
# User Commands
|
||
|
#----------------------------------------------------------------------
|
||
|
proc tixControl:incr {w {by 1}} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$data(-state) ne "disabled"} {
|
||
|
if {![catch {$data(w:entry) index sel.first}]} {
|
||
|
$data(w:entry) select from end
|
||
|
$data(w:entry) select to end
|
||
|
}
|
||
|
# CYGNUS - why set value before changing it?
|
||
|
#tixControl:SetValue $w [$data(w:entry) get] 0 1
|
||
|
tixControl:AdjustValue $w $by
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:decr {w {by 1}} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$data(-state) ne "disabled"} {
|
||
|
if {![catch {$data(w:entry) index sel.first}]} {
|
||
|
$data(w:entry) select from end
|
||
|
$data(w:entry) select to end
|
||
|
}
|
||
|
# CYGNUS - why set value before changing it?
|
||
|
#tixControl:SetValue $w [$data(w:entry) get] 0 1
|
||
|
tixControl:AdjustValue $w [expr {0 - $by}]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:invoke {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
tixControl:Invoke $w 0
|
||
|
}
|
||
|
|
||
|
proc tixControl:update {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {[info exists data(edited)]} {
|
||
|
tixControl:invoke $w
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
# Internal Commands
|
||
|
#----------------------------------------------------------------------
|
||
|
|
||
|
# Change the value by a multiple of the data(-step)
|
||
|
#
|
||
|
proc tixControl:AdjustValue {w amount} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$amount == 1 && [llength $data(-incrcmd)]} {
|
||
|
set newValue [tixEvalCmdBinding $w $data(-incrcmd) "" $data(-value)]
|
||
|
} elseif {$amount == -1 && [llength $data(-decrcmd)]} {
|
||
|
set newValue [tixEvalCmdBinding $w $data(-decrcmd) "" $data(-value)]
|
||
|
} else {
|
||
|
set newValue [expr {$data(-value) + $amount * $data(-step)}]
|
||
|
}
|
||
|
|
||
|
if {$data(-state) ne "disabled"} {
|
||
|
tixControl:SetValue $w $newValue 0 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:SetValue {w newvalue noUpdate forced} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {[$data(w:entry) selection present]} {
|
||
|
set oldSelection [list [$data(w:entry) index sel.first] \
|
||
|
[$data(w:entry) index sel.last]]
|
||
|
}
|
||
|
|
||
|
set oldvalue $data(-value)
|
||
|
set oldCursor [$data(w:entry) index insert]
|
||
|
set changed 0
|
||
|
|
||
|
|
||
|
if {[llength $data(-validatecmd)]} {
|
||
|
# Call the user supplied validation command
|
||
|
#
|
||
|
set data(-value) [tixEvalCmdBinding $w $data(-validatecmd) "" $newvalue]
|
||
|
} else {
|
||
|
# Here we only allow int or floating numbers
|
||
|
#
|
||
|
# If the new value is not a valid number, the old value will be
|
||
|
# kept due to the "catch" statements
|
||
|
#
|
||
|
if {[catch {expr 0+$newvalue}]} {
|
||
|
set newvalue 0
|
||
|
set data(-value) 0
|
||
|
set changed 1
|
||
|
}
|
||
|
|
||
|
if {$newvalue == ""} {
|
||
|
if {![string is true -strict $data(-allowempty)]} {
|
||
|
set newvalue 0
|
||
|
set changed 1
|
||
|
} else {
|
||
|
set data(-value) ""
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if {$newvalue != ""} {
|
||
|
# Change this to a valid decimal string (trim leading 0)
|
||
|
#
|
||
|
regsub -- {^[0]*} $newvalue "" newvalue
|
||
|
if {[catch {expr 0+$newvalue}]} {
|
||
|
set newvalue 0
|
||
|
set data(-value) 0
|
||
|
set changed 1
|
||
|
}
|
||
|
if {$newvalue == ""} {
|
||
|
set newvalue 0
|
||
|
}
|
||
|
|
||
|
if {[string is true -strict $data(-integer)]} {
|
||
|
set data(-value) [tixGetInt -nocomplain $newvalue]
|
||
|
} else {
|
||
|
if {[catch {set data(-value) [format "%d" $newvalue]}]} {
|
||
|
if {[catch {set data(-value) [expr $newvalue+0.0]}]} {
|
||
|
set data(-value) $oldvalue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Now perform boundary checking
|
||
|
#
|
||
|
if {$data(-max) != "" && $data(-value) > $data(-max)} {
|
||
|
set data(-value) $data(-max)
|
||
|
}
|
||
|
if {$data(-min) != "" && $data(-value) < $data(-min)} {
|
||
|
set data(-value) $data(-min)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if {! $noUpdate} {
|
||
|
tixVariable:UpdateVariable $w
|
||
|
}
|
||
|
|
||
|
if {$forced || ($newvalue ne $data(-value)) || $changed} {
|
||
|
$data(w:entry) delete 0 end
|
||
|
$data(w:entry) insert 0 $data(-value)
|
||
|
$data(w:entry) icursor $oldCursor
|
||
|
if {[info exists oldSelection]} {
|
||
|
eval [list $data(w:entry) selection range] $oldSelection
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if {!$data(-disablecallback) && $data(-command) != ""} {
|
||
|
if {![info exists data(varInited)]} {
|
||
|
set bind(specs) ""
|
||
|
tixEvalCmdBinding $w $data(-command) bind $data(-value)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:Invoke {w forced} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
catch {
|
||
|
unset data(edited)
|
||
|
}
|
||
|
|
||
|
if {[catch {$data(w:entry) index sel.first}] == 0} {
|
||
|
# THIS ENTRY OWNS SELECTION --> TURN IT OFF
|
||
|
#
|
||
|
$data(w:entry) select from end
|
||
|
$data(w:entry) select to end
|
||
|
}
|
||
|
|
||
|
tixControl:SetValue $w [$data(w:entry) get] 0 $forced
|
||
|
}
|
||
|
|
||
|
#----------------------------------------------------------------------
|
||
|
# The three functions StartRepeat, Repeat and StopRepeat make use of the
|
||
|
# data(serial) variable to discard spurious repeats: If a button is clicked
|
||
|
# repeatedly but is not hold down, the serial counter will increase
|
||
|
# successively and all "after" time event handlers will be discarded
|
||
|
#----------------------------------------------------------------------
|
||
|
proc tixControl:StartRepeat {w amount} {
|
||
|
if {![winfo exists $w]} {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
upvar #0 $w data
|
||
|
|
||
|
incr data(serial)
|
||
|
# CYGNUS bug fix
|
||
|
# Need to set a local variable because otherwise the buttonrelease
|
||
|
# callback could change the value of data(serial) between now and
|
||
|
# the time the repeat is scheduled.
|
||
|
set serial $data(serial)
|
||
|
|
||
|
if {![catch {$data(w:entry) index sel.first}]} {
|
||
|
$data(w:entry) select from end
|
||
|
$data(w:entry) select to end
|
||
|
}
|
||
|
|
||
|
if {[info exists data(edited)]} {
|
||
|
unset data(edited)
|
||
|
tixControl:SetValue $w [$data(w:entry) get] 0 1
|
||
|
}
|
||
|
|
||
|
tixControl:AdjustValue $w $amount
|
||
|
|
||
|
if {$data(-autorepeat)} {
|
||
|
after $data(-initwait) tixControl:Repeat $w $amount $serial
|
||
|
}
|
||
|
|
||
|
focus $data(w:entry)
|
||
|
}
|
||
|
|
||
|
proc tixControl:Repeat {w amount serial} {
|
||
|
if {![winfo exists $w]} {
|
||
|
return
|
||
|
}
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$serial eq $data(serial)} {
|
||
|
tixControl:AdjustValue $w $amount
|
||
|
|
||
|
if {$data(-autorepeat)} {
|
||
|
after $data(-repeatrate) tixControl:Repeat $w $amount $serial
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
proc tixControl:StopRepeat {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
incr data(serial)
|
||
|
}
|
||
|
|
||
|
proc tixControl:Destructor {w} {
|
||
|
|
||
|
tixVariable:DeleteVariable $w
|
||
|
|
||
|
# Chain this to the superclass
|
||
|
#
|
||
|
tixChainMethod $w Destructor
|
||
|
}
|
||
|
|
||
|
# ToDo: maybe should return -code break if the value is not good ...
|
||
|
#
|
||
|
proc tixControl:Tab {w detail} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {![info exists data(edited)]} {
|
||
|
return
|
||
|
} else {
|
||
|
unset data(edited)
|
||
|
}
|
||
|
|
||
|
tixControl:invoke $w
|
||
|
}
|
||
|
|
||
|
proc tixControl:Escape {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
$data(w:entry) delete 0 end
|
||
|
$data(w:entry) insert 0 $data(-value)
|
||
|
}
|
||
|
|
||
|
proc tixControl:KeyPress {w} {
|
||
|
upvar #0 $w data
|
||
|
|
||
|
if {$data(-selectmode) eq "normal"} {
|
||
|
set data(edited) 0
|
||
|
return
|
||
|
} else {
|
||
|
# == "immediate"
|
||
|
after 1 tixControl:invoke $w
|
||
|
}
|
||
|
}
|