# ------------------------------------------------------------------------------
#  panedw.tcl
#  This file is part of Unifix BWidget Toolkit
# ------------------------------------------------------------------------------
#  Index of commands:
#     - PanedWindow::create
#     - PanedWindow::configure
#     - PanedWindow::cget
#     - PanedWindow::add
#     - PanedWindow::getframe
#     - PanedWindow::_destroy
#     - PanedWindow::_beg_move_sash
#     - PanedWindow::_move_sash
#     - PanedWindow::_end_move_sash
# ------------------------------------------------------------------------------

namespace eval PanedWindow {
    namespace eval Pane {
        Widget::declare PanedWindow::Pane {
            {-minsize Int 0 0 "%d >= 0"}
            {-weight  Int 1 0 "%d >= 0"}
        }
    }

    Widget::declare PanedWindow {
        {-side       Enum       top 1 {top left bottom right}}
        {-width      Int        10  1 "%d >=6"}
        {-pad        Int        4   1 "%d >= 0"}
        {-background TkResource ""  0 frame}
        {-bg         Synonym    -background}
    }

    variable _panedw

    proc ::PanedWindow { path args } { return [eval PanedWindow::create $path $args] }
    proc use {} {}
}



# ------------------------------------------------------------------------------
#  Command PanedWindow::create
# ------------------------------------------------------------------------------
proc PanedWindow::create { path args } {
    variable _panedw

    Widget::init PanedWindow $path $args

    frame $path -background [Widget::cget $path -background] -class PanedWindow
    set _panedw($path,nbpanes) 0

    bind $path <Destroy>   "PanedWindow::_destroy $path"

    rename $path ::$path:cmd
    proc ::$path { cmd args } "return \[eval PanedWindow::\$cmd $path \$args\]"

    return $path
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::configure
# ------------------------------------------------------------------------------
proc PanedWindow::configure { path args } {
    variable _panedw

    set res [Widget::configure $path $args]

    if { [Widget::hasChanged $path -background bg] && $_panedw($path,nbpanes) > 0 } {
        $path:cmd configure -background $bg
        $path.f0 configure -background $bg
        for {set i 1} {$i < $_panedw($path,nbpanes)} {incr i} {
            set frame $path.sash$i
            $frame configure -background $bg
            $frame.sep configure -background $bg
	    if { [string compare $::tcl_platform(platform) "windows"] } {
		$frame.but configure -background $bg
	    }
            $path.f$i configure -background $bg
            $path.f$i.frame configure -background $bg
        }
    }
    return $res
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::cget
# ------------------------------------------------------------------------------
proc PanedWindow::cget { path option } {
    return [Widget::cget $path $option]
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::add
# ------------------------------------------------------------------------------
proc PanedWindow::add { path args } {
    variable _panedw

    set num $_panedw($path,nbpanes)
    Widget::init PanedWindow::Pane $path.f$num $args
    set bg [Widget::getoption $path -background]

    set wbut  [Widget::getoption $path -width]
    set pad   [Widget::getoption $path -pad]
    set width [expr {$wbut+2*$pad}]
    set side  [Widget::getoption $path -side]
    
    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
	set size width
    } else {
	set size height
    }
    

    set rp 0.0
    set trs [expr {0.0 + [Widget::getoption $path.f$num -weight]}]

    # Re-'place' old frames and old sashes
    if { $num > 0 } {
	for { set i 0 } { $i < $num } { incr i } {
	    place forget $path.f$i

	    if { $i > 0 } {
		place forget $path.sash$i
	    }

	    set trs [expr {$trs + [Widget::getoption $path.f$i -weight]}]
	}

	set as [winfo $size $path]

	set rn $num.0

	for { set i 0 } { $i < $num } { incr i } {
	    set rs [expr {[Widget::getoption $path.f$i -weight] / $trs}]
	    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
		place $path.f$i -relx $rp -rely 0.0 -anchor nw -relwidth $rs -relheight 1.0 -width -$width
	    } else {
		place $path.f$i -relx 0.0 -rely $rp -anchor nw -relwidth 1.0 -relheight $rs -height -$width
	    }

	    if { $i > 0 } {
		if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
		    place $path.sash$i -relx $rp -x -$width -rely 0.0 -anchor nw -relheight 1.0 -width $width
		} else {
		    place $path.sash$i -relx 0.0 -rely $rp  -y -$width -anchor nw -relwidth 1.0 -height $width
		}
	    }

	    set rp [expr {$rp + $rs}]
	}
    }
    
    # Add new sash
    if { $num > 0 } {
        set frame [frame $path.sash$num -relief flat -bd 0 -highlightthickness 0 -width $width -height $width -bg $bg]
	set sep   [frame $frame.sep -bd 1 -relief raised -highlightthickness 0 -bg $bg]
	
	if { [string compare $::tcl_platform(platform) "windows"] } {
	    set sep_width 2
	} else {
	    set sep_width 5
	}	

	if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
	    place $frame -relx $rp -x -$width -rely 0.0 -anchor nw -relheight 1.0 -width $width
	    place $sep  -relx 0.5 -y 0 -width $sep_width -relheight 1.0 -anchor n
	    $sep configure -cursor sb_h_double_arrow 
	} else {
	    place $frame -relx 0.0 -rely $rp  -y -$width -anchor nw -relwidth 1.0 -height $width
	    place $sep -x 0 -rely 0.5 -height $sep_width -relwidth 1.0 -anchor w
	    $sep configure -cursor sb_v_double_arrow 
	}

	bind $sep <ButtonPress-1> "PanedWindow::_beg_move_sash $path $num %X %Y"

	if { [string compare $::tcl_platform(platform) "windows"] } {
	    set but   [frame $frame.but -bd 1 -relief raised -highlightthickness 0 -bg $bg -width $wbut -height $wbut]
	    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
		if { ![string compare $side "top"] } {
		    place $but -relx 0.5 -y [expr {6+$wbut/2}] -anchor c
		} else {
		    place $but -relx 0.5 -rely 1.0 -y [expr {-6-$wbut/2}] -anchor c
		}
		$but configure -cursor sb_h_double_arrow 
	    } else {
		if { ![string compare $side "left"] } {
		    place $but -rely 0.5 -x [expr {6+$wbut/2}] -anchor c
		} else {
		    place $but -rely 0.5 -relx 1.0 -x [expr {-6-$wbut/2}] -anchor c
		}
		$but configure -cursor sb_v_double_arrow 
	    }
	    bind $but <ButtonPress-1> "PanedWindow::_beg_move_sash $path $num %X %Y"
	}
    } 

    # Add new frame
    set pane [frame $path.f$num -bd 0 -relief flat -highlightthickness 0 -bg $bg]
    set user [frame $path.f$num.frame  -bd 0 -relief flat -highlightthickness 0 -bg $bg]

    set rs [expr {[Widget::getoption $path.f$num -weight] / $trs}]

    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
	place $pane -relx $rp -rely 0.0 -anchor nw -relwidth $rs -relheight 1.0
    } else {
	place $pane -relx 0.0 -rely $rp -anchor nw -relwidth 1.0 -relheight $rs
    }

    pack $user -fill both -expand yes
    incr _panedw($path,nbpanes)

    return $user
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::getframe
# ------------------------------------------------------------------------------
proc PanedWindow::getframe { path index } {
    if { [winfo exists $path.f$index.frame] } {
        return $path.f$index.frame
    }
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::_destroy
# ------------------------------------------------------------------------------
proc PanedWindow::_destroy { path } {
    variable _panedw

    for {set i 0} {$i < $_panedw($path,nbpanes)} {incr i} {
        Widget::destroy $path.f$i
    }
    unset _panedw($path,nbpanes)
    Widget::destroy $path
    rename $path {}
}
    

# ------------------------------------------------------------------------------
#  Command PanedWindow::_beg_move_sash
# ------------------------------------------------------------------------------
proc PanedWindow::_beg_move_sash { path num x y } {
    variable _panedw

    set fprev $path.f[expr {$num-1}]
    set fnext $path.f$num
    set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}]

    if { [string compare $::tcl_platform(platform) "windows"] } {
	$path.sash$num.but configure -relief sunken
    }
    set top  [toplevel $path.sash -borderwidth 1 -relief raised]

    set minszg [Widget::getoption $fprev -minsize]
    set minszd [Widget::getoption $fnext -minsize]
    set side   [Widget::getoption $path -side]

    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
        $top configure -cursor sb_h_double_arrow
        set h    [winfo height $path]
        set yr   [winfo rooty $path.sash$num]
        set xmin [expr {$wsash/2+[winfo rootx $fprev]+$minszg}]
        set xmax [expr {-$wsash/2-1+[winfo rootx $fnext]+[winfo width $fnext]-$minszd}]
        wm overrideredirect $top 1
        wm geom $top "2x${h}+$x+$yr"

        update idletasks
        grab set $top
        bind $top <ButtonRelease-1> "PanedWindow::_end_move_sash $path $top $num $xmin $xmax %X rootx width"
        bind $top <Motion>          "PanedWindow::_move_sash $top $xmin $xmax %X +%%d+$yr"
        _move_sash $top $xmin $xmax $x "+%d+$yr"
    } else {
        $top configure -cursor sb_v_double_arrow
        set w    [winfo width $path]
        set xr   [winfo rootx $path.sash$num]
        set ymin [expr {$wsash/2+[winfo rooty $fprev]+$minszg}]
        set ymax [expr {-$wsash/2-1+[winfo rooty $fnext]+[winfo height $fnext]-$minszd}]
        wm overrideredirect $top 1
        wm geom $top "${w}x2+$xr+$y"

        update idletasks
        grab set $top
        bind $top <ButtonRelease-1> "PanedWindow::_end_move_sash $path $top $num $ymin $ymax %Y rooty height"
        bind $top <Motion>          "PanedWindow::_move_sash $top $ymin $ymax %Y +$xr+%%d"
        _move_sash $top $ymin $ymax $y "+$xr+%d"
    }
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::_move_sash
# ------------------------------------------------------------------------------
proc PanedWindow::_move_sash { top min max v form } {

    if { $v < $min } {
	set v $min
    } elseif { $v > $max } {
	set v $max
    }
    wm geom $top [format $form $v]
}


