# ResizeButs.tcl --
#
# Matthew J. Middleton 8/16/2005, Revision 1.0
# 7/6/2006 Revision 2.0
# 11/20/2006 Revision 3.0

namespace eval ResizeButs {
    variable Priv
    variable specs
    variable itemspecs

    if {![info exists Priv(upImage)]} {
	set Priv(upImage) [image create photo -data {
	    R0lGODlhDgAOAJEAANnZ2YCAgPz8/P///yH5BAEAAAAALAAAAAAOAA4AAAImhI+py+1LIsJH
	    iBAh+BgmiEAJQITgW6DgUQIAECH4JN8IPqYuNxUAOw==}]
    }
    if {![info exists Priv(downImage)]} {
	set Priv(downImage) [image create photo -data {
	    R0lGODlhDgAOAJEAANnZ2YCAgPz8/P///yH5BAEAAAAALAAAAAAOAA4AAAInhI+py+1I4ocQ
	    /IgDEYIPgYJICUCE4F+YIBolEoKPEJKZmVJK6ZACADs=}]
    }
    if {![info exists Priv(leftImage)]} {
	set Priv(leftImage) [image create photo -data {
	    R0lGODlhDgAOAJEAANnZ2YCAgPz8/P///yH5BAEAAAAALAAAAAAOAA4AAAIphI+py50UET5G
	    hCBSDBCCDxEoeCQBAITgm4iYEHwUEUFEIhE+pi43UAEAOw==}]
    }
    if {![info exists Priv(rightImage)]} {
	set Priv(rightImage) [image create photo -data {
	    R0lGODlhDgAOAJEBANnZ2YCAgPz8/P///yH5BAEAAAAALAAAAAAOAA4AAAIahI+pyw0RnIHQ
	    xVfXnRt1IWgGGGqkA0rqyhYAIf8LTFZpZXdQcm8yMDAAOw==}]
    }

    array set specs {
	-side			{"" "" left}
	-resizecommand			{command Command ""}
	-ordercommand			{command Command ""}
	-showcommand			{command Command ""}
	-scrollcommand			{command Command ""}
	-scrollincrement			{"" "" 0}
	-orderbutton			{"" "" "0 increasing"}
	-orient			{orient Orient horizontal}
	-borderwidth			{borderWidth BorderWidth 2}
	-highlightthickness	{highlightThickness HighlightThickness 0}
	-highlightcolor			{highlightColor HighlightColor black}
	-takefocus			{takeFocus TakeFocus 0}
	-relief			{relief Relief raised}
	-pressrelief			{relief Relief sunken}
	-foreground			{foreground Foreground black}
	-background			{background Background ""}
	-showtriangle			{"" "" 1}
	-cursor			{cursor Cursor ""}
	-font			{font Font ""}
	-showmenu			{"" "" 1}
	-width			{width Width ""}
	-height			{height Height ""}
    }

    array set itemspecs {
	-state			{state State normal}
	-width			{width Width ""}
	-height			{height Height ""}
	-text			{text Text ""}
	-command			{command Command ""}
	-image			{image Image ""}
	-show			{"" "" 1}
	-lockshow			{"" "" 0}
    }
    set Priv(minwb) 30
    set Priv(minhb) 15

    bind ResizeButsButton <Button-1> [list ResizeButs::_Btn1 %W]
    bind ResizeButsButton <ButtonRelease-1> [list ResizeButs::_BtnRels1 %W %X %Y]
    bind ResizeButsButton <Motion> [list ResizeButs::_Motion %W %X %Y]
    bind ResizeButsButton <B1-Motion> [list ResizeButs::_Motion1 %W %X %Y]
    bind ResizeButsButton <Leave> [list ResizeButs::_Leave %W %X %Y]
    bind ResizeButsButton <Enter> [list ResizeButs::_Enter %W %X %Y]
    bind ResizeButsButton <FocusIn> [list ResizeButs::_FocusIn %W]
    bind ResizeButsButton <FocusOut> [list ResizeButs::_FocusOut %W]
    bind ResizeButsButton <KeyPress-Return> [list ResizeButs::_KeyPressEnter %W]
    bind ResizeButsButton <KeyRelease-Return> [list ResizeButs::_KeyReleaseEnter %W %X %Y]
    bind ResizeButsButton <Button-3> [list ResizeButs::_Btn3 %W %X %Y]
    bind ResizeButs <Destroy> [list ResizeButs::_Destroy %W]
    bind ResizeButs <FocusIn> {if {[focus] == "%W"} {focus [tk_focusNext %W]}}
    bind ResizeButs <Configure> [list ResizeButs::_Configure %W %w %h]
    bind ResizeButs <Map> [list ResizeButs::_positionItems %W]

    proc ::ResizeButs {args} {return [eval ResizeButs::_Create $args]}
}

