Canvas polygon buttons


canvas polygon button image


MM Strange thing: if I move the pointer just above the text on a button and click the event is delivered (I have verified that uwp_cb_action_press is invoked) but then nothing happens: the button is not pressed. There is a small rectangle area just above the text item that shows this behaviour: if I move the pointer a few pixel above or below everything works. I was not able to reproduce the behaviour with a script that just displayes a canvas with a polygon and a word of text in it, so the bug must be in my code.


IDG For me, there is a small dead area on all sides of the text. I wonder if this is associated with enter/leave events as you move between the text and the button. You bind to the containing frame ... are all events guaranteed to arrive in the correct order?


MM If someone is able to suggest a way to draw an outer polygon to mimic the highlight border when the focus in in, let me know thank you.


SeS (11th July, 2012) Nice set of custom canvas buttons, indeed I do observe the same dead area around the text, additionally when user presses the button and at the same time moves into the TEXT area, it will generate the 'release' event and thus will activate the unpress procedure of the button, even if user is still pressing on the same button. To overcome this situation, we may add the following to the existing set of bindings:

  $c bind Clickable <B1-Motion>       [list uwp_cb_event_press   $widget]

But the dead area problem remains persistently...

One other thing, when copy/pasting this complete code into tG² I had to add the command 'update' right after 'wm geometry . +100+100' inside procedure 'main' in order to see the buttons. No idea why...


SeS (12th of July, 2012)

Found some more time to fix the dead area problem...

 proposal for fixing dead area problem:
