From 7592631bf0bba25b2c17a5a81bb33c8e7947ffb9 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Mon, 2 Sep 2024 01:49:16 +0200 Subject: [PATCH 1/8] Add initial GUI for network encoder --- .gitignore | 3 + .../semitransparent-pixel.kra | Bin 0 -> 22057 bytes src/graphics/frame/semitransparent-pixel.png | Bin 0 -> 108 bytes src/locale/en/mod.cfg | 9 + src/prototypes/styles.lua | 25 + src/scripts/gui.lua | 583 +++++++++++++++++- src/scripts/masking.lua | 3 +- 7 files changed, 600 insertions(+), 23 deletions(-) create mode 100644 graphics/semitransparent-pixel/semitransparent-pixel.kra create mode 100644 src/graphics/frame/semitransparent-pixel.png diff --git a/.gitignore b/.gitignore index 74f0de0..e69491d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ /graphics/combinator-entity/constant-combinator.png /graphics/combinator-entity/hr-constant-combinator.png /graphics/combinator-icon/constant-combinator.png + +# Ignore graphic exports +/graphics/semitransparent-pixel/semitransparent-pixel.png diff --git a/graphics/semitransparent-pixel/semitransparent-pixel.kra b/graphics/semitransparent-pixel/semitransparent-pixel.kra new file mode 100644 index 0000000000000000000000000000000000000000..ef4ab602b438d9fccf96d3c110a396438a38a83b GIT binary patch literal 22057 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 HwfBDjOBrE0 literal 0 HcmV?d00001 diff --git a/src/graphics/frame/semitransparent-pixel.png b/src/graphics/frame/semitransparent-pixel.png new file mode 100644 index 0000000000000000000000000000000000000000..47c0d432167f4e78e23e15876ad1852bb860ad37 GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm#=yXM@7uZ;Kn`btM`SSrgPt-7Ggd6MF9Qn7 zdAc};a9mGLNJ#KVW)SQ#5Sw%G2m@<@phQBF12aQb6BFCqrMF{&Dj7Uo{an^LB{Ts5 Dyh|Ci literal 0 HcmV?d00001 diff --git a/src/locale/en/mod.cfg b/src/locale/en/mod.cfg index 75877f0..bf70037 100644 --- a/src/locale/en/mod.cfg +++ b/src/locale/en/mod.cfg @@ -116,3 +116,12 @@ item-stacks=Total stacks item-stacks-description=The total number of stacks being requested by this combinator, only negative signal values count towards this total. fluid-total=Total fluids fluid-total-description=The total amount of fluids being requested by this combinator, only negative signal values count towards this total. + +[cybersyn-combinator-encoder] +title=Network encoder +all=All +none=None +decimal=Decimal +hexadecimal=Hexadecimal +binary=Binary +octal=Octal diff --git a/src/prototypes/styles.lua b/src/prototypes/styles.lua index 2e75497..e66a38f 100644 --- a/src/prototypes/styles.lua +++ b/src/prototypes/styles.lua @@ -87,3 +87,28 @@ styles["cybersyn-combinator_network-list_item-active"] = { default_font_color = styles.button.selected_font_color, default_vertical_offset = styles.button.selected_vertical_offset } + +styles["cybersyn-combinator_frame_semitransparent"] = { + type = "frame_style", + graphical_set = { + base = { + type = "composition", + filename = "__cybersyn-combinator__/graphics/frame/semitransparent-pixel.png", + corner_size = 1, + position = {0, 0} + } + } +} + +styles["cybersyn-combinator_encoder_bit-button"] = { + type = "button_style", + parent = "flib_standalone_slot_button_grey", + size = 32, + hovered_graphical_set = styles.flib_standalone_slot_button_grey.default_graphical_set +} + +styles["cybersyn-combinator_encoder_bit-button_pressed"] = { + type = "button_style", + parent = "flib_selected_standalone_slot_button_grey", + size = 32 +} diff --git a/src/scripts/gui.lua b/src/scripts/gui.lua index 0bd4aac..9d4560a 100644 --- a/src/scripts/gui.lua +++ b/src/scripts/gui.lua @@ -25,6 +25,7 @@ local function format_signal_count(count) end local WINDOW_ID = "cybersyn-constant-combinator-window" +local ENCODER_ID = "cybersyn-constant-combinator-encoder" local RED = "utility/status_not_working" local GREEN = "utility/status_working" @@ -50,8 +51,17 @@ local STATUS_NAMES = { } local DEFAULT_STATUS_NAME = { "entity-status.disabled" } +local BIT_BUTTON_STYLE = "cybersyn-combinator_encoder_bit-button" +local BIT_BUTTON_PRESSED_STYLE = "cybersyn-combinator_encoder_bit-button_pressed" + +--- @param pressed boolean +local function bit_button_style(pressed) + return pressed and BIT_BUTTON_PRESSED_STYLE or BIT_BUTTON_STYLE +end + local cc_gui = { - WINDOW_ID = WINDOW_ID + WINDOW_ID = WINDOW_ID, + ENCODER_ID = ENCODER_ID } --- @class SignalEntry @@ -64,6 +74,19 @@ local cc_gui = { --- @field add_button LuaGuiElement --- @field signal Signal? --- @field mask integer? +--- @field slot integer? + +--- @class EncoderState +--- @field dialog LuaGuiElement? +--- @field signal_button LuaGuiElement +--- @field textfield LuaGuiElement +--- @field bit_buttons LuaGuiElement +--- @field mask integer? +--- @field display_dec LuaGuiElement +--- @field display_hex LuaGuiElement +--- @field display_bin LuaGuiElement +--- @field display_oct LuaGuiElement +--- @field confirm_button LuaGuiElement --- @class UiState --- @field main_window LuaGuiElement @@ -84,6 +107,8 @@ local cc_gui = { --- @field selected_slot_button LuaGuiElement? --- @field stack_size integer? --- @field network_mask NetworkMaskState +--- @field encoder EncoderState? +--- @field dimmer LuaGuiElement? --- @param player_index PlayerIdentification? --- @return UiState? @@ -594,37 +619,76 @@ local function handle_cs_signal_reset(event) end --- @param event EventData.on_gui_elem_changed -local function handle_network_mask_signal_changed(event) +--- @param on_failure function +--- @return Signal|false +local function handle_mask_signal_changed(event, on_failure) local state = get_player_state(event.player_index) - if not state then return end + if not state then return false end local element = event.element - if not element then return end + if not element then return false end --- @type Signal local signal = { signal = element.elem_value --[[@as SignalID]], count = 0 } if not signal.signal then - state.network_mask.signal = nil - state.network_mask.add_button.enabled = false - return + on_failure() + return false end if not cc_util.is_valid_output_signal(signal) then event.element.elem_value = nil - state.network_mask.signal = nil - state.network_mask.add_button.enabled = false + on_failure() local player = game.get_player(event.player_index) - if not player then return end + if not player then return false end player.print({ "cybersyn-combinator-window.invalid-signal" }) - return + return false end if signal.signal.type ~= "virtual" then event.element.elem_value = nil - state.network_mask.signal = nil - state.network_mask.add_button.enabled = false + on_failure() log:info("attempt to use non-virtual signal as network mask") local player = game.get_player(event.player_index) - if not player then return end + if not player then return false end player.print { "cybersyn-combinator-window.non-virtual-network-mask", signal.signal.type, signal.signal.name } - return + return false end + return signal +end + +--- @param event EventData.on_gui_elem_changed +local function handle_network_mask_signal_changed(event) + local state = get_player_state(event.player_index) + if not state then return end + -- local element = event.element + -- if not element then return end + -- --- @type Signal + -- local signal = { signal = element.elem_value --[[@as SignalID]], count = 0 } + -- if not signal.signal then + -- state.network_mask.signal = nil + -- state.network_mask.add_button.enabled = false + -- return + -- end + -- if not cc_util.is_valid_output_signal(signal) then + -- event.element.elem_value = nil + -- state.network_mask.signal = nil + -- state.network_mask.add_button.enabled = false + -- local player = game.get_player(event.player_index) + -- if not player then return end + -- player.print({ "cybersyn-combinator-window.invalid-signal" }) + -- return + -- end + -- if signal.signal.type ~= "virtual" then + -- event.element.elem_value = nil + -- state.network_mask.signal = nil + -- state.network_mask.add_button.enabled = false + -- log:info("attempt to use non-virtual signal as network mask") + -- local player = game.get_player(event.player_index) + -- if not player then return end + -- player.print { "cybersyn-combinator-window.non-virtual-network-mask", signal.signal.type, signal.signal.name } + -- return + -- end + local signal = handle_mask_signal_changed(event, function() + state.network_mask.signal = nil + state.network_mask.add_button.enabled = false + end) + if not signal then return end state.network_mask.signal = signal log:debug("network signal changed to ", serpent.block(signal)) --- @type integer? @@ -685,6 +749,430 @@ local function handle_network_mask_add_click(event) add_network_mask(event.player_index, state) end +--- @param event EventData.on_gui_click +local function handle_encoder_close(event) + log:debug("encoder close button clicked") + cc_gui:close_encoder(event.player_index, true) +end + +--- @param event EventData.on_gui_click +local function handle_encoder_confirm(event) + log:debug("encoder confirm button clicked") + local state = get_player_state(event.player_index) + if not state then + cc_gui:close_encoder(event.player_index, true) + return + end + state.network_mask.signal.signal = state.encoder.signal_button.elem_value --[[@as SignalID]] + state.network_mask.signal.count = masking.uint_to_int(state.encoder.mask) + cc_gui:close_encoder(event.player_index, true) + add_network_mask(event.player_index, state) +end + +--- @param player_index integer +--- @param state UiState +--- @param update_textfield boolean +local function refresh_encoder(player_index, state, update_textfield) + state.encoder.confirm_button.enabled = state.encoder.signal_button.elem_value ~= nil + if not state.encoder.bit_buttons then return end + local mask = state.encoder.mask + if not mask then return end + if update_textfield then + state.encoder.textfield.text = masking.format_for_input(mask, player_index) + end + state.encoder.display_dec.caption = masking.format_explicit(mask, masking.Mode.DECIMAL, false, true) + state.encoder.display_hex.caption = masking.format_explicit(mask, masking.Mode.HEX, false, true) + state.encoder.display_bin.caption = masking.format_explicit(mask, masking.Mode.BINARY, false, true) + state.encoder.display_oct.caption = masking.format_explicit(mask, masking.Mode.OCTAL, false, true) + for i, button in ipairs(state.encoder.bit_buttons.children) do + local bit_index = i - 1 + local bit_value = bit32.extract(state.encoder.mask, bit_index) + if bit_value == 1 then + button.style = BIT_BUTTON_PRESSED_STYLE + else + button.style = BIT_BUTTON_STYLE + end + end +end + +--- @param event EventData.on_gui_elem_changed +local function handle_encoder_signal_changed(event) + local state = get_player_state(event.player_index) + if not state then return end + local signal = handle_mask_signal_changed(event, function() + state.encoder.signal_button.elem_value = nil + end) + refresh_encoder(event.player_index, state, true) + if not signal then return end + state.encoder.textfield.focus() + state.encoder.textfield.select_all() +end + +--- @param event EventData.on_gui_click +local function handle_encoder_signal_click(event) + local state = get_player_state(event.player_index) + if not state then return end + refresh_encoder(event.player_index, state, true) +end + +--- @param event EventData.on_gui_text_changed +local function handle_encoder_mask_changed(event) + local state = get_player_state(event.player_index) + if not state then return end + local text = event.element.text + local mask = masking.parse(text, event.player_index) + state.encoder.mask = mask + refresh_encoder(event.player_index, state, false) +end + +-- --- @param event EventData.on_gui_confirmed +-- local function handle_encoder_mask_confirmed(event) +-- local state = get_player_state(event.player_index) +-- if not state then return end +-- end + +--- @param event EventData.on_gui_click +local function handle_encoder_bit_button_click(event) + local state = get_player_state(event.player_index) + if not state then return end + local index = event.element.tags.index + local bit_index = event.element.tags.bit_index --[[@as integer]] + state.encoder.mask = bit32.bxor(state.encoder.mask, bit32.lshift(1, bit_index)) + log:debug("Pressed bit button ", index, " (bit ", bit_index, ")") + refresh_encoder(event.player_index, state, true) +end + +--- @param event EventData.on_gui_click +local function handle_encoder_all(event) + local state = get_player_state(event.player_index) + if not state then return end + state.encoder.mask = 0xFFFFFFFF + refresh_encoder(event.player_index, state, true) +end + +--- @param event EventData.on_gui_click +local function handle_encoder_none(event) + local state = get_player_state(event.player_index) + if not state then return end + state.encoder.mask = 0 + refresh_encoder(event.player_index, state, true) +end + +local function handle_dimmer_click(event) + local state = get_player_state(event.player_index) + if not state or not state.encoder then return end + state.encoder.dialog.bring_to_front() +end + +--- @param player_index integer +--- @param state UiState +local function create_encoder(player_index, state) + local player = game.players[player_index] + local screen = player.gui.screen + -- local wide = settings.get_player_settings(player)[constants.SETTINGS.NETWORK_MASK_DISPLAY_MODE].value == "BINARY" + -- local rows = settings.startup[constants.SETTINGS.SLOT_ROWS].value + -- local dim_width = wide and 825 or 685 + -- local dim_height = 352 + 40 * rows + -- local _, dimmer = flib_gui.add(screen, { + -- type = "frame", + -- name = "cybersyn-combinator_dimmer", + -- style = "cybersyn-combinator_frame_semitransparent", + -- style_mods = { + -- width = dim_width, + -- height = dim_height, + -- padding = 0, + -- use_header_filler = false + -- }, + -- handler = { + -- [defines.events.on_gui_click] = handle_dimmer_click + -- } + -- }) + -- dimmer.location = state.main_window.location + -- state.dimmer = dimmer + local named, dialog = flib_gui.add(screen, { + { + type = "frame", + direction = "vertical", + name = ENCODER_ID, + tags = { + unit_number = state.entity.unit_number + }, + style_mods = { + -- minimal_width = 240 + width = 400 + }, + children = { + { + type = "flow", + direction = "horizontal", + drag_target = ENCODER_ID, + children = { + { + type = "label", + style = "frame_title", + caption = { "cybersyn-combinator-encoder.title" }, + elem_mods = { ignored_by_interaction = true } + }, + { + type = "empty-widget", + style = "flib_titlebar_drag_handle", + elem_mods = { ignored_by_interaction = true } + } + } + }, + { + type = "frame", + direction = "vertical", + style = "inside_shallow_frame_with_padding", + style_mods = { + horizontally_stretchable = true, + vertically_stretchable = true, + horizontal_align = "center", + padding = 8 + }, + children = { + { -- Signal and text field + type = "flow", + direction = "horizontal", + style_mods = { + horizontally_stretchable = true, + vertical_align = "center" + }, + children = { + { + type = "choose-elem-button", + name = "encoder_signal_button", + elem_type = "signal", + style_mods = { width = 48, height = 48 }, + handler = { + [defines.events.on_gui_elem_changed] = handle_encoder_signal_changed, + [defines.events.on_gui_click] = handle_encoder_signal_click + } + }, + { + type = "textfield", + name = "encoder_mask_textfield", + style = "cybersyn-combinator_network-mask-text-input", + style_mods = { horizontally_stretchable = true, maximal_width = 400 }, + numeric = false, + clear_and_focus_on_right_click = true, + lose_focus_on_confirm = true, + handler = { + [defines.events.on_gui_text_changed] = handle_encoder_mask_changed + -- [defines.events.on_gui_confirmed] = handle_encoder_mask_confirmed + } + } + } + }, + { -- Bit buttons + type = "flow", + direction = "vertical", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "center" + }, + children = { + { + type = "table", + name = "bit_buttons", + column_count = 8 + } + } + }, + { -- All/None buttons + type = "flow", + direction = "horizontal", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "center" + }, + children = { + { + type = "button", + caption = { "cybersyn-combinator-encoder.all" }, + handler = handle_encoder_all + }, + { + type = "button", + caption = { "cybersyn-combinator-encoder.none" }, + handler = handle_encoder_none + } + } + }, + { + type = "table", + name = "mask_display_table", + column_count = 2, + style_mods = { + horizontally_stretchable = true + }, + children = { + { + type = "label", + caption = { "cybersyn-combinator-encoder.decimal" } + }, + { + type = "flow", + direction = "vertical", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "right" + }, + children = { + { + type = "label", + name = "display_dec", + style_mods = { + horizontal_align = "right", + horizontally_stretchable = true + } + } + } + }, + { + type = "label", + caption = { "cybersyn-combinator-encoder.hexadecimal" } + }, + { + type = "flow", + direction = "vertical", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "right" + }, + children = { + { + type = "label", + name = "display_hex", + style_mods = { + horizontal_align = "right", + horizontally_stretchable = true + } + } + } + }, + { + type = "label", + caption = { "cybersyn-combinator-encoder.binary" } + }, + { + type = "flow", + direction = "vertical", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "right" + }, + children = { + { + type = "label", + name = "display_bin", + style_mods = { + horizontal_align = "right", + horizontally_stretchable = true + } + } + } + }, + { + type = "label", + caption = { "cybersyn-combinator-encoder.octal" } + }, + { + type = "flow", + direction = "vertical", + style_mods = { + horizontally_stretchable = true, + horizontal_align = "right" + }, + children = { + { + type = "label", + name = "display_oct", + style_mods = { + horizontal_align = "right", + horizontally_stretchable = true + } + } + } + } + } + } + } + }, + { + type = "flow", + direction = "horizontal", + style_mods = { + horizontal_spacing = 0 + }, + children = { + { + type = "button", + style = "back_button", + caption = { "gui.cancel" }, + name = ENCODER_ID .. "_close", + handler = handle_encoder_close + }, + { + type = "empty-widget", + style = "flib_dialog_footer_drag_handle", + drag_target = ENCODER_ID + }, + { + type = "button", + name = "confirm_button", + style = "confirm_button", + caption = { "gui.confirm" }, + tooltip = nil, + handler = handle_encoder_confirm + } + } + } + } + } + }) + local bit_buttons = named.bit_buttons + state.encoder = { + mask = state.network_mask.mask, + dialog = dialog, + signal_button = named.encoder_signal_button, + textfield = named.encoder_mask_textfield, + bit_buttons = bit_buttons, + display_dec = named.display_dec, + display_hex = named.display_hex, + display_bin = named.display_bin, + display_oct = named.display_oct, + confirm_button = named.confirm_button + } + local signal = state.network_mask.signal + if not signal then + cc_gui:close_encoder(player_index, true) + return + end + state.encoder.signal_button.elem_value = signal.signal + state.encoder.textfield.text = masking.format_for_input(signal.count, player_index) + for i = 1, 32 do + local bit_index = i - 1 + local is_active = bit32.extract(state.encoder.mask, bit_index) == 1 + local bb_style = bit_button_style(is_active) + flib_gui.add(bit_buttons, { + type = "sprite-button", + caption = tostring(i), + style = bb_style, + mouse_button_filter = { "left" }, + tags = { + index = i, + bit_index = bit_index + }, + handler = handle_encoder_bit_button_click + }) + end + refresh_encoder(player_index, state, true) + dialog.force_auto_center() + state.main_window.visible = false + -- player.opened = dialog +end + --- @param event EventData.on_gui_click handle_network_list_item_click = function(event) local state = get_player_state(event.player_index) @@ -705,10 +1193,16 @@ handle_network_list_item_click = function(event) if not signal then return end state.network_mask.signal = signal state.network_mask.mask = signal.count - state.network_mask.signal_button.elem_value = signal.signal - state.network_mask.textfield.text = masking.format_for_input(signal.count, event.player_index) - state.network_mask.add_button.enabled = true - focus_network_mask_input(state) + state.network_mask.slot = slot + if event.control then + log:debug("Showing network encoder!") + create_encoder(event.player_index, state) + else + state.network_mask.signal_button.elem_value = signal.signal + state.network_mask.textfield.text = masking.format_for_input(signal.count, event.player_index) + state.network_mask.add_button.enabled = true + focus_network_mask_input(state) + end end --- @param player LuaPlayer @@ -740,7 +1234,10 @@ local function create_window(player, entity) type = "label", style = "frame_title", caption = { "cybersyn-combinator-window.title" }, - elem_mods = { ignored_by_interaction = true } + elem_mods = { ignored_by_interaction = true }, + style_mods = { + maximal_width = 600 + } }, { type = "empty-widget", @@ -926,7 +1423,10 @@ local function create_window(player, entity) children = { { -- On/off switch type = "flow", - style_mods = { horizontal_align = "left" }, + style_mods = { + horizontal_align = "left", + maximal_width = 110 + }, direction = "vertical", children = { { @@ -957,6 +1457,7 @@ local function create_window(player, entity) { type = "flow", direction = "vertical", + style_mods = { maximal_width = 105 }, children = { { type = "label", @@ -980,6 +1481,7 @@ local function create_window(player, entity) { type = "flow", direction = "vertical", + style_mods = { maximal_width = 105 }, children = { { type = "label", @@ -1003,6 +1505,7 @@ local function create_window(player, entity) { type = "flow", direction = "vertical", + style_mods = { maximal_width = 105 }, children = { { type = "label", @@ -1299,12 +1802,39 @@ local function destroy(player, window_id) return true end +function cc_gui:close_encoder(player_index, silent) + if not player_index then return end + local player = game.get_player(player_index) + if not player then return end + local player_data = cc_util.get_player_data(player_index) + local state = player_data and player_data.state + if state and not state.encoder then return end + log:debug("Encoder close, player index ", player_index) + local destroyed = destroy(player, ENCODER_ID) + if state and state.encoder then + state.encoder = nil + end + if not destroyed then return end + if state and state.dimmer then + state.dimmer.destroy() + state.dimmer = nil + end + if not silent then + player.play_sound { path = constants.ENTITY_CLOSE_SOUND } + end + if state then + state.main_window.visible = true + player.opened = state.main_window + end +end + --- @param player_index string|uint? function cc_gui:close(player_index, silent) if not player_index then return end local player = game.get_player(player_index) if not player then return end log:debug("GUI close, player index ", player_index) + self:close_encoder(player_index, true) local destroyed = destroy(player, WINDOW_ID) local player_data = cc_util.get_player_data(player_index) if player_data and player_data.state and player_data.state.combinator then @@ -1396,7 +1926,16 @@ function cc_gui:register() [WINDOW_ID .. "_network_mask_changed"] = handle_network_mask_changed, [WINDOW_ID .. "_network_mask_confirmed"] = handle_network_mask_confirmed, [WINDOW_ID .. "_network_mask_add_click"] = handle_network_mask_add_click, - [WINDOW_ID .. "_network_list_item_click"] = handle_network_list_item_click + [WINDOW_ID .. "_network_list_item_click"] = handle_network_list_item_click, + [ENCODER_ID .. "_close"] = handle_encoder_close, + [ENCODER_ID .. "_confirm"] = handle_encoder_confirm, + [ENCODER_ID .. "_signal_changed"] = handle_encoder_signal_changed, + [ENCODER_ID .. "_signal_click"] = handle_encoder_signal_click, + [ENCODER_ID .. "_mask_changed"] = handle_encoder_mask_changed, + [ENCODER_ID .. "_bit_button_click"] = handle_encoder_bit_button_click, + [ENCODER_ID .. "_all"] = handle_encoder_all, + [ENCODER_ID .. "_none"] = handle_encoder_none, + ["cybersyn-combinator_dimmer_click"] = handle_dimmer_click } flib_gui.handle_events() script.on_event(defines.events.on_gui_opened, function(event) self:on_gui_opened(event) end) diff --git a/src/scripts/masking.lua b/src/scripts/masking.lua index 7822f10..a1e7668 100644 --- a/src/scripts/masking.lua +++ b/src/scripts/masking.lua @@ -166,7 +166,8 @@ local function get_is_hex_mode(player) end local masking = { - Mode = Mode + Mode = Mode, + uint_to_int = uint_to_int } local PRETTIFIERS = { From c1dcc1a4952cd78a08316070d51cccf217efb257 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Mon, 2 Sep 2024 01:54:20 +0200 Subject: [PATCH 2/8] Update changelog --- src/changelog.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/changelog.txt b/src/changelog.txt index e74f508..4801085 100644 --- a/src/changelog.txt +++ b/src/changelog.txt @@ -1,4 +1,12 @@ --------------------------------------------------------------------------------------------------- +Version: 1.0.0 +Date: TBD + Major Features: + - Added new GUI for encoding network signals. + Bugfixes: + - Add possible fix for obscure issue with stack sizes. + (For more context, see issue #32 in the repository.) +--------------------------------------------------------------------------------------------------- Version: 0.6.1 Date: 2023-08-06 Bugfixes: From 462a87af7fbf060aa7f60ed9539e5ef34e45eb17 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 21:23:49 +0200 Subject: [PATCH 3/8] Add option to use 0-based indexing for encoder --- src/locale/en/mod.cfg | 2 ++ src/scripts/constants.lua | 2 ++ src/scripts/gui.lua | 4 +++- src/settings.lua | 7 +++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/locale/en/mod.cfg b/src/locale/en/mod.cfg index bf70037..33fdeb1 100644 --- a/src/locale/en/mod.cfg +++ b/src/locale/en/mod.cfg @@ -35,6 +35,7 @@ cybersyn-combinator-network-mask-parse-mode=Network mask input mode cybersyn-combinator-network-mask-display-mode=Display mode for network masks cybersyn-combinator-network-mask-display-prefix=Display prefix in front of network masks cybersyn-combinator-network-mask-use-cs-default=Pre-fill default network mask +cybersyn-combinator-encoder-zero-index=Use zero-based indexing for encoder display cybersyn-combinator-emit-default-request-threshold=Explicit default request threshold cybersyn-combinator-emit-default-priority=Explicit default priority cybersyn-combinator-emit-default-locked-slots=Explicit default locked slots @@ -55,6 +56,7 @@ cybersyn-combinator-network-mask-parse-mode=Method to use for parsing (sub-)netw cybersyn-combinator-network-mask-display-mode=How to display (sub-)network masks.\n\n[font=default-bold]Decimal:[/font] Masks are displayed as-is in decimal (e.g. '128').\n[font=default-bold]Hexadecimal:[/font] Masks are displayed as hexadecimal (e.g. '80' instead of '128').\n[font=default-bold]Binary:[/font] Masks are displayed as their full binary value (e.g. '10000000' instead of '128').\n[font=default-bold]Octal:[/font] Masks are displayed as octal (e.g. '200' instead of '128'). cybersyn-combinator-network-mask-display-prefix=When enabled, a prefix will be shown in front of formatted (sub-)network masks to indicate what format they are in.\n\nExample:\nA [font=default-bold]decimal[/font] number will be formatted as '0d12345'.\nA [font=default-bold]hexadecimal[/font] number will be formatted as '0xDEADBEEF'.\nA [font=default-bold]binary[/font] number will be formatted as '0b101010'.\nAn [font=default-bold]octal[/font] number will be formatted as '0o644'. cybersyn-combinator-network-mask-use-cs-default=When enabled, the setting "Default network mask" from Project Cybersyn will be used to pre-fill the mask value when creating a new network mask in the combinator. When disabled, the previously entered mask value will be used (if there is one). +cybersyn-combinator-encoder-zero-index=When enabled, the encoder bit buttons will use zero-based indexing for their captions (starting from 0 and going to 31) instead of one-based (starting from 1 and going to 32). cybersyn-combinator-emit-default-request-threshold=When enabled, a request threshold value that matches the Cybersyn default request threshold will not be removed from the combinator. cybersyn-combinator-emit-default-priority=When enabled, a priority value that matches the Cybersyn default priority will not be removed from the combinator. cybersyn-combinator-emit-default-locked-slots=When enabled, a locked slots value that matches the Cybersyn default locked slots will not be removed from the combinator. diff --git a/src/scripts/constants.lua b/src/scripts/constants.lua index 96724c9..180abce 100644 --- a/src/scripts/constants.lua +++ b/src/scripts/constants.lua @@ -24,6 +24,8 @@ local constants = { NETWORK_MASK_DISPLAY_MODE = "cybersyn-combinator-network-mask-display-mode", NETWORK_MASK_DISPLAY_PREFIX = "cybersyn-combinator-network-mask-display-prefix", NETWORK_MASK_USE_CS_DEFAULT = "cybersyn-combinator-network-mask-use-cs-default", + ENCODER_ZERO_INDEX = "cybersyn-combinator-encoder-zero-index", + -- Project Cybersyn settings CS_REQUEST_THRESHOLD = "cybersyn-request-threshold", CS_PRIORITY = "cybersyn-priority", CS_LOCKED_SLOTS = "cybersyn-locked-slots", diff --git a/src/scripts/gui.lua b/src/scripts/gui.lua index 9d4560a..35f0914 100644 --- a/src/scripts/gui.lua +++ b/src/scripts/gui.lua @@ -1151,13 +1151,15 @@ local function create_encoder(player_index, state) end state.encoder.signal_button.elem_value = signal.signal state.encoder.textfield.text = masking.format_for_input(signal.count, player_index) + local settings = settings.get_player_settings(player_index) + local zeroIndex = settings[constants.SETTINGS.ENCODER_ZERO_INDEX].value for i = 1, 32 do local bit_index = i - 1 local is_active = bit32.extract(state.encoder.mask, bit_index) == 1 local bb_style = bit_button_style(is_active) flib_gui.add(bit_buttons, { type = "sprite-button", - caption = tostring(i), + caption = tostring(zeroIndex and bit_index or i), style = bb_style, mouse_button_filter = { "left" }, tags = { diff --git a/src/settings.lua b/src/settings.lua index 80ce9c1..380209a 100644 --- a/src/settings.lua +++ b/src/settings.lua @@ -150,6 +150,13 @@ data:extend { default_value = true, order = "c[cybersyn]-c[combinator]-m[masks]-d[default]-c[cybersyn]" }, + { + type = "bool-setting", + name = NAMES.ENCODER_ZERO_INDEX, + setting_type = "runtime-per-user", + default_value = false, + order = "c[cybersyn]-c[combinator]-e[encoder]-z[zeroindex]" + }, { type = "bool-setting", name = NAMES.NEGATIVE_SIGNALS, From e8fadced0b8fd94df9a8ebf0837fcc4fd5d09ce7 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 21:39:04 +0200 Subject: [PATCH 4/8] Adjust encoder UI --- src/scripts/gui.lua | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/scripts/gui.lua b/src/scripts/gui.lua index 35f0914..a998f16 100644 --- a/src/scripts/gui.lua +++ b/src/scripts/gui.lua @@ -899,7 +899,7 @@ local function create_encoder(player_index, state) }, style_mods = { -- minimal_width = 240 - width = 400 + width = 450 }, children = { { @@ -934,11 +934,15 @@ local function create_encoder(player_index, state) { -- Signal and text field type = "flow", direction = "horizontal", + style = "centering_horizontal_flow", style_mods = { - horizontally_stretchable = true, - vertical_align = "center" + bottom_margin = 4 }, children = { + { + type = "flow", + style_mods = { horizontally_stretchable = true } + }, { type = "choose-elem-button", name = "encoder_signal_button", @@ -953,7 +957,7 @@ local function create_encoder(player_index, state) type = "textfield", name = "encoder_mask_textfield", style = "cybersyn-combinator_network-mask-text-input", - style_mods = { horizontally_stretchable = true, maximal_width = 400 }, + style_mods = { left_margin = 8, width = 200 }, numeric = false, clear_and_focus_on_right_click = true, lose_focus_on_confirm = true, @@ -961,7 +965,11 @@ local function create_encoder(player_index, state) [defines.events.on_gui_text_changed] = handle_encoder_mask_changed -- [defines.events.on_gui_confirmed] = handle_encoder_mask_confirmed } - } + }, + { + type = "flow", + style_mods = { horizontally_stretchable = true } + }, } }, { -- Bit buttons @@ -969,7 +977,9 @@ local function create_encoder(player_index, state) direction = "vertical", style_mods = { horizontally_stretchable = true, - horizontal_align = "center" + horizontal_align = "center", + top_margin = 4, + bottom_margin = 4 }, children = { { @@ -984,7 +994,9 @@ local function create_encoder(player_index, state) direction = "horizontal", style_mods = { horizontally_stretchable = true, - horizontal_align = "center" + horizontal_align = "center", + top_margin = 4, + bottom_margin = 4 }, children = { { From 759c460cc54a3bd1b1fece752f826ff3fa5feb85 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 21:57:23 +0200 Subject: [PATCH 5/8] Add Swedish translations for encoder --- src/locale/sv-SE/mod.cfg | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/locale/sv-SE/mod.cfg b/src/locale/sv-SE/mod.cfg index e0f6542..b498328 100644 --- a/src/locale/sv-SE/mod.cfg +++ b/src/locale/sv-SE/mod.cfg @@ -35,6 +35,7 @@ cybersyn-combinator-network-mask-parse-mode=Inmatningsläge för nätverksbitmas cybersyn-combinator-network-mask-display-mode=Visningsläge för nätverksbitmaskar cybersyn-combinator-network-mask-display-prefix=Visa prefix framför nätverksbitmaskar cybersyn-combinator-network-mask-use-cs-default=Förifyll standard nätverksmask +cybersyn-combinator-encoder-zero-index=Använd nollbaserad indexering för nätverkskodaren cybersyn-combinator-emit-default-request-threshold=Explicit standardförfrågningströskel cybersyn-combinator-emit-default-priority=Explicit standardprioritet cybersyn-combinator-emit-default-locked-slots=Explicit standard låsta platser @@ -55,6 +56,7 @@ cybersyn-combinator-network-mask-parse-mode=Metod att använda för inläsning a cybersyn-combinator-network-mask-display-mode=Ställer in hur (sub-)nätverksmasker visas.\n\n[font=default-bold]Decimalt:[/font] Masker visas som vanliga decimaltal (t.ex. '128').\n[font=default-bold]Hexadecimalt:[/font] Masker visas som hexadecimala tal (e.g. '80' istället för '128').\n[font=default-bold]Binärt:[/font] Masker visas som binära tal (t.ex. '10000000' istället för '128').\n[font=default-bold]Oktalt:[/font] Masker visas som oktala tal (e.g. '200' istället för '128'). cybersyn-combinator-network-mask-display-prefix=Visar prefix framför formaterade (sub-)nätverksmasker för att indikera vilket format de har.\n\nExempel:\nEtt [font=default-bold]decimaltal[/font] formateras likt '0d12345'.\nEtt [font=default-bold]hexadecimalt[/font] tal formateras likt '0xDEADBEEF'.\nEtt [font=default-bold]binärt[/font] tal formateras likt '0b101010'.\nEtt [font=default-bold]oktalt[/font] tal formateras likt '0o644'. cybersyn-combinator-network-mask-use-cs-default=Använder standardnätverksmasken från Project Cybersyn som standardvärde för bitmasken när en ny nätverksmask skapas i kombinatorn. Annars används den förra inskrivna masken (om det finns en). +cybersyn-combinator-encoder-zero-index=Om aktiverad används nollbaserad indexering för texten på knapparna i nätverkskodaren (från 0 till 31) istället för ettbaserad indexering (från 1 till 32). cybersyn-combinator-emit-default-request-threshold=Om aktiverad kommer en förfrågningströskel som matchar Cybersyns standardvärde inte att tas bort från kombinatorn. cybersyn-combinator-emit-default-priority=Om aktiverad kommer en prioritet som matchar Cybersyns standardvärde inte att tas bort från kombinatorn. cybersyn-combinator-emit-default-locked-slots=Om aktiverad kommer ett värde på "låsta platser" som matchar Cybersyns standardvärde inte att tas bort från kombinatorn. @@ -116,3 +118,12 @@ item-stacks=Antal staplar item-stacks-description=Totalt antal staplar som efterfrågas av kombinatorn, endast negativa signalvärden räknas in i totalen. fluid-total=Mängd vätska fluid-total-description=Total mängd vätska som efterfrågas av kombinatorn, endast negativa signalvärden räknas in i totalen. + +[cybersyn-combinator-encoder] +title=Nätverkskodare +all=Alla +none=Inga +decimal=Decimalt +hexadecimal=Hexadecimalt +binary=Binärt +octal=Oktalt From 44f78d5134120e9674ac0231c54fa186b3275e76 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 21:58:11 +0200 Subject: [PATCH 6/8] Add encoder instructions to tooltips --- src/locale/en/mod.cfg | 4 ++-- src/locale/sv-SE/mod.cfg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locale/en/mod.cfg b/src/locale/en/mod.cfg index 33fdeb1..ceede6a 100644 --- a/src/locale/en/mod.cfg +++ b/src/locale/en/mod.cfg @@ -107,8 +107,8 @@ cs-signal-reset=Reset to default stacks=Stacks items=Items network-list-title=Network masks -network-list-tooltip=Select a signal with the left button, input a network mask value in the text box, and then press the green confirm button to add it.\nUse __CONTROL_LEFT_CLICK__ on an item in the list to edit it, or __CONTROL_RIGHT_CLICK__ to remove it.\n(Adding an existing signal with a new value will update it.) -network-list-item-tooltip=Mask:\nDecimal: __1__\nHex: __2__\nBinary: __3__\nOctal: __4__\n\n__CONTROL_LEFT_CLICK__: Edit\n__CONTROL_RIGHT_CLICK__: Remove +network-list-tooltip=Select a signal with the left button, input a network mask value in the text box, and then press the green confirm button to add it.\nUse __CONTROL_LEFT_CLICK__ on an item in the list to edit it, or __CONTROL_RIGHT_CLICK__ to remove it.\nIf you __CONTROL_KEY_CTRL____CONTROL_STYLE_BEGIN__ + __CONTROL_STYLE_END____CONTROL_LEFT_CLICK__ on a signal, it will open in the network encoder GUI.\n(Adding an existing signal with a new value will update it.) +network-list-item-tooltip=Mask:\nDecimal: __1__\nHex: __2__\nBinary: __3__\nOctal: __4__\n\n__CONTROL_LEFT_CLICK__: Edit\n__CONTROL_RIGHT_CLICK__: Remove\n__CONTROL_KEY_CTRL____CONTROL_STYLE_BEGIN__ + __CONTROL_STYLE_END____CONTROL_LEFT_CLICK__: Open in network encoder invalid-signal=The virtual signals [virtual-signal=signal-everything], [virtual-signal=signal-anything], and [virtual-signal=signal-each], or empty/unknown signals are not valid as output signals.\nSee [color=blue]https://forums.factorio.com/viewtopic.php?p=554711[/color] for details. max-network-signals=The maximum number of __1__ network __plural_for_parameter_1_{1=signal has|rest=signals have}__ been reached, you cannot add any more to this combinator. non-virtual-network-mask=[__1__=__2__] is not a valid network mask signal, only virtual signals are allowed. diff --git a/src/locale/sv-SE/mod.cfg b/src/locale/sv-SE/mod.cfg index b498328..60f4dbd 100644 --- a/src/locale/sv-SE/mod.cfg +++ b/src/locale/sv-SE/mod.cfg @@ -107,8 +107,8 @@ cs-signal-reset=Återställ till standardvärde stacks=Staplar items=Styck network-list-title=Nätverksmasker -network-list-tooltip=Välj en signal med den vänstra knappen, mata in ett maskvärde i textboxen, och tryck sedan på den gröna bekräftelseknappen för att lägga till den.\nAnvänd __CONTROL_LEFT_CLICK__ på en rad i listan för att ändra på den, eller __CONTROL_RIGHT_CLICK__ för att ta bort den.\n(Tillägg av en existerande signal med ett nytt värde kommer att uppdatera den.) -network-list-item-tooltip=Mask:\nDecimalt: __1__\nHex: __2__\nBinärt: __3__\nOktalt: __4__\n\n__CONTROL_LEFT_CLICK__: Ändra\n__CONTROL_RIGHT_CLICK__: Ta bort +network-list-tooltip=Välj en signal med den vänstra knappen, mata in ett maskvärde i textboxen, och tryck sedan på den gröna bekräftelseknappen för att lägga till den.\nAnvänd __CONTROL_LEFT_CLICK__ på en rad i listan för att ändra på den, eller __CONTROL_RIGHT_CLICK__ för att ta bort den.\nAnvänd __CONTROL_KEY_CTRL____CONTROL_STYLE_BEGIN__ + __CONTROL_STYLE_END____CONTROL_LEFT_CLICK__ på en signal för att öppna den i nätverkskodaren.\n(Tillägg av en existerande signal med ett nytt värde kommer att uppdatera den.) +network-list-item-tooltip=Mask:\nDecimalt: __1__\nHex: __2__\nBinärt: __3__\nOktalt: __4__\n\n__CONTROL_LEFT_CLICK__: Ändra\n__CONTROL_RIGHT_CLICK__: Ta bort\n__CONTROL_KEY_CTRL____CONTROL_STYLE_BEGIN__ + __CONTROL_STYLE_END____CONTROL_LEFT_CLICK__: Öppna i nätverkskodaren invalid-signal=Signalerna [virtual-signal=signal-everything], [virtual-signal=signal-anything], och [virtual-signal=signal-each], eller tomma/okända signaler är inte giltiga som utsignaler.\nSe [color=blue]https://forums.factorio.com/viewtopic.php?p=554711[/color] för mer detaljer. max-network-signals=Maximalt antal (__1__) nätverks__plural_for_parameter_1_{1=signal|rest=signaler}__ har nåtts, du kan inte lägga till fler på den här kombinatorn. non-virtual-network-mask=[__1__=__2__] är inte en giltig signal för nätverksmasker, endast virtuella signaler är tillåtna. From 507a8c2601c2e6959a6f40aa39e47a2be1ab3c04 Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 22:37:17 +0200 Subject: [PATCH 7/8] Add tooltip to explain the encoder --- src/locale/en/mod.cfg | 1 + src/locale/sv-SE/mod.cfg | 1 + src/scripts/gui.lua | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/locale/en/mod.cfg b/src/locale/en/mod.cfg index ceede6a..09fa6bc 100644 --- a/src/locale/en/mod.cfg +++ b/src/locale/en/mod.cfg @@ -121,6 +121,7 @@ fluid-total-description=The total amount of fluids being requested by this combi [cybersyn-combinator-encoder] title=Network encoder +tooltip=Each numbered button represents a bit in the network mask (a sub-network). __CONTROL_LEFT_CLICK__ a button to toggle the bit (sub-network) on or off.\nThe number corresponds to the bit position in the network mask, starting at the first bit (least significant, or right-most) at the top left button, and ending on the last bit (most significant, or left-most) at the bottom right button.\n\nEach enabled button essentially adds a power of two to the final network mask value (signal), with the first button starting at 2^0 (1), and increasing until the last button at 2^31 (2 147 483 648). all=All none=None decimal=Decimal diff --git a/src/locale/sv-SE/mod.cfg b/src/locale/sv-SE/mod.cfg index 60f4dbd..fdab239 100644 --- a/src/locale/sv-SE/mod.cfg +++ b/src/locale/sv-SE/mod.cfg @@ -121,6 +121,7 @@ fluid-total-description=Total mängd vätska som efterfrågas av kombinatorn, en [cybersyn-combinator-encoder] title=Nätverkskodare +tooltip=Varje numrerad knapp representerar en bit i nätverksmasken (subnätverk). ___CONTROL_LEFT_CLICK__ en knapp för att slå på eller av biten (subnätverket).\nNumret motsvarar bitpositionen i nätverksmasken, där den första biten (minst signifikanta, eller längst åt höger) är på den översta vänstra knappen, och den sista biten (mest signifikanta, eller längst till vänster) är på den nedersta högra knappen.\n\nVarje aktiverad knapp lägger i princip till en potens av två i nätverksmaskvärdet (signalen), där den första knappen börjar på 2^0 (1), och ökar tills den sista knappen på 2^31 (2 147 483 648). all=Alla none=Inga decimal=Decimalt diff --git a/src/scripts/gui.lua b/src/scripts/gui.lua index a998f16..b580f94 100644 --- a/src/scripts/gui.lua +++ b/src/scripts/gui.lua @@ -906,11 +906,17 @@ local function create_encoder(player_index, state) type = "flow", direction = "horizontal", drag_target = ENCODER_ID, + tooltip = { "cybersyn-combinator-encoder.tooltip" }, children = { { type = "label", style = "frame_title", - caption = { "cybersyn-combinator-encoder.title" }, + caption = { + "", + { "cybersyn-combinator-encoder.title" }, + " [img=info]" + }, + tooltip = { "cybersyn-combinator-encoder.tooltip" }, elem_mods = { ignored_by_interaction = true } }, { From 38bdafab6f97f25c1539c4f13f20abab66e0902e Mon Sep 17 00:00:00 2001 From: Adam Hellberg Date: Tue, 3 Sep 2024 22:38:53 +0200 Subject: [PATCH 8/8] Add date for v1.0.0 to changelog --- src/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/changelog.txt b/src/changelog.txt index 4801085..fa50333 100644 --- a/src/changelog.txt +++ b/src/changelog.txt @@ -1,6 +1,6 @@ --------------------------------------------------------------------------------------------------- Version: 1.0.0 -Date: TBD +Date: 2024-09-03 Major Features: - Added new GUI for encoding network signals. Bugfixes: