# tabs.tcl --
#
#

namespace eval NSTabs {

proc NSTabs {oop parent} {

	Info $oop parent $parent
	Info $oop nextId 0
	Info $oop id {}
	Info $oop totalWidth 0
	Info $oop tabWidth {}
	Info $oop current -1
	Info $oop invokeCmd ""
	Info $oop font {{MS Sans Serif} 8}
	Info $oop active 0

	InitDisplay $oop

	set canvas [Info $oop canvas]
	bindtags $canvas [concat [bindtags $canvas] TabsBindTag($oop)]
	bind TabsBindTag($oop) <Destroy> "
		NSObject::Delete NSTabs $oop
	"
}

proc Info {oop info args} {

	global NSTabs

	# Set info
	if {[llength $args]} {
		switch -- $info {
			default {
				set NSTabs($oop,$info) [lindex $args 0]
			}
		}

	# Get info
	} else {
		switch -- $info {
			default {
				return $NSTabs($oop,$info)
			}
		}
	}
}

proc InitDisplay oop {

	set parent [Info $oop parent]
	set canvas $parent.tabs$oop
	canvas $canvas \
		-height 24 -width 0 -scrollregion {0 0 1000 21} -highlightthickness 0

	$canvas create line 0 22 1000 22 -fill White -width 1.0 -tags ridge
	$canvas create line 0 23 1000 23 -fill #E0E0E0 -width 1.0 -tags ridge

	Info $oop canvas $canvas
}

proc Add {oop text} {

	set xoffset 2

	set canvas [Info $oop canvas]
	set index [Info $oop nextId]
	set x [expr [Info $oop totalWidth] + $xoffset]

	# Find the text width
	set width [expr [font measure [Info $oop font] $text] + 8 * 2]

	# Keep a list of tab widths
	set tabWidth [Info $oop tabWidth]
	lappend tabWidth $width
	Info $oop tabWidth $tabWidth

	set bg [$canvas cget -background]

	# Outer line
	$canvas create line $x 22 $x 6 [expr $x + 2] 4 [expr $x + $width - 2] 4 \
		-fill White -width 1.0 -tags tab$index
	$canvas create line [expr $x + $width - 2] 5 [expr $x + $width - 1] 6 \
		[expr $x + $width - 1] 23 -fill Black -width 1.0 -tags tab$index

	# Inner line
	$canvas create line [expr $x + 1] 22 [expr $x + 1] 6 [expr $x + 2] 5 \
		[expr $x + $width - 2] 5 -fill #E0E0E0 -width 1.0 -tags tab$index
	$canvas create line [expr $x + $width - 2] 6 \
		[expr $x + $width - 2] 23 -fill #808080 -width 1.0 -tags tab$index

	# Rectangle
	$canvas create rectangle [expr $x + 2] 6 [expr $x + $width - 2] 22 \
		-outline "" -fill $bg -tags tab$index

	# Text
	$canvas create text [expr $x + $width / 2.0] 13 -anchor center \
		-font [Info $oop font] -text $text -tags [list tab$index text$index]

	$canvas bind tab$index <ButtonPress-1> "
		NSTabs::Invoke $oop $index
	"
	$canvas bind tab$index <Control-ButtonPress-1> "
		NSTabs::Dump $oop
	"

	Info $oop totalWidth [expr [Info $oop totalWidth] + $width]
	$canvas configure -width [expr [Info $oop totalWidth] + $xoffset + 3]
	Info $oop nextId [expr $index + 1]

	set id [Info $oop id]
	Info $oop id [lappend id $index]

	if {[Info $oop current] != -1} {
		$canvas raise ridge
		$canvas raise tab[Info $oop current]
	}

	return $index
}

proc SetText {oop index text} {

	set canvas [Info $oop canvas]

	set idx [lsearch -exact [Info $oop id] $index]
	if {$idx == -1} {
		error "can't find tab with id \"$index\""
	}
	set widthOld [lindex [Info $oop tabWidth] $idx]

	# Set the text
	$canvas itemconfigure text$index -text $text

	# Calculate the new width
	set widthNew [expr [font measure [Info $oop font] $text] + 8 * 2]

	# Calculate the difference in old/new width
	set widthDiff [expr $widthNew - $widthOld]

	if !$widthDiff return

	# Move tabs by difference in tab widths
	foreach id2 [Info $oop id] {
		if {$id2 <= $index} continue
		$canvas move tab$id2 $widthDiff 0
	}

	# Resize this tab
	IncrTabSize $oop $index 0 0 $widthDiff 0

	# Update width of this tab
	Info $oop tabWidth [lreplace [Info $oop tabWidth] $idx $idx $widthNew]

	# Remember out current width
	Info $oop totalWidth [expr [Info $oop totalWidth] + $widthDiff]

	# Hack -- Set canvas width
	set xoffset 2
	$canvas configure -width [expr [Info $oop totalWidth] + $xoffset + 3]
}

proc Remove {oop index} {

	set canvas [Info $oop canvas]
	set idx [lsearch -exact [Info $oop id] $index]
	if {$idx == -1} {
		error "can't find tab with id \"$index\""
	}
	set width [lindex [Info $oop tabWidth] $idx]

	$canvas delete tab$index
	set id [Info $oop id]
	set idx [lsearch -exact $id $index]
	set id [lreplace $id $idx $idx]
	Info $oop id $id

	set tabWidth [lreplace [Info $oop tabWidth] $idx $idx]
	Info $oop tabWidth $tabWidth

	# Move tabs to right left by width of removed tab
	foreach id2 $id {
		if {$id2 < $index} continue
		$canvas move tab$id2 -$width 0
	}

	# Remember out current width
	Info $oop totalWidth [expr [Info $oop totalWidth] - $width]

	# If the selected tab is removed, select the first tab
	if {$index == [Info $oop current] && [llength $id]} {
		Bigger $oop [lindex $id 0]
		Info $oop current [lindex $id 0]
	}

	set xoffset 2
	$canvas configure -width [expr [Info $oop totalWidth] + $xoffset + 3]
}

proc Invoke {oop index} {

	if {$index == [Info $oop current]} return

	set canvas [Info $oop canvas]

	if {[Info $oop active]} {
		Smaller $oop [Info $oop current]
		Bigger $oop $index
		Info $oop current $index
	}

	set command [Info $oop invokeCmd]
	if {[string length $command]} {
		uplevel #0 eval $command $oop $index
	}
}

proc IncrTabSize {oop index left top right bottom} {

	set canvas [Info $oop canvas]

	set items [$canvas find withtag tab$index]

	set lineId [lindex $items 0]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + $left]
	set y1 [expr [lindex $coords 1] + $bottom]
	set x2 [expr [lindex $coords 2] + $left]
	set y2 [expr [lindex $coords 3] + $top]
	set x3 [expr [lindex $coords 4] + $left]
	set y3 [expr [lindex $coords 5] + $top]
	set x4 [expr [lindex $coords 6] + $right]
	set y4 [expr [lindex $coords 7] + $top]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 1]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + $right]
	set y1 [expr [lindex $coords 1] + $top]
	set x2 [expr [lindex $coords 2] + $right]
	set y2 [expr [lindex $coords 3] + $top]
	set x3 [expr [lindex $coords 4] + $right]
	set y3 [expr [lindex $coords 5] + $bottom]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3

	set lineId [lindex $items 2]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + $left]
	set y1 [expr [lindex $coords 1] + $top]
	set x2 [expr [lindex $coords 2] + $left]
	set y2 [expr [lindex $coords 3] + $top]
	set x3 [expr [lindex $coords 4] + $left]
	set y3 [expr [lindex $coords 5] + $top]
	set x4 [expr [lindex $coords 6] + $right]
	set y4 [expr [lindex $coords 7] + $top]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 3]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + $right]
	set y1 [expr [lindex $coords 1] + $top]
	set x2 [expr [lindex $coords 2] + $right]
	set y2 [expr [lindex $coords 3] + $bottom]
	$canvas coords $lineId $x1 $y1 $x2 $y2

	set rectId [lindex $items 4]
	set coords [$canvas coords $rectId]
	set x1 [expr [lindex $coords 0] + $left]
	set y1 [expr [lindex $coords 1] + $top]
	set x2 [expr [lindex $coords 2] + $right]
	set y2 [expr [lindex $coords 3] + $bottom]
	$canvas coords $rectId $x1 $y1 $x2 $y2

	set textId [lindex $items 5]
	set dw [expr ($left + $right) / 2.0]
	set dh [expr ($top + $bottom) / 2.0]

	$canvas move $textId $dw $dh
}