proc ResizeButs::_Create {args} {
    variable specs
    variable Priv

    if {[llength $args] == 0} {error "wrong # args: should be \"ResizeButs pathName ?option value ...?\""}
    set w [lindex $args 0]
    if {$w == ""} {error "bad window path name \"\""}
    if [winfo exists $w] {error "window name \"$w\" already exists"}
    upvar ::ResizeButs::$w data

    set opts [lsort [array names specs]]
    set errmsg [join [lreplace $opts end end "or [lindex $opts end]"] ", "]
    if {([llength $args] - 1) & 1} {
	set opt [lindex $args end]
	set vopt [_validarg $opt]
	catch {unset data}
	if {![info exists specs($vopt)]} {
	    error "bad option \"$opt\": must be $errmsg"
	}
	error "value for \"$opt\" missing"
    }
    foreach opt $opts {
	set data($opt) [lindex $specs($opt) 2]
    }
    foreach {opt val} [lrange $args 1 end] {
	set vopt [_validarg $opt]
	if {![info exists specs($vopt)]} {
	    catch {unset data}
	    error "bad option \"$opt\": must be $errmsg"
	}
	set data($vopt) $val
    }

    set b [lindex $data(-orderbutton) 0]
    set order [lindex $data(-orderbutton) 1]
    if {![string is integer -strict $b] || $b < 0} {set b 0}
    if {$order != "decreasing"} {set order increasing}
    set data(-orderbutton) [list $b $order]
    if {![string equal $data(-showtriangle) 0]} {set data(-showtriangle) 1}
    if {$data(-orient) != "vertical"} {
	set data(-orient) horizontal
	if {$data(-side) != "right" && $data(-side) != "both"} {set data(-side) left}
    } elseif {$data(-side) != "bottom" && $data(-side) != "right" && $data(-side) != "both"} {
	set data(-side) left
    } elseif {$data(-side) == "bottom"} {
	set data(-side) right
    }
    foreach opt [list -highlightthickness -borderwidth] {
	if ![string is integer -strict $data($opt)] {
	    catch {unset data}
	    error "bad integer value \"$data($opt)\""
	}
	if {$data($opt) < 0} {set data($opt) 0}
    }
    if {$data(-showmenu) != 0} {set data(-showmenu) 1}

    if {$data(-scrollcommand) != ""} {catch {uplevel #0 $data(-scrollcommand) 0 1}}
    # End of Config

    if {$data(-orient) == "vertical"} {
	set data(wtri) [image width $Priv(leftImage)]
	set data(htri) [image height $Priv(leftImage)]
	set popts [list -relwidth 1.0]
    } else {
	set data(wtri) [image width $Priv(upImage)]
	set data(htri) [image height $Priv(upImage)]
	set popts [list -relheight 1.0]
    }
    if {$data(-background) != ""} {set options [list -bg $data(-background)]} \
    else {set options ""}
    if {$data(-font) != ""} {lappend options -font $data(-font)}

    if [catch {
	frame $w -bd 0 -highlightthickness 0 -takefocus 0 -class ResizeButs -cursor $data(-cursor)
	if {$data(-height) == ""} {$w configure -height 0} \
	else {
	    set val [winfo pixels $w $data(-height)]
	    if {$val < 0} {set data(-height) 0; set val 0}
	    $w configure -height $val
	}
	if {$data(-width) == ""} {$w configure -width 0} \
	else {
	    set val [winfo pixels $w $data(-width)]
	    if {$val < 0} {set data(-width) 0; set val 0}
	    $w configure -width $val
	}
	# error check
	winfo pixels $w $data(-scrollincrement)
	set scr [frame $w.scrollregion -bd 0 -highlightthickness 0 -takefocus 0 -cursor $data(-cursor) -height 0 -width 0]
	eval {menu $w.menu -type normal -tearoff 0 -relief $data(-relief) -bd $data(-borderwidth) -takefocus 0 \
		-fg $data(-foreground)} $options
    } res] {
	unset data
	destroy $w
	error $res
    }

    eval {place $scr -anchor nw -bordermode inside -x 0 -y 0} $popts

    if {$data(-orient) == "horizontal"} {
	set dir column
	grid rowconfigure $scr 0 -weight 1
    } else {
	set dir row
	grid columnconfigure $scr 0 -weight 1
    }
    if {$data(-side) == "right"} {grid ${dir}configure $scr 0 -weight 1}
    set data(buts) ""

    rename ::$w ::$w:cmd
    proc ::$w {cmd args} "return \[eval ResizeButs::_command \$cmd $w \$args\]"

    return $w
}

proc ResizeButs::_command {cmd w args} {
    variable Priv

    if {[lsearch $Priv(coms) $cmd] < 0} {
	set errmsg [join [lreplace $Priv(coms) end end "or [lindex $Priv(coms) end]"] ", "]
	error "bad option \"$cmd\": must be $errmsg"
    }
    return [eval ResizeButs::$cmd $w $args]
}

proc ResizeButs::insert {w args} {
    upvar ::ResizeButs::$w data
    variable Priv
    variable itemspecs

    if [info exists Priv(add)] {set com $Priv(add)} else {set com "insert index"}
    set numargs [llength $args]
    if {$numargs == 0} {catch {unset Priv(add)}; error "wrong # args: should be \"$w $com ?option value ...?\""}
    set item [lindex $args 0]
    set Priv(insert) 1
    set index [ResizeButs::index $w $item]
    unset Priv(insert)
    if {$index < 0} {catch {unset Priv(add)}; error "bad index number \"$item\""}

    set opts [lsort [array names itemspecs]]
    set errmsg [join [lreplace $opts end end "or [lindex $opts end]"] ", "]
    if {($numargs - 1) & 1} {
	catch {unset Priv(add)}
	set opt [lindex $args end]
	if {![info exists itemspecs($opt)]} {
	    error "bad option \"$opt\": must be $errmsg"
	}
	error "wrong # args: should be \"$w $com ?option value ...?\""
    }

    set scr $w.scrollregion
    for {set i 0} {[winfo exists [set b $scr.b$i]]} {incr i} {}
    set bname b$i
    foreach opt $opts {
	set data($opt,$bname) [lindex $itemspecs($opt) 2]
    }
    foreach {opt val} [lrange $args 1 end] {
	if {![info exists itemspecs($opt)]} {
	    catch {unset Priv(add)}
	    error "bad option \"$opt\": must be $errmsg"
	}
	set data($opt,$bname) $val
    }
    if {$data(-state,$bname) != "disabled"} {set data(-state,$bname) normal}
    if {$data(-show,$bname) != 0} {set data(-show,$bname) 1}
    if {$data(-lockshow,$bname) != 1} {set data(-lockshow,$bname) 0}
    # End of Config

    if {$data(-background) != ""} {
	set options [list -bg $data(-background)]
    } else {
	set options ""
    }
    if {$data(-font) != ""} {
	set itemoptions [list -font $data(-font)]
    } else {
	set itemoptions ""
    }
    set data(disabledimage,$bname) [image create photo]

    if [catch {
	eval {canvas $b -relief $data(-relief) -highlightthickness 0 -cursor $data(-cursor) \
	    -takefocus $data(-takefocus) -bd $data(-borderwidth)} $options

	if {$data(-orient) == "horizontal"  && $data(-width,$bname) != ""} {
	    if {[winfo pixels $w $data(-width,$bname)] < 0} {set data(-width,$bname) 0}
	} else {
	    set data(-width,$bname) ""
	}
	if {$data(-orient) == "vertical"  && $data(-height,$bname) != ""} {
	    if {[winfo pixels $w $data(-height,$bname)] < 0} {set data(-height,$bname) 0}
	} else {
	    set data(-height,$bname) ""
	}

	bindtags $b [list $b $w ResizeButsButton [winfo toplevel $b] all]
	$b create image 0 0 -image $data(-image,$bname) \
	    -disabledimage $data(disabledimage,$bname) -anchor w -tags image
	eval {$b create text 0 0 -text $data(-text,$bname) -anchor w -fill $data(-foreground) \
	    -disabledfill #808080 -tags text} $itemoptions
	$b create image 0 0 -anchor w -tags tri
    } res] {
	image delete $data(disabledimage,$bname)
	catch {unset data(disabledimage,$bname)}
	foreach opt [array names itemspecs] {
	    catch {unset data($opt,$bname)}
	}
	destroy $b
	error $res
    }

    set before [lindex $data(buts) $index]
    if {$before != ""} {lower $b $before}

    if {$data(-state,$bname) == "disabled"} {
	if {$data(-image,$bname) != ""} {
	    $data(disabledimage,$bname) copy $data(-image,$bname)
	    _disabledImage $data(disabledimage,$bname) $b
	}
	$b itemconfigure text -state disabled
	$b itemconfigure image -state disabled
    }

    if $data(-show,$bname) {
	set gindex $index
	for {set i 0} {$i < $index} {incr i} {
	    if !$data(-show,[winfo name [lindex $data(buts) $i]]) {incr gindex -1}
	}
	set rbuts {}
	set buts [grid slaves $scr]
	set end [expr {[llength $buts] - 1}]
	for {set i [expr {$end - $gindex}]} {$i >= 0} {incr i -1} {lappend rbuts [lindex $buts $i]}
	foreach rb $rbuts {grid remove $rb}

	if {$data(-orient) == "horizontal"} {
	    set col $gindex
	    set row 0
	    set dir column
	} else {
	    set col 0
	    set row $gindex
	    set dir row
	}

	grid $b -sticky nswe -row $row -column $col
	incr end

	foreach rb $rbuts {
	    if {$data(-orient) == "horizontal"} {incr col} else {incr row}
	    grid $rb -row $row -column $col
	}

	if {$data(-side) != "right"} {
	    grid ${dir}configure $scr $end -weight 1
	    if {$end > 0} {grid ${dir}configure $scr [expr {$end - 1}] -weight 0}
	}
    }

    set data(buts) [linsert $data(buts) $index $b]
    if $data(-lockshow,$bname) {
	set options [list -state disabled]
    } else {
	set options ""
    }
    eval {$w.menu insert $index checkbutton -label $data(-text,$bname) -variable ::ResizeButs::${w}(-show,$bname) \
	-command [list ResizeButs::_setShow $w $bname]} $options

    foreach {but order} $data(-orderbutton) break
    if {$but != "" && $order != "" && $but >= $index} {
	if ![info exists Priv(add)] {
	    incr but
	    set data(-orderbutton) [list $but $order]
	} elseif {$data(-showtriangle) && $but == $index} {
	    if {$order == "increasing"} {
		if {$data(-orient) == "vertical"} {$b itemconfigure tri -image $Priv(leftImage)} \
		else {$b itemconfigure tri -image $Priv(upImage)}
	    } else {
		if {$data(-orient) == "vertical"} {$b itemconfigure tri -image $Priv(rightImage)} \
		else {$b itemconfigure tri -image $Priv(downImage)}
	    }
	}
    }

    _positionItems $w
}

proc ResizeButs::_Btn1 {W} {
    variable Priv
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data

    if {$data(-orient) == "vertical"} {
	set dir height
    } else {
	set dir width
    }
    if ![info exists Priv(move)] {
	if {$data(-state,[winfo name $W]) == "normal"} {
	    set size [expr {[winfo $dir $W] - 2 * [$W cget -highlightthickness] - 2 * [$W cget -bd]}]
	    if {$size <= 1} return
	    $W configure -relief $data(-pressrelief)
	    $W move image 1 1
	    $W move text 1 1
	    $W move tri 1 1
	    set Priv(butDown) $W
	}
    } else {
	set Priv(moving) 1
    }
}

proc ResizeButs::_BtnRels1 {W X Y} {
    variable Priv
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data

    if [info exists Priv(butDown)] {
	$W configure -relief $data(-relief)
	$W move image -1 -1
	$W move text -1 -1
	$W move tri -1 -1
	unset Priv(butDown)

	foreach {but order} $data(-orderbutton) break
	set i [lsearch $data(buts) $W]
	if {$i < 0} return
	if {$but != $i} {
	    set order increasing
	    if {$data(-showtriangle) && $but != ""} {
		set but [lindex $data(buts) $but]
		if [winfo exists $but] {$but itemconfigure tri -image ""}
	    }
	} else {
	    if {$order == "increasing"} {set order decreasing} \
	    else {set order increasing}
	}
	set data(-orderbutton) [list $i $order]
	if $data(-showtriangle) {
	    if {$order == "increasing"} {
		if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(leftImage)} \
		else {$W itemconfigure tri -image $Priv(upImage)}
	    } else {
		if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(rightImage)} \
		else {$W itemconfigure tri -image $Priv(downImage)}
	    }
	}
	if {$data(-ordercommand) != ""} {
	    uplevel #0 $data(-ordercommand) $i $order
	}
	set bname [winfo name $W]
	if {$data(-command,$bname) != ""} {
	    uplevel #0 $data(-command,$bname)
	}

    } else {
	catch {unset Priv(moving)}
    }
    ResizeButs::_Leave $W $X $Y
}

proc ResizeButs::_setOrderButton {w {b 0} {order increasing}} {
    upvar ::ResizeButs::$w data
    variable Priv

    if {![string is integer -strict $b] || $b < 0} return
    if {$order != "decreasing" && $order != "increasing"} return
#    if {[ResizeButs::itemcget $w $b -show] == 0} return
    foreach {old_b old_order} $data(-orderbutton) break

    set data(-orderbutton) [list $b $order]
    set W [lindex $data(buts) $b]
    if {$old_b != ""} {set old_but [lindex $data(buts) $old_b]} \
    else {set old_but ""}
    if $data(-showtriangle) {
	if {$old_b != $b && [winfo exists $old_but]} {$old_but itemconfigure tri -image ""}
	if [winfo exists $W] {
	    if {$order == "increasing"} {
		if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(leftImage)} \
		else {$W itemconfigure tri -image $Priv(upImage)}
	    } else {
		if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(rightImage)} \
		else {$W itemconfigure tri -image $Priv(downImage)}
	    }
	}
    } elseif [winfo exists $old_but] {
	$old_but itemconfigure tri -image ""
    }

    if {($old_b != $b || $old_order != $order) && [winfo exists $W]} {
	if {$data(-ordercommand) != ""} {
	    uplevel #0 $data(-ordercommand) $b $order
	}
    }
}

