227 lines
7.0 KiB
Lua

local gui = {}
local util = scripts.util
local templates = scripts["gui-templates"]
local mod_gui = require("mod-gui")
local helpers = scripts.helpers
local _ = helpers.on
local MAX_DUPLICATES = 1000
-- GUI events are saved in global.guiEvents["EVENT NAME"][PLAYER INDEX][GUI ELEMENT INDEX]
local eventHandlers = {} -- FIXME: support multiple events (curently all events saved under same ID in eventHandlers)
local events = {
on_gui_checked_state_changed = "onCheckedStateChanged",
on_gui_click = "onClicked",
on_gui_elem_changed = "onElementChanged",
on_gui_selection_state_changed = "onSelectionStateChanged",
on_gui_text_changed = "onTextChanged",
on_gui_value_changed = "onValueChanged",
on_gui_confirmed = "onConfirmed",
on_gui_selected_tab_changed = "onSelectedTabChanged",
on_gui_switch_state_changed = "onSwitchStateChanged",
on_gui_location_changed = "onLocationChanged",
}
local onChangedEvents = {
["checkbox"] = "onCheckedStateChanged",
["radiobutton"] = "onCheckedStateChanged",
["choose-elem-button"] = "onElementChanged",
["button"] = "onClicked",
["sprite-button"] = "onClicked",
["drop-down"] = "onSelectionStateChanged",
["list-box"] = "onSelectionStateChanged",
["textfield"] = "onTextChanged",
["text-box"] = "onTextChanged",
["slider"] = "onValueChanged",
["tabbed-pane"] = "onSelectedTabChanged",
["switch"] = "onSwitchStateChanged",
}
local specialParameters = {
children = true,
onCreated = true,
onChanged = true,
onCheckedStateChanged = true,
onClicked = true,
onElementChanged = true,
onSelectionStateChanged = true,
onTextChanged = true,
onValueChanged = true,
onConfirmed = true,
onSelectedTabChanged = true,
onSwitchStateChanged = true,
onLocationChanged = true,
ID = true,
root = true,
unique = true,
content = true,
}
local function registerHandlers(template, ID)
ID = ID or template.ID
local elemName = template.name
for _,event in pairs(events) do -- register event handler functions with generated ID
if template[event] then
eventHandlers[ID..";"..elemName] = template[event]
end
end
if template.onChanged and onChangedEvents[template.type] then -- register unified onChanged event
eventHandlers[ID..";"..elemName] = template.onChanged
end
if template.children then -- recursively register childs event handlers
for _,child in ipairs(template.children) do
registerHandlers(child, ID)
end
end
if template.type == "tab" and template.content then -- build tab contents
registerHandlers(template.content, ID)
end
end
function gui.registerTemplates(obj) -- called when lua script is loaded initially, assigns unqiue ID to every template
for name,template in pairs(obj.templates) do
template.ID = obj.class..";"..name -- unique ID, obj.class is assigned by framework.lua
registerHandlers(template)
end
end
local function getParameters(template, name)
local parameters = { name = name }
for param,value in pairs(template) do
if param ~= "name" and not specialParameters[param] then
if param == "style" and _(value):is("table") then
parameters.style = value.parent
else
parameters[param] = value
end
end
end
return parameters
end
local function getDefaultRoot(template, player)
if template.type == "button" or template.type == "sprite-button" then
return mod_gui.get_button_flow(player)
end
return mod_gui.get_frame_flow(player)
end
local function getRoot(template, player)
if template.root then
return template.root(player, getDefaultRoot(template, player))
end
return getDefaultRoot(template, player)
end
function gui.create(player, template, data, parent, ID) -- recursively builds a gui from a template
ID = ID or template.ID
parent = parent or getRoot(template, player)
local elemName = template.name
local uniqueElemName = elemName
if template.unique == false then
-- duplicates are named NAME[i] where i is the index starting at 1 (-> multiple can exist at once)
for i = 1, MAX_DUPLICATES do
if not parent[elemName.."#"..i] then
uniqueElemName = elemName.."#"..i
break
end
end
elseif template.ID then -- destroy any existing instances of this template if it's not unique
gui.destroy(player, template, parent)
end
local created = parent.add(getParameters(template, uniqueElemName)) -- create gui element
-- Apply custom styles
local style = _(template.style)
if style:is("table") then
_(created.style):set(style:unlesskey("parent"))
end
local index = created.player_index
for event,list in pairs(global.guiEvents) do -- register events
if template[event] then
list[index] = list[index] or {}
list[index][created.index] = ID..";"..elemName
end
end
if template.onChanged and onChangedEvents[template.type] then -- register unified onChanged event
local list = global.guiEvents[onChangedEvents[template.type]]
list[index] = list[index] or {}
list[index][created.index] = ID..";"..elemName
end
if template.children then -- build children
for _,child in ipairs(template.children) do
gui.create(player, child, data, created, ID)
end
end
if template.type == "tab" and parent.type == "tabbed-pane" and template.content then -- build tab contents
parent.add_tab(created, gui.create(player, template.content, data, parent, ID))
end
if template.onCreated then template.onCreated(created, data) end -- fire onCreated event
return created
end
function gui.get(player, template, parent) -- get the gui element matching the given template (unique templates only)
parent = parent or getRoot(template, player)
return parent[template.name]
end
function gui.getAll(player, template, parent) -- get table of all gui elements matching the given template (unique and non-unique)
parent = parent or getRoot(template, player)
local result = {}
if template.unique == false then -- destroy all
local regex = "^"..util.escape(template.name).."#[0-9]+$"
for _,child in pairs(parent.children) do
if child.name:find(regex) then
result[#result + 1] = child
end
end
else
result[1] = gui.get(player, template, parent)
end
return result
end
function gui.destroy(player, template, parent) -- destroy all gui elements matching the given template
for _,child in ipairs(gui.getAll(player, template, parent)) do
util.destroyIfValid(child)
end
end
local function handleGuiEvent(event, name)
if event.element.get_mod() == script.mod_name then
local handlers = global.guiEvents[name][event.player_index]
if handlers then
local handler = handlers[event.element.index]
if handler and eventHandlers[handler] then eventHandlers[handler](event.element, event) end
end
end
end
-- register game gui events
for gameEvent,translated in pairs(events) do
gui[gameEvent] = function(event)
handleGuiEvent(event, translated)
end
end
return gui