proc Bigger {oop index} {

	set canvas [Info $oop canvas]

	set items [$canvas find withtag tab$index]

	set lineId [lindex $items 0]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] - 2]
	set y1 [lindex $coords 1]
	set x2 [expr [lindex $coords 2] - 2]
	set y2 [expr [lindex $coords 3] - 2]
	set x3 [expr [lindex $coords 4] - 2]
	set y3 [expr [lindex $coords 5] - 2]
	set x4 [expr [lindex $coords 6] + 2]
	set y4 [expr [lindex $coords 7] - 2]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 1]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + 2]
	set y1 [expr [lindex $coords 1] - 2]
	set x2 [expr [lindex $coords 2] + 2]
	set y2 [expr [lindex $coords 3] - 2]
	set x3 [expr [lindex $coords 4] + 2]
	set y3 [lindex $coords 5]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3

	set lineId [lindex $items 2]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] - 2]
	set y1 [lindex $coords 1]
	set x2 [expr [lindex $coords 2] - 2]
	set y2 [expr [lindex $coords 3] - 2]
	set x3 [expr [lindex $coords 4] - 2]
	set y3 [expr [lindex $coords 5] - 2]
	set x4 [expr [lindex $coords 6] + 2]
	set y4 [expr [lindex $coords 7] - 2]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 3]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + 2]
	set y1 [expr [lindex $coords 1] - 2]
	set x2 [expr [lindex $coords 2] + 2]
	set y2 [lindex $coords 3]
	$canvas coords $lineId $x1 $y1 $x2 $y2

	set rectId [lindex $items 4]
	set coords [$canvas coords $rectId]
	set x1 [expr [lindex $coords 0] - 2]
	set y1 [expr [lindex $coords 1] - 2]
	set x2 [expr [lindex $coords 2] + 2]
	set y2 [expr [lindex $coords 3] + 2]
	$canvas coords $rectId $x1 $y1 $x2 $y2

	set textId [lindex $items 5]
	$canvas move $textId 0 -2

	$canvas raise ridge
	$canvas raise tab$index
}