# canvas_polygon_button.tcl --
 # 
 # Part of: Useless Widgets Packages
 # Contents: test canvas buttons
 # Date: Wed Dec 22, 2004
 # Credits: Gerard Sookahet has put the superformula on the TCL'ers Wiki
 # 
 # Abstract
 # 
 #        It should support all the common button operations:
 #
 #        * when the pointer enters the button is hilighted;
 #        * when the button is clicked it is pressed;
 #        * when the pointer leaves the button is de-hilighted
 #          and raised (if pressed);
 #        * when the button is unclicked the button is raised
 #          (if pressed) and the command invoked (if the button
 #          is pressed);
 #        * if focus comes in the text is underlined;
 #        * if the focus goes out the text is deunderlined;
 #        * if the "Return" key is pressed while the focus is in
 #          the button is pressed and then depressed after 100 ms,
 #          and the command invoked.
 # 
 # Copyright (c) 2004 Marco Maggi
 # 
 # The author  hereby grant permission to use,  copy, modify, distribute,
 # and  license this  software  and its  documentation  for any  purpose,
 # provided that  existing copyright notices  are retained in  all copies
 # and that  this notice  is included verbatim  in any  distributions. No
 # written agreement, license, or royalty  fee is required for any of the
 # authorized uses.  Modifications to this software may be copyrighted by
 # their authors and need not  follow the licensing terms described here,
 # provided that the new terms are clearly indicated on the first page of
 # each file where they apply.
 # 
 # IN NO  EVENT SHALL THE AUTHOR  OR DISTRIBUTORS BE LIABLE  TO ANY PARTY
 # FOR  DIRECT, INDIRECT, SPECIAL,  INCIDENTAL, OR  CONSEQUENTIAL DAMAGES
 # ARISING OUT  OF THE  USE OF THIS  SOFTWARE, ITS DOCUMENTATION,  OR ANY
 # DERIVATIVES  THEREOF, EVEN  IF THE  AUTHOR  HAVE BEEN  ADVISED OF  THE
 # POSSIBILITY OF SUCH DAMAGE.
 # 
 # THE  AUTHOR  AND DISTRIBUTORS  SPECIFICALLY  DISCLAIM ANY  WARRANTIES,
 # INCLUDING,   BUT   NOT  LIMITED   TO,   THE   IMPLIED  WARRANTIES   OF
 # MERCHANTABILITY,    FITNESS   FOR    A    PARTICULAR   PURPOSE,    AND
 # NON-INFRINGEMENT.  THIS  SOFTWARE IS PROVIDED  ON AN "AS  IS" BASIS,
 # AND  THE  AUTHOR  AND  DISTRIBUTORS  HAVE  NO  OBLIGATION  TO  PROVIDE
 # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
 # Bugfix proposals by Sedat Serper:
 #  11th of July 2012
 #    - moving over text while pressing button behaves as intended
 #  12th of July 2012
 #    - the dead area problem is fixed
 #  Observed additionally:
 #    - even when user looses focus while pressing button, it will not 
 #      restore the button to normal view, until user releases the button
 #  Note:
 #   All additions/corrections by this author is identied with the #SeS  
 #   string in the code
 #
 
 #page
 ## ------------------------------------------------------------
 ## Setup.
 ## ------------------------------------------------------------
 
 package require Tcl 8.4
 package require Tk  8.4
 
 #page
 ## ------------------------------------------------------------
 ## Widget options.
 ## ------------------------------------------------------------
 
 option add *borderWidth                  1
 
 option add *Cb.relief                    flat
 option add *Cb.canvas.relief             flat
 
 option add *Cb.borderWidth               2
 option add *Cb*highlightThickness        0
 # this is the default light gray
 option add *Cb.background                "\#d9d9d9"
 option add *Cb.bbground                  "\#d9d9d9"
 # bisque see the "colors" man page or "/usr/X11R6/lib/X11/rgb.txt"
 option add *Cb.activebbground            bisque
 option add *Cb.foreground                black
 option add *Cb.pressedbordercolor        {dark gray}
 option add *Cb.width                     100
 option add *Cb.height                    100
 option add *Cb.takeFocus                 1
 
 option add *Cb.text                      Text
 option add *Cb.font                      {-weight bold -family Helvetica -size 12}
 
 #page
 ## ------------------------------------------------------------
 ## Main.
 ## ------------------------------------------------------------
 
 proc main {} {
     global        exit_trigger
 
     wm title . "Testing canvas buttons"
     wm geometry . 600x600+100+100
     #SeS : tG2 requires this for some odd reason...
     update
     
     set counter 0
     
     set col -1
     foreach {name num fraction} {
         a 3 -4  b 4 8  c 6 1  d 12 1  e 50 1
     } {
         uwp_cb_build .$name [polygon_regular_coords $num 0.8 $fraction] \
             button_command
         grid .$name -row 0 -column [incr col]
     }
     set col -1
     foreach {name num} {
         m 3  n 4  o 6  p 12  q 20
     } {
         uwp_cb_build .$name [polygon_star_coords $num] button_command
         grid .$name -row 1 -column [incr col]
     }
     set col -1
     # parms: a b m n1 n2 n3
     foreach {name parms} {
         r {0.7   0.9   6.0   1.0   2.0   1.4}
         s {0.9   0.7  12.0   1.5   2.0   7.5}
         t {0.9   0.7  10.0   0.9   1.7   1.1}
     } {
         uwp_cb_build .$name [eval superformula $parms] button_command
         grid .$name -row 2 -column [incr col]
     }
 
     grid \
         [label .l -text 0 -width 5 -background \#ffffff] \
         [button .quit -text Exit -command main_exit]
     focus .quit
     bind .quit <Return> main_exit
     
     interp alias {} main_exit {} set exit_trigger 1
     vwait exit_trigger
     #SeS : tG2 has renamed the 'exit' command to 'tcl_exit' for exit handling...
     #exit
     destroy .
 }
 proc button_command {} { .l configure -text [expr {[.l cget -text]+1}] }
 #page
 proc polygon_regular_coords { num radius {fraction 1.0} } {
     for {set i 0} {$i < $num} {incr i} {
         set angle [expr {6.28318530718/double($fraction)+
                          (6.28318530718*double($i)/double($num))}]
         lappend coords \
             [expr {double($radius)*cos($angle)}] \
             [expr {double($radius)*sin($angle)}]
     }
     return $coords
 }
 proc polygon_star_coords { num } {
     set fraction [expr {double($num)*2.0}]
     foreach {x1 y1} [polygon_regular_coords $num 0.9] \
         {x2 y2} [polygon_regular_coords $num 0.6 $fraction] {
             lappend result $x1 $y1 $x2 $y2
     }
     return $result
 }
 proc superformula { a b m n1 n2 n3 } {
     set num 50
     for {set i 0} {$i < $num} {incr i} {
         set theta [expr {double($i)*6.28318530718/double($num)}]
         set rho \
             [expr { pow(pow(abs(cos(0.25*double($m)*double($theta))/double($a)),
                             double($n2))+
                         pow(abs(sin(0.25*double($m)*double($theta))/double($b)),
                             double($n2)), (-1/double($n1))) }]
         lappend result [expr {$rho*cos($theta)}] [expr {$rho*sin($theta)}]
     }
     return $result
 }
 #page
 proc uwp_op_array { widget varName } {
     uplevel [list array set $varName { a b }]
     uplevel [list trace add variable $varName read  [list uwp_op_get $widget]]
     uplevel [list trace add variable $varName write [list uwp_op_set $widget]]
 }
 proc uwp_op_get { widget name1 name2 op } {
     upvar        $name1 options
     set options($name2) [option get $widget $name2 {}]
 }
 proc uwp_op_set { widget name1 name2 op } {
     upvar        $name1 options
     option add *[string trimleft $widget .].$name2 $options($name2)
 }
 #page
 proc uwp_cb_build { widget coords {command {}} } {
     global        uwp_data
     uwp_op_array $widget options
     
     frame $widget -class Cb
     canvas [set c $widget.canvas] -background $options(background) \
         -width $options(width) -height $options(height)
     grid $c
     
     set width  [$c cget -width]
     set height [$c cget -height]
     
     foreach {x y} $coords {
         lappend border_coords \
             [expr {int((double($x)+1.0)*double($width)*0.5)}] \
             [expr {int((double($y)+1.0)*double($height)*0.5)}]
     }
     array set uwp_data \
         [list $widget:border_coords $border_coords $widget:pressed no]
     
     $c create polygon $border_coords -tags {Clickable Button} \
         -fill $options(bbground)
     $c create text [expr {int($width/2)}] [expr {int($height/2)}] \
         -text $options(text) -font $options(font) \
         -fill $options(foreground) -tags {Clickable Text}
     uwp_p_cb_draw_released_border $widget
     
     bind $widget <Destroy>  [list uwp_p_cb_destroy $widget]
     bind $widget <FocusIn>  [list uwp_cb_event_focus yes $widget]
     bind $widget <FocusOut> [list uwp_cb_event_focus no $widget]
     bind $widget <Return>   [list uwp_cb_event_return $widget]
     $c bind Clickable <ButtonRelease-1> [list uwp_cb_event_release $widget]
     $c bind Clickable <ButtonPress-1>   [list uwp_cb_event_press   $widget]
     $c bind Clickable <Enter>           [list uwp_cb_event_enter   $widget]
     $c bind Clickable <Leave>           [list uwp_cb_event_leave   $widget]

     #SeS
     $c bind Clickable <B1-Motion>       [list uwp_cb_event_press   $widget]
     
     uwp_cb_command $widget $command
     return $widget
 }
 proc uwp_p_cb_destroy { widget } {
     global        uwp_data
     array unset uwp_data $widget:*
 }
 #page
 proc uwp_p_cb_draw_border { pressed widget } {
     global        uwp_data
     uwp_op_array $widget options
     
     set coords $uwp_data($widget:border_coords)
     set coords1 [concat [lrange $coords 2 end] [lrange $coords 0 1]]
     
     foreach {x1 y1} $coords {x2 y2} $coords1 {
         set d [expr {(-double($y2-$y1)+double($x2-$x1))/
                      sqrt(pow(double($y2-$y1),2.0)+pow(double($x2-$x1),2.0))}]
         set level [expr {180+int(50.0*$d)}]
         if { $pressed } {
             if { $level < 200 } { set color $options(background)
             } else { set color $options(pressedbordercolor) }
         } else {
             set color [format "\#%x%x%x" $level $level $level]            
         }
         $widget.canvas create line $x1 $y1 $x2 $y2 \
             -fill $color -tags Border -width $options(borderWidth)
     }
 }
 interp alias {} uwp_p_cb_draw_pressed_border  {} uwp_p_cb_draw_border yes
 interp alias {} uwp_p_cb_draw_released_border {} uwp_p_cb_draw_border no
 proc deg2rad { angle } { expr {double($angle)*57.2957795131} }
 #page
 proc uwp_cb_command { widget {command {}} } {
     global        uwp_data
     set uwp_data($widget:command) $command
 }
 proc uwp_cb_invoke { widget } {
     upvar        \#0 uwp_data($widget:command) cmd
     upvar        \#0 uwp_data($widget:focus) focus
     if { [string length $cmd] && $focus } { uplevel \#0 $cmd }
 }
 proc uwp_cb_event_press { widget } {
     uwp_cb_action_press $widget
 }
 proc uwp_cb_event_release { widget } {
     #SeS
     upvar        \#0 uwp_data($widget:pressed) pressed
     upvar        \#0 uwp_data($widget:focus) focus
     if { $pressed && $focus} { after 0 [list uwp_cb_invoke $widget] }
     uwp_cb_action_release $widget
 }
 proc uwp_cb_event_enter { widget } {
    #SeS
    upvar        \#0 uwp_data($widget:pressed) pressed
    if { ! $pressed } {uwp_cb_action_state_active $widget}
    set ::uwp_data($widget:focus) 1
 }
 proc uwp_cb_event_leave { widget } {
    #SeS
    upvar        \#0 uwp_data($widget:pressed) pressed
    upvar        \#0 uwp_data($widget:focus) focus
    if { !$pressed && $focus } {
      uwp_cb_action_state_normal $widget
      uwp_cb_action_release $widget
      set ::uwp_data($widget:focus) 0
    }
 }
 proc uwp_cb_event_focus { mode widget } {
     $widget.canvas itemconfigure Text \
         -font [concat [$widget.canvas itemcget Text -font] [list -underline $mode]]
 }
 proc uwp_cb_event_return { widget } {
     uwp_cb_event_press $widget
     after 100 [list uwp_cb_event_release $widget]
 }
 #page
 proc uwp_cb_action_state_active { widget } {
     uwp_op_array $widget options
     $widget.canvas itemconfigure Button -fill $options(activebbground)
 }
 proc uwp_cb_action_state_normal { widget } {
     uwp_op_array $widget options
     $widget.canvas itemconfigure Button -fill $options(bbground)
 }
 proc uwp_cb_action_press { widget } {
     upvar        \#0 uwp_data($widget:pressed) pressed
     if { ! $pressed } {
         uwp_p_cb_draw_pressed_border $widget
         $widget.canvas move Text 2 2
         set pressed yes
     }
 }
 proc uwp_cb_action_release { widget } {
     upvar        \#0 uwp_data($widget:pressed) pressed
     if { $pressed } {
         uwp_p_cb_draw_released_border $widget
         $widget.canvas move Text -2 -2
         set pressed no
     }
 }
 #page
 ## ------------------------------------------------------------
 ## Let's go.
 ## ------------------------------------------------------------
 main
 
 ### end of file
 # Local Variables:
 # mode: tcl
 # End:


Orginal code:

 # canvas_polygon_button.tcl --
 # 
 # Part of: Useless Widgets Packages
 # Contents: test canvas buttons
 # Date: Wed Dec 22, 2004
 # Credits: Gerard Sookahet has put the superformula on the TCL'ers Wiki
 # 
 # Abstract
 # 
 #        It should support all the common button operations:
 #
 #        * when the pointer enters the button is hilighted;
 #        * when the button is clicked it is pressed;
 #        * when the pointer leaves the button is de-hilighted
 #          and raised (if pressed);
 #        * when the button is unclicked the button is raised
 #          (if pressed) and the command invoked (if the button
 #          is pressed);
 #        * if focus comes in the text is underlined;
 #        * if the focus goes out the text is deunderlined;
 #        * if the "Return" key is pressed while the focus is in
 #          the button is pressed and then depressed after 100 ms,
 #          and the command invoked.
 # 
 # Copyright (c) 2004 Marco Maggi
 # 
 # The author  hereby grant permission to use,  copy, modify, distribute,
 # and  license this  software  and its  documentation  for any  purpose,
 # provided that  existing copyright notices  are retained in  all copies
 # and that  this notice  is included verbatim  in any  distributions. No
 # written agreement, license, or royalty  fee is required for any of the
 # authorized uses.  Modifications to this software may be copyrighted by
 # their authors and need not  follow the licensing terms described here,
 # provided that the new terms are clearly indicated on the first page of
 # each file where they apply.
 # 
 # IN NO  EVENT SHALL THE AUTHOR  OR DISTRIBUTORS BE LIABLE  TO ANY PARTY
 # FOR  DIRECT, INDIRECT, SPECIAL,  INCIDENTAL, OR  CONSEQUENTIAL DAMAGES
 # ARISING OUT  OF THE  USE OF THIS  SOFTWARE, ITS DOCUMENTATION,  OR ANY
 # DERIVATIVES  THEREOF, EVEN  IF THE  AUTHOR  HAVE BEEN  ADVISED OF  THE
 # POSSIBILITY OF SUCH DAMAGE.
 # 
 # THE  AUTHOR  AND DISTRIBUTORS  SPECIFICALLY  DISCLAIM ANY  WARRANTIES,
 # INCLUDING,   BUT   NOT  LIMITED   TO,   THE   IMPLIED  WARRANTIES   OF
 # MERCHANTABILITY,    FITNESS   FOR    A    PARTICULAR   PURPOSE,    AND
 # NON-INFRINGEMENT.  THIS  SOFTWARE IS PROVIDED  ON AN "AS  IS" BASIS,
 # AND  THE  AUTHOR  AND  DISTRIBUTORS  HAVE  NO  OBLIGATION  TO  PROVIDE
 # MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
 #
 
 #page
 ## ------------------------------------------------------------
 ## Setup.
 ## ------------------------------------------------------------
 
 package require Tcl 8.4
 package require Tk  8.4
 
 #page
 ## ------------------------------------------------------------
 ## Widget options.
 ## ------------------------------------------------------------
 
 option add *borderWidth                        1
 
 option add *Cb.relief                        flat
 option add *Cb.canvas.relief                flat
 
 option add *Cb.borderWidth                2
 option add *Cb*highlightThickness        0
 # this is the default light gray
 option add *Cb.background                "\#d9d9d9"
 option add *Cb.bbground                        "\#d9d9d9"
 # bisque see the "colors" man page or "/usr/X11R6/lib/X11/rgb.txt"
 option add *Cb.activebbground                bisque
 option add *Cb.foreground                black
 option add *Cb.pressedbordercolor        {dark gray}
 option add *Cb.width                        100
 option add *Cb.height                        100
 option add *Cb.takeFocus                1
 
 option add *Cb.text                        Text
 option add *Cb.font                        {-weight bold -family Helvetica -size 12}
 
 #page
 ## ------------------------------------------------------------
 ## Main.
 ## ------------------------------------------------------------
 
 proc main {} {
     global        exit_trigger
 
     wm title . "Testing canvas buttons"
     wm geometry . +100+100
     
     set counter 0
     
     set col -1
     foreach {name num fraction} {
         a 3 -4  b 4 8  c 6 1  d 12 1  e 50 1
     } {
         uwp_cb_build .$name [polygon_regular_coords $num 0.8 $fraction] \
             button_command
         grid .$name -row 0 -column [incr col]
     }
     set col -1
     foreach {name num} {
         m 3  n 4  o 6  p 12  q 20
     } {
         uwp_cb_build .$name [polygon_star_coords $num] button_command
         grid .$name -row 1 -column [incr col]
     }
     set col -1
     # parms: a b m n1 n2 n3
     foreach {name parms} {
         r {0.7   0.9   6.0   1.0   2.0   1.4}
         s {0.9   0.7  12.0   1.5   2.0   7.5}
         t {0.9   0.7  10.0   0.9   1.7   1.1}
     } {
         uwp_cb_build .$name [eval superformula $parms] button_command
         grid .$name -row 2 -column [incr col]
     }
 
     grid \
         [label .l -text 0 -width 5 -background \#ffffff] \
         [button .quit -text Exit -command main_exit]
     focus .quit
     bind .quit <Return> main_exit
     
     interp alias {} main_exit {} set exit_trigger 1
     vwait exit_trigger
     exit
 }
 proc button_command {} { .l configure -text [expr {[.l cget -text]+1}] }
 #page
 proc polygon_regular_coords { num radius {fraction 1.0} } {
     for {set i 0} {$i < $num} {incr i} {
         set angle [expr {6.28318530718/double($fraction)+
                          (6.28318530718*double($i)/double($num))}]
         lappend coords \
             [expr {double($radius)*cos($angle)}] \
             [expr {double($radius)*sin($angle)}]
     }
     return $coords
 }
 proc polygon_star_coords { num } {
     set fraction [expr {double($num)*2.0}]
     foreach {x1 y1} [polygon_regular_coords $num 0.9] \
         {x2 y2} [polygon_regular_coords $num 0.6 $fraction] {
             lappend result $x1 $y1 $x2 $y2
     }
     return $result
 }
 proc superformula { a b m n1 n2 n3 } {
     set num 50
     for {set i 0} {$i < $num} {incr i} {
         set theta [expr {double($i)*6.28318530718/double($num)}]
         set rho \
             [expr { pow(pow(abs(cos(0.25*double($m)*double($theta))/double($a)),
                             double($n2))+
                         pow(abs(sin(0.25*double($m)*double($theta))/double($b)),
                             double($n2)), (-1/double($n1))) }]
         lappend result [expr {$rho*cos($theta)}] [expr {$rho*sin($theta)}]
     }
     return $result
 }
 #page
 proc uwp_op_array { widget varName } {
     uplevel [list array set $varName { a b }]
     uplevel [list trace add variable $varName read  [list uwp_op_get $widget]]
     uplevel [list trace add variable $varName write [list uwp_op_set $widget]]
 }
 proc uwp_op_get { widget name1 name2 op } {
     upvar        $name1 options
     set options($name2) [option get $widget $name2 {}]
 }
 proc uwp_op_set { widget name1 name2 op } {
     upvar        $name1 options
     option add *[string trimleft $widget .].$name2 $options($name2)
 }
 #page
 proc uwp_cb_build { widget coords {command {}} } {
     global        uwp_data
     uwp_op_array $widget options
     
     frame $widget -class Cb
     canvas [set c $widget.canvas] -background $options(background) \
         -width $options(width) -height $options(height)
     grid $c
     
     set width  [$c cget -width]
     set height [$c cget -height]
     
     foreach {x y} $coords {
         lappend border_coords \
             [expr {int((double($x)+1.0)*double($width)*0.5)}] \
             [expr {int((double($y)+1.0)*double($height)*0.5)}]
     }
     array set uwp_data \
         [list $widget:border_coords $border_coords $widget:pressed no]
     
     $c create polygon $border_coords -tags {Clickable Button} \
         -fill $options(bbground)
     $c create text [expr {int($width/2)}] [expr {int($height/2)}] \
         -text $options(text) -font $options(font) \
         -fill $options(foreground) -tags {Clickable Text}
     uwp_p_cb_draw_released_border $widget
     
     bind $widget <Destroy>  [list uwp_p_cb_destroy $widget]
     bind $widget <FocusIn>  [list uwp_cb_event_focus yes $widget]
     bind $widget <FocusOut> [list uwp_cb_event_focus no $widget]
     bind $widget <Return>   [list uwp_cb_event_return $widget]
     $c bind Clickable <ButtonRelease-1> [list uwp_cb_event_release $widget]
     $c bind Clickable <ButtonPress-1>   [list uwp_cb_event_press   $widget]
     $c bind Clickable <Enter>           [list uwp_cb_event_enter   $widget]
     $c bind Clickable <Leave>           [list uwp_cb_event_leave   $widget]
     
     uwp_cb_command $widget $command
     return $widget
 }
 proc uwp_p_cb_destroy { widget } {
     global        uwp_data
     array unset uwp_data $widget:*
 }
 #page
 proc uwp_p_cb_draw_border { pressed widget } {
     global        uwp_data
     uwp_op_array $widget options
     
     set coords $uwp_data($widget:border_coords)
     set coords1 [concat [lrange $coords 2 end] [lrange $coords 0 1]]
     
     foreach {x1 y1} $coords {x2 y2} $coords1 {
         set d [expr {(-double($y2-$y1)+double($x2-$x1))/
                      sqrt(pow(double($y2-$y1),2.0)+pow(double($x2-$x1),2.0))}]
         set level [expr {180+int(50.0*$d)}]
         if { $pressed } {
             if { $level < 200 } { set color $options(background)
             } else { set color $options(pressedbordercolor) }
         } else {
             set color [format "\#%x%x%x" $level $level $level]            
         }
         $widget.canvas create line $x1 $y1 $x2 $y2 \
             -fill $color -tags Border -width $options(borderWidth)
     }
 }
 interp alias {} uwp_p_cb_draw_pressed_border  {} uwp_p_cb_draw_border yes
 interp alias {} uwp_p_cb_draw_released_border {} uwp_p_cb_draw_border no
 proc deg2rad { angle } { expr {double($angle)*57.2957795131} }
 #page
 proc uwp_cb_command { widget {command {}} } {
     global        uwp_data
     set uwp_data($widget:command) $command
 }
 proc uwp_cb_invoke { widget } {
     upvar        \#0 uwp_data($widget:command) cmd
     if { [string length $cmd] } { uplevel \#0 $cmd }
 }
 proc uwp_cb_event_press { widget } {
     uwp_cb_action_press $widget
 }
 proc uwp_cb_event_release { widget } {
     upvar        \#0 uwp_data($widget:pressed) pressed
     if { $pressed } { after 0 [list uwp_cb_invoke $widget] }
     uwp_cb_action_release $widget
 }
 proc uwp_cb_event_enter { widget } {
     uwp_cb_action_state_active $widget
 }
 proc uwp_cb_event_leave { widget } {
     uwp_cb_action_state_normal $widget
     uwp_cb_action_release $widget
 }
 proc uwp_cb_event_focus { mode widget } {
     $widget.canvas itemconfigure Text \
         -font [concat [$widget.canvas itemcget Text -font] [list -underline $mode]]
 }
 proc uwp_cb_event_return { widget } {
     uwp_cb_event_press $widget
     after 100 [list uwp_cb_event_release $widget]
 }
 #page
 proc uwp_cb_action_state_active { widget } {
     uwp_op_array $widget options
     $widget.canvas itemconfigure Button -fill $options(activebbground)
 }
 proc uwp_cb_action_state_normal { widget } {
     uwp_op_array $widget options
     $widget.canvas itemconfigure Button -fill $options(bbground)
 }
 proc uwp_cb_action_press { widget } {
     upvar        \#0 uwp_data($widget:pressed) pressed
     if { ! $pressed } {
         uwp_p_cb_draw_pressed_border $widget
         $widget.canvas move Text 2 2
         set pressed yes
     }
 }
 proc uwp_cb_action_release { widget } {
     upvar        \#0 uwp_data($widget:pressed) pressed
     if { $pressed } {
         uwp_p_cb_draw_released_border $widget
         $widget.canvas move Text -2 -2
         set pressed no
     }
 }
 #page
 ## ------------------------------------------------------------
 ## Let's go.
 ## ------------------------------------------------------------
 
 main
 
 ### end of file
 # Local Variables:
 # mode: tcl
 # End: