summaryrefslogtreecommitdiffstatshomepage
path: root/plugins/autofire/autofire_menu.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/autofire/autofire_menu.lua')
-rw-r--r--plugins/autofire/autofire_menu.lua301
1 files changed, 180 insertions, 121 deletions
diff --git a/plugins/autofire/autofire_menu.lua b/plugins/autofire/autofire_menu.lua
index a880d1c5008..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():seq_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,138 +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():seq_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'}
+ 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
+ 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
--- 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()
- local clearmsg = true
- while (not input:seq_poll()) and (input:seq_poll_modified() or (os.clock() < time + 1)) do
- if input:seq_poll_modified() then
- if not input:seq_poll_valid() then
- manager:machine():popmessage(_("Invalid sequence entered"))
- clearmsg = false
- break
+local function handle_configure_menu(index, event)
+ 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
- manager:machine():popmessage(input:seq_name(input:seq_poll_sequence()))
- manager:machine():video():frame_update(true)
+ hotkey_poller = nil
+ return true
end
+ return false
end
- if clearmsg then
- manager:machine():popmessage()
- end
- return input:seq_poll_valid() and input:seq_poll_final() or nil
-end
-local function handle_configure_menu(index, event)
- -- Input
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
@@ -236,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)
@@ -276,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)
@@ -293,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)