# mindcraft.tcl --
#
#	The Mindcraft Window and related commands. The Mindcraft Window
#	displays powers of the Mindcrafter class.
#

namespace eval NSMindcraft {

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

proc InitModule {} {

	NSObject::New NSMindcraft
}

# NSMindcraft::NSMindcraft --
#
#	Object constructor called by NSObject::New().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NSMindcraft oop {

	global Windows

	InitWindow $oop

	NSWindowManager::RegisterWindow mindcraft [Info $oop win] \
		"NSMindcraft::GeometryCmd $oop" "" "NSMindcraft::DisplayCmd $oop"

	#
	# Global list of application windows
	#

	set Windows(mindcraft,win) [Info $oop win]
	set Windows(mindcraft,class) NSMindcraft
	set Windows(mindcraft,oop) $oop
}

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

proc Info {oop info args} {

	global NSMindcraft

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

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

# NSMindcraft::InitWindow --
#
#	Create the window associated with this object.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc InitWindow oop {

	global NSToolbar
	global Windows

	set w .mindcraft$oop
	toplevel $w
	wm title $w "Mindcraft Powers"

	wm transient $w $Windows(main,win)

	# Do stuff when window closes
	wm protocol $w WM_DELETE_WINDOW "NSMindcraft::Close $oop"

	# Start out withdrawn (hidden)
	wm withdraw $w

	Info $oop win $w

	#
	# Toolbar
	#

	set toolId [NSObject::New NSToolbar 20 $w]
	NSToolbar::AddTool $toolId Image_ButtonOptions "DoCommandIfAllowed ="
	NSToolbar::AddTool $toolId Image_ButtonHelp "DoCommandIfAllowed ?"

	#
	# Divider
	#

	frame $w.divider2 \
		-borderwidth 1 -height 2 -relief groove

	#
	# List
	#

	frame $w.frame \
		-borderwidth 1 -relief sunken

	InitHeader $w.frame 2 {Courier 9} {Name 3 nw Level 32 ne Mana 37 ne Fail 42 ne Comment 43 nw}

	set canvistId [NSObject::New NSCanvist $w.frame 20 400 300 \
		"NSMindcraft::NewItemCmd $oop" "NSMindcraft::HighlightItemCmd $oop"]
	set canvas [NSCanvist::Info $canvistId canvas]
	ListBackgroundChanged $canvas
	$canvas configure -yscrollcommand "$w.frame.scroll set"
	scrollbar $w.frame.scroll \
		-borderwidth 0 -command "$canvas yview" -orient vert

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

	Info $oop list $canvistId

	pack $w.frame.scroll -side right -fill y
	pack $w.frame.header \
		-side top -fill x
	pack $canvas -side left -expand yes -fill both

	#
	# Double-click to select spell
	#

	NSCanvist::Info $canvistId invokeCmd \
		"NSMindcraft::Invoke $oop"

	#
	# Statusbar
	#

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

	#
	# Geometry
	#

	grid rowconfig $w 0 -weight 0 -minsize 0
	grid rowconfig $w 1 -weight 0 -minsize 0
	grid rowconfig $w 2 -weight 1 -minsize 0
	grid rowconfig $w 3 -weight 0 -minsize 0
	grid columnconfig $w 0 -weight 1 -minsize 0
 
	pack forget $NSToolbar($toolId,frame)
	grid $NSToolbar($toolId,frame) -in $w \
		-row 0 -column 0 -rowspan 1 -columnspan 1 -sticky ew
	grid $w.divider2 -in $w \
		-row 1 -column 0 -rowspan 1 -columnspan 1 -sticky ew
	grid $w.frame -in $w \
		-row 2 -column 0 -rowspan 1 -columnspan 1 -sticky news
	grid $w.statusBar -in $w \
		-row 3 -column 0 -rowspan 1 -columnspan 1 -sticky ew

	#
	# Feed Term when keys pressed
	#

	bind $w <KeyPress> {
		angband keypress %A
	}

	#
	# Synch the scrollbars when window is shown.
	#

	bind $w.frame.scroll <Map> "NSMindcraft::SynchScrollBars $oop"

	bind $w <FocusIn> "if !\[string compare %W $w] {focus $canvas}"
}

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

proc DisplayCmd {oop message first} {

	switch -- $message {
		preDisplay {
			SetList $oop
		}
		postDisplay {
		}
	}
}

