diff options
Diffstat (limited to 'plugins/autofire/autofire_menu.lua')
-rw-r--r-- | plugins/autofire/autofire_menu.lua | 299 |
1 files changed, 182 insertions, 117 deletions
diff --git a/plugins/autofire/autofire_menu.lua b/plugins/autofire/autofire_menu.lua index 1533465105f..c53dd711f53 100644 --- a/plugins/autofire/autofire_menu.lua +++ b/plugins/autofire/autofire_menu.lua @@ -1,5 +1,8 @@ local lib = {} +-- Common UI helper library +local commonui + -- Set of all menus local MENU_TYPES = { MAIN = 0, EDIT = 1, ADD = 2, BUTTON = 3 } @@ -15,11 +18,29 @@ 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 + +-- Helper for polling for hotkeys +local hotkey_poller + -- Button being created/edited local current_button = {} --- Inputs that can be autofired (to list in BUTTON menu) -local inputs = {} +-- Initial button to select when opening buttons menu +local initial_input + +-- Handler for BUTTON menu +local input_menu -- Returns the section (from MENU_SECTIONS) and the index within that section local function menu_section(index) @@ -41,51 +62,76 @@ local function create_new_button() end local function is_button_complete(button) - return button.port and button.field and button.key and button.on_frames and button.off_frames and button.button and button.counter -end - -local function is_supported_input(ioport_field) - -- IPT_BUTTON1 through IPT_BUTTON16 in ioport_type enum (ioport.h) - return ioport_field.type >= 64 and ioport_field.type <= 79 + return button.port and button.mask and button.type and button.key and button.on_frames and button.off_frames and button.button and button.counter end -- Main menu local function populate_main_menu(buttons) + local ioport = manager.machine.ioport + local input = manager.machine.input local menu = {} - menu[#menu + 1] = {_('Autofire buttons'), '', 'off'} - menu[#menu + 1] = {'---', '', ''} + table.insert(menu, {_p('plugin-autofire', 'Autofire buttons'), '', 'off'}) + table.insert(menu, {string.format(_p('plugin-autofire', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off'}) + table.insert(menu, {'---', '', ''}) header_height = #menu - 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 - rate = math.floor(rate * 100) / 100 - local text = button.button.name .. ' [' .. rate .. ' Hz]' - local subtext = manager:machine():input():code_name(button.key) - menu[#menu + 1] = {text, subtext, ''} + -- 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 + + if #buttons > 0 then + for index, button in ipairs(buttons) do + -- Round rate to two decimal places + local rate = freq / (button.on_frames + button.off_frames) + rate = math.floor(rate * 100) / 100 + local text + if button.button then + text = string.format(_p('plugin-autofire', '%s [%g Hz]'), button.button.name, rate) + else + text = string.format(_p('plugin-autofire', 'n/a [%g Hz]'), rate) + end + table.insert(menu, {text, input:seq_name(button.key), ''}) + if index == initial_button then + main_selection_save = #menu + end + end + else + table.insert(menu, {_p('plugin-autofire', '[no autofire buttons]'), '', 'off'}) + end + initial_button = nil content_height = #menu - menu[#menu + 1] = {'---', '', ''} - menu[#menu + 1] = {_('Add autofire button'), '', ''} - return menu + table.insert(menu, {'---', '', ''}) + table.insert(menu, {_p('plugin-autofire', 'Add autofire button'), '', ''}) + + 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 @@ -97,132 +143,158 @@ end -- Add/edit menus (mostly identical) local function populate_configure_menu(menu) - local button_name = current_button.button and current_button.button.name or _('NOT SET') - local key_name = current_button.key and manager:machine():input():code_name(current_button.key) or _('NOT SET') - menu[#menu + 1] = {_('Input'), button_name, ''} - 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'} -end - --- Borrowed from the cheat plugin -local function poll_for_hotkey() - local input = manager:machine():input() - manager:machine():popmessage(_('Press button for hotkey or wait to leave unchanged')) - manager:machine():video():frame_update(true) - input:seq_poll_start('switch') - local time = os.clock() - while (not input:seq_poll()) and (os.clock() < time + 1) do end - local tokens = input:seq_to_tokens(input:seq_poll_final()) - manager:machine():popmessage() - manager:machine():video():frame_update(true) - - local final_token = nil - for token in tokens:gmatch('%S+') do - final_token = token + local button_name + if current_button.button then + button_name = current_button.button.name + elseif current_button.port then + button_name = _p('plugin-autofire', 'n/a') + else + button_name = _p('plugin-autofire', '[not set]') + end + local key_name = current_button.key and manager.machine.input:seq_name(current_button.key) or _p('plugin-autofire', '[not set]') + table.insert(menu, {_p('plugin-autofire', 'Input'), button_name, ''}) + if not (configure_menu_active or configure_selection_save) then + configure_selection_save = #menu end - return final_token and input:code_from_token(final_token) or nil + table.insert(menu, {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''}) + table.insert(menu, {_p('plugin-autofire', 'On frames'), tostring(current_button.on_frames), current_button.on_frames > 1 and 'lr' or 'r'}) + table.insert(menu, {_p('plugin-autofire', 'Off frames'), tostring(current_button.off_frames), current_button.off_frames > 1 and 'lr' or 'r'}) + configure_menu_active = true end local function handle_configure_menu(index, event) - -- Input + if hotkey_poller then + -- special handling for polling for hotkey + if hotkey_poller:poll() then + if hotkey_poller.sequence then + current_button.key = hotkey_poller.sequence + current_button.key_cfg = manager.machine.input:seq_to_tokens(hotkey_poller.sequence) + end + hotkey_poller = nil + return true + end + return false + end + 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.button then + initial_input = current_button.button + end return true - else - return false end - -- Hotkey elseif index == 2 then + -- Hotkey if event == 'select' then - local keycode = poll_for_hotkey() - if keycode then - current_button.key = keycode - return true - else - return false + if not commonui then + commonui = require('commonui') end - else - return false + hotkey_poller = commonui.switch_polling_helper() + return true end - -- On frames elseif index == 3 then - manager:machine():popmessage(_('Number of frames button will be pressed')) + -- On frames + manager.machine:popmessage(_p('plugin-autofire', 'Number of frames button will be pressed')) if event == 'left' then current_button.on_frames = current_button.on_frames - 1 + return true 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 - -- Off frames elseif index == 4 then - manager:machine():popmessage(_('Number of frames button will be released')) + -- Off frames + manager.machine:popmessage(_p('plugin-autofire', 'Number of frames button will be released')) if event == 'left' then current_button.off_frames = current_button.off_frames - 1 + return true 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 true + return false end local function populate_edit_menu() local menu = {} - menu[#menu + 1] = {_('Edit autofire button'), '', 'off'} - menu[#menu + 1] = {'---', '', ''} + table.insert(menu, {_p('plugin-autofire', 'Edit autofire button'), '', 'off'}) + table.insert(menu, {'---', '', ''}) header_height = #menu populate_configure_menu(menu) content_height = #menu - menu[#menu + 1] = {'---', '', ''} - menu[#menu + 1] = {_('Done'), '', ''} - return menu + table.insert(menu, {'---', '', ''}) + table.insert(menu, {_p('plugin-autofire', 'Done'), '', ''}) + + local selection = configure_selection_save + configure_selection_save = nil + if hotkey_poller then + return hotkey_poller:overlay(menu, selection, 'lrrepeat') + else + return menu, selection, 'lrrepeat' + end end local function handle_edit_menu(index, event, buttons) local section, adjusted_index = menu_section(index) - if section == MENU_SECTIONS.CONTENT then + if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'back') then + configure_menu_active = false + table.remove(menu_stack) + return true + elseif section == MENU_SECTIONS.CONTENT then return handle_configure_menu(adjusted_index, event) - elseif section == MENU_SECTIONS.FOOTER then - if event == 'select' then - table.remove(menu_stack) - return true - end end return false end local function populate_add_menu() local menu = {} - menu[#menu + 1] = {_('Add autofire button'), '', 'off'} - menu[#menu + 1] = {'---', '', ''} + table.insert(menu, {_p('plugin-autofire', 'Add autofire button'), '', 'off'}) + table.insert(menu, {'---', '', ''}) header_height = #menu populate_configure_menu(menu) content_height = #menu - menu[#menu + 1] = {'---', '', ''} + table.insert(menu, {'---', '', ''}) if is_button_complete(current_button) then - menu[#menu + 1] = {_('Create'), '', ''} + table.insert(menu, {_p('plugin-autofire', 'Create'), '', ''}) else - menu[#menu + 1] = {_('Cancel'), '', ''} + table.insert(menu, {_p('plugin-autofire', 'Cancel'), '', ''}) + end + + local selection = configure_selection_save + configure_selection_save = nil + if hotkey_poller then + return hotkey_poller:overlay(menu, selection, 'lrrepeat') + else + return menu, selection, 'lrrepeat' end - return menu end local function handle_add_menu(index, event, buttons) local section, adjusted_index = menu_section(index) - if section == MENU_SECTIONS.CONTENT then - return handle_configure_menu(adjusted_index, event) - elseif section == MENU_SECTIONS.FOOTER then - if event == 'select' then - table.remove(menu_stack) - if is_button_complete(current_button) then - buttons[#buttons + 1] = current_button - end - return true + if ((section == MENU_SECTIONS.FOOTER) and (event == 'select')) or (event == 'back') then + configure_menu_active = false + table.remove(menu_stack) + if is_button_complete(current_button) and (event == 'select') then + table.insert(buttons, current_button) + initial_button = #buttons end + return true + elseif section == MENU_SECTIONS.CONTENT then + return handle_configure_menu(adjusted_index, event) end return false end @@ -230,39 +302,32 @@ end -- Button selection menu local function populate_button_menu() - menu = {} - inputs = {} - menu[#menu + 1] = {_('Select an input for autofire'), '', 'off'} - menu[#menu + 1] = {'---', '', ''} - header_height = #menu + local function is_supported_input(ioport_field) + -- IPT_BUTTON1 through IPT_BUTTON16 in ioport_type enum (ioport.h) + return ioport_field.type >= 64 and ioport_field.type <= 79 + end - for port_key, port in pairs(manager:machine():ioport().ports) do - for field_key, field in pairs(port.fields) do - if is_supported_input(field) then - menu[#menu + 1] = {field.name, '', ''} - inputs[#inputs + 1] = { - port_name = port_key, - field_name = field_key, - ioport_field = field - } - end + local function action(field) + if field then + current_button.port = field.port.tag + current_button.mask = field.mask + current_button.type = field.type + current_button.button = field end + initial_input = nil + input_menu = nil + table.remove(menu_stack) end - content_height = #menu - return menu + + if not commonui then + commonui = require('commonui') + end + input_menu = commonui.input_selection_menu(action, _p('plugin-autofire', 'Select an input for autofire'), is_supported_input) + return input_menu:populate(initial_input) end local function handle_button_menu(index, event) - local section, adjusted_index = menu_section(index) - if section == MENU_SECTIONS.CONTENT and event == 'select' then - local selected_input = inputs[adjusted_index] - current_button.port = selected_input.port_name - current_button.field = selected_input.field_name - current_button.button = selected_input.ioport_field - table.remove(menu_stack) - return true - end - return false + return input_menu:handle(index, event) end function lib:init_menu(buttons) @@ -270,7 +335,7 @@ function lib:init_menu(buttons) content_height = 0 menu_stack = { MENU_TYPES.MAIN } current_button = {} - inputs = {} + input_menu = nil end function lib:populate_menu(buttons) @@ -287,7 +352,7 @@ function lib:populate_menu(buttons) end function lib:handle_menu_event(index, event, buttons) - manager:machine():popmessage() + manager.machine:popmessage() local current_menu = menu_stack[#menu_stack] if current_menu == MENU_TYPES.MAIN then return handle_main_menu(index, event, buttons) |