# alternate.tcl --
#
#	The Alternate Editor Window and related commands.
#

namespace eval NSAlternate {

# NSAlternate::InitModule --
#
#	One-time-only-ever initialization.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitModule {} {

	NSModule::LoadIfNeeded NSIconBrowser
	NSObject::New NSAlternate
}

# NSAlternate:: --
#
#	Description.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NSAlternate oop {

	global Windows

	Info $oop alternate,current -1
	Info $oop frame,current -1
	Info $oop alternate,current2 -1
	Info $oop frame,current2 -1

	InitWindow $oop

	set win [Info $oop win]

	NSWindowManager::RegisterWindow alternate $win \
		"NSAlternate::GeometryCmd $oop" "" "NSAlternate::DisplayCmd $oop"

	bind $win <KeyPress-Escape> "NSAlternate::Close $oop"
	bind $win <Control-KeyPress-w> "NSAlternate::Close $oop"

	bind $win <KeyPress-n> "NSAlternate::NewAlternate $oop"
#	bind $win <KeyPress-plus> "NSAlternate::NewFrame $oop"
#	bind $win <KeyPress-minus> "NSAlternate::DeleteFrame $oop"

	#
	# Global list of application windows
	#

	set Windows(alternate,win) [Info $oop win]
	set Windows(alternate,class) NSAlternate
	set Windows(alternate,oop) $oop
}

# NSAlternateWindow::~NSAlternate --
#
#	Object destructor called by NSObject::Delete().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ~NSAlternate oop {

	NSValueManager::RemoveClient listBG [Info $oop alternate,clientId]
	NSValueManager::RemoveClient listBG [Info $oop frame,clientId]
}

# NSAlternate::Info --
#
#	Query and modify info.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Info {oop info args} {

	global NSAlternate

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

	# Get info
	} else {
		switch -- $info {
			alternateCanvas {
				set canvistId [Info $oop alternate,canvistId]
				return [NSCanvist2::Info $canvistId canvas]
			}
			frameCanvas {
				set canvistId [Info $oop frame,canvistId]
				return [NSCanvist2::Info $canvistId canvas]
			}
			default {
				return $NSAlternate($oop,$info)
			}
		}
	}
}