proc ResizeButs::_Enter {W X Y} {
    variable Priv

    if {[info exists Priv(butDown)] || [info exists Priv(moving)]} return
    ResizeButs::_Motion $W $X $Y
}

proc ResizeButs::_Motion {W X Y} {
    variable Priv
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data

    if [info exists Priv(menuUp)] return
    set buts [grid slaves $parent.scrollregion]
    set i [lsearch $buts $W]
    if {$i < 0} return
    set reset_curs 0
    if {$data(-orient) == "vertical"} {
	set dir height
	set j v
	set coord Y
	set rcoord rooty
    } else {
	set dir width
	set j h
	set coord X
	set rcoord rootx
    }
    set C [set $coord]
    set size [winfo $dir $W]
    set c [expr {$C - [winfo $rcoord $W]}]
    if {($c <= $size * 0.1) && ($W != [lindex $buts end] || $data(-side) == "right") && ($c < 5)} {
	set Lbut [lindex $buts [incr i]]
	if [info exists Priv(move)] {
	    foreach {C1 oldLbut oldRbut} $Priv(move) break
	    if {$oldLbut != $Lbut || $oldRbut != $W} {set reset_curs 1}
	}
	set move [list $C $Lbut $W]
	if {$Lbut != ""} {$Lbut configure -cursor sb_${j}_double_arrow}
	$W configure -cursor sb_${j}_double_arrow
    } elseif {($c >= $size * 0.9 - [$W cget -bd]/2) && ($i != 0 || $data(-side) == "left") && ($size - $c < 7)} {
	set Rbut [lindex $buts [incr i -1]]
	if [info exists Priv(move)] {
	    foreach {C1 oldLbut oldRbut} $Priv(move) break
	    if {$oldLbut != $W || $oldRbut != $Rbut} {set reset_curs 1}
	}
	set move [list $C $W $Rbut]
	if {$Rbut != ""} {$Rbut configure -cursor sb_${j}_double_arrow}
	$W configure -cursor sb_${j}_double_arrow
    } elseif [info exists Priv(move)] {
	set reset_curs 2
    }

    if $reset_curs {
	foreach w [lreplace $Priv(move) 0 0] {
	    if [winfo exists $w] {$w configure -cursor $data(-cursor)}
	}
	if {$reset_curs == 2} {unset Priv(move)} \
	else {set Priv(move) $move}
    } elseif [info exists move] {
	set Priv(move) $move
    }
}

proc ResizeButs::_Leave {W X Y} {
    variable Priv
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data

    if {[info exists Priv(butDown)] || [info exists Priv(moving)]} return
    set w [winfo containing $X $Y]
    if {[lsearch $data(buts) $w] >= 0} return
    foreach b $data(buts) {
	$b configure -cursor $data(-cursor)
    }
    catch {unset Priv(move)}
}

