513 lines
16 KiB
Lua
513 lines
16 KiB
Lua
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 gui_util = require("scripts.gui.util")
|
|
local util = require("scripts.util")
|
|
|
|
--- @class SearchGuiRefs
|
|
--- @field window LuaGuiElement
|
|
--- @field titlebar SearchGuiTitlebarRefs
|
|
--- @field tabbed_pane LuaGuiElement
|
|
--- @field search_textfield LuaGuiElement
|
|
--- @field textual_results_pane LuaGuiElement
|
|
--- @field visual_results_flow LuaGuiElement
|
|
--- @field group_table LuaGuiElement
|
|
--- @field objects_frame LuaGuiElement
|
|
--- @field warning_frame LuaGuiElement
|
|
--- @field delete_favorites_button LuaGuiElement
|
|
--- @field delete_history_button LuaGuiElement
|
|
--- @field favorites_pane LuaGuiElement
|
|
--- @field history_pane LuaGuiElement
|
|
|
|
--- @class SearchGuiTitlebarRefs
|
|
--- @field flow LuaGuiElement
|
|
--- @field drag_handle LuaGuiElement
|
|
--- @field pin_button LuaGuiElement
|
|
--- @field settings_button LuaGuiElement
|
|
|
|
--- @class SearchGui
|
|
local Gui = {}
|
|
|
|
local actions = require("scripts.gui.search.actions")
|
|
|
|
function Gui:dispatch(msg, e)
|
|
if type(msg) == "string" then
|
|
actions[msg](self, msg, e)
|
|
else
|
|
actions[msg.action](self, msg, e)
|
|
end
|
|
end
|
|
|
|
function Gui:destroy()
|
|
if self.refs.window.valid then
|
|
self.refs.window.destroy()
|
|
end
|
|
self.player_table.guis.search = nil
|
|
self.player.set_shortcut_toggled("rb-search", false)
|
|
end
|
|
|
|
function Gui:open()
|
|
local refs = self.refs
|
|
refs.window.visible = true
|
|
refs.window.bring_to_front()
|
|
refs.tabbed_pane.selected_tab_index = 1
|
|
refs.search_textfield.select_all()
|
|
refs.search_textfield.focus()
|
|
|
|
if not self.state.pinned then
|
|
self.player.opened = refs.window
|
|
end
|
|
-- Workaround to prevent the search GUI from centering itself if the player doesn't manually recenter
|
|
if self.player_table.settings.general.interface.search_gui_location ~= "center" then
|
|
refs.window.auto_center = false
|
|
end
|
|
|
|
self.player.set_shortcut_toggled("rb-search", true)
|
|
|
|
if self.state.search_type == "visual" and self.state.needs_visual_update then
|
|
self:update_visual_contents()
|
|
end
|
|
end
|
|
|
|
function Gui:close()
|
|
local window = self.player_table.guis.search.refs.window
|
|
window.visible = false
|
|
|
|
local player = self.player
|
|
player.set_shortcut_toggled("rb-search", false)
|
|
if player.opened == window then
|
|
player.opened = nil
|
|
end
|
|
end
|
|
|
|
function Gui:toggle()
|
|
if self.refs.window.visible then
|
|
self:close()
|
|
else
|
|
self:open()
|
|
end
|
|
end
|
|
|
|
function Gui:update_visual_contents()
|
|
self.state.needs_visual_update = false
|
|
|
|
local player_data = formatter.build_player_data(self.player, self.player_table)
|
|
|
|
local show_fluid_temperatures = player_data.settings.general.search.show_fluid_temperatures
|
|
local groups = {}
|
|
|
|
for _, objects in pairs(
|
|
{ database.item, database.fluid }
|
|
-- { database.recipe }
|
|
) do
|
|
for name, object in pairs(objects) do
|
|
-- Create / retrieve group and subgroup
|
|
local group = object.group
|
|
local group_table = groups[group.name]
|
|
if not group_table then
|
|
group_table = {
|
|
button = {
|
|
type = "sprite-button",
|
|
name = group.name,
|
|
style = "rb_filter_group_button_tab",
|
|
sprite = "item-group/" .. group.name,
|
|
tooltip = { "item-group-name." .. group.name },
|
|
actions = {
|
|
on_click = { gui = "search", action = "change_group", group = group.name },
|
|
},
|
|
},
|
|
members = 0,
|
|
scroll_pane = {
|
|
type = "scroll-pane",
|
|
name = group.name,
|
|
style = "rb_filter_scroll_pane",
|
|
vertical_scroll_policy = "always",
|
|
visible = false,
|
|
},
|
|
subgroups = {},
|
|
}
|
|
groups[group.name] = group_table
|
|
end
|
|
local subgroup = object.subgroup
|
|
local subgroup_table = group_table.subgroups[subgroup.name]
|
|
if not subgroup_table then
|
|
subgroup_table = { type = "table", style = "slot_table", column_count = 10 }
|
|
group_table.subgroups[subgroup.name] = subgroup_table
|
|
table.insert(group_table.scroll_pane, subgroup_table)
|
|
end
|
|
|
|
-- Check fluid temperature
|
|
local matched = true
|
|
local temperature_ident = object.temperature_ident
|
|
if temperature_ident then
|
|
local is_range = temperature_ident.min ~= temperature_ident.max
|
|
if is_range then
|
|
if show_fluid_temperatures ~= "all" then
|
|
matched = false
|
|
end
|
|
else
|
|
if show_fluid_temperatures == "off" then
|
|
matched = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if matched then
|
|
local blueprint_result = object.place_result and { name = object.place_result.name } or nil
|
|
local formatted = formatter(object, player_data, { blueprint_result = blueprint_result })
|
|
if formatted then
|
|
group_table.members = group_table.members + 1
|
|
local style = "default"
|
|
if formatted.disabled or formatted.hidden then
|
|
style = "grey"
|
|
elseif not formatted.researched then
|
|
style = "red"
|
|
end
|
|
-- Create the button
|
|
table.insert(subgroup_table, {
|
|
type = "sprite-button",
|
|
style = "flib_slot_button_" .. style,
|
|
sprite = object.class .. "/" .. object.prototype_name,
|
|
tooltip = formatted.tooltip,
|
|
mouse_button_filter = { "left", "middle", "right" },
|
|
tags = {
|
|
blueprint_result = blueprint_result,
|
|
context = { class = object.class, name = name },
|
|
},
|
|
actions = {
|
|
on_click = { gui = "search", action = "open_object" },
|
|
},
|
|
temperature_ident and {
|
|
type = "label",
|
|
style = "rb_slot_label",
|
|
caption = temperature_ident.short_string,
|
|
ignored_by_interaction = true,
|
|
} or nil,
|
|
temperature_ident and temperature_ident.short_top_string and {
|
|
type = "label",
|
|
style = "rb_slot_label_top",
|
|
caption = temperature_ident.short_top_string,
|
|
ignored_by_interaction = true,
|
|
} or nil,
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local group_buttons = {}
|
|
local group_scroll_panes = {}
|
|
local first_group
|
|
for group_name, group in pairs(groups) do
|
|
if group.members > 0 then
|
|
table.insert(group_buttons, group.button)
|
|
table.insert(group_scroll_panes, group.scroll_pane)
|
|
if not first_group then
|
|
first_group = group_name
|
|
end
|
|
end
|
|
end
|
|
|
|
if
|
|
#self.state.active_group == 0
|
|
or not table.for_each(group_buttons, function(button)
|
|
return button.name == self.state.active_group
|
|
end)
|
|
then
|
|
self.state.active_group = first_group
|
|
end
|
|
|
|
local refs = self.refs
|
|
|
|
refs.group_table.clear()
|
|
gui.build(refs.group_table, group_buttons)
|
|
|
|
refs.objects_frame.clear()
|
|
gui.build(refs.objects_frame, group_scroll_panes)
|
|
|
|
self:dispatch({ action = "change_group", group = self.state.active_group, ignore_last_button = true })
|
|
self:dispatch("update_search_results")
|
|
end
|
|
|
|
function Gui:update_favorites()
|
|
local favorites = self.player_table.favorites
|
|
local refs = self.refs
|
|
gui_util.update_list_box(
|
|
refs.favorites_pane,
|
|
favorites,
|
|
formatter.build_player_data(self.player, self.player_table),
|
|
pairs,
|
|
{ always_show = true }
|
|
)
|
|
refs.delete_favorites_button.enabled = next(favorites) and true or false
|
|
for id, InfoGui in pairs(self.player_table.guis.info) do
|
|
if not constants.ignored_info_ids[id] then
|
|
local context = InfoGui:get_context()
|
|
local to_state = favorites[context.class .. "." .. context.name]
|
|
InfoGui:dispatch({ action = "update_header_button", button = "favorite_button", to_state = to_state })
|
|
end
|
|
end
|
|
end
|
|
|
|
function Gui:update_history()
|
|
local refs = self.refs
|
|
gui_util.update_list_box(
|
|
refs.history_pane,
|
|
self.player_table.global_history,
|
|
formatter.build_player_data(self.player, self.player_table),
|
|
ipairs,
|
|
{ always_show = true }
|
|
)
|
|
refs.delete_history_button.enabled = next(self.player_table.global_history) and true or false
|
|
end
|
|
|
|
function Gui:bring_to_front()
|
|
self.refs.window.bring_to_front()
|
|
end
|
|
|
|
local index = {}
|
|
|
|
--- @param player LuaPlayer
|
|
--- @param player_table PlayerTable
|
|
function index.build(player, player_table)
|
|
--- @type SearchGuiRefs
|
|
local gui_type = player_table.settings.general.search.default_gui_type
|
|
local refs = gui.build(player.gui.screen, {
|
|
{
|
|
type = "frame",
|
|
name = "rb_search_window",
|
|
style = "invisible_frame",
|
|
visible = false,
|
|
ref = { "window" },
|
|
actions = {
|
|
on_closed = { gui = "search", action = "close" },
|
|
},
|
|
-- Search frame
|
|
{
|
|
type = "frame",
|
|
direction = "vertical",
|
|
{
|
|
type = "flow",
|
|
style = "flib_titlebar_flow",
|
|
ref = { "titlebar", "flow" },
|
|
actions = {
|
|
on_click = { gui = "search", action = "reset_location" },
|
|
},
|
|
{
|
|
type = "label",
|
|
style = "frame_title",
|
|
caption = { "gui.rb-search-title" },
|
|
ignored_by_interaction = true,
|
|
},
|
|
{ type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
|
|
util.frame_action_button(
|
|
"rb_pin",
|
|
{ "gui.rb-pin-instruction" },
|
|
{ "titlebar", "pin_button" },
|
|
{ gui = "search", action = "toggle_pinned" }
|
|
),
|
|
util.frame_action_button(
|
|
"rb_settings",
|
|
{ "gui.rb-settings-instruction" },
|
|
{ "titlebar", "settings_button" },
|
|
{ gui = "search", action = "toggle_settings" }
|
|
),
|
|
util.frame_action_button(
|
|
"utility/close",
|
|
{ "gui.close" },
|
|
{ "titlebar", "close_button" },
|
|
{ gui = "search", action = "close" }
|
|
),
|
|
},
|
|
{
|
|
type = "frame",
|
|
style = "inside_deep_frame_for_tabs",
|
|
direction = "vertical",
|
|
ref = { "tab_frame" },
|
|
{
|
|
type = "tabbed-pane",
|
|
style = "tabbed_pane_with_no_side_padding",
|
|
style_mods = { maximal_width = 426 },
|
|
ref = { "tabbed_pane" },
|
|
{
|
|
tab = { type = "tab", caption = { "gui.search" } },
|
|
content = {
|
|
type = "frame",
|
|
style = "rb_inside_deep_frame_under_tabs",
|
|
direction = "vertical",
|
|
{
|
|
type = "frame",
|
|
style = "rb_subheader_frame",
|
|
{
|
|
type = "textfield",
|
|
style = "flib_widthless_textfield",
|
|
style_mods = { horizontally_stretchable = true },
|
|
clear_and_focus_on_right_click = true,
|
|
ref = { "search_textfield" },
|
|
actions = {
|
|
on_text_changed = { gui = "search", action = "update_search_query" },
|
|
},
|
|
},
|
|
-- {
|
|
-- type = "sprite-button",
|
|
-- style = "tool_button",
|
|
-- tooltip = { "gui.rb-search-filters" },
|
|
-- sprite = "rb_filter",
|
|
-- actions = {
|
|
-- on_click = { gui = "search", action = "toggle_filters" },
|
|
-- },
|
|
-- },
|
|
{
|
|
type = "sprite-button",
|
|
style = "tool_button",
|
|
tooltip = { "gui.rb-change-search-type" },
|
|
sprite = "rb_swap",
|
|
actions = {
|
|
on_click = { gui = "search", action = "change_search_type" },
|
|
},
|
|
},
|
|
},
|
|
{
|
|
type = "scroll-pane",
|
|
style = "rb_search_results_scroll_pane",
|
|
ref = { "textual_results_pane" },
|
|
visible = gui_type == "textual",
|
|
},
|
|
{
|
|
type = "flow",
|
|
style_mods = { padding = 0, margin = 0, vertical_spacing = 0 },
|
|
direction = "vertical",
|
|
visible = gui_type == "visual",
|
|
ref = { "visual_results_flow" },
|
|
{
|
|
type = "table",
|
|
style = "filter_group_table",
|
|
style_mods = { width = 426 },
|
|
column_count = 6,
|
|
ref = { "group_table" },
|
|
},
|
|
{
|
|
type = "frame",
|
|
style = "rb_filter_frame",
|
|
{
|
|
type = "frame",
|
|
style = "deep_frame_in_shallow_frame",
|
|
style_mods = { natural_height = 40 * 15, natural_width = 40 * 10 },
|
|
ref = { "objects_frame" },
|
|
},
|
|
{
|
|
type = "frame",
|
|
style = "rb_warning_frame_in_shallow_frame",
|
|
style_mods = { height = 40 * 15, width = 40 * 10 },
|
|
ref = { "warning_frame" },
|
|
visible = false,
|
|
{
|
|
type = "flow",
|
|
style = "rb_warning_flow",
|
|
direction = "vertical",
|
|
{ type = "label", style = "bold_label", caption = { "gui.rb-no-results" } },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
tab = { type = "tab", caption = { "gui.rb-favorites" } },
|
|
content = {
|
|
type = "frame",
|
|
style = "rb_inside_deep_frame_under_tabs",
|
|
direction = "vertical",
|
|
{
|
|
type = "frame",
|
|
style = "subheader_frame",
|
|
{ type = "empty-widget", style = "flib_horizontal_pusher" },
|
|
{
|
|
type = "sprite-button",
|
|
style = "tool_button_red",
|
|
sprite = "utility/trash",
|
|
tooltip = { "gui.rb-delete-favorites" },
|
|
ref = { "delete_favorites_button" },
|
|
actions = {
|
|
on_click = { gui = "search", action = "delete_favorites" },
|
|
},
|
|
},
|
|
},
|
|
{ type = "scroll-pane", style = "rb_search_results_scroll_pane", ref = { "favorites_pane" } },
|
|
},
|
|
},
|
|
{
|
|
tab = { type = "tab", caption = { "gui.rb-history" } },
|
|
content = {
|
|
type = "frame",
|
|
style = "rb_inside_deep_frame_under_tabs",
|
|
direction = "vertical",
|
|
{
|
|
type = "frame",
|
|
style = "subheader_frame",
|
|
{ type = "empty-widget", style = "flib_horizontal_pusher" },
|
|
{
|
|
type = "sprite-button",
|
|
style = "tool_button_red",
|
|
sprite = "utility/trash",
|
|
tooltip = { "gui.rb-delete-history" },
|
|
ref = { "delete_history_button" },
|
|
actions = {
|
|
on_click = { gui = "search", action = "delete_history" },
|
|
},
|
|
},
|
|
},
|
|
{ type = "scroll-pane", style = "rb_search_results_scroll_pane", ref = { "history_pane" } },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
refs.titlebar.flow.drag_target = refs.window
|
|
|
|
if player_table.settings.general.interface.search_gui_location == "top_left" then
|
|
refs.window.location = table.map(constants.search_gui_top_left_location, function(pos)
|
|
return pos * player.display_scale
|
|
end)
|
|
else
|
|
refs.window.force_auto_center()
|
|
end
|
|
|
|
--- @class SearchGui
|
|
local self = {
|
|
player = player,
|
|
player_table = player_table,
|
|
state = {
|
|
active_group = "",
|
|
ignore_closed = false,
|
|
needs_visual_update = true,
|
|
search_query = "",
|
|
search_type = gui_type,
|
|
pinned = false,
|
|
},
|
|
refs = refs,
|
|
}
|
|
index.load(self)
|
|
player_table.guis.search = self
|
|
|
|
self:update_favorites()
|
|
self:update_history()
|
|
|
|
if gui_type == "visual" then
|
|
self:update_visual_contents()
|
|
end
|
|
end
|
|
|
|
function index.load(self)
|
|
setmetatable(self, { __index = Gui })
|
|
end
|
|
|
|
return index
|