1# ---------------------------------------------------------------------------- 2# panedw.tcl 3# This file is part of Unifix BWidget Toolkit 4# $Id: panedw.tcl,v 1.16 2009/10/25 20:55:36 oberdorfer Exp $ 5# ---------------------------------------------------------------------------- 6# Index of commands: 7# - PanedWindow::create 8# - PanedWindow::configure 9# - PanedWindow::cget 10# - PanedWindow::add 11# - PanedWindow::getframe 12# - PanedWindow::_apply_weights 13# - PanedWindow::_destroy 14# - PanedWindow::_beg_move_sash 15# - PanedWindow::_move_sash 16# - PanedWindow::_end_move_sash 17# - PanedWindow::_realize 18# ---------------------------------------------------------------------------- 19 20# JDC: added option to choose behavior of weights 21# -weights extra : only apply weights to extra space (as current (>= 1.3.1) with grid command) 22# -weights available : apply weights to total available space (as before (<1.3.1) with place command) 23 24namespace eval PanedWindow { 25 Widget::define PanedWindow panedw 26 27 namespace eval Pane { 28 Widget::declare PanedWindow::Pane { 29 {-minsize Int 0 0 "%d >= 0"} 30 {-weight Int 1 0 "%d >= 0"} 31 } 32 } 33 34 Widget::declare PanedWindow { 35 {-side Enum top 1 {top left bottom right}} 36 {-width Int 10 1 "%d >=3"} 37 {-pad Int 4 1 "%d >= 0"} 38 {-background Color "SystemWindowFrame" 0} 39 {-bg Synonym -background} 40 {-activator Enum "" 1 {line button}} 41 {-weights Enum extra 1 {extra available}} 42 } 43 44 variable _panedw 45 46 if { [BWidget::using ttk] } { 47 if {[lsearch [bindtags .] PanedWThemeChanged] < 0} { 48 bindtags . [linsert [bindtags .] 1 PanedWThemeChanged] 49 } 50 } 51 52} 53 54 55 56# ---------------------------------------------------------------------------- 57# Command PanedWindow::create 58# ---------------------------------------------------------------------------- 59proc PanedWindow::create { path args } { 60 variable _panedw 61 62 Widget::init PanedWindow $path $args 63 frame $path -background [Widget::cget $path -background] \ 64 -class PanedWindow \ 65 -highlightthickness 0 66 67 set _panedw($path,nbpanes) 0 68 set _panedw($path,weights) "" 69 set _panedw($path,configuredone) 0 70 71 set activator [Widget::getoption $path -activator] 72 if {[string equal $activator ""]} { 73 if { $::tcl_platform(platform) != "windows" } { 74 Widget::setMegawidgetOption $path -activator button 75 } else { 76 Widget::setMegawidgetOption $path -activator line 77 } 78 } 79 if {[string equal [Widget::getoption $path -activator] "line"]} { 80 Widget::setMegawidgetOption $path -width 3 81 } 82 83 bind $path <Configure> [list PanedWindow::_realize $path %w %h] 84 bind $path <Destroy> [list PanedWindow::_destroy $path] 85 86 if { [BWidget::using ttk] } { 87 bind PanedWThemeChanged <<ThemeChanged>> \ 88 "+[namespace current]::_themechanged $path" 89 } 90 91 92 return [Widget::create PanedWindow $path] 93} 94 95 96# ---------------------------------------------------------------------------- 97# Command PanedWindow::configure 98# ---------------------------------------------------------------------------- 99proc PanedWindow::configure { path args } { 100 variable _panedw 101 102 set res [Widget::configure $path $args] 103 104 if { [Widget::hasChanged $path -background bg] && $_panedw($path,nbpanes) > 0 } { 105 $path:cmd configure -background $bg 106 $path.f0 configure -background $bg 107 for {set i 1} {$i < $_panedw($path,nbpanes)} {incr i} { 108 set frame $path.sash$i 109 $frame configure -background $bg 110 $frame.sep configure -background $bg 111 $frame.but configure -background $bg 112 $path.f$i configure -background $bg 113 $path.f$i.frame configure -background $bg 114 } 115 } 116 return $res 117} 118 119 120# ---------------------------------------------------------------------------- 121# Command PanedWindow::cget 122# ---------------------------------------------------------------------------- 123proc PanedWindow::cget { path option } { 124 return [Widget::cget $path $option] 125} 126 127 128# ---------------------------------------------------------------------------- 129# Command PanedWindow::add 130# ---------------------------------------------------------------------------- 131proc PanedWindow::add { path args } { 132 variable _panedw 133 134 set num $_panedw($path,nbpanes) 135 Widget::init PanedWindow::Pane $path.f$num $args 136 set bg [Widget::getoption $path -background] 137 138 set wbut [Widget::getoption $path -width] 139 set pad [Widget::getoption $path -pad] 140 set width [expr {$wbut+2*$pad}] 141 set side [Widget::getoption $path -side] 142 set weight [Widget::getoption $path.f$num -weight] 143 lappend _panedw($path,weights) $weight 144 145 if { $num > 0 } { 146 set frame [frame $path.sash$num -relief flat -bd 0 \ 147 -highlightthickness 0 -width $width -height $width -bg $bg] 148 set sep [frame $frame.sep -bd 5 -relief raised \ 149 -highlightthickness 0 -bg $bg] 150 set but [frame $frame.but -bd 1 -relief raised \ 151 -highlightthickness 0 -bg $bg -width $wbut -height $wbut] 152 set sepsize 2 153 154 set activator [Widget::getoption $path -activator] 155 if {$activator == "button"} { 156 set activator $but 157 set placeButton 1 158 } else { 159 set activator $sep 160 $sep configure -bd 1 161 set placeButton 0 162 } 163 if {[string equal $side "top"] || [string equal $side "bottom"]} { 164 place $sep -relx 0.5 -y 0 -width $sepsize -relheight 1.0 -anchor n 165 if { $placeButton } { 166 if {[string equal $side "top"]} { 167 place $but -relx 0.5 -y [expr {6+$wbut/2}] -anchor c 168 } else { 169 place $but -relx 0.5 -rely 1.0 -y [expr {-6-$wbut/2}] \ 170 -anchor c 171 } 172 } 173 $activator configure -cursor sb_h_double_arrow 174 grid $frame -column [expr {2*$num-1}] -row 0 -sticky ns 175 grid columnconfigure $path [expr {2*$num-1}] -weight 0 176 } else { 177 place $sep -x 0 -rely 0.5 -height $sepsize -relwidth 1.0 -anchor w 178 if { $placeButton } { 179 if {[string equal $side "left"]} { 180 place $but -rely 0.5 -x [expr {6+$wbut/2}] -anchor c 181 } else { 182 place $but -rely 0.5 -relx 1.0 -x [expr {-6-$wbut/2}] \ 183 -anchor c 184 } 185 } 186 $activator configure -cursor sb_v_double_arrow 187 grid $frame -row [expr {2*$num-1}] -column 0 -sticky ew 188 grid rowconfigure $path [expr {2*$num-1}] -weight 0 189 } 190 bind $activator <ButtonPress-1> \ 191 [list PanedWindow::_beg_move_sash $path $num %X %Y] 192 } else { 193 if { [string equal $side "top"] || \ 194 [string equal $side "bottom"] } { 195 grid rowconfigure $path 0 -weight 1 196 } else { 197 grid columnconfigure $path 0 -weight 1 198 } 199 } 200 201 set pane [frame $path.f$num -bd 0 -relief flat \ 202 -highlightthickness 0 -bg $bg] 203 set user [frame $path.f$num.frame -bd 0 -relief flat \ 204 -highlightthickness 0 -bg $bg] 205 if { [string equal $side "top"] || [string equal $side "bottom"] } { 206 grid $pane -column [expr {2*$num}] -row 0 -sticky nsew 207 grid columnconfigure $path [expr {2*$num}] -weight $weight 208 } else { 209 grid $pane -row [expr {2*$num}] -column 0 -sticky nsew 210 grid rowconfigure $path [expr {2*$num}] -weight $weight 211 } 212 pack $user -fill both -expand yes 213 incr _panedw($path,nbpanes) 214 if {$_panedw($path,configuredone)} { 215 _realize $path [winfo width $path] [winfo height $path] 216 } 217 218 return $user 219} 220 221 222# ---------------------------------------------------------------------------- 223# Command PanedWindow::getframe 224# ---------------------------------------------------------------------------- 225proc PanedWindow::getframe { path index } { 226 if { [winfo exists $path.f$index.frame] } { 227 return $path.f$index.frame 228 } 229} 230 231 232# ---------------------------------------------------------------------------- 233# Command PanedWindow::_beg_move_sash 234# ---------------------------------------------------------------------------- 235proc PanedWindow::_beg_move_sash { path num x y } { 236 variable _panedw 237 238 set fprev $path.f[expr {$num-1}] 239 set fnext $path.f$num 240 set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}] 241 242 $path.sash$num.but configure -relief sunken 243 set top [toplevel $path.sash -borderwidth 1 -relief raised] 244 245 set minszg [Widget::getoption $fprev -minsize] 246 set minszd [Widget::getoption $fnext -minsize] 247 set side [Widget::getoption $path -side] 248 249 if { [string equal $side "top"] || [string equal $side "bottom"] } { 250 $top configure -cursor sb_h_double_arrow 251 set h [winfo height $path] 252 set yr [winfo rooty $path.sash$num] 253 set xmin [expr {$wsash/2+[winfo rootx $fprev]+$minszg}] 254 set xmax [expr {-$wsash/2-1+[winfo rootx $fnext]+[winfo width $fnext]-$minszd}] 255 wm overrideredirect $top 1 256 wm geom $top "2x${h}+$x+$yr" 257 258 update idletasks 259 grab set $top 260 bind $top <ButtonRelease-1> [list PanedWindow::_end_move_sash $path $top $num $xmin $xmax %X rootx width] 261 bind $top <Motion> [list PanedWindow::_move_sash $top $xmin $xmax %X +%%d+$yr] 262 _move_sash $top $xmin $xmax $x "+%d+$yr" 263 } else { 264 $top configure -cursor sb_v_double_arrow 265 set w [winfo width $path] 266 set xr [winfo rootx $path.sash$num] 267 set ymin [expr {$wsash/2+[winfo rooty $fprev]+$minszg}] 268 set ymax [expr {-$wsash/2-1+[winfo rooty $fnext]+[winfo height $fnext]-$minszd}] 269 wm overrideredirect $top 1 270 wm geom $top "${w}x2+$xr+$y" 271 272 update idletasks 273 grab set $top 274 bind $top <ButtonRelease-1> [list PanedWindow::_end_move_sash \ 275 $path $top $num $ymin $ymax %Y rooty height] 276 bind $top <Motion> [list PanedWindow::_move_sash \ 277 $top $ymin $ymax %Y +$xr+%%d] 278 _move_sash $top $ymin $ymax $y "+$xr+%d" 279 } 280} 281 282 283# ---------------------------------------------------------------------------- 284# Command PanedWindow::_move_sash 285# ---------------------------------------------------------------------------- 286proc PanedWindow::_move_sash { top min max v form } { 287 288 if { $v < $min } { 289 set v $min 290 } elseif { $v > $max } { 291 set v $max 292 } 293 wm geom $top [format $form $v] 294} 295 296 297# ---------------------------------------------------------------------------- 298# Command PanedWindow::_end_move_sash 299# ---------------------------------------------------------------------------- 300proc PanedWindow::_end_move_sash { path top num min max v rootv size } { 301 variable _panedw 302 303 destroy $top 304 if { $v < $min } { 305 set v $min 306 } elseif { $v > $max } { 307 set v $max 308 } 309 set fprev $path.f[expr {$num-1}] 310 set fnext $path.f$num 311 312 $path.sash$num.but configure -relief raised 313 314 set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}] 315 set dv [expr {$v-[winfo $rootv $path.sash$num]-$wsash/2}] 316 set w1 [winfo $size $fprev] 317 set w2 [winfo $size $fnext] 318 319 for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} { 320 if { $i == $num-1} { 321 $fprev configure -$size [expr {[winfo $size $fprev]+$dv}] 322 } elseif { $i == $num } { 323 $fnext configure -$size [expr {[winfo $size $fnext]-$dv}] 324 } else { 325 $path.f$i configure -$size [winfo $size $path.f$i] 326 } 327 } 328} 329 330 331# ---------------------------------------------------------------------------- 332# Command PanedWindow::_realize 333# ---------------------------------------------------------------------------- 334proc PanedWindow::_realize { path width height } { 335 variable _panedw 336 337 set x 0 338 set y 0 339 set hc [winfo reqheight $path] 340 set hmax 0 341 for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} { 342 $path.f$i configure \ 343 -width [winfo reqwidth $path.f$i.frame] \ 344 -height [winfo reqheight $path.f$i.frame] 345 place $path.f$i.frame -x 0 -y 0 -relwidth 1 -relheight 1 346 } 347 348 bind $path <Configure> {} 349 350 _apply_weights $path 351 set _panedw($path,configuredone) 1 352 return 353} 354 355# ---------------------------------------------------------------------------- 356# Command PanedWindow::_apply_weights 357# ---------------------------------------------------------------------------- 358proc PanedWindow::_apply_weights { path } { 359 variable _panedw 360 361 set weights [Widget::getoption $path -weights] 362 if {[string equal $weights "extra"]} { 363 return 364 } 365 366 set side [Widget::getoption $path -side] 367 if {[string equal $side "top"] || [string equal $side "bottom"] } { 368 set size width 369 } else { 370 set size height 371 } 372 set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}] 373 set rs [winfo $size $path] 374 set s [expr {$rs - ($_panedw($path,nbpanes) - 1) * $wsash}] 375 376 set tw 0.0 377 foreach w $_panedw($path,weights) { 378 set tw [expr {$tw + $w}] 379 } 380 381 for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} { 382 set rw [lindex $_panedw($path,weights) $i] 383 set ps [expr {int($rw / $tw * $s)}] 384 $path.f$i configure -$size $ps 385 } 386 return 387} 388 389 390# ---------------------------------------------------------------------------- 391# Command PanedWindow::_destroy 392# ---------------------------------------------------------------------------- 393proc PanedWindow::_destroy { path } { 394 variable _panedw 395 396 for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} { 397 Widget::destroy $path.f$i 398 } 399 unset _panedw($path,nbpanes) 400 Widget::destroy $path 401} 402 403 404# ---------------------------------------------------------------------------- 405# Command PanedWindow::_themechanged 406# ---------------------------------------------------------------------------- 407proc PanedWindow::_themechanged { path } { 408 409 if { ![winfo exists $path] } { return } 410 BWidget::set_themedefaults 411 412 $path configure \ 413 -background $BWidget::colors(SystemWindowFrame) 414} 415