mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 03:25:23 +09:00
* Fix bugs in core and add default args to Gui defs * Refactor production Gui * Refactor landfill blueprint button * Fix more bugs in core * Consistent naming of new guis * Refactor module inserter gui * Refactor surveillance gui * Add shorthand for data from arguments * Make element names consistent * Add types * Change how table rows work * Refactor player stats gui * Refactor quick actions gui * Refactor research milestones gui * Refactor player bonus gui * Refactor science production gui * Refactor autofill gui * Cleanup use of aligned flow * Rename "Gui.element" to "Gui.define" * Rename Gui types * Rename property_from_arg * Add guide for making guis * Add full reference document * Add condensed reference * Apply style guide to refactored guis * Bug fixes
262 lines
10 KiB
Lua
262 lines
10 KiB
Lua
--[[-- Gui - Production Data
|
|
Adds a Gui for displaying item production stats
|
|
]]
|
|
|
|
local Gui = require("modules/exp_gui")
|
|
local Roles = require("modules/exp_legacy/expcore/roles")
|
|
|
|
--- @class ExpGui_ProductionStats.elements
|
|
local Elements = {}
|
|
|
|
--- The flow precision values in the same order as production_precision_dropdown.items
|
|
local precision_indexes = {
|
|
defines.flow_precision_index.five_seconds,
|
|
defines.flow_precision_index.one_minute,
|
|
defines.flow_precision_index.ten_minutes,
|
|
defines.flow_precision_index.one_hour,
|
|
defines.flow_precision_index.ten_hours,
|
|
}
|
|
|
|
--- The font colours used for number labels
|
|
local font_color = {
|
|
positive = { r = 0.3, g = 1, b = 0.3 },
|
|
negative = { r = 1, g = 0.3, b = 0.3 },
|
|
}
|
|
|
|
--- Format a number to include commas and a suffix
|
|
local function format_number(amount)
|
|
if math.abs(amount) < 0.009 then
|
|
return "0.00"
|
|
end
|
|
|
|
local scaler = 1
|
|
local suffix = ""
|
|
local suffix_list = {
|
|
[" G"] = 1e9,
|
|
[" M"] = 1e6,
|
|
[" k"] = 1e3
|
|
}
|
|
|
|
-- Select which suffix and scaler to use
|
|
for _suffix, _scaler in pairs(suffix_list) do
|
|
if math.abs(amount) >= _scaler then
|
|
scaler = _scaler
|
|
suffix = _suffix
|
|
break
|
|
end
|
|
end
|
|
|
|
local formatted = string.format("%.2f%s", amount / scaler, suffix)
|
|
-- Split into integer and fractional parts
|
|
local integer_part, fractional_part = formatted:match("^(%-?%d+)%.(%d+)(.*)$")
|
|
-- Add commas to integer part
|
|
return string.format("%s.%s%s", (integer_part or formatted):reverse():gsub("(%d%d%d)", "%1,"):reverse():gsub("^,", ""):gsub("-,", "-"), fractional_part or "00", suffix)
|
|
end
|
|
|
|
--- Used to select the precision of the production table
|
|
Elements.precision_dropdown = Gui.define("production_stats/precision_dropdown")
|
|
:draw{
|
|
type = "drop-down",
|
|
items = { "5s", "1m", "10m", "1h", "10h" },
|
|
selected_index = 3,
|
|
}
|
|
:style{
|
|
width = 80,
|
|
}
|
|
|
|
--- Used to select the item to be displayed on a row
|
|
--- @class ExpGui_ProductionStats.elements.item_selector: ExpElement
|
|
--- @field data table<LuaGuiElement, { on_last_row: boolean, production_table: LuaGuiElement }>
|
|
--- @overload fun(parent: LuaGuiElement, production_table: LuaGuiElement): LuaGuiElement
|
|
Elements.item_selector = Gui.define("production_stats/item_selector")
|
|
:draw{
|
|
type = "choose-elem-button",
|
|
elem_type = "item",
|
|
style = "slot_button",
|
|
}
|
|
:style{
|
|
size = 32,
|
|
}
|
|
:element_data{
|
|
on_last_row = true,
|
|
production_table = Gui.from_argument(1),
|
|
}
|
|
:on_elem_changed(function(def, player, element, event)
|
|
--- @cast def ExpGui_ProductionStats.elements.item_selector
|
|
local element_data = def.data[element]
|
|
if not element.elem_value then
|
|
if element_data.on_last_row then
|
|
Elements.production_table.reset_row(element_data.production_table, element)
|
|
else
|
|
Elements.production_table.remove_row(element_data.production_table, element)
|
|
end
|
|
elseif element_data.on_last_row then
|
|
element_data.on_last_row = false
|
|
Elements.production_table.add_row(element_data.production_table)
|
|
end
|
|
end) --[[ @as any ]]
|
|
|
|
--- Label used for every element in the production table
|
|
Elements.table_label = Gui.define("production_stats/table_label")
|
|
:draw{
|
|
type = "label",
|
|
caption = Gui.from_argument(1, "0.00"),
|
|
tooltip = Gui.from_argument(2),
|
|
style = Gui.from_argument(3),
|
|
}
|
|
:style{
|
|
horizontal_align = "right",
|
|
minimal_width = 60,
|
|
}
|
|
|
|
--- @class ExpGui_ProductionStats.elements.production_table.row_elements
|
|
--- @field item_selector LuaGuiElement
|
|
--- @field production LuaGuiElement
|
|
--- @field consumption LuaGuiElement
|
|
--- @field net LuaGuiElement
|
|
|
|
--- @class ExpGui_ProductionStats.elements.production_table.row_data
|
|
--- @field production LocalisedString
|
|
--- @field consumption LocalisedString
|
|
--- @field net LocalisedString
|
|
--- @field font_color Color
|
|
|
|
--- A table that allows selecting items
|
|
--- @class ExpGui_ProductionStats.elements.production_table: ExpElement
|
|
--- @field data table<LuaGuiElement, { precision_dropdown: LuaGuiElement, rows: ExpGui_ProductionStats.elements.production_table.row_elements[] }>
|
|
--- @overload fun(parent: LuaGuiElement): LuaGuiElement
|
|
Elements.production_table = Gui.define("production_stats/production_table")
|
|
:track_all_elements()
|
|
:draw(function(def, parent)
|
|
local scroll_table = Gui.elements.scroll_table(parent, 304, 4)
|
|
local display_alignments = scroll_table.style.column_alignments
|
|
for i = 2, 4 do
|
|
display_alignments[i] = "right"
|
|
end
|
|
|
|
def.data[scroll_table] = {
|
|
precision_dropdown = Elements.precision_dropdown(scroll_table),
|
|
rows = {},
|
|
}
|
|
|
|
Elements.table_label(scroll_table, { "gui-production.production" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label")
|
|
Elements.table_label(scroll_table, { "gui-production.consumption" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label")
|
|
Elements.table_label(scroll_table, { "exp-gui_production-stats.caption-net" }, { "exp-gui_production-stats.tooltip-per-second" }, "heading_2_label")
|
|
|
|
return scroll_table
|
|
end) --[[ @as any ]]
|
|
|
|
--- Calculate the row data for a production table
|
|
--- @param force LuaForce
|
|
--- @param surface LuaSurface
|
|
--- @param item_name string
|
|
--- @param precision_index defines.flow_precision_index
|
|
--- @return ExpGui_ProductionStats.elements.production_table.row_data
|
|
function Elements.production_table.calculate_row_data(force, surface, item_name, precision_index)
|
|
local get_flow_count = force.get_item_production_statistics(surface).get_flow_count
|
|
local production = math.floor(get_flow_count{ name = item_name, category = "input", precision_index = precision_index, count = false } / 6) / 10
|
|
local consumption = math.floor(get_flow_count{ name = item_name, category = "output", precision_index = precision_index, count = false } / 6) / 10
|
|
local net = production - consumption
|
|
return {
|
|
production = format_number(production),
|
|
consumption = format_number(consumption),
|
|
net = format_number(net),
|
|
font_color = net < 0 and font_color.negative or font_color.positive,
|
|
}
|
|
end
|
|
|
|
--- A single row of a production table, the parent must be a production table
|
|
--- @param production_table LuaGuiElement
|
|
function Elements.production_table.add_row(production_table)
|
|
local rows = Elements.production_table.data[production_table].rows
|
|
local item_selector = Elements.item_selector(production_table, production_table)
|
|
rows[item_selector.index] = {
|
|
item_selector = item_selector,
|
|
production = Elements.table_label(production_table, "0.00"),
|
|
consumption = Elements.table_label(production_table, "0.00"),
|
|
net = Elements.table_label(production_table, "0.00"),
|
|
}
|
|
end
|
|
|
|
--- Remove a row from a production table
|
|
--- @param production_table LuaGuiElement
|
|
--- @param item_selector LuaGuiElement
|
|
function Elements.production_table.remove_row(production_table, item_selector)
|
|
local rows = Elements.production_table.data[production_table].rows
|
|
local row = rows[item_selector.index]
|
|
rows[item_selector.index] = nil
|
|
Gui.destroy_if_valid(item_selector)
|
|
for _, element in pairs(row) do
|
|
Gui.destroy_if_valid(element)
|
|
end
|
|
end
|
|
|
|
--- Reset a row in a production table
|
|
--- @param production_table LuaGuiElement
|
|
--- @param item_selector LuaGuiElement
|
|
function Elements.production_table.reset_row(production_table, item_selector)
|
|
local rows = Elements.production_table.data[production_table].rows
|
|
local row = rows[item_selector.index]
|
|
row.production.caption = "0.00"
|
|
row.consumption.caption = "0.00"
|
|
row.net.caption = "0.00"
|
|
row.net.style.font_color = font_color.positive
|
|
end
|
|
|
|
--- Refresh the data on a row
|
|
--- @param production_table LuaGuiElement
|
|
--- @param item_selector LuaGuiElement
|
|
--- @param row_data ExpGui_ProductionStats.elements.production_table.row_data
|
|
function Elements.production_table.refresh_row(production_table, item_selector, row_data)
|
|
local rows = Elements.production_table.data[production_table].rows
|
|
local row = rows[item_selector.index]
|
|
row.production.caption = row_data.production
|
|
row.consumption.caption = row_data.consumption
|
|
row.net.caption = row_data.net
|
|
row.net.style.font_color = row_data.font_color
|
|
end
|
|
|
|
--- Refresh all online tables
|
|
function Elements.production_table.refresh_online()
|
|
for player, production_table in Elements.production_table:online_elements() do
|
|
local element_data = Elements.production_table.data[production_table]
|
|
local precision_index = precision_indexes[element_data.precision_dropdown.selected_index]
|
|
for _, row in pairs(element_data.rows) do
|
|
local item_selector = row.item_selector
|
|
local item_name = item_selector.elem_value --[[ @as string? ]]
|
|
if item_name then
|
|
local row_data = Elements.production_table.calculate_row_data(player.force --[[ @as LuaForce ]], player.surface, item_name, precision_index)
|
|
Elements.production_table.refresh_row(production_table, item_selector, row_data)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Container added to the left gui flow
|
|
Elements.container = Gui.define("production_stats/container")
|
|
:draw(function(def, parent)
|
|
local container = Gui.elements.container(parent)
|
|
local production_table = Elements.production_table(container)
|
|
Elements.production_table.add_row(production_table)
|
|
return Gui.elements.container.get_root_element(container)
|
|
end)
|
|
|
|
--- Add the element to the left flow with a toolbar button
|
|
Gui.add_left_element(Elements.container, false)
|
|
Gui.toolbar.create_button{
|
|
name = "toggle_production_stats",
|
|
left_element = Elements.container,
|
|
sprite = "entity/assembling-machine-3",
|
|
tooltip = { "exp-gui_production-stats.tooltip-main" },
|
|
visible = function(player, element)
|
|
return Roles.player_allowed(player, "gui/production")
|
|
end
|
|
}
|
|
|
|
return {
|
|
elements = Elements,
|
|
on_nth_tick = {
|
|
[60] = Elements.production_table.refresh_online,
|
|
}
|
|
}
|