| 1 | #---------------------------------------------------------------------- |
|---|
| 2 | # |
|---|
| 3 | # autoscroll.tcl -- |
|---|
| 4 | # |
|---|
| 5 | # Package to create scroll bars that automatically appear when |
|---|
| 6 | # a window is too small to display its content. |
|---|
| 7 | # |
|---|
| 8 | #---------------------------------------------------------------------- |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | package require Tk |
|---|
| 12 | |
|---|
| 13 | if { 0 eq [namespace exists autoscroll] } { |
|---|
| 14 | |
|---|
| 15 | namespace eval autoscroll { |
|---|
| 16 | namespace export autoscroll |
|---|
| 17 | |
|---|
| 18 | bind Autoscroll <Delete> [namespace code [list delete %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 |
|---|
| 31 | # exist and have its geometry managed by the gridder. |
|---|
| 32 | # |
|---|
| 33 | # Results: |
|---|
| 34 | # None. |
|---|
| 35 | # |
|---|
| 36 | # Side effects: |
|---|
| 37 | # The widget command is renamed, so that the 'set' command can |
|---|
| 38 | # be intercepted and determine whether the widget should appear. |
|---|
| 39 | # In addition, the 'Autoscroll' bind tag is added to the widget, |
|---|
| 40 | # so that the <Destroy> event can be intercepted. |
|---|
| 41 | # |
|---|
| 42 | # Notes: |
|---|
| 43 | # It is an error to change the widget's gridding after |
|---|
| 44 | # calling 'autoscroll' on it. |
|---|
| 45 | # |
|---|
| 46 | #---------------------------------------------------------------------- |
|---|
| 47 | |
|---|
| 48 | proc autoscroll::autoscroll { w } { |
|---|
| 49 | |
|---|
| 50 | variable grid |
|---|
| 51 | variable needed |
|---|
| 52 | |
|---|
| 53 | rename $w [namespace current]::renamed$w |
|---|
| 54 | |
|---|
| 55 | proc ::$w {args} " |
|---|
| 56 | return \[eval \[list autoscroll::widgetCommand $w\] \$args\] |
|---|
| 57 | " |
|---|
| 58 | |
|---|
| 59 | set i [grid info $w] |
|---|
| 60 | if { [string match {} $i] } { |
|---|
| 61 | error "$w is not gridded" |
|---|
| 62 | } |
|---|
| 63 | set grid($w) $i |
|---|
| 64 | set needed($w) 1 |
|---|
| 65 | |
|---|
| 66 | bindtags $w [linsert [bindtags $w] 1 Autoscroll] |
|---|
| 67 | |
|---|
| 68 | eval [list ::$w set] [renamed$w get] |
|---|
| 69 | |
|---|
| 70 | return |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | #---------------------------------------------------------------------- |
|---|
| 74 | # |
|---|
| 75 | # autoscroll::widgetCommand -- |
|---|
| 76 | # |
|---|
| 77 | # Widget command on an 'autoscroll' scrollbar |
|---|
| 78 | # |
|---|
| 79 | # Parameters: |
|---|
| 80 | # w -- Path name of the scroll bar |
|---|
| 81 | # command -- Widget command being executed |
|---|
| 82 | # args -- Arguments to the commane |
|---|
| 83 | # |
|---|
| 84 | # Results: |
|---|
| 85 | # Returns whatever the widget command returns |
|---|
| 86 | # |
|---|
| 87 | # Side effects: |
|---|
| 88 | # Has whatever side effects the widget command has. In |
|---|
| 89 | # addition, the 'set' widget command is handled specially, |
|---|
| 90 | # by setting/unsetting the 'needed' flag and gridding/ungridding |
|---|
| 91 | # the scroll bar according to whether it is required. |
|---|
| 92 | # |
|---|
| 93 | #---------------------------------------------------------------------- |
|---|
| 94 | |
|---|
| 95 | proc autoscroll::widgetCommand { w command args } { |
|---|
| 96 | |
|---|
| 97 | variable grid |
|---|
| 98 | variable needed |
|---|
| 99 | |
|---|
| 100 | switch -exact -- $command { |
|---|
| 101 | set { |
|---|
| 102 | foreach { min max } $args {} |
|---|
| 103 | if { $min <= 0 && $max >= 1 } { |
|---|
| 104 | if { [info exists needed($w)] } { |
|---|
| 105 | unset needed($w) |
|---|
| 106 | grid forget $w |
|---|
| 107 | } |
|---|
| 108 | } else { |
|---|
| 109 | if { ! [info exists needed($w)] } { |
|---|
| 110 | set needed($w) {} |
|---|
| 111 | eval [list grid $w] $grid($w) |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | return [eval [list renamed$w $command] $args] |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | #---------------------------------------------------------------------- |
|---|
| 121 | # |
|---|
| 122 | # autoscroll::delete -- |
|---|
| 123 | # |
|---|
| 124 | # Delete an automatic scroll bar |
|---|
| 125 | # |
|---|
| 126 | # Parameters: |
|---|
| 127 | # w -- Path name of the scroll bar |
|---|
| 128 | # |
|---|
| 129 | # Results: |
|---|
| 130 | # None. |
|---|
| 131 | # |
|---|
| 132 | # Side effects: |
|---|
| 133 | # Cleans up internal memory. |
|---|
| 134 | # |
|---|
| 135 | #---------------------------------------------------------------------- |
|---|
| 136 | |
|---|
| 137 | proc autoscroll::delete { w } { |
|---|
| 138 | variable grid |
|---|
| 139 | variable needed |
|---|
| 140 | |
|---|
| 141 | catch { unset grid($w) } |
|---|
| 142 | catch { unset needed($w) } |
|---|
| 143 | catch { rename renamed$w {} } |
|---|
| 144 | |
|---|
| 145 | return |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | #---------------------------------------------------------------------- |
|---|
| 149 | # |
|---|
| 150 | # autoscroll::map -- |
|---|
| 151 | # |
|---|
| 152 | # Callback executed when an automatic scroll bar is mapped. |
|---|
| 153 | # |
|---|
| 154 | # Parameters: |
|---|
| 155 | # w -- Path name of the scroll bar. |
|---|
| 156 | # |
|---|
| 157 | # Results: |
|---|
| 158 | # None. |
|---|
| 159 | # |
|---|
| 160 | # Side effects: |
|---|
| 161 | # Geometry of the scroll bar's top-level window is constrained. |
|---|
| 162 | # |
|---|
| 163 | # This procedure keeps the top-level window associated with an |
|---|
| 164 | # automatic scroll bar from being resized automatically after the |
|---|
| 165 | # scroll bar is mapped. This effect avoids a potential endless loop |
|---|
| 166 | # in the case where the resize of the top-level window resizes the |
|---|
| 167 | # widget being scrolled, causing the scroll bar no longer to be needed. |
|---|
| 168 | # |
|---|
| 169 | #---------------------------------------------------------------------- |
|---|
| 170 | |
|---|
| 171 | proc autoscroll::map { w } { |
|---|
| 172 | wm geometry [winfo toplevel $w] \ |
|---|
| 173 | [wm geometry [winfo toplevel $w]] |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | package provide autoscroll 1.0 |
|---|
| 177 | } |
|---|