Kevin Walzer I was trying to create a variation of the standard Tk file browser handled with a listbox, which would emulate the NeXT (now Mac OS X) style of file browsing: navigating horizontally across a file system. I hit a wall and asked for help on comp.lang.tcl.
[Kaitzschu
] came to the rescue and did more than add some guidance to my rough initial code; he radically transformed it. Thanks to Kaitzchu for the help.
The result is below, licensed under the standard Tcl BSD-style license. Embellishments and improvements are more than welcome!
package require Tcl 8.5
package require Tk
namespace eval ::nextlist {namespace export nextlist}
proc ::nextlist::nextlist {wid dir} {
if {![file isdirectory $dir]} {error "non-directory $dir"}
nlist [frame $wid] $dir 0
return $wid
}
proc ::nextlist::nlist {base dir cnt} {
if {![file isdirectory $dir]} {return}; # here file-clicketyclicks
# check for [file readable]? nah
# dear santa, let children be in order
destroy {*}[lrange [winfo children $base] [expr {2*$cnt}] end]
# exportselection 0 looks good, but selection gets easily out-of-sync
set l [listbox "[set b "$base.nl$cnt"]-list" -yscrollcommand [list "$b-scroll" set] -height 20 -exportselection 0]
pack $l [scrollbar "$b-scroll" -command [list $l yview]] -side left -expand 1 -fill y -anchor w
# I like my directories first and everything dictionarized, love {*}
# could be done with intermediate list and $l insert end {*}$lst
foreach item [concat [lsort -dictionary [glob -directory $dir -nocomplain -types {d} -- *]] \
[lsort -dictionary [glob -directory $dir -nocomplain -types {f} -- *]]] \
{$l insert end "[file tail $item][expr {[file isdirectory $item] ? {/} : {}}]"}
bind $l <Double-1> [list ::nextlist::navigare $dir [incr cnt] %W %x %y]
}
proc ::nextlist::navigare {d c w x y} {
if {[set subdir [$w get [$w index "@$x,$y"]]] eq {}} {return}
nlist [winfo parent $w] [file join $d $subdir] $c
}
# To test this code, try the following command:
pack [::nextlist::nextlist .nl ~/Desktop]
You will see listboxes added and deleted horizontally as you navigate through the file hierarchy.
With all due respect to the author's love of
{*}, the second use of it is rather pointless:
[list {*}[lsort ...] {*}[lsort ...]]
is equivalent to, but not as clear as
[concat [lsort ...] [lsort ...]]
[Kaitzschu
] Guilty as charged. Use
concat, it is also very, very fast once lists get bigger. I wasn't familiar with this command, because its manual page is confounding wrt use with lists (trimming and spaces, sounds too much like strings).
jcw - And by writing "eval destroy [...]", the same code runs in 8.x ...
NEM - Removed a rogue "09" in the code that caused a dreaded octal error. Not sure where the stray 9 came from.
RKzn 20161027 - changed
if {![file isdirectory $dir]} {return; # here file-clicketyclicks}
to
if {![file isdirectory $dir]} {return}; # here file-clicketyclicks
because the first one breaks auto-indentation, with emacs' tcl-mode; and I agree with it that the second version it is clearer.
Also changed the "[list {*}[lsort ..." to "[concat [lsort ..." as suggested above and it works just fine (8.6.3)