# NSMindcraft::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 winMicro $Windows(micromap,win)
	set x [winfo x $winMain]
	set y [winfo y $winMain]
	set width [NSToplevel::ContentWidth $win [expr [NSToplevel::EdgeRight $winMicro] - $x]]
	set height [NSToplevel::ContentHeight $win [expr [NSToplevel::EdgeBottom $winMain] - $y]]
	return ${width}x$height+$x+$y
}

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

proc Close oop {

	angband keypress \033
}

# NSMindcraft::Invoke --
#
#	When a Mindcraft power is double-clicked, "angband keypress" the
#	char.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Invoke {oop canvistId x y} {

	if {[lsearch -exact [angband inkey_flags] INKEY_MINDCRAFT] == -1} return

	set row [NSCanvist::PointToRow $canvistId $x $y]
	if {$row == -1} return

	set power [lindex [angband mindcraft get] $row]
	angband mindcraft info $power attrib
	angband keypress $attrib(char)
}

# NSMindcraft::SetList --
#
#	Fill the list with castable Mindcraft powers.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SetList oop {

	set win [Info $oop win]
	set canvistId [Info $oop list]
	set canvas [NSCanvist::Info $canvistId canvas]

	NSCanvist::Delete $canvistId 0 end

	set powerList [angband mindcraft get]
	foreach power $powerList {

		angband mindcraft info $power attrib
		if !$attrib(okay) continue

		NSCanvist::Insert $canvistId end $attrib(char) $attrib(name) \
			$attrib(level) $attrib(mana) $attrib(fail) $attrib(comment)
	}

	# Display number of Mindcraft powers
	set num [llength $powerList]
	if {$num > 1} {
		set s s
	} else {
		set s ""
	}
	$win.statusBar.label configure -text "$num power$s"
}

# NSMindcraft::SynchScrollBars --
#
#	There is a bug (my bug or in Tk?) which prevents the scroll bars
#	from synchronizing when the window is not mapped. So I bind to
#	the <Map> event and synch the scroll bars here.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SynchScrollBars oop {

	set win [Info $oop win]
	set canvistId [Info $oop list]
	set canvas [NSCanvist::Info $canvistId canvas]

	eval $win.frame.scroll set [$canvas yview]
	$canvas yview moveto 0.0
}

# NSMindcraft::NewItemCmd --
#
#	Called by NSCanvist::InsertItem() to create a list row.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NewItemCmd {oop canvistId y char name level mana fail comment} {

	set c [NSCanvist::Info $canvistId canvas]
	set lineHeight [NSCanvist::Info $canvistId rowHgt]
	set font {Courier 9}

	set text "$char) $name"
	set textLeft 5

	set cw [font measure $font "W"]
	set fw [font measure $font $text]
	set fh [font metrics $font -linespace]
	set diff [expr int([expr ($lineHeight - $fh) / 2])]

	# Selection rectangle inside row
	lappend itemIdList [$c create rectangle 2 [expr $y + 2] \
		[expr [winfo width $c] - 3] [expr $y + $lineHeight - 2] \
		-fill "" -outline "" -tags enabled -width 2.0]

	# Text
	lappend itemIdList [$c create text $textLeft [expr $y + $diff] \
		-text $text -anchor nw -font $font -fill White -tags enabled]

	set offset 0

	# Level
	lappend itemIdList [$c create text [expr $textLeft + $cw * [incr offset 32]] \
		[expr $y + $diff] \
		-text $level -anchor ne -justify right -font $font -fill White]

	# Mana
	lappend itemIdList [$c create text [expr $textLeft + $cw * [incr offset 5]] \
		[expr $y + $diff] \
		-text $mana -anchor ne -justify right -font $font -fill White]

	# Fail
	lappend itemIdList [$c create text [expr $textLeft + $cw * [incr offset 5]] \
		[expr $y + $diff] \
		-text $fail% -anchor ne -justify right -font $font -fill White]

	# Comment
	lappend itemIdList [$c create text [expr $textLeft + $cw * [incr offset 1]] \
		[expr $y + $diff] \
		-text $comment -anchor nw -justify left -font $font -fill White]

	return $itemIdList
}

# NSMindcraft::HighlightItemCmd --
#
#	Called by NSCanvist::Select() to highlight a row.
#
# Arguments:
#	oop					OOP ID. See above.
#	canvistId					OOP ID of NSCanvist object.
#	state					1 or 0 highlight state.
#	args					List of canvas item ids
#
# Results:
#	What happened.

