1# 2# fdisp.tcl 3# 4# Folder display, handling nesting and highlights to reflect folder state. 5# 6# Copyright (c) 1993 Xerox Corporation. 7# Use and copying of this software and preparation of derivative works based 8# upon this software are permitted. Any distribution of this software or 9# derivative works must comply with all applicable United States export 10# control laws. This software is made available AS IS, and Xerox Corporation 11# makes no warranty about the software, its performance or its conformity to 12# any specification. 13 14proc Fdisp_Init {} { 15 global fdisp mhProfile exmh flist 16 17 if {[info exists exmh(newuser)] && [info exists flist(allfolders)]} { 18 set N [llength $flist(allfolders)] 19 if {$N < 5} { 20 set fdisp(maxLines) 1 21 } elseif {$N < 15} { 22 set fdisp(maxLines) 2 23 } elseif {$N < 30} { 24 set fdisp(maxLines) 3 25 } else { 26 set fdisp(maxLines) 4 27 } 28 } 29 30 Preferences_Add "Folder Display" \ 31"These items affect the display of the labels in the folder display window. 32If you change key bindings on labels, you'll have to toggle one of the other 33options to force a redisplay because that's when the bindings are set." { 34 {fdisp(maxLines) fdispLines 4 {Max fdisp rows} 35"The maximum number of rows of folder labels in 36the folder display. If there are more folders than 37will fit in this space, the display becomes scrollable." } 38 {fdisp(toplevel) fl_toplevel OFF {Detached fdisp display} 39"The folder display area can be displayed in a separate 40toplevel window. You can use the *Fltop.position Xresource 41to control its initial placement on the screen, and the 42*Fltop.Canvas.width and *Fltop.Canvas.height to control 43its size."} 44 {fdisp(oneCol) fdisp1Col OFF {Use one column} 45"Enabling this with a detached display aligns all the 46folders in one vertical column."} 47 {fdisp(popdownStyle) fdispPopdownStyle {CHOICE polygon rectangle} {Subfolder popdown} 48"The style of the sub folder popdown menu 49used to display subfolders." } 50 {fdisp(popdownAction) fdispPopdownAction {CHOICE navbutton enter redisplay} {Popdown action} 51"This determines how the popdown display is triggered: 52navbutton - press navigation button to get the popdown. 53 54enter - move the mouse over the button to get the popdown. 55 56redisplay - do not use popdowns at all. Instead, navbutton 57causes the whole folder display to change. 58 59The navigation button is settable via a X resource fl_navbutton." } 60 {fdisp(popdownRemove) fdispPopdownRemove {CHOICE leave navbutton} {Remove popdown on...} 61"This determines what causes a popdown display to be removed: 62navbutton - press navigation button on another label. 63 64leave - leave the area of the popdown. This actually is 65implemented by triggering on <Enter> to other labels. 66 67The navigation button is settable via a X resource fl_navbutton." } 68{fdisp(tarbuttonAction) fdispTarbuttonAction {CHOICE {select+move} {select+copy} {select only}} {Action when Target button clicked...} 69"This determines what action is taken when the \"target\" 70mouse button is clicked. The target button is usually mouse 71button 3 but can be changed by setting X resource fl_tarbutton. 72 73select+move - Selects the folder at the mouse cursor as 74the target folder and moves the current message to the 75target folder. 76 77select+copy - Selects the folder at the mouse cursor as 78the target folder and copies the current message to the 79target folder. 80 81select only - Selects the folder at the mouse cursor as 82the target folder." } 83{findSettings(defaultLoc) findSettingsDefaultLoc {CHOICE FTOC Msg} 84"Default search location" 85"Determines whether, initially, a search takes place in the \"folder 86table of contents\" window (if set to \"FTOC\") or the \"message\" window 87(if set to \"Msg\")."} 88 } 89 # The remaining parameters can be overridden by hand in the user resources 90 91 Preferences_Resource fdisp(font) fl_font fixed 92 Preferences_Resource fdisp(xgap) fl_xgap 8 93 Preferences_Resource fdisp(ygap) fl_ygap 8 94 Preferences_Resource fdisp(curbutton) fl_curbutton 1 95 Preferences_Resource fdisp(navbutton) fl_navbutton 2 96 Preferences_Resource fdisp(tarbutton) fl_tarbutton 3 97 98 Preferences_Resource fdisp(c_fg) c_foreground black 99 Preferences_Resource fdisp(c_bg) c_background white 100 Preferences_Resource fdisp(c_current) c_current red 101 Preferences_Resource fdisp(c_unseen) c_unseen blue 102 Preferences_Resource fdisp(c_unseenBg) c_unseenBg $fdisp(c_bg) 103 Preferences_Resource fdisp(c_moved) c_moved yellow 104 Preferences_Resource fdisp(c_movedFg) c_movedFg $fdisp(c_fg) 105 Preferences_Resource fdisp(c_popup) c_popup wheat 106 107 trace variable fdisp(font) w FdispFixupFont 108 set fdisp(lastFont) $fdisp(font) 109 trace variable fdisp(maxLines) w FdispFixupMaxLines 110 set fdisp(lastMaxLines) $fdisp(maxLines) 111 trace variable fdisp(toplevel) w FdispFixupToplevel 112 set fdisp(lastToplevel) $fdisp(toplevel) 113 trace variable fdisp(oneCol) w FdispFixupRedisplay 114 trace variable fdisp(popdownStyle) w FdispFixupRedisplay 115} 116 117# Hooks for recreating the folder display when config changes 118proc FdispFixupMaxLines { args } { 119 global exwin fdisp 120 121 if [catch {expr {$fdisp(maxLines) * 2}}] { 122 set fdisp(maxLines) $fdisp(lastMaxLines) 123 return ;# bogus value 124 } 125 if {$fdisp(maxLines) != $fdisp(lastMaxLines)} { 126 set fdisp(width,canvas) 0 127 set fdisp(maxLines,$fdisp(canvas)) $fdisp(maxLines) 128 set fdisp(lastMaxLines) $fdisp(maxLines) 129 set h [expr {$fdisp(maxLines)*($fdisp(itemHeight) + $fdisp(ygap)) + $fdisp(ygap)}] 130 $fdisp(canvas) configure -height $h 131 } 132} 133proc FdispFixupRedisplay { args } { 134 Fdisp_Redisplay 135} 136proc FdispFixupToplevel { args } { 137 global fdisp 138 if {$fdisp(toplevel) != $fdisp(lastToplevel)} { 139 if [info exists fdisp(topWidget)] { 140 destroy $fdisp(topWidget) 141 unset fdisp(topWidget) 142 } else { 143 destroy $fdisp(frame) 144 unset fdisp(frame) 145 } 146 FdispMake 147 } 148 set fdisp(lastToplevel) $fdisp(toplevel) 149} 150 151# Make the folder display 152proc FdispMake {} { 153 global fdisp 154 if {$fdisp(toplevel)} { 155 FdispMakeToplevel 156 } else { 157 FdispMakeFrame 158 } 159} 160 161# Create folder list in a toplevel and make the canvas inside it 162proc FdispMakeToplevel { } { 163 global fdisp 164 Exwin_Toplevel .fl "Folder list" Fltop nomenu 165 wm protocol .fl WM_TAKE_FOCUS { 166 global exwin 167 focus $exwin(mtext) 168 } 169 set fdisp(topWidget) .fl 170 wm minsize $fdisp(topWidget) 100 30 171 wm protocol .fl WM_DELETE_WINDOW FdispDeleted 172 FdispMakeCanvas $fdisp(topWidget) 173 set icon [option get $fdisp(topWidget) iconposition IconPosition] 174 catch { 175 Exwin_IconPosition $fdisp(topWidget) $icon 176 } 177 set iconic [option get $fdisp(topWidget) iconic Iconic] 178 if {$iconic == {}} { 179 set iconic $exmh(iconic) 180 } 181 if {$iconic} { 182 wm iconify $fdisp(topWidget) 183 } 184} 185proc FdispDeleted {} { 186 wm iconify .fl 187 Exmh_Status "Folder display closed, not destroyed" 188} 189proc Fdisp_Checkpoint { varName } { 190 # Add Xresources lines to $varName that save window size 191 upvar $varName newstuff 192 global fdisp 193 catch { 194 set can $fdisp(topWidget).can 195 set width [winfo width $can] 196 set height [winfo height $can] 197 set bd [$can cget -borderwidth] 198 incr bd [$can cget -highlightthickness] 199 set width [expr $width - 2*$bd] 200 set height [expr $height - 2*$bd] 201 lappend newstuff "*Fltop.Canvas.height:\t$height" 202 lappend newstuff "*Fltop.Canvas.width:\t$width" 203 } 204} 205 206# Create folder list in a frame and make the canvas inside it 207proc FdispMakeFrame { } { 208 global fdisp 209 set fdisp(frame) [Widget_Frame $fdisp(parent) f1 Frame] 210 FdispMakeCanvas $fdisp(frame) 211} 212 213# Create the canvas for the folder display 214proc FdispMakeCanvas { frame } { 215 global fdisp exwin 216 set fdisp(canvas) [canvas $frame.can -bd 2 -relief raised \ 217 -highlightthickness 0] 218 set s [scrollbar $frame.sv -command [list $fdisp(canvas) yview] \ 219 -highlightthickness 0] 220 $fdisp(canvas) configure -yscrollcommand [list $s set] 221 222 # Find out how big labels are 223 if [catch { 224 set id [$fdisp(canvas) create text 0 0 \ 225 -anchor nw -justify center -text 0123456789 -font $fdisp(font)] 226 } err] { 227 Exmh_Status $err 228 set fdisp(font) fixed 229 set id [$fdisp(canvas) create text 0 0 \ 230 -anchor nw -justify center -text 0123456789 -font $fdisp(font)] 231 } 232 set size [$fdisp(canvas) bbox $id] 233 set fdisp(itemHeight) [expr {[lindex $size 3] - [lindex $size 1]}] 234 set fdisp(charWidth) [expr {([lindex $size 2] - [lindex $size 0])/10}] 235 $fdisp(canvas) delete $id 236 237 catch { 238 $fdisp(canvas) configure -yscrollincrement \ 239 [expr {$fdisp(itemHeight)+$fdisp(ygap)+1}] 240 } 241 242 if {!$fdisp(toplevel)} { 243 set h [expr {$fdisp(maxLines)*($fdisp(itemHeight) + $fdisp(ygap)) + $fdisp(ygap)}] 244 $fdisp(canvas) configure -height $h 245 } 246 247 bindtags $fdisp(canvas) \ 248 [list $fdisp(canvas) Command [winfo toplevel $fdisp(canvas)] all] 249 bind $fdisp(canvas) <2> {%W scan mark %x %y} 250 bind $fdisp(canvas) <B2-Motion> {%W scan dragto %x %y} 251 bind $fdisp(canvas) <Configure> FdispCanvasConfigure 252 pack $s -side $exwin(scrollbarSide) -fill y 253 pack $fdisp(canvas) -side $exwin(scrollbarSide) -fill both -expand 1 254 255 # Enable wheelscroll if desired 256 if {$exwin(wheelEnabled)} { 257 fmscroll $fdisp(canvas) 5 258 } 259 260 # fdisp popup color hack 261 if {[winfo depth $fdisp(canvas)] <= 4} { 262 if {! [regexp {black|white} $fdisp(c_popup)]} { 263 set fdisp(c_popup) [$fdisp(canvas) cget -bg] 264 } 265 } 266 267 FdispDragAttach canvas 268} 269proc FdispFixupFont { args } { 270 global exwin fdisp 271 if {$fdisp(lastFont) != $fdisp(font)} { 272 273 # Find out how big labels are 274 if [catch { 275 set id [$fdisp(canvas) create text 0 0 \ 276 -anchor nw -justify center -text foo -font $fdisp(font)] 277 } err] { 278 Exmh_Status $err 279 set fdisp(font) fixed 280 set id [$fdisp(canvas) create text 0 0 \ 281 -anchor nw -justify center -text foo -font $fdisp(font)] 282 } 283 set size [$fdisp(canvas) bbox $id] 284 set fdisp(itemHeight) [expr {[lindex $size 3] - [lindex $size 1]}] 285 $fdisp(canvas) delete $id 286 set fdisp(lastFont) $fdisp(font) 287 288 # Changing canvas size triggers redisplay 289 set h [expr {$fdisp(maxLines)*($fdisp(itemHeight) + $fdisp(ygap)) + $fdisp(ygap)}] 290 $fdisp(canvas) configure -height $h 291 if [info exists fdisp(cache)] { 292 set h [expr {($fdisp(itemHeight) + $fdisp(ygap)) + $fdisp(ygap)}] 293 $fdisp(cache) configure -height $h 294 } 295 } 296} 297 298proc Fdisp_Window { parent } { 299 global fdisp exwin 300 301 set fdisp(parent) $parent 302 303 # a bogus child is needed inside fdisp(parent) so it properly 304 # shrinks down when the cache is removed or when the main display 305 # is moved to a separate top-level 306 Widget_Frame $parent bogus Frame 307 308 # The following creates fdisp(canvas), either in a toplevel or a frame 309 FdispMake 310 311 global fcache 312 if $fcache(enabled) { 313 Fcache_CreateWindow 314 FdispDragAttach cache 315 } 316 317 set fdisp(folder) . 318 foreach can {canvas cache} { 319 set fdisp(entered,$can) 0 ;# Display routine entered 320 set fdisp(pending,$can) 0 ;# Display routine blocked 321 set fdisp(width,$can) 0 ;# last display width 322 set fdisp(fset,$can) {} ;# last folder set 323 set fdisp(cur,$can) {} ;# current folder name 324 set fdisp(tar,$can) {} ;# target folder name 325 set fdisp(curid,$can) {} ;# canvas item ids 326 set fdisp(boxid,$can) {} 327 set fdisp(tarid,$can) {} 328 set fdisp(tboxid,$can) {} 329 set fdisp(leafs,$can) {} ;# list of leaf highlight tags 330 } 331 332} 333proc Fdisp_Redisplay {} { 334 global fdisp 335 FdispMain $fdisp(folder) 1 336 Fcache_Display 1 337} 338 339proc FdispCanvasConfigure {} { 340 global fdisp 341 FdispMain $fdisp(folder) 1 342} 343 344proc FdispMain { {folder {.}} {force 0} } { 345 # Layout the current level of folder buttons on the canvas 346 global fdisp exmh 347 Label_Main [expr {[string compare $folder "."]==0 ? {} : "$folder"}] 348 set fdisp(folder) $folder 349 Flist_FindAllFolders 350 set folderSet [Flist_FolderSet $folder] 351 set len [llength $folderSet] 352 set msec [lindex [time [list Fdisp_Layout canvas $folderSet $folder $force]] 0] 353 Exmh_Debug Fdisp_HighlightCanvas [time [list Fdisp_HighlightCanvas canvas]] 354} 355 356proc Fdisp_Layout { can folderSet {folder {}} {force 0} } { 357 # Main layout routine. Because this is triggered by 358 # <Configure> events, and because it dinks with the 359 # size of the canvas, it needs to be reentrant. 360 # 361 global fdisp 362 363 set canvas $fdisp($can) 364 365 if {$fdisp(entered,$can)} { 366 set fdisp(pending,$can) 1 367 return 368 } 369 set width [winfo width $canvas] 370 set bd [$canvas cget -borderwidth] 371 incr bd [$canvas cget -highlightthickness] 372 set width [expr $width - 2*$bd] 373 374 if {! $force && 375 ($width == $fdisp(width,$can)) && 376 ($folderSet == $fdisp(fset,$can))} { 377 if {$fdisp(pending,$can)} { 378 set fdisp(pending,$can) 0 379 after 1 [list Fdisp_Layout $can $folderSet $folder] 380 } 381 return 382 } 383 incr fdisp(entered,$can) 384 385 set fdisp(width,$can) $width 386 set fdisp(fset,$can) $folderSet 387 388 catch { $canvas delete all } 389 Fdisp_ClearSpecials $canvas 390 391 if {$can != "cache"} { 392 FdispPopdownReset 393 Exmh_Status "Building folder display... $folder" 394 } 395 set fdisp(maxy,$can) [FdispLayoutInner $can $fdisp(xgap) $fdisp(ygap) \ 396 $width $folderSet $folder FdispBindLabel] 397 398 set fdisp(bgid,$can) [$canvas create rect 0 0 0 0 \ 399 -fill [$canvas cget -bg] -outline ""] 400 $canvas lower $fdisp(bgid,$can) 401 FdispSetCanvasSize $can $fdisp(maxy,$can) 402 if {$can != "cache"} { 403 Exmh_Status "" 404 } 405 incr fdisp(entered,$can) -1 406 if {$fdisp(pending,$can)} { 407 set fdisp(pending,$can) 0 408 after 1 [list Fdisp_Layout $can $folderSet $folder] 409 } 410} 411proc FdispLayoutInner { can x1 y1 width folderSet folder bindProc {skipSelf no} {tag _notag_} } { 412 global fdisp 413 set canvas $fdisp($can) 414 set maxy $fdisp(itemHeight) ;# Per row max item height 415 set x $x1 416 set y $y1 417 set iscache [string match cache $can] 418 foreach f $folderSet { 419 # Determine label text for the folder 420 if {[string compare $f $folder] == 0} { 421 if [string match skipSelf $skipSelf] { 422 continue 423 } else { 424 set text ".." 425 } 426 } else { 427 if $iscache { 428 set text [Fcache_FolderName $f] 429 } else { 430 set text [file tail $f] 431 } 432 } 433 # Create the text (or bitmap) at location 0 0 434 set id [Fdisp_Label $canvas $f $text] 435 set bbox [$canvas bbox $id] 436 set twidth [expr [lindex $bbox 2]-[lindex $bbox 0]] 437 set theight [expr [lindex $bbox 3]-[lindex $bbox 1]] 438 if {($twidth + $fdisp(xgap)/2 + $x > $width) || 439 (($fdisp(oneCol) && !$iscache) && ($y > $y1 || $x > $x1))} { 440 incr y [expr {$fdisp(ygap) + $maxy}] 441 set x $x1 442 set maxy $fdisp(itemHeight) ;# Per row max item height 443 } 444 if {$theight > $maxy} { 445 set maxy $theight 446 } 447 # Move it into position after we see how big it is. 448 $canvas move $id $x $y 449 incr x [expr {$fdisp(xgap) + $twidth}] 450 451 # Determine style of the box, depending on nesting 452 if {[string compare $f $folder] == 0} { 453 set ftype goParent 454 } else { 455 if [Flist_SubFolders $f] { 456 if $iscache { 457 # This supresses the drop-shadow in the cache display, 458 # but also turns off the redisplay mode behavior... 459 set ftype leaf 460 } else { 461 set ftype hasNested 462 } 463 } else { 464 set ftype leaf 465 } 466 } 467 set box [Fdisp_Box $fdisp($can) $id $ftype $tag] 468 FdispUpdateMap $can $f $id 469 FdispUpdateBmap $can $f $box 470 $bindProc $can $id $ftype $f 471 if {$fdisp(popdownAction) != "enter"} { 472 $bindProc $can $box $ftype $f 473 } 474 } 475 return [expr $y + $maxy] 476} 477proc Fdisp_Label { canvas f text } { 478 global fdisp folderInfo fdispSpecial 479 if [info exists folderInfo(bitmap,$f)] { 480 set special 0 481 if [info exists folderInfo(fg,$f)] { 482 set fg $folderInfo(fg,$f) 483 set special 1 484 } else { 485 set fg black 486 } 487 if [info exists folderInfo(bg,$f)] { 488 set bg $folderInfo(bg,$f) 489 set special 1 490 } else { 491 set bg white 492 } 493 set id [$canvas create bitmap 0 0 -anchor nw \ 494 -bitmap $folderInfo(bitmap,$f) \ 495 -foreground $fg -background $bg] 496 if {! $special} { 497 $canvas addtag bitmap withtag $id 498 } else { 499 lappend fdispSpecial($canvas) $id 500 set fdispSpecial($canvas,$id) [list $fg $bg] 501 } 502 } else { 503 set id [$canvas create text 0 0 -anchor nw \ 504 -justify center -text $text -font $fdisp(font) -tag text] 505 } 506 return $id 507} 508proc Fdisp_FixupSpecials { canvas } { 509 global fdispSpecial 510 if ![info exists fdispSpecial($canvas)] { 511 return 512 } 513 foreach id $fdispSpecial($canvas) { 514 if [info exists fdispSpecial($canvas,$id)] { 515 set fg [lindex $fdispSpecial($canvas,$id) 0] 516 set bg [lindex $fdispSpecial($canvas,$id) 1] 517 $canvas itemconfigure $id -background $bg -foreground $fg 518 } 519 } 520} 521proc Fdisp_ClearSpecials { canvas } { 522 global fdispSpecial 523 if ![info exists fdispSpecial($canvas)] { 524 return 525 } 526 foreach id $fdispSpecial($canvas) { 527 unset fdispSpecial($canvas,$id) 528 } 529 unset fdispSpecial($canvas) 530} 531proc Fdisp_Box { canvas tid ftype {tag {}} } { 532 # outline box. I note that for variable width fonts, 533 # the bbox is too long. Oh well. 534 global fdisp 535 536 if {$tag != {}} { 537 $canvas addtag $tag withtag $tid 538 } 539 540 set bbox [$canvas bbox $tid] 541 set x1 [expr {[lindex $bbox 0] - 1}] 542 set x2 [expr {[lindex $bbox 2] + 1}] 543 set y1 [expr {[lindex $bbox 1] - 1}] 544 set y2 [expr {[lindex $bbox 3] + 1}] 545 546 set box [$canvas create rect $x1 $y1 $x2 $y2 -fill $fdisp(c_bg) \ 547 -tags [list box $tag]] 548 549 # Need one box for a dropshadow, and then one extra box to ensure 550 # a stippled foreground obscures the dropshadow box 551 if {[string compare $ftype goParent] == 0} { 552 $canvas lower [$canvas create rect $x1 $y1 $x2 $y2 \ 553 -fill $fdisp(c_bg) -tags $tag] 554 $canvas lower [$canvas create rect \ 555 [expr $x1+3] [expr $y1+3] [expr $x2+3] [expr $y2+3] \ 556 -fill $fdisp(c_bg) -tags $tag] 557 } else { 558 if {[string compare $ftype hasNested] == 0} { 559 $canvas lower [$canvas create rect $x1 $y1 $x2 $y2 \ 560 -fill $fdisp(c_bg) -tags $tag] 561 $canvas lower [$canvas create rect \ 562 [expr $x1+3] [expr $y1+3] [expr $x2+3] [expr $y2+3] \ 563 -fill $fdisp(c_fg) -tags $tag] 564 } 565 } 566 $canvas raise $tid ;# display text over top the box 567 return $box 568} 569proc FdispBindLabel { can id ftype f } { 570 global fdisp 571 set canvas $fdisp($can) 572 573 $canvas bind $id <$fdisp(curbutton)> [list Folder_Change $f] 574 if {$fdisp(tarbuttonAction) == "select+move"} { 575 $canvas bind $id <$fdisp(tarbutton)> \ 576 [list Folder_TargetMove $f] 577 } elseif {$fdisp(tarbuttonAction) == "select+copy"} { 578 $canvas bind $id <$fdisp(tarbutton)> \ 579 [list Folder_TargetCopy $f] 580 } elseif {$fdisp(tarbuttonAction) == "select only"} { 581 $canvas bind $id <$fdisp(tarbutton)> \ 582 [list Folder_Target $f] 583 } else { 584 $canvas bind $id <$fdisp(tarbutton)> \ 585 [list Folder_TargetMove $f] 586 } 587 $canvas bind $id <Shift-$fdisp(tarbutton)> \ 588 [list Folder_TargetCopy $f] 589 $canvas bind $id <Control-$fdisp(tarbutton)> \ 590 [list Folder_TargetClear] 591 592 593 if {[string compare $ftype goParent] == 0} { 594 $canvas bind $id <$fdisp(navbutton)> \ 595 [list FdispMain [file dirname $f]] 596 } else { 597 if {[string compare $ftype hasNested] == 0} { 598 if {$can != "cache"} { 599 case $fdisp(popdownAction) { 600 redisplay { 601 $canvas bind $id <$fdisp(navbutton)> \ 602 [list FdispMain $f] 603 } 604 enter { 605 $canvas bind $id <Any-Enter> \ 606 [list FdispDisplayPopdown $f down %x %y] 607 } 608 navbutton { 609 $canvas bind $id <$fdisp(navbutton)> \ 610 [list FdispDisplayPopdown $f down %x %y] 611 } 612 } 613 } else { 614 if {$fdisp(popdownAction) == "redisplay"} { 615 $canvas bind $id <$fdisp(navbutton)> \ 616 [list FdispMain $f] 617 } 618 } 619 } else { 620 # Leaf 621 if {$fdisp(popdownAction) == "redisplay"} { 622 $canvas bind $id <$fdisp(navbutton)> {} 623 } else { 624 if {$fdisp(popdownRemove) == "navbutton"} { 625 $canvas bind $id <$fdisp(navbutton)> FdispPopdownRemove 626 } else { 627 # Use enter on another leaf label to simulate Leave 628 # of the popdown. Cannot bind to <Leave> on the popdown 629 # background because that triggers when you enter one 630 # of its own labels. 631 $canvas bind $id <Enter> FdispPopdownRemove 632 } 633 } 634 } 635 } 636} 637proc FdispSetCanvasSize { can maxy {noshrink 0}} { 638 global fdisp 639 640 set canvas $fdisp($can) 641 set w $fdisp(width,$can) 642 643 set height [winfo height $canvas] 644 set bd [$canvas cget -borderwidth] 645 incr bd [$canvas cget -highlightthickness] 646 set height [expr $height - 2*$bd] 647 648 set h [expr $maxy + $fdisp(ygap) + $fdisp(ygap)] 649 if {$height > $h} {set h $height} 650 651 #puts "SetSize $maxy->$h [lindex [$canvas cget -scrollregion] 3]" 652 653 if {$noshrink && [lindex [$canvas cget -scrollregion] 3] > $h} { 654 return 655 } 656 657 $canvas configure -scrollregion [list 0 0 $w $h] 658 # adjust background to cover new scrollregion 659 $canvas coords $fdisp(bgid,$can) 0 0 $w $h 660} 661 662proc FdispUpdateMap { can folder id } { 663 global fdisp 664 $fdisp($can) addtag Ftext=$folder withtag $id 665} 666proc FdispUpdateBmap { can folder box } { 667 global fdisp 668 $fdisp($can) addtag Fbox=$folder withtag $box 669} 670proc FdispGetMap { can folder } { 671 global fdisp 672 return [$fdisp($can) find withtag Ftext=$folder] 673} 674proc FdispGetBmap { can folder } { 675 global fdisp 676 return [$fdisp($can) find withtag Fbox=$folder] 677} 678# Routines to Highlight the folder display 679 680proc Fdisp_ResetHighlights {} { 681 global fdisp 682 Fdisp_ClearHighlights 683 Fdisp_HighlightCanvas canvas 684 if [info exists fdisp(cache)] { 685 Fdisp_HighlightCanvas cache 686 } 687} 688proc Fdisp_ClearHighlights {} { 689 global fdisp 690 FdispClearHighlights canvas 691 if [info exists fdisp(cache)] { 692 FdispClearHighlights cache 693 } 694} 695 696proc Fdisp_HighlightCanvas { can } { 697 global fdisp flist 698 if ![info exist fdisp($can)] { 699 return 700 } 701 if {$fdisp(cur,$can) != {}} { 702 FdispHighlightCur $can $fdisp(cur,$can) 703 } 704 if {$fdisp(tar,$can) != {}} { 705 FdispHighlightTarget $can $fdisp(tar,$can) 706 } 707 foreach f [Flist_UnseenFolders] { 708 FdispHighlightUnseen $can $f 709 } 710 Fdisp_LabelConfigure $fdisp($can) 711} 712 713proc FdispWhichLabel { can f } { 714 # Figure out what label to highlight, handling nesting 715 global fdisp mhProfile 716 717 if {"$can" == "cache" || [FdispNotDotDot $can $f]} { 718 return $f 719 } 720 while {[string compare $f "."] && [string compare $f "/"]} { 721 set nf [file dirname $f] 722 if {[string compare $nf $f] == 0} { 723 break 724 } 725 set f $nf 726 if [FdispNotDotDot $can $f] { 727 return $f 728 } 729 } 730 return {} 731} 732proc FdispAllLabels { can f } { 733 # Figure out what labels to highlight, returning 734 # multiple labels if they are present because of popdowns. 735 global fdisp mhProfile 736 737 set res {} 738 if [FdispNotDotDot $can $f] { 739 lappend res $f 740 } 741 while {[string compare $f "."] && [string compare $f "/"]} { 742 set nf [file dirname $f] 743 if {[string compare $nf $f] == 0} { 744 break 745 } 746 set f $nf 747 if [FdispNotDotDot $can $f] { 748 lappend res $f 749 } 750 } 751 return $res 752} 753# See if the folder label displayed for $f is ".." (and is displayed at all) 754proc FdispNotDotDot { can f } { 755 global fdisp 756 set map [FdispGetMap $can $f] 757 if {$map != {}} { 758 if [catch {$fdisp($can) itemcget $map -text} l] { 759 if [string compare $f ".."] { 760 return 1 761 } 762 } else { 763 if [string compare $l ".."] { 764 return 1 765 } 766 } 767 } 768 return 0 769} 770proc Fdisp_HighlightCur { f } { 771 global fdisp 772 773 Fcache_Folder $f 774 foreach can {canvas cache} { 775 if [info exists fdisp($can)] { 776 FdispHighlightCur $can $f 777 Fdisp_LabelConfigure $fdisp($can) 778 } 779 } 780} 781proc FdispHighlightCur { can f } { 782 global fdisp 783 set l [FdispWhichLabel $can $f] 784 set canvas $fdisp($can) 785 if {$fdisp(curid,$can) != {}} { 786 $canvas dtag $fdisp(curid,$can) cur[$canvas type $fdisp(curid,$can)] 787 $canvas dtag $fdisp(boxid,$can) curbox 788 } 789 790 set fdisp(cur,$can) $f 791 if {[string compare $l {}]} { 792 set id [FdispGetMap $can $l] 793 set box [FdispGetBmap $can $l] 794 $canvas addtag cur[$canvas type $id] withtag $id 795 $canvas addtag curbox withtag $box 796 set fdisp(curid,$can) $id 797 set fdisp(boxid,$can) $box 798 } 799} 800proc Fdisp_HighlightTarget { f } { 801 global fdisp fcache 802 803 if $fcache(cacheTarget) { 804 Fcache_Folder $f 805 } 806 foreach can {canvas cache} { 807 if [info exists fdisp($can)] { 808 FdispHighlightTarget $can $f 809 Fdisp_LabelConfigure $fdisp($can) 810 } 811 } 812} 813proc FdispHighlightTarget { can f } { 814 global fdisp 815 set l [FdispWhichLabel $can $f] 816 set canvas $fdisp($can) 817 if {$fdisp(tarid,$can) != {}} { 818 $canvas dtag $fdisp(tarid,$can) tar[$canvas type $fdisp(tarid,$can)] 819 $canvas dtag $fdisp(tboxid,$can) tarbox 820 } 821 822 set fdisp(tar,$can) $f 823 if {[string compare $l {}]} { 824 set id [FdispGetMap $can $l] 825 set box [FdispGetBmap $can $l] 826 $canvas addtag tar[$canvas type $id] withtag $id 827 $canvas addtag tarbox withtag $box 828 set fdisp(tarid,$can) $id 829 set fdisp(tboxid,$can) $box 830 } 831} 832 833proc Fdisp_HighlightUnseen { f } { 834 global fdisp fcache 835 836 if $fcache(cacheUnseen) { 837 Fcache_Folder $f 838 } 839 foreach can {canvas cache} { 840 if [info exists fdisp($can)] { 841 FdispHighlightUnseen $can $f 842 Fdisp_LabelConfigure $fdisp($can) 843 } 844 } 845} 846proc FdispHighlightUnseen { can f } { 847 global exmh fdisp 848 if {$can != "cache"} { 849 set ll [FdispAllLabels $can $f] 850 } else { 851 set ll [list $f] 852 } 853 set canvas $fdisp($can) 854 foreach l $ll { 855 set id [FdispGetMap $can $l] 856 set box [FdispGetBmap $can $l] 857 $canvas addtag leaf=$f withtag $id 858 if {[lsearch $fdisp(leafs,$can) leaf=$f] < 0} { 859 # needed when resetting highlights 860 lappend fdisp(leafs,$can) leaf=$f 861 } 862 $canvas addtag unsn[$canvas type $id] withtag $id 863 $canvas addtag unsnbox withtag $box 864 } 865} 866proc Fdisp_UnHighlightUnseen { f } { 867 global fdisp 868 foreach can {canvas cache} { 869 if [info exists fdisp($can)] { 870 FdispUnHighlightUnseen $fdisp($can) $can $f 871 Fdisp_LabelConfigure $fdisp($can) 872 } 873 } 874} 875proc FdispUnHighlightUnseen { canvas can f } { 876 global exmh fdisp 877 set ll [FdispAllLabels $can $f] 878 set canvas $fdisp($can) 879 foreach l $ll { 880 set id [FdispGetMap $can $l] 881 set box [FdispGetBmap $can $l] 882 set stillLight 0 883 foreach tag [$canvas gettags $id] { 884 if [string match leaf=* $tag] { 885 set leaf [lindex [split $tag =] 1] 886 if {[string compare $leaf $f] == 0} { 887 $canvas dtag $id $tag 888 } else { 889 set stillLight 1 890 } 891 } 892 } 893 if {! $stillLight} { 894 $canvas dtag $id unsn[$canvas type $id] 895 $canvas dtag $box unsnbox 896 } 897 } 898} 899proc Fdisp_Lines { canvas labels } { 900 # Return the number of lines needed to display the set of labels 901 global fdisp 902 set x $fdisp(xgap) 903 set lines 1 904 set width [winfo width $canvas] 905 set bd [$canvas cget -borderwidth] 906 incr bd [$canvas cget -highlightthickness] 907 set width [expr $width - 2*$bd] 908 foreach folder $labels { 909 set f [Fcache_FolderName $folder] 910 set id [Fdisp_Label $canvas $f $f] 911 set bbox [$canvas bbox $id] 912 set twidth [expr [lindex $bbox 2]-[lindex $bbox 0]] 913 if {$twidth + $fdisp(xgap)/2 + $x > $width} { 914 incr lines 915 set x $fdisp(xgap) 916 } 917 incr x [expr {$fdisp(xgap) + $twidth}] 918 $canvas delete $id 919 } 920 return $lines 921} 922 923# 924# Interface to Drag & Drop 925# 926set fdispDrag(callback) FdispDragRelease 927set fdispDrag(types) {folder filename} 928set fdispDrag(formats) string 929set fdispDrag(format,folder) string 930set fdispDrag(format,filename) string 931set fdispDrag(type,string) folder 932set fdispDrag(decorate) FdispDragWindow 933 934proc FdispDragAttach {where} { 935 global fdisp 936 937 Drag_Attach $fdisp($where) FdispDragSelect Shift $fdisp(navbutton) 938 if [string match cache $where] { 939 Drop_Attach $fdisp(cache) FdispDropCache 940 } else { 941 Drop_Attach $fdisp(canvas) FdispDropCanvas 942 } 943} 944 945# A drag was dropped on the cache 946proc FdispDropCache {w args} { 947 global dragging 948 949 if ![info exists dragging(data,folder)] return 950 set folder $dragging(data,folder) 951 952 # Add the folder to the cache 953 Fcache_Folder $folder 954} 955 956# A drag was dropped on the canvas 957proc FdispDropCanvas {w args} { 958 global fdisp dragging 959 960 if ![info exists dragging(data,folder)] return 961 set folder $dragging(data,folder) 962 963 # If dropped on the folder display and source was cache, 964 # remove the folder from the cache 965 if {[info exists fdisp(cache)] && 966 $dragging(source) == $fdisp(cache)} { 967 Fcache_FolderDiscard $folder 968 } 969} 970 971# Called when after a drag we sourced has been dropped 972proc FdispDragRelease {dstw args} { 973 974 global fdisp dragging 975 set folder $dragging(data,folder) 976 977tlog-add .t "released on $dstw" 978 979 # If we tossed it somewhere unknown, Add the folder to the cache 980 if {$dragging(source) == $fdisp(canvas) && $dstw != $fdisp(canvas) && 981 "$dstw" != {}} { 982 Fcache_Folder $folder 983 } 984} 985 986# Drag Selected 987proc FdispDragSelect {c x y wx wy} { 988 global fdisp 989 990 set closest [$c find closest [$c canvasy $wx] [$c canvasy $wy]] 991 992 # Find what folder we're over 993 set tags [$c gettags $closest] 994 set which [lsearch -glob $tags F*=*] 995 if {$which >= 0} { 996 set tag [lindex $tags $which] 997 regsub -- .*=(.*) $tag {\1} folder 998 } 999 if ![info exists folder] return 1000 1001 # Hand off to Drag code 1002 global fdispDrag mhProfile 1003 set fdispDrag(source) $c 1004 set fdispDrag(data,folder) $folder 1005 set fdispDrag(data,filename) $mhProfile(path)/$folder 1006 1007 Drag_Source fdispDrag $x $y 1008 1009} 1010 1011# How do decorate the Drag window 1012proc FdispDragWindow {w} { 1013 global fdisp dragging 1014 1015 set c $w.fdisp 1016 if ![winfo exists $c] { 1017 set height [expr $fdisp(itemHeight) + $fdisp(ygap)] 1018 canvas $c -height $height 1019 } 1020 1021 pack $c 1022 catch {$c delete all} 1023 1024 set f $dragging(data,folder) 1025 1026 set id [Fdisp_Label $c $f $f] 1027 set bbox [$c bbox $id] 1028 set twidth [expr [lindex $bbox 2]-[lindex $bbox 0]] 1029 set theight [expr [lindex $bbox 3]-[lindex $bbox 1]] 1030 $c move $id [expr $fdisp(xgap)/2 + 1] [expr $fdisp(ygap)/2] 1031 set width [expr $twidth + $fdisp(xgap)] 1032 $c config -width $width 1033 set bid [Fdisp_Box $c $id leaf {}] 1034} 1035