# ------------------------------------------------------------------------------
#  Command PanedWindow::_end_move_sash
# ------------------------------------------------------------------------------
proc PanedWindow::_end_move_sash { path top num min max v rootv size } {
    variable _panedw

    destroy $top
    if { $v < $min } {
	set v $min
    } elseif { $v > $max } {
	set v $max
    }
    set fprev $path.f[expr {$num-1}]
    set fnext $path.f$num
    set sash $path.sash$num
    if { [string compare $::tcl_platform(platform) "windows"] } {
	$sash.but configure -relief raised
    }
    set side  [Widget::getoption $path -side]
    set wsash [expr {[Widget::getoption $path -width] + 2*[Widget::getoption $path -pad]}]
    set dv    [expr {$v-[winfo $rootv $sash]-$wsash/2}].0
    set w     [winfo $size $path].0
    set rdv   [expr {$dv / $w}]

    set lprev [place info $fprev]
    set lnext [place info $fnext]
    set lsash [place info $sash]

    if { ![string compare $side "top"] || ![string compare $side "bottom"] } {
	set rpprev [lindex $lprev [expr {[lsearch -exact $lprev -relx] + 1}]]
	set rsprev [lindex $lprev [expr {[lsearch -exact $lprev -relwidth] + 1}]]

	set rpnext [lindex $lnext [expr {[lsearch -exact $lnext -relx] + 1}]]
	set rsnext [lindex $lnext [expr {[lsearch -exact $lnext -relwidth] + 1}]]
	
	set rpsash [lindex $lsash [expr {[lsearch -exact $lsash -relx] + 1}]]
	

	set nrpprev $rpprev
	set nrsprev [expr {$rsprev + $rdv}]

	set nrpnext [expr {$rpnext + $rdv}]
	set nrsnext [expr {$rsnext - $rdv}]

	set nrpsash [expr {$rpsash + $rdv}]

	place $fprev -relx $nrpprev -rely 0.0 -anchor nw -relwidth $nrsprev -relheight 1.0 -width -$wsash
	if { [expr {$num+1}] == $_panedw($path,nbpanes) } {
	    place $fnext -relx $nrpnext -rely 0.0 -anchor nw -relwidth $nrsnext -relheight 1.0
	} else {
	    place $fnext -relx $nrpnext -rely 0.0 -anchor nw -relwidth $nrsnext -relheight 1.0 -width -$wsash
	}
	place $sash  -relx $nrpsash -rely 0.0 -anchor nw -x -$wsash -relheight 1.0 -width $wsash
    } else {
	set rpprev [lindex $lprev [expr {[lsearch -exact $lprev -rely] + 1}]]
	set rsprev [lindex $lprev [expr {[lsearch -exact $lprev -relheight] + 1}]]

	set rpnext [lindex $lnext [expr {[lsearch -exact $lnext -rely] + 1}]]
	set rsnext [lindex $lnext [expr {[lsearch -exact $lnext -relheight] + 1}]]
	
	set rpsash [lindex $lsash [expr {[lsearch -exact $lsash -rely] + 1}]]
	

	set nrpprev $rpprev
	set nrsprev [expr {$rsprev + $rdv}]

	set nrpnext [expr {$rpnext + $rdv}]
	set nrsnext [expr {$rsnext - $rdv}]

	set nrpsash [expr {$rpsash + $rdv}]

	place $fprev -relx 0.0 -rely $nrpprev -anchor nw -relwidth 1.0 -relheight $nrsprev -height -$wsash
	if { [expr {$num+1}] == $_panedw($path,nbpanes) } {
	    place $fnext -relx 0.0 -rely $nrpnext -anchor nw -relwidth 1.0 -relheight $nrsnext
	} else {
		place $fnext -relx 0.0 -rely $nrpnext -anchor nw -relwidth 1.0 -relheight $nrsnext -height -$wsash
	}
	place $sash -relx 0.0 -rely $nrpsash  -y -$wsash -anchor nw -relwidth 1.0 -height $wsash
    }
}

