| 1 | package require Metawidget |
|---|
| 2 | |
|---|
| 3 | # name: Pane |
|---|
| 4 | # args: args: Option-value pairs |
|---|
| 5 | # creates two frames to hold the user widgets on each side of the Pane. |
|---|
| 6 | # creates the Pane as an invisible frame and assigns bindings to it for |
|---|
| 7 | # movements. A binding for window resize is created to recalculate the |
|---|
| 8 | # Pane position according to the window's new geometry. the metawidget |
|---|
| 9 | # options are initialized by calling their metawidget functions. |
|---|
| 10 | metawidget create Pane { |
|---|
| 11 | frame $this.frm1 |
|---|
| 12 | frame $this.frm2 |
|---|
| 13 | frame $this.pane |
|---|
| 14 | |
|---|
| 15 | bind $this.pane <1> "$this _click" |
|---|
| 16 | bind $this.pane <B1-Motion> "$this _move" |
|---|
| 17 | bind $this.pane <ButtonRelease-1> "$this _release" |
|---|
| 18 | bind $this <Configure> "$this _resize" |
|---|
| 19 | |
|---|
| 20 | -orientation vertical |
|---|
| 21 | -update on |
|---|
| 22 | -width 4 |
|---|
| 23 | -resize both |
|---|
| 24 | } {} -default Pane |
|---|
| 25 | |
|---|
| 26 | # name: _click |
|---|
| 27 | # args: - |
|---|
| 28 | # called when the mouse button is pressed over the Pane. Stores the Pane's x |
|---|
| 29 | # position and the width of the enclosing widget in two private variables. |
|---|
| 30 | # if the -orientation is horizontal, then x is in fact y, the width is in |
|---|
| 31 | # fact the height. also, if real-time update is off, creates a temporary |
|---|
| 32 | # frameless toplevel as a visual indicator for the pane position. |
|---|
| 33 | # during dragging this toplevel is laid over the pane frame. |
|---|
| 34 | metawidget proc Pane _click {} { |
|---|
| 35 | set x [my sX] |
|---|
| 36 | set w [my sW] |
|---|
| 37 | |
|---|
| 38 | my iPos0 [expr [mkw.decode -$x [place info $this.pane]]-[winfo pointer$x .]] |
|---|
| 39 | my iArea [winfo $w $this] |
|---|
| 40 | |
|---|
| 41 | if { ! [my -update] } { |
|---|
| 42 | toplevel $this.drag |
|---|
| 43 | wm overrideredirect $this.drag 1 |
|---|
| 44 | wm geometry $this.drag =[my -width]x[winfo height $this.pane]+[winfo rootx $this.pane]+[winfo rooty $this.pane] |
|---|
| 45 | } |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | # name: _move |
|---|
| 49 | # args: - |
|---|
| 50 | # called when the Pane is moved. the new Pane position is calculated. |
|---|
| 51 | # if the -update option is on, the _release metawidget is called which |
|---|
| 52 | # immediately redraws the Paned windows. |
|---|
| 53 | metawidget proc Pane _move {} { |
|---|
| 54 | set x [my sX] |
|---|
| 55 | |
|---|
| 56 | my iPos [expr [my iPos0]+[winfo pointer$x .]] |
|---|
| 57 | if { [my iPos] < 0 } { |
|---|
| 58 | my iPos 0 |
|---|
| 59 | } elseif { [my iPos] > [my iArea]-[my -width] } { |
|---|
| 60 | my iPos [expr [my iArea]-[my -width]] |
|---|
| 61 | } |
|---|
| 62 | |
|---|
| 63 | place $this.pane -$x [my iPos] |
|---|
| 64 | |
|---|
| 65 | if { [my -update] } { |
|---|
| 66 | _release |
|---|
| 67 | } else { |
|---|
| 68 | wm geometry $this.drag =[my -width]x[winfo height $this.pane]+[winfo rootx $this.pane]+[winfo rooty $this.pane] |
|---|
| 69 | } |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | # name: _release |
|---|
| 73 | # args: - |
|---|
| 74 | # called after the Pane has been dragged, or while dragging if the -update |
|---|
| 75 | # option is on. calculates the new size and position of the Paned windows |
|---|
| 76 | # and places them accordingly. the variable fRatio contains the width (height) |
|---|
| 77 | # ratios of the two Paned windows. |
|---|
| 78 | metawidget proc Pane _release {} { |
|---|
| 79 | set x [my sX] |
|---|
| 80 | set w [my sW] |
|---|
| 81 | |
|---|
| 82 | place $this.frm1 -$x 0 -$w [my iPos] |
|---|
| 83 | place $this.frm2 -$x [expr [my iPos]+[my -width]] -$w [expr [my iArea]-[my iPos]-[my -width]] |
|---|
| 84 | my fRatio [expr 1.*[my iPos]/[my iArea]] |
|---|
| 85 | |
|---|
| 86 | if { ! [my -update] } { |
|---|
| 87 | destroy $this.drag |
|---|
| 88 | } |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | # name: _resize |
|---|
| 92 | # args: - |
|---|
| 93 | # called when the toplevel window is resized. depending on the -resize option |
|---|
| 94 | # the Pane position is recalculated and the windows are updated accordingly. |
|---|
| 95 | metawidget proc Pane _resize {} { |
|---|
| 96 | set x [my sX] |
|---|
| 97 | set w [my sW] |
|---|
| 98 | set h [my sH] |
|---|
| 99 | |
|---|
| 100 | my iArea [winfo $w $this] |
|---|
| 101 | |
|---|
| 102 | if { ! [myinfo exists iPos] } { |
|---|
| 103 | my iPos [expr [my iArea]/2] |
|---|
| 104 | my fRatio .5 |
|---|
| 105 | place $this.pane -$x [my iPos] -$w [my -width] -rel$h 1 |
|---|
| 106 | place $this.frm1 -$x 0 -$w [my iPos] -rel$h 1 |
|---|
| 107 | place $this.frm2 -$x [expr [my iPos]+[my -width]] -$w [expr [my iArea]-[my iPos]-[my -width]] -rel$h 1 |
|---|
| 108 | update |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | switch [my iM] { |
|---|
| 112 | 0 { |
|---|
| 113 | my iPos [expr [my fRatio]*[my iArea]] |
|---|
| 114 | place $this.pane -$x [my iPos] |
|---|
| 115 | place $this.frm1 -$w [my iPos] |
|---|
| 116 | place $this.frm2 -$x [expr [my iPos]+[my -width]] -$w [expr [my iArea]-[my iPos]-[my -width]] |
|---|
| 117 | } |
|---|
| 118 | 1 { |
|---|
| 119 | my iPos [expr [my iArea]-[my -width]-[winfo $w $this.frm2]] |
|---|
| 120 | place $this.pane -$x [my iPos] |
|---|
| 121 | place $this.frm1 -$w [my iPos] |
|---|
| 122 | place $this.frm2 -$x [expr [my iPos]+[my -width]] |
|---|
| 123 | } |
|---|
| 124 | 2 { |
|---|
| 125 | place $this.frm2 -$w [expr [my iArea]-[my iPos]-[my -width]] |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | # name: -orientation |
|---|
| 131 | # args: sOrient: vertical or horizontal |
|---|
| 132 | # option metawidget. depending on the orientation some variables are defined. |
|---|
| 133 | # they are later used as e.g. x, y, width and height options. if orientation |
|---|
| 134 | # is horizontal then x becomes y, width becomes height and vice versa. |
|---|
| 135 | metawidget proc Pane -orientation { sOrient } { |
|---|
| 136 | my -orientation [mkw.complete $sOrient {vertical horizontal}] |
|---|
| 137 | my iO [mkw.decode [my -orientation] {vertical 1 horizontal 0}] |
|---|
| 138 | |
|---|
| 139 | my sX [mkw.decode [my iO] {1 x 0 y}] |
|---|
| 140 | my sY [mkw.decode [my iO] {1 y 0 x}] |
|---|
| 141 | my sW [mkw.decode [my iO] {1 width 0 height}] |
|---|
| 142 | my sH [mkw.decode [my iO] {1 height 0 width}] |
|---|
| 143 | |
|---|
| 144 | $this.pane config -cursor [mkw.decode [my iO] {1 sb_h_double_arrow 0 sb_v_double_arrow}] |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | # name: -width |
|---|
| 148 | # args: iWidth: Pane width |
|---|
| 149 | # the desired Pane width is stored in a private variable. |
|---|
| 150 | metawidget proc Pane -width { iWidth } { |
|---|
| 151 | if { $iWidth < 1 } { |
|---|
| 152 | error "Pane $this: Pane must be at least 1 pixel wide." |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | my -width $iWidth |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | # name: -resize |
|---|
| 159 | # args: sMode: resize mode |
|---|
| 160 | # the new resize mode is stored in a private variable. 'left' means |
|---|
| 161 | # that only the left Paned window is resized, the right keeps its size. |
|---|
| 162 | # 'right' means the same for the right window. 'both' will resize both |
|---|
| 163 | # Paned windows proportionally. |
|---|
| 164 | metawidget proc Pane -resize { sMode } { |
|---|
| 165 | my -resize [mkw.complete $sMode {both first second}] |
|---|
| 166 | my iM [mkw.decode [my -resize] {both 0 first 1 second 2}] |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | # name: -update |
|---|
| 170 | # args: sUpdate: flag |
|---|
| 171 | # stores the update mode (a boolean) in a private variable. |
|---|
| 172 | metawidget proc Pane -update { sUpdate } { |
|---|
| 173 | set sUpdate [mkw.complete $sUpdate {on yes true 1 off no false 0}] |
|---|
| 174 | my -update [mkw.decode $sUpdate {on 1 yes 1 true 1 off 0 no 0 false 0} $sUpdate] |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | # name: set |
|---|
| 178 | # args: iPos: new Pane position |
|---|
| 179 | # sMode: same as for -resize |
|---|
| 180 | # for 'both' iPos is considered to be a percentage value (0-100). 0 is left |
|---|
| 181 | # (top), 100 is right (bottom). for 'first' and 'second' iPos is taken as a |
|---|
| 182 | # pixel value. the Pane is positioned that amount of pixels from left (top) |
|---|
| 183 | # resp. right (bottom). |
|---|
| 184 | metawidget proc Pane set_ { iPos {sMode both} } { |
|---|
| 185 | switch [mkw.complete $sMode {both first second}] { |
|---|
| 186 | both { set iPos [expr $iPos/100.*[my iArea]] } |
|---|
| 187 | first { set iPos $iPos } |
|---|
| 188 | second { set iPos [expr [my iArea]-[my -width]-$iPos] } |
|---|
| 189 | } |
|---|
| 190 | |
|---|
| 191 | if { $iPos < 0 } { |
|---|
| 192 | set iPos 0 |
|---|
| 193 | } elseif { $iPos > [my iArea]-[my -width] } { |
|---|
| 194 | set iPos [expr [my iArea]-[my -width]] |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | my iPos $iPos |
|---|
| 198 | place $this.pane -[my sX] [my iPos] |
|---|
| 199 | $this _release |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | # name: get |
|---|
| 203 | # args: sMode: same as for -resize |
|---|
| 204 | # the 'inverse' for the 'set' metawidget. retrieves the Pane position in a format |
|---|
| 205 | # depending on sMode: for 'both' it is a percentage value, otherwise the |
|---|
| 206 | # pixel position from the left resp. right (top resp. bottom). |
|---|
| 207 | metawidget proc Pane get { {sMode both} } { |
|---|
| 208 | set w [my sW] |
|---|
| 209 | |
|---|
| 210 | switch [mkw.complete $sMode {both first second}] { |
|---|
| 211 | both { return [expr 100*[winfo $w $this.frm1]/[my iArea]] } |
|---|
| 212 | first { return [winfo $w $this.frm1] } |
|---|
| 213 | second { return [winfo $w $this.frm2] } |
|---|
| 214 | } |
|---|
| 215 | } |
|---|
| 216 | |
|---|
| 217 | # name: place |
|---|
| 218 | # args: sMode: first or second. Paned window to place widgets into. |
|---|
| 219 | # sWindow: widget to place |
|---|
| 220 | # args: option-value pairs for the place command |
|---|
| 221 | # places sWindow in one of the two Paned windows. |
|---|
| 222 | metawidget proc Pane place_ { sMode sWindow args } { |
|---|
| 223 | set sPane $this.[mkw.decode $sMode {first frm1 second frm2}] |
|---|
| 224 | eval place $sWindow -in $sPane $args |
|---|
| 225 | raise $sWindow |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | # name: pack |
|---|
| 229 | # args: sMode: first or second. Paned window to pack widgets into. |
|---|
| 230 | # sWindow: widget to pack |
|---|
| 231 | # args: option-value pairs for the pack command |
|---|
| 232 | # packs sWindow in one of the two Paned windows. |
|---|
| 233 | metawidget proc Pane pack_ { sMode sWindow args } { |
|---|
| 234 | set sPane $this.[mkw.decode $sMode {first frm1 second frm2}] |
|---|
| 235 | eval pack $sWindow -in $sPane $args |
|---|
| 236 | raise $sWindow |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | # name: grid |
|---|
| 240 | # args: sMode: first or second. Paned window to grid widgets into. |
|---|
| 241 | # sWindow: widget to place |
|---|
| 242 | # args: option-value pairs for the grid command |
|---|
| 243 | # grids sWindow in one of the two Paned windows. sWindow can in fact be |
|---|
| 244 | # something like 'configure' which is detected with the if-clause. |
|---|
| 245 | metawidget proc Pane grid_ { sMode sWindow args } { |
|---|
| 246 | set sPane $this.[mkw.decode $sMode {first frm1 second frm2}] |
|---|
| 247 | |
|---|
| 248 | if { [winfo exists $sWindow] } { |
|---|
| 249 | eval grid $sWindow -in $sPane $args |
|---|
| 250 | } else { |
|---|
| 251 | eval grid $sWindow $sPane $args |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | raise $sWindow |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | metawidget command Pane _click _click |
|---|
| 258 | metawidget command Pane _move _move |
|---|
| 259 | metawidget command Pane _release _release |
|---|
| 260 | metawidget command Pane _resize _resize |
|---|
| 261 | |
|---|
| 262 | metawidget command Pane set set_ |
|---|
| 263 | metawidget command Pane get get |
|---|
| 264 | metawidget command Pane place place_ |
|---|
| 265 | metawidget command Pane pack pack_ |
|---|
| 266 | metawidget command Pane grid grid_ |
|---|
| 267 | |
|---|
| 268 | metawidget option Pane -orientation -orientation |
|---|
| 269 | metawidget option Pane -resize -resize |
|---|
| 270 | metawidget option Pane -width -width |
|---|
| 271 | metawidget option Pane -update -update |
|---|
| 272 | |
|---|
| 273 | proc test {} { |
|---|
| 274 | wm geometry . 300x300 |
|---|
| 275 | |
|---|
| 276 | pack [checkbutton .chk1 -text "Don't update while dragging" -on 0 -off 1 -command {.pan1 config -update $chk1}] -anchor w |
|---|
| 277 | pack [checkbutton .chk2 -text "Don't resize left editor" -on s -off b -command {.pan1 config -resize $chk2}] -anchor w |
|---|
| 278 | |
|---|
| 279 | text .txt1 -bg white |
|---|
| 280 | text .txt2 -bg white |
|---|
| 281 | text .txt3 -bg white |
|---|
| 282 | .txt1 insert end "left editor: the quick brown fox jumps over the lazy dog" |
|---|
| 283 | .txt2 insert end "upper right editor: bla bla bla bla bla" |
|---|
| 284 | .txt3 insert end [info body test] |
|---|
| 285 | |
|---|
| 286 | pane .pan1 -width 3 |
|---|
| 287 | pane .pan2 -width 3 -orientation horiz |
|---|
| 288 | |
|---|
| 289 | pack .pan1 -fill both -expand 1 |
|---|
| 290 | .pan1 pack first .txt1 -fill both -expand 1 |
|---|
| 291 | .pan1 pack second .pan2 -fill both -expand 1 |
|---|
| 292 | .pan2 pack first .txt2 -fill both -expand 1 |
|---|
| 293 | .pan2 pack second .txt3 -fill both -expand 1 |
|---|
| 294 | |
|---|
| 295 | } |
|---|
| 296 | |
|---|
| 297 | #test |
|---|