# NSAlternate::Init Window --
#
#	Description.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitWindow oop {

	global NSAlternate
	global Windows

	set win .alternate$oop
	toplevel $win
	wm title $win "Alternate Editor"

	wm transient $win $Windows(main,win)

	# Start out withdrawn (hidden)
	wm withdraw $win

	# Do stuff when window closes
	wm protocol $win WM_DELETE_WINDOW "NSAlternate::Close $oop"

	Info $oop win $win

	# Menus
	InitMenus $oop

	frame $win.divider1 \
		-borderwidth 1 -height 2 -relief sunken

	# Frame around alternate list, frame list, etc on the left
	set frame $win.frame
	frame $frame \
		-borderwidth 0

	set iconSize [expr [icon size] + 8]

	# The list of alternates
	set frameAlternate $frame.frameAlternate
	frame $frameAlternate \
		-borderwidth 1 -relief sunken
	set canvistId [NSObject::New NSCanvist2 $frameAlternate $iconSize $iconSize 240 160]
	NSCanvist2::Info $canvistId newItemCmd \
		"NSIconBrowser::NewItemCmd $oop"
	NSCanvist2::Info $canvistId highlightCmd \
		"NSIconBrowser::HighlightItemCmd $oop"
	NSCanvist2::Info $canvistId columns 6
	set canvas [NSCanvist2::Info $canvistId canvas]
	scrollbar $frameAlternate.yscroll \
		-borderwidth 0 -command "$canvas yview" -orient vertical
	bind $frameAlternate.yscroll <Map> "eval %W set \[$canvas yview]"

	$canvas configure -background [NSColorPreferences::Get listBG]
	$canvas configure -yscrollcommand "$frameAlternate.yscroll set"

	# When a alternate is selected, show the frames of it
	NSCanvist2::Info $canvistId selectionCmd \
		"NSAlternate::SelectionChanged_Alternate $oop"

	# This call updates the list background color whenever the
	# global list background color changes
	Info $oop alternate,clientId \
		[NSValueManager::AddClient listBG "ListBackgroundChanged $canvas"]

	Info $oop alternate,canvistId $canvistId

	pack $canvas \
		-side left -expand yes -fill both -anchor nw
	pack $frameAlternate.yscroll \
		-side left -fill y

	frame $frame.divider2 \
		-borderwidth 1 -height 2 -relief sunken

	# The list of frames in a alternate
	set frameFrame $frame.frameFrame
	frame $frameFrame \
		-borderwidth 1 -relief sunken
	set canvistId [NSObject::New NSCanvist2 $frameFrame $iconSize $iconSize 240 $iconSize]
	NSCanvist2::Info $canvistId newItemCmd \
		"NSIconBrowser::NewItemCmd $oop"
	NSCanvist2::Info $canvistId highlightCmd \
		"NSIconBrowser::HighlightItemCmd $oop"
	NSCanvist2::Info $canvistId columns 1
	set canvas [NSCanvist2::Info $canvistId canvas]
	scrollbar $frameFrame.xscroll \
		-borderwidth 0 -command "$canvas xview" -orient horizontal
	bind $frameFrame.xscroll <Map> "eval %W set \[$canvas xview]"
	$canvas configure -background [NSColorPreferences::Get listBG]
	$canvas configure -xscrollcommand "$frameFrame.xscroll set"

	NSCanvist2::Info $canvistId selectionCmd \
		"NSAlternate::SelectionChanged_Frame $oop"

	# This call updates the list background color whenever the
	# global list background color changes
	Info $oop frame,clientId \
		[NSValueManager::AddClient listBG "ListBackgroundChanged $canvas"]

	Info $oop frame,canvistId $canvistId

	pack $canvas \
		-side top -expand yes -fill both -anchor nw
	pack $frameFrame.xscroll \
		-side top -fill x

	# Geometry of stuff on the left
	grid rowconfig $frame 0 -weight 1 -minsize 0
	grid rowconfig $frame 1 -weight 0 -minsize 0
	grid rowconfig $frame 2 -weight 0 -minsize 0
	grid columnconfig $frame 0 -weight 1 -minsize 0
	grid $frameAlternate \
		-row 0 -column 0 -rowspan 1 -columnspan 1 -sticky news
	grid $frame.divider2 \
		-row 1 -column 0 -rowspan 1 -columnspan 1 -sticky ew \
		-padx 2 -pady 2
	grid $frameFrame \
		-row 2 -column 0 -rowspan 1 -columnspan 1 -sticky ew

	# An NSIconBrowser lets the user examine all icon types
	set browserId [NSObject::New NSIconBrowser $win]
	set canvistId [NSIconBrowser::Info $browserId member,canvistId]
	NSCanvist2::Info $canvistId selectionCmd \
		"NSAlternate::SelectionChanged_Icon $oop"

	# Display progress while listing an icon type
	NSIconBrowser::Info $browserId clientCmd \
		"NSAlternate::BrowserCmd $oop"

	Info $oop browserId $browserId

	#
	# Statusbar
	#

	frame $win.statusBar -relief flat -borderwidth 0
	label $win.statusBar.label -anchor w -relief sunken -padx 2
	label $win.statusBar.label2 -anchor w -relief sunken -padx 2 -width 20
	pack $win.statusBar -side top -fill x -anchor w
	pack $win.statusBar.label -side left -expand yes -fill both
	pack $win.statusBar.label2 -side right -expand no

	# Progress bar used to display progress of listing icons
	set progId [NSObject::New NSProgress2 $win.statusBar.label 225 10 {} {}]
	[NSProgress2::Info $progId frame] configure -borderwidth 0
	Info $oop progId $progId

	#
	# Geometry
	#

	grid rowconfig $win 0 -weight 0 -minsize 0
	grid rowconfig $win 1 -weight 1 -minsize 0
	grid rowconfig $win 2 -weight 0 -minsize 0
	grid columnconfig $win 0 -weight 1 -minsize 0
	grid columnconfig $win 1 -weight 0 -minsize 0
	grid columnconfig $win 2 -weight 1 -minsize 0
 
	grid $win.divider1 \
		-row 0 -column 0 -rowspan 1 -columnspan 3 -sticky ew \
		-padx 2 -pady 2
	grid $frame \
		-row 1 -column 0 -rowspan 1 -columnspan 1 -sticky news
	grid [frame $win.divider2 -borderwidth 1 -relief sunken -width 2] \
		-row 1 -column 1 -rowspan 1 -columnspan 1 -sticky ns \
		-padx 4 -pady 2
	grid [NSIconBrowser::Info $browserId frame] \
		-row 1 -column 2 -rowspan 1 -columnspan 1 -sticky news
	grid $win.statusBar \
		-row 2 -column 0 -rowspan 1 -columnspan 3 -sticky ew

	# Destroy the object along with the toplevel
	bind $win <Destroy> "+
		if !\[string compare %W $win] {
			NSObject::Delete NSAlternate $oop
		}
	"
}