proc HighlightItemCmd {oop canvistId state args} {

	global NSCanvist

	set canvas $NSCanvist($canvistId,canvas)
	set itemIdList $args

	set idRect [lindex $itemIdList 0]

	if $state {

		$canvas itemconfigure $idRect -outline [NSColorPreferences::Get listHilite]

	} else {

		$canvas itemconfigure $idRect -outline {}
	}
}

# namespace eval NSMindcraft
}



# mindcraft-menu.tcl --
#
#	Implements the Mindcraft Menu. Each item is the name of a power..
#

namespace eval NSMindcraftMenu {

# Option: Bypass NSMenu::MenuEnable
variable SetupFaster 1

# NSMindcraftMenu::NSMindcraftMenu --
#
#	Object constructor called by NSObject::New().
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc NSMindcraftMenu {oop mbarId} {

	global NSMindcraftMenu

	Info $oop mbar $mbarId

	NSObject::New NSMenu $mbarId "-tearoff 0 \
		-postcommand \"NSMindcraftMenu::SetupMenus $oop\" \
		-identifier MENU_MINDCRAFT"
	NSMenu::MenuInsertEntry $mbarId -end MENUBAR \
		{-type cascade -menu MENU_MINDCRAFT -label "Mindcraft" \
		-underline 0 -identifier M_MINDCRAFT}

	foreach power [angband mindcraft get] {
		angband mindcraft info $power attrib
		lappend entries "-type command -label \"$attrib(char) $attrib(name)\" \
			-command \"NSMindcraftMenu::Invoke $oop $attrib(char)\" \
			-underline 0 -identifier \"E_POWER_$attrib(char)\""
	}

	NSMenu::MenuInsertEntries $mbarId -end MENU_MINDCRAFT $entries
}

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

proc Info {oop info args} {

	global NSMindcraftMenu

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

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

# NSMindcraftMenu::SetupMenus --
#
#	Enable entries representing usable Mindcraft powers.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc SetupMenus oop {

	set flag [lindex [angband inkey_flags] 0]

	# Enable entries during commands and when choosing mindcraft powers
	if {[string compare $flag INKEY_MINDCRAFT]} {
		if {[string compare $flag INKEY_CMD]} return
	}

	set mbarId [Info $oop mbar]

	set identList {}
	foreach power [angband mindcraft get] {
		angband mindcraft info $power attrib
		if $attrib(okay) {
			lappend identList E_POWER_$attrib(char)
		}
	}

	NSMenu::MenuEnable $mbarId $identList
}

# NSMindcraftMenu::Invoke --
#
#	Call "angband keypress" to invoke the Mindcraft power.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc Invoke {oop charPower} {

	set flag [lindex [angband inkey_flags] 0]

	if {![string compare $flag INKEY_CMD]} {

		# Use "cast" for Mindcraft powers
		set charCmd m
	
		angband keypress $charCmd$charPower
	}

	if {![string compare $flag INKEY_MINDCRAFT]} {
		angband keypress $charPower
	}
}

# NSMindcraftMenu::PopupSelect --
#
#	Show a pop-up menu of Mindcraft power choices.
#
# Arguments:
#	arg1					about arg1
#
# Results:
#	What happened.

proc PopupSelect {menu x y} {

	global PopupResult

	set PopupResult 0

	$menu delete 0 end
	set num 0
	foreach power [angband mindcraft get] {

		angband mindcraft info $power attrib

		# Can we invoke this power?
		if !$attrib(okay) continue

		# Append menu entry
		$menu add command -label "$attrib(char) $attrib(name)" \
			-command "angband keypress $attrib(char) ; set PopupResult 1" \
			-underline 0

		incr num
	}
	if !$num return

	# Pressing and holding Button-3, poping up, then letting go selects 
	# an item, so wait a bit if it was a quick press-release
	after 100

	tk_popup $menu $x $y [expr $num / 2]

	# If the user unposts the menu without choosing an entry, then
	# I want to feed Escape into the Term. I tried binding to the <Unmap>
	# event but it isn't called on Windows(TM).
	after idle {
		if !$PopupResult {
			angband keypress \033
		}
	}
}

# namespace eval NSMindcraftMenu
}

