-- ** LOCAL UTIL ** local function add_preference_box(content_frame, type) local bordered_frame = content_frame.add{type="frame", direction="vertical", style="fp_frame_bordered_stretch"} local caption = {"fp.info_label", {"fp.preference_".. type .. "_title"}} local tooltip = {"fp.preference_".. type .. "_title_tt"} bordered_frame.add{type="label", caption=caption, tooltip=tooltip, style="caption_label"} return bordered_frame end local function refresh_defaults_table(player, modal_elements, type, category_id) local table_prototypes, prototypes if not category_id then table_prototypes = modal_elements[type] prototypes = global.prototypes[type] else table_prototypes = modal_elements[type][category_id] prototypes = global.prototypes[type][category_id].members end table_prototypes.clear() local default_proto = prototyper.defaults.get(player, type, category_id) for prototype_id, prototype in ipairs(prototypes) do local selected = (default_proto.id == prototype_id) local style = (selected) and "flib_slot_button_green_small" or "flib_slot_button_default_small" local first_line = (selected) and {"fp.tt_title_with_note", prototype.localised_name, {"fp.selected"}} or {"fp.tt_title", prototype.localised_name} local tooltip = {"", first_line, "\n", prototyper.util.get_attributes(prototype)} table_prototypes.add{type="sprite-button", sprite=prototype.sprite, tooltip=tooltip, style=style, tags={mod="fp", on_gui_click="select_preference_default", type=type, prototype_id=prototype_id, category_id=category_id}, mouse_button_filter={"left"}} end end local preference_structures = {} function preference_structures.checkboxes(preferences, content_frame, type, preference_names) local preference_box = add_preference_box(content_frame, type) local flow_checkboxes = preference_box.add{type="flow", direction="vertical"} for _, pref_name in ipairs(preference_names) do local identifier = type .. "_" .. pref_name local caption = {"fp.info_label", {"fp.preference_" .. identifier}} local tooltip ={"fp.preference_" .. identifier .. "_tt"} flow_checkboxes.add{type="checkbox", state=preferences[pref_name], caption=caption, tooltip=tooltip, tags={mod="fp", on_gui_checked_state_changed="toggle_preference", type=type, name=pref_name}} end end function preference_structures.mb_defaults(preferences, content_frame) local mb_defaults = preferences.mb_defaults local preference_box = add_preference_box(content_frame, "mb_defaults") local function add_mb_default_button(parent_flow, type) local flow = parent_flow.add{type="flow", direction="horizontal"} flow.style.vertical_align = "center" flow.style.horizontal_spacing = 8 flow.add{type="label", caption={"fp.info_label", {"fp.preference_mb_default_" .. type}}, tooltip={"fp.preference_mb_default_" .. type .. "_tt"}} local item = (mb_defaults[type] ~= nil) and mb_defaults[type].name or nil flow.add{type="choose-elem-button", elem_type="item", item=item, style="fp_sprite-button_inset_tiny", elem_filters={{filter="type", type="module"}, {filter="flag", flag="hidden", mode="and", invert=true}}, tags={mod="fp", on_gui_elem_changed="change_mb_default", type=type}} end local table_mb_defaults = preference_box.add{type="table", column_count=3} table_mb_defaults.style.horizontal_spacing = 18 -- Table alignment is so stupid table_mb_defaults.style.column_alignments[1] = "left" table_mb_defaults.style.column_alignments[2] = "right" table_mb_defaults.style.column_alignments[3] = "right" table_mb_defaults.add{type="label", caption={"", {"fp.pu_machine", 1}, ":"}} add_mb_default_button(table_mb_defaults, "machine") add_mb_default_button(table_mb_defaults, "machine_secondary") table_mb_defaults.add{type="label", caption={"", {"fp.pu_beacon", 1}, ":"}} add_mb_default_button(table_mb_defaults, "beacon") local beacon_amount_flow = table_mb_defaults.add{type="flow", direction="horizontal"} beacon_amount_flow.style.vertical_align = "center" beacon_amount_flow.style.horizontal_spacing = 8 beacon_amount_flow.add{type="label", caption={"fp.info_label", {"fp.preference_mb_default_beacon_amount"}}, tooltip={"fp.preference_mb_default_beacon_amount_tt"}} local beacon_amount = (BEACON_OVERLOAD_ACTIVE) and "1" or tostring(mb_defaults.beacon_count or "") local textfield_amount = beacon_amount_flow.add{type="textfield", text=beacon_amount, enabled=(not BEACON_OVERLOAD_ACTIVE), tags={mod="fp", on_gui_text_changed="mb_default_beacon_amount"}} util.gui.setup_numeric_textfield(textfield_amount, true, false) textfield_amount.style.width = 42 end function preference_structures.prototypes(player, content_frame, modal_elements, type) local preference_box = add_preference_box(content_frame, ("default_" .. type)) local table_prototypes = preference_box.add{type="table", column_count=3} table_prototypes.style.horizontal_spacing = 20 table_prototypes.style.vertical_spacing = 8 table_prototypes.style.top_margin = 4 local function add_defaults_table(column_count, category_id) local frame = table_prototypes.add{type="frame", direction="horizontal", style="fp_frame_deep_slots_small"} local table = frame.add{type="table", column_count=column_count, style="filter_slot_table"} if category_id then modal_elements[type] = modal_elements[type] or {} modal_elements[type][category_id] = table else modal_elements[type] = table end end if not prototyper.data_types[type] then local prototypes = global.prototypes[type] if #prototypes < 2 then preference_box.visible = false; return end table_prototypes.add{type="empty-widget", style="flib_horizontal_pusher"} add_defaults_table(8, nil) refresh_defaults_table(player, modal_elements, type, nil) else local categories = global.prototypes[type] if not next(categories) then preference_box.visible = false; return end local any_category_visible = false for category_id, category in ipairs(categories) do local prototypes = category.members if #prototypes > 1 then any_category_visible = true table_prototypes.add{type="label", caption=("'" .. category.name .. "'")} table_prototypes.add{type="empty-widget", style="flib_horizontal_pusher"} add_defaults_table(8, category_id) refresh_defaults_table(player, modal_elements, type, category_id) end end if not any_category_visible then preference_box.visible = false end end end local function handle_checkbox_preference_change(player, tags, event) local preference_name = tags.name util.globals.preferences(player)[preference_name] = event.element.state local refresh = util.globals.modal_data(player).refresh if tags.type == "production" or preference_name == "round_button_numbers" or preference_name == "show_floor_items" or preference_name == "fold_out_subfloors" then refresh.production = true end if preference_name == "ingredient_satisfaction" then -- Only recalculate if the satisfaction data will actually be shown now refresh.update_ingredient_satisfaction = (event.element.state) refresh.production = true -- always refresh production elseif preference_name == "attach_subfactory_products" then refresh.subfactory_list = true end end local function handle_mb_default_change(player, tags, event) local mb_defaults = util.globals.preferences(player).mb_defaults local module_name = event.element.elem_value mb_defaults[tags.type] = (module_name ~= nil) and MODULE_NAME_MAP[module_name] or nil end local function handle_default_prototype_change(player, tags, event) local type = tags.type local category_id = tags.category_id local modal_data = util.globals.modal_data(player) if type == "belts" then modal_data.refresh.view_state = true end if type == "wagons" then modal_data.refresh.production = true end prototyper.defaults.set(player, type, tags.prototype_id, category_id) refresh_defaults_table(player, modal_data.modal_elements, type, category_id) -- If this was an shift-click, set this prototype on every category that also has it if event.shift and type == "machines" then local new_default_prototype = prototyper.defaults.get(player, type, category_id) for _, secondary_category in pairs(PROTOTYPE_MAPS[type]) do if table_size(secondary_category.members) > 1 then -- don't attempt to change categories with only one machine local secondary_prototype = secondary_category.members[new_default_prototype.name] if secondary_prototype ~= nil then prototyper.defaults.set(player, type, secondary_prototype.id, secondary_category.id) refresh_defaults_table(player, modal_data.modal_elements, type, secondary_category.id) end end end end end local function open_preferences_dialog(player, modal_data) local preferences = util.globals.preferences(player) local modal_elements = modal_data.modal_elements modal_data.refresh = {} local flow_content = modal_elements.dialog_flow.add{type="flow", direction="horizontal"} flow_content.style.horizontal_spacing = 12 local function add_content_frame() local content_frame = flow_content.add{type="frame", direction="vertical", style="inside_shallow_frame"} content_frame.style.vertically_stretchable = true return content_frame.add{type="scroll-pane", style="flib_naked_scroll_pane"} end local left_content_frame = add_content_frame() local info_frame = left_content_frame.add{type="frame", direction="vertical", style="fp_frame_bordered_stretch"} local label_preferences_info = info_frame.add{type="label", caption={"fp.preferences_info"}} label_preferences_info.style.single_line = false label_preferences_info.style.width = 335 local support_frame = left_content_frame.add{type="frame", direction="vertical", style="fp_frame_bordered_stretch"} support_frame.add{type="label", caption={"fp.preferences_support"}} local general_preference_names = {"attach_subfactory_products", "show_floor_items", "fold_out_subfloors", "ingredient_satisfaction", "round_button_numbers", "ignore_barreling_recipes", "ignore_recycling_recipes"} preference_structures.checkboxes(preferences, left_content_frame, "general", general_preference_names) local production_preference_names = {"done_column", "pollution_column", "line_comment_column"} preference_structures.checkboxes(preferences, left_content_frame, "production", production_preference_names) preference_structures.mb_defaults(preferences, left_content_frame) local right_content_frame = add_content_frame() preference_structures.prototypes(player, right_content_frame, modal_elements, "belts") preference_structures.prototypes(player, right_content_frame, modal_elements, "beacons") preference_structures.prototypes(player, right_content_frame, modal_elements, "wagons") preference_structures.prototypes(player, right_content_frame, modal_elements, "fuels") preference_structures.prototypes(player, right_content_frame, modal_elements, "machines") end local function close_preferences_dialog(player, _) -- We refresh all these things only when closing to avoid duplicate refreshes local refresh = util.globals.modal_data(player).refresh if refresh.update_ingredient_satisfaction then local player_table = util.globals.player_table(player) Factory.update_ingredient_satisfactions(player_table.factory) Factory.update_ingredient_satisfactions(player_table.archive) end if refresh.subfactory_list then util.raise.refresh(player, "subfactory_list", nil) end local context_to_refresh = nil -- don't refresh by default -- The order of these matters, they go from smallest context to biggest if refresh.production then context_to_refresh = "production" end if refresh.view_state then -- Rebuilding state requires every button that shows item amounts to refresh view_state.rebuild_state(player) context_to_refresh = "production" end if refresh.calculations then local context = util.globals.context(player) solver.update(player, context.subfactory) context_to_refresh = "subfactory" end if context_to_refresh then util.raise.refresh(player, context_to_refresh, nil) end end -- ** EVENTS ** local listeners = {} listeners.gui = { on_gui_click = { { name = "select_preference_default", handler = handle_default_prototype_change } }, on_gui_text_changed = { { name = "mb_default_beacon_amount", handler = (function(player, _, event) local mb_defaults = util.globals.preferences(player).mb_defaults mb_defaults.beacon_count = tonumber(event.element.text) end) } }, on_gui_checked_state_changed = { { name = "toggle_preference", handler = handle_checkbox_preference_change } }, on_gui_elem_changed = { { name = "change_mb_default", handler = handle_mb_default_change } } } listeners.dialog = { dialog = "preferences", metadata = (function(_) return { caption = {"fp.preferences"}, create_content_frame = false } end), open = open_preferences_dialog, close = close_preferences_dialog } return { listeners }