proc ResizeButs::_Motion1 {W X Y} {
    variable Priv
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data

    if {![info exists Priv(move)] || ![info exists data(-side)]} return
    if {$data(-orient) == "vertical"} {
	set dir height
	set coord Y
	set rcoord rooty
    } else {
	set dir width
	set coord X
	set rcoord rootx
    }
    set C [set $coord]
    foreach {C1 Lbut Rbut} $Priv(move) break
    if {$C == $C1} return
    set Priv(move) [list $C $Lbut $Rbut]
    if {$Lbut != ""} {
	set Lpad [expr {2 * [$Lbut cget -highlightthickness] + 2 * [$Lbut cget -bd]}]
	set CL [expr {[winfo $rcoord $Lbut] + $Lpad}]
	set Lsize [expr {[winfo $dir $Lbut] - $Lpad}]
    }
    if {$Rbut != ""} {
	set Rpad [expr {2 * [$Rbut cget -highlightthickness] + 2 * [$Rbut cget -bd]}]
	set CR [expr {[winfo $rcoord $Rbut] + [winfo $dir $Rbut] - $Rpad}]
	set Rsize [expr {[winfo $dir $Rbut] - $Rpad}]
    } else {
	set Rsize 0
	set CR [expr {$CL + $Lsize}]
    }
    if {$Lbut == ""} {
	set Lsize 0
	set CL [expr {$CR - $Rsize}]
    }

    set c [expr {$C - $C1}]
    if {$C1 < $CL && $Lsize <= 0} {
	if {$C > $CL} {set c [expr {$C - $CL}]} \
	elseif {$data(-side) != "right" || [info exists Priv(nomove)]} {set nomove 1}
    } elseif {$C1 > $CR && $Rsize <= 0} {
	if {$C < $CR} {set c [expr {$C - $CR}]} \
	elseif {$data(-side) != "left" || [info exists Priv(nomove)]} {set nomove 1}
    }

    if ![info exists nomove] {
	incr Lsize $c
	incr Rsize [expr {-1 * $c}]
	if {$Lsize < 0 && $data(-side) != "right"} {
	    incr Rsize $Lsize
	    set Lsize 0
	} elseif {$Rsize < 0 && $data(-side) != "left"} {
	    incr Lsize $Rsize
	    set Rsize 0
	}

	if {$data(-side) != "right"} {
	    $Lbut configure -$dir $Lsize
	    set data(-$dir,[winfo name $Lbut]) $Lsize
	}
	if {$data(-side) != "left"} {
	    $Rbut configure -$dir $Rsize
	    set data(-$dir,[winfo name $Rbut]) $Rsize
	}

	_positionItems $parent

	if {$data(-side) == "left"} {
	    set newLsize [expr {[winfo $dir $Lbut] - $Lpad}]
	    if {$Lsize != $newLsize} {set Priv(nomove) 1} else {catch {unset Priv(nomove)}}
	}
	if {$data(-side) == "right"} {
	    set newRsize [expr {[winfo $dir $Rbut] - $Rpad}]
	    if {$Rsize != $newRsize} {set Priv(nomove) 1} else {catch {unset Priv(nomove)}}
	}

	if {$data(-resizecommand) != ""} {
	    if {$Lbut != "" && $data(-side) != "right"} {
		set iL [lsearch $data(buts) $Lbut]
		if {$iL < 0} return
	    }
	    if {$Rbut != "" && $data(-side) != "left"} {
		set iR [lsearch $data(buts) $Rbut]
		if {$iR < 0} return
	    }
	    set com $data(-resizecommand)
	    switch $data(-side) {
		left {uplevel #0 $com $iL [expr {$newLsize + $Lpad}]}
		right {uplevel #0 $com $iR [expr {$newRsize + $Rpad}]}
		both {
		    uplevel #0 $com $iL [expr {$Lsize + $Lpad}]
		    uplevel #0 $com $iR [expr {$Rsize + $Rpad}]
		}
	    }
	    update idletasks
	}
    }
}

proc ResizeButs::cget {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 1} {error "wrong # args: should be \"$w cget option\""}
    set opt [_validarg [lindex $args 0]]
    if [info exists data($opt)] {return $data($opt)}
    error "unknown option \"$opt\""
}

proc ResizeButs::configure {w args} {
    upvar ::ResizeButs::$w data
    variable specs
    variable Priv

    set numargs [llength $args]
    if {$numargs == 0} {
	set ret ""
	foreach opt [array names specs] {
	    lappend ret [eval list $opt $specs($opt) [list $data($opt)]]
	}
	return [lsort $ret]
    }
    if {$numargs == 1} {
	set opt [_validarg [lindex $args 0]]
	set val [ResizeButs::cget $w $opt]
	return [eval list $opt $specs($opt) [list $val]]
    }
    if {$numargs & 1} {
	set opt [_validarg [lindex $args end]]
	if {[info exists specs($opt)]} {error "value for \"[lindex $args end]\" missing"} \
	else {error "unknown option \"$opt\""}
    }
    for {set i 0} {$i < $numargs} {incr i} {
	set opt [_validarg [lindex $args $i]]
	set val [lindex $args [incr i]]
	switch -- $opt {
	    -pressrelief - -ordercommand - -resizecommand - -showcommand {set data($opt) $val}
	    -scrollcommand {
		set data($opt) $val
		if {$val != ""} {
		    catch {uplevel #0 $val [ResizeButs::view $w]}
		}
	    }
	    -foreground {
		foreach b $data(buts) {
		    $b itemconfigure text -fill $val
		}
		$w.menu configure -fg $val
		set data(-foreground) $val
	    }
	    -font {
		foreach b $data(buts) {
		    $b itemconfigure text -font $val
		}
		$w.menu configure -font $val
		set data(-font) $val
		set update 1
	    }
	    -width - -height {
		if {$val != "" && [winfo pixels $w $val] < 0} {set val 0}
		set data($opt) $val
		set update 1
	    }
	    -background - -borderwidth - -takefocus - -relief - -cursor {
		foreach b $data(buts) {
		    $b configure $opt $val
		    if {$opt == "-background"} {
			set bname [winfo name $b]
			if {$data(-state,$bname) == "disabled"} {
			    _disabledImage $data(disabledimage,$bname) $b
			}
		    }
		}
		if {$opt == "-cursor"} {
		    $w:cmd configure -cursor $val
		    $w.scrollregion configure -cursor $val
		}
		if {$opt == "-background" || $opt == "-borderwidth" || $opt == "-relief"} {
		    $w.menu configure $opt $val
		    if {$opt == "-borderwidth"} {set update 1}
		}
		set data($opt) $val
	    }
	    -highlightthickness {
		if ![string is integer -strict $val] {error "bad integer value \"$val\""}
		if {$val < 0} {set val 0}
		set data(-highlightthickness) $val
		set update 1
	    }
	    -highlightcolor {
		set data(-highlightcolor) $val
		set update 1
	    }
	    -orderbutton {eval ResizeButs::_setOrderButton $w $val}
	    -showtriangle {
		if {($val == 1 || $val == 0) && $data(-showtriangle) != $val} {
		    set data(-showtriangle) $val
		    foreach {b order} $data(-orderbutton) break
		    if {$b != ""} {
			set W [lindex $data(buts) $b]
			if [winfo exists $W] {
			    if $val {
				if {$order == "increasing"} {
				    if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(leftImage)} \
				    else {$W itemconfigure tri -image $Priv(upImage)}
				} elseif {$order == "decreasing"} {
				    if {$data(-orient) == "vertical"} {$W itemconfigure tri -image $Priv(rightImage)} \
				    else {$W itemconfigure tri -image $Priv(downImage)}
				}
			    } else {
				$W itemconfigure tri -image ""
			    }
			}
		    }
		    set update 1
		}
	    }
	    -showmenu {
		if {$val != 0 && $val != 1} {error "bad -showmenu value \"$val\": must be 0 or 1"}
		set data(-showmenu) $val
	    }
	    -scrollincrement {
		if [catch {winfo pixels $w $val} err] {error $err}
		set data(-scrollincrement) $val
	    }
	    -side - -orient {error "can't modify $opt option after widget is created"}
	    default {error "unknown option \"$opt\""}
	}
    }
    if [info exists update] {_positionItems $w}
}

proc ResizeButs::itemcget {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 2} {error "wrong # args: should be \"$w itemcget index option\""}
    set item [lindex $args 0]
    set i [ResizeButs::index $w -strict $item]
    if {$i < 0} {error "bad index number \"$item\""}
    set opt [lindex $args 1]
    set b [lindex $data(buts) $i]
    if {$b == ""} {error "bad index number \"$item\""}
    set bname [winfo name $b]
    if [info exists data($opt,$bname)] {return $data($opt,$bname)}
    error "unknown option \"$opt\""
}

