1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-16 02:47:48 +02:00
ComfyFactorio/utils/gui.lua

1093 lines
32 KiB
Lua
Raw Normal View History

2019-02-26 21:25:59 +02:00
local Token = require 'utils.token'
2018-09-19 06:51:25 +02:00
local Event = require 'utils.event'
2019-02-26 21:25:59 +02:00
local Global = require 'utils.global'
2021-10-23 00:04:48 +02:00
local mod_gui = require('__core__/lualib/mod-gui')
2022-04-05 19:28:08 +02:00
local Server = require 'utils.server'
local SpamProtection = require 'utils.spam_protection'
2018-09-19 06:51:25 +02:00
2023-09-23 15:57:08 +02:00
local insert = table.insert
2020-07-25 17:22:04 +02:00
local tostring = tostring
local next = next
2022-04-05 19:28:08 +02:00
local Public = {}
2024-01-31 23:19:48 +02:00
Public.events = {
on_gui_removal = Event.generate_event_name('on_gui_removal'),
on_gui_closed_main_frame = Event.generate_event_name('on_gui_closed_main_frame')
}
2018-09-19 06:51:25 +02:00
2022-04-05 19:28:08 +02:00
-- local to this file
local local_settings = {
toggle_button = false
}
2022-04-05 19:28:08 +02:00
local main_gui_tabs = {}
local screen_elements = {}
2023-08-10 14:29:05 +02:00
local remove_data_recursively
2024-06-04 23:27:12 +02:00
local concat = table.concat
local names = {}
2022-04-05 19:28:08 +02:00
-- global
2019-02-26 21:25:59 +02:00
local data = {}
2022-04-05 19:28:08 +02:00
local settings = {
2024-05-30 09:28:49 +02:00
mod_gui_top_frame = false,
2023-06-22 22:57:07 +02:00
disabled_tabs = {},
disable_clear_invalid_data = true
2022-04-05 19:28:08 +02:00
}
2018-09-19 06:51:25 +02:00
2022-04-05 19:28:08 +02:00
Public.token =
2020-07-25 17:22:04 +02:00
Global.register(
2024-06-04 23:27:12 +02:00
{ data = data, settings = settings },
function (tbl)
data = tbl.data
settings = tbl.settings
end
)
Public.names = names
2019-02-26 21:25:59 +02:00
2022-07-10 20:27:18 +02:00
Public.beam = 'file/utils/files/beam.png'
Public.beam_1 = 'file/utils/files/beam_1.png'
Public.beam_2 = 'file/utils/files/beam_2.png'
2022-04-05 19:28:08 +02:00
Public.settings_white_icon = 'file/utils/files/settings-white.png'
Public.settings_black_icon = 'file/utils/files/settings-black.png'
Public.pin_white_icon = 'file/utils/files/pin-white.png'
Public.pin_black_icon = 'file/utils/files/pin-black.png'
Public.infinite_icon = 'file/utils/files/infinity.png'
Public.arrow_up_icon = 'file/utils/files/arrow-up.png'
Public.arrow_down_icon = 'file/utils/files/arrow-down.png'
2024-05-29 19:57:58 +02:00
Public.tidal_icon = 'file/utils/files/tidal.png'
Public.spew_icon = 'file/utils/files/spew.png'
Public.berserk_icon = 'file/utils/files/berserk.png'
Public.warp_icon = 'file/utils/files/warp.png'
Public.x_icon = 'file/utils/files/x.png'
2022-04-18 01:18:06 +02:00
Public.info_icon = 'file/utils/files/info.png'
Public.mod_gui_button_enabled = false
2019-02-26 21:25:59 +02:00
2022-04-05 19:28:08 +02:00
function Public.uid_name()
2024-06-04 23:27:12 +02:00
if game then
return error('This function is not allowed to be called in this context.', 2)
end
local info = debug.getinfo(2, 'Sl')
local filepath = info.source:match('^@__level__/(.+)$'):sub(1, -5)
2024-06-04 23:27:12 +02:00
local line = info.currentline
local token = tostring(Token.uid())
local name = concat { token, ' - ', filepath, ':line:', line }
names[token] = name
return token
2018-09-19 06:51:25 +02:00
end
2022-04-05 19:28:08 +02:00
function Public.uid()
2020-08-31 20:37:27 +02:00
return Token.uid()
end
2022-04-05 19:28:08 +02:00
local main_frame_name = Public.uid_name()
local main_toggle_button_name = Public.uid_name()
2022-04-05 19:28:08 +02:00
local main_button_name = Public.uid_name()
local close_button_name = Public.uid_name()
if not Public.mod_gui_button_enabled then
Public.button_style = nil
end
2022-09-22 20:42:46 +02:00
Public.top_main_gui_button = main_button_name
Public.main_frame_name = main_frame_name
Public.main_toggle_button_name = main_toggle_button_name
2024-05-27 20:30:03 +02:00
Public.frame_style = 'non_draggable_frame'
Public.button_style = 'mod_gui_button'
Public.top_flow_button_enabled_style = 'menu_button_continue'
Public.top_flow_button_disabled_style = Public.button_style
2022-09-22 20:42:46 +02:00
2022-08-12 19:13:48 +02:00
--- Verifies if a frame is valid and destroys it.
---@param align userdata
---@param frame userdata
local function validate_frame_and_destroy(align, frame)
local get_frame = align[frame]
if get_frame and get_frame.valid then
2023-08-10 14:29:05 +02:00
remove_data_recursively(frame)
2022-08-12 19:13:48 +02:00
get_frame.destroy()
end
end
2018-09-19 06:51:25 +02:00
-- Associates data with the LuaGuiElement. If data is nil then removes the data
2022-04-05 19:28:08 +02:00
function Public.set_data(element, value)
2023-11-29 01:48:08 +02:00
if not element or not element.valid then
return
end
2023-11-29 01:48:20 +02:00
2020-07-25 17:22:04 +02:00
local player_index = element.player_index
local values = data[player_index]
if value == nil then
if not values then
return
end
2021-04-04 13:51:27 +02:00
values[element.index] = nil
2020-07-25 17:22:04 +02:00
if next(values) == nil then
data[player_index] = nil
end
else
if not values then
values = {}
data[player_index] = values
end
2024-06-04 23:27:12 +02:00
values[element.index] = { value = value, name = element.name }
2020-07-25 17:22:04 +02:00
end
2018-09-19 06:51:25 +02:00
end
2024-06-04 23:27:12 +02:00
2022-04-05 19:28:08 +02:00
local set_data = Public.set_data
2018-09-19 06:51:25 +02:00
2023-09-22 22:34:37 +02:00
-- Associates data with the LuaGuiElement. If data is nil then removes the data
function Public.set_data_parent(parent, element, value)
local player_index = parent.player_index
local values = data[player_index]
if value == nil then
if not values then
return
end
values[parent.index] = nil
if next(values) == nil then
data[player_index] = nil
end
else
if not values then
values = {}
data[player_index] = values
end
if not values[parent.index] then
values[parent.index] = {}
end
2024-06-04 23:27:12 +02:00
values[parent.index][element.index] = { value = value, name = element.name }
2023-11-14 00:58:43 +02:00
end
end
2018-09-19 06:51:25 +02:00
-- Gets the Associated data with this LuaGuiElement if any.
2022-04-05 19:28:08 +02:00
function Public.get_data(element)
2021-06-06 20:14:26 +02:00
if not element then
return
end
2020-07-25 17:22:04 +02:00
local player_index = element.player_index
local values = data[player_index]
if not values then
return nil
end
2024-06-04 23:27:12 +02:00
return values[element.index].value
2018-09-19 06:51:25 +02:00
end
2023-09-22 22:34:37 +02:00
-- Gets the Associated data with this LuaGuiElement if any.
function Public.get_data_parent(parent, element)
if not parent then
return
end
if not element then
return
end
local player_index = parent.player_index
local values = data[player_index]
if not values then
return nil
end
values = values[parent.index]
if not values then
return nil
end
2024-06-04 23:27:12 +02:00
return values[element.index].value
2023-11-14 00:58:43 +02:00
end
2022-04-05 19:28:08 +02:00
-- Adds a gui that is alike the factorio native gui.
2024-06-04 23:27:12 +02:00
function Public.add_main_frame_with_toolbar(player, align, set_frame_name, set_settings_button_name,
close_main_frame_name, name, info, inside_table_count)
2022-04-05 19:28:08 +02:00
if not align then
return
end
local main_frame
if align == 'left' then
2022-08-12 19:13:48 +02:00
validate_frame_and_destroy(player.gui.left, set_frame_name)
2024-06-04 23:27:12 +02:00
main_frame = player.gui.left.add { type = 'frame', name = set_frame_name, direction = 'vertical' }
2022-04-05 19:28:08 +02:00
elseif align == 'center' then
2022-08-12 19:13:48 +02:00
validate_frame_and_destroy(player.gui.center, set_frame_name)
2024-06-04 23:27:12 +02:00
main_frame = player.gui.center.add { type = 'frame', name = set_frame_name, direction = 'vertical' }
2022-04-05 19:28:08 +02:00
elseif align == 'screen' then
2022-08-12 19:13:48 +02:00
validate_frame_and_destroy(player.gui.screen, set_frame_name)
2024-06-04 23:27:12 +02:00
main_frame = player.gui.screen.add { type = 'frame', name = set_frame_name, direction = 'vertical' }
2022-04-05 19:28:08 +02:00
end
2024-06-04 23:27:12 +02:00
local titlebar = main_frame.add { type = 'flow', name = 'titlebar', direction = 'horizontal' } --[[@as LuaGuiElement]]
2022-04-05 19:28:08 +02:00
titlebar.style.horizontal_spacing = 8
titlebar.style = 'horizontal_flow'
if align == 'screen' then
titlebar.drag_target = main_frame
end
titlebar.add {
type = 'label',
name = 'main_label',
style = 'frame_title',
caption = name,
ignored_by_interaction = true
}
2024-06-04 23:27:12 +02:00
local widget = titlebar.add { type = 'empty-widget', style = 'draggable_space', ignored_by_interaction = true }
2022-04-05 19:28:08 +02:00
widget.style.left_margin = 4
widget.style.right_margin = 4
widget.style.height = 24
widget.style.horizontally_stretchable = true
if set_settings_button_name then
2022-04-18 01:18:06 +02:00
if not info then
titlebar.add {
type = 'sprite-button',
name = set_settings_button_name,
style = 'frame_action_button',
sprite = Public.settings_white_icon,
2024-06-04 23:27:12 +02:00
mouse_button_filter = { 'left' },
2022-04-18 01:18:06 +02:00
hovered_sprite = Public.settings_black_icon,
clicked_sprite = Public.settings_black_icon,
tooltip = 'Settings',
tags = {
action = 'open_settings_gui'
}
2022-04-05 19:28:08 +02:00
}
2022-04-18 01:18:06 +02:00
else
titlebar.add {
type = 'sprite-button',
name = set_settings_button_name,
style = 'frame_action_button',
sprite = Public.info_icon,
2024-06-04 23:27:12 +02:00
mouse_button_filter = { 'left' },
2022-04-18 01:18:06 +02:00
hovered_sprite = Public.info_icon,
clicked_sprite = Public.info_icon,
tooltip = 'Info',
tags = {
action = 'open_settings_gui'
}
}
end
2022-04-05 19:28:08 +02:00
end
if close_main_frame_name then
titlebar.add {
type = 'sprite-button',
name = close_main_frame_name,
style = 'frame_action_button',
2024-06-04 23:27:12 +02:00
mouse_button_filter = { 'left' },
sprite = 'utility/close',
hovered_sprite = 'utility/close_fat',
clicked_sprite = 'utility/close_fat',
2022-04-05 19:28:08 +02:00
tooltip = 'Close',
tags = {
action = 'close_main_frame_gui'
}
}
end
local inside_frame =
main_frame.add {
2024-06-04 23:27:12 +02:00
type = 'table',
column_count = 1 or inside_table_count,
name = 'inside_frame'
}
2022-04-05 19:28:08 +02:00
return main_frame, inside_frame
2022-04-05 19:28:08 +02:00
end
2019-02-26 21:25:59 +02:00
-- Removes data associated with LuaGuiElement and its children recursively.
2022-04-05 19:28:08 +02:00
function Public.remove_data_recursively(element)
2020-07-25 17:22:04 +02:00
set_data(element, nil)
2018-09-19 06:51:25 +02:00
local children = element.children
if not children then
return
end
2020-07-25 17:22:04 +02:00
for _, child in next, children do
2018-09-19 06:51:25 +02:00
if child.valid then
2020-07-25 17:22:04 +02:00
remove_data_recursively(child)
2018-09-19 06:51:25 +02:00
end
end
end
2024-06-04 23:27:12 +02:00
2022-04-05 19:28:08 +02:00
remove_data_recursively = Public.remove_data_recursively
2018-09-19 06:51:25 +02:00
2020-07-25 17:22:04 +02:00
local remove_children_data
2022-04-05 19:28:08 +02:00
function Public.remove_children_data(element)
2018-09-19 06:51:25 +02:00
local children = element.children
if not children then
return
end
2020-07-25 17:22:04 +02:00
for _, child in next, children do
2018-09-19 06:51:25 +02:00
if child.valid then
2020-07-25 17:22:04 +02:00
set_data(child, nil)
remove_children_data(child)
2018-09-19 06:51:25 +02:00
end
end
end
2024-06-04 23:27:12 +02:00
2022-04-05 19:28:08 +02:00
remove_children_data = Public.remove_children_data
2018-09-19 06:51:25 +02:00
2022-04-05 19:28:08 +02:00
function Public.destroy(element)
2023-09-23 15:57:08 +02:00
if not element then
return
end
2020-07-25 17:22:04 +02:00
remove_data_recursively(element)
2018-09-19 06:51:25 +02:00
element.destroy()
end
2022-04-05 19:28:08 +02:00
function Public.clear(element)
2020-07-25 17:22:04 +02:00
remove_children_data(element)
2018-09-19 06:51:25 +02:00
element.clear()
end
2021-05-23 17:03:52 +02:00
local function clear_invalid_data()
if settings.disable_clear_invalid_data then
return
end
for _, player in pairs(game.players) do
2020-09-12 19:16:38 +02:00
local player_index = player.index
local values = data[player_index]
if values then
2021-05-23 17:03:52 +02:00
for k, element in next, values do
2020-09-12 19:16:38 +02:00
if type(element) == 'table' then
for key, obj in next, element do
if type(obj) == 'table' and obj.valid ~= nil then
if not obj.valid then
element[key] = nil
end
end
end
2021-05-23 17:03:52 +02:00
if type(element) == 'userdata' and not element.valid then
values[k] = nil
end
2020-09-12 19:16:38 +02:00
end
end
end
end
end
Event.on_nth_tick(300, clear_invalid_data)
2018-09-19 06:51:25 +02:00
local function handler_factory(event_id)
local handlers
local function on_event(event)
local element = event.element
if not element or not element.valid then
return
end
local handler = handlers[element.name]
if not handler then
return
end
2020-07-25 17:22:04 +02:00
local player = game.get_player(event.player_index)
2020-12-14 20:36:37 +02:00
if not (player and player.valid) then
2018-09-19 06:51:25 +02:00
return
end
2021-01-12 22:52:45 +02:00
2018-09-19 06:51:25 +02:00
event.player = player
2023-09-23 15:57:08 +02:00
if type(handler) == 'function' then
handler(event)
else
for i = 1, #handler do
local callback = handler[i]
if callback then
callback(event)
end
end
end
2018-09-19 06:51:25 +02:00
end
2024-06-04 23:27:12 +02:00
return function (element_name, handler)
2023-09-23 15:57:08 +02:00
if not element_name then
return error('Element name is required when passing it onto the handler_factory.', 2)
end
if not handler or not type(handler) == 'function' then
2024-06-04 23:27:12 +02:00
return error(
'Handler is required when passing it onto the handler_factory and needs to be of type function.', 2)
2023-09-23 15:57:08 +02:00
end
2018-09-19 06:51:25 +02:00
if not handlers then
handlers = {}
Event.add(event_id, on_event)
end
2023-09-23 15:57:08 +02:00
if handlers[element_name] then
local old = handlers[element_name]
handlers[element_name] = {}
insert(handlers[element_name], old)
insert(handlers[element_name], handler)
else
handlers[element_name] = handler
end
2018-09-19 06:51:25 +02:00
end
end
2021-03-24 21:14:55 +02:00
--luacheck: ignore custom_raise
2022-04-07 16:11:57 +02:00
---@diagnostic disable-next-line: unused-function, unused-local
2019-02-26 21:25:59 +02:00
local function custom_raise(handlers, element, player)
local handler = handlers[element.name]
if not handler then
return
end
2024-06-04 23:27:12 +02:00
handler({ element = element, player = player })
2019-02-26 21:25:59 +02:00
end
2021-05-23 17:03:52 +02:00
-- Disabled the handler so it does not clean then data table of invalid data.
2022-04-05 19:28:08 +02:00
function Public.set_disable_clear_invalid_data(value)
2021-05-23 17:03:52 +02:00
settings.disable_clear_invalid_data = value or false
end
-- Gets state if the cleaner handler is active or false
2022-04-05 19:28:08 +02:00
function Public.get_disable_clear_invalid_data()
2021-05-23 17:03:52 +02:00
return settings.disable_clear_invalid_data
end
2022-04-08 22:39:15 +02:00
-- Disable a gui.
---@param frame_name string
---@param state boolean?
function Public.set_disabled_tab(frame_name, state)
if not frame_name then
return
end
settings.disabled_tabs[frame_name] = state or false
end
-- Fetches if a gui is disabled.
---@param frame_name string
function Public.get_disabled_tab(frame_name)
if not frame_name then
return
end
return settings.disabled_tabs[frame_name]
end
2022-04-05 19:28:08 +02:00
-- Fetches the main frame name
function Public.get_main_frame(player)
if not player then
return false
end
local left = player.gui.left
local frame = left[main_frame_name]
if frame and frame.valid then
local inside_frame = frame.children[2]
if inside_frame and inside_frame.valid then
return inside_frame
2022-04-05 19:28:08 +02:00
end
return false
end
return false
end
-- Fetches the parent frame name
function Public.get_parent_frame(player)
if not player then
return false
end
local left = player.gui.left
local frame = left[main_frame_name]
if frame and frame.valid then
return frame
end
return false
end
--- This adds the given gui to the top gui.
---@param player LuaPlayer
2022-07-11 00:14:21 +02:00
---@param frame userdata|table
2022-04-05 19:28:08 +02:00
function Public.add_mod_button(player, frame)
if Public.get_button_flow(player)[frame.name] and Public.get_button_flow(player)[frame.name].valid then
return Public.get_button_flow(player)[frame.name]
2022-04-05 19:28:08 +02:00
end
2024-05-27 20:30:03 +02:00
return Public.get_button_flow(player).add(frame)
2022-04-05 19:28:08 +02:00
end
2022-04-07 16:11:57 +02:00
---@param state boolean
2022-04-05 19:28:08 +02:00
--- If we should use the new mod gui or not
function Public.set_mod_gui_top_frame(state)
settings.mod_gui_top_frame = state or false
end
--- Get mod_gui_top_frame
function Public.get_mod_gui_top_frame()
return settings.mod_gui_top_frame
end
---@param state boolean
--- If we should show the toggle button or not
function Public.set_toggle_button(state)
if _LIFECYCLE == 8 then
error('Calling Gui.set_toggle_button after on_init() or on_load() has run is a desync risk.', 2)
end
local_settings.toggle_button = state or false
end
--- Get toggle_button state
function Public.get_toggle_button()
if _LIFECYCLE == 8 then
error('Calling Gui.get_toggle_button after on_init() or on_load() has run is a desync risk.', 2)
end
return local_settings.toggle_button
end
2022-04-05 19:28:08 +02:00
--- This adds the given gui to the main gui.
2022-04-07 16:11:57 +02:00
---@param tbl table
2022-04-05 19:28:08 +02:00
function Public.add_tab_to_gui(tbl)
if _LIFECYCLE == 8 then
error('Calling Gui.add_tab_to_gui after on_init() or on_load() has run is a desync risk.', 2)
end
2022-04-05 19:28:08 +02:00
if not tbl then
return
end
if not tbl.name then
return
end
if not tbl.caption then
return
end
if not tbl.id then
return
end
local admin = tbl.admin or false
local only_server_sided = tbl.only_server_sided or false
if not main_gui_tabs[tbl.caption] then
2024-06-04 23:27:12 +02:00
main_gui_tabs[tbl.caption] = { id = tbl.id, name = tbl.name, admin = admin, only_server_sided = only_server_sided }
2022-04-05 19:28:08 +02:00
else
error('Given name: ' .. tbl.caption .. ' already exists in table.')
end
end
function Public.screen_to_bypass(elem)
screen_elements[elem] = true
return screen_elements
end
--- Fetches the main gui tabs. You are forbidden to write as this is local.
2022-04-07 16:11:57 +02:00
---@param key string
2022-04-05 19:28:08 +02:00
function Public.get(key)
if key then
return main_gui_tabs[key]
else
return main_gui_tabs
end
end
function Public.clear_main_frame(player)
if not player then
return
end
local frame = Public.get_main_frame(player)
if frame then
2023-08-10 14:29:05 +02:00
remove_data_recursively(frame)
2022-04-05 19:28:08 +02:00
frame.destroy()
end
end
2022-04-18 01:18:06 +02:00
function Public.clear_all_center_frames(player)
for _, child in pairs(player.gui.center.children) do
2023-08-10 14:29:05 +02:00
remove_data_recursively(child)
2022-04-18 01:18:06 +02:00
child.destroy()
end
end
function Public.clear_all_screen_frames(player)
for _, child in pairs(player.gui.screen.children) do
if not screen_elements[child.name] then
2023-08-10 14:29:05 +02:00
remove_data_recursively(child)
2022-04-18 01:18:06 +02:00
child.destroy()
end
end
end
2022-04-05 19:28:08 +02:00
function Public.clear_all_active_frames(player)
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_closed_main_frame, { player_index = player.index })
2022-04-05 19:28:08 +02:00
for _, child in pairs(player.gui.left.children) do
2023-08-10 14:29:05 +02:00
remove_data_recursively(child)
2022-04-05 19:28:08 +02:00
child.destroy()
end
for _, child in pairs(player.gui.screen.children) do
if not screen_elements[child.name] then
2023-08-10 14:29:05 +02:00
remove_data_recursively(child)
2022-04-05 19:28:08 +02:00
child.destroy()
end
end
for _, child in pairs(player.gui.center.children) do
remove_data_recursively(child)
child.destroy()
end
2022-04-05 19:28:08 +02:00
end
function Public.get_player_active_frame(player)
local main_frame = Public.get_main_frame(player)
if not main_frame then
return false
end
local panel = main_frame.tabbed_pane
if not panel then
return
end
local index = panel.selected_tab_index
if not index then
return panel.tabs[1].content
end
return panel.tabs[index].content
end
local function get_player_active_tab(player)
local main_frame = Public.get_main_frame(player)
if not main_frame then
return false
end
local panel = main_frame.tabbed_pane
if not panel then
return
end
local index = panel.selected_tab_index
if not index then
return panel.tabs[1].tab, panel.tabs[1].content
end
return panel.tabs[index].tab, panel.tabs[index].content
end
function Public.reload_active_tab(player, forced)
local is_spamming = SpamProtection.is_spamming(player, nil, 'Reload active tab')
if is_spamming and not forced then
return
end
local frame, main_tab = get_player_active_tab(player)
if not frame then
return
end
local tab = main_gui_tabs[frame.caption]
if not tab then
return
end
local id = tab.id
if not id then
return
end
local callback = Token.get(id)
2022-04-05 19:28:08 +02:00
local d = {
player = player,
frame = main_tab
}
return callback(d)
2022-04-05 19:28:08 +02:00
end
local function top_button(player)
if settings.mod_gui_top_frame then
2024-06-04 23:27:12 +02:00
local button = Public.add_mod_button(player,
{ type = 'sprite-button', name = main_button_name, sprite = 'item/raw-fish', style = Public.button_style })
2024-05-27 20:30:03 +02:00
if button then
button.style.minimal_height = 36
button.style.maximal_height = 36
button.style.minimal_width = 40
button.style.padding = -2
end
2022-04-05 19:28:08 +02:00
else
if player.gui.top[main_button_name] then
return
end
2024-06-04 23:27:12 +02:00
local button = player.gui.top.add({
type = 'sprite-button',
name = main_button_name,
sprite = 'item/raw-fish',
style = Public.button_style
})
2022-04-05 19:28:08 +02:00
button.style.minimal_height = 38
button.style.maximal_height = 38
button.style.minimal_width = 40
button.style.padding = -2
end
end
local function top_toggle_button(player)
if not player or not player.valid then
return
end
2024-05-27 20:30:03 +02:00
if Public.get_mod_gui_top_frame() then
local b =
Public.add_mod_button(
2024-06-04 23:27:12 +02:00
player,
{
type = 'sprite-button',
name = main_toggle_button_name,
sprite = 'utility/preset',
tooltip = 'Click to hide top buttons!',
style = Public.button_style
}
)
2024-05-27 20:30:03 +02:00
if b then
2024-06-04 23:27:12 +02:00
b.style.font_color = { 165, 165, 165 }
b.style.font = 'default-semibold'
2024-05-27 20:30:03 +02:00
b.style.minimal_height = 36
b.style.maximal_height = 36
b.style.minimal_width = 15
b.style.maximal_width = 15
b.style.padding = -2
end
else
local b =
player.gui.top.add(
2024-06-04 23:27:12 +02:00
{
type = 'sprite-button',
name = main_toggle_button_name,
sprite = 'utility/preset',
style = Public.button_style,
tooltip = 'Click to hide top buttons!'
}
)
2024-05-27 20:30:03 +02:00
b.style.padding = 2
b.style.width = 20
b.style.maximal_height = 38
end
end
2022-04-05 19:28:08 +02:00
local function draw_main_frame(player)
local tabs = main_gui_tabs
2022-06-10 22:06:35 +02:00
2022-04-05 19:28:08 +02:00
Public.clear_all_active_frames(player)
if Public.get_main_frame(player) then
2023-08-10 14:29:05 +02:00
remove_data_recursively(Public.get_main_frame(player))
2022-04-05 19:28:08 +02:00
Public.get_main_frame(player).destroy()
end
2024-03-29 00:37:14 +02:00
local admins = Server.get_admins_data()
2024-06-04 23:27:12 +02:00
local frame, inside_frame = Public.add_main_frame_with_toolbar(player, 'left', main_frame_name, nil,
close_button_name, 'Comfy Factorio')
local tabbed_pane = inside_frame.add({ type = 'tabbed-pane', name = 'tabbed_pane' })
for name, callback in pairs(tabs) do
2022-04-08 22:39:15 +02:00
if not settings.disabled_tabs[name] then
2024-03-29 00:37:14 +02:00
local secs = Server.get_current_time()
if callback.only_server_sided then
2022-04-08 22:39:15 +02:00
if secs then
2024-06-04 23:27:12 +02:00
local tab = tabbed_pane.add({ type = 'tab', caption = name, name = callback.name })
local name_frame = tabbed_pane.add({ type = 'frame', name = name, direction = 'vertical' })
2022-04-08 22:39:15 +02:00
tabbed_pane.add_tab(tab, name_frame)
end
elseif callback.admin == true then
2022-04-08 22:39:15 +02:00
if player.admin then
2024-03-29 00:37:14 +02:00
if not secs then
2024-06-04 23:27:12 +02:00
local tab = tabbed_pane.add({ type = 'tab', caption = name, name = callback.name })
local name_frame = tabbed_pane.add({ type = 'frame', name = name, direction = 'vertical' })
2024-03-29 00:37:14 +02:00
tabbed_pane.add_tab(tab, name_frame)
elseif secs and admins[player.name] then
2024-06-04 23:27:12 +02:00
local tab = tabbed_pane.add({ type = 'tab', caption = name, name = callback.name })
local name_frame = tabbed_pane.add({ type = 'frame', name = name, direction = 'vertical' })
2024-03-29 00:37:14 +02:00
tabbed_pane.add_tab(tab, name_frame)
end
2022-04-08 22:39:15 +02:00
end
else
2024-06-04 23:27:12 +02:00
local tab = tabbed_pane.add({ type = 'tab', caption = name, name = callback.name })
local name_frame = tabbed_pane.add({ type = 'frame', name = name, direction = 'vertical' })
2022-04-05 19:28:08 +02:00
tabbed_pane.add_tab(tab, name_frame)
end
end
end
for _, child in pairs(tabbed_pane.children) do
child.style.padding = 8
child.style.left_padding = 2
child.style.right_padding = 2
end
2024-01-31 23:19:48 +02:00
player.opened = frame
2022-04-05 19:28:08 +02:00
Public.reload_active_tab(player, true)
return frame, inside_frame
end
function Public.get_content(player)
local left_frame = Public.get_main_frame(player)
if not left_frame then
return false
end
return left_frame.tabbed_pane
end
function Public.refresh(player)
local frame = get_player_active_tab(player)
if not frame then
return false
end
local tabbed_pane = Public.get_content(player)
for _, tab in pairs(tabbed_pane.tabs) do
if tab.content.name ~= frame.name then
tab.content.clear()
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_removal, { player_index = player.index })
end
end
Public.reload_active_tab(player, true)
return true
end
2022-04-05 19:28:08 +02:00
function Public.call_existing_tab(player, name)
local frame, inside_frame = draw_main_frame(player)
if not frame then
return
end
2022-10-26 00:05:47 +02:00
if not inside_frame then
return
end
2022-04-05 19:28:08 +02:00
local tabbed_pane = inside_frame.tabbed_pane
for key, v in pairs(tabbed_pane.tabs) do
if v.tab.caption == name then
tabbed_pane.selected_tab_index = key
Public.reload_active_tab(player, true)
end
end
end
2023-11-14 00:58:43 +02:00
Public.get_button_flow = mod_gui.get_button_flow
Public.mod_button = mod_gui.get_button_flow
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_checked_state_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_checked_state_changed = handler_factory(defines.events.on_gui_checked_state_changed)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_click event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_click = handler_factory(defines.events.on_gui_click)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_closed event for a custom LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_custom_close = handler_factory(defines.events.on_gui_closed)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_elem_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_elem_changed = handler_factory(defines.events.on_gui_elem_changed)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_selection_state_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_selection_state_changed = handler_factory(defines.events.on_gui_selection_state_changed)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_text_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_text_changed = handler_factory(defines.events.on_gui_text_changed)
2018-09-19 06:51:25 +02:00
-- Register a handler for the on_gui_value_changed event for LuaGuiElements with element_name.
-- Can only have one handler per element name.
-- Guarantees that the element and the player are valid when calling the handler.
-- Adds a player field to the event table.
2022-04-05 19:28:08 +02:00
Public.on_value_changed = handler_factory(defines.events.on_gui_value_changed)
2018-09-19 06:51:25 +02:00
2022-04-05 19:28:08 +02:00
Public.on_click(
main_button_name,
2024-06-04 23:27:12 +02:00
function (event)
2022-04-05 19:28:08 +02:00
local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Main button')
if is_spamming then
return
end
local player = event.player
local frame = Public.get_parent_frame(player)
2024-05-27 20:30:03 +02:00
2022-04-05 19:28:08 +02:00
if frame then
2023-08-10 14:29:05 +02:00
remove_data_recursively(frame)
2022-04-05 19:28:08 +02:00
frame.destroy()
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_removal, { player_index = player.index })
2024-01-31 23:19:48 +02:00
local active_frame = Public.get_player_active_frame(player)
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_closed_main_frame,
{ player_index = player.index, element = active_frame or nil })
2022-04-05 19:28:08 +02:00
else
draw_main_frame(player)
end
end
)
Public.on_click(
close_button_name,
2024-06-04 23:27:12 +02:00
function (event)
2024-01-31 23:19:48 +02:00
local player = event.player
local frame = Public.get_parent_frame(player)
local active_frame = Public.get_player_active_frame(player)
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_closed_main_frame, { player_index = player.index, element = active_frame or nil })
2024-01-31 23:19:48 +02:00
if frame then
remove_data_recursively(frame)
frame.destroy()
2022-04-05 19:28:08 +02:00
end
2024-01-31 23:19:48 +02:00
end
)
Public.on_custom_close(
main_frame_name,
2024-06-04 23:27:12 +02:00
function (event)
2022-04-05 19:28:08 +02:00
local player = event.player
2024-01-31 23:19:48 +02:00
local active_frame = Public.get_player_active_frame(player)
2024-06-04 23:27:12 +02:00
Event.raise(Public.events.on_gui_closed_main_frame, { player_index = player.index, element = active_frame or nil })
2022-04-05 19:28:08 +02:00
local frame = Public.get_parent_frame(player)
if frame then
2023-08-10 14:29:05 +02:00
remove_data_recursively(frame)
2022-04-05 19:28:08 +02:00
frame.destroy()
end
end
)
Public.on_click(
main_toggle_button_name,
2024-06-04 23:27:12 +02:00
function (event)
local button = event.element
local player = event.player
local top = player.gui.top
if button.sprite == 'utility/preset' then
2024-05-27 20:30:03 +02:00
if Public.get_mod_gui_top_frame() then
for _, ele in pairs(top.mod_gui_top_frame.mod_gui_inner_frame.children) do
if ele and ele.valid and ele.name ~= main_toggle_button_name then
ele.visible = false
end
end
else
for _, ele in pairs(top.children) do
if ele and ele.valid and ele.name ~= main_toggle_button_name then
ele.visible = false
end
end
end
Public.clear_all_active_frames(player)
local main_frame = Public.get_main_frame(player)
if main_frame then
main_frame.destroy()
end
button.sprite = 'utility/expand_dots'
button.tooltip = 'Click to show top buttons!'
else
2024-05-27 20:30:03 +02:00
if Public.get_mod_gui_top_frame() then
for _, ele in pairs(top.mod_gui_top_frame.mod_gui_inner_frame.children) do
if ele and ele.valid and ele.name ~= main_toggle_button_name then
ele.visible = true
end
end
else
for _, ele in pairs(top.children) do
if ele and ele.valid and ele.name ~= main_toggle_button_name then
ele.visible = true
end
end
end
button.sprite = 'utility/preset'
button.tooltip = 'Click to hide top buttons!'
end
end
)
Event.add(
defines.events.on_gui_click,
2024-06-04 23:27:12 +02:00
function (event)
local element = event.element
if not element or not element.valid then
return
end
local player = game.get_player(event.player_index)
local name = element.name
if name == main_button_name then
local is_spamming = SpamProtection.is_spamming(player, nil, 'Main GUI Click')
if is_spamming then
return
end
Public.refresh(player)
end
if not event.element.caption then
return
end
if event.element.type ~= 'tab' then
return
end
local success = Public.refresh(player)
if not success then
Public.reload_active_tab(player)
end
end
)
2022-04-05 19:28:08 +02:00
Event.add(
defines.events.on_player_created,
2024-06-04 23:27:12 +02:00
function (event)
2022-04-05 19:28:08 +02:00
local player = game.get_player(event.player_index)
if local_settings.toggle_button then
top_toggle_button(player)
end
2022-04-05 19:28:08 +02:00
top_button(player)
end
)
Event.add(
defines.events.on_player_joined_game,
2024-06-04 23:27:12 +02:00
function (event)
2022-04-05 19:28:08 +02:00
local player = game.get_player(event.player_index)
top_button(player)
end
)
2021-10-23 00:04:48 +02:00
2024-06-04 23:27:12 +02:00
function Public.data()
return data
2023-11-14 00:58:43 +02:00
end
2022-04-05 19:28:08 +02:00
return Public