diff options
author | 2021-10-22 01:14:05 +1100 | |
---|---|---|
committer | 2021-10-22 01:14:05 +1100 | |
commit | f459eb6e137252301fefeff443d10ae8b9a69828 (patch) | |
tree | e50f3edd884637b30aee2a14af6d76fb4d012070 /plugins/autofire/autofire_menu.lua | |
parent | 9c61152a201e9f4757cc20d3571a0714890d3cc4 (diff) |
Plugin usability improvements:
* autofire, inputmacro: Made left/right repeat when held (makes setting
long delays/durations easier).
* autofire, inputmacro: Added headings for devices in input selection
menus (helps when controller buttons have identical names, e.g. AES)
* autofire: Made intial selection when moving between menus intuitive,
log some errors on saving/loading configuration.
* autofire: Fixed two errors in Chinese localisations.
Diffstat (limited to 'plugins/autofire/autofire_menu.lua')
-rw-r--r-- | plugins/autofire/autofire_menu.lua | 172 |
1 files changed, 131 insertions, 41 deletions
diff --git a/plugins/autofire/autofire_menu.lua b/plugins/autofire/autofire_menu.lua index c9afa90e94f..18000bfbd99 100644 --- a/plugins/autofire/autofire_menu.lua +++ b/plugins/autofire/autofire_menu.lua @@ -15,11 +15,26 @@ local content_height = 0 -- Stack of menus (see MENU_TYPES) local menu_stack = { MENU_TYPES.MAIN } +-- Button to select when showing the main menu (so newly added button can be selected) +local initial_button + +-- Saved selection on main menu (to restore after configure menu is dismissed) +local main_selection_save + +-- Whether configure menu is active (so first item can be selected initially) +local configure_menu_active = false + +-- Saved selection on configure menu (to restore after button menu is dismissed) +local configure_selection_save + -- Button being created/edited local current_button = {} +-- Initial button to select when opening buttons menu +local initial_input + -- Inputs that can be autofired (to list in BUTTON menu) -local inputs = {} +local inputs -- Returns the section (from MENU_SECTIONS) and the index within that section local function menu_section(index) @@ -60,35 +75,54 @@ local function populate_main_menu(buttons) menu[#menu + 1] = {'---', '', ''} header_height = #menu + -- Use frame rate of first screen or 60Hz if no screens + local freq = 60 + local screen = manager.machine.screens:at(1) + if screen then + freq = 1 / screen.frame_period + end + for index, button in ipairs(buttons) do - -- Assume refresh rate of 60 Hz; maybe better to use screen_device refresh()? - local rate = 60 / (button.on_frames + button.off_frames) - -- Round to two decimal places + -- Round rate to two decimal places + local rate = freq / (button.on_frames + button.off_frames) rate = math.floor(rate * 100) / 100 - local text = string.format(_('%s [%d Hz]'), _p('input-name', button.button.name), rate) + local text = string.format(_('%s [%g Hz]'), _p('input-name', button.button.name), rate) local subtext = input:seq_name(button.key) menu[#menu + 1] = {text, subtext, ''} + if index == initial_button then + main_selection_save = #menu + end end + initial_button = nil content_height = #menu menu[#menu + 1] = {'---', '', ''} menu[#menu + 1] = {_('Add autofire button'), '', ''} - return menu + + local selection = main_selection_save + main_selection_save = nil + return menu, selection end local function handle_main_menu(index, event, buttons) local section, adjusted_index = menu_section(index) if section == MENU_SECTIONS.CONTENT then if event == 'select' then + main_selection_save = index current_button = buttons[adjusted_index] table.insert(menu_stack, MENU_TYPES.EDIT) return true elseif event == 'clear' then table.remove(buttons, adjusted_index) + main_selection_save = index + if adjusted_index > #buttons then + main_selection_save = main_selection_save - 1 + end return true end elseif section == MENU_SECTIONS.FOOTER then if event == 'select' then + main_selection_save = index current_button = create_new_button() table.insert(menu_stack, MENU_TYPES.ADD) return true @@ -103,9 +137,13 @@ local function populate_configure_menu(menu) local button_name = current_button.button and _p('input-name', current_button.button.name) or _('NOT SET') local key_name = current_button.key and manager.machine.input:seq_name(current_button.key) or _('NOT SET') menu[#menu + 1] = {_('Input'), button_name, ''} + if not (configure_menu_active or configure_selection_save) then + configure_selection_save = #menu + end menu[#menu + 1] = {_('Hotkey'), key_name, ''} menu[#menu + 1] = {_('On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'} menu[#menu + 1] = {_('Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'} + configure_menu_active = true end -- Borrowed from the cheat plugin @@ -138,7 +176,11 @@ local function handle_configure_menu(index, event) if index == 1 then -- Input if event == 'select' then + configure_selection_save = header_height + index table.insert(menu_stack, MENU_TYPES.BUTTON) + if current_button.port and current_button.field then + initial_input = {port_name = current_button.port, ioport_field = current_button.button} + end return true end elseif index == 2 then @@ -159,6 +201,9 @@ local function handle_configure_menu(index, event) elseif event == 'right' then current_button.on_frames = current_button.on_frames + 1 return true + elseif event == 'clear' then + current_button.on_frames = 1 + return true end elseif index == 4 then -- Off frames @@ -169,6 +214,9 @@ local function handle_configure_menu(index, event) elseif event == 'right' then current_button.off_frames = current_button.off_frames + 1 return true + elseif event == 'clear' then + current_button.off_frames = 1 + return true end end return false @@ -185,12 +233,17 @@ local function populate_edit_menu() menu[#menu + 1] = {'---', '', ''} menu[#menu + 1] = {_('Done'), '', ''} - return menu + + local selection = configure_selection_save + configure_selection_save = nil + return menu, selection, 'lrrepeat' end local function handle_edit_menu(index, event, buttons) local section, adjusted_index = menu_section(index) if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'cancel') then + inputs = nil + configure_menu_active = false table.remove(menu_stack) return true elseif section == MENU_SECTIONS.CONTENT then @@ -214,15 +267,21 @@ local function populate_add_menu() else menu[#menu + 1] = {_('Cancel'), '', ''} end - return menu + + local selection = configure_selection_save + configure_selection_save = nil + return menu, selection, 'lrrepeat' end local function handle_add_menu(index, event, buttons) local section, adjusted_index = menu_section(index) if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'cancel') then + inputs = nil + configure_menu_active = false table.remove(menu_stack) if is_button_complete(current_button) and (event == 'select') then - buttons[#buttons + 1] = current_button + table.insert(buttons, current_button) + initial_button = #buttons end return true elseif section == MENU_SECTIONS.CONTENT then @@ -236,54 +295,85 @@ end local function populate_button_menu() local ioport = manager.machine.ioport menu = {} - inputs = {} menu[#menu + 1] = {_('Select an input for autofire'), '', 'off'} menu[#menu + 1] = {'---', '', ''} header_height = #menu - for port_key, port in pairs(ioport.ports) do - for field_key, field in pairs(port.fields) do - if is_supported_input(field) then - inputs[#inputs + 1] = { - port_name = port_key, - field_name = field_key, - ioport_field = field - } + if not inputs then + inputs = {} + + for port_key, port in pairs(ioport.ports) do + for field_key, field in pairs(port.fields) do + if is_supported_input(field) then + inputs[#inputs + 1] = { + port_name = port_key, + field_name = field_key, + ioport_field = field + } + end end end - end - local function compare(x, y) - if x.ioport_field.device.tag < y.ioport_field.device.tag then - return true - elseif x.ioport_field.device.tag > y.ioport_field.device.tag then - return false + local function compare(x, y) + if x.ioport_field.device.tag < y.ioport_field.device.tag then + return true + elseif x.ioport_field.device.tag > y.ioport_field.device.tag then + return false + end + groupx = ioport:type_group(x.ioport_field.type, x.ioport_field.player) + groupy = ioport:type_group(y.ioport_field.type, y.ioport_field.player) + if groupx < groupy then + return true + elseif groupx > groupy then + return false + elseif x.ioport_field.type < y.ioport_field.type then + return true + elseif x.ioport_field.type > y.ioport_field.type then + return false + else + return x.ioport_field.name < y.ioport_field.name + end end - groupx = ioport:type_group(x.ioport_field.type, x.ioport_field.player) - groupy = ioport:type_group(y.ioport_field.type, y.ioport_field.player) - if groupx < groupy then - return true - elseif groupx > groupy then - return false - elseif x.ioport_field.type < y.ioport_field.type then - return true - elseif x.ioport_field.type > y.ioport_field.type then - return false - else - return x.ioport_field.name < y.ioport_field.name + table.sort(inputs, compare) + + local i = 1 + local prev + while i <= #inputs do + local current = inputs[i] + if (not prev) or (prev.ioport_field.device.tag ~= current.ioport_field.device.tag) then + table.insert(inputs, i, false) + i = i + 2 + else + i = i + 1 + end + prev = current end end - table.sort(inputs, compare) - for i, input in pairs(inputs) do - menu[header_height + i] = { _p('input-name', input.ioport_field.name), '', '' } + local selection = header_height + 1 + for i, input in ipairs(inputs) do + if input then + menu[header_height + i] = { _p('input-name', input.ioport_field.name), '', '' } + if initial_input and (initial_input.port_name == input.port_name) and (initial_input.ioport_field.mask == input.ioport_field.mask) and (initial_input.ioport_field.type == input.ioport_field.type) then + selection = header_height + i + initial_input = nil + end + else + local device = inputs[i + 1].ioport_field.device + if device.owner then + menu[header_height + i] = {string.format(_('%s [root%s]'), device.name, device.tag), '', 'heading'} + else + menu[header_height + i] = {string.format(_('[root%s]'), device.tag), '', 'heading'} + end + end end content_height = #menu + initial_input = nil menu[#menu + 1] = {'---', '', ''} menu[#menu + 1] = {_('Cancel'), '', ''} - return menu + return menu, selection end local function handle_button_menu(index, event) @@ -307,7 +397,7 @@ function lib:init_menu(buttons) content_height = 0 menu_stack = { MENU_TYPES.MAIN } current_button = {} - inputs = {} + inputs = nil end function lib:populate_menu(buttons) |