| 1 | # autoscroll.tcl -- |
|---|
| 2 | # |
|---|
| 3 | # Package to create scroll bars that automatically appear when |
|---|
| 4 | # a window is too small to display its content. |
|---|
| 5 | # |
|---|
| 6 | # Copyright (c) 2003 Kevin B Kenny <kennykb@users.sourceforge.net> |
|---|
| 7 | # |
|---|
| 8 | # See the file "license.terms" for information on usage and redistribution |
|---|
| 9 | # of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
|---|
| 10 | # |
|---|
| 11 | # RCS: @(#) $Id: autoscroll.tcl,v 1.8 2005/06/01 02:37:51 andreas_kupries Exp $ |
|---|
| 12 | |
|---|
| 13 | package require Tk |
|---|
| 14 | package provide autoscroll 1.1 |
|---|
| 15 | |
|---|
| 16 | namespace eval ::autoscroll { |
|---|
| 17 | namespace export autoscroll unautoscroll |
|---|
| 18 | bind Autoscroll <Destroy> [namespace code [list destroyed %W]] |
|---|
| 19 | bind Autoscroll <Map> [namespace code [list map %W]] |
|---|
| 20 | } |
|---|
| 21 | |
|---|
| 22 | #---------------------------------------------------------------------- |
|---|
| 23 | # |
|---|
| 24 | # ::autoscroll::autoscroll -- |
|---|
| 25 | # |
|---|
| 26 | # Create a scroll bar that disappears when it is not needed, and |
|---|
| 27 | # reappears when it is. |
|---|
| 28 | # |
|---|
| 29 | # Parameters: |
|---|
| 30 | # w -- Path name of the scroll bar, which should already exist |
|---|
| 31 | # |
|---|
| 32 | # Results: |
|---|
| 33 | # None. |
|---|
| 34 | # |
|---|
| 35 | # Side effects: |
|---|
| 36 | # The widget command is renamed, so that the 'set' command can |
|---|
| 37 | # be intercepted and determine whether the widget should appear. |
|---|
| 38 | # In addition, the 'Autoscroll' bind tag is added to the widget, |
|---|
| 39 | # so that the <Destroy> event can be intercepted. |
|---|
| 40 | # |
|---|
| 41 | #---------------------------------------------------------------------- |
|---|
| 42 | |
|---|
| 43 | proc ::autoscroll::autoscroll { w } { |
|---|
| 44 | if { [info commands ::autoscroll::renamed$w] != "" } { return $w } |
|---|
| 45 | rename $w ::autoscroll::renamed$w |
|---|
| 46 | interp alias {} ::$w {} ::autoscroll::widgetCommand $w |
|---|
| 47 | bindtags $w [linsert [bindtags $w] 1 Autoscroll] |
|---|
| 48 | eval [list ::$w set] [renamed$w get] |
|---|
| 49 | return $w |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | #---------------------------------------------------------------------- |
|---|
| 53 | # |
|---|
| 54 | # ::autoscroll::unautoscroll -- |
|---|
| 55 | # |
|---|
| 56 | # Return a scrollbar to its normal static behavior by removing |
|---|
| 57 | # it from the control of this package. |
|---|
| 58 | # |
|---|
| 59 | # Parameters: |
|---|
| 60 | # w -- Path name of the scroll bar, which must have previously |
|---|
| 61 | # had ::autoscroll::autoscroll called on it. |
|---|
| 62 | # |
|---|
| 63 | # Results: |
|---|
| 64 | # None. |
|---|
| 65 | # |
|---|
| 66 | # Side effects: |
|---|
| 67 | # The widget command is renamed to its original name. The widget |
|---|
| 68 | # is mapped if it was not currently displayed. The widgets |
|---|
| 69 | # bindtags are returned to their original state. Internal memory |
|---|
| 70 | # is cleaned up. |
|---|
| 71 | # |
|---|
| 72 | #---------------------------------------------------------------------- |
|---|
| 73 | |
|---|
| 74 | proc ::autoscroll::unautoscroll { w } { |
|---|
| 75 | if { [info commands ::autoscroll::renamed$w] != "" } { |
|---|
| 76 | variable grid |
|---|
| 77 | rename ::$w {} |
|---|
| 78 | rename ::autoscroll::renamed$w ::$w |
|---|
| 79 | if { [set i [lsearch -exact [bindtags $w] Autoscroll]] > -1 } { |
|---|
| 80 | bindtags $w [lreplace [bindtags $w] $i $i] |
|---|
| 81 | } |
|---|
| 82 | if { [info exists grid($w)] } { |
|---|
| 83 | eval [join $grid($w) \;] |
|---|
| 84 | unset grid($w) |
|---|
| 85 | } |
|---|
| 86 | } |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | #---------------------------------------------------------------------- |
|---|
| 90 | # |
|---|
| 91 | # ::autoscroll::widgetCommand -- |
|---|
| 92 | # |
|---|
| 93 | # Widget command on an 'autoscroll' scrollbar |
|---|
| 94 | # |
|---|
| 95 | # Parameters: |
|---|
| 96 | # w -- Path name of the scroll bar |
|---|
| 97 | # command -- Widget command being executed |
|---|
| 98 | # args -- Arguments to the commane |
|---|
| 99 | # |
|---|
| 100 | # Results: |
|---|
| 101 | # Returns whatever the widget command returns |
|---|
| 102 | # |
|---|
| 103 | # Side effects: |
|---|
| 104 | # Has whatever side effects the widget command has. In |
|---|
| 105 | # addition, the 'set' widget command is handled specially, |
|---|
| 106 | # by gridding/packing the scroll bar according to whether |
|---|
| 107 | # it is required. |
|---|
| 108 | # |
|---|
| 109 | #------------------------------------------------------------ |
|---|
| 110 | |
|---|
| 111 | proc ::autoscroll::widgetCommand { w command args } { |
|---|
| 112 | variable grid |
|---|
| 113 | if { $command == "set" } { |
|---|
| 114 | foreach { min max } $args {} |
|---|
| 115 | if { $min <= 0 && $max >= 1 } { |
|---|
| 116 | switch -exact -- [winfo manager $w] { |
|---|
| 117 | grid { |
|---|
| 118 | lappend grid($w) "[list grid $w] [grid info $w]" |
|---|
| 119 | grid forget $w |
|---|
| 120 | } |
|---|
| 121 | pack { |
|---|
| 122 | foreach x [pack slaves [winfo parent $w]] { |
|---|
| 123 | lappend grid($w) "[list pack $x] [pack info $x]" |
|---|
| 124 | } |
|---|
| 125 | pack forget $w |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | } elseif { [info exists grid($w)] } { |
|---|
| 129 | eval [join $grid($w) \;] |
|---|
| 130 | unset grid($w) |
|---|
| 131 | } |
|---|
| 132 | } |
|---|
| 133 | return [eval [list renamed$w $command] $args] |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | |
|---|
| 137 | #---------------------------------------------------------------------- |
|---|
| 138 | # |
|---|
| 139 | # ::autoscroll::destroyed -- |
|---|
| 140 | # |
|---|
| 141 | # Callback executed when an automatic scroll bar is destroyed. |
|---|
| 142 | # |
|---|
| 143 | # Parameters: |
|---|
| 144 | # w -- Path name of the scroll bar |
|---|
| 145 | # |
|---|
| 146 | # Results: |
|---|
| 147 | # None. |
|---|
| 148 | # |
|---|
| 149 | # Side effects: |
|---|
| 150 | # Cleans up internal memory. |
|---|
| 151 | # |
|---|
| 152 | #---------------------------------------------------------------------- |
|---|
| 153 | |
|---|
| 154 | proc ::autoscroll::destroyed { w } { |
|---|
| 155 | variable grid |
|---|
| 156 | catch { unset grid($w) } |
|---|
| 157 | rename ::$w {} |
|---|
| 158 | } |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | #---------------------------------------------------------------------- |
|---|
| 162 | # |
|---|
| 163 | # ::autoscroll::map -- |
|---|
| 164 | # |
|---|
| 165 | # Callback executed when an automatic scroll bar is mapped. |
|---|
| 166 | # |
|---|
| 167 | # Parameters: |
|---|
| 168 | # w -- Path name of the scroll bar. |
|---|
| 169 | # |
|---|
| 170 | # Results: |
|---|
| 171 | # None. |
|---|
| 172 | # |
|---|
| 173 | # Side effects: |
|---|
| 174 | # Geometry of the scroll bar's top-level window is constrained. |
|---|
| 175 | # |
|---|
| 176 | # This procedure keeps the top-level window associated with an |
|---|
| 177 | # automatic scroll bar from being resized automatically after the |
|---|
| 178 | # scroll bar is mapped. This effect avoids a potential endless loop |
|---|
| 179 | # in the case where the resize of the top-level window resizes the |
|---|
| 180 | # widget being scrolled, causing the scroll bar no longer to be needed. |
|---|
| 181 | # |
|---|
| 182 | #---------------------------------------------------------------------- |
|---|
| 183 | |
|---|
| 184 | proc ::autoscroll::map { w } { |
|---|
| 185 | wm geometry [winfo toplevel $w] [wm geometry [winfo toplevel $w]] |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | #---------------------------------------------------------------------- |
|---|
| 189 | # |
|---|
| 190 | # ::autoscroll::wrap -- |
|---|
| 191 | # |
|---|
| 192 | # Arrange for all new scrollbars to be automatically autoscrolled |
|---|
| 193 | # |
|---|
| 194 | # Parameters: |
|---|
| 195 | # None. |
|---|
| 196 | # |
|---|
| 197 | # Results: |
|---|
| 198 | # None. |
|---|
| 199 | # |
|---|
| 200 | # Side effects: |
|---|
| 201 | # ::scrollbar is overloaded to automatically autoscroll any new |
|---|
| 202 | # scrollbars. |
|---|
| 203 | # |
|---|
| 204 | #---------------------------------------------------------------------- |
|---|
| 205 | |
|---|
| 206 | proc ::autoscroll::wrap {} { |
|---|
| 207 | if {[info commands ::autoscroll::_scrollbar] != ""} {return} |
|---|
| 208 | rename ::scrollbar ::autoscroll::_scrollbar |
|---|
| 209 | proc ::scrollbar {w args} { |
|---|
| 210 | eval ::autoscroll::_scrollbar [list $w] $args |
|---|
| 211 | ::autoscroll::autoscroll $w |
|---|
| 212 | return $w |
|---|
| 213 | } |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | #---------------------------------------------------------------------- |
|---|
| 217 | # |
|---|
| 218 | # ::autoscroll::unwrap -- |
|---|
| 219 | # |
|---|
| 220 | # Turns off automatic autoscrolling of new scrollbars. Does not |
|---|
| 221 | # effect existing scrollbars. |
|---|
| 222 | # |
|---|
| 223 | # Parameters: |
|---|
| 224 | # None. |
|---|
| 225 | # |
|---|
| 226 | # Results: |
|---|
| 227 | # None. |
|---|
| 228 | # |
|---|
| 229 | # Side effects: |
|---|
| 230 | # ::scrollbar is returned to its original state |
|---|
| 231 | # |
|---|
| 232 | #---------------------------------------------------------------------- |
|---|
| 233 | |
|---|
| 234 | proc ::autoscroll::unwrap {} { |
|---|
| 235 | if {[info commands ::autoscroll::_scrollbar] == ""} {return} |
|---|
| 236 | rename ::scrollbar {} |
|---|
| 237 | rename ::autoscroll::_scrollbar ::scrollbar |
|---|
| 238 | } |
|---|