# NSAlternate::InitMenus --
#
#	Create menus in the toplevel associated with this object.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitMenus oop {

	set win [Info $oop win]
	set mod "Ctrl"

	#
	# Menu bar
	#

	set menuDef "-tearoff 0 -postcommand \"NSAlternate::SetupMenus $oop\" -identifier MENUBAR"
	set mbar [NSObject::New NSMenu $win $menuDef]
	Info $oop mbar $mbar

	#
	# Alternate Menu
	#

	NSObject::New NSMenu $mbar {-tearoff 0 -identifier MENU_SPRITE}
	NSMenu::MenuInsertEntry $mbar -end MENUBAR {-type cascade \
		-menu MENU_SPRITE -label "Alternate" -underline 0 -identifier M_SPRITE}

	set entries {}
	lappend entries "-type command -label \"New Alternate\" -accelerator n \
		-command \"NSAlternate::NewAlternate $oop\" -identifier E_NEW"
#	lappend entries "-type command -label \"Insert Frame\" -accelerator plus \
#		-command \"NSAlternate::NewFrame $oop\" -identifier E_INSERT_FRAME"
#	lappend entries "-type command -label \"Delete Frame\" -accelerator minus \
#		-command \"NSAlternate::DeleteFrame $oop\" -identifier E_DELETE_FRAME"
	lappend entries "-type separator"
	lappend entries "-type command -label \"Close\" \
		-command \"NSAlternate::Close $oop\" -underline 0 \
		-accelerator $mod+W -identifier E_CLOSE"

	NSMenu::MenuInsertEntries $mbar -end MENU_SPRITE $entries

	#
	# Reason Menu
	#

	NSObject::New NSMenu $mbar {-tearoff 0 -identifier MENU_REASON}
	NSMenu::MenuInsertEntry $mbar -end MENUBAR {-type cascade \
		-menu MENU_REASON -label "Reason" -underline 0 \
		-identifier M_REASON}

	set entries {}
	lappend entries "-type radiobutton -label \"None\" \
		-command \"NSAlternate::ConfigAlternate $oop reason none\" \
		-variable NSAlternate($oop,radio,reason) -value none \
		-identifier E_REASON_NONE"
	lappend entries "-type radiobutton -label \"Feature\" \
		-command \"NSAlternate::ConfigAlternate $oop reason feature\" \
		-variable NSAlternate($oop,radio,reason) -value feature \
		-identifier E_REASON_FEATURE"
	lappend entries "-type radiobutton -label \"Ident\" \
		-command \"NSAlternate::ConfigAlternate $oop reason ident\" \
		-variable NSAlternate($oop,radio,reason) -value ident \
		-identifier E_REASON_IDENT"
	lappend entries "-type radiobutton -label \"Number\" \
		-command \"NSAlternate::ConfigAlternate $oop reason number\" \
		-variable NSAlternate($oop,radio,reason) -value number \
		-identifier E_REASON_NUMBER"

	NSMenu::MenuInsertEntries $mbar -end MENU_REASON $entries
}

