mame/plugins/commonui/init.lua
Vas Crabb d4589e0b29 Input refactoring:
osd/modules/input, emu/inpttype.cpp: Made most default joystick
assignments supplied by input modules.  Input modules take available
controls into consideration when generating default assignments.

emu/inpttype.ipp: Added a separate "Back" UI input separate from Cancel.
You may want an easier to hit combination for moving to the previous
menu than for exiting or cancelling input.  They both default to Escape.

emu/inpttype.ipp: Added a UI Help control.  Currently only used by
analog inputs menu

emu/inpttype.h: Moved I/O port field type enum to its own header and
sorted UI controls so they appear in a more logical order.

ui: Don't use UI Select to restore defaults - people should be getting
used to the UI Clear input by now.  UI Select cycles multi-value items
instead.

ui/inputmap.cpp: Don't use immediate cancel to cycle between clearing
and restoring default assignment (use UI Clear instead).

osd: Reduced the number of files needing to include the dreaded emu.h.
Got some implementation out of headers.
2023-02-18 06:18:45 +11:00

217 lines
5.2 KiB
Lua

-- license:BSD-3-Clause
-- copyright-holders:Vas Crabb
local exports = {
name = 'commonui',
version = '0.0.1',
description = 'Common plugin UI helpers',
license = 'BSD-3-Clause',
author = { name = 'Vas Crabb' } }
local commonui = exports
function commonui.input_selection_menu(action, title, filter)
menu = { }
local choices
local index_first_choice
local index_cancel
local function populate_choices()
local ioport = manager.machine.ioport
local function compare(a, b)
if a.device.tag < b.device.tag then
return true
elseif a.device.tag > b.device.tag then
return false
end
groupa = ioport:type_group(a.type, a.player)
groupb = ioport:type_group(b.type, b.player)
if groupa < groupb then
return true
elseif groupa > groupb then
return false
elseif a.type < b.type then
return true
elseif a.type > b.type then
return false
else
return a.name < b.name
end
end
choices = { }
for tag, port in pairs(manager.machine.ioport.ports) do
for name, field in pairs(port.fields) do
if (not filter) or filter(field) then
table.insert(choices, field)
end
end
end
table.sort(choices, compare)
local index = 1
local prev
while index <= #choices do
local current = choices[index]
if (not prev) or (prev.device.tag ~= current.device.tag) then
table.insert(choices, index, false)
index = index + 2
else
index = index + 1
end
prev = current
end
end
function menu:populate(initial_selection)
if not choices then
populate_choices()
end
local items = { }
if title then
table.insert(items, { title, '', 'off' })
table.insert(items, { '---', '', '' })
end
index_first_choice = #items + 1
local selection = index_first_choice
for index, field in ipairs(choices) do
if field then
table.insert(items, { field.name, '', '' })
if initial_selection and (field.port.tag == initial_selection.port.tag) and (field.mask == initial_selection.mask) and (field.type == initial_selection.type) then
selection = #items
initial_selection = nil
end
else
local device = choices[index + 1].device
if device.owner then
table.insert(items, { string.format(_p('plugin-commonui', '%s [root%s]'), device.name, device.tag), '', 'heading' })
else
table.insert(items, { string.format(_p('plugin-commonui', '[root%s]'), device.tag), '', 'heading' })
end
end
end
table.insert(items, { '---', '', '' })
table.insert(items, { _p('plugin-commonui', 'Cancel'), '', '' })
index_cancel = #items
return items, selection
end
function menu:handle(index, event)
local selection
if (event == 'back') or ((index == input_item_cancel) and (event == 'select')) then
action(nil)
return true
elseif event == 'select' then
local field = choices[index - index_first_choice + 1]
if field then
action(field)
return true
end
elseif event == 'prevgroup' then
local found_break = false
while (index > index_first_choice) and (not selection) do
index = index - 1
if not choices[index - index_first_choice + 1] then
if found_break then
selection = index + 1
else
found_break = true
end
end
end
elseif event == 'nextgroup' then
while ((index - index_first_choice + 2) < #choices) and (not selection) do
index = index + 1
if not choices[index - index_first_choice + 1] then
selection = index + 1
end
end
end
return false, selection
end
return menu
end
function commonui.switch_polling_helper(starting_sequence)
helper = { }
local machine = manager.machine
local cancel = machine.ioport:token_to_input_type('UI_CANCEL')
local cancel_prompt = manager.ui:get_general_input_setting(cancel)
local input = machine.input
local uiinput = machine.uiinput
local poller = input:switch_sequence_poller()
local modified_ticks = 0
if starting_sequence then
poller:start(starting_sequence)
else
poller:start()
end
function helper:overlay(items, selection, flags)
if flags then
flags = flags .. " nokeys"
else
flags = "nokeys"
end
return items, selection, flags
end
function helper:poll()
-- prevent race condition between uiinput:pressed() and poll()
if (modified_ticks == 0) and poller.modified then
modified_ticks = emu.osd_ticks()
end
if uiinput:pressed(cancel) then
-- UI_CANCEL pressed, abort
machine:popmessage()
uiinput:reset()
if (not poller.modified) or (modified_ticks == emu.osd_ticks()) then
-- cancelled immediately
self.sequence = nil -- TODO: communicate this better?
return true
else
-- entered something before cancelling
self.sequence = nil
return true
end
elseif poller:poll() then
uiinput:reset()
if poller.valid then
-- valid sequence entered
machine:popmessage()
self.sequence = poller.sequence
return true
else
-- invalid sequence entered
machine:popmessage(_p('plugin-commonui', 'Invalid combination entered'))
self.sequence = nil
return true
end
else
machine:popmessage(string.format(
_p('plugin-commonui', 'Enter combination or press %s to cancel\n%s'),
cancel_prompt,
input:seq_name(poller.sequence)))
return false
end
end
return helper
end
return exports