proc ResizeButs::itemconfigure {w args} {
    upvar ::ResizeButs::$w data
    variable itemspecs

    set numargs [llength $args]
    if {$numargs == 0} {error "wrong # args: should be \"$w itemconfigure index ?option value ...?\""}
    set item [lindex $args 0]
    set index [ResizeButs::index $w -strict $item]
    if {$index < 0} {error "bad index number \"$item\""}
    set opts [array names itemspecs]
    if {$numargs == 1} {
	set ret ""
	foreach opt $opts {
	    lappend ret [eval list $opt $itemspecs($opt) [list [ResizeButs::itemcget $w $index $opt]]]
	}
	return $ret
    }

    if {$numargs == 2} {
	set opt [lindex $args 1]
	set val [ResizeButs::itemcget $w $index $opt]
	return [eval list $opt $itemspecs($opt) [list $val]]
    }
    if {($numargs - 1) & 1} {
	set opt [lindex $args end]
	if {[lsearch $opts $opt] > -1} {error "value for \"$opt\" missing"} \
	else {error "unknown option \"$opt\""}
    }
    set b [lindex $data(buts) $index]
    if {$b == ""} {error "bad index number \"$item\""}
    set bname [winfo name $b]
    for {set i 1} {$i < $numargs} {incr i} {
	set opt [lindex $args $i]
	set val [lindex $args [incr i]]
	switch -- $opt {
	    -text {
		$b itemconfigure text -text $val
		$w.menu entryconfigure $index -label $val
		set data(-text,$bname) $val
		set update 1
	    }
	    -width - -height {
		if {$opt == "-width"} {
		    if {$data(-orient) == "vertical"} continue 
		} elseif {$data(-orient) == "horizontal"} continue
		if {$val != "" && [winfo pixels $w $val] < 0} {set val 0}
		set data($opt,$bname) $val
		set update 1
	    }
	    -state {
		if {$val == "normal"} {
		    $data(disabledimage,$bname) blank
		    $b itemconfigure image -state normal
		    $b itemconfigure text -state normal
		    set data(-state,$bname) normal
		} elseif {$val == "disabled"} {
		    $data(disabledimage,$bname) copy $data(-image,$bname)
		    _disabledImage $data(disabledimage,$bname) $b
		    $b itemconfigure image -state disabled
		    $b itemconfigure text -state disabled
		    set data(-state,$bname) disabled
		} else {
		    error "bad -state value \"$val\": must be normal or disabled"
		}
	    }
	    -show {
		if {$val != 0 && $val != 1} {
		    error "bad -show value \"$val\": must be 0 or 1"
		}
		if {$data(-show,$bname) != $val} {
		    set data(-show,$bname) $val
		    ResizeButs::_setShow $w $bname
		}
	    }
	    -lockshow {
		if {$val != 0 && $val != 1} {
		    error "bad -lockshow value \"$val\": must be 0 or 1"
		}
		if $val {$w.menu entryconfigure $index -state disabled} \
		else {$w.menu entryconfigure $index -state normal}
		set data(-lockshow,$bname) $val
	    }
	    -command {
		set data(-command,$bname) $val
	    }
	    -image {
		$b itemconfigure image -image $val
		$data(disabledimage,$bname) blank
		if {$data(-state,$bname) == "disabled" && $val != ""} {
		    $data(disabledimage,$bname) copy $val
		    _disabledImage $data(disabledimage,$bname) $b
		}
		set data(-image,$bname) $val
		set update 1
	    }
	    default {error "unknown option \"$opt\""}
	}
    }
    if [info exists update] {_positionItems $w}
}

proc ResizeButs::index {w args} {
    upvar ::ResizeButs::$w data
    variable Priv

    set nargs [llength $args]
    if {$nargs < 1 || $nargs > 3} {error "wrong # args: should be \"$w index ?-strict? ?-shown? string\""}
    set strict 0
    set shown 0
    foreach arg [lrange $args 0 end-1] {
	switch -- $arg {
	    -strict {set strict 1}
	    -shown {set shown 1}
	    default {error "unknown option \"$arg\": must be -strict or -shown"}
	}
    }
    set index [lindex $args end]
    if $shown {
	set index [ResizeButs::index $w -strict $index]
	if {$index < 0} {return -1}
	set gindex $index
	for {set i 0} {$i < $index} {incr i} {
	    if !$data(-show,[winfo name [lindex $data(buts) $i]]) {incr gindex -1}
	}
	return $gindex
    }
    set end [expr {[llength $data(buts)] - 1}]
    if {$end < 0 && ![info exists Priv(insert)]} {return -1}
    switch -regexp -- $index {
	"^-?[0-9]+$" {
	    if {$index < 0} {if $strict {return -1} else {return 0}}
	    if {$index > $end} {
		if $strict {return -1} \
		elseif [info exists Priv(insert)] {return [expr {$end + 1}]} \
		else {return $end}
	    }
	    return $index
	}
	"^end$" - "^last$" {
	    if [info exists Priv(insert)] {return [expr {$end + 1}]}
	    return $end
	}
	"^@-?[0-9]+$" {
	    if {$data(-orient) == "vertical"} {
		set coord y
		set dir height
	    } else {
		set coord x
		set dir width
	    }
	    set buts [grid slaves $w.scrollregion]
	    if {[llength $buts] < 1 && ![info exists Priv(insert)]} {return -1}
	    scan $index {@%d} index
	    if {$index < 0} {if $strict {return -1} else {return 0}}
	    set total [winfo req$dir $w]
	    if {$index >= $total} {
		set end [lsearch $data(buts) [lindex $buts 0]]
		if $strict {return -1} \
		elseif [info exists Priv(insert)] {return [expr {$end + 1}]} \
		else {return $end}
	    }
	    foreach b $buts {
		if {$index >= [winfo $coord $b]} {return [lsearch $data(buts) $b]}
	    }		
	}
	default {
	    # text search
	    # -strict makes no sense here
	    set j 0
	    foreach b $data(buts) {
		if {[string match $index [$b itemcget text -text]]} {return $j}
		incr j
	    }
	    return -1
	}
    }
}