# NSAlternate::SetupMenus --
#
#	Prepare to post the menus.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SetupMenus {oop mbarID} {

	set alternateIndex [Info $oop alternate,current]
	set frameIndex [Info $oop frame,current]

	lappend identList E_NEW E_CLOSE
	if {$alternateIndex != -1} {
		lappend identList E_REASON_NONE E_REASON_NUMBER \
			E_REASON_IDENT E_REASON_FEATURE
#		if {($frameIndex != -1) && ([alternate count $alternateIndex] > 2)} {
#			lappend identList E_DELETE_FRAME
#		}
	}

	NSMenu::MenuEnable $mbarID $identList
}

# NSAlternate::DisplayCmd --
#
#	Called by NSWindowManager::Display().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc DisplayCmd {oop message first} {

	switch -- $message {
		preDisplay {
			Map $oop
		}
		postDisplay {
			if $first {
				set browserId [Info $oop browserId]
				set canvistId [NSIconBrowser::Info $browserId group,canvistId]
				NSIconBrowser::SetList_Group $browserId
				NSCanvist2::UpdateSelection $canvistId 0 ""
			}
		}
		postWithdraw {
			Unmap $oop
		}
	}
}

# NSAlternate::GeometryCmd --
#
#	Called by NSWindowManager::Setup(). Returns the desired (default)
#	geometry for the window.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc GeometryCmd oop {

	global Windows

	set win [Info $oop win]
	set winMain $Windows(main,win)
	set x [winfo x $winMain]
	set y [winfo y $winMain]
	set width [winfo width $win]
	set height [winfo height $win]
	return ${width}x$height+$x+$y
}

# NSAlternate::Close --
#
#	Description.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Close oop {

	NSWindowManager::Undisplay alternate
}

# NSAlternate::Map --
#
#	Do something when the toplevel is mapped.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Map oop {

	SetAlternateList $oop

	# Restore the selected alternate
	set current [Info $oop alternate,current2]
	set canvistId [Info $oop alternate,canvistId]
	if {$current != -1} {
		NSCanvist2::UpdateSelection $canvistId $current {}
		NSCanvist2::See $canvistId $current
	}

	# Restore the selected frame
	set current [Info $oop frame,current2]
	set canvistId [Info $oop frame,canvistId]
	if {$current != -1} {
		NSCanvist2::UpdateSelection $canvistId $current {}
		NSCanvist2::See $canvistId $current
	}
}

# NSAlternate::Unmap --
#
#	Do something when unmapping the window.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Unmap oop {

	# Because we are clearing the lists here, and don't want to
	# upset the user, we save the selected alternate/frame so it can
	# be restored in Map() below.
	Info $oop alternate,current2 [Info $oop alternate,current]
	Info $oop frame,current2 [Info $oop frame,current]

	NSCanvist2::DeleteAll [Info $oop alternate,canvistId]
}

# NSAlternate::SetAlternateList --
#
#	.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SetAlternateList oop {

	set win [Info $oop win]
	set canvistId [Info $oop alternate,canvistId]

	# Clear the list
	NSCanvist2::DeleteAll $canvistId
	
	# Get the number of alternates */
	set max [alternate count]

	# Add each alternate to the list
	for {set i 0} {$i < $max} {incr i} {

		# Append match to the list
		NSCanvist2::Append $canvistId alternate $i
	}
}

# NSAlternate::SelectionChanged_Alternate --
#
#	When a alternate is selected, display the frames (icons) in that alternate.
#	Otherwise clear the frames list.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SelectionChanged_Alternate {oop canvistId select deselect} {

	set win [Info $oop win]

	# No alternate was selected
	if {![llength $select]} {

		# Clear the frame list
		set canvistId [Info $oop frame,canvistId]
		NSCanvist2::DeleteAll $canvistId

		# No alternate is selected now
		Info $oop alternate,current -1
		return
	}

	# Get the (first) cell
	set index [lindex $select 0]

	# Radiobutton menu entries
	Info $oop radio,reason [alternate configure $index -reason]

	# Display icons in that alternate
	SetFrameList $oop $index 0

	# Remember which alternate is selected
	Info $oop alternate,current $index
}

