summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-11-06 13:52:48 +1100
committer Vas Crabb <vas@vastheman.com>2021-11-06 13:52:48 +1100
commit270276c4d30721dc397de6d8c92334469ce37243 (patch)
tree99e802773ecec08ade94f574fdca3d665d726901 /src/frontend
parent07e55935cf49c94a94dcc75d8240d0733d1ed5d7 (diff)
-Enabled complex combinations for analog axes:
* Made it possible to add digital controls to axis settings as enables. * Mix multiple analog controls assigned to an axis setting. * Added a "reverse" modifier for analog controls (useful with mixing). * Fixed an issue assigning mouse axes using multiple mouse-like devices with -nomultimouse. -frontend: More cleanup: * Got rid of some abuse of "special main menus". * Added a helper class for auto-pause menus that don't spawn submenus. * Got rid of the fake menu that schedules an exit on the first frame. * Turned the confirm quit prompt into a menu, eliminated one more special-cased event loop. * Fixed the confirm quit prompt resuming if you return to emulation if you weren't paused to begin with. -bus/centronics: Fixed conflicting DIP locations, reversed order and inverted polarity for Epson printers. * Also added the LX-810 (without L suffix) DIP switches for reference - we don't have a device for this printer yet.
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/mame/iptseqpoll.cpp164
-rw-r--r--src/frontend/mame/iptseqpoll.h22
-rw-r--r--src/frontend/mame/ui/confswitch.cpp53
-rw-r--r--src/frontend/mame/ui/filemngr.cpp35
-rw-r--r--src/frontend/mame/ui/filemngr.h3
-rw-r--r--src/frontend/mame/ui/filesel.cpp1
-rw-r--r--src/frontend/mame/ui/imgcntrl.cpp2
-rw-r--r--src/frontend/mame/ui/menu.cpp38
-rw-r--r--src/frontend/mame/ui/menu.h40
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp26
-rw-r--r--src/frontend/mame/ui/miscmenu.h13
-rw-r--r--src/frontend/mame/ui/quitmenu.cpp61
-rw-r--r--src/frontend/mame/ui/quitmenu.h36
-rw-r--r--src/frontend/mame/ui/selgame.cpp11
-rw-r--r--src/frontend/mame/ui/selmenu.cpp4
-rw-r--r--src/frontend/mame/ui/simpleselgame.cpp10
-rw-r--r--src/frontend/mame/ui/sliders.h2
-rw-r--r--src/frontend/mame/ui/state.cpp20
-rw-r--r--src/frontend/mame/ui/state.h4
-rw-r--r--src/frontend/mame/ui/swlist.cpp1
-rw-r--r--src/frontend/mame/ui/ui.cpp47
-rw-r--r--src/frontend/mame/ui/ui.h2
22 files changed, 370 insertions, 225 deletions
diff --git a/src/frontend/mame/iptseqpoll.cpp b/src/frontend/mame/iptseqpoll.cpp
index 639295f7e02..9c4782f4c54 100644
--- a/src/frontend/mame/iptseqpoll.cpp
+++ b/src/frontend/mame/iptseqpoll.cpp
@@ -12,7 +12,8 @@
input_code_poller::input_code_poller(input_manager &manager) noexcept :
m_manager(manager),
- m_axis_memory()
+ m_axis_memory(),
+ m_switch_memory()
{
}
@@ -26,6 +27,7 @@ void input_code_poller::reset()
{
// iterate over device classes and devices
m_axis_memory.clear();
+ m_switch_memory.clear();
for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
input_class &devclass(m_manager.device_class(classno));
@@ -53,22 +55,7 @@ void input_code_poller::reset()
}
-
-switch_code_poller_base::switch_code_poller_base(input_manager &manager) noexcept :
- input_code_poller(manager),
- m_switch_memory()
-{
-}
-
-
-void switch_code_poller_base::reset()
-{
- m_switch_memory.clear();
- input_code_poller::reset();
-}
-
-
-bool switch_code_poller_base::code_pressed_once(input_code code, bool moved)
+bool input_code_poller::code_pressed_once(input_code code, bool moved)
{
// look for the code in the memory
bool const pressed(m_manager.code_pressed(code));
@@ -105,14 +92,50 @@ input_code axis_code_poller::poll()
// iterate over the axis items we found
for (auto memory = m_axis_memory.begin(); m_axis_memory.end() != memory; ++memory)
{
- input_code const code = memory->first->code();
+ input_code code = memory->first->code();
if (memory->first->check_axis(code.item_modifier(), memory->second))
{
m_axis_memory.erase(memory);
+ if (!m_manager.device_class(memory->first->device().devclass()).multi())
+ code.set_device_index(0);
return code;
}
}
+ // iterate over device classes and devices, skipping disabled classes
+ for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
+ {
+ input_class &devclass(m_manager.device_class(classno));
+ if (!devclass.enabled())
+ continue;
+
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ {
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (!device)
+ continue;
+
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ input_device_item *const item(device->item(itemid));
+ if (!item)
+ continue;
+
+ input_code code = item->code();
+ if (item->itemclass() == ITEM_CLASS_SWITCH)
+ {
+ // item is natively a switch, poll it
+ if (code_pressed_once(code, true))
+ return code;
+ else
+ continue;
+ }
+ }
+ }
+ }
+
// if nothing, return an invalid code
return INPUT_CODE_INVALID;
}
@@ -120,7 +143,7 @@ input_code axis_code_poller::poll()
switch_code_poller::switch_code_poller(input_manager &manager) noexcept :
- switch_code_poller_base(manager)
+ input_code_poller(manager)
{
}
@@ -210,7 +233,7 @@ input_code switch_code_poller::poll()
keyboard_code_poller::keyboard_code_poller(input_manager &manager) noexcept :
- switch_code_poller_base(manager)
+ input_code_poller(manager)
{
}
@@ -336,42 +359,93 @@ input_code axis_sequence_poller::do_poll()
lastcode = m_sequence[curlen - 2];
input_code newcode = m_code_poller.poll();
- // if the last code doesn't match absolute/relative of this code, ignore the new one
- input_item_class const lastclass = lastcode.item_class();
- input_item_class const newclass = newcode.item_class();
- if (((ITEM_CLASS_ABSOLUTE == lastclass) && (ITEM_CLASS_ABSOLUTE != newclass)) ||
- ((ITEM_CLASS_RELATIVE == lastclass) && (ITEM_CLASS_RELATIVE != newclass)))
- newcode = INPUT_CODE_INVALID;
-
- // if the new code is valid, check for half-axis toggles on absolute controls
- if ((INPUT_CODE_INVALID != newcode) && curlen && (ITEM_CLASS_ABSOLUTE == newclass))
+ // if not empty, see if it's the same control again to cycle modifiers
+ if ((INPUT_CODE_INVALID != newcode) && curlen)
{
+ input_item_class const newclass = newcode.item_class();
input_code last_nomodifier = lastcode;
last_nomodifier.set_item_modifier(ITEM_MODIFIER_NONE);
if (newcode == last_nomodifier)
{
- // increment the modifier, wrapping back to none
- switch (lastcode.item_modifier())
+ if (ITEM_CLASS_ABSOLUTE == newclass)
{
- case ITEM_MODIFIER_NONE:
- newcode.set_item_modifier(ITEM_MODIFIER_POS);
- break;
- case ITEM_MODIFIER_POS:
- newcode.set_item_modifier(ITEM_MODIFIER_NEG);
- break;
- default:
- case ITEM_MODIFIER_NEG:
- newcode.set_item_modifier(ITEM_MODIFIER_NONE);
- break;
+ // increment the modifier, wrapping back to none
+ switch (lastcode.item_modifier())
+ {
+ case ITEM_MODIFIER_NONE:
+ newcode.set_item_modifier(ITEM_MODIFIER_POS);
+ break;
+ case ITEM_MODIFIER_POS:
+ newcode.set_item_modifier(ITEM_MODIFIER_NEG);
+ break;
+ case ITEM_MODIFIER_NEG:
+ newcode.set_item_modifier(ITEM_MODIFIER_REVERSE);
+ break;
+ default:
+ case ITEM_MODIFIER_REVERSE:
+ newcode.set_item_modifier(ITEM_MODIFIER_NONE);
+ break;
+ }
+
+ // back up over the previous code so we can re-append
+ if (has_or)
+ m_sequence.backspace();
+ m_sequence.backspace();
+ }
+ else if (ITEM_CLASS_RELATIVE == newclass)
+ {
+ // increment the modifier, wrapping back to none
+ switch (lastcode.item_modifier())
+ {
+ case ITEM_MODIFIER_NONE:
+ newcode.set_item_modifier(ITEM_MODIFIER_REVERSE);
+ break;
+ default:
+ case ITEM_MODIFIER_REVERSE:
+ newcode.set_item_modifier(ITEM_MODIFIER_NONE);
+ break;
+ }
+
+ // back up over the previous code so we can re-append
+ if (has_or)
+ m_sequence.backspace();
+ m_sequence.backspace();
}
+ else if (!has_or && (ITEM_CLASS_SWITCH == newclass))
+ {
+ // back up over the existing code
+ m_sequence.backspace();
- // back up over the previous code so we can re-append
- if (has_or)
+ // if there was a NOT preceding it, delete it as well, otherwise append a fresh one
+ if (m_sequence[curlen - 2] == input_seq::not_code)
+ m_sequence.backspace();
+ else
+ m_sequence += input_seq::not_code;
+ }
+ }
+ else if (!has_or && (ITEM_CLASS_SWITCH == newclass))
+ {
+ // ignore switches following axes
+ if (ITEM_CLASS_SWITCH != lastcode.item_class())
+ {
+ // hack to stop it timing out so user can cancel
m_sequence.backspace();
- m_sequence.backspace();
+ newcode = lastcode;
+ }
}
}
- return newcode;
+
+ // hack to stop it timing out before assigning an axis
+ if (ITEM_CLASS_SWITCH == newcode.item_class())
+ {
+ m_sequence += newcode;
+ set_modified();
+ return INPUT_CODE_INVALID;
+ }
+ else
+ {
+ return newcode;
+ }
}
diff --git a/src/frontend/mame/iptseqpoll.h b/src/frontend/mame/iptseqpoll.h
index b9f31f70477..b33eeebf292 100644
--- a/src/frontend/mame/iptseqpoll.h
+++ b/src/frontend/mame/iptseqpoll.h
@@ -27,22 +27,10 @@ public:
protected:
input_code_poller(input_manager &manager) noexcept;
- input_manager &m_manager;
- std::vector<std::pair<input_device_item *, s32> > m_axis_memory;
-};
-
-
-class switch_code_poller_base : public input_code_poller
-{
-public:
- virtual void reset() override;
-
-protected:
- switch_code_poller_base(input_manager &manager) noexcept;
-
bool code_pressed_once(input_code code, bool moved);
-private:
+ input_manager &m_manager;
+ std::vector<std::pair<input_device_item *, s32> > m_axis_memory;
std::vector<input_code> m_switch_memory;
};
@@ -56,7 +44,7 @@ public:
};
-class switch_code_poller : public switch_code_poller_base
+class switch_code_poller : public input_code_poller
{
public:
switch_code_poller(input_manager &manager) noexcept;
@@ -65,7 +53,7 @@ public:
};
-class keyboard_code_poller : public switch_code_poller_base
+class keyboard_code_poller : public input_code_poller
{
public:
keyboard_code_poller(input_manager &manager) noexcept;
@@ -90,6 +78,8 @@ public:
protected:
input_sequence_poller() noexcept;
+ void set_modified() noexcept { m_modified = true; }
+
input_seq m_sequence;
private:
diff --git a/src/frontend/mame/ui/confswitch.cpp b/src/frontend/mame/ui/confswitch.cpp
index 3aa10cd9133..1e89cb48d58 100644
--- a/src/frontend/mame/ui/confswitch.cpp
+++ b/src/frontend/mame/ui/confswitch.cpp
@@ -102,7 +102,6 @@ void menu_confswitch::populate(float &customtop, float &custombottom)
// loop over input ports and set up the current values
device_t *prev_owner(nullptr);
- bool first_entry(true);
for (field_descriptor &desc : m_fields)
{
ioport_field &field(desc.field);
@@ -114,11 +113,10 @@ void menu_confswitch::populate(float &customtop, float &custombottom)
if (&field.device() != prev_owner)
{
prev_owner = &field.device();
- if (first_entry)
- first_entry = false;
+ if (prev_owner->owner())
+ item_append(string_format(_("%1$s [root%2$s]"), prev_owner->type().fullname(), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
else
- item_append(menu_item_type::SEPARATOR);
- item_append(string_format("[root%s]", prev_owner->tag()), 0, nullptr);
+ item_append(string_format(_("[root%1$s]"), prev_owner->tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
}
// set the left/right flags appropriately
@@ -214,6 +212,51 @@ void menu_confswitch::handle(event const *ev)
field.select_next_setting();
changed = true;
break;
+
+ // trick to get previous group - depend on headings having null reference
+ case IPT_UI_PREV_GROUP:
+ {
+ auto current = selected_index();
+ bool found_break = false;
+ while (0 < current)
+ {
+ if (!found_break)
+ {
+ if (!item(--current).ref)
+ found_break = true;
+ }
+ else if (!item(current - 1).ref)
+ {
+ set_selected_index(current);
+ set_top_line(current - 1);
+ break;
+ }
+ else
+ {
+ --current;
+ }
+ }
+ }
+ break;
+
+ // trick to get next group - depend on special item references
+ case IPT_UI_NEXT_GROUP:
+ {
+ auto current = selected_index();
+ while (item_count() > ++current)
+ {
+ if (!item(current).ref)
+ {
+ if ((item_count() > (current + 1)) && (uintptr_t(item(current + 1).ref) != 1))
+ {
+ set_selected_index(current + 1);
+ set_top_line(current);
+ }
+ break;
+ }
+ }
+ }
+ break;
}
// if anything changed, rebuild the menu, trying to stay on the same field
diff --git a/src/frontend/mame/ui/filemngr.cpp b/src/frontend/mame/ui/filemngr.cpp
index 029950865d4..06c2d822b1e 100644
--- a/src/frontend/mame/ui/filemngr.cpp
+++ b/src/frontend/mame/ui/filemngr.cpp
@@ -33,16 +33,13 @@ namespace ui {
// ctor
//-------------------------------------------------
-menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings) : menu(mui, container), selected_device(nullptr)
+menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings)
+ : menu(mui, container)
+ , selected_device(nullptr)
+ , m_warnings(warnings ? warnings : "")
{
- // This warning string is used when accessing from the force_file_manager call, i.e.
+ // The warning string is used when accessing from the force_file_manager call, i.e.
// when the file manager is loaded top front in the case of mandatory image devices
- if (warnings)
- m_warnings.assign(warnings);
- else
- m_warnings.clear();
-
- m_curr_selected = false;
}
@@ -108,12 +105,10 @@ void menu_file_manager::populate(float &customtop, float &custombottom)
std::string tmp_inst, tmp_name;
if (!m_warnings.empty())
- {
item_append(m_warnings, FLAG_DISABLE, nullptr);
- item_append(std::string(), FLAG_DISABLE, nullptr);
- }
// cycle through all devices for this system
+ bool missing_mandatory = false;
std::unordered_set<std::string> devtags;
for (device_t &dev : device_enumerator(machine().root_device()))
{
@@ -135,12 +130,16 @@ void menu_file_manager::populate(float &customtop, float &custombottom)
if (strcmp(scan.device().owner()->tag(), dev.tag()) == 0)
if (devtags.insert(scan.device().tag()).second)
{
+ if (!scan.basename() && scan.must_be_loaded())
+ missing_mandatory = true;
+
// check whether we already had some devices with the same owner: if not, output the owner tag!
if (!tag_appended)
{
item_append(string_format(_("[root%1$s]"), dev.tag()), FLAG_UI_HEADING | FLAG_DISABLE, nullptr);
tag_appended = true;
}
+
// finally, append the image interface to the menu
fill_image_line(&scan, tmp_inst, tmp_name);
item_append(tmp_inst, tmp_name, 0, (void *)&scan);
@@ -150,8 +149,8 @@ void menu_file_manager::populate(float &customtop, float &custombottom)
}
item_append(menu_item_type::SEPARATOR);
- if (m_warnings.empty() || m_curr_selected)
- item_append(_("Reset Machine"), 0, (void *)1);
+ if (m_warnings.empty() || !missing_mandatory)
+ item_append(m_warnings.empty() ? _("Reset Machine") : _("Start Machine"), 0, (void *)1);
custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border();
}
@@ -175,7 +174,6 @@ void menu_file_manager::handle(event const *ev)
selected_device = (device_image_interface *) ev->itemref;
if (selected_device)
{
- m_curr_selected = true;
floppy_image_device *floppy_device = dynamic_cast<floppy_image_device *>(selected_device);
if (floppy_device)
menu::stack_push<menu_control_floppy_image>(ui(), container(), *floppy_device);
@@ -192,14 +190,9 @@ void menu_file_manager::handle(event const *ev)
// force file manager menu
void menu_file_manager::force_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings)
{
- // reset the menu stack
+ // drop any existing menus and start the file manager
menu::stack_reset(mui);
-
- // add the quit entry followed by the game select entry
- menu::stack_push_special_main<menu_quit_game>(mui, container);
- menu::stack_push<menu_file_manager>(mui, container, warnings);
-
- // force the menus on
+ menu::stack_push_special_main<menu_file_manager>(mui, container, warnings);
mui.show_menu();
// make sure MAME is paused
diff --git a/src/frontend/mame/ui/filemngr.h b/src/frontend/mame/ui/filemngr.h
index a925e24b35e..379912c8dfb 100644
--- a/src/frontend/mame/ui/filemngr.h
+++ b/src/frontend/mame/ui/filemngr.h
@@ -38,8 +38,7 @@ private:
void fill_image_line(device_image_interface *img, std::string &instance, std::string &filename);
- std::string m_warnings;
- bool m_curr_selected;
+ std::string const m_warnings;
};
} // namespace ui
diff --git a/src/frontend/mame/ui/filesel.cpp b/src/frontend/mame/ui/filesel.cpp
index ea5c1e02e37..3da27ae7a36 100644
--- a/src/frontend/mame/ui/filesel.cpp
+++ b/src/frontend/mame/ui/filesel.cpp
@@ -59,6 +59,7 @@ menu_file_selector::menu_file_selector(mame_ui_manager &mui, render_container &c
, m_result(result)
{
(void)m_image;
+ set_process_flags(PROCESS_IGNOREPAUSE);
}
diff --git a/src/frontend/mame/ui/imgcntrl.cpp b/src/frontend/mame/ui/imgcntrl.cpp
index 96f520d332b..5708a4a832a 100644
--- a/src/frontend/mame/ui/imgcntrl.cpp
+++ b/src/frontend/mame/ui/imgcntrl.cpp
@@ -234,7 +234,7 @@ void menu_control_device_image::menu_activated()
else
{
m_software_info_name.clear();
- menu::stack_push_special_main<menu_software_list>(ui(), container(), m_sld, m_image.image_interface(), m_software_info_name);
+ menu::stack_push<menu_software_list>(ui(), container(), m_sld, m_image.image_interface(), m_software_info_name);
m_state = SELECT_PARTLIST;
}
break;
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index 94b4b1eff5e..525e378dca6 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -112,7 +112,7 @@ menu::global_state::~global_state()
void menu::global_state::stack_push(std::unique_ptr<menu> &&menu)
{
- if (m_stack && m_stack->m_active)
+ if (m_stack && m_stack->is_active())
{
m_stack->m_active = false;
m_stack->menu_deactivated();
@@ -127,8 +127,13 @@ void menu::global_state::stack_pop()
{
if (m_stack)
{
- if (m_stack->m_one_shot)
+ if (m_stack->is_one_shot())
m_hide = true;
+ if (m_stack->is_active())
+ {
+ m_stack->m_active = false;
+ m_stack->menu_deactivated();
+ }
m_stack->menu_dismissed();
std::unique_ptr<menu> menu(std::move(m_stack));
m_stack = std::move(menu->m_parent);
@@ -177,10 +182,10 @@ uint32_t menu::global_state::ui_handler(render_container &container)
{
// if we have no menus stacked up, start with the main menu
if (!m_stack)
- stack_push(std::unique_ptr<menu>(make_unique_clear<menu_main>(m_ui, container)));
+ stack_push(std::make_unique<menu_main>(m_ui, container));
// ensure topmost menu is active - need a loop because it could push another menu
- while (m_stack && !m_stack->m_active)
+ while (m_stack && !m_stack->is_active())
{
m_stack->m_active = true;
m_stack->menu_activated();
@@ -199,11 +204,11 @@ uint32_t menu::global_state::ui_handler(render_container &container)
{
if (m_stack)
{
- if (m_stack->m_one_shot)
+ if (m_stack->is_one_shot())
{
stack_pop();
}
- else if (m_stack->m_active)
+ else if (m_stack->is_active())
{
m_stack->m_active = false;
m_stack->menu_deactivated();
@@ -287,17 +292,6 @@ void menu::reset(reset_options options)
//-------------------------------------------------
-// is_special_main_menu - returns whether the
-// menu has special needs
-//-------------------------------------------------
-
-bool menu::is_special_main_menu() const
-{
- return m_special_main_menu;
-}
-
-
-//-------------------------------------------------
// set_special_main_menu - set whether the
// menu has special needs
//-------------------------------------------------
@@ -897,6 +891,8 @@ void menu::handle_events(uint32_t flags, event &ev)
{
ev.iptkey = IPT_UI_CANCEL;
stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
}
stop = true;
}
@@ -974,6 +970,8 @@ void menu::handle_keys(uint32_t flags, int &iptkey)
{
iptkey = IPT_UI_CANCEL;
stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
}
return;
}
@@ -981,7 +979,7 @@ void menu::handle_keys(uint32_t flags, int &iptkey)
// UI configure hides the menus
if (!(flags & PROCESS_NOKEYS) && exclusive_input_pressed(iptkey, IPT_UI_CONFIGURE, 0) && !m_global_state.stack_has_special_main_menu())
{
- if (m_one_shot)
+ if (is_one_shot())
stack_pop();
else
m_global_state.hide_menu();
@@ -996,7 +994,11 @@ void menu::handle_keys(uint32_t flags, int &iptkey)
if (exclusive_input_pressed(iptkey, IPT_UI_CANCEL, 0))
{
if (!custom_ui_cancel())
+ {
stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
+ }
return;
}
diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h
index b2111168dc4..00b42890f4b 100644
--- a/src/frontend/mame/ui/menu.h
+++ b/src/frontend/mame/ui/menu.h
@@ -65,12 +65,12 @@ public:
template <typename T, typename... Params>
static void stack_push(Params &&... args)
{
- stack_push(std::unique_ptr<menu>(make_unique_clear<T>(std::forward<Params>(args)...)));
+ stack_push(std::make_unique<T>(std::forward<Params>(args)...));
}
template <typename T, typename... Params>
static void stack_push_special_main(Params &&... args)
{
- std::unique_ptr<menu> ptr(make_unique_clear<T>(std::forward<Params>(args)...));
+ std::unique_ptr<menu> ptr(std::make_unique<T>(std::forward<Params>(args)...));
ptr->set_special_main_menu(true);
stack_push(std::move(ptr));
}
@@ -130,6 +130,10 @@ protected:
running_machine &machine() const { return m_ui.machine(); }
render_container &container() const { return m_container; }
+ bool is_special_main_menu() const { return m_special_main_menu; }
+ bool is_one_shot() const { return m_one_shot; }
+ bool is_active() const { return m_active; }
+
void set_one_shot(bool oneshot) { m_one_shot = oneshot; }
void set_needs_prev_menu_item(bool needs) { m_needs_prev_menu_item = needs; }
void reset(reset_options options);
@@ -338,7 +342,6 @@ private:
virtual void draw(uint32_t flags);
// request the specific handling of the game selection main menu
- bool is_special_main_menu() const;
void set_special_main_menu(bool disable);
// to be implemented in derived classes
@@ -392,6 +395,37 @@ private:
float m_mouse_y;
};
+
+template <typename Base = menu>
+class autopause_menu : public Base
+{
+protected:
+ using Base::Base;
+
+ virtual void menu_activated() override
+ {
+ m_was_paused = this->machine().paused();
+ if (m_was_paused)
+ m_unpaused = false;
+ else if (!m_unpaused)
+ this->machine().pause();
+ Base::menu_activated();
+ }
+
+ virtual void menu_deactivated() override
+ {
+ m_unpaused = !this->machine().paused();
+ if (!m_was_paused && !m_unpaused)
+ this->machine().resume();
+ Base::menu_deactivated();
+ }
+
+private:
+ bool m_was_paused = false;
+ bool m_unpaused = false;
+};
+
+
} // namespace ui
#endif // MAME_FRONTEND_UI_MENU_H
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index 2254ef609e3..8c70dce18ad 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -560,32 +560,6 @@ menu_crosshair::~menu_crosshair()
{
}
-/*-------------------------------------------------
- menu_quit_game - handle the "menu" for
- quitting the game
--------------------------------------------------*/
-
-menu_quit_game::menu_quit_game(mame_ui_manager &mui, render_container &container) : menu(mui, container)
-{
-}
-
-menu_quit_game::~menu_quit_game()
-{
-}
-
-void menu_quit_game::populate(float &customtop, float &custombottom)
-{
-}
-
-void menu_quit_game::handle(event const *ev)
-{
- // request a reset
- machine().schedule_exit();
-
- // reset the menu stack
- stack_reset();
-}
-
//-------------------------------------------------
// ctor / dtor
//-------------------------------------------------
diff --git a/src/frontend/mame/ui/miscmenu.h b/src/frontend/mame/ui/miscmenu.h
index 1b19b4c5d45..b17e6713597 100644
--- a/src/frontend/mame/ui/miscmenu.h
+++ b/src/frontend/mame/ui/miscmenu.h
@@ -54,6 +54,7 @@ private:
attotime prevtime;
};
+
class menu_crosshair : public menu
{
public:
@@ -87,16 +88,6 @@ private:
std::vector<std::string> m_pics;
};
-class menu_quit_game : public menu
-{
-public:
- menu_quit_game(mame_ui_manager &mui, render_container &container);
- virtual ~menu_quit_game();
-
-private:
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle(event const *ev) override;
-};
class menu_bios_selection : public menu
{
@@ -127,6 +118,7 @@ private:
std::vector<const game_driver*> m_list;
};
+
//-------------------------------------------------
// machine configure menu
//-------------------------------------------------
@@ -173,6 +165,7 @@ private:
bool m_want_favorite;
};
+
//-------------------------------------------------
// plugins configure menu
//-------------------------------------------------
diff --git a/src/frontend/mame/ui/quitmenu.cpp b/src/frontend/mame/ui/quitmenu.cpp
new file mode 100644
index 00000000000..bb26f7e6290
--- /dev/null
+++ b/src/frontend/mame/ui/quitmenu.cpp
@@ -0,0 +1,61 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ui/quitmenu.h
+
+ Menus involved in quitting MAME.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "quitmenu.h"
+
+#include "uiinput.h"
+
+
+namespace ui {
+
+menu_confirm_quit::menu_confirm_quit(mame_ui_manager &mui, render_container &container)
+ : autopause_menu<>(mui, container)
+{
+ set_one_shot(true);
+ set_process_flags(PROCESS_CUSTOM_ONLY | PROCESS_NOINPUT);
+}
+
+
+menu_confirm_quit::~menu_confirm_quit()
+{
+}
+
+
+void menu_confirm_quit::custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2)
+{
+ ui().draw_text_box(
+ container(),
+ util::string_format(
+ _("Are you sure you want to quit?\n\n"
+ "Press %1$s to quit\n"
+ "Press %2$s to return to emulation"),
+ ui().get_general_input_setting(IPT_UI_SELECT),
+ ui().get_general_input_setting(IPT_UI_CANCEL)),
+ text_layout::text_justify::CENTER,
+ 0.5f, 0.5f,
+ UI_RED_COLOR);
+}
+
+
+void menu_confirm_quit::populate(float &customtop, float &custombottom)
+{
+}
+
+
+void menu_confirm_quit::handle(event const *ev)
+{
+ if (machine().ui_input().pressed(IPT_UI_SELECT))
+ machine().schedule_exit();
+ else if (machine().ui_input().pressed(IPT_UI_CANCEL))
+ stack_pop();
+}
+
+} // namespace ui
diff --git a/src/frontend/mame/ui/quitmenu.h b/src/frontend/mame/ui/quitmenu.h
new file mode 100644
index 00000000000..81ca61e2892
--- /dev/null
+++ b/src/frontend/mame/ui/quitmenu.h
@@ -0,0 +1,36 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/***************************************************************************
+
+ ui/quitmenu.h
+
+ Menus involved in quitting MAME.
+
+***************************************************************************/
+#ifndef MAME_FRONTEND_UI_QUITMENU_H
+#define MAME_FRONTEND_UI_QUITMENU_H
+
+#pragma once
+
+#include "ui/menu.h"
+
+
+namespace ui {
+
+class menu_confirm_quit : public autopause_menu<>
+{
+public:
+ menu_confirm_quit(mame_ui_manager &mui, render_container &container);
+ virtual ~menu_confirm_quit();
+
+protected:
+ virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
+
+private:
+ virtual void populate(float &customtop, float &custombottom) override;
+ virtual void handle(event const *ev) override;
+};
+
+} // namespace ui
+
+#endif // MAME_FRONTEND_UI_QUITMENU_H
diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp
index 5fceddc1b3e..315722922d2 100644
--- a/src/frontend/mame/ui/selgame.cpp
+++ b/src/frontend/mame/ui/selgame.cpp
@@ -438,7 +438,9 @@ void menu_select_game::populate(float &customtop, float &custombottom)
skip_main_items = 3;
}
else
+ {
skip_main_items = 0;
+ }
// configure the custom rendering
customtop = 3.0f * ui().get_line_height() + 5.0f * ui().box_tb_border();
@@ -569,14 +571,9 @@ void menu_select_game::build_available_list()
void menu_select_game::force_game_select(mame_ui_manager &mui, render_container &container)
{
- // reset the menu stack
+ // drop any existing menus and start the system selection menu
menu::stack_reset(mui);
-
- // add the quit entry followed by the game select entry
- menu::stack_push_special_main<menu_quit_game>(mui, container);
- menu::stack_push<menu_select_game>(mui, container, nullptr);
-
- // force the menus on
+ menu::stack_push_special_main<menu_select_game>(mui, container, nullptr);
mui.show_menu();
// make sure MAME is paused
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index 29bec4fe639..b299c7e4167 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -1441,6 +1441,8 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
{
// otherwise pop the stack
stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
}
return;
}
@@ -1761,6 +1763,8 @@ void menu_select_launch::handle_events(uint32_t flags, event &ev)
{
ev.iptkey = IPT_UI_CANCEL;
stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
stop = true;
}
else if (hover() >= HOVER_RP_FIRST && hover() <= HOVER_RP_LAST)
diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp
index 82fde5bae79..7cb346ee397 100644
--- a/src/frontend/mame/ui/simpleselgame.cpp
+++ b/src/frontend/mame/ui/simpleselgame.cpp
@@ -13,7 +13,6 @@
#include "ui/simpleselgame.h"
#include "ui/info.h"
-#include "ui/miscmenu.h"
#include "ui/optsmenu.h"
#include "ui/ui.h"
#include "ui/utils.h"
@@ -418,13 +417,10 @@ void simple_menu_select_game::force_game_select(mame_ui_manager &mui, render_con
char *gamename = (char *)mui.machine().options().system_name();
// reset the menu stack
- menu::stack_reset(mui);
-
- // add the quit entry followed by the game select entry
- menu::stack_push_special_main<menu_quit_game>(mui, container);
- menu::stack_push<simple_menu_select_game>(mui, container, gamename);
- // force the menus on
+ // drop any existing menus and start the system selection menu
+ menu::stack_reset(mui);
+ menu::stack_push_special_main<simple_menu_select_game>(mui, container, gamename);
mui.show_menu();
// make sure MAME is paused
diff --git a/src/frontend/mame/ui/sliders.h b/src/frontend/mame/ui/sliders.h
index 6dd763b9c2f..a1ac25bf96c 100644
--- a/src/frontend/mame/ui/sliders.h
+++ b/src/frontend/mame/ui/sliders.h
@@ -2,7 +2,7 @@
// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
/***************************************************************************
- ui/miscmenu.h
+ ui/sliders.h
Internal MAME menus for the user interface.
diff --git a/src/frontend/mame/ui/state.cpp b/src/frontend/mame/ui/state.cpp
index 72ed3941196..afd02a3b08d 100644
--- a/src/frontend/mame/ui/state.cpp
+++ b/src/frontend/mame/ui/state.cpp
@@ -89,15 +89,12 @@ menu_load_save_state_base::menu_load_save_state_base(
std::string_view footer,
bool must_exist,
bool one_shot)
- : menu(mui, container)
+ : autopause_menu<>(mui, container)
, m_switch_poller(machine().input())
, m_header(header)
, m_footer(footer)
, m_confirm_delete(nullptr)
, m_must_exist(must_exist)
- , m_one_shot(one_shot)
- , m_first_time(true)
- , m_was_paused(false)
, m_keys_released(false)
{
set_one_shot(one_shot);
@@ -111,10 +108,6 @@ menu_load_save_state_base::menu_load_save_state_base(
menu_load_save_state_base::~menu_load_save_state_base()
{
- // resume if appropriate (is the destructor really the right place
- // to do this sort of activity?)
- if (!m_was_paused)
- machine().resume();
}
@@ -225,24 +218,15 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom)
set_selection(nullptr);
}
item_append(menu_item_type::SEPARATOR);
- if (m_one_shot)
+ if (is_one_shot())
item_append(_("Cancel"), 0, nullptr);
// set up custom render proc
customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
custombottom = (2.0f * ui().get_line_height()) + (3.0f * ui().box_tb_border());
- // pause if appropriate
- if (m_first_time)
- {
- m_was_paused = machine().paused();
- if (!m_was_paused)
- machine().pause();
- }
-
// get ready to poll inputs
m_switch_poller.reset();
- m_first_time = false;
m_keys_released = false;
}
diff --git a/src/frontend/mame/ui/state.h b/src/frontend/mame/ui/state.h
index f6a48331981..dd3d9f190ec 100644
--- a/src/frontend/mame/ui/state.h
+++ b/src/frontend/mame/ui/state.h
@@ -22,7 +22,7 @@
namespace ui {
-class menu_load_save_state_base : public menu
+class menu_load_save_state_base : public autopause_menu<>
{
public:
virtual ~menu_load_save_state_base() override;
@@ -73,9 +73,7 @@ private:
std::string m_confirm_prompt;
file_entry const * m_confirm_delete;
bool const m_must_exist;
- bool const m_one_shot;
bool m_first_time;
- bool m_was_paused;
bool m_keys_released;
static void *itemref_from_file_entry(const file_entry &entry);
diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp
index 72e076df67c..70c9471da56 100644
--- a/src/frontend/mame/ui/swlist.cpp
+++ b/src/frontend/mame/ui/swlist.cpp
@@ -148,6 +148,7 @@ void menu_software_parts::handle(event const *ev)
menu_software_list::menu_software_list(mame_ui_manager &mui, render_container &container, software_list_device *swlist, const char *interface, std::string &result)
: menu(mui, container), m_result(result)
{
+ set_process_flags(PROCESS_IGNOREPAUSE);
m_swlist = swlist;
m_interface = interface;
m_ordered_by_shortname = false;
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index fa7d1644d40..7d3a51c8928 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -19,6 +19,7 @@
#include "ui/info.h"
#include "ui/mainmenu.h"
#include "ui/menu.h"
+#include "ui/quitmenu.h"
#include "ui/sliders.h"
#include "ui/state.h"
#include "ui/systemlist.h"
@@ -594,7 +595,9 @@ void mame_ui_manager::display_startup_screens(bool first_time)
// if we're the empty driver, force the menus on
if (ui::menu::stack_has_special_main_menu(*this))
+ {
show_menu();
+ }
else if (config_menu)
{
show_menu();
@@ -1417,50 +1420,14 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
void mame_ui_manager::request_quit()
{
if (!machine().options().confirm_quit())
+ {
machine().schedule_exit();
+ }
else
- set_handler(ui_callback_type::GENERAL, handler_callback_func(&mame_ui_manager::handler_confirm_quit, this));
-}
-
-
-//-------------------------------------------------
-// handler_confirm_quit - leads the user through
-// confirming quit emulation
-//-------------------------------------------------
-
-uint32_t mame_ui_manager::handler_confirm_quit(render_container &container)
-{
- uint32_t state = 0;
-
- // get the text for 'UI Select'
- std::string ui_select_text = get_general_input_setting(IPT_UI_SELECT);
-
- // get the text for 'UI Cancel'
- std::string ui_cancel_text = get_general_input_setting(IPT_UI_CANCEL);
-
- // assemble the quit message
- std::string quit_message = string_format(
- _("Are you sure you want to quit?\n\n"
- "Press ''%1$s'' to quit,\n"
- "Press ''%2$s'' to return to emulation."),
- ui_select_text,
- ui_cancel_text);
-
- draw_text_box(container, quit_message, ui::text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR);
- machine().pause();
-
- // if the user press ENTER, quit the game
- if (machine().ui_input().pressed(IPT_UI_SELECT))
- machine().schedule_exit();
-
- // if the user press ESC, just continue
- else if (machine().ui_input().pressed(IPT_UI_CANCEL))
{
- machine().resume();
- state = UI_HANDLER_CANCEL;
+ show_menu();
+ ui::menu::stack_push<ui::menu_confirm_quit>(*this, machine().render().ui_container());
}
-
- return state;
}
diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h
index cda90e22df9..272fb0ae810 100644
--- a/src/frontend/mame/ui/ui.h
+++ b/src/frontend/mame/ui/ui.h
@@ -266,8 +266,6 @@ private:
// UI handlers
uint32_t handler_ingame(render_container &container);
- uint32_t handler_load_save(render_container &container, uint32_t state);
- uint32_t handler_confirm_quit(render_container &container);
// private methods
void set_handler(ui_callback_type callback_type, handler_callback_func &&callback);