# This does -ordercommand
proc ResizeButs::invoke {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 0} {error "wrong # args: should be \"$w invoke\""}
    if {$data(-ordercommand) != ""} {
	foreach {b order} $data(-orderbutton) break
	if {$b != "" && $order != ""} {
	    uplevel #0 $data(-ordercommand) $b $order
	}
    }
}

# This does -command for the specific button
proc ResizeButs::iteminvoke {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 1} {error "wrong # args: should be \"$w iteminvoke index\""}
    set item [lindex $args 0]
    set i [ResizeButs::index $w -strict $item]
    if {$i < 0} {error "bad index number \"$item\""}
    set b [lindex $data(buts) $i]
    if {$b == ""} {error "bad index number \"$item\""}
    set bname [winfo name $b]
    if {$data(-command,$bname) != ""} {
	uplevel #0 $data(-command,$bname)
    }
}

proc ResizeButs::add {w args} {
    variable Priv

    set Priv(add) add
    eval ResizeButs::insert $w end $args
    unset Priv(add)
}

proc ResizeButs::delete {w args} {
    upvar ::ResizeButs::$w data
    variable itemspecs

    set numargs [llength $args]
    if {$numargs > 2 || $numargs == 0} {error "wrong # args: should be \"$w delete index1 ?index2?\""}
    set index1 [lindex $args 0]
    set first [ResizeButs::index $w -strict $index1]
    if {$first < 0} {error "bad index number \"$index1\""}
    if {$numargs == 1} {
	set last $first
    }
    if {$numargs == 2} {
	set index2 [lindex $args 1]
	set last [ResizeButs::index $w -strict $index2]
	if {$last < 0} {error "bad index number \"$index2\""}
    }
    if { $first > $last } {
	set tmp $first
	set first $last
	set last $tmp
    }

    set scr $w.scrollregion
    set prevend [expr {[llength [grid slaves $scr]] -1}]
    foreach b [lrange $data(buts) $first $last] {
	set bname [winfo name $b]
	image delete $data(disabledimage,$bname)
	catch {unset data(disabledimage,$bname)}
	foreach opt [array names itemspecs] {
	    catch {unset data($opt,$bname)}
	}
	destroy $b
    }

    foreach {b order} $data(-orderbutton) break
    if {$b != "" && $order != "" && $b >= $first} {
	if {$b <= $last} {
	    set data(-orderbutton) [list {} {}]
	} else {
	    incr b [expr {$first - $last - 1}]
	    set data(-orderbutton) [list $b $order]
	}
    }

    set data(buts) [lreplace $data(buts) $first $last]
    $w.menu delete $first $last

    set gindex $first
    for {set i 0} {$i < $first} {incr i} {
	if !$data(-show,[winfo name [lindex $data(buts) $i]]) {incr gindex -1}
    }
    foreach b [lrange $data(buts) $first end] {
	if !$data(-show,[winfo name $b]) continue
	grid remove $b
	if {$data(-orient) == "horizontal"} {grid $b -row 0 -column $gindex} \
	else {grid $b -row $gindex -column 0}
	incr gindex
    }
    if {$data(-side) != "right"} {
	incr gindex -1
	# gindex is now the end index
	if {$data(-orient) == "horizontal"} {set dir column} else {set dir row}
	grid ${dir}configure $scr $prevend -weight 0
	if {$gindex >= 0} {grid ${dir}configure $scr $gindex -weight 1}
    }

    _positionItems $w
}

proc ResizeButs::_FocusIn {W {idletasks 1}} {

    if {$W == "update"} {set W [focus]}
    if {[catch {winfo parent [winfo parent $W]} parent] || $parent == ""} return
    if {[winfo class $parent] != "ResizeButs"} return
    upvar ::ResizeButs::$parent data

    if $idletasks {update idletasks}
    $W delete rect
    set bd [$W cget -bd]
    set th $data(-highlightthickness)
    set d1 [expr {$bd + int($th/2)}]
#    set d2 [expr {$bd + int(ceil($th/(2+0.0)))}]
# "ceil" is not working in tcl8.4.11
	set th2 [expr {$th/(2+0.0)}]
	set intth2 [expr {int($th2)}]
	set d2 [expr {($th2 > $intth2 ? $intth2 + 1 : $intth2) + $bd}]
	
    set x2 [expr {[winfo width $W] - $d2}]
    set y2 [expr {[winfo height $W] - $d2}]
    $W create rectangle $d1 $d1 $x2 $y2 -outline $data(-highlightcolor) -width $th -tags rect -fill ""
}

proc ResizeButs::_FocusOut {W} {
    $W delete rect
}

proc ResizeButs::setfocus {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 1} {error "wrong # args: should be \"$w setfocus index\""}
    set item [lindex $args 0]
    set i [ResizeButs::index $w -strict $item]
    if {$i < 0} {error "bad index number \"$item\""}
    set b [lindex $data(buts) $i]
    if {$b == ""} {error "bad index number \"$item\""}
    focus $b
}

proc ResizeButs::_KeyPressEnter {W} {
    variable Priv

    if [info exists Priv(KeyEnterDown)] return
    set Priv(KeyEnterDown) 1
    if [info exists Priv(move)] {set move $Priv(move)}
    catch {unset Priv(move)}
    ResizeButs::_Btn1 $W
    if [info exists move] {set Priv(move) $move}
    update idletasks
    after 130
}

proc ResizeButs::_KeyReleaseEnter {W X Y} {
    variable Priv

    if ![info exists Priv(KeyEnterDown)] return
    ResizeButs::_BtnRels1 $W $X $Y
    unset Priv(KeyEnterDown)
}

proc ResizeButs::_Destroy {w} {
    upvar ::ResizeButs::$w data

    # We can't use "grid slaves" because this procedure is done after W is destroyed
    foreach name [array names data disabledimage,*] {
	image delete $data($name)
    }
    catch {
	unset data
	rename ::$w {}
    }
}

proc ResizeButs::_validarg {arg} {
    switch -- $arg {
	-bd {return -borderwidth}
	-fg {return -foreground}
	-bg {return -background}
    }
    return $arg
}

proc ResizeButs::_disabledImage {im w} {
    # cget -bg can return a colorword not recognized by images
    # This procedure takes more time than I'd like

    set colorword [$w cget -bg]
    set colordecimal [winfo rgb $w $colorword]
    set hexcolor #
    foreach dec $colordecimal {
	append hexcolor [string range [format %02X $dec] 0 1]
    }

    set h [image height $im]
    set w [image width $im]
    for {set y 0} {$y < $h} {incr y} {
	for {set x 0} {$x < $w} {incr x} {
	    if {$y & 1} {
		if {$x & 1} {$im put $hexcolor -to $x $y}
	    } elseif {!($x & 1)} {$im put $hexcolor -to $x $y}
	}
    }
}

