mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 03:25:23 +09:00
Add toolbar saving and better consistency
This commit is contained in:
@@ -130,18 +130,17 @@ end
|
||||
local function ensure_elements(player, element_defines, elements, parent)
|
||||
local done = {}
|
||||
for define, visible in pairs(element_defines) do
|
||||
done[define.name] = true
|
||||
local element = elements[define.name]
|
||||
if not element or not element.valid then
|
||||
element = define(parent)
|
||||
element = assert(define(parent), "Element define did not return an element: " .. define.name)
|
||||
elements[define.name] = element
|
||||
assert(element, "Element define did not return an element: " .. define.name)
|
||||
|
||||
if type(visible) == "function" then
|
||||
visible = visible(player, element)
|
||||
end
|
||||
element.visible = visible
|
||||
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
|
||||
@@ -154,7 +153,7 @@ end
|
||||
|
||||
--- Ensure all elements have been created
|
||||
--- @param event EventData.on_player_created | EventData.on_player_joined_game
|
||||
function ExpGui._ensure_elements(event)
|
||||
function ExpGui._ensure_consistency(event)
|
||||
local player = assert(game.get_player(event.player_index))
|
||||
local elements = player_elements[event.player_index]
|
||||
if not elements then
|
||||
@@ -171,7 +170,7 @@ function ExpGui._ensure_elements(event)
|
||||
ensure_elements(player, ExpGui.relative_elements, elements.relative, player.gui.relative)
|
||||
|
||||
--- @diagnostic disable-next-line invisible
|
||||
ExpGui.toolbar._ensure_elements(player)
|
||||
ExpGui.toolbar._create_elements(player)
|
||||
--- @diagnostic disable-next-line invisible
|
||||
ExpGui.toolbar._ensure_consistency(player)
|
||||
end
|
||||
@@ -202,8 +201,8 @@ end
|
||||
|
||||
local e = defines.events
|
||||
local events = {
|
||||
[e.on_player_created] = ExpGui._ensure_elements,
|
||||
[e.on_player_joined_game] = ExpGui._ensure_elements,
|
||||
[e.on_player_created] = ExpGui._ensure_consistency,
|
||||
[e.on_player_joined_game] = ExpGui._ensure_consistency,
|
||||
[e.on_gui_opened] = on_gui_opened,
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ ExpGui.toolbar = Toolbar
|
||||
local elements = {}
|
||||
Toolbar.elements = elements
|
||||
|
||||
local toolbar_buttons = {} --- @type ExpElement[]
|
||||
local left_elements_with_button = {} --- @type table<ExpElement, ExpElement>
|
||||
local buttons_with_left_element = {} --- @type table<string, ExpElement>
|
||||
|
||||
@@ -214,38 +215,11 @@ function Toolbar.create_button(options)
|
||||
end
|
||||
|
||||
-- Add the define to the top flow and return
|
||||
toolbar_buttons[#toolbar_buttons + 1] = toolbar_button
|
||||
ExpGui.add_top_element(toolbar_button, visible)
|
||||
return toolbar_button
|
||||
end
|
||||
|
||||
--- Ensure all the toolbar buttons are in a consistent state
|
||||
--- @param player LuaPlayer
|
||||
function Toolbar._ensure_consistency(player)
|
||||
-- Update clear_left_flow
|
||||
local has_visible = Toolbar.has_visible_left_elements(player)
|
||||
for _, clear_left_flow in elements.clear_left_flow:tracked_elements(player) do
|
||||
clear_left_flow.visible = has_visible
|
||||
end
|
||||
|
||||
-- Update open_toolbar
|
||||
local top_flow = assert(ExpGui.get_top_flow(player).parent)
|
||||
for _, open_toolbar in elements.open_toolbar:tracked_elements(player) do
|
||||
open_toolbar.visible = not top_flow.visible
|
||||
end
|
||||
|
||||
-- Update toggle_toolbar
|
||||
local has_buttons = Toolbar.has_visible_buttons(player)
|
||||
for _, toggle_toolbar in elements.toggle_toolbar:tracked_elements(player) do
|
||||
toggle_toolbar.enabled = has_buttons
|
||||
end
|
||||
|
||||
-- Update the state of buttons with left elements
|
||||
for left_element, button in pairs(left_elements_with_button) do
|
||||
local element = ExpGui.get_left_element(left_element, player)
|
||||
Toolbar.set_button_toggled_state(button, player, element.visible)
|
||||
end
|
||||
end
|
||||
|
||||
--- Toggles the toolbar settings, RMB will instead hide the toolbar
|
||||
elements.close_toolbar = ExpGui.element("close_toolbar")
|
||||
:draw{
|
||||
@@ -388,13 +362,6 @@ local function move_toolbar_button(player, item, offset)
|
||||
item_data.move_item_down.enabled = false
|
||||
other_item_data.move_item_down.enabled = true
|
||||
end
|
||||
|
||||
--[[ Update the datastore state
|
||||
ToolbarState:update(player, function(_, order)
|
||||
local tmp = order[old_index]
|
||||
order[old_index] = order[new_index]
|
||||
order[new_index] = tmp
|
||||
end)]]
|
||||
end
|
||||
|
||||
--- @alias ExpGui.ToolbarOrder { name: string, favourite: boolean }[]
|
||||
@@ -404,35 +371,35 @@ end
|
||||
--- @param order ExpGui.ToolbarOrder
|
||||
function Toolbar.set_order(player, order)
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local left_flow = ExpGui.get_left_flow(player)
|
||||
local top_flow = ExpGui.get_top_flow(player)
|
||||
|
||||
-- Reorder the buttons
|
||||
local left_index = 1
|
||||
local last_index = #order
|
||||
for index, item_state in ipairs(order) do
|
||||
-- Switch item order
|
||||
local item = assert(list[item_state.name], "Missing toolbox item for " .. tostring(item_state.name))
|
||||
list.swap_children(index, item.get_index_in_parent())
|
||||
|
||||
-- Update the item visibility
|
||||
-- Switch the toolbar button order
|
||||
local element_define = ExpElement.get(item_state.name)
|
||||
local allowed = ExpGui.top_elements[element_define]
|
||||
local toolbar_button = ExpGui.get_top_element(element_define, player)
|
||||
if type(allowed) == "function" then allowed = allowed(player, toolbar_button) end
|
||||
top_flow.swap_children(index + 1, toolbar_button.get_index_in_parent())
|
||||
toolbar_button.visible = allowed and item_state.favourite or false
|
||||
item.visible = toolbar_button.visible
|
||||
|
||||
-- Update the children buttons
|
||||
local data = elements.toolbar_list_item.data[item]
|
||||
data.set_favourite.state = item_state.favourite
|
||||
data.move_item_up.enabled = index ~= 1
|
||||
data.move_item_down.enabled = index ~= last_index
|
||||
end
|
||||
|
||||
-- Update the state of the toggle button
|
||||
local has_buttons = Toolbar.has_visible_buttons(player)
|
||||
for _, toggle_toolbar in elements.toggle_toolbar:tracked_elements(player) do
|
||||
toggle_toolbar.enabled = has_buttons
|
||||
-- Switch the left element order
|
||||
local left_define = buttons_with_left_element[item_state.name]
|
||||
if left_define then
|
||||
local left_element = ExpGui.get_left_element(left_define, player)
|
||||
left_flow.swap_children(left_index, left_element.get_index_in_parent())
|
||||
left_index = left_index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -470,11 +437,35 @@ function Toolbar.set_state(player, state)
|
||||
end
|
||||
end
|
||||
|
||||
--- Get the full toolbar state for a player
|
||||
--- @param player LuaPlayer
|
||||
--- @return ExpGui.ToolbarState
|
||||
function Toolbar.get_state(player)
|
||||
-- Get the order of toolbar buttons
|
||||
local order = {}
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
for index, item in pairs(list.children) do
|
||||
order[index] = { name = item.name, favourite = elements.toolbar_list_item.data[item].set_favourite.state }
|
||||
end
|
||||
|
||||
-- Get the names of all open left elements
|
||||
local open, open_index = {}, 1
|
||||
for left_element in pairs(ExpGui.left_elements) do
|
||||
if Toolbar.get_left_element_visible_state(left_element, player) then
|
||||
open[open_index] = left_element.name
|
||||
open_index = open_index + 1
|
||||
end
|
||||
end
|
||||
|
||||
return { order = order, open = open, visible = Toolbar.get_visible_state(player) }
|
||||
end
|
||||
|
||||
--- Ensure the toolbar settings gui has all its elements
|
||||
--- @param player LuaPlayer
|
||||
function Toolbar._ensure_elements(player)
|
||||
function Toolbar._create_elements(player)
|
||||
-- Add any missing items to the gui
|
||||
local toolbar_list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
local previous_last_index = #toolbar_list.children_names
|
||||
for define in pairs(ExpGui.top_elements) do
|
||||
if define ~= elements.close_toolbar and toolbar_list[define.name] == nil then
|
||||
local element = elements.toolbar_list_item(toolbar_list, define)
|
||||
@@ -482,14 +473,64 @@ function Toolbar._ensure_elements(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the state of the move buttons for the first and last element
|
||||
-- Reset the state of the previous last child
|
||||
local children = toolbar_list.children
|
||||
if previous_last_index > 0 then
|
||||
elements.toolbar_list_item.data[children[previous_last_index]].move_item_down.enabled = true
|
||||
end
|
||||
|
||||
-- Set the state of the move buttons for the first and last element
|
||||
if #children > 0 then
|
||||
elements.toolbar_list_item.data[children[1]].move_item_up.enabled = false
|
||||
elements.toolbar_list_item.data[children[#children]].move_item_down.enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
--- Ensure all the toolbar buttons are in a consistent state
|
||||
--- @param player LuaPlayer
|
||||
function Toolbar._ensure_consistency(player)
|
||||
-- Update the toolbar buttons
|
||||
local list = elements.toolbar_settings.data[player] --[[ @as LuaGuiElement ]]
|
||||
for _, button in ipairs(toolbar_buttons) do
|
||||
-- Update the visible state based on if the player is allowed the button
|
||||
local element = ExpGui.get_top_element(button, player)
|
||||
local allowed = ExpGui.top_elements[button]
|
||||
if type(allowed) == "function" then
|
||||
allowed = allowed(player, element)
|
||||
end
|
||||
element.visible = allowed and element.visible or false
|
||||
list[button.name].visible = element.visible
|
||||
|
||||
-- Update the toggle state and hide the linked left element if the button is not allowed
|
||||
local left_define = buttons_with_left_element[button.name]
|
||||
if left_define then
|
||||
local left_element = ExpGui.get_left_element(left_define, player)
|
||||
Toolbar.set_button_toggled_state(button, player, left_element.visible)
|
||||
if not allowed then
|
||||
Toolbar.set_left_element_visible_state(left_define, player, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Update clear_left_flow
|
||||
local has_visible = Toolbar.has_visible_left_elements(player)
|
||||
for _, clear_left_flow in elements.clear_left_flow:tracked_elements(player) do
|
||||
clear_left_flow.visible = has_visible
|
||||
end
|
||||
|
||||
-- Update open_toolbar
|
||||
local top_flow = assert(ExpGui.get_top_flow(player).parent)
|
||||
for _, open_toolbar in elements.open_toolbar:tracked_elements(player) do
|
||||
open_toolbar.visible = not top_flow.visible
|
||||
end
|
||||
|
||||
-- Update toggle_toolbar
|
||||
local has_buttons = Toolbar.has_visible_buttons(player)
|
||||
for _, toggle_toolbar in elements.toggle_toolbar:tracked_elements(player) do
|
||||
toggle_toolbar.enabled = has_buttons
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local default_order --- @type ExpGui.ToolbarOrder
|
||||
--- Gets the default order for the toolbar
|
||||
@@ -542,7 +583,6 @@ elements.reset_toolbar = ExpGui.element("reset_toolbar")
|
||||
})
|
||||
:on_click(function(def, event, element)
|
||||
local player = ExpGui.get_player(event)
|
||||
--ToolbarState:set(player, nil)
|
||||
Toolbar.set_order(player, Toolbar.get_default_order())
|
||||
end)
|
||||
|
||||
@@ -616,12 +656,6 @@ elements.set_favourite = ExpGui.element("set_favourite")
|
||||
toggle_toolbar.enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Update the datastore state
|
||||
ToolbarState:update(player, function(_, order)
|
||||
local index = element.parent.get_index_in_parent()
|
||||
order[index].favourite = element.state
|
||||
end)]]
|
||||
end)
|
||||
|
||||
elements.toolbar_list_item = ExpGui.element("toolbar_list_item")
|
||||
@@ -703,7 +737,7 @@ elements.toolbar_settings = ExpGui.element("toolbar_settings")
|
||||
elements.reset_toolbar(header)
|
||||
|
||||
def.data[player] = elements.toolbar_list(frame)
|
||||
Toolbar._ensure_elements(player)
|
||||
Toolbar._create_elements(player)
|
||||
return frame.parent
|
||||
end)
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ return {
|
||||
"modules.gui.production",
|
||||
"modules.gui.playerdata",
|
||||
"modules.gui.surveillance",
|
||||
|
||||
"modules.gui._role_updates",
|
||||
|
||||
"modules.graftorio.require", -- graftorio
|
||||
--- Config Files
|
||||
"config.expcore.permission_groups", -- loads some predefined permission groups
|
||||
|
||||
@@ -1,190 +1,31 @@
|
||||
local Gui = require("modules/exp_gui")
|
||||
local ExpElement = require("modules/exp_gui/prototype")
|
||||
local PlayerData = require("modules.exp_legacy.expcore.player_data") --- @dep expcore.player_data
|
||||
local PlayerData = require("modules.exp_legacy.expcore.player_data")
|
||||
|
||||
-- Used to store the state of the toolbar when a player leaves
|
||||
local ToolbarState = PlayerData.Settings:combine("ToolbarState")
|
||||
ToolbarState:set_metadata{
|
||||
stringify = function(value)
|
||||
local buttons, favourites = 0, 0
|
||||
for _, state in ipairs(value) do
|
||||
buttons = buttons + 1
|
||||
if state.favourite then
|
||||
favourites = favourites + 1
|
||||
end
|
||||
end
|
||||
|
||||
return string.format("Buttons: %d, Favourites: %d", buttons, favourites)
|
||||
stringify = function()
|
||||
return "Toolbar is saved on exit"
|
||||
end,
|
||||
}
|
||||
|
||||
--- Set the default value for the datastore
|
||||
local datastore_id_map = {} --- @type table<string, ExpElement>
|
||||
local toolbar_default_state = {}
|
||||
ToolbarState:set_default(toolbar_default_state)
|
||||
|
||||
--- Get the datastore id for this element define, to best of ability it should be unique between versions
|
||||
local function to_datastore_id(element_define)
|
||||
-- First try to use the tooltip locale string
|
||||
local tooltip = element_define.tooltip
|
||||
if type(tooltip) == "table" then
|
||||
return tooltip[1]:gsub("%.(.+)", "")
|
||||
end
|
||||
|
||||
-- Then try to use the caption or sprite
|
||||
return element_define.caption or element_define.sprite
|
||||
end
|
||||
|
||||
--- For all top element, register an on click which will copy their style
|
||||
for index, element_define in ipairs(Gui.top_elements) do
|
||||
-- Insert the element into the id map
|
||||
datastore_id_map[to_datastore_id(element_define)] = element_define -- Backwards Compatibility
|
||||
datastore_id_map[element_define.name] = element_define
|
||||
|
||||
-- Add the element to the default state
|
||||
table.insert(toolbar_default_state, {
|
||||
element = element_define.uid,
|
||||
favourite = true,
|
||||
})
|
||||
end
|
||||
|
||||
--- Get the top order based on the players settings
|
||||
Gui.inject_top_flow_order(function(player)
|
||||
local order = ToolbarState:get(player)
|
||||
|
||||
local elements = {}
|
||||
for index, state in ipairs(order) do
|
||||
elements[index] = Gui.defines[state.element]
|
||||
end
|
||||
|
||||
return elements
|
||||
end)
|
||||
|
||||
--- Get the left order based on the player settings, with toolbar menu first, and all remaining after
|
||||
Gui.inject_left_flow_order(function(player)
|
||||
local order = Gui.get_top_flow_order(player)
|
||||
local elements, element_map = { toolbar_container }, { [toolbar_container] = true }
|
||||
|
||||
-- Add the flows that have a top element
|
||||
for _, element_define in ipairs(order) do
|
||||
if element_define.left_flow_element then
|
||||
table.insert(elements, element_define.left_flow_element)
|
||||
element_map[element_define.left_flow_element] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Add the flows that dont have a top element
|
||||
for _, element_define in ipairs(Gui.left_elements) do
|
||||
if not element_map[element_define] then
|
||||
table.insert(elements, element_define)
|
||||
end
|
||||
end
|
||||
|
||||
return elements
|
||||
end)
|
||||
|
||||
--- Overwrite the default update top flow
|
||||
local _update_top_flow = Gui.update_top_flow
|
||||
function Gui.update_top_flow(player)
|
||||
_update_top_flow(player) -- Call the original
|
||||
|
||||
local order = ToolbarState:get(player)
|
||||
for index, state in ipairs(order) do
|
||||
local element_define = Gui.defines[state.element]
|
||||
local top_element = Gui.get_top_element(player, element_define)
|
||||
top_element.visible = top_element.visible and state.favourite or false
|
||||
end
|
||||
end
|
||||
|
||||
--- Uncompress the data to be more useable
|
||||
ToolbarState:on_load(function(player_name, value)
|
||||
-- If there is no value, do nothing
|
||||
if value == nil then return end
|
||||
--- @cast value [ string[], string[], string[], boolean ]
|
||||
-- Old format, we discard it [ string[], string[], string[], boolean ]
|
||||
if type(value) ~= "string" then return end
|
||||
|
||||
-- Create a hash map of the favourites
|
||||
local favourites = {}
|
||||
for _, id in ipairs(value[2]) do
|
||||
favourites[id] = true
|
||||
end
|
||||
|
||||
-- Read the order from the value
|
||||
local elements = {}
|
||||
local element_hash = {}
|
||||
for index, id in ipairs(value[1]) do
|
||||
local element = datastore_id_map[id]
|
||||
if element and not element_hash[element.name] then
|
||||
element_hash[element.name] = true
|
||||
elements[index] = {
|
||||
element = element,
|
||||
favourite = favourites[id] or false,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Add any in the default state that are missing
|
||||
for _, state in ipairs(toolbar_default_state) do
|
||||
if not element_hash[state.element] then
|
||||
table.insert(elements, table.deep_copy(state))
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a hash map of the open left flows
|
||||
local open_left_elements = {}
|
||||
for _, id in ipairs(value[3]) do
|
||||
local element = datastore_id_map[id]
|
||||
local left_element = element.left_flow_element
|
||||
if left_element then
|
||||
open_left_elements[left_element] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the visible state of all left flows
|
||||
local decompressed = helpers.json_to_table(assert(helpers.decode_string(value), "Failed String Decode"))
|
||||
local player = assert(game.get_player(player_name))
|
||||
for left_element in pairs(Gui.left_elements) do
|
||||
Gui.set_left_element_visible(left_element, player, open_left_elements[left_element] or false)
|
||||
end
|
||||
Gui.toolbar.set_state(player, decompressed --[[ @as ExpGui.ToolbarState ]])
|
||||
|
||||
-- Set the toolbar visible state
|
||||
Gui.set_top_flow_visible(player, value[4])
|
||||
|
||||
-- Set the data now and update now, ideally this would be on_update but that had too large of a latency
|
||||
ToolbarState:raw_set(player_name, elements)
|
||||
Gui.reorder_top_flow(player)
|
||||
Gui.reorder_left_flow(player)
|
||||
reorder_toolbar_menu(player)
|
||||
|
||||
return elements
|
||||
return nil -- We don't save the state, use Gui.toolbar.get_state
|
||||
end)
|
||||
|
||||
--- Save the current state of the players toolbar menu
|
||||
ToolbarState:on_save(function(player_name, value)
|
||||
if value == nil then return nil end -- Don't save default
|
||||
local order, favourites, left_flows = {}, {}, {}
|
||||
|
||||
ToolbarState:on_save(function(player_name, _)
|
||||
local player = assert(game.get_player(player_name))
|
||||
local top_flow_open = Gui.get_top_flow(player).parent.visible
|
||||
|
||||
for index, state in ipairs(value) do
|
||||
-- Add the element to the order array
|
||||
--- @diagnostic disable-next-line invisible
|
||||
local element_define = ExpElement._elements[state.element]
|
||||
local id = to_datastore_id(element_define)
|
||||
order[index] = id
|
||||
|
||||
-- If its a favourite then insert it
|
||||
if state.favourite then
|
||||
table.insert(favourites, id)
|
||||
end
|
||||
|
||||
-- If it has a left flow and its open then insert it
|
||||
if element_define.left_flow_element then
|
||||
local left_element = Gui.get_left_element(element_define.left_flow_element, player)
|
||||
if left_element.visible then
|
||||
table.insert(left_flows, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return { order, favourites, left_flows, top_flow_open }
|
||||
local value = Gui.toolbar.get_state(player)
|
||||
return helpers.encode_string(helpers.table_to_json(value))
|
||||
end)
|
||||
|
||||
7
exp_legacy/module/modules/gui/_role_updates.lua
Normal file
7
exp_legacy/module/modules/gui/_role_updates.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
local Gui = require("modules/exp_gui")
|
||||
local Roles = require("modules.exp_legacy.expcore.roles")
|
||||
local Event = require("modules/exp_legacy/utils/event")
|
||||
|
||||
--- @diagnostic disable invisible
|
||||
Event.add(Roles.events.on_role_assigned, Gui._ensure_consistency)
|
||||
Event.add(Roles.events.on_role_unassigned, Gui._ensure_consistency)
|
||||
Reference in New Issue
Block a user