# NSAlternate::SelectionChanged_Frame --
#
#	.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SelectionChanged_Frame {oop canvistId select deselect} {

	if {![llength $select]} {

		# No frame is selected now
		Info $oop frame,current -1
		return
	}

	# Remember which frame is selected
	set frameIndex [lindex $select 0]
	Info $oop frame,current $frameIndex

	# Get the icon for that frame
	set icon [lindex [alternate get [Info $oop alternate,current] $frameIndex] 0]

	# Select the frame in the icon browser, if the type is shown
	set browserId [Info $oop browserId]
	set iconType [NSIconBrowser::Info $browserId iconType]
	if {![string compare $iconType [lindex $icon 0]]} {
		NSIconBrowser::SeeIcon $browserId $iconType [lindex $icon 1]
	}
}

# NSAlternate::SelectionChanged_Icon --
#
#	When an icon is selected, change the icon assigned to the selected
#	frame.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SelectionChanged_Icon {oop canvistId select deselect} {

	# Do nothing if no new cell was selected
	if {![llength $select]} return

	set selectedAlternate [Info $oop alternate,current]
	if {$selectedAlternate < 0} return
	set selectedFrame [Info $oop frame,current]
	if {$selectedFrame < 0} return

	# Get the (first) cell
	set index [lindex $select 0]

	# Get the type of icon to assign
	set browserId [Info $oop browserId]
	set iconType [NSIconBrowser::Info $browserId iconType]

	# Assign the icon to the frame
	alternate assign $selectedAlternate $selectedFrame -type $iconType -index $index

	# Scroll the frame into view if it isn't already
	NSCanvist2::See [Info $oop frame,canvistId] $selectedFrame

	# Update the alternate list if needed
	if !$selectedFrame {
		set icon [lindex [alternate get $selectedAlternate 0] 0]
		eval UpdateList $oop alternate $selectedAlternate $icon
	}

	# Update the frame list
	UpdateList $oop frame $selectedFrame $iconType $index
}

# NSAlternate::UpdateList --
#
#	Configure the Widget canvas item on the row of a list.
#	When the user assigns an icon to a frame, we want to update
#	the frame list, and sometimes the alternate list too.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc UpdateList {oop list cell type index} {

	global NSCanvist2

	set canvistId [Info $oop $list,canvistId]
	set canvas [Info $oop ${list}Canvas]
	set cellTag [lindex [NSCanvist2::Info $canvistId cellTags] $cell]
	foreach itemId [$canvas find withtag $cellTag] {
		if {[$canvas type $itemId] == "widget"} break
	}
	$canvas itemconfigure $itemId -type $type -index $index
}

# NSAlternate::SetFrameList --
#
#	.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SetFrameList {oop alternateIndex preserve} {

	set win [Info $oop win]
	set canvistId [Info $oop frame,canvistId]
	set canvas [Info $oop frameCanvas]

	# Sometimes maintain the selection and scroll position
	if $preserve {
		set columnWidth [$canvas cget -xscrollincrement]
		set colLeft [expr int([$canvas canvasx 0 $columnWidth] / $columnWidth)]
		set rowHeight [$canvas cget -yscrollincrement]
		set rowTop [expr int([$canvas canvasy 0 $rowHeight] / $rowHeight)]
		set selection [NSCanvist2::Selection $canvistId]
	}

	# Clear the list
	NSCanvist2::DeleteAll $canvistId

	NSCanvist2::Info $canvistId columns [alternate count $alternateIndex]

	# Add each frame to the list
	foreach frame [alternate get $alternateIndex] {

		# Append icon to the list
		NSCanvist2::Append $canvistId [lindex $frame 0] [lindex $frame 1]
	}

	if $preserve {
		$canvas xview scroll $colLeft units
		$canvas yview scroll $rowTop units
		NSCanvist2::UpdateSelection $canvistId $selection {}
	}
}