proc ResizeButs::_positionItems {w {showBut ""}} {
    upvar ::ResizeButs::$w data
    variable Priv

    if ![llength $data(buts)] return
    set Priv(inPos) 1

    set hf 0
    set wf 0
    set others 0
    set th2 [expr {$data(-highlightthickness) * 2}]
    set bd2 [expr {$data(-borderwidth) * 2}]
    set x_org [expr {$data(-borderwidth) + $data(-highlightthickness) + 3}]
    set buts [grid slaves $w.scrollregion]
    if {$data(-side) == "right"} {set endbut [lindex $buts end]} \
    else {set endbut [lindex $buts 0]}

    foreach but $data(buts) {
	set bname [winfo name $but]
	set x $x_org
	$but coords image $x [lindex [$but coords image] 1]
	set im [$but itemcget image -image]
	if {$im != ""} {
	    set x [expr {$x + [image width $im] + 5}]
	    set hb [expr {[image height $im] + 1}]
	} else {set hb 0}
	$but coords text $x [lindex [$but coords text] 1]
	set bboxt [$but bbox text]
	foreach {x1 y1 x2 y2} $bboxt break
	set x [expr {$x + $x2 - $x1 + 5}]
	$but coords tri $x [lindex [$but coords tri] 1]
	if {$data(-orient) == "horizontal" || $data(-width) == ""} {
	    if {$data(-orient) != "horizontal" || $data(-width,$bname) == ""} {
		set wb [expr {$x - $data(-borderwidth) + 3}]
		if $data(-showtriangle) {incr wb $data(wtri)}
		if {$wb < $Priv(minwb)} {set wb $Priv(minwb)}
		incr wb $th2
	    } else {
		set wb [winfo pixels $w $data(-width,$bname)]
	    }
	} else {
	    set wb [expr {[winfo pixels $w $data(-width)] - $bd2}]
	}
	if {$data(-orient) == "vertical" || $data(-height) == ""} {
	    if {$data(-orient) != "vertical" || $data(-height,$bname) == ""} {
		set ht [expr {$y2 - $y1 + 3}]
		if {$ht > $hb} {set hb $ht}
		if {$data(-showtriangle) && $data(htri) > $hb} {set hb $data(htri)}
		if {$hb < $Priv(minhb)} {set hb $Priv(minhb)}
		incr hb $th2
	    } else {
		set hb [winfo pixels $w $data(-height,$bname)]
	    }
	} else {
	    set hb [expr {[winfo pixels $w $data(-height)] - $bd2}]
	}
	$but configure -height $hb -width $wb
	if {$data(-orient) == "vertical" && ($but != $endbut || ![winfo ismapped $endbut])} {
	    set y [expr {$hb / 2 + $data(-borderwidth)}]
	    if {!($y & 1)} {incr y -1}
	    foreach item {image text tri} {
		set x [lindex [$but coords $item] 0]
		$but coords $item $x $y
	    }
	}

	incr hb $bd2; incr wb $bd2
	if {$data(-orient) == "horizontal"} {
	    if {$hb > $hf} {set hf $hb}
	    if $data(-show,$bname) {
		incr wf $wb
		if {$but != $endbut} {incr others $wb}
	    }
	} else {
	    if $data(-show,$bname) {
		incr hf $hb
		if {$but != $endbut} {incr others $hb}
	    }
	    if {$wb > $wf} {set wf $wb}
	}
    }

    # This is needed so [winfo reqheight] and [winfo reqwidth] work for the frame
    $w.scrollregion configure -height $hf -width $wf
    if {$data(-orient) == "horizontal"} {
	if {$data(-width) != ""} {$w:cmd configure -width $data(-width) -height $hf} \
	else {$w:cmd configure -width $wf -height $hf}
    } else {
	if {$data(-height) != ""} {$w:cmd configure -height $data(-height) -width $wf} \
	else {$w:cmd configure -height $hf -width $wf}
    }

    if [winfo ismapped $w] {
	update idletasks
	set view [ResizeButs::view $w]
	set hf [winfo height $w]
	ResizeButs::_FocusIn update 0
    } else {
	set view [ResizeButs::view $w]
    }

    if {$data(-orient) == "horizontal"} {
	set y [expr {$hf / 2}]
	if {!($y & 1)} {incr y -1}
	foreach but $data(buts) {
	    foreach item {image text tri} {
		set x [lindex [$but coords $item] 0]
		$but coords $item $x $y
	    }
	}
    }
    if {$data(-scrollcommand) != ""} {
	catch {uplevel #0 $data(-scrollcommand) $view}
    }

    if {[winfo ismapped $w] && $endbut != ""} {
	foreach {first last} $view break
	if {$data(-orient) == "vertical"} {
	    if {$last == 1 && $first == 0} {set size [expr {$hf - $others}]} \
	    else {set size [expr {[$endbut cget -height] + $bd2}]}
	    set y [expr {$size / 2}]
	    if {!($y & 1)} {incr y -1}
	    foreach item {image text tri} {
		set x [lindex [$endbut coords $item] 0]
		$endbut coords $item $x $y
	    }
	}
	if {$data(-showcommand) != "" && $showBut != ""} {
	    if {$data(-orient) == "vertical"} {set dir height} else {set dir width}
	    set i [lsearch $data(buts) $showBut]
	    if {$last == 1 && $first == 0} {
		uplevel #0 $data(-showcommand) $i [winfo $dir $showBut]
	    } else {
		uplevel #0 $data(-showcommand) $i [expr {[$showBut cget -$dir] + $bd2}]
	    }
	}

	if {$data(-resizecommand) != ""} {
	    if {$showBut == $endbut} {
		if {$data(-side) == "right"} {set resizeprev [lindex $buts end-1]} \
		else {set resizeprev [lindex $buts 1]}
		if {$resizeprev != ""} {
		    if {$data(-orient) == "horizontal"} {set sizeprev [$resizeprev cget -width]} \
		    else {set sizeprev [$resizeprev cget -height]}
		    incr sizeprev $bd2
		    set i [lsearch $data(buts) $resizeprev]
		    uplevel #0 $data(-resizecommand) $i $sizeprev
		}

	    } elseif {[info exists Priv(doResize)]} {
		if {$data(-orient) == "horizontal"} {
		    if {$last == 1 && $first == 0} {set size [expr {[winfo width $w] - $others}]} \
		    else {set size [expr {[$endbut cget -width] + $bd2}]}
		}
		set i [lsearch $data(buts) $endbut]
		uplevel #0 $data(-resizecommand) $i $size
	    }
	}
    }

    catch {unset Priv(inPos)}
    # return nothing so we don't return the catch value
    return
}

proc ResizeButs::_setShow {w bname} {
    upvar ::ResizeButs::$w data

    set scr $w.scrollregion
    set b $scr.$bname
    set buts [grid slaves $scr]
    set end [expr {[llength $buts] - 1}]
    set index [lsearch $data(buts) $b]
    if {$index < 0} return
    if $data(-show,$bname) {
	if [winfo ismapped $b] return

	set gindex $index
	for {set i 0} {$i < $index} {incr i} {
	    if !$data(-show,[winfo name [lindex $data(buts) $i]]) {incr gindex -1}
	}
	set rbuts {}
	for {set i [expr {$end - $gindex}]} {$i >= 0} {incr i -1} {lappend rbuts [lindex $buts $i]}
	foreach rb $rbuts {grid remove $rb}

	if {$data(-orient) == "horizontal"} {
	    set col $gindex
	    set row 0
	    set dir column
	} else {
	    set col 0
	    set row $gindex
	    set dir row
	}

	grid $b -sticky nswe -row $row -column $col
	incr end

	foreach rb $rbuts {
	    if {$data(-orient) == "horizontal"} {incr col} else {incr row}
	    grid $rb -row $row -column $col
	}

	if {$data(-side) != "right"} {
	    grid ${dir}configure $scr $end -weight 1
	    if {$end > 0} {grid ${dir}configure $scr [expr {$end - 1}] -weight 0}
	}

	_positionItems $w $b

    } else {
	set i [lsearch $buts $b]
	if {$i < 0} return
	set gindex [expr {$end - $i}]
	grid remove $b

	for {incr i -1} {$i >= 0} {incr i -1} {
	    set b [lindex $buts $i]
	    grid remove $b
	    if {$data(-orient) == "horizontal"} {grid $b -row 0 -column $gindex} \
	    else {grid $b -row $gindex -column 0}
	    incr gindex
	}
	if {$data(-side) != "right"} {
	    incr gindex -1
	    # gindex is now the end index
	    if {$data(-orient) == "horizontal"} {set dir column} else {set dir row}
	    grid ${dir}configure $scr $end -weight 0
	    if {$gindex >= 0} {grid ${dir}configure $scr $gindex -weight 1}
	}

	if {$data(-showcommand) != ""} {
	    uplevel #0 $data(-showcommand) $index 0
	}

	_positionItems $w
    }
}

proc ResizeButs::_Btn3 {W X Y} {
    if [catch {winfo parent [winfo parent $W]} parent] return
    upvar ::ResizeButs::$parent data
    variable Priv

    if {[info exists Priv(move)] || [info exists Priv(butDown)]} return
    if !$data(-showmenu) return
    if {$data(-orient) == "vertical"} {set dir height} else {set dir width}
    set size [expr {[winfo $dir $W] - 2 * [$W cget -highlightthickness] - 2 * [$W cget -bd]}]
    if {$size <= 1} return

    set i 0
    foreach but $data(buts) {
	if !$data(-lockshow,[winfo name $but]) {	    
	    $parent.menu entryconfigure $i -state normal
	}
	incr i
    }
    set buts [grid slaves $parent.scrollregion]
    if {[llength $buts] == 1} {
	$parent.menu entryconfigure [lsearch $data(buts) [lindex $buts 0]] -state disabled
    }

    set Priv(menuUp) 1
    tk_popup $parent.menu $X $Y
    # I have to do this for some reason or events can get messed up in a toplevel
    event generate $W <ButtonRelease-1> -when now -state 264
    catch {unset Priv(menuUp)}
}

proc ResizeButs::view {w args} {
    upvar ::ResizeButs::$w data
    variable Priv

    if {$data(-orient) == "vertical"} {
	set dir height
	set c y
    } else {
	set dir width
	set c x
    }
    set numargs [llength $args]
    set scrsize [winfo req$dir $w.scrollregion]
    set wsize [winfo $dir $w]
    if {$numargs == 0} {
	if ![winfo ismapped $w] {return {0 1}}
	set coorddif [expr {[winfo root$c $w] - [winfo root$c $w.scrollregion]}]
	set first [expr {$coorddif / ($scrsize + 0.0)}]
	set last [expr {($coorddif + $wsize) / ($scrsize + 0.0)}]
	set config [place info $w.scrollregion]
	set index [lsearch $config -rel$dir]
	set relprev [lindex $config [expr {$index + 1}]]
	if {$last >= 1} {
	    if {$first <= 0} {
		if {$first < 0 || $last > 1} {
		    place $w.scrollregion -$c 0 -rel$dir 1.0
		    set Priv(doResize) 1
		} elseif {$relprev == ""} {
		    catch {unset Priv(doResize)}
		} else {
		    set Priv(doResize) 1
		}
	    } else {
		set loc [expr {$wsize - $scrsize}]
		if {$loc > 0} {
		    set first 0
		    place $w.scrollregion -$c 0 -rel$dir 1.0
		    set Priv(doResize) 1
		} else {
		    set first [expr {$loc * -1 / ($scrsize + 0.0)}]
		    place $w.scrollregion -$c $loc -rel$dir ""
		    if {$relprev == ""} {catch {unset Priv(doResize)}} \
		    else {set Priv(doResize) 1}
		}
	    }
	} else {
	    place $w.scrollregion -rel$dir ""
	    if {$relprev == ""} {catch {unset Priv(doResize)}} \
	    else {set Priv(doResize) 1}
	}
	set first [expr {$first <= 0 ? 0 : [format %.3f $first]}]
	set last [expr {$last >= 1 ? 1 : [format %.3f $last]}]
	return [list $first $last]
    }

    set cmd [lindex $args 0]
    if {$cmd == "moveto"} {
	if {$numargs != 2} {error "wrong # args: should be \"$w view moveto fraction\""}
	set fraction [lindex $args 1]
	if {![string is double -strict $fraction]} {error "expected floating-point number but got \"$fraction\""}
	if {$fraction < 0 || $fraction > 1} return
	set loc [expr {-1 * round($scrsize * $fraction)}]
    } elseif {$cmd == "scroll"} {
	if {$numargs != 3} {error "wrong # args: should be \"$w view scroll number units|pages\""}
	set number [lindex $args 1]
	if {![string is integer -strict $number]} {error "expected integer but got \"$number\""}
	set what [lindex $args 2]
	if {$what == "units"} {
	    set inc [winfo pixels $w $data(-scrollincrement)]
	    if {$inc <= 0} {
		set inc [expr {round($wsize * 0.1)}]
	    }
	} elseif {$what == "pages"} {
	    set inc [expr {round($wsize * 0.9)}]
	} else {error "bad argument \"$what\": must be units or pages"}
	set dist [expr {$number * $inc}]
	if !$dist return
	set loc [expr {[winfo root$c $w.scrollregion] - [winfo root$c $w] - $dist}]
    } else {error "unknown option \"$cmd\": must be moveto or scroll"}
    set limit [expr {$wsize - $scrsize}]
    if {$loc < $limit} {set loc $limit}
    if {$loc > 0} {set loc 0}
    place $w.scrollregion -$c $loc

    if {$data(-scrollcommand) != ""} {
	if [winfo ismapped $w] {update idletasks}
	catch {uplevel #0 $data(-scrollcommand) [ResizeButs::view $w]}
    }
    # return nothing so we don't return the catch value
    return
}

proc ResizeButs::_Configure {w width height} {
    upvar ::ResizeButs::$w data
    variable Priv

    if [info exists Priv(inPos)] return

    # The only problem is that -height or -width may be equal to nothing
    # Then, it will think it was changed when it wasn't
    if {$height != $data(-height) || ($width != $data(-width) && $data(-orient) == "horizontal")} {
	_positionItems $w
    }
}

proc ResizeButs::visible {w args} {
    upvar ::ResizeButs::$w data

    if {[llength $args] != 0} {error "wrong # args: should be \"$w visible\""}
    set vis ""
    set i 0
    foreach but $data(buts) {
	if {$data(-show,[winfo name $but])} {lappend vis $i} 
	incr i
    }
    return $vis
}

# This needs to be at the end
regsub -all {::ResizeButs::(_+[^ ]*)?} [info commands ResizeButs::*] {} ::ResizeButs::Priv(coms)
set ::ResizeButs::Priv(coms) [lsort [eval list $::ResizeButs::Priv(coms)]]
return

# Make a command to return each button's width
# Make a comand to reurn the requested scrollregion's width
# moving the last button border remembers the motion in one direction
# resizing the second to last border with the slider all the way to the right makes it remember the motion in one direction

# have insert do resizecommand within positionItems

# maybe add -confine option so that scrollregion is never bigger than the frame.  It will resize frame.

