#!../tree_wish -f
# -*-Tcl-*-
#
# dirtree11 - same as dirtree10, but adds bindings for mouse button <2>
#             to open a listbox displaying the files in the selected directory


source dirtree10


# add a binding to tree node labels to open/close a listbox listing files in 
# the selected directory
$canvas bind text <2> "focus %W; SelectNode $canvas; ShowFiles $canvas $tree"


# Display the file names in the selected directory in
# a scrolling list beneath the node

proc ShowFiles {canvas tree} {
    set dir [GetPath $canvas]
    set frame [UniqueName $canvas $dir]
    
    # create the frame and list if not already there
    if {![llength [$canvas find withtag $dir:list]]} {
        MakeListFrame $canvas $tree $frame $dir
    } else {
        RemoveListFrame $canvas $tree $frame $dir
    }
}


# generates a unique name for a widget from the given
# directory name by replacing the '.'s with '_'s

proc UniqueName {canvas dir} {
    global dirtree
    if {![catch {set path $dirtree($canvas.$dir)}]} {
	return $path
    }
    if {[catch {incr dirtree(listboxcnt)}]} {
	set dirtree(listboxcnt) 0
    } 
    set dirtree($canvas.$dir) $canvas.list$dirtree(listboxcnt)
    return $dirtree($canvas.$dir)
}


# make the list frame for displaying the files in dir

proc MakeListFrame {canvas tree frame dir} {
    global dirtree 
    set bg [$canvas cget -bg]
    
    # make the list frame and set up resizing 
    frame $frame -borderwidth 3 -cursor bottom_right_corner
    scrollbar $frame.scroll -relief sunken -command "$frame.list yview" -width 10
    listbox $frame.list -yscrollcommand "$frame.scroll set" -relief sunken	\
	-bg $bg -selectmode single
    pack $frame.scroll -side right -fill y 
    pack $frame.list -side left -expand yes -fill both
    
    # fill the list with the files in the selected dir
    # (with the uninteresting files filtered out)
    set n 0
    foreach i [exec ls $dir] {
	if {[file isfile $dir/$i]} {
	    incr n
	    $frame.list insert end $i
	}
    }
    
    # insert the list frame in the canvas
    $canvas create window 0 0 -tags "$dir $dir:list list" \
	-window $frame -width 3c -height 2c

    # arrange the items in the tree node and change the bitmap
    # to show an "open" directory
    LayoutNode $canvas $tree $dir
    $canvas itemconfig $dir:bitmap -bitmap "@bitmaps/open_dir.xbm"
    $tree nodeconfig $dir -remove "destroy $frame" 

    # add bindings for resizing the listbox in the canvas
    SetFileListBindings $canvas $tree $frame $frame.list $frame.scroll $dir
}


# remove the list frame for displaying the files in dir

proc RemoveListFrame {canvas tree frame dir} {
    global dirtree 
    $canvas delete $dir:list
    destroy $frame

    $canvas itemconfig $dir:bitmap -bitmap @bitmaps/dir.xbm
    $tree nodeconfig $dir -remove "" -border 2
    set dirtree(list) ""
    set dirtree(dir) ""
}


# event proc called to resize the file listbox in the canvas 
# while the user is dragging its corner

proc ResizeList {canvas tree frame list x y dir {when any}} {
    global dirtree
    
    case "$when" {
	"first" {
	    set dirtree(tlx) $x
	    set dirtree(tly) $y
	} 
	"last" {
	    $tree nodeconfig $dir
	}
	default {
	    set w [$canvas itemcget $dir:list -width]
	    set h [$canvas itemcget $dir:list -height]
	    set nw [expr $w+($x-$dirtree(tlx))]
	    set nh [expr $h+($y-$dirtree(tly))]
	    $canvas itemconfig $dir:list -width $nw -height $nh
	    set dirtree(tlx) $x
	    set dirtree(tly) $y
	}
    }
}


# set the bindings for a file listbox in the tree canvas

proc SetFileListBindings {canvas tree frame list scroll dir} {
    global dirtree
    bind $frame <ButtonPress-1> "ResizeList $canvas $tree $frame $list %x %y $dir first"
    bind $frame <Button1-Motion> "ResizeList $canvas $tree $frame $list %x %y $dir"
    bind $frame <ButtonRelease-1> "ResizeList $canvas $tree $frame $list %x %y $dir last"
    
    bind $list <1>  "set dirtree(list) %W; set dirtree(dir) $dir; [bind Listbox <1>]"
    bind $list <Double-Button-1> ChooseFile
    
    # set/clear the resize cursor
    bind $list <Any-Enter> "$frame config -cursor {}"
    bind $list <Any-Leave> "$frame config -cursor bottom_right_corner"
    bind $scroll <Any-Enter> "$frame config -cursor {}"
    bind $scroll <Any-Leave> "$frame config -cursor bottom_right_corner"
}



# This proc is called when the user double-clicks on a filename 
# in one of the listboxes listing the files in a directory.

proc ChooseFile {} {
    set file [GetFilename]
    if {"$file" == ""} {return}

    # for test purposes, just print the file name here
    puts "got $file"
}
  

# Return the path name of the file currently selected in the
# current node's listbox, or the empty string if none are selected. 

proc GetFilename {} {
    global dirtree
    set dir $dirtree(dir)
    set list $dirtree(list)
    if {"$dir" == "" || "$list" == ""} {return ""}
    
    set sel [$list curselection]
    if {![llength $sel]} {return ""}
    return $dir/[$list get [lindex $sel 0]]
}


# layout the components of the given node depending on whether
# the tree is vertical or horizontal
# (Also take the file listbox into consideration if it is open)

proc LayoutNode {canvas tree dir} {
    set text $dir:text
    set bitmap $dir:bitmap
    set list [$canvas find withtag $dir:list]
    
    if {[$tree cget -layout] == "horizontal"} {
        scan [$canvas bbox $text] "%d %d %d %d" x1 y1 x2 y2
	$canvas itemconfig $bitmap -anchor se
	$canvas coords $bitmap $x1 $y2
	if {"$list" != ""} {
	    scan  [$canvas bbox $text $bitmap] "%d %d %d %d" x1 y1 x2 y2
	    $canvas itemconfig $list -anchor nw
	    $canvas coords $list $x1 $y2
	}
    } else {
        scan [$canvas bbox $bitmap] "%d %d %d %d" x1 y1 x2 y2
	$canvas itemconfig $text -anchor n
	$canvas coords $text [expr "$x1+($x2-$x1)/2"] $y2
	if {"$list" != ""} {
	    scan  [$canvas bbox $text $bitmap] "%d %d %d %d" x1 y1 x2 y2
	    $canvas itemconfig $list -anchor n
	    $canvas coords $list [expr "$x1+($x2-$x1)/2"] $y2
	}
    }
}