# NSAlternate::NewAlternate --
#
#	.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NewAlternate oop {

	set canvistId [Info $oop alternate,canvistId]

	# Every alternate must have at least 2 frames, or else!
	set alternateIndex [alternate create none]
	alternate insert $alternateIndex 0 -type default -index 0
	alternate insert $alternateIndex 1 -type default -index 0

	# Display the new alternate and select it
	SetAlternateList $oop
	NSCanvist2::UpdateSelection $canvistId $alternateIndex {}
	NSCanvist2::See $canvistId $alternateIndex

	# Select the first new frame
	set canvistId [Info $oop frame,canvistId]
	NSCanvist2::UpdateSelection $canvistId 0 {}
	NSCanvist2::See $canvistId 0
}

# NSAlternate::NewFrame --
#
#	Insert a new (blank) frame into the selected alternate.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NewFrame oop {

	set selectedAlternate [Info $oop alternate,current]
	if {$selectedAlternate < 0} return

	# Currently, only 2 frames are used
	if {[alternate count $selectedAlternate] == 2} {
		tk_messageBox -icon warning -title "Insert Frame" \
			-message "An alternate only requires 2 frames!"
		return
	}

	set canvistId [Info $oop frame,canvistId]

	set frameIndex [Info $oop frame,current]
	if {$frameIndex == -1} {
		set frameIndex [alternate count $selectedAlternate]
	}
	alternate insert $selectedAlternate $frameIndex -type default -index 0

	# Display icons in that alternate
	SetFrameList $oop $selectedAlternate 0

	NSCanvist2::UpdateSelection $canvistId $frameIndex {}
	NSCanvist2::See $canvistId $frameIndex
}

# NSAlternate::DeleteFrame --
#
#	Delete the selected frame.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc DeleteFrame oop {

	set alternateIndex [Info $oop alternate,current]
	if {$alternateIndex < 0} return
	set frameIndex [Info $oop frame,current]
	if {$frameIndex < 0} return

	# Program bombs if a alternate has less than 2 frames
	if {[alternate count $alternateIndex] == 2} {
		tk_messageBox -icon warning -title "Delete Frame" \
			-message "An alternate must have 2 frames or else!"
		return
	}

	set canvistId [Info $oop frame,canvistId]

	alternate delete $alternateIndex $frameIndex

	if {$frameIndex >= [alternate count $alternateIndex] - 1} {
		incr frameIndex -1
	}

	# Display icons in that alternate
	SetFrameList $oop $alternateIndex 0
	NSCanvist2::UpdateSelection $canvistId $frameIndex {}
	NSCanvist2::See $canvistId $frameIndex
}

# NSAlternate::ConfigAlternate --
#
#	Sets the frame delay of the selected alternate.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc ConfigAlternate {oop option value} {

	set selectedAlternate [Info $oop alternate,current]
	if {$selectedAlternate < 0} return

	alternate configure $selectedAlternate -$option $value
}

# NSAlternate::BrowserCmd --
#
#	Called by NSIconBrowser when displaying an icon type. Display
#	the progress of listing the icons. Note that this can
#	actually slow down listing the icons.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc BrowserCmd {oop action args} {

	set win [Info $oop win]
	set progId [Info $oop progId]
	
	switch -- $action {
		open {
			NSProgress2::Zero $progId
			pack [NSProgress2::Info $progId frame] -pady 1 -fill x
			update idletasks
		}
		update {
			set cur [lindex $args 0]
			set max [lindex $args 1]
			set bump [expr (($max / 20) > 40) ? ($max / 20) : 40]
			if {$cur && ($cur % $bump) == 0} {
				NSProgress2::SetDoneRatio $progId [expr $cur / $max.0]
				$win.statusBar.label2 configure -text "$cur/$max"
				update idletasks
			}
		}
		close {
			NSProgress2::SetDoneRatio $progId 1.0
			update idletasks
			pack forget [NSProgress2::Info $progId frame]
			$win.statusBar.label2 configure -text ""
		}
	}
}

# namespace eval NSAlternate
}
