summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/emu/emuopts.cpp4
-rw-r--r--src/emu/ui/menu.cpp37
-rw-r--r--src/emu/ui/miscmenu.cpp121
-rw-r--r--src/emu/ui/optsmenu.cpp10
-rw-r--r--src/emu/ui/optsmenu.h3
-rw-r--r--src/emu/ui/submenu.cpp304
-rw-r--r--src/emu/ui/submenu.h129
-rw-r--r--src/emu/ui/utils.cpp9
-rw-r--r--src/emu/ui/utils.h1
-rw-r--r--src/lib/util/options.h1
10 files changed, 482 insertions, 137 deletions
diff --git a/src/emu/emuopts.cpp b/src/emu/emuopts.cpp
index e05a16a5dd5..dfca2bde492 100644
--- a/src/emu/emuopts.cpp
+++ b/src/emu/emuopts.cpp
@@ -150,8 +150,8 @@ const options_entry emu_options::s_option_entries[] =
{ OPTION_UI_ACTIVE, "0", OPTION_BOOLEAN, "enable user interface on top of emulated keyboard (if present)" },
{ OPTION_OFFSCREEN_RELOAD ";reload", "0", OPTION_BOOLEAN, "convert lightgun button 2 into offscreen reload" },
{ OPTION_JOYSTICK_MAP ";joymap", "auto", OPTION_STRING, "explicit joystick map, or auto to auto-select" },
- { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz", "0.3", OPTION_FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" },
- { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat", "0.85", OPTION_FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" },
+ { OPTION_JOYSTICK_DEADZONE ";joy_deadzone;jdz(0.00-1)", "0.3", OPTION_FLOAT, "center deadzone range for joystick where change is ignored (0.0 center, 1.0 end)" },
+ { OPTION_JOYSTICK_SATURATION ";joy_saturation;jsat(0.00-1)", "0.85", OPTION_FLOAT, "end of axis saturation range for joystick where change is ignored (0.0 center, 1.0 end)" },
{ OPTION_NATURAL_KEYBOARD ";nat", "0", OPTION_BOOLEAN, "specifies whether to use a natural keyboard or not" },
{ OPTION_JOYSTICK_CONTRADICTORY ";joy_contradictory","0", OPTION_BOOLEAN, "enable contradictory direction digital joystick input at the same time" },
{ OPTION_COIN_IMPULSE, "0", OPTION_INTEGER, "set coin impulse time (n<0 disable impulse, n==0 obey driver, 0<n set time n)" },
diff --git a/src/emu/ui/menu.cpp b/src/emu/ui/menu.cpp
index 2af806fa586..3655ac76bc7 100644
--- a/src/emu/ui/menu.cpp
+++ b/src/emu/ui/menu.cpp
@@ -544,14 +544,25 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
if (!customonly)
machine().ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
- // determine the first visible line based on the current selection
- if (selected > top_line + visible_lines || selected < top_line - visible_lines)
- top_line = selected - (visible_lines / 2);
if (top_line < 0 || selected == 0)
top_line = 0;
- if (top_line + visible_lines >= item.size())
+ if (top_line > item.size() - visible_lines || selected == (item.size() - 1))
top_line = item.size() - visible_lines;
+ bool show_top_arrow = false;
+ bool show_bottom_arrow = false;
+
+ // if scrolling, show arrows
+ if (item.size() > visible_lines) {
+ if (top_line > 0)
+ show_top_arrow = true;
+ if (top_line != item.size() - visible_lines)
+ show_bottom_arrow = true;
+ }
+
+ // set the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
+ visitems = visible_lines - show_top_arrow - show_bottom_arrow;
+
// determine effective positions taking into account the hilighting arrows
float effective_width = visible_width - 2.0f * gutter_width;
float effective_left = visible_left + gutter_width;
@@ -573,6 +584,7 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
float line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
float line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
if (!customonly)
+ {
for (linenum = 0; linenum < visible_lines; linenum++)
{
float line_y = visible_top + (float)linenum * line_height;
@@ -613,7 +625,7 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor);
// if we're on the top line, display the up arrow
- if (linenum == 0 && top_line != 0)
+ if (linenum == 0 && show_top_arrow)
{
draw_arrow(container,
0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
@@ -627,7 +639,7 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
}
// if we're on the bottom line, display the down arrow
- else if (linenum == visible_lines - 1 && itemnum != item.size() - 1)
+ else if (linenum == visible_lines - 1 && show_bottom_arrow)
{
draw_arrow(container,
0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
@@ -708,6 +720,7 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
}
}
}
+ }
// if the selected subitem is too big, display it in a separate offset box
if (selected_subitem_too_big)
@@ -741,9 +754,6 @@ void ui_menu::draw(bool customonly, bool noimage, bool noinput)
// if there is something special to add, do it by calling the virtual method
custom_render((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
-
- // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
- visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != item.size());
}
void ui_menu::custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2)
@@ -989,7 +999,9 @@ void ui_menu::handle_keys(UINT32 flags)
}
(selected == 0) ? selected = top_line = item.size() - 1 : --selected;
validate_selection(-1);
- top_line -= (selected == top_line && top_line != 0);
+ top_line -= (selected <= top_line && top_line != 0);
+ if (selected <= top_line && visitems != visible_lines)
+ top_line--;
}
// down advances by one item
@@ -1001,7 +1013,10 @@ void ui_menu::handle_keys(UINT32 flags)
return;
}
(selected == item.size() - 1) ? selected = top_line = 0 : ++selected;
- top_line += (selected == top_line + visitems + (top_line != 0));
+ validate_selection(1);
+ top_line += (selected >= top_line + visitems + (top_line != 0));
+ if (selected >= (top_line + visitems + (top_line != 0)))
+ top_line++;
}
// page up backs up by visitems
diff --git a/src/emu/ui/miscmenu.cpp b/src/emu/ui/miscmenu.cpp
index edca54ebd20..69f36b6cfda 100644
--- a/src/emu/ui/miscmenu.cpp
+++ b/src/emu/ui/miscmenu.cpp
@@ -552,127 +552,6 @@ void ui_menu_quit_game::handle()
ui_menu::stack_reset(machine());
}
-ui_menu_misc_options::misc_option ui_menu_misc_options::m_options[] = {
- { 0, nullptr, nullptr },
- { 0, __("Re-select last machine played"), OPTION_REMEMBER_LAST },
- { 0, __("Enlarge images in the right panel"), OPTION_ENLARGE_SNAPS },
- { 0, __("DATs info"), OPTION_DATS_ENABLED },
- { 0, __("Cheats"), OPTION_CHEAT },
- { 0, __("Show mouse pointer"), OPTION_UI_MOUSE },
- { 0, __("Confirm quit from machines"), OPTION_CONFIRM_QUIT },
- { 0, __("Skip displaying information's screen at startup"), OPTION_SKIP_GAMEINFO },
- { 0, __("Force 4:3 appearance for software snapshot"), OPTION_FORCED4X3 },
- { 0, __("Use image as background"), OPTION_USE_BACKGROUND },
- { 0, __("Skip bios selection menu"), OPTION_SKIP_BIOS_MENU },
- { 0, __("Skip software parts selection menu"), OPTION_SKIP_PARTS_MENU }
-};
-
-//-------------------------------------------------
-// ctor / dtor
-//-------------------------------------------------
-
-ui_menu_misc_options::ui_menu_misc_options(running_machine &machine, render_container *container) : ui_menu(machine, container)
-{
- for (int d = 1; d < ARRAY_LENGTH(m_options); ++d)
- if (machine.ui().options().exists(m_options[d].option))
- m_options[d].status = machine.ui().options().bool_value(m_options[d].option);
- else
- m_options[d].status = machine.options().bool_value(m_options[d].option);
-}
-
-ui_menu_misc_options::~ui_menu_misc_options()
-{
- std::string error_string;
- for (int d = 1; d < ARRAY_LENGTH(m_options); ++d) {
- if (machine().ui().options().exists(m_options[d].option))
- {
- machine().ui().options().set_value(m_options[d].option, m_options[d].status, OPTION_PRIORITY_CMDLINE, error_string);
- }
- else
- {
- if (machine().options().bool_value(m_options[d].option) != m_options[d].status)
- {
- machine().options().set_value(m_options[d].option, m_options[d].status, OPTION_PRIORITY_CMDLINE, error_string);
- machine().options().mark_changed(m_options[d].option);
- }
- }
- }
- ui_globals::reset = true;
-}
-
-//-------------------------------------------------
-// handlethe options menu
-//-------------------------------------------------
-
-void ui_menu_misc_options::handle()
-{
- bool changed = false;
-
- // process the menu
- const ui_menu_event *m_event = process(0);
- if (m_event != nullptr && m_event->itemref != nullptr)
- {
- if (m_event->iptkey == IPT_UI_LEFT || m_event->iptkey == IPT_UI_RIGHT || m_event->iptkey == IPT_UI_SELECT)
- {
- changed = true;
- int value = (FPTR)m_event->itemref;
- if (!strcmp(m_options[value].option, OPTION_ENLARGE_SNAPS))
- ui_globals::switch_image = true;
- m_options[value].status = !m_options[value].status;
- }
- }
-
- if (changed)
- reset(UI_MENU_RESET_REMEMBER_REF);
-}
-
-//-------------------------------------------------
-// populate
-//-------------------------------------------------
-
-void ui_menu_misc_options::populate()
-{
- // add options items
- for (int opt = 1; opt < ARRAY_LENGTH(m_options); ++opt)
- item_append(_(m_options[opt].description), m_options[opt].status ? _("On") : _("Off"), m_options[opt].status ? MENU_FLAG_RIGHT_ARROW : MENU_FLAG_LEFT_ARROW, (void *)(FPTR)opt);
-
- item_append(MENU_SEPARATOR_ITEM, nullptr, 0, nullptr);
- customtop = machine().ui().get_line_height() + (3.0f * UI_BOX_TB_BORDER);
-}
-
-//-------------------------------------------------
-// perform our special rendering
-//-------------------------------------------------
-
-void ui_menu_misc_options::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
-{
- float width;
- ui_manager &mui = machine().ui();
-
- mui.draw_text_full(container, _("Miscellaneous Options"), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE,
- DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr);
- width += 2 * UI_BOX_LR_BORDER;
- float maxwidth = MAX(origx2 - origx1, width);
-
- // compute our bounds
- float x1 = 0.5f - 0.5f * maxwidth;
- float x2 = x1 + maxwidth;
- float y1 = origy1 - top;
- float y2 = origy1 - UI_BOX_TB_BORDER;
-
- // draw a box
- mui.draw_outlined_box(container, x1, y1, x2, y2, UI_GREEN_COLOR);
-
- // take off the borders
- x1 += UI_BOX_LR_BORDER;
- x2 -= UI_BOX_LR_BORDER;
- y1 += UI_BOX_TB_BORDER;
-
- // draw the text within it
- mui.draw_text_full(container, _("Miscellaneous Options"), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE,
- DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
-}
-
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
diff --git a/src/emu/ui/optsmenu.cpp b/src/emu/ui/optsmenu.cpp
index fef44b8e542..296427b42ac 100644
--- a/src/emu/ui/optsmenu.cpp
+++ b/src/emu/ui/optsmenu.cpp
@@ -11,6 +11,7 @@
#include "emu.h"
#include "ui/ui.h"
#include "ui/menu.h"
+#include "ui/submenu.h"
#include "ui/datfile.h"
#include "ui/inifile.h"
#include "ui/selector.h"
@@ -162,7 +163,7 @@ void ui_menu_game_options::handle()
break;
case MISC_MENU:
if (m_event->iptkey == IPT_UI_SELECT)
- ui_menu::stack_push(global_alloc_clear<ui_menu_misc_options>(machine(), container));
+ ui_menu::stack_push(global_alloc_clear<ui_submenu>(machine(), container, misc_submenu_options));
break;
case SOUND_MENU:
if (m_event->iptkey == IPT_UI_SELECT)
@@ -188,6 +189,10 @@ void ui_menu_game_options::handle()
if (m_event->iptkey == IPT_UI_SELECT)
ui_menu::stack_push(global_alloc_clear<ui_menu_custom_filter>(machine(), container));
break;
+ case ADVANCED_MENU:
+ if (m_event->iptkey == IPT_UI_SELECT)
+ ui_menu::stack_push(global_alloc_clear<ui_submenu>(machine(), container, advanced_submenu_options));
+ break;
case SAVE_CONFIG:
if (m_event->iptkey == IPT_UI_SELECT)
save_main_option(machine());
@@ -260,9 +265,10 @@ void ui_menu_game_options::populate()
}
item_append(_("Display Options"), nullptr, 0, (void *)(FPTR)DISPLAY_MENU);
item_append(_("Sound Options"), nullptr, 0, (void *)(FPTR)SOUND_MENU);
- item_append(_("Miscellaneous Options"), nullptr, 0, (void *)(FPTR)MISC_MENU);
+ item_append(misc_submenu_options[0].description, nullptr, 0, (void *)(FPTR)MISC_MENU);
item_append(_("Device Mapping"), nullptr, 0, (void *)(FPTR)CONTROLLER_MENU);
item_append(_("General Inputs"), nullptr, 0, (void *)(FPTR)CGI_MENU);
+ item_append(advanced_submenu_options[0].description, nullptr, 0, (void *)(FPTR)ADVANCED_MENU);
item_append(MENU_SEPARATOR_ITEM, nullptr, 0, nullptr);
item_append(_("Save Configuration"), nullptr, 0, (void *)(FPTR)SAVE_CONFIG);
diff --git a/src/emu/ui/optsmenu.h b/src/emu/ui/optsmenu.h
index 4dd2d0f53be..f6b4243afa0 100644
--- a/src/emu/ui/optsmenu.h
+++ b/src/emu/ui/optsmenu.h
@@ -33,11 +33,12 @@ private:
YEAR_CAT_FILTER,
CATEGORY_FILTER,
CONF_DIR,
- MISC_MENU,
DISPLAY_MENU,
CUSTOM_MENU,
SOUND_MENU,
CONTROLLER_MENU,
+ MISC_MENU,
+ ADVANCED_MENU,
SAVE_OPTIONS,
CGI_MENU,
CUSTOM_FILTER,
diff --git a/src/emu/ui/submenu.cpp b/src/emu/ui/submenu.cpp
new file mode 100644
index 00000000000..d1db35ad500
--- /dev/null
+++ b/src/emu/ui/submenu.cpp
@@ -0,0 +1,304 @@
+// license:BSD-3-Clause
+// copyright-holders:Maurizio Petrarota,Jeffrey Clark
+/***************************************************************************
+
+ ui/submenu.cpp
+
+ UI options menu
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ui/ui.h"
+#include "ui/submenu.h"
+#include "ui/utils.h"
+#include <limits>
+
+//-------------------------------------------------
+// ctor / dtor
+//-------------------------------------------------
+
+ui_submenu::ui_submenu(running_machine &machine, render_container *container, std::vector<ui_submenu::option> &suboptions)
+ : ui_menu(machine, container),
+ m_options(suboptions)
+{
+ for (auto & sm_option : m_options)
+ {
+ if (sm_option.type < ui_submenu::EMU)
+ continue;
+
+ // fixme use switch
+ sm_option.entry = machine.options().get_entry(sm_option.name);
+ if (sm_option.entry == nullptr)
+ {
+ sm_option.entry = machine.ui().options().get_entry(sm_option.name);
+ sm_option.options = dynamic_cast<core_options*>(&machine.ui().options());
+ }
+ else
+ {
+ sm_option.options = dynamic_cast<core_options*>(&machine.options());
+ }
+ }
+}
+
+ui_submenu::~ui_submenu()
+{
+}
+
+//-------------------------------------------------
+// handlethe options menu
+//-------------------------------------------------
+
+void ui_submenu::handle()
+{
+ bool changed = false;
+ std::string error_string, tmptxt;
+ int i_cur;
+ float f_cur, f_step;
+
+ // process the menu
+ const ui_menu_event *m_event = process(UI_MENU_PROCESS_LR_REPEAT);
+
+ if (m_event != nullptr && m_event->itemref != nullptr &&
+ (m_event->iptkey == IPT_UI_LEFT || m_event->iptkey == IPT_UI_RIGHT || m_event->iptkey == IPT_UI_SELECT))
+ {
+ ui_submenu::option *sm_option = (ui_submenu::option *)m_event->itemref;
+
+ switch (sm_option->type)
+ {
+ case ui_submenu::EMU:
+ case ui_submenu::UI:
+ case ui_submenu::OSD:
+ switch (sm_option->entry->type())
+ {
+ case OPTION_BOOLEAN:
+ changed = true;
+ sm_option->options->set_value(sm_option->name, !strcmp(sm_option->entry->value(),"1") ? "0" : "1", OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option->entry->mark_changed();
+ break;
+ case OPTION_INTEGER:
+ if (m_event->iptkey == IPT_UI_LEFT || m_event->iptkey == IPT_UI_RIGHT)
+ {
+ changed = true;
+ i_cur = atof(sm_option->entry->value());
+ (m_event->iptkey == IPT_UI_LEFT) ? i_cur-- : i_cur++;
+ sm_option->options->set_value(sm_option->name, i_cur, OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option->entry->mark_changed();
+ }
+ break;
+ case OPTION_FLOAT:
+ if (m_event->iptkey == IPT_UI_LEFT || m_event->iptkey == IPT_UI_RIGHT)
+ {
+ changed = true;
+ f_cur = atof(sm_option->entry->value());
+ if (sm_option->entry->has_range())
+ {
+ f_step = atof(sm_option->entry->minimum());
+ if (f_step <= 0.0f) {
+ int pmin = getprecisionchr(sm_option->entry->minimum());
+ int pmax = getprecisionchr(sm_option->entry->maximum());
+ tmptxt = '1' + std::string((pmin > pmax) ? pmin : pmax, '0');
+ f_step = 1 / atof(tmptxt.c_str());
+ }
+ }
+ else
+ {
+ int precision = getprecisionchr(sm_option->entry->default_value());
+ tmptxt = '1' + std::string(precision, '0');
+ f_step = 1 / atof(tmptxt.c_str());
+ }
+ if (m_event->iptkey == IPT_UI_LEFT)
+ f_cur -= f_step;
+ else
+ f_cur += f_step;
+ tmptxt = string_format("%g", f_cur);
+ sm_option->options->set_value(sm_option->name, tmptxt.c_str(), OPTION_PRIORITY_CMDLINE, error_string);
+ sm_option->entry->mark_changed();
+ }
+ break;
+ }
+ break;
+ default:
+ osd_printf_error("Unhandled option: %s", sm_option->description);
+ break;
+ }
+ }
+
+ if (changed)
+ reset(UI_MENU_RESET_REMEMBER_REF);
+}
+
+//-------------------------------------------------
+// populate
+//-------------------------------------------------
+
+void ui_submenu::populate()
+{
+ UINT32 arrow_flags;
+ std::string tmptxt;
+ float f_min, f_max, f_cur;
+ int i_min, i_max, i_cur;
+
+ // add options
+ for (auto sm_option = m_options.begin(); sm_option < m_options.end(); sm_option++)
+ {
+ // skip first heading (is menu title)
+ if (sm_option == m_options.begin() && sm_option->type == ui_submenu::HEAD) continue;
+
+ switch (sm_option->type)
+ {
+ case ui_submenu::HEAD:
+ item_append(sm_option->description, nullptr, MENU_FLAG_INVERT | MENU_FLAG_DISABLE, nullptr);
+ break;
+ case ui_submenu::SEP:
+ item_append(MENU_SEPARATOR_ITEM, nullptr, 0, nullptr);
+ break;
+ case ui_submenu::CMD:
+ item_append(sm_option->description, nullptr, 0, static_cast<void*>(&(*sm_option)));
+ break;
+ case ui_submenu::EMU:
+ case ui_submenu::UI:
+ case ui_submenu::OSD:
+ switch (sm_option->entry->type())
+ {
+ case OPTION_BOOLEAN:
+ arrow_flags = sm_option->options->bool_value(sm_option->name) ? MENU_FLAG_RIGHT_ARROW : MENU_FLAG_LEFT_ARROW;
+ item_append(sm_option->description,
+ (arrow_flags == MENU_FLAG_RIGHT_ARROW) ? "On" : "Off",
+ arrow_flags,
+ static_cast<void*>(&(*sm_option)));
+ break;
+ case OPTION_INTEGER:
+ i_cur = atof(sm_option->entry->value());
+ if (sm_option->entry->has_range())
+ {
+ i_min = atof(sm_option->entry->minimum());
+ i_max = atof(sm_option->entry->maximum());
+ }
+ else
+ {
+ i_min = std::numeric_limits<int>::min();
+ i_max = std::numeric_limits<int>::max();
+ }
+ arrow_flags = get_arrow_flags(i_min, i_max, i_cur);
+ item_append(sm_option->description,
+ sm_option->entry->value(),
+ arrow_flags,
+ static_cast<void*>(&(*sm_option)));
+ break;
+ case OPTION_FLOAT:
+ f_cur = atof(sm_option->entry->value());
+ if (sm_option->entry->has_range())
+ {
+ f_min = atof(sm_option->entry->minimum());
+ f_max = atof(sm_option->entry->maximum());
+ }
+ else
+ {
+ f_min = 0.0f;
+ f_max = std::numeric_limits<float>::max();
+ }
+ arrow_flags = get_arrow_flags(f_min, f_max, f_cur);
+ tmptxt = string_format("%g", f_cur);
+ item_append(sm_option->description,
+ tmptxt.c_str(),
+ arrow_flags,
+ static_cast<void*>(&(*sm_option)));
+ break;
+ default:
+ arrow_flags = MENU_FLAG_RIGHT_ARROW;
+ item_append(sm_option->description,
+ sm_option->options->value(sm_option->name),
+ arrow_flags, static_cast<void*>(&(*sm_option)));
+ break;
+ }
+ break;
+ default:
+ osd_printf_error("Unknown option type: %s", sm_option->description);
+ break;
+ }
+ }
+
+ item_append(MENU_SEPARATOR_ITEM, nullptr, 0, nullptr);
+ custombottom = customtop = machine().ui().get_line_height() + (3.0f * UI_BOX_TB_BORDER);
+}
+
+//-------------------------------------------------
+// perform our special rendering
+//-------------------------------------------------
+
+void ui_submenu::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
+{
+ static int interval = 0;
+ static ui_submenu::option *last_sm_option = nullptr;
+
+ float width;
+ ui_manager &mui = machine().ui();
+
+ mui.draw_text_full(container, m_options[0].description, 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr);
+ width += 2 * UI_BOX_LR_BORDER;
+ float maxwidth = MAX(origx2 - origx1, width);
+
+ // compute our bounds
+ float x1 = 0.5f - 0.5f * maxwidth;
+ float x2 = x1 + maxwidth;
+ float y1 = origy1 - top;
+ float y2 = origy1 - UI_BOX_TB_BORDER;
+
+ // draw a box
+ mui.draw_outlined_box(container, x1, y1, x2, y2, UI_GREEN_COLOR);
+
+ // take off the borders
+ x1 += UI_BOX_LR_BORDER;
+ x2 -= UI_BOX_LR_BORDER;
+ y1 += UI_BOX_TB_BORDER;
+
+ // draw the text within it
+ mui.draw_text_full(container, m_options[0].description, x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
+
+ if (selectedref != nullptr)
+ {
+ ui_submenu::option *selected_sm_option = (ui_submenu::option *)selectedref;
+
+ if (last_sm_option == selected_sm_option) {
+ if (interval <= 30) interval++;
+ } else {
+ last_sm_option = selected_sm_option;
+ interval = 0;
+ }
+
+ if (interval > 30 && last_sm_option->entry != nullptr)
+ {
+ mui.draw_text_full(container, last_sm_option->entry->description(), 0.0f, 0.0f, 1.0f, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &width, nullptr);
+
+ width += 2 * UI_BOX_LR_BORDER;
+ maxwidth = MAX(origx2 - origx1, width);
+
+ // compute our bounds
+ x1 = 0.5f - 0.5f * maxwidth;
+ x2 = x1 + maxwidth;
+ y1 = origy2 + UI_BOX_TB_BORDER;
+ y2 = origy2 + bottom;
+
+ // draw a box
+ mui.draw_outlined_box(container, x1, y1, x2, y2, UI_RED_COLOR);
+
+ // take off the borders
+ x1 += UI_BOX_LR_BORDER;
+ x2 -= UI_BOX_LR_BORDER;
+ y1 += UI_BOX_TB_BORDER;
+
+ // draw the text within it
+ mui.draw_text_full(container, last_sm_option->entry->description(), x1, y1, x2 - x1, JUSTIFY_CENTER, WRAP_NEVER,
+ DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
+ }
+ }
+ else
+ {
+ last_sm_option = nullptr;
+ interval = 0;
+ }
+}
diff --git a/src/emu/ui/submenu.h b/src/emu/ui/submenu.h
new file mode 100644
index 00000000000..cf658b50d4c
--- /dev/null
+++ b/src/emu/ui/submenu.h
@@ -0,0 +1,129 @@
+// license:BSD-3-Clause
+// copyright-holders:Maurizio Petrarota,Jeffrey Clark
+/***************************************************************************
+
+ ui/submenu.h
+
+ UI options menu.
+
+***************************************************************************/
+#pragma once
+
+#ifndef __UI_SUBMENU_H__
+#define __UI_SUBMENU_H__
+
+#include "ui/menu.h"
+
+//-------------------------------------------------
+// class ui menu
+//-------------------------------------------------
+class ui_submenu : public ui_menu
+{
+public:
+ enum option_type {
+ HEAD,
+ SEP,
+ MENU,
+ CMD,
+ EMU,
+ UI,
+ OSD,
+ };
+
+ struct option {
+ option_type type;
+ const char *description;
+ const char *name;
+ core_options::entry *entry;
+ core_options (*options);
+ };
+
+ ui_submenu(running_machine &machine, render_container *container, std::vector<ui_submenu::option> &suboptions);
+ virtual ~ui_submenu();
+ virtual void populate() override;
+ virtual void handle() override;
+ virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
+
+private:
+ std::vector<option> &m_options;
+};
+
+static std::vector<ui_submenu::option> misc_submenu_options = {
+ { ui_submenu::HEAD, _("Miscellaneous Options") },
+ { ui_submenu::UI, _("Re-select last machine played"), OPTION_REMEMBER_LAST },
+ { ui_submenu::UI, _("Enlarge images in the right panel"), OPTION_ENLARGE_SNAPS },
+ { ui_submenu::UI, _("DATs info"), OPTION_DATS_ENABLED },
+ { ui_submenu::EMU, _("Cheats"), OPTION_CHEAT },
+ { ui_submenu::EMU, _("Show mouse pointer"), OPTION_UI_MOUSE },
+ { ui_submenu::EMU, _("Confirm quit from machines"), OPTION_CONFIRM_QUIT },
+ { ui_submenu::EMU, _("Skip information screen at startup"), OPTION_SKIP_GAMEINFO },
+ { ui_submenu::UI, _("Force 4:3 aspect for snapshot display"), OPTION_FORCED4X3 },
+ { ui_submenu::UI, _("Use image as background"), OPTION_USE_BACKGROUND },
+ { ui_submenu::UI, _("Skip bios selection menu"), OPTION_SKIP_BIOS_MENU },
+ { ui_submenu::UI, _("Skip software parts selection menu"), OPTION_SKIP_PARTS_MENU },
+ { ui_submenu::UI, _("Info auto audit"), OPTION_INFO_AUTO_AUDIT },
+};
+
+static std::vector<ui_submenu::option> advanced_submenu_options = {
+ { ui_submenu::HEAD, _("Advanced Options") },
+ { ui_submenu::HEAD, _("Performance Options") },
+ { ui_submenu::EMU, _("Auto frame skip"), OPTION_AUTOFRAMESKIP },
+ { ui_submenu::EMU, _("Frame skip"), OPTION_FRAMESKIP },
+ { ui_submenu::EMU, _("Throttle"), OPTION_THROTTLE },
+ { ui_submenu::EMU, _("Sleep"), OPTION_SLEEP },
+ { ui_submenu::EMU, _("Speed"), OPTION_SPEED },
+ { ui_submenu::EMU, _("Refresh speed"), OPTION_REFRESHSPEED },
+//};
+
+//static std::vector<ui_submenu::option> rotate_submenu_options = {
+ { ui_submenu::HEAD, _("Rotation Options") },
+ { ui_submenu::EMU, _("Rotate"), OPTION_ROTATE },
+ { ui_submenu::EMU, _("Rotate right"), OPTION_ROR },
+ { ui_submenu::EMU, _("Rotate left"), OPTION_ROL },
+ { ui_submenu::EMU, _("Auto rotate right"), OPTION_AUTOROR },
+ { ui_submenu::EMU, _("Auto rotate left"), OPTION_AUTOROL },
+ { ui_submenu::EMU, _("Flip X"), OPTION_FLIPX },
+ { ui_submenu::EMU, _("Flip Y"), OPTION_FLIPY },
+//};
+
+//static std::vector<ui_submenu::option> artwork_submenu_options = {
+ { ui_submenu::HEAD, _("Artwork Options") },
+ { ui_submenu::EMU, _("Artwork Crop"), OPTION_ARTWORK_CROP },
+ { ui_submenu::EMU, _("Use Backdrops"), OPTION_USE_BACKDROPS },
+ { ui_submenu::EMU, _("Use Overlays"), OPTION_USE_OVERLAYS },
+ { ui_submenu::EMU, _("Use Bezels"), OPTION_USE_BEZELS },
+ { ui_submenu::EMU, _("Use Control Panels"), OPTION_USE_CPANELS },
+ { ui_submenu::EMU, _("Use Marquees"), OPTION_USE_MARQUEES },
+//};
+
+//static std::vector<ui_submenu::option> state_submenu_options = {
+ { ui_submenu::HEAD, _("State/Playback Options") },
+ { ui_submenu::EMU, _("Automatic save/restore"), OPTION_AUTOSAVE },
+ { ui_submenu::EMU, _("Bilinear snapshot"), OPTION_SNAPBILINEAR },
+ { ui_submenu::EMU, _("Burn-in"), OPTION_BURNIN },
+//};
+
+//static std::vector<ui_submenu::option> input_submenu_options = {
+ { ui_submenu::HEAD, _("Input Options") },
+ { ui_submenu::EMU, _("Coin lockout"), OPTION_COIN_LOCKOUT },
+ { ui_submenu::EMU, _("Mouse"), OPTION_MOUSE },
+ { ui_submenu::EMU, _("Joystick"), OPTION_JOYSTICK },
+ { ui_submenu::EMU, _("Lightgun"), OPTION_LIGHTGUN },
+ { ui_submenu::EMU, _("Multi-keyboard"), OPTION_MULTIKEYBOARD },
+ { ui_submenu::EMU, _("Multi-mouse"), OPTION_MULTIMOUSE },
+ { ui_submenu::EMU, _("Steadykey"), OPTION_STEADYKEY },
+ { ui_submenu::EMU, _("UI active"), OPTION_UI_ACTIVE },
+ { ui_submenu::EMU, _("Offscreen reload"), OPTION_OFFSCREEN_RELOAD },
+ { ui_submenu::EMU, _("Joystick deadzone"), OPTION_JOYSTICK_DEADZONE },
+ { ui_submenu::EMU, _("Joystick saturation"), OPTION_JOYSTICK_SATURATION },
+ { ui_submenu::EMU, _("Natural keyboard"), OPTION_NATURAL_KEYBOARD },
+ { ui_submenu::EMU, _("Simultaneous contradictory"), OPTION_JOYSTICK_CONTRADICTORY },
+ { ui_submenu::EMU, _("Coin impulse"), OPTION_COIN_IMPULSE },
+};
+
+//static std::vector<ui_submenu::option> export_submenu_options = {
+// { ui_submenu::COMMAND, _("Export XML format (like -listxml)"), "exportxml" },
+// { ui_submenu::COMMAND, _("Export TXT format (like -listfull)"), "exporttxt" },
+//};
+
+#endif /* __UI_SUBMENU_H__ */
diff --git a/src/emu/ui/utils.cpp b/src/emu/ui/utils.cpp
index 1e998d04c9d..6a59208cd30 100644
--- a/src/emu/ui/utils.cpp
+++ b/src/emu/ui/utils.cpp
@@ -84,6 +84,15 @@ const char* strensure(const char* s)
return s == nullptr ? "" : s;
}
+int getprecisionchr(const char* s)
+{
+ int precision = 1;
+ char *dp = const_cast<char *>(strchr(s, '.'));
+ if (dp != nullptr)
+ precision = strlen(s) - (dp - s) - 1;
+ return precision;
+}
+
//-------------------------------------------------
// search a substring with even partial matching
//-------------------------------------------------
diff --git a/src/emu/ui/utils.h b/src/emu/ui/utils.h
index 81107c0911c..519f74e667b 100644
--- a/src/emu/ui/utils.h
+++ b/src/emu/ui/utils.h
@@ -254,5 +254,6 @@ char* chartrimcarriage(char str[]);
const char* strensure(const char* s);
+int getprecisionchr(const char* s);
#endif /* __UI_UTILS_H__ */
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
index 9af9c61233e..a6c003162fd 100644
--- a/src/lib/util/options.h
+++ b/src/lib/util/options.h
@@ -131,6 +131,7 @@ public:
// getters
entry *first() const { return m_entrylist.first(); }
const char *command() const { return m_command.c_str(); }
+ entry *get_entry(const char *option) { return (m_entrymap.find(option) != m_entrymap.end()) ? m_entrymap.find(option)->second : nullptr; }
// range iterators
using auto_iterator = simple_list<entry>::auto_iterator;