]> granicus.if.org Git - xconq/blobdiff - tcltk/BWidget/spinbox.tcl
commits for 7.5.0 pre-release tarball
[xconq] / tcltk / BWidget / spinbox.tcl
diff --git a/tcltk/BWidget/spinbox.tcl b/tcltk/BWidget/spinbox.tcl
new file mode 100644 (file)
index 0000000..ee51ce3
--- /dev/null
@@ -0,0 +1,331 @@
+# spinbox.tcl --
+#
+#      BWidget SpinBox implementation.
+#
+# Copyright (c) 1999 by Unifix
+# Copyright (c) 2000 by Ajuba Solutions
+# All rights reserved.
+# 
+# RCS: @(#) $Id: spinbox.tcl,v 1.1.1.1 2004/11/21 03:02:55 eric_mcdonald Exp $
+# -----------------------------------------------------------------------------
+#  Index of commands:
+#     - SpinBox::create
+#     - SpinBox::configure
+#     - SpinBox::cget
+#     - SpinBox::setvalue
+#     - SpinBox::_destroy
+#     - SpinBox::_modify_value
+#     - SpinBox::_test_options
+# -----------------------------------------------------------------------------
+
+namespace eval SpinBox {
+    Widget::define SpinBox spinbox Entry ArrowButton
+
+    Widget::tkinclude SpinBox frame :cmd \
+           include {-background -borderwidth -bg -bd -relief} \
+           initialize {-relief sunken -borderwidth 2}
+
+    Widget::bwinclude SpinBox Entry .e \
+        remove {-relief -bd -borderwidth -fg -bg} \
+        rename {-foreground -entryfg -background -entrybg}
+
+    Widget::declare SpinBox {
+        {-range          String ""  0}
+        {-values         String ""  0}
+        {-modifycmd      String ""  0}
+        {-repeatdelay    Int    400 0 {%d >= 0}}
+        {-repeatinterval Int    100 0 {%d >= 0}}
+       {-foreground     TkResource black 0 {button}}
+    }
+
+    Widget::addmap SpinBox "" :cmd {-background {}}
+    Widget::addmap SpinBox ArrowButton .arrup {
+        -foreground {} -background {} -disabledforeground {} -state {} \
+               -repeatinterval {} -repeatdelay {}
+    }
+    Widget::addmap SpinBox ArrowButton .arrdn {
+        -foreground {} -background {} -disabledforeground {} -state {} \
+               -repeatinterval {} -repeatdelay {}
+    }
+
+    ::bind SpinBox <FocusIn> [list after idle {BWidget::refocus %W %W.e}]
+    ::bind SpinBox <Destroy> [list SpinBox::_destroy %W]
+
+    variable _widget
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::create
+# -----------------------------------------------------------------------------
+proc SpinBox::create { path args } {
+    array set maps [list SpinBox {} :cmd {} .e {} .arrup {} .arrdn {}]
+    array set maps [Widget::parseArgs SpinBox $args]
+    eval [list frame $path] $maps(:cmd) \
+       [list -highlightthickness 0 -takefocus 0 -class SpinBox]
+    Widget::initFromODB SpinBox $path $maps(SpinBox)
+
+    set entry [eval [list Entry::create $path.e] $maps(.e) -relief flat -bd 0]
+    bindtags $path.e [linsert [bindtags $path.e] 1 SpinBoxEntry]
+
+    set farr   [frame $path.farr -relief flat -bd 0 -highlightthickness 0]
+    set height [expr {[winfo reqheight $path.e]/2-2}]
+    set width  11
+    set arrup  [eval [list ArrowButton::create $path.arrup -dir top] \
+           $maps(.arrup) \
+                   [list -highlightthickness 0 -borderwidth 1 -takefocus 0 \
+                        -type button -width $width -height $height \
+                        -armcommand    [list SpinBox::_modify_value $path next arm] \
+                        -disarmcommand [list SpinBox::_modify_value $path next disarm]]]
+    set arrdn  [eval [list ArrowButton::create $path.arrdn -dir bottom] \
+           $maps(.arrdn) \
+                   [list -highlightthickness 0 -borderwidth 1 -takefocus 0 \
+                        -type button -width $width -height $height \
+                        -armcommand    [list SpinBox::_modify_value $path previous arm] \
+                        -disarmcommand [list SpinBox::_modify_value $path previous disarm]]]
+
+    # --- update SpinBox value ---
+    _test_options $path
+    set val [Entry::cget $path.e -text]
+    if { [string equal $val ""] } {
+       Entry::configure $path.e -text $::SpinBox::_widget($path,curval)
+    } else {
+       set ::SpinBox::_widget($path,curval) $val
+    }
+
+    grid $arrup -in $farr -column 0 -row 0 -sticky nsew
+    grid $arrdn -in $farr -column 0 -row 2 -sticky nsew
+    grid rowconfigure $farr 0 -weight 1
+    grid rowconfigure $farr 2 -weight 1
+
+    pack $farr  -side right -fill y
+    pack $entry -side left  -fill both -expand yes
+
+    ::bind $entry <Key-Up>    [list SpinBox::_modify_value $path next activate]
+    ::bind $entry <Key-Down>  [list SpinBox::_modify_value $path previous activate]
+    ::bind $entry <Key-Prior> [list SpinBox::_modify_value $path last activate]
+    ::bind $entry <Key-Next>  [list SpinBox::_modify_value $path first activate]
+
+    ::bind $farr <Configure> {grid rowconfigure %W 1 -minsize [expr {%h%%2}]}
+
+    return [Widget::create SpinBox $path]
+}
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::configure
+# -----------------------------------------------------------------------------
+proc SpinBox::configure { path args } {
+    set res [Widget::configure $path $args]
+    if { [Widget::hasChangedX $path -values] ||
+         [Widget::hasChangedX $path -range] } {
+        _test_options $path
+    }
+    return $res
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::cget
+# -----------------------------------------------------------------------------
+proc SpinBox::cget { path option } {
+    return [Widget::cget $path $option]
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::setvalue
+# -----------------------------------------------------------------------------
+proc SpinBox::setvalue { path index } {
+    variable _widget
+
+    set values [Widget::getMegawidgetOption $path -values]
+    set value  [Entry::cget $path.e -text]
+    
+    if { [llength $values] } {
+        # --- -values SpinBox ---
+        switch -- $index {
+            next {
+                if { [set idx [lsearch $values $value]] != -1 } {
+                    incr idx
+                } elseif { [set idx [lsearch $values "$value*"]] == -1 } {
+                    set idx [lsearch $values $_widget($path,curval)]
+                }
+            }
+            previous {
+                if { [set idx [lsearch $values $value]] != -1 } {
+                    incr idx -1
+                } elseif { [set idx [lsearch $values "$value*"]] == -1 } {
+                    set idx [lsearch $values $_widget($path,curval)]
+                }
+            }
+            first {
+                set idx 0
+            }
+            last {
+                set idx [expr {[llength $values]-1}]
+            }
+            default {
+                if { [string index $index 0] == "@" } {
+                    set idx [string range $index 1 end]
+                    if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } {
+                        return -code error "bad index \"$index\""
+                    }
+                } else {
+                    return -code error "bad index \"$index\""
+                }
+            }
+        }
+        if { $idx >= 0 && $idx < [llength $values] } {
+            set newval [lindex $values $idx]
+        } else {
+            return 0
+        }
+    } else {
+        # --- -range SpinBox ---
+       foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
+           break
+       }
+       # Allow zero padding on the value; strip it out for calculation by
+       # scanning the value into a floating point number.
+       scan $value %f value
+        switch -- $index {
+            next {
+                if { [catch {expr {double($value-$vmin)/$incr}} idx] } {
+                    set newval $_widget($path,curval)
+                } else {
+                    set newval [expr {$vmin+(round($idx)+1)*$incr}]
+                    if { $newval < $vmin } {
+                        set newval $vmin
+                    } elseif { $newval > $vmax } {
+                        set newval $vmax
+                    }
+                }
+            }
+            previous {
+                if { [catch {expr {double($value-$vmin)/$incr}} idx] } {
+                    set newval $_widget($path,curval)
+                } else {
+                    set newval [expr {$vmin+(round($idx)-1)*$incr}]
+                    if { $newval < $vmin } {
+                        set newval $vmin
+                    } elseif { $newval > $vmax } {
+                        set newval $vmax
+                    }
+                }
+            }
+            first {
+                set newval $vmin
+            }
+            last {
+                set newval $vmax
+            }
+            default {
+                if { [string index $index 0] == "@" } {
+                    set idx [string range $index 1 end]
+                    if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } {
+                        return -code error "bad index \"$index\""
+                    }
+                    set newval [expr {$vmin+int($idx)*$incr}]
+                    if { $newval < $vmin || $newval > $vmax } {
+                        return 0
+                    }
+                } else {
+                    return -code error "bad index \"$index\""
+                }
+            }
+        }
+    }
+    set _widget($path,curval) $newval
+    Entry::configure $path.e -text $newval
+    return 1
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::getvalue
+# -----------------------------------------------------------------------------
+proc SpinBox::getvalue { path } {
+    variable _widget
+
+    set values [Widget::getMegawidgetOption $path -values]
+    set value  [Entry::cget $path.e -text]
+
+    if { [llength $values] } {
+        # --- -values SpinBox ---
+        return  [lsearch $values $value]
+    } else {
+       foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
+           break
+       }
+        if { ![catch {expr {double($value-$vmin)/$incr}} idx] &&
+             $idx == int($idx) } {
+            return [expr {int($idx)}]
+        }
+        return -1
+    }
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::bind
+# -----------------------------------------------------------------------------
+proc SpinBox::bind { path args } {
+    return [eval [list ::bind $path.e] $args]
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::_modify_value
+# -----------------------------------------------------------------------------
+proc SpinBox::_modify_value { path direction reason } {
+    if { $reason == "arm" || $reason == "activate" } {
+        SpinBox::setvalue $path $direction
+    }
+    if { ($reason == "disarm" || $reason == "activate") &&
+         [set cmd [Widget::getMegawidgetOption $path -modifycmd]] != "" } {
+        uplevel \#0 $cmd
+    }
+}
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::_test_options
+# -----------------------------------------------------------------------------
+proc SpinBox::_test_options { path } {
+    set values [Widget::getMegawidgetOption $path -values]
+    if { [llength $values] } {
+        set ::SpinBox::_widget($path,curval) [lindex $values 0]
+    } else {
+       foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
+           break
+       }
+       set update 0
+        if { [catch {expr {int($vmin)}}] } {
+            set vmin 0
+           set update 1
+        }
+        if { [catch {expr {$vmax<$vmin}} res] || $res } {
+            set vmax $vmin
+           set update 1
+        }
+        if { [catch {expr {$incr<0}} res] || $res } {
+            set incr 1
+           set update 1
+        }
+       # Only do the set back (which is expensive) if we changed a value
+       if { $update } {
+           Widget::setMegawidgetOption $path -range [list $vmin $vmax $incr]
+       }
+        set ::SpinBox::_widget($path,curval) $vmin
+    }
+}
+
+
+# -----------------------------------------------------------------------------
+#  Command SpinBox::_destroy
+# -----------------------------------------------------------------------------
+proc SpinBox::_destroy { path } {
+    variable _widget
+
+    unset _widget($path,curval)
+    Widget::destroy $path
+}