Первый фикс

Пачки некоторых позиций увеличены
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,427 @@
local gui = require("__flib__.gui")
local on_tick_n = require("__flib__.on-tick-n")
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")
local actions = {}
--- @param Gui SearchGui
--- @param e on_gui_click
function actions.reset_location(Gui, _, e)
if e.button ~= defines.mouse_button_type.middle then
return
end
if Gui.player_table.settings.general.interface.search_gui_location == "top_left" then
local scale = Gui.player.display_scale
Gui.refs.window.location = table.map(constants.search_gui_top_left_location, function(pos)
return pos * scale
end)
Gui.refs.window.auto_center = false
else
Gui.refs.window.force_auto_center()
end
end
--- @param Gui SearchGui
function actions.close(Gui, _, _)
if not Gui.state.ignore_closed and not Gui.player_table.flags.technology_gui_open then
Gui:close()
end
end
--- @param Gui SearchGui
function actions.toggle_pinned(Gui, _, _)
local player = Gui.player
local refs = Gui.refs
local state = Gui.state
local pin_button = refs.titlebar.pin_button
state.pinned = not state.pinned
if state.pinned then
pin_button.style = "flib_selected_frame_action_button"
pin_button.sprite = "rb_pin_black"
if player.opened == refs.window then
state.ignore_closed = true
player.opened = nil
state.ignore_closed = false
end
else
pin_button.style = "frame_action_button"
pin_button.sprite = "rb_pin_white"
player.opened = refs.window
end
end
--- @param Gui SearchGui
function actions.toggle_settings(Gui, _, _)
local state = Gui.state
local player = Gui.player
state.ignore_closed = true
local SettingsGui = util.get_gui(Gui.player.index, "settings")
if SettingsGui then
SettingsGui:destroy()
else
SETTINGS_GUI.build(player, Gui.player_table)
end
state.ignore_closed = false
local settings_button = Gui.refs.titlebar.settings_button
if Gui.player_table.guis.settings then
settings_button.style = "flib_selected_frame_action_button"
settings_button.sprite = "rb_settings_black"
else
settings_button.style = "frame_action_button"
settings_button.sprite = "rb_settings_white"
if not state.pinned then
player.opened = Gui.refs.window
end
end
end
--- @param Gui SearchGui
function actions.deselect_settings_button(Gui, _, _)
local settings_button = Gui.refs.titlebar.settings_button
settings_button.style = "frame_action_button"
settings_button.sprite = "rb_settings_white"
if not Gui.state.pinned and Gui.refs.window.visible then
Gui.player.opened = Gui.refs.window
end
end
--- @param Gui SearchGui
--- @param e on_gui_text_changed
function actions.update_search_query(Gui, _, e)
local player_table = Gui.player_table
local state = Gui.state
local refs = Gui.refs
local class_filter
local query = string.lower(e.element.text)
if string.find(query, "/") then
-- The `_`s here are technically globals, but whatever
_, _, class_filter, query = string.find(query, "^/(.-)/(.-)$")
if class_filter then
class_filter = string.lower(class_filter)
end
-- Check translations of each class filter
local matched = false
if class_filter then
local gui_translations = player_table.translations.gui
for _, class in pairs(constants.classes) do
if class_filter == string.lower(gui_translations[class]) then
matched = true
class_filter = class
break
end
end
end
-- Invalidate textfield
if not class_filter or not query or not matched then
class_filter = false
query = nil
end
end
-- Remove results update action if there is one
if state.update_results_ident then
on_tick_n.remove(state.update_results_ident)
state.update_results_ident = nil
end
if query then
-- Fuzzy search
if 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
state.class_filter = class_filter
-- Reset textfield style
refs.search_textfield.style = "rb_search_textfield"
if #query == 0 and not class_filter then
-- Update immediately
actions.update_search_results(Gui)
else
-- Update in a while
state.update_results_ident = on_tick_n.add(
game.tick + constants.search_timeout,
{ gui = "search", action = "update_search_results", player_index = e.player_index }
)
end
else
state.search_query = ""
refs.search_textfield.style = "rb_search_invalid_textfield"
end
end
--- @param Gui SearchGui
function actions.update_search_results(Gui, _, _)
local player = Gui.player
local player_table = Gui.player_table
local state = Gui.state
local refs = Gui.refs
-- Data
local player_data = formatter.build_player_data(player, player_table)
local show_fluid_temperatures = player_table.settings.general.search.show_fluid_temperatures
local search_type = player_table.settings.general.search.search_type
local class_filter = state.class_filter
local query = state.search_query
if state.search_type == "textual" then
-- Update results based on query
local i = 0
local pane = refs.textual_results_pane
local children = pane.children
local max = constants.search_results_limit
if class_filter ~= false and (class_filter or #query >= 2) then
for class in pairs(constants.pages) do
if not class_filter or class_filter == class then
for internal, translation in pairs(player_table.translations[class]) do
-- Match against search string
local matched
if search_type == "both" then
matched = string.find(string.lower(internal), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(internal), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
if matched then
local obj_data = database[class][internal]
-- Check temperature settings
local passed = true
if obj_data.class == "fluid" then
local temperature_ident = obj_data.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
passed = false
end
else
if show_fluid_temperatures == "off" then
passed = false
end
end
end
end
if passed then
local blueprint_result = class == "entity" and obj_data.blueprintable and { name = internal } or nil
local info = formatter(obj_data, player_data, { blueprint_result = blueprint_result })
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 = class, name = internal } }
)
else
gui.add(pane, {
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 = class, name = internal },
},
actions = {
on_click = { gui = "search", action = "open_object" },
},
})
if i >= max then
break
end
end
end
end
end
end
end
if i >= max then
break
end
end
end
-- Destroy extraneous items
for j = i + 1, #children do
children[j].destroy()
end
elseif state.search_type == "visual" then
refs.objects_frame.visible = true
refs.warning_frame.visible = false
--- @type LuaGuiElement
local group_table = refs.group_table
for _, group_scroll in pairs(refs.objects_frame.children) do
local group_has_results = false
for _, subgroup_table in pairs(group_scroll.children) do
local visible_count = 0
for _, obj_button in pairs(subgroup_table.children) do
local context = gui.get_tags(obj_button).context
local matched
-- Match against class filter
if not class_filter or class_filter == context.class then
local translation = player_data.translations[context.class][context.name]
-- Match against search string
if search_type == "both" then
matched = string.find(string.lower(context.name), query) or string.find(string.lower(translation), query)
elseif search_type == "internal" then
matched = string.find(string.lower(context.name), query)
elseif search_type == "localised" then
matched = string.find(string.lower(translation), query)
end
end
if matched then
obj_button.visible = true
visible_count = visible_count + 1
else
obj_button.visible = false
end
end
if visible_count > 0 then
group_has_results = true
subgroup_table.visible = true
else
subgroup_table.visible = false
end
end
local group_name = group_scroll.name
local group_button = group_table[group_name]
if group_has_results then
group_button.style = "rb_filter_group_button_tab"
group_button.enabled = state.active_group ~= group_scroll.name
if state.active_group == group_name then
group_scroll.visible = true
else
group_scroll.visible = false
end
else
group_scroll.visible = false
group_button.style = "rb_disabled_filter_group_button_tab"
group_button.enabled = false
if state.active_group == group_name then
local matched = false
for _, group_button in pairs(group_table.children) do
if group_button.enabled then
matched = true
actions.change_group(Gui, { group = group_button.name, ignore_last_button = true })
break
end
end
if not matched then
refs.objects_frame.visible = false
refs.warning_frame.visible = true
end
end
end
end
end
end
--- @param Gui SearchGui
--- @param e on_gui_click
function actions.open_object(Gui, _, e)
local context = gui_util.navigate_to(e)
if context then
local attach = Gui.player_table.settings.general.interface.attach_search_results
local sticky = attach and e.button == defines.mouse_button_type.left
local id = sticky and Gui.state.id and Gui.player_table.guis.info[Gui.state.id] and Gui.state.id or nil
local parent = sticky and Gui.refs.window or nil
OPEN_PAGE(Gui.player, Gui.player_table, context, { id = id, parent = parent })
if sticky and not id then
Gui.state.id = Gui.player_table.guis.info._active_id
end
if not sticky and Gui.player_table.settings.general.interface.close_search_gui_after_selection then
actions.close(Gui)
end
end
end
--- @param Gui SearchGui
function actions.change_search_type(Gui)
local state = Gui.state
local refs = Gui.refs
if state.search_type == "textual" then
state.search_type = "visual"
refs.textual_results_pane.visible = false
refs.visual_results_flow.visible = true
if state.needs_visual_update then
state.needs_visual_update = false
Gui:update_visual_contents()
end
elseif state.search_type == "visual" then
state.search_type = "textual"
refs.textual_results_pane.visible = true
refs.visual_results_flow.visible = false
end
actions.update_search_results(Gui)
end
--- @param Gui SearchGui
--- @param msg table
function actions.change_group(Gui, msg)
local last_group = Gui.state.active_group
if not msg.ignore_last_button then
Gui.refs.group_table[last_group].enabled = true
end
Gui.refs.objects_frame[last_group].visible = false
local new_group = msg.group
Gui.refs.group_table[new_group].enabled = false
Gui.refs.objects_frame[new_group].visible = true
Gui.state.active_group = msg.group
end
--- @param Gui SearchGui
function actions.update_favorites(Gui, _, _)
Gui:update_favorites()
end
--- @param Gui SearchGui
function actions.update_history(Gui, _, _)
Gui:update_history()
end
--- @param Gui SearchGui
function actions.delete_favorites(Gui, _, _)
Gui.player_table.favorites = {}
Gui:update_favorites()
end
--- @param Gui SearchGui
function actions.delete_history(Gui, _, _)
Gui.player_table.global_history = {}
Gui:update_history()
end
return actions

View File

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