| #------------------------------------------------------------------------------- |
| # Extbutton |
| #------------------------------------------------------------------------------- |
| # This [incr Widget] is pretty simple - it just extends the behavior of |
| # the Tk button by allowing the user to add a bitmap or an image, which |
| # can be placed at various locations relative to the text via the -imagepos |
| # configuration option. |
| # |
| #------------------------------------------------------------------------------- |
| # IMPORTANT NOTE: This [incr Widget] will only work with Tk 8.4 or later. |
| # |
| #------------------------------------------------------------------------------- |
| # AUTHOR: Chad Smith E-mail: csmith@adc.com, itclguy@yahoo.com |
| #------------------------------------------------------------------------------- |
| # Permission to use, copy, modify, distribute, and license this software |
| # and its documentation for any purpose is hereby granted as long as this |
| # comment block remains intact. |
| #------------------------------------------------------------------------------- |
| |
| # |
| # Default resources |
| # |
| option add *Extbutton.borderwidth 2 widgetDefault |
| option add *Extbutton.relief raised widgetDefault |
| |
| # |
| # Usual options |
| # |
| itk::usual Extbutton { |
| keep -cursor -font |
| } |
| |
| itcl::class iwidgets::Extbutton { |
| inherit itk::Widget |
| |
| constructor {args} {} |
| |
| itk_option define -activebackground activeBackground Foreground #ececec |
| itk_option define -bd borderwidth BorderWidth 2 |
| itk_option define -bitmap bitmap Bitmap {} |
| itk_option define -command command Command {} |
| itk_option define -defaultring defaultring DefaultRing 0 |
| itk_option define -defaultringpad defaultringpad Pad 4 |
| itk_option define -image image Image {} |
| itk_option define -imagepos imagePos Position w |
| itk_option define -relief relief Relief raised |
| itk_option define -state state State normal |
| itk_option define -text text Text {} |
| |
| public method invoke {} {eval $itk_option(-command)} |
| public method flash {} |
| |
| private method changeColor {event_} |
| private method sink {} |
| private method raise {} {configure -relief $_oldValues(-relief)} |
| |
| private variable _oldValues |
| } |
| |
| |
| # |
| # Provide the usual lowercase access command. |
| # |
| proc iwidgets::extbutton {path_ args} { |
| uplevel iwidgets::Extbutton $path_ $args |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -bd |
| # |
| # DESCRIPTION: This isn't a new option. Similar to -image, we just need to |
| # repack the frame when the borderwidth changes. This option is kept by |
| # the private reliefframe component. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::bd { |
| pack $itk_component(frame) -padx 4 -pady 4 |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -bitmap |
| # |
| # DESCRIPTION: This isn't a new option - we just need to reset the -image option |
| # so that the user can toggle back and forth between images and bitmaps. |
| # Otherwise, the image will take precedence and the user will be unable to |
| # change to a bitmap without manually setting the label component's -image to |
| # an empty string. This option is kept by the image component. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::bitmap { |
| if {$itk_option(-bitmap) == ""} { |
| return |
| } |
| if {$itk_option(-image) != ""} { |
| configure -image {} |
| } |
| pack $itk_component(frame) -padx 4 -pady 4 |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -command |
| # |
| # DESCRIPTION: Invoke the given command to simulate the Tk button's -command |
| # option. The command is invoked on <ButtonRelease-1> events only or by |
| # direct calls to the public invoke() method. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::command { |
| if {$itk_option(-command) == ""} { |
| return |
| } |
| |
| # Only create the tag binding if the button is operable. |
| if {$itk_option(-state) == "normal"} { |
| bind $this-commandtag <ButtonRelease-1> [itcl::code $this invoke] |
| } |
| |
| # Associate the tag with each component if it's not already done. |
| if {[lsearch [bindtags $itk_interior] $this-commandtag] == -1} { |
| foreach component [component] { |
| bindtags [component $component] \ |
| [linsert [bindtags [component $component]] end $this-commandtag] |
| } |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -defaultring |
| # |
| # DESCRIPTION: Controls display of the sunken frame surrounding the button. |
| # This option simulates the pushbutton iwidget -defaultring option. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::defaultring { |
| switch -- $itk_option(-defaultring) { |
| 1 {set ring 1} |
| 0 {set ring 0} |
| default { |
| error "Invalid option for -defaultring: \"$itk_option(-defaultring)\". \ |
| Should be 1 or 0." |
| } |
| } |
| |
| if ($ring) { |
| $itk_component(ring) configure -borderwidth 2 |
| pack $itk_component(reliefframe) -padx $itk_option(-defaultringpad) \ |
| -pady $itk_option(-defaultringpad) |
| } else { |
| $itk_component(ring) configure -borderwidth 0 |
| pack $itk_component(reliefframe) -padx 0 -pady 0 |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -defaultringpad |
| # |
| # DESCRIPTION: The pad distance between the ring and the button. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::defaultringpad { |
| # Must be an integer. |
| if ![string is integer $itk_option(-defaultringpad)] { |
| error "Invalid value specified for -defaultringpad:\ |
| \"$itk_option(-defaultringpad)\". Must be an integer." |
| } |
| |
| # Let's go ahead and make the maximum padding 20 pixels. Surely no one |
| # will want more than that. |
| if {$itk_option(-defaultringpad) < 0 || $itk_option(-defaultringpad) > 20} { |
| error "Value for -defaultringpad must be between 0 and 20." |
| } |
| |
| # If the ring is displayed, repack it according to the new padding amount. |
| if {$itk_option(-defaultring)} { |
| pack $itk_component(reliefframe) -padx $itk_option(-defaultringpad) \ |
| -pady $itk_option(-defaultringpad) |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -image |
| # |
| # DESCRIPTION: This isn't a new option - we just need to repack the frame after |
| # the image is changed in case the size is different than the previous one. |
| # This option is kept by the image component. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::image { |
| pack $itk_component(frame) -padx 4 -pady 4 |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -imagepos |
| # |
| # DESCRIPTION: Allows the user to move the image to different locations areound |
| # the text. Valid options are n, nw, ne, s, sw, se e, en, es, w, wn or ws. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::imagepos { |
| switch -- $itk_option(-imagepos) { |
| n {set side top; set anchor center} |
| ne {set side top; set anchor e} |
| nw {set side top; set anchor w} |
| |
| s {set side bottom; set anchor center} |
| se {set side bottom; set anchor e} |
| sw {set side bottom; set anchor w} |
| |
| w {set side left; set anchor center} |
| wn {set side left; set anchor n} |
| ws {set side left; set anchor s} |
| |
| e {set side right; set anchor center} |
| en {set side right; set anchor n} |
| es {set side right; set anchor s} |
| |
| default { |
| error "Invalid option: \"$itk_option(-imagepos)\". \ |
| Must be n, nw, ne, s, sw, se e, en, es, w, wn or ws." |
| } |
| } |
| |
| pack $itk_component(image) -side $side -anchor $anchor |
| pack $itk_component(frame) -padx 4 -pady 4 |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -relief |
| # |
| # DESCRIPTION: Move the frame component according to the relief to simulate |
| # the text in a Tk button when its relief is changed. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::relief { |
| update idletasks |
| switch -- $itk_option(-relief) { |
| flat - ridge - groove { |
| place $itk_component(frame) -x 5 -y 5 |
| } |
| |
| raised { |
| place $itk_component(frame) -x 4 -y 4 |
| } |
| |
| sunken { |
| place $itk_component(frame) -x 6 -y 6 |
| } |
| |
| default { |
| error "Invalid option: \"$itk_option(-relief)\". \ |
| Must be flat, ridge, groove, raised, or sunken." |
| } |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -state |
| # |
| # DESCRIPTION: Simulate the button's -state option. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::state { |
| switch -- $itk_option(-state) { |
| disabled { |
| bind $itk_interior <Enter> { } |
| bind $itk_interior <Leave> { } |
| bind $this-sunkentag <1> { } |
| bind $this-raisedtag <ButtonRelease-1> { } |
| bind $this-commandtag <ButtonRelease-1> { } |
| set _oldValues(-fg) [cget -foreground] |
| set _oldValues(-cursor) [cget -cursor] |
| configure -foreground $itk_option(-disabledforeground) |
| configure -cursor "X_cursor red black" |
| } |
| |
| normal { |
| bind $itk_interior <Enter> [itcl::code $this changeColor enter] |
| bind $itk_interior <Leave> [itcl::code $this changeColor leave] |
| bind $this-sunkentag <1> [itcl::code $this sink] |
| bind $this-raisedtag <ButtonRelease-1> [itcl::code $this raise] |
| bind $this-commandtag <ButtonRelease-1> [itcl::code $this invoke] |
| configure -foreground $_oldValues(-fg) |
| configure -cursor $_oldValues(-cursor) |
| } |
| |
| default { |
| error "Bad option for -state: \"$itk_option(-state)\". Should be\ |
| normal or disabled." |
| } |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # OPTION: -text |
| # |
| # DESCRIPTION: This isn't a new option. Similar to -image, we just need to |
| # repack the frame when the text changes. |
| #------------------------------------------------------------------------------- |
| itcl::configbody iwidgets::Extbutton::text { |
| pack $itk_component(frame) -padx 4 -pady 4 |
| } |
| |
| |
| |
| #------------------------------------------------------------------------------- |
| # CONSTRUCTOR |
| #------------------------------------------------------------------------------- |
| itcl::body iwidgets::Extbutton::constructor {args} { |
| # Extbutton will not work with versions of Tk less than 8.4 (the |
| # -activeforeground option was added to the Tk label widget in 8.4, for |
| # example). So disallow its use unless the right wish is being used. |
| if {$::tk_version < 8.4} { |
| error "The extbutton \[incr Widget\] can only be used with versions of\ |
| Tk greater than 8.3.\nYou're currently using version $::tk_version." |
| } |
| |
| # This frame is optionally displayed as a "default ring" around the button. |
| itk_component add ring { |
| frame $itk_interior.ring -relief sunken |
| } { |
| rename -background -ringbackground ringBackground Background |
| } |
| |
| # Add an outer frame for the widget's relief. Ideally we could just keep |
| # the hull's -relief, but it's too tricky to handle relief changes. |
| itk_component add -private reliefframe { |
| frame $itk_component(ring).f |
| } { |
| rename -borderwidth -bd borderwidth BorderWidth |
| keep -relief |
| usual |
| } |
| |
| # This frame contains the image and text. It will be moved slightly to |
| # simulate the text in a Tk button when the button is depressed/raised. |
| itk_component add frame { |
| frame $itk_component(reliefframe).f -borderwidth 0 |
| } |
| |
| itk_component add image { |
| label $itk_component(frame).img -borderwidth 0 |
| } { |
| keep -bitmap -background -image |
| rename -foreground -bitmapforeground foreground Foreground |
| } |
| |
| itk_component add label { |
| label $itk_component(frame).txt -borderwidth 0 |
| } { |
| keep -activeforeground -background -disabledforeground |
| keep -font -foreground -justify -text |
| } |
| |
| pack $itk_component(image) $itk_component(label) -side left -padx 6 -pady 4 |
| pack $itk_component(frame) -padx 4 -pady 4 |
| pack $itk_component(reliefframe) -fill both |
| pack $itk_component(ring) -fill both |
| |
| # Create a couple of binding tags for handling relief changes. Then |
| # add these tags to each component. |
| foreach component [component] { |
| bindtags [component $component] \ |
| [linsert [bindtags [component $component]] end $this-sunkentag] |
| bindtags [component $component] \ |
| [linsert [bindtags [component $component]] end $this-raisedtag] |
| } |
| |
| set _oldValues(-fg) [cget -foreground] |
| set _oldValues(-cursor) [cget -cursor] |
| |
| eval itk_initialize $args |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # METHOD: flash |
| # |
| # ACCESS: public |
| # |
| # DESCRIPTION: Simulate the Tk button flash command. |
| # |
| # ARGUMENTS: none |
| #------------------------------------------------------------------------------- |
| itcl::body iwidgets::Extbutton::flash {} { |
| set oldbg [cget -background] |
| config -background $itk_option(-activebackground) |
| update idletasks |
| |
| after 50; config -background $oldbg; update idletasks |
| after 50; config -background $itk_option(-activebackground); update idletasks |
| after 50; config -background $oldbg |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # METHOD: changeColor |
| # |
| # ACCESS: private |
| # |
| # DESCRIPTION: This method is invoked by <Enter> and <Leave> events to change |
| # the background and foreground colors of the widget. |
| # |
| # ARGUMENTS: event_ --> either "enter" or "leave" |
| #------------------------------------------------------------------------------- |
| itcl::body iwidgets::Extbutton::changeColor {event_} { |
| switch -- $event_ { |
| enter { |
| set _oldValues(-bg) [cget -background] |
| set _oldValues(-fg) [cget -foreground] |
| configure -background $itk_option(-activebackground) |
| configure -foreground $itk_option(-activeforeground) |
| } |
| leave { |
| configure -background $_oldValues(-bg) |
| configure -foreground $_oldValues(-fg) |
| } |
| } |
| } |
| |
| |
| #------------------------------------------------------------------------------- |
| # METHOD: sink |
| # |
| # ACCESS: private |
| # |
| # DESCRIPTION: This method is invoked on <1> mouse events. It saves the |
| # current relief for later restoral and configures the relief to sunken if |
| # it isn't already sunken. |
| # |
| # ARGUMENTS: none |
| #------------------------------------------------------------------------------- |
| itcl::body iwidgets::Extbutton::sink {} { |
| set _oldValues(-relief) [cget -relief] |
| if {$_oldValues(-relief) == "sunken"} { |
| return |
| } |
| configure -relief sunken |
| } |