mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Feature: Toolbar Menu (#268)
* Fix left flow not using uids * Mock Toolbar menu * Fix task list after core gui change * Allow show/hide override * Fix autofill permissions * Copy style from toolbar on change * Open and close automatically * Removed hacky prevent default * Fixed more core issues * Add reset button * Allow for custom draw order on join * Add methods to reorder ui flows * Impliment move buttons * Add locale * Add toolbar to player data * Better player data layout * Picked a suitable datastore id * Update locale for readme * Fix swaping left flow order * Fix datastore updates * Code cleanup * Fix incorrect top flow hashing on load * Fix loading of malformed data * Fixed loading state of left flows * Dont save default data * Dont open menu on join * Lint * Remove incorrect new index metamethod * Revert method used for move_toolbar_button * Fixed missing toolbar button * Fixed desync between visibilty and toggle state * Fix bad gui element path * Fixed enable state of toggle button * Change order of operations * Fix reset not showing top flow
This commit is contained in:
@@ -122,10 +122,10 @@ end)
|
||||
]]
|
||||
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
require 'expcore.gui.helper_functions'
|
||||
require 'expcore.gui.core_defines'
|
||||
require 'expcore.gui.top_flow'
|
||||
require 'expcore.gui.left_flow'
|
||||
require 'expcore.gui.helper_functions'
|
||||
require 'expcore.gui.defines'
|
||||
|
||||
local Roles = _C.opt_require('expcore.roles')
|
||||
|
||||
@@ -25,7 +25,7 @@ Gui.element{
|
||||
height = 36
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.toggle_top_flow(player)
|
||||
Gui.toggle_top_flow(player, false)
|
||||
end)
|
||||
Gui.core_defines.hide_top_flow = hide_top_flow
|
||||
|
||||
@@ -45,7 +45,7 @@ Gui.element{
|
||||
height = 20
|
||||
}
|
||||
:on_click(function(player, _,_)
|
||||
Gui.toggle_top_flow(player)
|
||||
Gui.toggle_top_flow(player, true)
|
||||
end)
|
||||
Gui.core_defines.show_top_flow = show_top_flow
|
||||
|
||||
|
||||
@@ -38,8 +38,10 @@ example_flow_with_button:add_to_left_flow(true)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:add_to_left_flow(open_on_join)
|
||||
_C.error_if_runtime()
|
||||
if not self.name then error("Elements for the top flow must have a static name") end
|
||||
Gui.left_elements[self] = open_on_join or false
|
||||
self.open_on_join = open_on_join or false
|
||||
table.insert(Gui.left_elements, self)
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -60,26 +62,38 @@ function Gui.left_toolbar_button(sprite, tooltip, element_define, authenticator)
|
||||
local button = Gui.toolbar_button(sprite, tooltip, authenticator)
|
||||
|
||||
-- Add on_click handler to handle click events comming from the player
|
||||
button:on_click(function(player, _,_)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
local element = top_flow[button.name]
|
||||
local visibility_state = Gui.toggle_left_element(player, element_define)
|
||||
|
||||
button:on_click(function(player, _, _)
|
||||
-- Raise custom event that tells listening elements if the element has changed visibility by a player clicking
|
||||
-- Used in warp gui to handle the keep open logic
|
||||
button:raise_custom_event{
|
||||
button:raise_event{
|
||||
name = Gui.events.on_visibility_changed_by_click,
|
||||
element = element,
|
||||
state = visibility_state
|
||||
element = Gui.get_top_element(player, button),
|
||||
state = Gui.toggle_left_element(player, element_define)
|
||||
}
|
||||
end)
|
||||
|
||||
-- Add property to the left flow element with the name of the button
|
||||
-- This is for the ability to reverse lookup the button from the left flow element
|
||||
element_define.toolbar_button = button.name
|
||||
element_define.toolbar_button = button
|
||||
button.left_flow_element = element_define
|
||||
return button
|
||||
end
|
||||
|
||||
Gui._left_flow_order_src = "<default>"
|
||||
--- Get the order of elements in the left flow, first argument is player but is unused in the default method
|
||||
function Gui.get_left_flow_order(_)
|
||||
return Gui.left_elements
|
||||
end
|
||||
|
||||
--- Inject a custom left flow order provider, this should accept a player and return a list of elements definitions to draw
|
||||
function Gui.inject_left_flow_order(provider)
|
||||
Gui.get_left_flow_order = provider
|
||||
local debug_info = debug.getinfo(2, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or "<anonymous:"..debug_info.linedefined..">"
|
||||
Gui._left_flow_order_src = file_name..":"..func_name
|
||||
end
|
||||
|
||||
--[[-- Draw all the left elements onto the left flow, internal use only with on join
|
||||
@tparam LuaPlayer player the player that you want to draw the elements for
|
||||
|
||||
@@ -92,22 +106,33 @@ function Gui.draw_left_flow(player)
|
||||
local hide_button = left_flow.gui_core_buttons[hide_left_flow]
|
||||
local show_hide_button = false
|
||||
|
||||
for element_define, open_on_join in pairs(Gui.left_elements) do
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_left_flow_order(player)
|
||||
if #flow_order ~= #Gui.left_elements then
|
||||
error(string.format("Left flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._left_flow_order_src, #Gui.left_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
for _, element_define in ipairs(flow_order) do
|
||||
-- Draw the element to the left flow
|
||||
local draw_success, left_element = xpcall(function()
|
||||
return element_define(left_flow)
|
||||
end, debug.traceback)
|
||||
|
||||
if not draw_success then
|
||||
error('There as been an error with an element draw function: '..element_define.defined_at..'\n\t'..left_element)
|
||||
log('There as been an error with an element draw function: '..element_define.defined_at..'\n\t'..left_element)
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- Check if it should be open by default
|
||||
local open_on_join = element_define.open_on_join
|
||||
local visible = type(open_on_join) == 'boolean' and open_on_join or false
|
||||
if type(open_on_join) == 'function' then
|
||||
local success, err = pcall(open_on_join, player)
|
||||
local success, err = xpcall(open_on_join, debug.traceback, player)
|
||||
if not success then
|
||||
error('There as been an error with an open on join hander for a gui element:\n\t'..err)
|
||||
log('There as been an error with an open on join hander for a gui element:\n\t'..err)
|
||||
goto continue
|
||||
end
|
||||
visible = err
|
||||
end
|
||||
@@ -116,23 +141,35 @@ function Gui.draw_left_flow(player)
|
||||
left_element.visible = visible
|
||||
show_hide_button = show_hide_button or visible
|
||||
|
||||
-- Get the assosiated element define
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
-- Check if the the element has a button attached
|
||||
if element_define.toolbar_button then
|
||||
-- Check if the topflow contains the button
|
||||
local button = top_flow[element_define.toolbar_button]
|
||||
if button then
|
||||
-- Style the button
|
||||
Gui.toolbar_button_style(button, visible)
|
||||
end
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, visible)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
||||
hide_button.visible = show_hide_button
|
||||
end
|
||||
|
||||
--- Reorder the left flow elements to match that returned by the provider, uses a method equivalent to insert sort
|
||||
function Gui.reorder_left_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_left_flow_order(player)
|
||||
if #flow_order ~= #Gui.left_elements then
|
||||
error(string.format("Left flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._left_flow_order_src, #Gui.left_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Reorder the elements, index 1 is the core ui buttons so +1 is required
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
local element = left_flow[element_define.name]
|
||||
left_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- Update the visible state of the hide button, can be used to check if any frames are visible
|
||||
@tparam LuaPlayer player the player to update the left flow for
|
||||
@treturn boolean true if any left element is visible
|
||||
@@ -144,7 +181,7 @@ local visible = Gui.update_left_flow(player)
|
||||
function Gui.update_left_flow(player)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local hide_button = left_flow.gui_core_buttons[hide_left_flow]
|
||||
for element_define, _ in pairs(Gui.left_elements) do
|
||||
for _, element_define in ipairs(Gui.left_elements) do
|
||||
local left_element = left_flow[element_define.name]
|
||||
if left_element.visible then
|
||||
hide_button.visible = true
|
||||
@@ -169,20 +206,18 @@ function Gui.hide_left_flow(player)
|
||||
|
||||
-- Set the visible state of all elements in the flow
|
||||
hide_button.visible = false
|
||||
for element_define, _ in pairs(Gui.left_elements) do
|
||||
for _, element_define in ipairs(Gui.left_elements) do
|
||||
left_flow[element_define.name].visible = false
|
||||
|
||||
-- Check if the the element has a toobar button attached
|
||||
if element_define.toolbar_button then
|
||||
-- Check if the topflow contains the button
|
||||
local button = top_flow[element_define.toolbar_button]
|
||||
local button = top_flow[element_define.toolbar_button.name]
|
||||
if button then
|
||||
-- Style the button
|
||||
Gui.toolbar_button_style(button, false)
|
||||
-- Get the button define from the reverse lookup on the element
|
||||
local button_define = Gui.defines[element_define.toolbar_button]
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, false)
|
||||
-- Raise the custom event if all of the top checks have passed
|
||||
button_define:raise_custom_event{
|
||||
element_define.toolbar_button:raise_event{
|
||||
name = Gui.events.on_visibility_changed_by_click,
|
||||
element = button,
|
||||
state = false
|
||||
@@ -192,6 +227,12 @@ function Gui.hide_left_flow(player)
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks if an element is loaded, used internally when the normal left gui assumptions may not hold
|
||||
function Gui.left_flow_loaded(player, element_define)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
return left_flow[element_define.name] ~= nil
|
||||
end
|
||||
|
||||
--[[-- Get the element define that is in the left flow, use in events without an element refrence
|
||||
@tparam LuaPlayer player the player that you want to get the element for
|
||||
@tparam table element_define the element that you want to get
|
||||
@@ -203,7 +244,7 @@ local frame = Gui.get_left_element(game.player, example_flow_with_button)
|
||||
]]
|
||||
function Gui.get_left_element(player, element_define)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
return left_flow[element_define.name]
|
||||
return assert(left_flow[element_define.name], "Left element failed to load")
|
||||
end
|
||||
|
||||
--[[-- Toggles the visible state of a left element for a given player, can be used to set the visible state
|
||||
@@ -220,23 +261,15 @@ Gui.toggle_top_flow(game.player, example_flow_with_button, true)
|
||||
|
||||
]]
|
||||
function Gui.toggle_left_element(player, element_define, state)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
-- Set the visible state
|
||||
local element = left_flow[element_define.name]
|
||||
local element = Gui.get_left_element(player, element_define)
|
||||
if state == nil then state = not element.visible end
|
||||
element.visible = state
|
||||
Gui.update_left_flow(player)
|
||||
|
||||
-- Check if the the element has a button attached
|
||||
if element_define.toolbar_button then
|
||||
-- Check if the topflow contains the button
|
||||
local button = top_flow[element_define.toolbar_button]
|
||||
if button then
|
||||
-- Style the button
|
||||
Gui.toolbar_button_style(button, state)
|
||||
end
|
||||
Gui.toggle_toolbar_button(player, element_define.toolbar_button, state)
|
||||
end
|
||||
return state
|
||||
end
|
||||
@@ -23,20 +23,46 @@ local Gui = {
|
||||
--- The prototype used to store the functions of an element define
|
||||
_prototype_element = {},
|
||||
--- The prototype metatable applied to new element defines
|
||||
_mt_element = {
|
||||
__call = function(self, parent, ...)
|
||||
local element = self._draw(self, parent, ...)
|
||||
if self._style then self._style(element.style, element, ...) end
|
||||
if self.name and self.name ~= element.name then
|
||||
error("Static name \""..self.name.."\" expected but got: "..tostring(element.name))
|
||||
end
|
||||
return element and self:triggers_events(element)
|
||||
end
|
||||
}
|
||||
_mt_element = {}
|
||||
}
|
||||
|
||||
--- Allow access to the element prototype methods
|
||||
Gui._mt_element.__index = Gui._prototype_element
|
||||
|
||||
--- Allows the define to be called to draw the element
|
||||
function Gui._mt_element.__call(self, parent, ...)
|
||||
local element, no_events = self._draw(self, parent, ...)
|
||||
if self._style then self._style(element.style, element, ...) end
|
||||
|
||||
-- Asserts to catch common errors
|
||||
if element then
|
||||
if self.name and self.name ~= element.name then
|
||||
error("Static name \""..self.name.."\" expected but got: "..tostring(element.name))
|
||||
end
|
||||
local event_triggers = element.tags and element.tags.ExpGui_event_triggers
|
||||
if event_triggers and table.array_contains(event_triggers, self.uid) then
|
||||
error("Element::triggers_events should not be called on the value you return from the definition")
|
||||
end
|
||||
elseif self.name then
|
||||
error("Static name \""..self.name.."\" expected but no element was returned from the definition")
|
||||
end
|
||||
|
||||
-- Register events by default, but allow skipping them
|
||||
if no_events == self.no_events then
|
||||
return element
|
||||
else
|
||||
return element and self:triggers_events(element)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get where a function was defined as a string
|
||||
local function get_defined_at(level)
|
||||
local debug_info = debug.getinfo(level, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or "<anonymous:"..debug_info.linedefined..">"
|
||||
return file_name..":"..func_name
|
||||
end
|
||||
|
||||
--- Element Define.
|
||||
-- @section elementDefine
|
||||
|
||||
@@ -97,20 +123,21 @@ function Gui.element(element_define)
|
||||
if element_define.name == Gui.unique_static_name then
|
||||
element_define.name = "ExpGui_"..tostring(uid)
|
||||
end
|
||||
element.name = element_define.name
|
||||
for k, v in pairs(element_define) do
|
||||
if element[k] == nil then
|
||||
element[k] = v
|
||||
end
|
||||
end
|
||||
element._draw = function(_, parent)
|
||||
return parent.add(element_define)
|
||||
end
|
||||
else
|
||||
Gui.debug_info[uid].draw = 'Function'
|
||||
Gui.debug_info[uid].draw = get_defined_at(element_define)
|
||||
element._draw = element_define
|
||||
end
|
||||
|
||||
-- Add the define to the base module
|
||||
local debug_info = debug.getinfo(2, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or "<anonymous:"..debug_info.linedefined..">"
|
||||
element.defined_at = file_name..":"..func_name
|
||||
element.defined_at = get_defined_at(3)
|
||||
Gui.file_paths[uid] = element.defined_at
|
||||
Gui.defines[uid] = element
|
||||
|
||||
@@ -154,6 +181,7 @@ end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:style(style_define)
|
||||
_C.error_if_runtime()
|
||||
-- Add the definition function
|
||||
if type(style_define) == 'table' then
|
||||
Gui.debug_info[self.uid].style = style_define
|
||||
@@ -163,7 +191,7 @@ function Gui._prototype_element:style(style_define)
|
||||
end
|
||||
end
|
||||
else
|
||||
Gui.debug_info[self.uid].style = 'Function'
|
||||
Gui.debug_info[self.uid].style = get_defined_at(style_define)
|
||||
self._style = style_define
|
||||
end
|
||||
|
||||
@@ -176,6 +204,7 @@ end
|
||||
@treturn table the element define is returned to allow for event handlers to be registered
|
||||
]]
|
||||
function Gui._prototype_element:static_name(name)
|
||||
_C.error_if_runtime()
|
||||
if name == Gui.unique_static_name then
|
||||
self.name = "ExpGui_"..tostring(self.uid)
|
||||
else
|
||||
@@ -185,16 +214,20 @@ function Gui._prototype_element:static_name(name)
|
||||
end
|
||||
|
||||
--[[-- Used to link an element to an element define such that any event on the element will call the handlers on the element define
|
||||
-- You should not call this on the element you return from your constructor because this is done automatically
|
||||
@tparam LuaGuiElement element The element that will trigger calls to the event handlers
|
||||
@treturn LuaGuiElement The element passed as the argument to allow for cleaner returns
|
||||
]]
|
||||
function Gui._prototype_element:triggers_events(element)
|
||||
if not self._has_events then return element end
|
||||
local tags = element.tags
|
||||
if not tags then
|
||||
element.tags = { ExpGui_event_triggers = { self.uid } }
|
||||
return element
|
||||
elseif not tags.ExpGui_event_triggers then
|
||||
tags.ExpGui_event_triggers = { self.uid }
|
||||
elseif table.array_contains(tags.ExpGui_event_triggers, self.uid) then
|
||||
error("Element::triggers_events called multiple times on the same element with the same definition")
|
||||
else
|
||||
table.insert(tags.ExpGui_event_triggers, self.uid)
|
||||
end
|
||||
@@ -203,21 +236,28 @@ function Gui._prototype_element:triggers_events(element)
|
||||
return element
|
||||
end
|
||||
|
||||
--- Explicitly skip events on the element returned by your definition function
|
||||
function Gui._prototype_element:no_events(element)
|
||||
return element, self.no_events
|
||||
end
|
||||
|
||||
--[[-- Set the handler which will be called for a custom event, only one handler can be used per event per element
|
||||
@tparam string event_name the name of the event you want to handler to be called on, often from Gui.events
|
||||
@tparam function handler the handler that you want to be called when the event is raised
|
||||
@treturn table the element define so more handleres can be registered
|
||||
|
||||
@usage-- Register a handler to "my_custom_event" for this element
|
||||
element_deinfe:on_custom_event('my_custom_event', function(event)
|
||||
element_deinfe:on_event('my_custom_event', function(event)
|
||||
event.player.print(player.name)
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:on_custom_event(event_name, handler)
|
||||
function Gui._prototype_element:on_event(event_name, handler)
|
||||
_C.error_if_runtime()
|
||||
table.insert(Gui.debug_info[self.uid].events, event_name)
|
||||
Gui.events[event_name] = event_name
|
||||
self[event_name] = handler
|
||||
self._has_events = true
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -226,13 +266,13 @@ end
|
||||
@treturn table the element define so more events can be raised
|
||||
|
||||
@usage Raising a custom event
|
||||
element_define:raise_custom_event{
|
||||
element_define:raise_event{
|
||||
name = 'my_custom_event',
|
||||
element = element
|
||||
}
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:raise_custom_event(event)
|
||||
function Gui._prototype_element:raise_event(event)
|
||||
-- Check the element is valid
|
||||
local element = event.element
|
||||
if not element or not element.valid then
|
||||
@@ -270,15 +310,14 @@ local function event_handler_factory(event_name)
|
||||
for _, uid in pairs(event_triggers) do
|
||||
local element_define = Gui.defines[uid]
|
||||
if element_define then
|
||||
element_define:raise_custom_event(event)
|
||||
element_define:raise_event(event)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Gui.events[event_name] = event_name
|
||||
return function(self, handler)
|
||||
table.insert(Gui.debug_info[self.uid].events, debug.getinfo(1, "n").name)
|
||||
self[event_name] = handler
|
||||
return self
|
||||
return self:on_event(event_name, handler)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
local Gui = require 'expcore.gui.prototype'
|
||||
local mod_gui = require 'mod-gui' --- @dep mod-gui
|
||||
|
||||
local toolbar_button_size = 36
|
||||
local hide_top_flow = Gui.core_defines.hide_top_flow.name
|
||||
local show_top_flow = Gui.core_defines.show_top_flow.name
|
||||
|
||||
--- Top Flow.
|
||||
-- @section topFlow
|
||||
|
||||
-- Triggered when a user changed the visibility of a left flow element by clicking a button
|
||||
Gui.events.on_toolbar_button_toggled = 'on_toolbar_button_toggled'
|
||||
|
||||
--- Contains the uids of the elements that will shown on the top flow and their auth functions
|
||||
-- @table top_elements
|
||||
Gui.top_elements = {}
|
||||
@@ -21,8 +25,30 @@ Gui.top_elements = {}
|
||||
Gui.top_flow_button_style = mod_gui.button_style
|
||||
|
||||
--- The style that should be used for buttons on the top flow when their flow is visible
|
||||
-- @field Gui.top_flow_button_visible_style
|
||||
Gui.top_flow_button_visible_style = 'menu_button_continue'
|
||||
-- @field Gui.top_flow_button_toggled_style
|
||||
Gui.top_flow_button_toggled_style = 'menu_button_continue'
|
||||
|
||||
--[[-- Styles a top flow button depending on the state given
|
||||
@tparam LuaGuiElement button the button element to style
|
||||
@tparam boolean state The state the button is in
|
||||
|
||||
@usage-- Sets the button to the visible style
|
||||
Gui.toolbar_button_style(button, true)
|
||||
|
||||
@usage-- Sets the button to the hidden style
|
||||
Gui.toolbar_button_style(button, false)
|
||||
|
||||
]]
|
||||
function Gui.toolbar_button_style(button, state, size)
|
||||
if state then
|
||||
button.style = Gui.top_flow_button_toggled_style
|
||||
else
|
||||
button.style = Gui.top_flow_button_style
|
||||
end
|
||||
button.style.minimal_width = size or toolbar_button_size
|
||||
button.style.height = size or toolbar_button_size
|
||||
button.style.padding = -2
|
||||
end
|
||||
|
||||
--[[-- Gets the flow refered to as the top flow, each player has one top flow
|
||||
@function Gui.get_top_flow(player)
|
||||
@@ -48,11 +74,43 @@ end)
|
||||
|
||||
]]
|
||||
function Gui._prototype_element:add_to_top_flow(authenticator)
|
||||
_C.error_if_runtime()
|
||||
if not self.name then error("Elements for the top flow must have a static name") end
|
||||
Gui.top_elements[self] = authenticator or true
|
||||
self.authenticator = authenticator or true
|
||||
table.insert(Gui.top_elements, self)
|
||||
return self
|
||||
end
|
||||
|
||||
--- Returns true if the top flow has visible elements
|
||||
function Gui.top_flow_has_visible_elements(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
for _, child in pairs(top_flow.children) do
|
||||
if child.name ~= hide_top_flow then
|
||||
if child.visible then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
Gui._top_flow_order_src = "<default>"
|
||||
--- Get the order of elements in the top flow, first argument is player but is unused in the default method
|
||||
function Gui.get_top_flow_order(_)
|
||||
return Gui.top_elements
|
||||
end
|
||||
|
||||
--- Inject a custom top flow order provider, this should accept a player and return a list of elements definitions to draw
|
||||
function Gui.inject_top_flow_order(provider)
|
||||
Gui.get_top_flow_order = provider
|
||||
local debug_info = debug.getinfo(2, "Sn")
|
||||
local file_name = debug_info.source:match('^.+/currently%-playing/(.+)$'):sub(1, -5)
|
||||
local func_name = debug_info.name or "<anonymous:"..debug_info.linedefined..">"
|
||||
Gui._top_flow_order_src = file_name..":"..func_name
|
||||
end
|
||||
|
||||
--[[-- Updates the visible state of all the elements on the players top flow, uses authenticator
|
||||
@tparam LuaPlayer player the player that you want to update the top flow for
|
||||
|
||||
@@ -62,21 +120,62 @@ Gui.update_top_flow(game.player)
|
||||
]]
|
||||
function Gui.update_top_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
local hide_button = top_flow[hide_top_flow]
|
||||
local is_visible = hide_button.visible
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_top_flow_order(player)
|
||||
if #flow_order ~= #Gui.top_elements then
|
||||
error(string.format("Top flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._top_flow_order_src, #Gui.top_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Set the visible state of all elements in the flow
|
||||
for element_define, authenticator in pairs(Gui.top_elements) do
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
-- Ensure the element exists
|
||||
local element = top_flow[element_define.name]
|
||||
if not element then
|
||||
element = element_define(top_flow)
|
||||
else
|
||||
top_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
|
||||
-- Set the visible state
|
||||
local allowed = authenticator
|
||||
local allowed = element_define.authenticator
|
||||
if type(allowed) == 'function' then allowed = allowed(player) end
|
||||
element.visible = is_visible and allowed or false
|
||||
element.visible = allowed or false
|
||||
|
||||
-- If its not visible and there is a left element, then hide it
|
||||
if element_define.left_flow_element and not element.visible and Gui.left_flow_loaded(player, element_define.left_flow_element) then
|
||||
Gui.toggle_left_element(player, element_define.left_flow_element, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if there are any visible elements in the top flow
|
||||
if not Gui.top_flow_has_visible_elements(player) then
|
||||
-- None are visible so hide the top_flow and its show button
|
||||
Gui.toggle_top_flow(player, false)
|
||||
local left_flow = Gui.get_left_flow(player)
|
||||
local show_button = left_flow.gui_core_buttons[show_top_flow]
|
||||
show_button.visible = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Reorder the top flow elements to match that returned by the provider, uses a method equivalent to insert sort
|
||||
function Gui.reorder_top_flow(player)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
|
||||
-- Get the order to draw the elements in
|
||||
local flow_order = Gui.get_top_flow_order(player)
|
||||
if #flow_order ~= #Gui.top_elements then
|
||||
error(string.format("Top flow order provider (%s) did not return the correct element count, expect %d got %d",
|
||||
Gui._top_flow_order_src, #Gui.top_elements, #flow_order
|
||||
))
|
||||
end
|
||||
|
||||
-- Reorder the elements, index 1 is the core ui buttons so +1 is required
|
||||
for index, element_define in ipairs(flow_order) do
|
||||
local element = top_flow[element_define.name]
|
||||
top_flow.swap_children(index+1, element.get_index_in_parent())
|
||||
end
|
||||
end
|
||||
|
||||
@@ -119,7 +218,33 @@ local button = Gui.get_top_element(game.player, example_button)
|
||||
]]
|
||||
function Gui.get_top_element(player, element_define)
|
||||
local top_flow = Gui.get_top_flow(player)
|
||||
return top_flow[element_define.name]
|
||||
return assert(top_flow[element_define.name], "Top element failed to load")
|
||||
end
|
||||
|
||||
--[[-- Toggles the state of a toolbar button for a given player, can be used to set the visual state
|
||||
@tparam LuaPlayer player the player that you want to toggle the element for
|
||||
@tparam table element_define the element that you want to toggle
|
||||
@tparam[opt] boolean state with given will set the state, else state will be toggled
|
||||
@treturn boolean the new visible state of the element
|
||||
|
||||
@usage-- Toggle your example button
|
||||
Gui.toggle_toolbar_button(game.player, toolbar_button)
|
||||
|
||||
@usage-- Show your example button
|
||||
Gui.toggle_toolbar_button(game.player, toolbar_button, true)
|
||||
|
||||
]]
|
||||
function Gui.toggle_toolbar_button(player, element_define, state)
|
||||
local toolbar_button = Gui.get_top_element(player, element_define)
|
||||
if state == nil then state = toolbar_button.style.name ~= Gui.top_flow_button_toggled_style end
|
||||
Gui.toolbar_button_style(toolbar_button, state, toolbar_button.style.minimal_width)
|
||||
element_define:raise_event{
|
||||
name = Gui.events.on_toolbar_button_toggled,
|
||||
element = toolbar_button,
|
||||
player = player,
|
||||
state = state
|
||||
}
|
||||
return state
|
||||
end
|
||||
|
||||
--[[-- Creates a button on the top flow with consistent styling
|
||||
@@ -143,31 +268,47 @@ function Gui.toolbar_button(sprite, tooltip, authenticator)
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
minimal_width = 36,
|
||||
height = 36,
|
||||
minimal_width = toolbar_button_size,
|
||||
height = toolbar_button_size,
|
||||
padding = -2
|
||||
}
|
||||
:add_to_top_flow(authenticator)
|
||||
end
|
||||
|
||||
--[[-- Styles a top flow button depending on the state given
|
||||
@tparam LuaGuiElement button the button element to style
|
||||
@tparam boolean state The state the button is in
|
||||
--[[-- Creates a toggle button on the top flow with consistent styling
|
||||
@tparam string sprite the sprite that you want to use on the button
|
||||
@tparam ?string|Concepts.LocalizedString tooltip the tooltip that you want the button to have
|
||||
@tparam[opt] function authenticator used to decide if the button should be visible to a player
|
||||
|
||||
@usage-- Sets the button to the visible style
|
||||
Gui.toolbar_button_style(button, true)
|
||||
|
||||
@usage-- Sets the button to the hidden style
|
||||
Gui.toolbar_button_style(button, false)
|
||||
@usage-- Add a button to the toolbar
|
||||
local toolbar_button =
|
||||
Gui.toolbar_toggle_button('entity/inserter', 'Nothing to see here', function(player)
|
||||
return player.admin
|
||||
end)
|
||||
:on_event(Gui.events.on_toolbar_button_toggled, function(player, element, event)
|
||||
game.print(table.inspect(event))
|
||||
end)
|
||||
|
||||
]]
|
||||
function Gui.toolbar_button_style(button, state)
|
||||
if state then
|
||||
button.style = Gui.top_flow_button_visible_style
|
||||
else
|
||||
button.style = Gui.top_flow_button_style
|
||||
end
|
||||
button.style.minimal_width = 36
|
||||
button.style.height = 36
|
||||
button.style.padding = -2
|
||||
function Gui.toolbar_toggle_button(sprite, tooltip, authenticator)
|
||||
local button =
|
||||
Gui.element{
|
||||
type = 'sprite-button',
|
||||
sprite = sprite,
|
||||
tooltip = tooltip,
|
||||
style = Gui.top_flow_button_style,
|
||||
name = Gui.unique_static_name
|
||||
}
|
||||
:style{
|
||||
minimal_width = toolbar_button_size,
|
||||
height = toolbar_button_size,
|
||||
padding = -2
|
||||
}
|
||||
:add_to_top_flow(authenticator)
|
||||
|
||||
button:on_click(function(player, _, _)
|
||||
Gui.toggle_toolbar_button(player, button)
|
||||
end)
|
||||
|
||||
return button
|
||||
end
|
||||
Reference in New Issue
Block a user