305 lines
8.2 KiB
Lua

local math = require("__flib__.math")
local on_tick_n = require("__flib__.on-tick-n")
local constants = require("constants")
local database = require("scripts.database")
local gui_util = require("scripts.gui.util")
local util = require("scripts.util")
local actions = {}
--- @param Gui InfoGui
function actions.set_as_active(Gui, _, _)
Gui.player_table.guis.info._active_id = Gui.id
end
--- @param Gui InfoGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button == defines.mouse_button_type.middle then
Gui.refs.root.force_auto_center()
end
end
--- @param Gui InfoGui
function actions.close(Gui, _, _)
Gui:destroy()
end
--- @param Gui InfoGui
function actions.bring_to_front(Gui, _, _)
if not Gui.state.docked then
Gui.refs.root.bring_to_front()
end
end
--- @param Gui InfoGui
function actions.toggle_search(Gui, _, _)
local state = Gui.state
local refs = Gui.refs
local opened = state.search_opened
state.search_opened = not opened
local search_button = refs.titlebar.search_button
local search_textfield = refs.titlebar.search_textfield
if opened then
search_button.sprite = "utility/search_white"
search_button.style = "frame_action_button"
search_textfield.visible = false
if state.search_query ~= "" then
-- Reset query
search_textfield.text = ""
state.search_query = ""
-- Refresh page
Gui:update_contents()
end
else
-- Show search textfield
search_button.sprite = "utility/search_black"
search_button.style = "flib_selected_frame_action_button"
search_textfield.visible = true
search_textfield.focus()
end
end
--- @param Gui InfoGui
--- @param msg table
--- @param e on_gui_click
function actions.navigate(Gui, msg, e)
-- Update position in history
local delta = msg.delta
local history = Gui.state.history
if e.shift then
if delta < 0 then
history._index = 1
else
history._index = #history
end
else
history._index = math.clamp(history._index + delta, 1, #history)
end
Gui:update_contents()
end
--- @param Gui InfoGui
--- @param msg table
--- @param e on_gui_text_changed
function actions.update_search_query(Gui, msg, e)
local state = Gui.state
local id = msg.id
local query = string.lower(e.element.text)
-- Fuzzy search
if Gui.player_table.settings.general.search.fuzzy_search then
query = string.gsub(query, ".", "%1.*")
end
-- Input sanitization
for pattern, replacement in pairs(constants.input_sanitizers) do
query = string.gsub(query, pattern, replacement)
end
-- Save query
state.search_query = query
-- Remove scheduled update if one exists
if state.update_results_ident then
on_tick_n.remove(state.update_results_ident)
state.update_results_ident = nil
end
if query == "" then
-- Update now
Gui:update_contents({ refresh = true })
else
-- Update in a while
state.update_results_ident = on_tick_n.add(
game.tick + constants.search_timeout,
{ gui = "info", id = id, action = "update_search_results", player_index = e.player_index }
)
end
end
--- @param Gui InfoGui
function actions.update_search_results(Gui, _, _)
-- Update based on query
Gui:update_contents({ refresh = true })
end
--- @param Gui InfoGui
--- @param e on_gui_click
function actions.navigate_to(Gui, _, e)
local context = gui_util.navigate_to(e)
if context then
if e.button == defines.mouse_button_type.middle then
INFO_GUI.build(Gui.player, Gui.player_table, context)
else
Gui:update_contents({ new_context = context })
end
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.navigate_to_plain(Gui, msg, _)
Gui:update_contents({ new_context = msg.context })
end
--- @param Gui InfoGui
function actions.open_in_tech_window(Gui, _, _)
Gui.player_table.flags.technology_gui_open = true
Gui.player.open_technology_gui(Gui:get_context().name)
end
--- @param Gui InfoGui
function actions.go_to_base_fluid(Gui, _, _)
local base_fluid = database.fluid[Gui:get_context().name].prototype_name
Gui:update_contents({ new_context = { class = "fluid", name = base_fluid } })
end
--- @param Gui InfoGui
function actions.toggle_quick_ref(Gui, _, _)
local player = Gui.player
-- Toggle quick ref GUI
local name = Gui:get_context().name
--- @type QuickRefGui?
local QuickRefGui = util.get_gui(player.index, "quick_ref", name)
local to_state = false
if QuickRefGui then
QuickRefGui:destroy()
else
to_state = true
QUICK_REF_GUI.build(player, Gui.player_table, name)
end
-- Update all quick ref buttons
for _, InfoGui in pairs(INFO_GUI.find_open_context(Gui.player_table, Gui:get_context())) do
InfoGui:dispatch({
action = "update_header_button",
button = "quick_ref_button",
to_state = to_state,
})
end
end
--- @param Gui InfoGui
function actions.toggle_favorite(Gui, _, _)
local player_table = Gui.player_table
local favorites = player_table.favorites
local context = Gui:get_context()
local combined_name = context.class .. "." .. context.name
local to_state
if favorites[combined_name] then
to_state = false
favorites[combined_name] = nil
else
-- Copy the table instead of passing a reference
favorites[combined_name] = { class = context.class, name = context.name }
to_state = true
end
for _, InfoGui in pairs(INFO_GUI.find_open_context(Gui.player_table, context)) do
InfoGui:dispatch({ action = "update_header_button", button = "favorite_button", to_state = to_state })
end
local SearchGui = util.get_gui(Gui.player.index, "search")
if SearchGui and SearchGui.refs.window.visible then
SearchGui:dispatch("update_favorites")
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.update_header_button(Gui, msg, _)
local button = Gui.refs.header[msg.button]
if msg.to_state then
button.style = "flib_selected_tool_button"
button.tooltip = constants.header_button_tooltips[msg.button].selected
else
button.style = "tool_button"
button.tooltip = constants.header_button_tooltips[msg.button].unselected
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.open_list(Gui, msg, _)
local list_context = msg.context
local source = msg.source
local list = database[list_context.class][list_context.name][source]
if list and #list > 0 then
local first_obj = list[1]
OPEN_PAGE(Gui.player, Gui.player_table, {
class = first_obj.class,
name = first_obj.name,
list = {
context = list_context,
index = 1,
source = source,
},
})
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.toggle_collapsed(Gui, msg, _)
local context = msg.context
local component_index = msg.component_index
local component_ident = constants.pages[context.class][component_index]
if component_ident then
local state = Gui.state.components[component_index]
if state then
state.collapsed = not state.collapsed
Gui:update_contents({ refresh = true })
end
end
end
--- @param Gui InfoGui
--- @param msg table
function actions.change_tech_level(Gui, msg, _)
local context = Gui:get_context()
local state = Gui.state
local context_data = database[context.class][context.name]
local min = context_data.min_level
local max = context_data.max_level
local new_level = math.clamp(state.selected_tech_level + msg.delta, min, max)
if new_level ~= state.selected_tech_level then
state.selected_tech_level = new_level
Gui:update_contents({ refresh = true })
end
end
--- @param Gui InfoGui
function actions.detach_window(Gui, _, _)
local state = Gui.state
-- Just in case
if not state.docked then
return
end
local context = Gui:get_context()
-- Close this GUI and create a detached one
Gui:destroy()
OPEN_PAGE(Gui.player, Gui.player_table, context)
end
--- @param Gui InfoGui
function actions.print_object(Gui, _, _)
local context = Gui:get_context()
local obj_data = database[context.class][context.name]
if obj_data then
if __DebugAdapter then
__DebugAdapter.print(obj_data)
Gui.player.print("Object data has been printed to the debug console.")
else
log(serpent.block(obj_data))
Gui.player.print("Object data has been printed to the log file.")
end
end
end
return actions