frontend: Beter provision for plugins with multiple menu levels.

Make it possible for a plugin to specify which item should be selected
on repopulate.  Also allowed plugins to specify the UI heading flag for
menu items.

Updated input macro plugin to select sane items when changing menus.
Other plugins not updated yet, but may be at some point in the future.
This commit is contained in:
Vas Crabb 2021-10-21 07:44:34 +11:00
parent a0be1bfba9
commit 3891d42471
5 changed files with 77 additions and 26 deletions

View file

@ -8,6 +8,8 @@ local MENU_TYPES = { MACROS = 0, ADD = 1, EDIT = 2, INPUT = 3 }
local macros
local menu_stack
local macros_start_macro -- really for the macros menu, but has to be declared local before edit menu functions
-- Helpers
@ -46,6 +48,7 @@ end
-- Input menu
local input_action
local input_start_field
local input_choices
local input_item_first_choice
local input_item_cancel
@ -119,21 +122,29 @@ function populate_input()
end
input_item_first_choice = #items + 1
local selection = input_item_first_choice
for index, field in ipairs(input_choices) do
items[#items + 1] = { _p('input-name', field.name), '', '' }
if input_start_field and (field.port.tag == input_start_field.port.tag) and (field.mask == input_start_field.mask) and (field.type == input_start_field.type) then
selection = #items
input_start_field = nil
end
end
input_start_field = nil
items[#items + 1] = { '---', '', '' }
items[#items + 1] = { _p('plugin-inputmacro', 'Cancel'), '', '' }
input_item_cancel = #items
return items
return items, selection
end
-- Add/edit menus
local edit_current_macro
local edit_start_selection
local edit_start_step
local edit_insert_position
local edit_name_buffer
local edit_items
@ -287,6 +298,8 @@ local function handle_edit_items(index, event)
inputs[command.input].port = field.port
inputs[command.input].field = field
end
input_start_field = inputs[command.input].field
edit_start_selection = index
table.insert(menu_stack, MENU_TYPES.INPUT)
return true
elseif event == 'clear' then
@ -304,6 +317,7 @@ local function handle_edit_items(index, event)
port = field.port,
field = field }
end
edit_start_selection = index
table.insert(menu_stack, MENU_TYPES.INPUT)
return true
end
@ -318,6 +332,10 @@ local function handle_edit_items(index, event)
if edit_insert_position > command.step then
edit_insert_position = edit_insert_position - 1
end
edit_start_step = command.step
if edit_start_step > #edit_current_macro.steps then
edit_start_step = edit_start_step - 1
end
return true
end
elseif command.action == 'addstep' then
@ -336,8 +354,10 @@ local function handle_edit_items(index, event)
if edit_current_macro.loop >= edit_insert_position then
edit_current_macro.loop = edit_current_macro.loop + 1
end
edit_start_step = edit_insert_position
edit_insert_position = edit_insert_position + 1
end
edit_start_selection = index
table.insert(menu_stack, MENU_TYPES.INPUT)
return true
elseif event == 'left' then
@ -386,11 +406,12 @@ local function add_edit_items(items)
edit_items[#items] = { action = 'holdaction' }
for i, step in ipairs(edit_current_macro.steps) do
items[#items + 1] = { '---', '', '' }
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'off' }
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Step %d'), i), '', 'heading' }
items[#items + 1] = { _p('plugin-inputmacro', 'Delay (frames)'), step.delay, (step.delay > 0) and 'lr' or 'r' }
edit_items[#items] = { action = 'delay', step = i }
if edit_start_step == i then
edit_start_selection = #items
end
items[#items + 1] = { _p('plugin-inputmacro', 'Duration (frames)'), step.duration, (step.duration > 1) and 'lr' or 'r' }
edit_items[#items] = { action = 'duration', step = i }
@ -411,6 +432,7 @@ local function add_edit_items(items)
edit_items[#items] = { action = 'deletestep', step = i }
end
end
edit_start_step = nil
local laststep = edit_current_macro.steps[#edit_current_macro.steps]
if laststep.inputs[#laststep.inputs].field then
@ -438,6 +460,7 @@ local function handle_add(index, event)
elseif (index == edit_item_exit) and (event == 'select') then
if current_macro_complete() then
table.insert(macros, edit_current_macro)
macros_start_macro = #macros
end
edit_current_macro = nil
edit_items = nil
@ -475,7 +498,9 @@ local function populate_add()
end
edit_item_exit = #items
return items
local selection = edit_start_selection
edit_start_selection = nil
return items, selection
end
local function populate_edit()
@ -490,13 +515,16 @@ local function populate_edit()
items[#items + 1] = { _p('plugin-inputmacro', 'Done'), '', '' }
edit_item_exit = #items
return items
local selection = edit_start_selection
edit_start_selection = nil
return items, selection
end
-- Macros menu
local macros_item_first_macro
local macros_selection_save
local macros_item_add
function handle_macros(index, event)
@ -504,6 +532,8 @@ function handle_macros(index, event)
if event == 'select' then
edit_current_macro = new_macro()
edit_insert_position = #edit_current_macro.steps + 1
edit_start_selection = 1 -- not actually selectable, but it will take the first item
macros_selection_save = index
table.insert(menu_stack, MENU_TYPES.ADD)
return true
end
@ -512,10 +542,17 @@ function handle_macros(index, event)
if event == 'select' then
edit_current_macro = macros[macro]
edit_insert_position = #edit_current_macro.steps + 1
macros_selection_save = index
table.insert(menu_stack, MENU_TYPES.EDIT)
return true
elseif event == 'clear' then
table.remove(macros, macro)
if #macros > 0 then
macros_selection_save = index
if macro > #macros then
macros_selection_save = macros_selection_save - 1
end
end
return true
end
end
@ -535,16 +572,22 @@ function populate_macros()
if #macros > 0 then
for index, macro in ipairs(macros) do
items[#items + 1] = { macro.name, input:seq_name(macro.binding), '' }
if macros_start_macro == index then
macros_selection_save = #items
end
end
else
items[#items + 1] = { _p('plugin-inputmacro', 'No macros'), '', 'off' }
end
macros_start_macro = nil
items[#items + 1] = { '---', '', '' }
items[#items + 1] = { _p('plugin-inputmacro', 'Add macro'), '', '' }
macros_item_add = #items
return items
local selection = macros_selection_save
macros_selection_save = nil
return items, selection
end

View file

@ -432,31 +432,33 @@ sol::object lua_engine::call_plugin(const std::string &name, sol::object in)
return sol::lua_nil;
}
void lua_engine::menu_populate(const std::string &menu, std::vector<std::tuple<std::string, std::string, std::string>> &menu_list)
std::optional<long> lua_engine::menu_populate(const std::string &menu, std::vector<std::tuple<std::string, std::string, std::string>> &menu_list)
{
std::string field = "menu_pop_" + menu;
sol::object obj = sol().registry()[field];
if(obj.is<sol::protected_function>())
if (obj.is<sol::protected_function>())
{
auto res = invoke(obj.as<sol::protected_function>());
if(!res.valid())
if (!res.valid())
{
sol::error err = res;
osd_printf_error("[LUA ERROR] in menu_populate: %s\n", err.what());
}
else
{
sol::table table = res;
for(auto &entry : table)
std::tuple<sol::table, std::optional<long> > table = res;
for (auto &entry : std::get<0>(table))
{
if(entry.second.is<sol::table>())
if (entry.second.is<sol::table>())
{
sol::table enttable = entry.second.as<sol::table>();
menu_list.emplace_back(enttable.get<std::string, std::string, std::string>(1, 2, 3));
}
}
return std::get<1>(table);
}
}
return std::nullopt;
}
bool lua_engine::menu_callback(const std::string &menu, int index, const std::string &event)

View file

@ -16,13 +16,11 @@
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#if defined(__GNUC__) && (__GNUC__ > 6)
#pragma GCC diagnostic ignored "-Wnoexcept-type"
#endif
#define SOL_SAFE_USERTYPE 1
#include "sol/sol.hpp"
@ -50,7 +48,7 @@ public:
bool frame_hook();
void menu_populate(const std::string &menu, std::vector<std::tuple<std::string, std::string, std::string>> &menu_list);
std::optional<long> menu_populate(const std::string &menu, std::vector<std::tuple<std::string, std::string, std::string>> &menu_list);
bool menu_callback(const std::string &menu, int index, const std::string &event);
void set_machine(running_machine *machine);

View file

@ -481,9 +481,9 @@ void menu_input::populate_sorted(float &customtop, float &custombottom)
else
item_append(menu_item_type::SEPARATOR);
if (item.owner->owner())
item_append(string_format(_("%1$s [root%2$s]"), item.owner->type().fullname(), item.owner->tag()), 0, nullptr);
item_append(string_format(_("%1$s [root%2$s]"), item.owner->type().fullname(), item.owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
else
item_append(string_format(_("[root%1$s]"), item.owner->tag()), 0, nullptr);
item_append(string_format(_("[root%1$s]"), item.owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
prev_owner = item.owner;
}

View file

@ -117,7 +117,8 @@ void menu_plugin_opt::handle()
void menu_plugin_opt::populate(float &customtop, float &custombottom)
{
std::vector<std::tuple<std::string, std::string, std::string>> menu_list;
mame_machine_manager::instance()->lua()->menu_populate(m_menu, menu_list);
auto const sel = mame_machine_manager::instance()->lua()->menu_populate(m_menu, menu_list);
uintptr_t i = 1;
for(auto &item : menu_list)
{
@ -126,13 +127,15 @@ void menu_plugin_opt::populate(float &customtop, float &custombottom)
const std::string &tflags = std::get<2>(item);
uint32_t flags = 0;
if(tflags == "off")
if (tflags == "off")
flags = FLAG_DISABLE;
else if(tflags == "l")
else if (tflags == "heading")
flags = FLAG_DISABLE | FLAG_UI_HEADING;
else if (tflags == "l")
flags = FLAG_LEFT_ARROW;
else if(tflags == "r")
else if (tflags == "r")
flags = FLAG_RIGHT_ARROW;
else if(tflags == "lr")
else if (tflags == "lr")
flags = FLAG_RIGHT_ARROW | FLAG_LEFT_ARROW;
if(text == "---")
@ -141,9 +144,14 @@ void menu_plugin_opt::populate(float &customtop, float &custombottom)
i++;
}
else
item_append(text, subtext, flags, (void *)i++);
{
item_append(text, subtext, flags, reinterpret_cast<void *>(i++));
}
}
item_append(menu_item_type::SEPARATOR);
if (sel)
set_selection(reinterpret_cast<void *>(uintptr_t(*sel)));
}
menu_plugin_opt::~menu_plugin_opt()