home *** CD-ROM | disk | FTP | other *** search
/ PC World 2002 May / PCWorld_2002-05_cd.bin / Software / TemaCD / activetcltk / ActiveTcl8.3.4.1-8.win32-ix86.exe / ActiveTcl8.3.4.1-win32-ix86 / lib / bwidget1.3.0 / spinbox.tcl < prev    next >
Encoding:
Text File  |  2001-10-22  |  11.6 KB  |  343 lines

  1. # spinbox.tcl --
  2. #
  3. #    BWidget SpinBox implementation.
  4. #
  5. # Copyright (c) 1999 by Unifix
  6. # Copyright (c) 2000 by Ajuba Solutions
  7. # All rights reserved.
  8. # RCS: @(#) $Id: spinbox.tcl,v 1.10 2000/05/30 23:44:46 ericm Exp $
  9. # -----------------------------------------------------------------------------
  10. #  Index of commands:
  11. #     - SpinBox::create
  12. #     - SpinBox::configure
  13. #     - SpinBox::cget
  14. #     - SpinBox::setvalue
  15. #     - SpinBox::_destroy
  16. #     - SpinBox::_modify_value
  17. #     - SpinBox::_test_options
  18. # -----------------------------------------------------------------------------
  19.  
  20. namespace eval SpinBox {
  21.     ArrowButton::use
  22.     Entry::use
  23.  
  24.     Widget::tkinclude SpinBox frame :cmd \
  25.         include {-background -borderwidth -bg -bd -relief} \
  26.         initialize {-relief sunken -borderwidth 2}
  27.  
  28.     Widget::bwinclude SpinBox Entry .e \
  29.         remove {-relief -bd -borderwidth -fg -bg} \
  30.         rename {-foreground -entryfg -background -entrybg}
  31.  
  32.     Widget::declare SpinBox {
  33.         {-range          String ""  0}
  34.         {-values         String ""  0}
  35.         {-modifycmd      String ""  0}
  36.         {-repeatdelay    Int    400 0 {%d >= 0}}
  37.         {-repeatinterval Int    100 0 {%d >= 0}}
  38.     {-foreground     TkResource black 0 {button}}
  39.     }
  40.  
  41.     Widget::addmap SpinBox "" :cmd {-background {}}
  42.     Widget::addmap SpinBox ArrowButton .arrup {
  43.         -foreground {} -background {} -disabledforeground {} -state {} \
  44.         -repeatinterval {} -repeatdelay {}
  45.     }
  46.     Widget::addmap SpinBox ArrowButton .arrdn {
  47.         -foreground {} -background {} -disabledforeground {} -state {} \
  48.         -repeatinterval {} -repeatdelay {}
  49.     }
  50.  
  51.     ::bind SpinBox <FocusIn> [list after idle {BWidget::refocus %W %W.e}]
  52.     ::bind SpinBox <Destroy> {SpinBox::_destroy %W}
  53.  
  54.     interp alias {} ::SpinBox {} ::SpinBox::create
  55.     proc use {} {}
  56.  
  57.     variable _widget
  58. }
  59.  
  60.  
  61. # -----------------------------------------------------------------------------
  62. #  Command SpinBox::create
  63. # -----------------------------------------------------------------------------
  64. proc SpinBox::create { path args } {
  65.     array set maps [list SpinBox {} :cmd {} .e {} .arrup {} .arrdn {}]
  66.     array set maps [Widget::parseArgs SpinBox $args]
  67.     eval frame $path $maps(:cmd) -highlightthickness 0 \
  68.         -takefocus 0 -class SpinBox
  69.     Widget::initFromODB SpinBox $path $maps(SpinBox)
  70.  
  71.     set entry [eval Entry::create $path.e $maps(.e) -relief flat -bd 0]
  72.     bindtags $path.e [linsert [bindtags $path.e] 1 SpinBoxEntry]
  73.  
  74.     set farr   [frame $path.farr -relief flat -bd 0 -highlightthickness 0]
  75.     set height [expr {[winfo reqheight $path.e]/2-2}]
  76.     set width  11
  77.     set arrup  [eval ArrowButton::create $path.arrup -dir top \
  78.         $maps(.arrup) \
  79.         -highlightthickness 0 -borderwidth 1 -takefocus 0 \
  80.         -type button \
  81.         -width $width -height $height \
  82.         -armcommand    [list "SpinBox::_modify_value $path next arm"] \
  83.         -disarmcommand [list "SpinBox::_modify_value $path next disarm"]]
  84.     set arrdn  [eval ArrowButton::create $path.arrdn -dir bottom \
  85.         $maps(.arrdn) \
  86.         -highlightthickness 0 -borderwidth 1 -takefocus 0 \
  87.         -type button \
  88.         -width $width -height $height \
  89.         -armcommand    [list "SpinBox::_modify_value $path previous arm"] \
  90.         -disarmcommand [list "SpinBox::_modify_value $path previous disarm"]]
  91.  
  92.     # --- update SpinBox value ---
  93.     _test_options $path
  94.     set val [Entry::cget $path.e -text]
  95.     if { [string equal $val ""] } {
  96.     Entry::configure $path.e -text $::SpinBox::_widget($path,curval)
  97.     } else {
  98.     set ::SpinBox::_widget($path,curval) $val
  99.     }
  100.  
  101.     grid $arrup -in $farr -column 0 -row 0 -sticky nsew
  102.     grid $arrdn -in $farr -column 0 -row 2 -sticky nsew
  103.     grid rowconfigure $farr 0 -weight 1
  104.     grid rowconfigure $farr 2 -weight 1
  105.  
  106.     pack $farr  -side right -fill y
  107.     pack $entry -side left  -fill both -expand yes
  108.  
  109.     ::bind $entry <Key-Up>    "SpinBox::_modify_value $path next activate"
  110.     ::bind $entry <Key-Down>  "SpinBox::_modify_value $path previous activate"
  111.     ::bind $entry <Key-Prior> "SpinBox::_modify_value $path last activate"
  112.     ::bind $entry <Key-Next>  "SpinBox::_modify_value $path first activate"
  113.  
  114.     ::bind $farr <Configure> {grid rowconfigure %W 1 -minsize [expr {%h%%2}]}
  115.  
  116.     rename $path ::$path:cmd
  117.     proc ::$path { cmd args } "return \[eval SpinBox::\$cmd $path \$args\]"
  118.  
  119.     return $path
  120. }
  121.  
  122. # -----------------------------------------------------------------------------
  123. #  Command SpinBox::configure
  124. # -----------------------------------------------------------------------------
  125. proc SpinBox::configure { path args } {
  126.     set res [Widget::configure $path $args]
  127.     if { [Widget::hasChangedX $path -values] ||
  128.          [Widget::hasChangedX $path -range] } {
  129.         _test_options $path
  130.     }
  131.     return $res
  132. }
  133.  
  134.  
  135. # -----------------------------------------------------------------------------
  136. #  Command SpinBox::cget
  137. # -----------------------------------------------------------------------------
  138. proc SpinBox::cget { path option } {
  139.     return [Widget::cget $path $option]
  140. }
  141.  
  142.  
  143. # -----------------------------------------------------------------------------
  144. #  Command SpinBox::setvalue
  145. # -----------------------------------------------------------------------------
  146. proc SpinBox::setvalue { path index } {
  147.     variable _widget
  148.  
  149.     set values [Widget::getMegawidgetOption $path -values]
  150.     set value  [Entry::cget $path.e -text]
  151.     
  152.     if { [llength $values] } {
  153.         # --- -values SpinBox ---
  154.         switch -- $index {
  155.             next {
  156.                 if { [set idx [lsearch $values $value]] != -1 } {
  157.                     incr idx
  158.                 } elseif { [set idx [lsearch $values "$value*"]] == -1 } {
  159.                     set idx [lsearch $values $_widget($path,curval)]
  160.                 }
  161.             }
  162.             previous {
  163.                 if { [set idx [lsearch $values $value]] != -1 } {
  164.                     incr idx -1
  165.                 } elseif { [set idx [lsearch $values "$value*"]] == -1 } {
  166.                     set idx [lsearch $values $_widget($path,curval)]
  167.                 }
  168.             }
  169.             first {
  170.                 set idx 0
  171.             }
  172.             last {
  173.                 set idx [expr {[llength $values]-1}]
  174.             }
  175.             default {
  176.                 if { [string index $index 0] == "@" } {
  177.                     set idx [string range $index 1 end]
  178.                     if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } {
  179.                         return -code error "bad index \"$index\""
  180.                     }
  181.                 } else {
  182.                     return -code error "bad index \"$index\""
  183.                 }
  184.             }
  185.         }
  186.         if { $idx >= 0 && $idx < [llength $values] } {
  187.             set newval [lindex $values $idx]
  188.         } else {
  189.             return 0
  190.         }
  191.     } else {
  192.         # --- -range SpinBox ---
  193.     foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
  194.         break
  195.     }
  196.     # Allow zero padding on the value; strip it out for calculation by
  197.     # scanning the value into a floating point number.
  198.     scan $value %f value
  199.         switch -- $index {
  200.             next {
  201.                 if { [catch {expr {double($value-$vmin)/$incr}} idx] } {
  202.                     set newval $_widget($path,curval)
  203.                 } else {
  204.                     set newval [expr {$vmin+(round($idx)+1)*$incr}]
  205.                     if { $newval < $vmin } {
  206.                         set newval $vmin
  207.                     } elseif { $newval > $vmax } {
  208.                         set newval $vmax
  209.                     }
  210.                 }
  211.             }
  212.             previous {
  213.                 if { [catch {expr {double($value-$vmin)/$incr}} idx] } {
  214.                     set newval $_widget($path,curval)
  215.                 } else {
  216.                     set newval [expr {$vmin+(round($idx)-1)*$incr}]
  217.                     if { $newval < $vmin } {
  218.                         set newval $vmin
  219.                     } elseif { $newval > $vmax } {
  220.                         set newval $vmax
  221.                     }
  222.                 }
  223.             }
  224.             first {
  225.                 set newval $vmin
  226.             }
  227.             last {
  228.                 set newval $vmax
  229.             }
  230.             default {
  231.                 if { [string index $index 0] == "@" } {
  232.                     set idx [string range $index 1 end]
  233.                     if { [catch {string compare [expr {int($idx)}] $idx} res] || $res != 0 } {
  234.                         return -code error "bad index \"$index\""
  235.                     }
  236.                     set newval [expr {$vmin+int($idx)*$incr}]
  237.                     if { $newval < $vmin || $newval > $vmax } {
  238.                         return 0
  239.                     }
  240.                 } else {
  241.                     return -code error "bad index \"$index\""
  242.                 }
  243.             }
  244.         }
  245.     }
  246.     set _widget($path,curval) $newval
  247.     Entry::configure $path.e -text $newval
  248.     return 1
  249. }
  250.  
  251.  
  252. # -----------------------------------------------------------------------------
  253. #  Command SpinBox::getvalue
  254. # -----------------------------------------------------------------------------
  255. proc SpinBox::getvalue { path } {
  256.     variable _widget
  257.  
  258.     set values [Widget::getMegawidgetOption $path -values]
  259.     set value  [Entry::cget $path.e -text]
  260.  
  261.     if { [llength $values] } {
  262.         # --- -values SpinBox ---
  263.         return  [lsearch $values $value]
  264.     } else {
  265.     foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
  266.         break
  267.     }
  268.         if { ![catch {expr {double($value-$vmin)/$incr}} idx] &&
  269.              $idx == int($idx) } {
  270.             return [expr {int($idx)}]
  271.         }
  272.         return -1
  273.     }
  274. }
  275.  
  276.  
  277. # -----------------------------------------------------------------------------
  278. #  Command SpinBox::bind
  279. # -----------------------------------------------------------------------------
  280. proc SpinBox::bind { path args } {
  281.     return [eval ::bind $path.e $args]
  282. }
  283.  
  284.  
  285. # -----------------------------------------------------------------------------
  286. #  Command SpinBox::_destroy
  287. # -----------------------------------------------------------------------------
  288. proc SpinBox::_destroy { path } {
  289.     variable _widget
  290.  
  291.     unset _widget($path,curval)
  292.     Widget::destroy $path
  293.     rename $path {}
  294. }
  295.  
  296.  
  297. # -----------------------------------------------------------------------------
  298. #  Command SpinBox::_modify_value
  299. # -----------------------------------------------------------------------------
  300. proc SpinBox::_modify_value { path direction reason } {
  301.     if { $reason == "arm" || $reason == "activate" } {
  302.         SpinBox::setvalue $path $direction
  303.     }
  304.     if { ($reason == "disarm" || $reason == "activate") &&
  305.          [set cmd [Widget::getMegawidgetOption $path -modifycmd]] != "" } {
  306.         uplevel \#0 $cmd
  307.     }
  308. }
  309.  
  310. # -----------------------------------------------------------------------------
  311. #  Command SpinBox::_test_options
  312. # -----------------------------------------------------------------------------
  313. proc SpinBox::_test_options { path } {
  314.     set values [Widget::getMegawidgetOption $path -values]
  315.     if { [llength $values] } {
  316.         set ::SpinBox::_widget($path,curval) [lindex $values 0]
  317.     } else {
  318.     foreach {vmin vmax incr} [Widget::getMegawidgetOption $path -range] {
  319.         break
  320.     }
  321.     set update 0
  322.         if { [catch {expr {int($vmin)}}] } {
  323.             set vmin 0
  324.         set update 1
  325.         }
  326.         if { [catch {expr {$vmax<$vmin}} res] || $res } {
  327.             set vmax $vmin
  328.         set update 1
  329.         }
  330.         if { [catch {expr {$incr<0}} res] || $res } {
  331.             set incr 1
  332.         set update 1
  333.         }
  334.     # Only do the set back (which is expensive) if we changed a value
  335.     if { $update } {
  336.         Widget::setMegawidgetOption $path -range [list $vmin $vmax $incr]
  337.     }
  338.         set ::SpinBox::_widget($path,curval) $vmin
  339.     }
  340. }
  341.  
  342.