mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Add core elements
This commit is contained in:
215
exp_gui/module/control.lua
Normal file
215
exp_gui/module/control.lua
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
|
||||||
|
local Storage = require("modules/exp_util/storage")
|
||||||
|
|
||||||
|
local ExpElement = require("modules/exp_gui/prototype")
|
||||||
|
|
||||||
|
--- @alias ExpGui.VisibleCallback fun(player: LuaPlayer, element: LuaGuiElement): boolean
|
||||||
|
|
||||||
|
--- @class ExpGui.player_elements
|
||||||
|
--- @field top table<string, LuaGuiElement?>
|
||||||
|
--- @field left table<string, LuaGuiElement?>
|
||||||
|
--- @field relative table<string, LuaGuiElement?>
|
||||||
|
|
||||||
|
--- @type table<uint, ExpGui.player_elements>
|
||||||
|
local player_elements = {}
|
||||||
|
Storage.register(player_elements, function(tbl)
|
||||||
|
player_elements = tbl
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- @class ExpGui
|
||||||
|
local ExpGui = {
|
||||||
|
element = ExpElement.create,
|
||||||
|
property_from_args = ExpElement.property_from_args,
|
||||||
|
property_from_name = ExpElement.property_from_name,
|
||||||
|
top_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
||||||
|
left_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
||||||
|
relative_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
||||||
|
}
|
||||||
|
|
||||||
|
local mod_gui = require("mod-gui")
|
||||||
|
ExpGui.get_top_flow = mod_gui.get_button_flow
|
||||||
|
ExpGui.get_left_flow = mod_gui.get_frame_flow
|
||||||
|
|
||||||
|
--- Get a player from an element or gui event
|
||||||
|
--- @param input LuaGuiElement | { player_index: uint }
|
||||||
|
--- @return LuaPlayer
|
||||||
|
function ExpGui.get_player(input)
|
||||||
|
return assert(game.get_player(input.player_index))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle the enable state of an element
|
||||||
|
--- @param element LuaGuiElement
|
||||||
|
--- @param state boolean?
|
||||||
|
--- @return boolean
|
||||||
|
function ExpGui.toggle_enabled_state(element, state)
|
||||||
|
if not element or not element.valid then return false end
|
||||||
|
if state == nil then
|
||||||
|
state = not element.enabled
|
||||||
|
end
|
||||||
|
element.enabled = state
|
||||||
|
return state
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle the visibility of an element
|
||||||
|
--- @param element LuaGuiElement
|
||||||
|
--- @param state boolean?
|
||||||
|
--- @return boolean
|
||||||
|
function ExpGui.toggle_visible_state(element, state)
|
||||||
|
if not element or not element.valid then return false end
|
||||||
|
if state == nil then
|
||||||
|
state = not element.visible
|
||||||
|
end
|
||||||
|
element.visible = state
|
||||||
|
return state
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Destroy an element if it exists and is valid
|
||||||
|
--- @param element LuaGuiElement?
|
||||||
|
function ExpGui.destroy_if_valid(element)
|
||||||
|
if not element or not element.valid then return end
|
||||||
|
element.destroy()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the top flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
||||||
|
function ExpGui.add_top_element(define, visible)
|
||||||
|
assert(ExpGui.top_elements[define.name] == nil, "Element is already added to the top flow")
|
||||||
|
ExpGui.top_elements[define] = visible or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the left flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
||||||
|
function ExpGui.add_left_element(define, visible)
|
||||||
|
assert(ExpGui.left_elements[define.name] == nil, "Element is already added to the left flow")
|
||||||
|
ExpGui.left_elements[define] = visible or false
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the relative flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
||||||
|
function ExpGui.add_relative_element(define, visible)
|
||||||
|
assert(ExpGui.relative_elements[define.name] == nil, "Element is already added to the relative flow")
|
||||||
|
ExpGui.relative_elements[define] = visible or false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the top flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return LuaGuiElement
|
||||||
|
function ExpGui.get_top_element(define, player)
|
||||||
|
return player_elements[player.index].top[define.name]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the left flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return LuaGuiElement
|
||||||
|
function ExpGui.get_left_element(define, player)
|
||||||
|
return player_elements[player.index].left[define.name]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Register a element define to be drawn to the relative flow on join
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @return LuaGuiElement
|
||||||
|
function ExpGui.get_relative_element(define, player)
|
||||||
|
return player_elements[player.index].relative[define.name]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return all top level elements for a player
|
||||||
|
---@param player LuaPlayer
|
||||||
|
---@return ExpGui.player_elements
|
||||||
|
function ExpGui._get_player_elements(player)
|
||||||
|
return player_elements[player.index]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Ensure all the correct elements are visible and exist
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param element_defines table<ExpElement, ExpGui.VisibleCallback | boolean>
|
||||||
|
--- @param elements table<string, LuaGuiElement?>
|
||||||
|
--- @param parent LuaGuiElement
|
||||||
|
local function ensure_elements(player, element_defines, elements, parent)
|
||||||
|
local done = {}
|
||||||
|
for define, visible in pairs(element_defines) do
|
||||||
|
local element = elements[define.name]
|
||||||
|
if not element then
|
||||||
|
element = define(parent)
|
||||||
|
elements[define.name] = element
|
||||||
|
assert(element, "Element define did not return an element: " .. define.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(visible) == "function" then
|
||||||
|
visible = visible(player, element)
|
||||||
|
end
|
||||||
|
element.visible = visible
|
||||||
|
done[define.name] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
for name, element in pairs(elements) do
|
||||||
|
if not done[name] then
|
||||||
|
element.destroy()
|
||||||
|
elements[name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Ensure all elements have been created
|
||||||
|
--- @param event EventData.on_player_created | EventData.on_player_joined_game
|
||||||
|
function ExpGui._ensure_elements(event)
|
||||||
|
local player = assert(game.get_player(event.player_index))
|
||||||
|
local elements = player_elements[event.player_index]
|
||||||
|
if not elements then
|
||||||
|
elements = {
|
||||||
|
top = {},
|
||||||
|
left = {},
|
||||||
|
relative = {},
|
||||||
|
}
|
||||||
|
player_elements[event.player_index] = elements
|
||||||
|
end
|
||||||
|
|
||||||
|
ensure_elements(player, ExpGui.top_elements, elements.top, ExpGui.get_top_flow(player))
|
||||||
|
ensure_elements(player, ExpGui.left_elements, elements.left, ExpGui.get_left_flow(player))
|
||||||
|
ensure_elements(player, ExpGui.relative_elements, elements.relative, player.gui.relative)
|
||||||
|
|
||||||
|
-- Check technically not needed, but makes it easier to use this lib without the core defines
|
||||||
|
if ExpGui.apply_consistency_checks then
|
||||||
|
ExpGui.apply_consistency_checks(player, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Rerun the visible check for relative elements
|
||||||
|
--- @param event EventData.on_gui_opened
|
||||||
|
local function on_gui_opened(event)
|
||||||
|
local player = ExpGui.get_player(event)
|
||||||
|
local original_element = event.element
|
||||||
|
|
||||||
|
for define, visible in pairs(ExpGui.relative_elements) do
|
||||||
|
local element = ExpGui.get_relative_element(define, player)
|
||||||
|
|
||||||
|
if type(visible) == "function" then
|
||||||
|
visible = visible(player, element)
|
||||||
|
end
|
||||||
|
element.visible = visible
|
||||||
|
|
||||||
|
if visible then
|
||||||
|
event.element = element
|
||||||
|
--- @diagnostic disable-next-line invisible
|
||||||
|
define:_raise_event(event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
event.element = original_element
|
||||||
|
end
|
||||||
|
|
||||||
|
local e = defines.events
|
||||||
|
local events = {
|
||||||
|
[e.on_player_created] = ExpGui._ensure_elements,
|
||||||
|
[e.on_player_joined_game] = ExpGui._ensure_elements,
|
||||||
|
[e.on_gui_opened] = on_gui_opened,
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpGui.events = events
|
||||||
|
return ExpGui
|
||||||
289
exp_gui/module/core_elements.lua
Normal file
289
exp_gui/module/core_elements.lua
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
|
||||||
|
--- @class ExpGui
|
||||||
|
local ExpGui = require("modules/exp_gui")
|
||||||
|
local mod_gui = require("mod-gui")
|
||||||
|
|
||||||
|
local toolbar_button_default_style = mod_gui.button_style
|
||||||
|
local toolbar_button_active_style = "menu_button_continue"
|
||||||
|
local toolbar_button_size = 36
|
||||||
|
|
||||||
|
local elements = {} --- @type table<string, ExpElement>
|
||||||
|
local buttons_with_left_element = {} --- @type table<string, ExpElement>
|
||||||
|
local left_elements_with_button = {} --- @type table<string, ExpElement>
|
||||||
|
|
||||||
|
--- Set the style of a toolbar button
|
||||||
|
--- @param element LuaGuiElement
|
||||||
|
--- @param state boolean?
|
||||||
|
--- @return boolean
|
||||||
|
function ExpGui.set_toolbar_button_style(element, state)
|
||||||
|
if state == nil then state = element.style.name == toolbar_button_default_style end
|
||||||
|
element.style = state and toolbar_button_active_style or toolbar_button_default_style
|
||||||
|
|
||||||
|
local style = element.style
|
||||||
|
style.minimal_width = toolbar_button_size
|
||||||
|
style.height = toolbar_button_size
|
||||||
|
if element.type == "sprite-button" then
|
||||||
|
style.padding = -2
|
||||||
|
else
|
||||||
|
style.font = "default-semibold"
|
||||||
|
style.padding = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return state
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the visible state of the top flow for a player
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param state boolean?
|
||||||
|
function ExpGui.set_top_flow_visible(player, state)
|
||||||
|
local top_flow = assert(ExpGui.get_top_flow(player).parent, player.name)
|
||||||
|
local show_top_flow = elements.core_button_flow.data[player].show_top_flow --- @type LuaGuiElement
|
||||||
|
|
||||||
|
if state == nil then
|
||||||
|
state = not top_flow.visible
|
||||||
|
end
|
||||||
|
|
||||||
|
top_flow.visible = state
|
||||||
|
show_top_flow.visible = not state
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the visible state of the left element for a player
|
||||||
|
--- @param define ExpElement
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param state boolean?
|
||||||
|
function ExpGui.set_left_element_visible(define, player, state)
|
||||||
|
local element = assert(ExpGui.get_left_element(define, player), "Define is not added to the left flow")
|
||||||
|
local clear_left_flow = elements.core_button_flow.data[player].clear_left_flow --- @type LuaGuiElement
|
||||||
|
|
||||||
|
-- Update the visible state
|
||||||
|
if state == nil then state = not element.visible end
|
||||||
|
element.visible = state
|
||||||
|
|
||||||
|
-- Check if there is a toolbar button linked to this element
|
||||||
|
local toolbar_button = left_elements_with_button[define.name]
|
||||||
|
if toolbar_button then
|
||||||
|
ExpGui.set_toolbar_button_style(ExpGui.get_top_element(toolbar_button, player), state)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If visible state is true, then we don't need to check all elements
|
||||||
|
if state then
|
||||||
|
clear_left_flow.visible = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if any left elements are visible
|
||||||
|
--- @diagnostic disable-next-line invisible
|
||||||
|
local player_elements = ExpGui._get_player_elements(player)
|
||||||
|
local flow_name = elements.core_button_flow.name
|
||||||
|
for name, left_element in pairs(player_elements.left) do
|
||||||
|
if left_element.visible and name ~= flow_name then
|
||||||
|
clear_left_flow.visible = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- There are no visible left elements, so can hide the button
|
||||||
|
clear_left_flow.visible = false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @class ExpGui.create_toolbar_button__param: LuaGuiElement.add_param.sprite_button, LuaGuiElement.add_param.button
|
||||||
|
--- @field name string
|
||||||
|
--- @field type nil
|
||||||
|
--- @field left_element ExpElement| nil
|
||||||
|
--- @field visible ExpGui.VisibleCallback | boolean | nil
|
||||||
|
|
||||||
|
--- Create a toolbar button
|
||||||
|
--- @param options ExpGui.create_toolbar_button__param
|
||||||
|
--- @return ExpElement
|
||||||
|
function ExpGui.create_toolbar_button(options)
|
||||||
|
-- Extract the custom options from the element.add options
|
||||||
|
local name = assert(options.name, "Name is required for the element")
|
||||||
|
options.type = options.sprite ~= nil and "sprite-button" or "button"
|
||||||
|
|
||||||
|
local visible = options.visible
|
||||||
|
if visible == nil then visible = true end
|
||||||
|
options.visible = nil
|
||||||
|
|
||||||
|
local auto_toggle = options.auto_toggle
|
||||||
|
options.auto_toggle = nil
|
||||||
|
|
||||||
|
local left_element = options.left_element
|
||||||
|
options.left_element = nil
|
||||||
|
|
||||||
|
if options.style == nil then
|
||||||
|
options.style = toolbar_button_default_style
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create the new element define
|
||||||
|
local toolbar_button = ExpGui.element(name)
|
||||||
|
:draw(options)
|
||||||
|
:style{
|
||||||
|
minimal_width = toolbar_button_size,
|
||||||
|
height = toolbar_button_size,
|
||||||
|
padding = options.sprite ~= nil and -2 or nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- If a left element was given then link the define
|
||||||
|
if left_element then
|
||||||
|
left_elements_with_button[left_element.name] = toolbar_button
|
||||||
|
buttons_with_left_element[toolbar_button.name] = left_element
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Setup auto toggle, required if there is a left element
|
||||||
|
if auto_toggle or left_element then
|
||||||
|
toolbar_button:on_click(function(def, event)
|
||||||
|
local state = ExpGui.set_toolbar_button_style(event.element)
|
||||||
|
if left_element then
|
||||||
|
local player = ExpGui.get_player(event)
|
||||||
|
ExpGui.set_left_element_visible(left_element, player, state)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add the define to the top flow and return
|
||||||
|
ExpGui.add_top_element(toolbar_button, visible)
|
||||||
|
return toolbar_button
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update the consistency of the core elements and registered elements
|
||||||
|
--- @param player LuaPlayer
|
||||||
|
--- @param skip_ensure boolean?
|
||||||
|
function ExpGui.apply_consistency_checks(player, skip_ensure)
|
||||||
|
if not skip_ensure then
|
||||||
|
--- @diagnostic disable-next-line invisible
|
||||||
|
ExpGui._ensure_elements{ player_index = player.index }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the core buttons for the player
|
||||||
|
local core_button_data = elements.core_button_flow.data[player]
|
||||||
|
local hide_top_flow = ExpGui.get_top_element(elements.hide_top_flow, player)
|
||||||
|
local show_top_flow = core_button_data.show_top_flow --- @type LuaGuiElement
|
||||||
|
local clear_left_flow = core_button_data.clear_left_flow --- @type LuaGuiElement
|
||||||
|
|
||||||
|
-- Check if any top elements are visible, this includes ones not controlled by this module
|
||||||
|
local has_top_elements = false
|
||||||
|
local top_flow = ExpGui.get_top_flow(player)
|
||||||
|
for _, element in pairs(top_flow.children) do
|
||||||
|
if element.visible and element ~= hide_top_flow then
|
||||||
|
has_top_elements = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The show button is only visible when the flow isn't visible but does have visible children
|
||||||
|
show_top_flow.visible = has_top_elements and not top_flow.visible or false
|
||||||
|
|
||||||
|
--- @diagnostic disable-next-line invisible
|
||||||
|
local player_elements = ExpGui._get_player_elements(player)
|
||||||
|
local left_elements, top_elements = player_elements.left, player_elements.top
|
||||||
|
|
||||||
|
--- Update the styles of toolbar buttons with left elements
|
||||||
|
for name, top_element in pairs(top_elements) do
|
||||||
|
local left_element = buttons_with_left_element[name]
|
||||||
|
if left_element then
|
||||||
|
local element = assert(left_elements[left_element.name], left_element.name)
|
||||||
|
ExpGui.set_toolbar_button_style(top_element, element.visible)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if any left elements are visible
|
||||||
|
local flow_name = elements.core_button_flow.name
|
||||||
|
for name, left_element in pairs(left_elements) do
|
||||||
|
if left_element.visible and name ~= flow_name then
|
||||||
|
clear_left_flow.visible = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- There are no visible left elements, so can hide the button
|
||||||
|
clear_left_flow.visible = false
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Hides the top flow when clicked
|
||||||
|
elements.hide_top_flow = ExpGui.element("hide_top_flow")
|
||||||
|
:draw{
|
||||||
|
type = "sprite-button",
|
||||||
|
sprite = "utility/preset",
|
||||||
|
style = "tool_button",
|
||||||
|
tooltip = { "exp-gui.hide-top-flow" },
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
padding = -2,
|
||||||
|
width = 18,
|
||||||
|
height = 36,
|
||||||
|
}
|
||||||
|
:on_click(function(def, event)
|
||||||
|
local player = ExpGui.get_player(event)
|
||||||
|
ExpGui.set_top_flow_visible(player, false)
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Shows the top flow when clicked
|
||||||
|
elements.show_top_flow = ExpGui.element("show_top_flow")
|
||||||
|
:draw{
|
||||||
|
type = "sprite-button",
|
||||||
|
sprite = "utility/preset",
|
||||||
|
style = "tool_button",
|
||||||
|
tooltip = { "exp-gui.show-top-flow" },
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
padding = -2,
|
||||||
|
width = 18,
|
||||||
|
height = 20,
|
||||||
|
}
|
||||||
|
:on_click(function(def, event)
|
||||||
|
local player = ExpGui.get_player(event)
|
||||||
|
ExpGui.set_top_flow_visible(player, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Hides all left elements when clicked
|
||||||
|
elements.clear_left_flow = ExpGui.element("clear_left_flow")
|
||||||
|
:draw{
|
||||||
|
type = "sprite-button",
|
||||||
|
sprite = "utility/close_black",
|
||||||
|
style = "tool_button",
|
||||||
|
tooltip = { "exp-gui.clear-left-flow" },
|
||||||
|
}
|
||||||
|
:style{
|
||||||
|
padding = -3,
|
||||||
|
width = 18,
|
||||||
|
height = 20,
|
||||||
|
}
|
||||||
|
:on_click(function(def, event)
|
||||||
|
local player = ExpGui.get_player(event)
|
||||||
|
event.element.visible = false
|
||||||
|
|
||||||
|
--- @diagnostic disable-next-line invisible
|
||||||
|
local player_elements = ExpGui._get_player_elements(player)
|
||||||
|
local flow_name = elements.core_button_flow.name
|
||||||
|
for name, left_element in pairs(player_elements.left) do
|
||||||
|
if name ~= flow_name then
|
||||||
|
left_element.visible = false
|
||||||
|
local toolbar_button = left_elements_with_button[name]
|
||||||
|
if toolbar_button then
|
||||||
|
ExpGui.set_toolbar_button_style(ExpGui.get_top_element(toolbar_button, player), false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Contains the two buttons on the left flow
|
||||||
|
elements.core_button_flow = ExpGui.element("core_button_flow")
|
||||||
|
:draw(function(def, parent)
|
||||||
|
local flow = parent.add{
|
||||||
|
type = "flow",
|
||||||
|
direction = "vertical",
|
||||||
|
}
|
||||||
|
|
||||||
|
local player = ExpGui.get_player(parent)
|
||||||
|
def.data[player] = {
|
||||||
|
show_top_flow = elements.show_top_flow(flow),
|
||||||
|
clear_left_flow = elements.clear_left_flow(flow),
|
||||||
|
}
|
||||||
|
|
||||||
|
return flow
|
||||||
|
end)
|
||||||
|
|
||||||
|
ExpGui.add_top_element(elements.hide_top_flow, true)
|
||||||
|
ExpGui.add_left_element(elements.core_button_flow, true)
|
||||||
|
|
||||||
|
return elements
|
||||||
@@ -56,7 +56,7 @@ local GuiData = {
|
|||||||
-- This class has no prototype methods
|
-- This class has no prototype methods
|
||||||
-- Do add keys to _raw without also referencing scope_data
|
-- Do add keys to _raw without also referencing scope_data
|
||||||
|
|
||||||
--- @class ExpGui.GuiData: table
|
--- @class ExpGui.GuiData: ExpGui.GuiData_Internal
|
||||||
--- @field element_data table<uint, table<uint, any>>
|
--- @field element_data table<uint, table<uint, any>>
|
||||||
--- @field player_data table<uint, any>
|
--- @field player_data table<uint, any>
|
||||||
--- @field force_data table<uint, any>
|
--- @field force_data table<uint, any>
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
[exp-gui]
|
||||||
|
hide-top-flow=Hide Toolbar.
|
||||||
|
show-top-flow=Show Toolbar.
|
||||||
|
clear-left-flow=Hide all open windows.
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
"data.lua",
|
"data.lua",
|
||||||
"iter.lua",
|
"iter.lua",
|
||||||
"prototype.lua",
|
"prototype.lua",
|
||||||
"module_exports.lua"
|
"control.lua"
|
||||||
],
|
],
|
||||||
"require": [
|
"require": [
|
||||||
|
"core_elements.lua",
|
||||||
|
"test.lua"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clusterio": "*",
|
"clusterio": "*",
|
||||||
|
|||||||
@@ -1,186 +1 @@
|
|||||||
|
return require("modules/exp_gui/control")
|
||||||
local Storage = require("modules/exp_util/storage")
|
|
||||||
|
|
||||||
local ExpElement = require("./prototype")
|
|
||||||
|
|
||||||
--- @alias ExpGui.VisibleCallback fun(player: LuaPlayer, element: LuaGuiElement): boolean
|
|
||||||
|
|
||||||
--- @class ExpGui.player_elements
|
|
||||||
--- @field top table<string, LuaGuiElement>
|
|
||||||
--- @field left table<string, LuaGuiElement>
|
|
||||||
--- @field relative table<string, LuaGuiElement>
|
|
||||||
|
|
||||||
--- @type table<uint, ExpGui.player_elements>
|
|
||||||
local player_elements = {}
|
|
||||||
Storage.register(player_elements, function(tbl)
|
|
||||||
player_elements = tbl
|
|
||||||
end)
|
|
||||||
|
|
||||||
--- @class ExpGui
|
|
||||||
local ExpGui = {
|
|
||||||
element = ExpElement,
|
|
||||||
top_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
|
||||||
left_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
|
||||||
relative_elements = {}, --- @type table<ExpElement, ExpGui.VisibleCallback | boolean>
|
|
||||||
}
|
|
||||||
|
|
||||||
local mod_gui = require("mod-gui")
|
|
||||||
ExpGui.get_top_flow = mod_gui.get_button_flow
|
|
||||||
ExpGui.get_left_flow = mod_gui.get_frame_flow
|
|
||||||
|
|
||||||
--- Get a player from an element or gui event
|
|
||||||
--- @param input LuaGuiElement | { player_index: uint }
|
|
||||||
--- @return LuaPlayer
|
|
||||||
function ExpGui.get_player(input)
|
|
||||||
return assert(game.get_player(input.player_index))
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Toggle the enable state of an element
|
|
||||||
--- @param element LuaGuiElement
|
|
||||||
--- @param state boolean?
|
|
||||||
function ExpGui.toggle_enabled_state(element, state)
|
|
||||||
if not element or not element.valid then return end
|
|
||||||
if state == nil then
|
|
||||||
state = not element.enabled
|
|
||||||
end
|
|
||||||
element.enabled = state
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Toggle the visibility of an element
|
|
||||||
--- @param element LuaGuiElement
|
|
||||||
--- @param state boolean?
|
|
||||||
function ExpGui.toggle_visible_state(element, state)
|
|
||||||
if not element or not element.valid then return end
|
|
||||||
if state == nil then
|
|
||||||
state = not element.visible
|
|
||||||
end
|
|
||||||
element.visible = state
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Destroy an element if it exists and is valid
|
|
||||||
--- @param element LuaGuiElement?
|
|
||||||
function ExpGui.destroy_if_valid(element)
|
|
||||||
if not element or not element.valid then return end
|
|
||||||
element.destroy()
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the top flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
|
||||||
function ExpGui.add_top_element(define, visible)
|
|
||||||
assert(ExpGui.top_elements[define.name] == nil, "Element is already added to the top flow")
|
|
||||||
ExpGui.top_elements[define] = visible or false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the left flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
|
||||||
function ExpGui.add_left_element(define, visible)
|
|
||||||
assert(ExpGui.left_elements[define.name] == nil, "Element is already added to the left flow")
|
|
||||||
ExpGui.left_elements[define] = visible or false
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the relative flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param visible ExpGui.VisibleCallback | boolean | nil
|
|
||||||
function ExpGui.add_relative_element(define, visible)
|
|
||||||
assert(ExpGui.relative_elements[define.name] == nil, "Element is already added to the relative flow")
|
|
||||||
ExpGui.relative_elements[define] = visible or false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the top flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param player LuaPlayer
|
|
||||||
--- @return LuaGuiElement
|
|
||||||
function ExpGui.get_top_element(define, player)
|
|
||||||
return player_elements[player.index].top[define.name]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the left flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param player LuaPlayer
|
|
||||||
--- @return LuaGuiElement
|
|
||||||
function ExpGui.get_left_element(define, player)
|
|
||||||
return player_elements[player.index].left[define.name]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Register a element define to be drawn to the relative flow on join
|
|
||||||
--- @param define ExpElement
|
|
||||||
--- @param player LuaPlayer
|
|
||||||
--- @return LuaGuiElement
|
|
||||||
function ExpGui.get_relative_element(define, player)
|
|
||||||
return player_elements[player.index].relative[define.name]
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Ensure all the correct elements are visible and exist
|
|
||||||
--- @param player LuaPlayer
|
|
||||||
--- @param element_defines table<ExpElement, ExpGui.VisibleCallback | boolean>
|
|
||||||
--- @param elements LuaGuiElement[]
|
|
||||||
--- @param parent LuaGuiElement
|
|
||||||
local function ensure_elements(player, element_defines, elements, parent)
|
|
||||||
local done = {}
|
|
||||||
for define, visible in pairs(element_defines) do
|
|
||||||
local element = elements[define.name]
|
|
||||||
if not element then
|
|
||||||
element = define(parent)
|
|
||||||
end
|
|
||||||
|
|
||||||
if type(visible) == "function" then
|
|
||||||
visible = visible(player, element)
|
|
||||||
end
|
|
||||||
element.visible = visible
|
|
||||||
done[define.name] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
for name, element in pairs(elements) do
|
|
||||||
if not done[name] then
|
|
||||||
element.destroy()
|
|
||||||
elements[name] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Ensure all elements have been created
|
|
||||||
--- @param event EventData.on_player_created | EventData.on_player_joined_game
|
|
||||||
function ExpGui._ensure_elements(event)
|
|
||||||
local player = assert(game.get_player(event.player_index))
|
|
||||||
local elements = player_elements[event.player_index]
|
|
||||||
ensure_elements(player, ExpGui.top_elements, elements.top, player.gui.top)
|
|
||||||
ensure_elements(player, ExpGui.left_elements, elements.left, player.gui.left)
|
|
||||||
ensure_elements(player, ExpGui.relative_elements, elements.relative, player.gui.relative)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Rerun the visible check for relative elements
|
|
||||||
--- @param event EventData.on_gui_opened
|
|
||||||
local function on_gui_opened(event)
|
|
||||||
local player = ExpGui.get_player(event)
|
|
||||||
local original_element = event.element
|
|
||||||
|
|
||||||
for define, visible in pairs(ExpGui.relative_elements) do
|
|
||||||
local element = ExpGui.get_relative_element(define, player)
|
|
||||||
|
|
||||||
if type(visible) == "function" then
|
|
||||||
visible = visible(player, element)
|
|
||||||
end
|
|
||||||
element.visible = visible
|
|
||||||
|
|
||||||
if visible then
|
|
||||||
event.element = element
|
|
||||||
--- @diagnostic disable-next-line invisible
|
|
||||||
define:_raise_event(event)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
event.element = original_element
|
|
||||||
end
|
|
||||||
|
|
||||||
local e = defines.events
|
|
||||||
local events = {
|
|
||||||
[e.on_player_created] = ExpGui._ensure_elements,
|
|
||||||
[e.on_player_joined_game] = ExpGui._ensure_elements,
|
|
||||||
[e.on_gui_opened] = on_gui_opened,
|
|
||||||
}
|
|
||||||
|
|
||||||
ExpGui.events = events
|
|
||||||
return ExpGui
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
local ExpUtil = require("modules/exp_util")
|
local ExpUtil = require("modules/exp_util")
|
||||||
|
|
||||||
local GuiData = require("./data")
|
local GuiData = require("modules/exp_gui/data")
|
||||||
local GuiIter = require("./iter")
|
local GuiIter = require("modules/exp_gui/iter")
|
||||||
|
|
||||||
--- @class ExpGui_ExpElement
|
--- @class ExpGui_ExpElement
|
||||||
local ExpElement = {
|
local ExpElement = {
|
||||||
@@ -54,6 +54,12 @@ ExpElement._metatable = {
|
|||||||
__class = "ExpGui",
|
__class = "ExpGui",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- Used to signal that the property should be the same as the define name
|
||||||
|
--- @return function
|
||||||
|
function ExpElement.property_from_name()
|
||||||
|
return ExpElement.property_from_name
|
||||||
|
end
|
||||||
|
|
||||||
--- Used to signal that a property should be taken from the arguments
|
--- Used to signal that a property should be taken from the arguments
|
||||||
--- @param arg_number number?
|
--- @param arg_number number?
|
||||||
--- @return [function, number?]
|
--- @return [function, number?]
|
||||||
@@ -64,11 +70,13 @@ end
|
|||||||
--- Extract the from args properties from a definition
|
--- Extract the from args properties from a definition
|
||||||
--- @param definition table
|
--- @param definition table
|
||||||
--- @return string[]
|
--- @return string[]
|
||||||
local function extract_from_args(definition)
|
function ExpElement._prototype:_extract_signals(definition)
|
||||||
local from_args = {}
|
local from_args = {}
|
||||||
for k, v in pairs(definition) do
|
for k, v in pairs(definition) do
|
||||||
if v == ExpElement.property_from_args then
|
if v == ExpElement.property_from_args then
|
||||||
from_args[#from_args + 1] = k
|
from_args[#from_args + 1] = k
|
||||||
|
elseif v == ExpElement.property_from_name then
|
||||||
|
definition[k] = self.name
|
||||||
elseif type(v) == "table" and v[1] == ExpElement.property_from_args then
|
elseif type(v) == "table" and v[1] == ExpElement.property_from_args then
|
||||||
from_args[v[2] or (#from_args + 1)] = k
|
from_args[v[2] or (#from_args + 1)] = k
|
||||||
end
|
end
|
||||||
@@ -81,18 +89,20 @@ end
|
|||||||
--- @return ExpElement
|
--- @return ExpElement
|
||||||
function ExpElement.create(name)
|
function ExpElement.create(name)
|
||||||
ExpUtil.assert_not_runtime()
|
ExpUtil.assert_not_runtime()
|
||||||
assert(ExpElement._elements[name] == nil, "ExpElement already defined with name: " .. name)
|
local module_name = ExpUtil.get_module_name(2)
|
||||||
|
local element_name = module_name .. "/" .. name
|
||||||
|
assert(ExpElement._elements[element_name] == nil, "ExpElement already defined with name: " .. name)
|
||||||
|
|
||||||
local instance = {
|
local instance = {
|
||||||
name = name,
|
name = element_name,
|
||||||
data = GuiData.create(name),
|
data = GuiData.create(element_name),
|
||||||
_events = {},
|
_events = {},
|
||||||
_debug = {
|
_debug = {
|
||||||
defined_at = ExpUtil.safe_file_path(2),
|
defined_at = ExpUtil.safe_file_path(2),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpElement._elements[name] = instance
|
ExpElement._elements[element_name] = instance
|
||||||
return setmetatable(instance, ExpElement._metatable)
|
return setmetatable(instance, ExpElement._metatable)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -180,7 +190,7 @@ function ExpElement._prototype:draw(definition)
|
|||||||
end
|
end
|
||||||
|
|
||||||
assert(type(definition) == "table", "Definition is not a table or function")
|
assert(type(definition) == "table", "Definition is not a table or function")
|
||||||
local from_args = extract_from_args(definition)
|
local from_args = self:_extract_signals(definition)
|
||||||
self._debug.draw_definition = definition
|
self._debug.draw_definition = definition
|
||||||
|
|
||||||
if #from_args == 0 then
|
if #from_args == 0 then
|
||||||
@@ -216,7 +226,7 @@ local function definition_factory(prop_name, debug_def, debug_args)
|
|||||||
end
|
end
|
||||||
|
|
||||||
assert(type(definition) == "table", "Definition is not a table or function")
|
assert(type(definition) == "table", "Definition is not a table or function")
|
||||||
local from_args = extract_from_args(definition)
|
local from_args = self:_extract_signals(definition)
|
||||||
self._debug[debug_def] = definition
|
self._debug[debug_def] = definition
|
||||||
|
|
||||||
if #from_args == 0 then
|
if #from_args == 0 then
|
||||||
|
|||||||
16
exp_gui/module/test.lua
Normal file
16
exp_gui/module/test.lua
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
local ExpGui = require("modules/exp_gui")
|
||||||
|
|
||||||
|
local frame = ExpGui.element("test")
|
||||||
|
:draw{
|
||||||
|
type = "frame",
|
||||||
|
caption = "Hello, World",
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpGui.add_left_element(frame, true)
|
||||||
|
|
||||||
|
ExpGui.create_toolbar_button{
|
||||||
|
name = "test-button",
|
||||||
|
left_element = frame,
|
||||||
|
caption = "Test",
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user