proc Smaller {oop index} {

	set canvas [Info $oop canvas]

	set items [$canvas find withtag tab$index]

	set lineId [lindex $items 0]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + 2]
	set y1 [lindex $coords 1]
	set x2 [expr [lindex $coords 2] + 2]
	set y2 [expr [lindex $coords 3] + 2]
	set x3 [expr [lindex $coords 4] + 2]
	set y3 [expr [lindex $coords 5] + 2]
	set x4 [expr [lindex $coords 6] - 2]
	set y4 [expr [lindex $coords 7] + 2]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 1]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] - 2]
	set y1 [expr [lindex $coords 1] + 2]
	set x2 [expr [lindex $coords 2] - 2]
	set y2 [expr [lindex $coords 3] + 2]
	set x3 [expr [lindex $coords 4] - 2]
	set y3 [lindex $coords 5]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3

	set lineId [lindex $items 2]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] + 2]
	set y1 [lindex $coords 1]
	set x2 [expr [lindex $coords 2] + 2]
	set y2 [expr [lindex $coords 3] + 2]
	set x3 [expr [lindex $coords 4] + 2]
	set y3 [expr [lindex $coords 5] + 2]
	set x4 [expr [lindex $coords 6] - 2]
	set y4 [expr [lindex $coords 7] + 2]
	$canvas coords $lineId $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4

	set lineId [lindex $items 3]
	set coords [$canvas coords $lineId]
	set x1 [expr [lindex $coords 0] - 2]
	set y1 [expr [lindex $coords 1] + 2]
	set x2 [expr [lindex $coords 2] - 2]
	set y2 [lindex $coords 3]
	$canvas coords $lineId $x1 $y1 $x2 $y2

	set rectId [lindex $items 4]
	set coords [$canvas coords $rectId]
	set x1 [expr [lindex $coords 0] + 2]
	set y1 [expr [lindex $coords 1] + 2]
	set x2 [expr [lindex $coords 2] - 2]
	set y2 [expr [lindex $coords 3] - 2]
	$canvas coords $rectId $x1 $y1 $x2 $y2

	set textId [lindex $items 5]
	$canvas move $textId 0 2
}

proc Dump oop {

	set canvas [Info $oop canvas]

	foreach id [Info $oop id] {
		append result "'[$canvas coords text$id]' "
	}
	dbwin "NSTags3::Dump($oop) $result\n"
}

# namespace eval NSTabs
}

if 0 {

set win .tabs
toplevel $win
set tabsId [NSObject::New NSTabs $win]
NSTabs::Info $tabsId active 1
pack [NSTabs::Info $tabsId canvas] -side top
NSTabs::Add $tabsId Queue
NSTabs::Add $tabsId Threads
NSTabs::Add $tabsId Downloads
NSTabs::Add $tabsId Failures
NSTabs::Info $tabsId current 2
NSTabs::Bigger $tabsId 2

set canvas $win.canvas
canvas $canvas -height 100 -highlightthickness 0
pack $canvas -side top -fill both

}
