diff options
Diffstat (limited to 'src/frontend/mame/ui/state.cpp')
-rw-r--r-- | src/frontend/mame/ui/state.cpp | 267 |
1 files changed, 209 insertions, 58 deletions
diff --git a/src/frontend/mame/ui/state.cpp b/src/frontend/mame/ui/state.cpp index 6939401d566..efbc9e67e98 100644 --- a/src/frontend/mame/ui/state.cpp +++ b/src/frontend/mame/ui/state.cpp @@ -13,6 +13,9 @@ #include "emuopts.h" #include "inputdev.h" +#include "uiinput.h" + +#include "path.h" namespace ui { @@ -82,14 +85,24 @@ menu_load_save_state_base::file_entry::file_entry(std::string &&file_name, std:: // ctor //------------------------------------------------- -menu_load_save_state_base::menu_load_save_state_base(mame_ui_manager &mui, render_container &container, const char *header, const char *footer, bool must_exist) - : menu(mui, container) - , m_header(header) +menu_load_save_state_base::menu_load_save_state_base( + mame_ui_manager &mui, + render_container &container, + std::string_view header, + std::string_view footer, + bool must_exist, + bool one_shot) + : autopause_menu<>(mui, container) + , m_switch_poller(machine().input()) , m_footer(footer) + , m_confirm_delete(nullptr) , m_must_exist(must_exist) - , m_was_paused(false) , m_keys_released(false) + , m_slot_selected(INPUT_CODE_INVALID) { + set_one_shot(one_shot); + set_needs_prev_menu_item(!one_shot); + set_heading(header); } @@ -99,10 +112,6 @@ menu_load_save_state_base::menu_load_save_state_base(mame_ui_manager &mui, rende 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(); } @@ -110,7 +119,7 @@ menu_load_save_state_base::~menu_load_save_state_base() // populate //------------------------------------------------- -void menu_load_save_state_base::populate(float &customtop, float &custombottom) +void menu_load_save_state_base::populate() { // build the "filename to code" map, if we have not already (if it were not for the // possibility that the system keyboard can be changed at runtime, I would put this @@ -163,7 +172,7 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom) if (core_filename_ends_with(entry->name, ".sta")) { // get the file name of the entry - std::string file_name = core_filename_extract_base(entry->name, true); + std::string file_name(core_filename_extract_base(entry->name, true)); // try translating it std::string visible_name = get_visible_name(file_name); @@ -200,7 +209,7 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom) // append the menu item void *const itemref = itemref_from_file_entry(*entry); - item_append(std::move(text), std::string(), 0, itemref); + item_append(std::move(text), 0, itemref); // is this item selected? if (entry->file_name() == s_last_file_selected) @@ -209,22 +218,15 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom) if (m_entries_vec.empty()) { - item_append(_("No save states found"), std::string(), 0, nullptr); + item_append(_("[no saved states found]"), FLAG_DISABLE, nullptr); set_selection(nullptr); } item_append(menu_item_type::SEPARATOR); - - // set up custom render proc - customtop = ui().get_line_height() + 3.0f * ui().box_tb_border(); - custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border(); - - // pause if appropriate - m_was_paused = machine().paused(); - if (!m_was_paused) - machine().pause(); + if (is_one_shot()) + item_append(_("Cancel"), 0, nullptr); // get ready to poll inputs - machine().input().reset_polling(); + m_switch_poller.reset(); m_keys_released = false; } @@ -233,27 +235,59 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom) // handle //------------------------------------------------- -void menu_load_save_state_base::handle() +bool menu_load_save_state_base::handle(event const *ev) { - // process the menu - event const *const event = process(0); - // process the event - if (event && (event->iptkey == IPT_UI_SELECT)) + if (INPUT_CODE_INVALID != m_slot_selected) { - if (event->itemref) + if (!machine().input().code_pressed(m_slot_selected)) + stack_pop(); + return false; + } + else if (ev && (ev->iptkey == IPT_UI_SELECT)) + { + if (ev->itemref) { // user selected one of the entries - file_entry const &entry = file_entry_from_itemref(event->itemref); + file_entry const &entry = file_entry_from_itemref(ev->itemref); slot_selected(std::string(entry.file_name())); } + stack_pop(); + return false; } - else + else if (ev && (ev->iptkey == IPT_UI_CLEAR)) + { + if (ev->itemref) + { + // prompt to confirm delete + m_confirm_delete = &file_entry_from_itemref(ev->itemref); + m_confirm_prompt = util::string_format( + _("Delete saved state %1$s?\nPress %2$s to delete\nPress %3$s to cancel"), + m_confirm_delete->visible_name(), + ui().get_general_input_setting(IPT_UI_SELECT), + ui().get_general_input_setting(IPT_UI_BACK)); + return true; + } + else + { + return false; + } + } + else if (!m_confirm_delete) { // poll inputs - std::string name = poll_inputs(); - if (!name.empty()) - try_select_slot(std::move(name)); + input_code code; + std::string name = poll_inputs(code); + if (!name.empty() && try_select_slot(std::move(name))) + { + m_switch_poller.reset(); + m_slot_selected = code; + } + return false; + } + else + { + return false; } } @@ -277,25 +311,32 @@ std::string menu_load_save_state_base::get_visible_name(const std::string &file_ // poll_inputs //------------------------------------------------- -std::string menu_load_save_state_base::poll_inputs() +std::string menu_load_save_state_base::poll_inputs(input_code &code) { - input_code const code = machine().input().poll_switches(); - if (INPUT_CODE_INVALID == code) + input_code const result = m_switch_poller.poll(); + if (INPUT_CODE_INVALID == result) { m_keys_released = true; } else if (m_keys_released) { - input_item_id const id = code.item_id(); + input_item_id const id = result.item_id(); // keyboard A-Z and 0-9 if (((ITEM_ID_A <= id) && (ITEM_ID_Z >= id)) || ((ITEM_ID_0 <= id) && (ITEM_ID_9 >= id))) + { + code = result; return keyboard_input_item_name(id); + } // joystick buttons - if ((DEVICE_CLASS_JOYSTICK == code.device_class()) && (ITEM_CLASS_SWITCH == code.item_class()) && (ITEM_MODIFIER_NONE == code.item_modifier()) && (ITEM_ID_BUTTON1 <= id) && (ITEM_ID_BUTTON32 >= id)) - return util::string_format("joy%i-%i", code.device_index(), id - ITEM_ID_BUTTON1 + 1); + if ((DEVICE_CLASS_JOYSTICK == result.device_class()) && (ITEM_CLASS_SWITCH == result.item_class()) && (ITEM_MODIFIER_NONE == result.item_modifier()) && (ITEM_ID_BUTTON1 <= id) && (ITEM_ID_BUTTON32 >= id)) + { + code = result; + return util::string_format("joy%i-%i", result.device_index(), id - ITEM_ID_BUTTON1 + 1); + } } + code = INPUT_CODE_INVALID; return ""; } @@ -304,10 +345,17 @@ std::string menu_load_save_state_base::poll_inputs() // try_select_slot //------------------------------------------------- -void menu_load_save_state_base::try_select_slot(std::string &&name) +bool menu_load_save_state_base::try_select_slot(std::string &&name) { if (!m_must_exist || is_present(name)) + { slot_selected(std::move(name)); + return true; + } + else + { + return false; + } } @@ -322,9 +370,96 @@ void menu_load_save_state_base::slot_selected(std::string &&name) // record the last slot touched s_last_file_selected = std::move(name); +} + + +//------------------------------------------------- +// handle_keys - override key handling +//------------------------------------------------- + +bool menu_load_save_state_base::handle_keys(uint32_t flags, int &iptkey) +{ + if (m_confirm_delete) + { + bool updated(false); + if (exclusive_input_pressed(iptkey, IPT_UI_SELECT, 0)) + { + // try to remove the file + std::string const filename(util::path_concat( + machine().options().state_directory(), + machine().get_statename(machine().options().state_name()), + m_confirm_delete->file_name() + ".sta")); + std::error_condition const err(osd_file::remove(filename)); + if (err) + { + osd_printf_error( + "Error removing file %s for state %s (%s:%d %s)\n", + filename, + m_confirm_delete->visible_name(), + err.category().name(), + err.value(), + err.message()); + machine().popmessage(_("Error removing saved state file %1$s"), filename); + } + + // repopulate the menu + // reset switch poller here to avoid bogus save/load if confirmed with joystick button + m_switch_poller.reset(); + m_confirm_prompt.clear(); + m_confirm_delete = nullptr; + m_keys_released = false; + reset(reset_options::REMEMBER_POSITION); + } + else if (exclusive_input_pressed(iptkey, IPT_UI_BACK, 0)) + { + // don't delete it - dismiss the prompt + m_switch_poller.reset(); + m_confirm_prompt.clear(); + m_confirm_delete = nullptr; + m_keys_released = false; + updated = true; + } + iptkey = IPT_INVALID; + return updated; + } + else if (INPUT_CODE_INVALID != m_slot_selected) + { + iptkey = IPT_INVALID; + return false; + } + else + { + return autopause_menu<>::handle_keys(flags, iptkey); + } +} + + +//------------------------------------------------- +// custom_pointer_updated - override pointer +// handling +//------------------------------------------------- - // no matter what, pop out - menu::stack_pop(machine()); +std::tuple<int, bool, bool> menu_load_save_state_base::custom_pointer_updated(bool changed, ui_event const &uievt) +{ + // suppress clicks on the menu while the delete prompt is visible + if (m_confirm_delete && uievt.pointer_buttons) + return std::make_tuple(IPT_INVALID, true, false); + else + return autopause_menu<>::custom_pointer_updated(changed, uievt); + +} + + +//------------------------------------------------- +// recompute_metrics - recompute metrics +//------------------------------------------------- + +void menu_load_save_state_base::recompute_metrics(uint32_t width, uint32_t height, float aspect) +{ + autopause_menu<>::recompute_metrics(width, height, aspect); + + // set up custom render proc + set_custom_space(0.0F, (2.0F * line_height()) + (3.0F * tb_border())); } @@ -332,18 +467,36 @@ void menu_load_save_state_base::slot_selected(std::string &&name) // custom_render - perform our special rendering //------------------------------------------------- -void menu_load_save_state_base::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) +void menu_load_save_state_base::custom_render(uint32_t flags, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) { - extra_text_render(top, bottom, origx1, origy1, origx2, origy2, m_header, nullptr); - if (m_footer) + std::string_view text[2]; + unsigned count(0U); + + // add fixed footer if supplied + if (!m_footer.empty()) + text[count++] = m_footer; + + // provide a prompt to delete if a state is selected + if (selected_item().ref()) + { + if (m_delete_prompt.empty()) + m_delete_prompt = util::string_format(_("Press %1$s to delete"), ui().get_general_input_setting(IPT_UI_CLEAR)); + text[count++] = m_delete_prompt; + } + + // draw the footer box if necessary + if (count) { - char const *const text[] = { m_footer }; draw_text_box( - std::begin(text), std::end(text), - origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, - ui().colors().text_color(), ui().colors().background_color(), 1.0f); + std::begin(text), std::next(std::begin(text), count), + origx1, origx2, origy2 + tb_border(), origy2 + (count * line_height()) + (3.0F * tb_border()), + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, + ui().colors().text_color(), ui().colors().background_color()); } + + // draw the confirmation prompt if necessary + if (!m_confirm_prompt.empty()) + ui().draw_text_box(container(), m_confirm_prompt, text_layout::text_justify::CENTER, 0.5F, 0.5F, ui().colors().background_color()); } @@ -373,11 +526,9 @@ const menu_load_save_state_base::file_entry &menu_load_save_state_base::file_ent std::string menu_load_save_state_base::state_directory() const { - const char *stateopt = machine().options().state_name(); - return util::string_format("%s%s%s", + return util::path_concat( machine().options().state_directory(), - PATH_SEPARATOR, - machine().get_statename(stateopt)); + machine().get_statename(machine().options().state_name())); } @@ -399,8 +550,8 @@ bool menu_load_save_state_base::is_present(const std::string &name) const // ctor //------------------------------------------------- -menu_load_state::menu_load_state(mame_ui_manager &mui, render_container &container) - : menu_load_save_state_base(mui, container, _("Load State"), _("Select state to load"), true) +menu_load_state::menu_load_state(mame_ui_manager &mui, render_container &container, bool one_shot) + : menu_load_save_state_base(mui, container, _("Load State"), _("Select state to load"), true, one_shot) { } @@ -423,8 +574,8 @@ void menu_load_state::process_file(std::string &&file_name) // ctor //------------------------------------------------- -menu_save_state::menu_save_state(mame_ui_manager &mui, render_container &container) - : menu_load_save_state_base(mui, container, _("Save State"), _("Press a key or joystick button, or select state to overwrite"), false) +menu_save_state::menu_save_state(mame_ui_manager &mui, render_container &container, bool one_shot) + : menu_load_save_state_base(mui, container, _("Save State"), _("Press a key or joystick button, or select state to overwrite"), false, one_shot) { } |