From 2ac15ea4adce1d8166e5f8a021900ab572e4c648 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Sun, 23 Oct 2011 11:22:27 +0000
Subject: [PATCH] New engine.ui.EquipDoll class

git-svn-id: http://svn.net-core.org/repos/t-engine4@4584 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engines/default/engine/ui/Dialog.lua     |   2 +-
 game/engines/default/engine/ui/EquipDoll.lua  | 183 ++++++++++++++++++
 .../default/engine/ui/EquipDollFrame.lua      |   2 +-
 game/engines/default/engine/ui/ImageList.lua  |   2 +-
 game/modules/tome/dialogs/ShowEquipInven.lua  |  86 ++------
 5 files changed, 204 insertions(+), 71 deletions(-)
 create mode 100644 game/engines/default/engine/ui/EquipDoll.lua

diff --git a/game/engines/default/engine/ui/Dialog.lua b/game/engines/default/engine/ui/Dialog.lua
index 80ea2226b8..1a369e3102 100644
--- a/game/engines/default/engine/ui/Dialog.lua
+++ b/game/engines/default/engine/ui/Dialog.lua
@@ -493,7 +493,7 @@ function _M:moveFocus(v)
 	local cnt = 0
 	id = util.boundWrap((id or 1) + v, 1, #self.uis)
 	while start ~= id and cnt <= #self.uis do
-		if self.uis[id] and self.uis[id].ui and self.uis[id].ui.can_focus then
+		if self.uis[id] and self.uis[id].ui and self.uis[id].ui.can_focus and not self.uis[id].ui.no_keyboard_focus then
 			self:setFocus(id)
 			break
 		end
diff --git a/game/engines/default/engine/ui/EquipDoll.lua b/game/engines/default/engine/ui/EquipDoll.lua
new file mode 100644
index 0000000000..d292833d40
--- /dev/null
+++ b/game/engines/default/engine/ui/EquipDoll.lua
@@ -0,0 +1,183 @@
+-- TE4 - T-Engine 4
+-- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+require "engine.class"
+local Base = require "engine.ui.Base"
+local Focusable = require "engine.ui.Focusable"
+local EquipDollFrame = require "engine.ui.EquipDollFrame"
+
+module(..., package.seeall, class.inherit(Base, Focusable))
+
+function _M:init(t)
+	self.actor = assert(t.actor, "no equipdoll actor")
+	self.drag_enable = t.drag_enable
+	self.on_select = t.on_select
+	self.fct = t.fct
+	self.actorWear = t.actorWear
+	self.filter = t.filter
+	self.focus_ui = nil
+
+	Base.init(self, t)
+end
+
+function _M:generate()
+	self.mouse:reset()
+	self.key:reset()
+
+	self:generateEquipDollFrames()
+
+	self.font_bold:setStyle("bold")
+	local tw, th = self.font_bold:size(self.actor.name)
+	local s = core.display.newSurface(tw, th)
+	s:erase(0, 0, 0, 0)
+	s:drawColorStringBlended(self.font_bold, self.actor.name, 0, 0, colors.GOLD.r, colors.GOLD.g, colors.GOLD.b, true)
+	self.font_bold:setStyle("normal")
+	self.charname_tex = {s:glTexture()}
+	self.charname_tex.w = tw
+	self.charname_tex.h = th
+
+	self.inner_scroll = self:makeFrame("ui/tooltip/", self.w, self.h)
+
+	self.mouse:registerZone(0, 0, self.w, self.h, function(button, x, y, xrel, yrel, bx, by, event)
+		self:mouseEvent(button, x, y, xrel, yrel, bx, by, event)
+	end)
+	self.key:addBinds{
+		ACCEPT = function() if self.focus_ui then self.focus_ui.ui.key:triggerVirtual("ACCEPT") end end,
+	}
+	self.key:addCommands{
+		_UP = function() self:moveFocus(-1) end,
+		_DOWN = function() self:moveFocus(1) end,
+	}
+end
+
+function _M:setInnerFocus(id)
+	if self.focus_ui and self.focus_ui.ui.can_focus then self.focus_ui.ui:setFocus(false) end
+
+	if type(id) == "table" then
+		for i = 1, #self.uis do
+			if self.uis[i].ui == id then id = i break end
+		end
+		if type(id) == "table" then self:no_focus() return end
+	end
+
+	local ui = self.uis[id]
+	if not ui.ui.can_focus then self:no_focus() return end
+	self.focus_ui = ui
+	self.focus_ui_id = id
+	ui.ui:setFocus(true)
+	self:on_focus(id, ui)
+end
+
+function _M:on_focus(id, ui)
+	if self.on_select and ui then self.on_select(ui, ui.ui.inven, ui.ui.item, ui.ui:getItem()) end
+end
+function _M:no_focus()
+end
+
+function _M:moveFocus(v)
+	local id = self.focus_ui_id
+	local start = id or 1
+	local cnt = 0
+	id = util.boundWrap((id or 1) + v, 1, #self.uis)
+	while start ~= id and cnt <= #self.uis do
+		if self.uis[id] and self.uis[id].ui and self.uis[id].ui.can_focus and not self.uis[id].ui.no_keyboard_focus then
+			self:setInnerFocus(id)
+			break
+		end
+		id = util.boundWrap(id + v, 1, #self.uis)
+		cnt = cnt + 1
+	end
+end
+
+function _M:mouseEvent(button, x, y, xrel, yrel, bx, by, event)
+	-- Look for focus
+	for i = 1, #self.uis do
+		local ui = self.uis[i]
+		if ui.ui.can_focus and bx >= ui.x and bx <= ui.x + ui.ui.w and by >= ui.y and by <= ui.y + ui.ui.h then
+			self:setInnerFocus(i)
+
+			-- Pass the event
+			ui.ui.mouse:delegate(button, bx, by, xrel, yrel, bx, by, event)
+			return
+		end
+	end
+	self:no_focus()
+end
+
+function _M:generateEquipDollFrames()
+	local doll = self.actor.equipdolls[self.actor.equipdoll or "default"]
+	if not doll then return end
+
+	local uis = {}
+	local max_w = 0
+	local max_h = 0
+
+	for k, v in pairs(doll.list) do
+		local inven = self.actor:getInven(k)
+		if inven then
+			for item, def in ipairs(v) do
+				local frame = EquipDollFrame.new{actor=self.actor, inven=inven, name_pos=def.text, item=item, w=doll.w, h=doll.h, iw=doll.iw, ih=doll.ih, ix=doll.ix, iy=doll.iy, bg=doll.itemframe, bg_sel=doll.itemframe_sel, bg_empty=self.actor.inven_def[inven.name].infos and self.actor.inven_def[inven.name].infos.equipdoll_back, drag_enable=self.drag_enable}
+				frame.doll_select = true
+				frame.actorWear = function(_, ...) if self.actorWear then self.actorWear(frame, ...) end end
+				frame.fct=function(button, event) if frame:getItem() and self.fct then self.fct({inven=inven, item=item, object=frame:getItem()}, button, event) end end
+				frame.filter = self.filter
+				uis[#uis+1] = {x=def.x, y=def.y, ui=frame, _weight=def.weight}
+				max_w = math.max(def.x, max_w)
+				max_h = math.max(def.y, max_h)
+			end
+		end
+	end
+
+	table.sort(uis, function(a,b) return a._weight < b._weight end)
+
+	self.w = max_w + math.floor(doll.w * 2.5)
+	self.h = max_h + math.floor(doll.h * 2.5)
+--	self.base_doll_y = (self.ih - self.h) / 2
+	self.base_doll_y = 0
+
+	for i, ui in ipairs(uis) do
+		ui.y = ui.y + self.base_doll_y
+		ui.ui.mouse.delegate_offset_x = ui.x
+		ui.ui.mouse.delegate_offset_y = ui.y
+	end
+
+	self.uis = uis
+	self:setFocus(1)
+end
+
+function _M:display(x, y, nb_keyframes, ox, oy)
+	self.last_display_x = ox
+	self.last_display_y = oy
+
+	Base.drawFrame(self, self.inner_scroll, x, y + self.base_doll_y, 1, 1, 1, self.focused and 1 or 0.5)
+
+	if self.title_shadow then self.charname_tex[1]:toScreenFull(x + (self.w - self.charname_tex.w) / 2 + 2, y + self.base_doll_y + 5 + 2, self.charname_tex.w, self.charname_tex.h, self.charname_tex[2], self.charname_tex[3], 0, 0, 0, 0.5) end
+	self.charname_tex[1]:toScreenFull(x + (self.w - self.charname_tex.w) / 2, y + self.base_doll_y + 5, self.charname_tex.w, self.charname_tex.h, self.charname_tex[2], self.charname_tex[3])
+
+	local doll = self.actor.equipdolls[self.actor.equipdoll or "default"]
+	if not doll then return end
+
+	self.actor:toScreen(nil, x + doll.doll_x, y + self.base_doll_y + doll.doll_y, 128, 128)
+
+	-- UI elements
+	for i = 1, #self.uis do
+		local ui = self.uis[i]
+		if not ui.hidden then ui.ui:display(x + ui.x, y + ui.y, nb_keyframes, ox + ui.x, oy + ui.y) end
+	end
+end
diff --git a/game/engines/default/engine/ui/EquipDollFrame.lua b/game/engines/default/engine/ui/EquipDollFrame.lua
index d43d5e0be8..c73d7b770f 100644
--- a/game/engines/default/engine/ui/EquipDollFrame.lua
+++ b/game/engines/default/engine/ui/EquipDollFrame.lua
@@ -60,7 +60,7 @@ function _M:generate()
 		if event == "motion" and button == "left" and self:getItem() then self:onDrag(self.inven, self.item, self:getItem())
 		elseif button == "drag-end" and self.drag_enable then
 			local drag = game.mouse.dragged.payload
-			print(table.serialize(drag,nil,true))
+--			print(table.serialize(drag,nil,true))
 			if drag.kind == "inventory" and drag.inven and self.actor:getInven(drag.inven) and not self.actor:getInven(drag.inven).worn then
 				self:actorWear(drag.inven, drag.item_idx, drag.object)
 				game.mouse:usedDrag()
diff --git a/game/engines/default/engine/ui/ImageList.lua b/game/engines/default/engine/ui/ImageList.lua
index 1d213de167..5ca6299139 100644
--- a/game/engines/default/engine/ui/ImageList.lua
+++ b/game/engines/default/engine/ui/ImageList.lua
@@ -165,7 +165,7 @@ function _M:onUse(button, forcectrl)
 		elseif self.selection == "multiple" then
 			item.selected = not item.selected
 		elseif self.selection == "ctrl-multiple" then
-			if not forcectrl and not core.key.modState("ctrl") then self:clearSelection() end
+			if not (forcectrl == true or (forcectrl == nil and core.key.modState("ctrl"))) then self:clearSelection() end
 			item.selected = not item.selected
 		end
 		self.fct(item)
diff --git a/game/modules/tome/dialogs/ShowEquipInven.lua b/game/modules/tome/dialogs/ShowEquipInven.lua
index 6898e450a0..bee368ee98 100644
--- a/game/modules/tome/dialogs/ShowEquipInven.lua
+++ b/game/modules/tome/dialogs/ShowEquipInven.lua
@@ -25,7 +25,7 @@ local Textzone = require "engine.ui.Textzone"
 local TextzoneList = require "engine.ui.TextzoneList"
 local Separator = require "engine.ui.Separator"
 local ImageList = require "engine.ui.ImageList"
-local EquipDollFrame = require "engine.ui.EquipDollFrame"
+local EquipDoll = require "engine.ui.EquipDoll"
 
 module(..., package.seeall, class.inherit(Dialog))
 
@@ -37,22 +37,20 @@ function _M:init(title, actor, filter, action, on_select)
 
 	Dialog.init(self, title or "Inventory", math.max(800, game.w * 0.8), math.max(600, game.h * 0.8))
 
-	self.font_bold:setStyle("bold")
-	local tw, th = self.font_bold:size(self.actor.name)
-	local s = core.display.newSurface(tw, th)
-	s:erase(0, 0, 0, 0)
-	s:drawColorStringBlended(self.font_bold, self.actor.name, 0, 0, colors.GOLD.r, colors.GOLD.g, colors.GOLD.b, true)
-	self.font_bold:setStyle("normal")
-	self.charname_tex = {s:glTexture()}
-	self.charname_tex.w = tw
-	self.charname_tex.h = th
-
 	self.max_h = 0
-	local uis = self:generateEquipDollFrames()
+	local uis = {}
 
-	self.inner_scroll = self:makeFrame("ui/tooltip/", self.equipdolls_max_w, self.equipdolls_max_h)
+	self.c_doll = EquipDoll.new{actor=actor, drag_enable=true,
+		fct = function(item, button, event) self:use(item, button, event) end,
+		on_select = function(ui, inven, item, o) if ui.ui.last_display_x then self:select{last_display_x=ui.ui.last_display_x+ui.ui.w, last_display_y=ui.ui.last_display_y, object=o} end end,
+		actorWear = function(ui, ...)
+			if ui:getItem() then self.actor:doTakeoff(ui.inven, ui.item, ui:getItem(), true) end
+			self.actor:doWear(...)
+			self:generateList()
+		end
+	}
 
-	self.c_tabs = ImageList.new{width=self.iw - 20 - self.equipdolls_max_w, height=36, tile_w=32, tile_h=32, padding=5, force_size=true, selection="ctrl-multiple", list={
+	self.c_tabs = ImageList.new{width=self.iw - 20 - self.c_doll.w, height=36, tile_w=32, tile_h=32, padding=5, force_size=true, selection="ctrl-multiple", list={
 		{image="metal-ui/inven_tabs/weapons.png", 	kind="weapons", desc="All kinds of weapons"},
 		{image="metal-ui/inven_tabs/armors.png", 	kind="armors", desc="All kinds of armours"},
 		{image="metal-ui/inven_tabs/jewelry.png", 	kind="jewelry", desc="Rings and Amulets"},
@@ -62,8 +60,9 @@ function _M:init(title, actor, filter, action, on_select)
 		{image="metal-ui/inven_tabs/quests.png", 	kind="quests", desc="Quest and plot related items"},
 	}, fct=function() self:generateList() end, on_select=function(item) self:select(item) end}
 	self.c_tabs.dlist[1][1].selected = true
+	self.c_tabs.no_keyboard_focus = true
 
-	self.c_inven = ListColumns.new{width=self.iw - 20 - self.equipdolls_max_w, height=self.ih - self.max_h*self.font_h - 10 - self.c_tabs.h, sortable=true, scrollbar=true, columns={
+	self.c_inven = ListColumns.new{width=self.iw - 20 - self.c_doll.w, height=self.ih - self.max_h*self.font_h - 10 - self.c_tabs.h, sortable=true, scrollbar=true, columns={
 		{name="", width={20,"fixed"}, display_prop="char", sort="id"},
 		{name="", width={24,"fixed"}, display_prop="object", sort="sortname", direct_draw=function(item, x, y) if item.object then item.object:toScreen(nil, x+4, y, 16, 16) end end},
 		{name="Inventory", width=72, display_prop="name", sort="sortname"},
@@ -73,9 +72,10 @@ function _M:init(title, actor, filter, action, on_select)
 
 	self:generateList()
 
+	uis[#uis+1] = {left=0, top=0, ui=self.c_doll}
 	uis[#uis+1] = {right=0, top=0, ui=self.c_tabs}
 	uis[#uis+1] = {right=0, top=self.c_tabs.h + 5, ui=self.c_inven}
-	uis[#uis+1] = {left=self.equipdolls_max_w, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}}
+	uis[#uis+1] = {left=self.c_doll.w, top=5, ui=Separator.new{dir="horizontal", size=self.ih - 10}}
 
 	self:loadUI(uis)
 	self:setFocus(self.c_inven)
@@ -91,6 +91,8 @@ function _M:init(title, actor, filter, action, on_select)
 				self:use(list[list.chars[c]])
 			end
 		end,
+		_TAB = function() self.c_tabs.sel_j = 1 self.c_tabs.sel_i = util.boundWrap(self.c_tabs.sel_i+1, 1, 7) self.c_tabs:onUse("left") end,
+		[{"_TAB","ctrl"}] = function() self.c_tabs.sel_j = 1 self.c_tabs.sel_i = util.boundWrap(self.c_tabs.sel_i-1, 1, 7) self.c_tabs:onUse("left", false) end,
 	}
 	self.key:addBinds{
 		HOTKEY_1 = function() self:defineHotkey(1) end,
@@ -206,8 +208,6 @@ end
 
 function _M:on_focus(id, ui)
 	if self.focus_ui and self.focus_ui.ui == self.c_inven then self:select(self.c_inven.list[self.c_inven.sel])
-	elseif self.focus_ui and self.focus_ui.ui and self.focus_ui.ui.doll_select and self.focus_ui.ui:getItem() and self.focus_ui.ui.last_display_x then
-		self:select{last_display_x=self.focus_ui.ui.last_display_x+self.focus_ui.ui.w, last_display_y=self.focus_ui.ui.last_display_y, object=self.focus_ui.ui:getItem()}
 	elseif self.focus_ui and self.focus_ui.ui == self.c_tabs then
 	else
 		game.tooltip_x = nil
@@ -225,52 +225,6 @@ function _M:use(item, button, event)
 	end
 end
 
-function _M:generateEquipDollFrames()
-	local doll = self.actor.equipdolls[self.actor.equipdoll or "default"]
-	if not doll then return end
-
-	local uis = {}
-	local max_w = 0
-	local max_h = 0
-
-	for k, v in pairs(doll.list) do
-		local inven = self.actor:getInven(k)
-		if inven then
-			for item, def in ipairs(v) do
-				local frame = EquipDollFrame.new{actor=self.actor, inven=inven, name_pos=def.text, item=item, w=doll.w, h=doll.h, iw=doll.iw, ih=doll.ih, ix=doll.ix, iy=doll.iy, bg=doll.itemframe, bg_sel=doll.itemframe_sel, bg_empty=self.actor.inven_def[inven.name].infos and self.actor.inven_def[inven.name].infos.equipdoll_back, drag_enable=true}
-				frame.doll_select = true
-				frame.actorWear = function(_, ...)
-					if frame:getItem() then self.actor:doTakeoff(inven, item, frame:getItem(), true) end
-					self.actor:doWear(...)
-					self:generateList()
-				end
-				frame.fct=function(button, event) if frame:getItem() then self:use({inven=inven, item=item, object=frame:getItem()}, button, event) end end
-				frame.filter = self.filter
-				uis[#uis+1] = {left=def.x, top=def.y, ui=frame, _weight=def.weight}
-				max_w = math.max(def.x, max_w)
-				max_h = math.max(def.y, max_h)
-			end
-		end
-	end
-
-	table.sort(uis, function(a,b) return a._weight < b._weight end)
-
-	self.equipdolls_max_w = max_w + math.floor(doll.w * 2.5)
-	self.equipdolls_max_h = max_h + math.floor(doll.h * 2.5)
-	self.base_doll_y = (self.ih - self.equipdolls_max_h) / 2
-
-	for i, ui in ipairs(uis) do ui.top = ui.top + self.base_doll_y end
-
-	return uis
-end
-
-function _M:innerDisplayBack(x, y, nb_keyframes)
-	local doll = self.actor.equipdolls[self.actor.equipdoll or "default"]
-	if not doll then return end
-
-	self.actor:toScreen(nil, x + doll.doll_x, y + self.base_doll_y + doll.doll_y, 128, 128)
-end
-
 local tab_filters = {
 	weapons = function(o) return o.type == "weapon" end,
 	armors = function(o) return o.type == "armor" end,
@@ -392,8 +346,4 @@ function _M:drawFrame(x, y, r, g, b, a)
 	if not self.title_fill then return end
 
 	core.display.drawQuad(x + self.frame.title_x, y + self.frame.title_y, self.title_fill, self.frame.title_h, self.title_fill_color.r, self.title_fill_color.g, self.title_fill_color.b, 60)
-
-	Base.drawFrame(self, self.inner_scroll, x, y + self.base_doll_y)
-	if self.title_shadow then self.charname_tex[1]:toScreenFull(x + (self.equipdolls_max_w - self.charname_tex.w) / 2 + 2, y + self.base_doll_y + 5 + 2, self.charname_tex.w, self.charname_tex.h, self.charname_tex[2], self.charname_tex[3], 0, 0, 0, 0.5) end
-	self.charname_tex[1]:toScreenFull(x + (self.equipdolls_max_w - self.charname_tex.w) / 2, y + self.base_doll_y + 5, self.charname_tex.w, self.charname_tex.h, self.charname_tex[2], self.charname_tex[3])
 end
-- 
GitLab