Add core elements

This commit is contained in:
Cooldude2606
2025-01-11 00:36:13 +00:00
parent ee6359582c
commit 88a47e3edc
8 changed files with 549 additions and 197 deletions

215
exp_gui/module/control.lua Normal file
View 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

View 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

View File

@@ -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>

View File

@@ -0,0 +1,5 @@
[exp-gui]
hide-top-flow=Hide Toolbar.
show-top-flow=Show Toolbar.
clear-left-flow=Hide all open windows.

View File

@@ -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": "*",

View File

@@ -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

View File

@@ -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
View 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",
}