Первый фикс

Пачки некоторых позиций увеличены
This commit is contained in:
2024-03-01 20:53:32 +03:00
commit 7c9c708c92
23653 changed files with 767936 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
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

View File

@@ -0,0 +1,653 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local player_data = require("scripts.player-data")
local util = require("scripts.util")
local components = {
list_box = require("scripts.gui.info.list-box"),
table = require("scripts.gui.info.table"),
}
local function tool_button(sprite, tooltip, ref, action, style_mods)
return {
type = "sprite-button",
style = "tool_button",
style_mods = style_mods,
sprite = sprite,
tooltip = tooltip,
mouse_button_filter = { "left" },
ref = ref,
actions = {
on_click = action,
},
}
end
--- @class InfoGui
local Gui = {}
local actions = require("scripts.gui.info.actions")
function Gui:dispatch(msg, e)
-- Mark this GUI as the active one whenever we do anything
self.player_table.guis.info._active_id = self.id
if type(msg) == "string" then
actions[msg](self, msg, e)
else
actions[msg.action](self, msg, e)
end
end
function Gui:destroy()
self.refs.window.destroy()
self.player_table.guis.info[self.id] = nil
if self.state.docked and not self.state.search_info then
self.player_table.guis.info._relative_id = nil
end
end
function Gui:get_context()
local history = self.state.history
return history[history._index]
end
function Gui:update_contents(options)
options = options or {}
local new_context = options.new_context
local refresh = options.refresh
local state = self.state
local refs = self.refs
-- HISTORY
-- Add new history if needed
local history = state.history
if new_context then
-- Remove all entries after this
for i = history._index + 1, #history do
history[i] = nil
end
-- Insert new entry
local new_index = #history + 1
history[new_index] = new_context
history._index = new_index
-- Limit the length
local max_size = constants.session_history_size
if new_index > max_size then
history._index = max_size
for _ = max_size + 1, new_index do
table.remove(history, 1)
end
end
end
local context = new_context or history[history._index]
if not refresh then
player_data.update_global_history(self.player_table.global_history, context)
local SearchGui = util.get_gui(self.player.index, "search")
if SearchGui then
SearchGui:dispatch("update_history")
end
end
-- COMMON DATA
local obj_data = database[context.class][context.name]
local player_data = formatter.build_player_data(self.player, self.player_table)
local gui_translations = player_data.translations.gui
-- TECH LEVEL
if not refresh and obj_data.research_unit_count_formula then
state.selected_tech_level = player_data.force.technologies[context.name].level
end
-- TITLEBAR
-- Nav buttons
-- Generate tooltips
local history_index = history._index
local history_len = #history
local entries = {}
for i, history_context in ipairs(history) do
local obj_data = database[history_context.class][history_context.name]
local info = formatter(obj_data, player_data, { always_show = true, label_only = true })
local caption = info.caption
if not info.researched then
caption = formatter.rich_text("color", "unresearched", caption)
end
entries[history_len - (i - 1)] = formatter.rich_text(
"font",
"default-semibold",
formatter.rich_text("color", history_index == i and "green" or "invisible", ">")
) .. " " .. caption
end
local entries = table.concat(entries, "\n")
local base_tooltip = formatter.rich_text(
"font",
"default-bold",
formatter.rich_text("color", "heading", gui_translations.session_history)
) .. "\n" .. entries
-- Apply button properties
local nav_backward_button = refs.titlebar.nav_backward_button
if history._index == 1 then
nav_backward_button.enabled = false
nav_backward_button.sprite = "rb_nav_backward_disabled"
else
nav_backward_button.enabled = true
nav_backward_button.sprite = "rb_nav_backward_white"
end
nav_backward_button.tooltip = base_tooltip
.. formatter.control(gui_translations.click, gui_translations.go_backward)
.. formatter.control(gui_translations.shift_click, gui_translations.go_to_the_back)
local nav_forward_button = refs.titlebar.nav_forward_button
if history._index == #history then
nav_forward_button.enabled = false
nav_forward_button.sprite = "rb_nav_forward_disabled"
else
nav_forward_button.enabled = true
nav_forward_button.sprite = "rb_nav_forward_white"
end
nav_forward_button.tooltip = base_tooltip
.. formatter.control(gui_translations.click, gui_translations.go_forward)
.. formatter.control(gui_translations.shift_click, gui_translations.go_to_the_front)
-- Label
local label = refs.titlebar.label
label.caption = gui_translations[context.class]
-- Reset search when moving pages
if not options.refresh and state.search_opened then
state.search_opened = false
local search_button = refs.titlebar.search_button
local search_textfield = refs.titlebar.search_textfield
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 = ""
end
end
-- HEADER
-- List navigation
-- List nav is kind of weird because it doesn't respect your settings, but making it respect the settings would be
-- too much work
local list_context = context.list
if list_context then
local source = list_context.context
local source_data = database[source.class][source.name]
local list = source_data[list_context.source]
local list_len = #list
local index = list_context.index
local list_refs = refs.header.list_nav
list_refs.flow.visible = true
-- Labels
local source_info = formatter(source_data, player_data, { always_show = true })
local source_label = list_refs.source_label
source_label.caption = formatter.rich_text("color", "heading", source_info.caption)
.. " - "
.. gui_translations[list_context.source]
local position_label = list_refs.position_label
position_label.caption = " (" .. index .. " / " .. list_len .. ")"
-- Buttons
for delta, button in pairs({ [-1] = list_refs.back_button, [1] = list_refs.forward_button }) do
local new_index = index + delta
if new_index < 1 then
new_index = list_len
elseif new_index > list_len then
new_index = 1
end
local ident = list[new_index]
gui.set_action(button, "on_click", {
gui = "info",
id = self.id,
action = "navigate_to_plain",
context = {
class = ident.class,
name = ident.name,
list = {
context = source,
index = new_index,
source = list_context.source,
},
},
})
end
refs.header.line.visible = true
else
refs.header.list_nav.flow.visible = false
refs.header.line.visible = false
end
-- Label
local title_info = formatter(obj_data, player_data, { always_show = true, is_label = true })
local label = refs.header.label
label.caption = title_info.caption
label.tooltip = title_info.tooltip
label.style = title_info.researched and "rb_toolbar_label" or "rb_unresearched_toolbar_label"
-- Buttons
if context.class == "technology" then
refs.header.open_in_tech_window_button.visible = true
else
refs.header.open_in_tech_window_button.visible = false
end
if context.class == "fluid" and obj_data.temperature_ident then
local base_fluid_button = refs.header.go_to_base_fluid_button
base_fluid_button.visible = true
gui.set_action(base_fluid_button, "on_click", {
gui = "info",
id = self.id,
action = "navigate_to_plain",
context = obj_data.base_fluid,
})
else
refs.header.go_to_base_fluid_button.visible = false
end
if context.class == "recipe" then
local button = refs.header.quick_ref_button
button.visible = true
local is_selected = self.player_table.guis.quick_ref[context.name]
button.style = is_selected and "flib_selected_tool_button" or "tool_button"
button.tooltip = { "gui.rb-" .. (is_selected and "close" or "open") .. "-quick-ref-window" }
else
refs.header.quick_ref_button.visible = false
end
local favorite_button = refs.header.favorite_button
if self.player_table.favorites[context.class .. "." .. context.name] then
favorite_button.style = "flib_selected_tool_button"
favorite_button.tooltip = { "gui.rb-remove-from-favorites" }
else
favorite_button.style = "tool_button"
favorite_button.tooltip = { "gui.rb-add-to-favorites" }
end
-- PAGE
local pane = refs.page_scroll_pane
local page_refs = refs.page_components
local page_settings = self.player_table.settings.pages[context.class]
local i = 0
local visible = false
local component_variables = {
context = context,
gui_id = self.id,
search_query = state.search_query,
selected_tech_level = state.selected_tech_level,
}
-- Add or update relevant components
for _, component_ident in pairs(constants.pages[context.class]) do
i = i + 1
local component = components[component_ident.type]
local component_refs = page_refs[i]
if not component_refs or component_refs.type ~= component_ident.type then
-- Destroy old elements
if component_refs then
component_refs.root.destroy()
end
-- Create new elements
component_refs = component.build(pane, i, component_ident, component_variables)
component_refs.type = component_ident.type
page_refs[i] = component_refs
end
local component_settings = page_settings[component_ident.label or component_ident.source]
if not refresh then
state.components[i] = component.default_state(component_settings)
end
component_variables.component_index = i
component_variables.component_state = state.components[i]
local comp_visible =
component.update(component_ident, component_refs, obj_data, player_data, component_settings, component_variables)
visible = visible or comp_visible
end
-- Destroy extraneous components
for j = i + 1, #page_refs do
page_refs[j].root.destroy()
page_refs[j] = nil
end
-- Show error frame if nothing is visible
if not visible and not state.warning_shown then
state.warning_shown = true
pane.visible = false
refs.page_frame.style = "rb_inside_warning_frame"
refs.page_frame.style.vertically_stretchable = state.docked and state.search_info
refs.warning_flow.visible = true
if state.search_query == "" then
refs.warning_text.caption = { "gui.rb-no-content-warning" }
else
refs.warning_text.caption = { "gui.rb-no-results" }
end
elseif visible and state.warning_shown then
state.warning_shown = false
pane.visible = true
refs.page_frame.style = "inside_shallow_frame"
refs.page_frame.style.vertically_stretchable = state.docked and state.search_info
refs.warning_flow.visible = false
end
end
local index = {}
--- @param player LuaPlayer
--- @param player_table PlayerTable
--- @param context Context
--- @param options table?
function index.build(player, player_table, context, options)
options = options or {}
local id = player_table.guis.info._next_id
player_table.guis.info._next_id = id + 1
local root_elem = options.parent or player.gui.screen
local search_info = root_elem.name == "rb_search_window" or root_elem.name == "rb_visual_search_window"
local relative = options.parent and not search_info
local refs = gui.build(root_elem, {
{
type = "frame",
style_mods = { minimal_width = 430, maximal_width = 600 },
direction = "vertical",
ref = { "window" },
anchor = options.anchor,
actions = {
on_click = { gui = "info", id = id, action = "set_as_active" },
on_closed = { gui = "info", id = id, action = "close" },
},
{
type = "flow",
style = "flib_titlebar_flow",
ref = { "titlebar", "flow" },
actions = {
on_click = not relative and {
gui = search_info and "search" or "info",
id = not search_info and id or nil,
action = "reset_location",
} or nil,
},
util.frame_action_button(
"rb_nav_backward",
nil,
{ "titlebar", "nav_backward_button" },
{ gui = "info", id = id, action = "navigate", delta = -1 }
),
util.frame_action_button(
"rb_nav_forward",
nil,
{ "titlebar", "nav_forward_button" },
{ gui = "info", id = id, action = "navigate", delta = 1 }
),
{
type = "label",
style = "frame_title",
style_mods = { left_margin = 4 },
ignored_by_interaction = true,
ref = { "titlebar", "label" },
},
{
type = "empty-widget",
style = relative and "flib_horizontal_pusher" or "flib_titlebar_drag_handle",
ignored_by_interaction = true,
},
{
type = "textfield",
style_mods = {
top_margin = -3,
right_padding = 3,
width = 120,
},
clear_and_focus_on_right_click = true,
visible = false,
ref = { "titlebar", "search_textfield" },
actions = {
on_text_changed = { gui = "info", id = id, action = "update_search_query" },
},
},
util.frame_action_button(
"utility/search",
{ "gui.rb-search-instruction" },
{ "titlebar", "search_button" },
{ gui = "info", id = id, action = "toggle_search" }
),
options.parent and util.frame_action_button(
"rb_detach",
{ "gui.rb-detach-instruction" },
nil,
{ gui = "info", id = id, action = "detach_window" }
) or {},
util.frame_action_button(
"utility/close",
{ "gui.close" },
{ "titlebar", "close_button" },
{ gui = "info", id = id, action = "close" }
),
},
{
type = "frame",
style = "inside_shallow_frame",
style_mods = { vertically_stretchable = search_info },
direction = "vertical",
ref = { "page_frame" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
{
type = "frame",
style = "rb_subheader_frame",
direction = "vertical",
{
type = "flow",
style_mods = { vertical_align = "center" },
visible = false,
ref = { "header", "list_nav", "flow" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
tool_button(
"rb_list_nav_backward_black",
{ "gui.rb-go-backward" },
{ "header", "list_nav", "back_button" },
nil,
{ padding = 3 }
),
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "label",
style = "bold_label",
style_mods = { horizontally_squashable = true },
ref = { "header", "list_nav", "source_label" },
},
{
type = "label",
style = "bold_label",
style_mods = { font_color = constants.colors.info.tbl },
ref = { "header", "list_nav", "position_label" },
},
{ type = "empty-widget", style = "flib_horizontal_pusher" },
tool_button(
"rb_list_nav_forward_black",
{ "gui.rb-go-forward" },
{ "header", "list_nav", "forward_button" },
nil,
{ padding = 3 }
),
},
{
type = "line",
style = "rb_dark_line",
direction = "horizontal",
visible = false,
ref = { "header", "line" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
{ type = "label", style = "rb_toolbar_label", ref = { "header", "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
__DebugAdapter and tool_button(nil, "Print", nil, { gui = "info", id = id, action = "print_object" }) or {},
tool_button(
"rb_technology_gui_black",
{ "gui.rb-open-in-technology-window" },
{ "header", "open_in_tech_window_button" },
{ gui = "info", id = id, action = "open_in_tech_window" }
),
tool_button(
"rb_fluid_black",
{ "gui.rb-view-base-fluid" },
{ "header", "go_to_base_fluid_button" },
{ gui = "info", id = id, action = "go_to_base_fluid" }
),
tool_button(
"rb_clipboard_black",
{ "gui.rb-toggle-quick-ref-window" },
{ "header", "quick_ref_button" },
{ gui = "info", id = id, action = "toggle_quick_ref" }
),
tool_button(
"rb_favorite_black",
{ "gui.rb-add-to-favorites" },
{ "header", "favorite_button" },
{ gui = "info", id = id, action = "toggle_favorite" }
),
},
},
{
type = "scroll-pane",
style = "rb_page_scroll_pane",
style_mods = { maximal_height = 900 },
ref = { "page_scroll_pane" },
action = {
on_click = { gui = "info", id = id, action = "set_as_active" },
},
},
{
type = "flow",
style = "rb_warning_flow",
direction = "vertical",
visible = false,
ref = { "warning_flow" },
{
type = "label",
style = "bold_label",
caption = { "gui.rb-no-content-warning" },
ref = { "warning_text" },
},
},
},
},
})
if options.parent then
refs.root = root_elem
else
refs.root = refs.window
refs.root.force_auto_center()
end
if not options.parent or search_info then
refs.titlebar.flow.drag_target = refs.root
end
refs.page_components = {}
--- @class InfoGui
local self = {
id = id,
player = player,
player_table = player_table,
refs = refs,
state = {
components = {},
docked = options.parent and true or false,
history = { _index = 0 },
search_info = search_info,
search_opened = false,
search_query = "",
selected_tech_level = 0,
warning_shown = false,
},
}
index.load(self)
player_table.guis.info[id] = self
player_table.guis.info._active_id = id
if options.anchor then
player_table.guis.info._relative_id = id
end
self:update_contents({ new_context = context })
end
function index.load(self)
setmetatable(self, { __index = Gui })
end
--- Find all info GUIs that are viewing the given context.
--- @param player_table PlayerTable
--- @param context Context
--- @return table<number, InfoGui>
function index.find_open_context(player_table, context)
local open = {}
for id, Gui in pairs(player_table.guis.info) do
if not constants.ignored_info_ids[id] then
local state = Gui.state
local opened_context = state.history[state.history._index]
if opened_context and opened_context.class == context.class and opened_context.name == context.name then
open[id] = Gui
end
end
end
return open
end
-- function root.update_all(player, player_table)
-- for id in pairs(player_table.guis.info) do
-- if not constants.ignored_info_ids[id] then
-- root.update_contents(player, player_table, id, { refresh = true })
-- end
-- end
-- end
-- function root.bring_all_to_front(player_table)
-- for id, gui_data in pairs(player_table.guis.info) do
-- if not constants.ignored_info_ids[id] then
-- if gui_data.state.docked then
-- if gui_data.state.search_info then
-- gui_data.refs.root.bring_to_front()
-- end
-- else
-- gui_data.refs.window.bring_to_front()
-- end
-- end
-- end
-- end
return index

View File

@@ -0,0 +1,190 @@
local gui = require("__flib__.gui")
local constants = require("constants")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local list_box = {}
function list_box.build(parent, index, component, variables)
return gui.build(parent, {
{
type = "flow",
direction = "vertical",
index = index,
ref = { "root" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{ type = "label", style = "rb_list_box_label", ref = { "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
tooltip = { "gui.rb-open-list-in-new-window" },
sprite = "rb_export_black",
ref = { "open_list_button" },
-- NOTE: Actions are set in the update function
},
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
ref = { "expand_collapse_button" },
-- NOTE: Sprite, tooltip, and action are set in the update function
},
},
{
type = "frame",
style = "deep_frame_in_shallow_frame",
{
type = "scroll-pane",
style = "rb_list_box_scroll_pane",
ref = { "scroll_pane" },
},
},
},
})
end
function list_box.default_state(settings)
return { collapsed = settings.default_state == "collapsed" }
end
function list_box.update(component, refs, context_data, player_data, settings, variables)
-- Scroll pane
local scroll = refs.scroll_pane
local children = scroll.children
-- Settings and variables
local always_show = component.always_show
local context = variables.context
local query = variables.search_query
local search_type = player_data.settings.general.search.search_type
-- Add items
local i = 0 -- The "added" index
local iterator = component.use_pairs and pairs or ipairs
local objects = settings.default_state ~= "hidden" and context_data[component.source] or {}
for _, obj in iterator(objects) do
local translation = player_data.translations[obj.class][obj.name]
-- Match against search string
local matched
if search_type == "both" then
matched = string.find(string.lower(obj.name), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(obj.name), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
if matched then
local obj_data = database[obj.class][obj.name]
local blueprint_result
if context.class == "recipe" and component.source == "made_in" and obj_data.blueprintable then
blueprint_result = { name = obj.name, recipe = context.name }
elseif context.class == "entity" and component.source == "can_craft" and context_data.blueprintable then
blueprint_result = { name = context.name, recipe = obj.name }
end
local info = formatter(obj_data, player_data, {
always_show = always_show,
amount_ident = obj.amount_ident,
blueprint_result = blueprint_result,
rocket_parts_required = obj_data.rocket_parts_required,
})
if info then
i = i + 1
local style = info.researched and "rb_list_box_item" or "rb_unresearched_list_box_item"
local item = children[i]
if item then
item.style = style
item.caption = info.caption
item.tooltip = info.tooltip
item.enabled = info.num_interactions > 0
gui.update_tags(
item,
{ blueprint_result = blueprint_result, context = { class = obj.class, name = obj.name } }
)
else
gui.add(scroll, {
type = "button",
style = style,
caption = info.caption,
tooltip = info.tooltip,
enabled = info.num_interactions > 0,
mouse_button_filter = { "left", "middle" },
tags = {
blueprint_result = blueprint_result,
context = { class = obj.class, name = obj.name },
},
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "navigate_to" },
},
})
end
end
end
end
-- Destroy extraneous items
for j = i + 1, #children do
children[j].destroy()
end
-- Set listbox properties
if i > 0 then
refs.root.visible = true
local translations = player_data.translations.gui
-- Update label caption
refs.label.caption = formatter.expand_string(
translations.list_box_label,
translations[component.source] or component.source,
i
)
-- Update open list button
if i > 1 then
refs.open_list_button.visible = true
gui.set_action(refs.open_list_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "open_list",
context = variables.context,
source = component.source,
})
else
refs.open_list_button.visible = false
end
-- Update expand/collapse button and height
gui.set_action(refs.expand_collapse_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "toggle_collapsed",
context = variables.context,
component_index = variables.component_index,
})
if variables.component_state.collapsed then
refs.expand_collapse_button.sprite = "rb_collapsed"
scroll.style.maximal_height = 1
refs.expand_collapse_button.tooltip = { "gui.rb-expand" }
else
refs.expand_collapse_button.sprite = "rb_expanded"
scroll.style.maximal_height = (settings.max_rows or constants.default_max_rows) * 28
refs.expand_collapse_button.tooltip = { "gui.rb-collapse" }
end
else
refs.root.visible = false
end
return i > 0
end
return list_box

View File

@@ -0,0 +1,248 @@
local gui = require("__flib__.gui")
local table = require("__flib__.table")
local database = require("scripts.database")
local formatter = require("scripts.formatter")
local table_comp = {}
function table_comp.build(parent, index, component, variables)
local has_label = (component.label or component.source) and true or false
return gui.build(parent, {
{
type = "flow",
style_mods = not has_label and { top_margin = 4 } or nil,
direction = "vertical",
index = index,
ref = { "root" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
{
type = "flow",
style_mods = { vertical_align = "center" },
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
visible = has_label,
{ type = "label", style = "rb_list_box_label", ref = { "label" } },
{ type = "empty-widget", style = "flib_horizontal_pusher" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
ref = { "expand_collapse_button" },
-- NOTE: Sprite, tooltip, and action are set in the update function
},
},
{
type = "frame",
style = "deep_frame_in_shallow_frame",
action = {
on_click = { gui = "info", id = variables.gui_id, action = "set_as_active" },
},
ref = { "deep_frame" },
{
type = "table",
style = "rb_info_table",
column_count = 2,
ref = { "table" },
-- Dummy elements so the first row doesn't get used
{ type = "empty-widget" },
{ type = "empty-widget" },
},
},
},
})
end
function table_comp.default_state(settings)
return { collapsed = settings.default_state == "collapsed" }
end
function table_comp.update(component, refs, object_data, player_data, settings, variables)
local tbl = refs.table
local children = tbl.children
local gui_translations = player_data.translations.gui
local search_query = variables.search_query
local i = 2
local is_shown = settings.default_state ~= "hidden"
local row_settings = settings.rows
local source_tbl = is_shown and (component.source and object_data[component.source] or component.rows) or {}
for _, row in ipairs(source_tbl) do
local row_name = row.label or row.source
local value = row.value or object_data[row.source]
if value and (not row_settings or row_settings[row_name]) then
local caption = gui_translations[row_name] or row_name
if string.find(string.lower(caption), search_query) then
-- Label
i = i + 1
local label_label = children[i]
if not label_label or not label_label.valid then
label_label = tbl.add({
type = "label",
style = "rb_table_label",
index = i,
})
end
local tooltip = row.label_tooltip
if tooltip then
caption = caption .. " [img=info]"
tooltip = gui_translations[row.label_tooltip]
else
tooltip = ""
end
label_label.caption = caption
label_label.tooltip = tooltip
-- Value
if row.type == "plain" then
local fmt = row.formatter
if fmt then
value = formatter[fmt](value, gui_translations)
end
i = i + 1
local value_label = children[i]
if not value_label or not value_label.valid or value_label.type ~= "label" then
if value_label then
value_label.destroy()
end
value_label = tbl.add({ type = "label", index = i })
end
value_label.caption = value
elseif row.type == "goto" then
i = i + 1
local button = children[i]
if not button or button.type ~= "button" then
if button then
button.destroy()
end
button = tbl.add({
type = "button",
style = "rb_table_button",
mouse_button_filter = { "left", "middle" },
index = i,
})
end
local source_data = database[value.class][value.name]
local options = table.shallow_copy(row.options or {})
options.label_only = true
options.amount_ident = value.amount_ident
options.blueprint_result = value.class == "entity" and source_data.blueprintable and { name = value.name }
or nil
local info = formatter(source_data, player_data, options)
if info then
button.caption = info.caption
button.tooltip = info.tooltip
gui.set_action(button, "on_click", { gui = "info", id = variables.gui_id, action = "navigate_to" })
gui.update_tags(
button,
{ context = { class = value.class, name = value.name }, blueprint_result = options.blueprint_result }
)
else
-- Don't actually show this row
-- This is an ugly way to do it, but whatever
button.destroy()
label_label.destroy()
i = i - 2
end
elseif row.type == "tech_level_selector" then
i = i + 1
local flow = children[i]
if not flow or flow.type ~= "flow" then
if flow then
flow.destroy()
end
flow = gui.build(tbl, {
{
type = "flow",
style_mods = { vertical_align = "center" },
index = i,
ref = { "flow" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
sprite = "rb_minus_black",
mouse_button_filter = { "left" },
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "change_tech_level", delta = -1 },
},
},
{ type = "label", name = "tech_level_label" },
{
type = "sprite-button",
style = "mini_button_aligned_to_text_vertically_when_centered",
sprite = "rb_plus_black",
mouse_button_filter = { "left" },
actions = {
on_click = { gui = "info", id = variables.gui_id, action = "change_tech_level", delta = 1 },
},
},
},
}).flow
end
flow.tech_level_label.caption = formatter.number(variables.selected_tech_level)
elseif row.type == "tech_level_research_unit_count" then
i = i + 1
local value_label = children[i]
if not value_label or value_label.type ~= "label" then
if value_label then
value_label.destroy()
end
value_label = tbl.add({ type = "label", index = i })
end
local tech_level = variables.selected_tech_level
value_label.caption = formatter[row.formatter](
game.evaluate_expression(value, { L = tech_level, l = tech_level })
)
end
end
end
end
for j = i + 1, #children do
children[j].destroy()
end
if i > 3 then
refs.root.visible = true
local label_source = component.source or component.label
if label_source then
if component.hide_count then
refs.label.caption = gui_translations[label_source] or label_source
else
refs.label.caption = formatter.expand_string(
gui_translations.list_box_label,
gui_translations[label_source] or label_source,
i / 2 - 1
)
end
end
-- Update expand/collapse button and height
gui.set_action(refs.expand_collapse_button, "on_click", {
gui = "info",
id = variables.gui_id,
action = "toggle_collapsed",
context = variables.context,
component_index = variables.component_index,
})
if variables.component_state.collapsed then
refs.deep_frame.style.maximal_height = 1
refs.expand_collapse_button.sprite = "rb_collapsed"
refs.expand_collapse_button.tooltip = { "gui.rb-expand" }
else
refs.deep_frame.style.maximal_height = 0
refs.expand_collapse_button.sprite = "rb_expanded"
refs.expand_collapse_button.tooltip = { "gui.rb-collapse" }
end
else
refs.root.visible = false
end
return i > 3
end
return table_comp