diff options
Diffstat (limited to 'src')
24 files changed, 1963 insertions, 1722 deletions
diff --git a/src/frontend/mame/ui/auditmenu.cpp b/src/frontend/mame/ui/auditmenu.cpp index 26c667401c0..ea3058914ab 100644 --- a/src/frontend/mame/ui/auditmenu.cpp +++ b/src/frontend/mame/ui/auditmenu.cpp @@ -159,7 +159,7 @@ void menu_audit::handle() std::stable_sort(m_unavailablesorted.begin(), m_unavailablesorted.end(), sorted_game_list); save_available_machines(); reset_parent(reset_options::SELECT_FIRST); - menu::stack_pop(machine()); + stack_pop(); } //------------------------------------------------- diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp index 6eb4352e0c5..6a7d7635e92 100644 --- a/src/frontend/mame/ui/custui.cpp +++ b/src/frontend/mame/ui/custui.cpp @@ -1045,7 +1045,7 @@ void menu_palette_sel::handle() { m_original = rgb_t((UINT32)strtoul(item[selected].subtext.c_str(), nullptr, 16)); reset_parent(reset_options::SELECT_FIRST); - menu::stack_pop(machine()); + stack_pop(); } } } diff --git a/src/frontend/mame/ui/datmenu.cpp b/src/frontend/mame/ui/datmenu.cpp index 9445f30c10f..7ac8095c725 100644 --- a/src/frontend/mame/ui/datmenu.cpp +++ b/src/frontend/mame/ui/datmenu.cpp @@ -18,6 +18,10 @@ #include "mame.h" #include "rendfont.h" #include "softlist.h" +#include "uiinput.h" + +#include <cmath> + namespace ui { //------------------------------------------------- @@ -119,6 +123,147 @@ void menu_dats_view::populate() } //------------------------------------------------- +// draw - draw dats menu +//------------------------------------------------- + +void menu_dats_view::draw(UINT32 flags) +{ + auto line_height = ui().get_line_height(); + auto ud_arrow_width = line_height * machine().render().ui_aspect(); + auto gutter_width = 0.52f * line_height * machine().render().ui_aspect(); + mouse_x = -1, mouse_y = -1; + float visible_width = 1.0f - 2.0f * UI_BOX_LR_BORDER; + float visible_left = (1.0f - visible_width) * 0.5f; + + draw_background(); + + hover = item.size() + 1; + visible_items = item.size() - 2; + float extra_height = 2.0f * line_height; + float visible_extra_menu_height = customtop + custombottom + extra_height; + + // locate mouse + mouse_hit = false; + mouse_button = false; + mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); + if (mouse_target != nullptr) + if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) + mouse_hit = true; + + // account for extra space at the top and bottom + float visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height; + m_visible_lines = int(std::trunc(visible_main_menu_height / line_height)); + visible_main_menu_height = float(m_visible_lines) * line_height; + + // compute top/left of inner menu area by centering + float visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f; + + // if the menu is at the bottom of the extra, adjust + visible_top += customtop; + + // compute left box size + float x1 = visible_left; + float y1 = visible_top - UI_BOX_TB_BORDER; + float x2 = x1 + visible_width; + float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER + extra_height; + float line = visible_top + float(m_visible_lines) * line_height; + + ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); + + m_visible_lines = (std::min)(visible_items, m_visible_lines); + top_line = (std::max)(0, top_line); + if (top_line + m_visible_lines >= visible_items) + top_line = visible_items - m_visible_lines; + + // 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; + + int const n_loop = (std::min)(visible_items, m_visible_lines); + for (int linenum = 0; linenum < n_loop; linenum++) + { + float line_y = visible_top + (float)linenum * line_height; + int itemnum = top_line + linenum; + const menu_item &pitem = item[itemnum]; + const char *itemtext = pitem.text.c_str(); + rgb_t fgcolor = UI_TEXT_COLOR; + rgb_t bgcolor = UI_TEXT_BG_COLOR; + float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; + float line_y0 = line_y; + float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; + float line_y1 = line_y + line_height; + + // if we're on the top line, display the up arrow + if (linenum == 0 && top_line != 0) + { + draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0); + + if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y) + { + fgcolor = UI_MOUSEOVER_COLOR; + bgcolor = UI_MOUSEOVER_BG_COLOR; + highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); + hover = HOVER_ARROW_UP; + } + } + // if we're on the bottom line, display the down arrow + else if (linenum == m_visible_lines - 1 && itemnum != visible_items - 1) + { + draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); + + if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y) + { + fgcolor = UI_MOUSEOVER_COLOR; + bgcolor = UI_MOUSEOVER_BG_COLOR; + highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); + hover = HOVER_ARROW_DOWN; + } + } + + // draw dats text + else if (pitem.subtext.empty()) + { + ui().draw_text_full(container, itemtext, effective_left, line_y, effective_width, ui::text_layout::LEFT, ui::text_layout::NEVER, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); + } + } + + for (size_t count = visible_items; count < item.size(); count++) + { + const menu_item &pitem = item[count]; + const char *itemtext = pitem.text.c_str(); + float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; + float line_y0 = line; + float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; + float line_y1 = line + line_height; + rgb_t fgcolor = UI_SELECTED_COLOR; + rgb_t bgcolor = UI_SELECTED_BG_COLOR; + + if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) + hover = count; + + if (pitem.type == menu_item_type::SEPARATOR) + container->add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, + UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + else + { + highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); + ui().draw_text_full(container, itemtext, effective_left, line, effective_width, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); + } + line += line_height; + } + + // if there is something special to add, do it by calling the virtual method + custom_render(get_selection_ref(), customtop, custombottom, x1, y1, x2, y2); + + // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow + m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items); +} + +//------------------------------------------------- // perform our special rendering //------------------------------------------------- diff --git a/src/frontend/mame/ui/datmenu.h b/src/frontend/mame/ui/datmenu.h index fb896781ef9..300a0f60eeb 100644 --- a/src/frontend/mame/ui/datmenu.h +++ b/src/frontend/mame/ui/datmenu.h @@ -38,6 +38,10 @@ public: virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override; private: + // draw dats menu + virtual void draw(UINT32 flags) override; + + int visible_items; int m_actual; const game_driver *m_driver; ui_software_info *m_swinfo; diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp index 13875c328f5..5e377d4e474 100644 --- a/src/frontend/mame/ui/dirmenu.cpp +++ b/src/frontend/mame/ui/dirmenu.cpp @@ -392,7 +392,7 @@ void menu_add_change_folder::handle() } reset_parent(reset_options::SELECT_FIRST); - menu::stack_pop(machine()); + stack_pop(); } else if (menu_event->is_char_printable()) { @@ -614,7 +614,7 @@ void menu_remove_folder::handle() } reset_parent(reset_options::REMEMBER_REF); - menu::stack_pop(machine()); + stack_pop(); } } diff --git a/src/frontend/mame/ui/filecreate.cpp b/src/frontend/mame/ui/filecreate.cpp index 80513c27318..9cd260684a3 100644 --- a/src/frontend/mame/ui/filecreate.cpp +++ b/src/frontend/mame/ui/filecreate.cpp @@ -125,7 +125,7 @@ void menu_confirm_save_as::handle() *m_yes = true; // no matter what, pop out - menu::stack_pop(machine()); + stack_pop(); } } @@ -238,7 +238,7 @@ void menu_file_create::handle() if (tmp_file.find(".") != -1 && tmp_file.find(".") < tmp_file.length() - 1) { m_current_file = m_filename; - menu::stack_pop(machine()); + stack_pop(); } else ui().popup_time(1, "%s", _("Please enter a file extension too")); @@ -316,7 +316,7 @@ void menu_select_format::handle() if (event != nullptr && event->iptkey == IPT_UI_SELECT) { *m_result = int(FPTR(event->itemref)); - menu::stack_pop(machine()); + stack_pop(); } } diff --git a/src/frontend/mame/ui/filesel.cpp b/src/frontend/mame/ui/filesel.cpp index 34e86c99fe8..673f6a96161 100644 --- a/src/frontend/mame/ui/filesel.cpp +++ b/src/frontend/mame/ui/filesel.cpp @@ -392,18 +392,18 @@ void menu_file_selector::handle() case SELECTOR_ENTRY_TYPE_EMPTY: // empty slot - unload m_result = result::EMPTY; - menu::stack_pop(machine()); + stack_pop(); break; case SELECTOR_ENTRY_TYPE_CREATE: // create m_result = result::CREATE; - menu::stack_pop(machine()); + stack_pop(); break; case SELECTOR_ENTRY_TYPE_SOFTWARE_LIST: m_result = result::SOFTLIST; - menu::stack_pop(machine()); + stack_pop(); break; case SELECTOR_ENTRY_TYPE_DRIVE: @@ -424,7 +424,7 @@ void menu_file_selector::handle() // file m_current_file.assign(entry->fullpath); m_result = result::FILE; - menu::stack_pop(machine()); + stack_pop(); break; } @@ -551,7 +551,7 @@ void menu_select_rw::handle() if (event != nullptr && event->iptkey == IPT_UI_SELECT) { m_result = result_from_itemref(event->itemref); - menu::stack_pop(machine()); + stack_pop(); } } diff --git a/src/frontend/mame/ui/floppycntrl.cpp b/src/frontend/mame/ui/floppycntrl.cpp index 0fc1408f603..f47b4d580bf 100644 --- a/src/frontend/mame/ui/floppycntrl.cpp +++ b/src/frontend/mame/ui/floppycntrl.cpp @@ -67,7 +67,7 @@ void menu_control_floppy_image::hook_load(std::string filename, bool softlist) { machine().popmessage("When loaded from software list, the disk is Read-only.\n"); image->load(filename.c_str()); - menu::stack_pop(machine()); + stack_pop(); return; } @@ -77,7 +77,7 @@ void menu_control_floppy_image::hook_load(std::string filename, bool softlist) if (!input_format) { machine().popmessage("Error: %s\n", image->error()); - menu::stack_pop(machine()); + stack_pop(); return; } @@ -134,7 +134,7 @@ void menu_control_floppy_image::handle() output_filename = util::zippath_combine(m_current_directory.c_str(), m_current_file.c_str()); output_format = format_array[submenu_result.i]; do_load_create(); - menu::stack_pop(machine()); + stack_pop(); } break; @@ -142,18 +142,18 @@ void menu_control_floppy_image::handle() switch(submenu_result.rw) { case menu_select_rw::result::READONLY: do_load_create(); - menu::stack_pop(machine()); + stack_pop(); break; case menu_select_rw::result::READWRITE: output_format = input_format; do_load_create(); - menu::stack_pop(machine()); + stack_pop(); break; case menu_select_rw::result::WRITE_DIFF: machine().popmessage("Sorry, diffs are not supported yet\n"); - menu::stack_pop(machine()); + stack_pop(); break; case menu_select_rw::result::WRITE_OTHER: diff --git a/src/frontend/mame/ui/imgcntrl.cpp b/src/frontend/mame/ui/imgcntrl.cpp index e6521f931c0..62082930f3b 100644 --- a/src/frontend/mame/ui/imgcntrl.cpp +++ b/src/frontend/mame/ui/imgcntrl.cpp @@ -156,7 +156,7 @@ void menu_control_device_image::hook_load(std::string name, bool softlist) { if (image->is_reset_on_load()) image->set_init_phase(); image->load(name.c_str()); - menu::stack_pop(machine()); + stack_pop(); } @@ -198,7 +198,7 @@ void menu_control_device_image::handle() case SELECT_SOFTLIST: if(!sld) { - menu::stack_pop(machine()); + stack_pop(); break; } software_info_name = ""; @@ -251,7 +251,7 @@ void menu_control_device_image::handle() case menu_software_parts::result::EMPTY: image->unload(); - menu::stack_pop(machine()); + stack_pop(); break; case menu_software_parts::result::SWLIST: @@ -260,7 +260,7 @@ void menu_control_device_image::handle() break; case menu_software_parts::result::INVALID: // return to system - menu::stack_pop(machine()); + stack_pop(); break; } @@ -270,7 +270,7 @@ void menu_control_device_image::handle() switch(submenu_result.filesel) { case menu_file_selector::result::EMPTY: image->unload(); - menu::stack_pop(machine()); + stack_pop(); break; case menu_file_selector::result::FILE: @@ -288,7 +288,7 @@ void menu_control_device_image::handle() break; default: // return to system - menu::stack_pop(machine()); + stack_pop(); break; } break; @@ -326,7 +326,7 @@ void menu_control_device_image::handle() int err = image->create(path.c_str(), nullptr, nullptr); if (err != 0) machine().popmessage("Error: %s", image->error()); - menu::stack_pop(machine()); + stack_pop(); break; } } diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp index 7fa50f9f8ea..0342559d47e 100644 --- a/src/frontend/mame/ui/mainmenu.cpp +++ b/src/frontend/mame/ui/mainmenu.cpp @@ -272,7 +272,7 @@ void menu_main::handle() break; case QUIT_GAME: - menu::stack_pop(machine()); + stack_pop(); ui().request_quit(); break; diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 095cae4acf1..6cfc3c464db 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -15,20 +15,18 @@ #include "ui/ui.h" #include "ui/mainmenu.h" #include "ui/utils.h" -#include "ui/defimg.h" -#include "ui/starimg.h" -#include "ui/icorender.h" -#include "ui/toolbar.h" #include "ui/miscmenu.h" #include "cheat.h" -#include "drivenum.h" #include "mame.h" + +#include "drivenum.h" #include "rendutil.h" #include "uiinput.h" #include <algorithm> #include <cmath> +#include <utility> namespace ui { @@ -37,75 +35,31 @@ namespace ui { ***************************************************************************/ #define UI_MENU_POOL_SIZE 65536 -#define MAX_ICONS_RENDER 40 - -static std::vector<std::pair<const char *, const char *>> arts_info = -{ - { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY }, - { __("Cabinets"), OPTION_CABINETS_PATH }, - { __("Control Panels"), OPTION_CPANELS_PATH }, - { __("PCBs"), OPTION_PCBS_PATH }, - { __("Flyers"), OPTION_FLYERS_PATH }, - { __("Titles"), OPTION_TITLES_PATH }, - { __("Ends"), OPTION_ENDS_PATH }, - { __("Artwork Preview"), OPTION_ARTPREV_PATH }, - { __("Bosses"), OPTION_BOSSES_PATH }, - { __("Logos"), OPTION_LOGOS_PATH }, - { __("Versus"), OPTION_VERSUS_PATH }, - { __("Game Over"), OPTION_GAMEOVER_PATH }, - { __("HowTo"), OPTION_HOWTO_PATH }, - { __("Scores"), OPTION_SCORES_PATH }, - { __("Select"), OPTION_SELECT_PATH }, - { __("Marquees"), OPTION_MARQUEES_PATH }, - { __("Covers"), OPTION_COVER_PATH }, -}; - -static const char *hover_msg[] = { - __("Add or remove favorites"), - __("Export displayed list to file"), - __("Show DATs view"), -}; /*************************************************************************** GLOBAL VARIABLES ***************************************************************************/ -std::unique_ptr<menu> menu::menu_stack; -std::unique_ptr<menu> menu::menu_free; +std::mutex menu::s_global_state_guard; +menu::global_state_map menu::s_global_states; std::unique_ptr<bitmap_rgb32> menu::hilight_bitmap; render_texture *menu::hilight_texture; -render_texture *menu::arrow_texture; render_texture *menu::snapx_texture; render_texture *menu::hilight_main_texture; -render_texture *menu::bgrnd_texture; -render_texture *menu::star_texture; -render_texture *menu::toolbar_texture[UI_TOOLBAR_BUTTONS]; -render_texture *menu::sw_toolbar_texture[UI_TOOLBAR_BUTTONS]; -render_texture *menu::icons_texture[MAX_ICONS_RENDER]; std::unique_ptr<bitmap_argb32> menu::snapx_bitmap; -std::unique_ptr<bitmap_argb32> menu::no_avail_bitmap; -std::unique_ptr<bitmap_argb32> menu::star_bitmap; -std::unique_ptr<bitmap_argb32> menu::bgrnd_bitmap; -std::vector<std::unique_ptr<bitmap_argb32>> menu::icons_bitmap; std::unique_ptr<bitmap_rgb32> menu::hilight_main_bitmap; -std::vector<std::shared_ptr<bitmap_argb32>> menu::toolbar_bitmap; -std::vector<std::shared_ptr<bitmap_argb32>> menu::sw_toolbar_bitmap; -std::vector<const game_driver *> menu::m_old_icons; /*************************************************************************** INLINE FUNCTIONS ***************************************************************************/ -//------------------------------------------------- -// is_selectable - return TRUE if the given -// item is selectable -//------------------------------------------------- - -inline bool is_selectable(menu_item const &item) +inline menu::global_state_ptr menu::get_global_state(running_machine &machine) { - return ((item.flags & (menu::FLAG_MULTILINE | menu::FLAG_DISABLE)) == 0 && item.type != menu_item_type::SEPARATOR); -} + std::lock_guard<std::mutex> guard(s_global_state_guard); + auto const it(s_global_states.find(&machine)); + return (it != s_global_states.end()) ? it->second : global_state_ptr(); +} //------------------------------------------------- // exclusive_input_pressed - return TRUE if the @@ -113,14 +67,17 @@ inline bool is_selectable(menu_item const &item) // reported a key //------------------------------------------------- -inline bool menu::exclusive_input_pressed(int key, int repeat) +bool menu::exclusive_input_pressed(int &iptkey, int key, int repeat) { - if (m_event.iptkey == IPT_INVALID && machine().ui_input().pressed_repeat(key, repeat)) + if ((iptkey == IPT_INVALID) && machine().ui_input().pressed_repeat(key, repeat)) { - m_event.iptkey = key; + iptkey = key; return true; } - return false; + else + { + return false; + } } @@ -129,6 +86,104 @@ inline bool menu::exclusive_input_pressed(int key, int repeat) CORE SYSTEM MANAGEMENT ***************************************************************************/ +menu::global_state::global_state(running_machine &machine, ui_options const &options) + : m_machine(machine) + , m_cleanup_callbacks() + , m_bgrnd_bitmap() + , m_bgrnd_texture() + , m_stack() + , m_free() +{ + render_manager &render(machine.render()); + auto const texture_free([&render](render_texture *texture) { render.texture_free(texture); }); + + // create a texture for arrow icons + m_arrow_texture = texture_ptr(render.texture_alloc(render_triangle), texture_free); + + // create a texture for main menu background + m_bgrnd_texture = texture_ptr(render.texture_alloc(render_texture::hq_scale), texture_free); + if (options.use_background_image() && (&machine.system() == &GAME_NAME(___empty))) + { + m_bgrnd_bitmap = std::make_unique<bitmap_argb32>(0, 0); + emu_file backgroundfile(".", OPEN_FLAG_READ); + render_load_jpeg(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.jpg"); + + if (!m_bgrnd_bitmap->valid()) + render_load_png(*m_bgrnd_bitmap, backgroundfile, nullptr, "background.png"); + + if (m_bgrnd_bitmap->valid()) + m_bgrnd_texture->set_bitmap(*m_bgrnd_bitmap, m_bgrnd_bitmap->cliprect(), TEXFORMAT_ARGB32); + else + m_bgrnd_bitmap->reset(); + } +} + + +menu::global_state::~global_state() +{ + stack_reset(); + clear_free_list(); + + for (auto const &callback : m_cleanup_callbacks) + callback(m_machine); +} + + +void menu::global_state::add_cleanup_callback(cleanup_callback &&callback) +{ + m_cleanup_callbacks.emplace_back(std::move(callback)); +} + + +void menu::global_state::stack_push(std::unique_ptr<menu> &&menu) +{ + menu->m_parent = std::move(m_stack); + m_stack = std::move(menu); + m_stack->reset(reset_options::SELECT_FIRST); + m_stack->machine().ui_input().reset(); +} + + +void menu::global_state::stack_pop() +{ + if (m_stack) + { + std::unique_ptr<menu> menu(std::move(m_stack)); + m_stack = std::move(menu->m_parent); + menu->m_parent = std::move(m_free); + m_free = std::move(menu); + m_machine.ui_input().reset(); + } +} + + +void menu::global_state::stack_reset() +{ + while (m_stack) + stack_pop(); +} + + +void menu::global_state::clear_free_list() +{ + while (m_free) + m_free = std::move(m_free->m_parent); +} + + +bool menu::global_state::stack_has_special_main_menu() const +{ + for (auto menu = m_stack.get(); menu != nullptr; menu = menu->m_parent.get()) + { + if (menu->is_special_main_menu()) + return true; + } + return false; +} + + + + //------------------------------------------------- // init - initialize the menu system //------------------------------------------------- @@ -136,7 +191,14 @@ inline bool menu::exclusive_input_pressed(int key, int repeat) void menu::init(running_machine &machine, ui_options &mopt) { // initialize the menu stack - menu::stack_reset(machine); + { + std::lock_guard<std::mutex> guard(s_global_state_guard); + auto const ins(s_global_states.emplace(&machine, std::make_shared<global_state>(machine, mopt))); + if (ins.second) + machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(menu::exit), &machine)); // add an exit callback to free memory + else + ins.first->second->stack_reset(); + } // create a texture for hilighting items hilight_bitmap = std::make_unique<bitmap_rgb32>(256, 1); @@ -150,14 +212,8 @@ void menu::init(running_machine &machine, ui_options &mopt) hilight_texture = machine.render().texture_alloc(); hilight_texture->set_bitmap(*hilight_bitmap, hilight_bitmap->cliprect(), TEXFORMAT_ARGB32); - // create a texture for arrow icons - arrow_texture = machine.render().texture_alloc(render_triangle); - // initialize ui init_ui(machine, mopt); - - // add an exit callback to free memory - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(menu::exit), &machine)); } @@ -168,31 +224,16 @@ void menu::init(running_machine &machine, ui_options &mopt) void menu::exit(running_machine &machine) { // free menus - menu::stack_reset(machine); - menu::clear_free_list(machine); + { + std::lock_guard<std::mutex> guard(s_global_state_guard); + s_global_states.erase(&machine); + } // free textures render_manager &mre = machine.render(); mre.texture_free(hilight_texture); - mre.texture_free(arrow_texture); mre.texture_free(snapx_texture); mre.texture_free(hilight_main_texture); - mre.texture_free(bgrnd_texture); - mre.texture_free(star_texture); - - for (auto & elem : icons_texture) - mre.texture_free(elem); - - for (int i = 0; i < UI_TOOLBAR_BUTTONS; ++i) - { - mre.texture_free(sw_toolbar_texture[i]); - mre.texture_free(toolbar_texture[i]); - } - - icons_bitmap.clear(); - sw_toolbar_bitmap.clear(); - toolbar_bitmap.clear(); - m_old_icons.clear(); } @@ -206,16 +247,14 @@ void menu::exit(running_machine &machine) //------------------------------------------------- menu::menu(mame_ui_manager &mui, render_container *_container) - : m_special_main_menu(false) + : m_visible_lines(0) + , m_visible_items(0) + , m_global_state(get_global_state(mui.machine())) + , m_special_main_menu(false) , m_ui(mui) , m_parent() - , m_pressed(false) - , m_repeat(0) , m_event() , m_pool(nullptr) - , m_focus(focused_menu::main) - , m_visible_lines(0) - , m_visible_items(0) , m_resetpos(0) , m_resetref(nullptr) { @@ -275,12 +314,12 @@ void menu::reset(reset_options options) if (machine().options().ui() == emu_options::UI_SIMPLE) item_append(_("Exit"), "", 0, nullptr); else - item_append(_("Exit"), "", FLAG_UI | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + item_append(_("Exit"), "", FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); } else { - if (machine().options().ui() != emu_options::UI_SIMPLE && menu::stack_has_special_main_menu()) - item_append(_("Return to Previous Menu"), "", FLAG_UI | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu()) + item_append(_("Return to Previous Menu"), "", FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); else item_append(_("Return to Previous Menu"), "", 0, nullptr); } @@ -398,32 +437,20 @@ const menu::event *menu::process(UINT32 flags, float x0, float y0) // draw the menu if (item.size() > 1 && (item[0].flags & FLAG_MULTILINE) != 0) draw_text_box(); - else if ((item[0].flags & FLAG_UI) != 0 || (item[0].flags & FLAG_UI_SWLIST) != 0) - draw_select_game((flags & PROCESS_NOINPUT)); else if ((item[0].flags & FLAG_UI_PALETTE) != 0) draw_palette_menu(); - else if ((item[0].flags & FLAG_UI_DATS) != 0) - draw_dats_menu(); else - draw(flags, x0, y0); + draw(flags); // process input if (!(flags & PROCESS_NOKEYS) && !(flags & PROCESS_NOINPUT)) { // read events - if ((item[0].flags & FLAG_UI ) != 0 || (item[0].flags & FLAG_UI_SWLIST ) != 0) - handle_main_events(); - else - handle_events(flags); + handle_events(flags, m_event); // handle the keys if we don't already have an event if (m_event.iptkey == IPT_INVALID) - { - if ((item[0].flags & FLAG_UI) != 0 || (item[0].flags & FLAG_UI_SWLIST) != 0) - handle_main_keys(flags); - else - handle_keys(flags); - } + handle_keys(flags, m_event.iptkey); } // update the selected item in the event @@ -497,7 +524,7 @@ void menu::set_selection(void *selected_itemref) // draw - draw a menu //------------------------------------------------- -void menu::draw(UINT32 flags, float origx0, float origy0) +void menu::draw(UINT32 flags) { // first draw the FPS counter if (ui().show_fps_counter()) @@ -514,8 +541,8 @@ void menu::draw(UINT32 flags, float origx0, float origy0) float const ud_arrow_width = line_height * machine().render().ui_aspect(); float const gutter_width = lr_arrow_width * 1.3f; - if (ui().options().use_background_image() && &machine().system() == &GAME_NAME(___empty) && bgrnd_bitmap->valid() && !noimage) - container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + if (&machine().system() == &GAME_NAME(___empty) && !noimage) + draw_background(); // compute the width and height of the full menu float visible_width = 0; @@ -850,7 +877,7 @@ void menu::draw_text_box() // input events for a menu //------------------------------------------------- -void menu::handle_events(UINT32 flags) +void menu::handle_events(UINT32 flags, event &ev) { bool stop = false; ui_event local_menu_event; @@ -901,11 +928,11 @@ void menu::handle_events(UINT32 flags) if (!(flags & PROCESS_ONLYCHAR) && hover >= 0 && hover < item.size()) { selected = hover; - m_event.iptkey = IPT_UI_SELECT; + ev.iptkey = IPT_UI_SELECT; if (is_last_selected()) { - m_event.iptkey = IPT_UI_CANCEL; - menu::stack_pop(machine()); + ev.iptkey = IPT_UI_CANCEL; + stack_pop(); } stop = true; } @@ -946,8 +973,8 @@ void menu::handle_events(UINT32 flags) // translate CHAR events into specials case UI_EVENT_CHAR: - m_event.iptkey = IPT_SPECIAL; - m_event.unichar = local_menu_event.ch; + ev.iptkey = IPT_SPECIAL; + ev.unichar = local_menu_event.ch; stop = true; break; @@ -964,9 +991,9 @@ void menu::handle_events(UINT32 flags) // keys for a menu //------------------------------------------------- -void menu::handle_keys(UINT32 flags) +void menu::handle_keys(UINT32 flags, int &iptkey) { - bool ignorepause = menu::stack_has_special_main_menu(); + bool ignorepause = stack_has_special_main_menu(); int code; // bail if no items @@ -974,12 +1001,12 @@ void menu::handle_keys(UINT32 flags) return; // if we hit select, return TRUE or pop the stack, depending on the item - if (exclusive_input_pressed(IPT_UI_SELECT, 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_SELECT, 0)) { if (is_last_selected()) { - m_event.iptkey = IPT_UI_CANCEL; - menu::stack_pop(machine()); + iptkey = IPT_UI_CANCEL; + stack_pop(); } return; } @@ -989,10 +1016,10 @@ void menu::handle_keys(UINT32 flags) return; // hitting cancel also pops the stack - if (exclusive_input_pressed(IPT_UI_CANCEL, 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_CANCEL, 0)) { if (!menu_has_search_active()) - menu::stack_pop(machine()); + stack_pop(); return; } @@ -1007,13 +1034,13 @@ void menu::handle_keys(UINT32 flags) ignoreleft = ignoreright = false; // accept left/right keys as-is with repeat - if (!ignoreleft && exclusive_input_pressed(IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + if (!ignoreleft && exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) return; - if (!ignoreright && exclusive_input_pressed(IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + if (!ignoreright && exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) return; // up backs up by one item - if (exclusive_input_pressed(IPT_UI_UP, 6)) + if (exclusive_input_pressed(iptkey, IPT_UI_UP, 6)) { if ((item[0].flags & FLAG_UI_DATS)) { @@ -1028,7 +1055,7 @@ void menu::handle_keys(UINT32 flags) } // down advances by one item - if (exclusive_input_pressed(IPT_UI_DOWN, 6)) + if (exclusive_input_pressed(iptkey, IPT_UI_DOWN, 6)) { if ((item[0].flags & FLAG_UI_DATS)) { @@ -1043,7 +1070,7 @@ void menu::handle_keys(UINT32 flags) } // page up backs up by m_visible_items - if (exclusive_input_pressed(IPT_UI_PAGE_UP, 6)) + if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_UP, 6)) { selected -= m_visible_items; top_line -= m_visible_items - (last_item_visible() ? 1 : 0); @@ -1053,7 +1080,7 @@ void menu::handle_keys(UINT32 flags) } // page down advances by m_visible_items - if (exclusive_input_pressed(IPT_UI_PAGE_DOWN, 6)) + if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_DOWN, 6)) { selected += m_visible_lines - 2 + (selected == 0); top_line += m_visible_lines - 2; @@ -1064,21 +1091,21 @@ void menu::handle_keys(UINT32 flags) } // home goes to the start - if (exclusive_input_pressed(IPT_UI_HOME, 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_HOME, 0)) { selected = top_line = 0; validate_selection(1); } // end goes to the last - if (exclusive_input_pressed(IPT_UI_END, 0)) + if (exclusive_input_pressed(iptkey, IPT_UI_END, 0)) { selected = top_line = item.size() - 1; validate_selection(-1); } // pause enables/disables pause - if (!ignorepause && exclusive_input_pressed(IPT_UI_PAUSE, 0)) + if (!ignorepause && exclusive_input_pressed(iptkey, IPT_UI_PAUSE, 0)) { if (machine().paused()) machine().resume(); @@ -1091,14 +1118,16 @@ void menu::handle_keys(UINT32 flags) mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled()); // see if any other UI keys are pressed - if (m_event.iptkey == IPT_INVALID) + if (iptkey == IPT_INVALID) + { for (code = IPT_UI_FIRST + 1; code < IPT_UI_LAST; code++) { if (code == IPT_UI_CONFIGURE || (code == IPT_UI_LEFT && ignoreleft) || (code == IPT_UI_RIGHT && ignoreright) || (code == IPT_UI_PAUSE && ignorepause)) continue; - if (exclusive_input_pressed(code, 0)) + if (exclusive_input_pressed(iptkey, code, 0)) break; } + } } @@ -1123,82 +1152,13 @@ void menu::validate_selection(int scandir) -//------------------------------------------------- -// clear_free_list - clear out anything -// accumulated in the free list -//------------------------------------------------- - -void menu::clear_free_list(running_machine &machine) -{ - while (menu_free) - menu_free = std::move(menu_free->m_parent); -} - - - /*************************************************************************** MENU STACK MANAGEMENT ***************************************************************************/ -//------------------------------------------------- -// menu::stack_reset - reset the menu stack -//------------------------------------------------- - -void menu::stack_reset(running_machine &machine) -{ - while (menu_stack) - menu::stack_pop(machine); -} - - -//------------------------------------------------- -// stack_push - push a new menu onto the -// stack -//------------------------------------------------- - -void menu::stack_push(std::unique_ptr<menu> &&menu) -{ - menu->m_parent = std::move(menu_stack); - menu_stack = std::move(menu); - menu_stack->reset(reset_options::SELECT_FIRST); - menu_stack->machine().ui_input().reset(); -} - - -//------------------------------------------------- -// stack_pop - pop a menu from the stack -//------------------------------------------------- - -void menu::stack_pop(running_machine &machine) -{ - if (menu_stack) - { - std::unique_ptr<menu> menu(std::move(menu_stack)); - menu_stack = std::move(menu->m_parent); - menu->m_parent = std::move(menu_free); - menu_free = std::move(menu); - machine.ui_input().reset(); - } -} - - -//------------------------------------------------- -// menu::stack_has_special_main_menu - -// check in the special main menu is in the stack -//------------------------------------------------- - -bool menu::stack_has_special_main_menu() -{ - for (auto menu = menu_stack.get(); menu != nullptr; menu = menu->m_parent.get()) - if (menu->is_special_main_menu()) - return true; - - return false; -} - void menu::do_handle() { - if(item.size() < 2) + if (item.size() < 2) populate(); handle(); } @@ -1215,19 +1175,21 @@ void menu::do_handle() UINT32 menu::ui_handler(render_container *container, mame_ui_manager &mui) { + global_state_ptr const state(get_global_state(mui.machine())); + // if we have no menus stacked up, start with the main menu - if (!menu_stack) - stack_push(std::unique_ptr<menu>(global_alloc_clear<menu_main>(mui, container))); + if (!state->topmost_menu<menu>()) + state->stack_push(std::unique_ptr<menu>(global_alloc_clear<menu_main>(mui, container))); // update the menu state - if (menu_stack) - menu_stack->do_handle(); + if (state->topmost_menu<menu>()) + state->topmost_menu<menu>()->do_handle(); // clear up anything pending to be released - clear_free_list(mui.machine()); + state->clear_free_list(); // if the menus are to be hidden, return a cancel here - if (mui.is_menu_active() && ((mui.machine().ui_input().pressed(IPT_UI_CONFIGURE) && !stack_has_special_main_menu()) || menu_stack == nullptr)) + if (mui.is_menu_active() && ((mui.machine().ui_input().pressed(IPT_UI_CONFIGURE) && !state->stack_has_special_main_menu()) || !state->topmost_menu<menu>())) return UI_HANDLER_CANCEL; return 0; @@ -1308,7 +1270,7 @@ void menu::highlight(render_container *container, float x0, float y0, float x1, void menu::draw_arrow(render_container *container, float x0, float y0, float x1, float y1, rgb_t fgcolor, UINT32 orientation) { - container->add_quad(x0, y0, x1, y1, fgcolor, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(orientation) | PRIMFLAG_PACKABLE); + container->add_quad(x0, y0, x1, y1, fgcolor, m_global_state->arrow_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(orientation) | PRIMFLAG_PACKABLE); } //------------------------------------------------- @@ -1336,1037 +1298,8 @@ void menu::init_ui(running_machine &machine, ui_options &mopt) // create a texture for snapshot snapx_bitmap = std::make_unique<bitmap_argb32>(0, 0); snapx_texture = mrender.texture_alloc(render_texture::hq_scale); - - // allocates and sets the default "no available" image - no_avail_bitmap = std::make_unique<bitmap_argb32>(256, 256); - UINT32 *dst = &no_avail_bitmap->pix32(0); - memcpy(dst, no_avail_bmp, 256 * 256 * sizeof(UINT32)); - - // allocates and sets the favorites star image - star_bitmap = std::make_unique<bitmap_argb32>(32, 32); - dst = &star_bitmap->pix32(0); - memcpy(dst, favorite_star_bmp, 32 * 32 * sizeof(UINT32)); - star_texture = mrender.texture_alloc(); - star_texture->set_bitmap(*star_bitmap, star_bitmap->cliprect(), TEXFORMAT_ARGB32); - - // allocate icons - for (auto & icons : icons_texture) - { - m_old_icons.emplace_back(nullptr); - icons_bitmap.emplace_back(std::make_unique<bitmap_argb32>()); - icons = mrender.texture_alloc(); - } - - // create a texture for main menu background - bgrnd_bitmap = std::make_unique<bitmap_argb32>(0, 0); - bgrnd_texture = mrender.texture_alloc(render_texture::hq_scale); - - if (mopt.use_background_image() && &machine.system() == &GAME_NAME(___empty)) - { - emu_file backgroundfile(".", OPEN_FLAG_READ); - render_load_jpeg(*bgrnd_bitmap, backgroundfile, nullptr, "background.jpg"); - - if (!bgrnd_bitmap->valid()) - render_load_png(*bgrnd_bitmap, backgroundfile, nullptr, "background.png"); - - if (bgrnd_bitmap->valid()) - bgrnd_texture->set_bitmap(*bgrnd_bitmap, bgrnd_bitmap->cliprect(), TEXFORMAT_ARGB32); - else - bgrnd_bitmap->reset(); - } - else - bgrnd_bitmap->reset(); - - // create a texture for toolbar - for (int x = 0; x < UI_TOOLBAR_BUTTONS; ++x) - { - toolbar_bitmap.emplace_back(std::make_shared<bitmap_argb32>(32, 32)); - sw_toolbar_bitmap.emplace_back(std::make_shared<bitmap_argb32>(32, 32)); - toolbar_texture[x] = mrender.texture_alloc(); - sw_toolbar_texture[x] = mrender.texture_alloc(); - UINT32 *texture_dst = &toolbar_bitmap.back()->pix32(0); - memcpy(texture_dst, toolbar_bitmap_bmp[x], 32 * 32 * sizeof(UINT32)); - if (toolbar_bitmap.back()->valid()) - toolbar_texture[x]->set_bitmap(*toolbar_bitmap.back(), toolbar_bitmap.back()->cliprect(), TEXFORMAT_ARGB32); - else - toolbar_bitmap.back()->reset(); - - if (x == 0 || x == 2) - { - texture_dst = &sw_toolbar_bitmap[x]->pix32(0); - memcpy(texture_dst, toolbar_bitmap_bmp[x], 32 * 32 * sizeof(UINT32)); - if (sw_toolbar_bitmap.back()->valid()) - sw_toolbar_texture[x]->set_bitmap(*sw_toolbar_bitmap.back(), sw_toolbar_bitmap.back()->cliprect(), TEXFORMAT_ARGB32); - else - sw_toolbar_bitmap.back()->reset(); - } - else - sw_toolbar_bitmap.back()->reset(); - - } -} - - -//------------------------------------------------- -// draw main menu -//------------------------------------------------- - -void menu::draw_select_game(UINT32 flags) -{ - bool noinput = (flags & PROCESS_NOINPUT); - float line_height = ui().get_line_height(); - float ud_arrow_width = line_height * machine().render().ui_aspect(); - float gutter_width = 0.52f * ud_arrow_width; - mouse_x = -1, mouse_y = -1; - float right_panel_size = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL) ? 2.0f * UI_BOX_LR_BORDER : 0.3f; - float visible_width = 1.0f - 4.0f * UI_BOX_LR_BORDER; - float primary_left = (1.0f - visible_width) * 0.5f; - float primary_width = visible_width; - bool is_swlist = (item[0].flags & FLAG_UI_SWLIST); - - // draw background image if available - if (ui().options().use_background_image() && bgrnd_bitmap->valid()) - container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - - hover = item.size() + 1; - visible_items = (is_swlist) ? item.size() - 2 : item.size() - 2 - skip_main_items; - float extra_height = (is_swlist) ? 2.0f * line_height : (2.0f + skip_main_items) * line_height; - float visible_extra_menu_height = customtop + custombottom + extra_height; - - // locate mouse - mouse_hit = false; - mouse_button = false; - if (!noinput) - { - mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); - if (mouse_target) - if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) - mouse_hit = true; - } - - // account for extra space at the top and bottom - float visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height; - m_visible_lines = int(std::trunc(visible_main_menu_height / line_height)); - visible_main_menu_height = float(m_visible_lines) * line_height; - - if (!is_swlist) - ui_globals::visible_main_lines = m_visible_lines; - else - ui_globals::visible_sw_lines = m_visible_lines; - - // compute top/left of inner menu area by centering - float visible_left = primary_left; - float visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f; - - // if the menu is at the bottom of the extra, adjust - visible_top += customtop; - - // compute left box size - float x1 = visible_left - UI_BOX_LR_BORDER; - float y1 = visible_top - UI_BOX_TB_BORDER; - float x2 = x1 + 2.0f * UI_BOX_LR_BORDER; - float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER + extra_height; - - // add left box - visible_left = draw_left_panel(x1, y1, x2, y2); - visible_width -= right_panel_size + visible_left - 2.0f * UI_BOX_LR_BORDER; - - // compute and add main box - x1 = visible_left - UI_BOX_LR_BORDER; - x2 = visible_left + visible_width + UI_BOX_LR_BORDER; - float line = visible_top + (float(m_visible_lines) * line_height); - ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); - - if (visible_items < m_visible_lines) - m_visible_lines = visible_items; - if (top_line < 0 || is_first_selected()) - top_line = 0; - if (selected < visible_items && top_line + m_visible_lines >= visible_items) - top_line = visible_items - m_visible_lines; - - // 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; - - if (m_prev_selected != nullptr && m_focus == focused_menu::main && selected < visible_items) - m_prev_selected = nullptr; - - int const n_loop = (std::min)(m_visible_lines, visible_items); - for (int linenum = 0; linenum < n_loop; linenum++) - { - float line_y = visible_top + (float)linenum * line_height; - int itemnum = top_line + linenum; - const menu_item &pitem = item[itemnum]; - const char *itemtext = pitem.text.c_str(); - rgb_t fgcolor = UI_TEXT_COLOR; - rgb_t bgcolor = UI_TEXT_BG_COLOR; - rgb_t fgcolor3 = UI_CLONE_COLOR; - float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float line_y0 = line_y; - float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float line_y1 = line_y + line_height; - - // set the hover if this is our item - if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) - hover = itemnum; - - // if we're selected, draw with a different background - if (itemnum == selected && m_focus == focused_menu::main) - { - fgcolor = rgb_t(0xff, 0xff, 0x00); - bgcolor = rgb_t(0xff, 0xff, 0xff); - fgcolor3 = rgb_t(0xcc, 0xcc, 0x00); - ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), - hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - } - // else if the mouse is over this item, draw with a different background - else if (itemnum == hover) - { - fgcolor = fgcolor3 = UI_MOUSEOVER_COLOR; - bgcolor = UI_MOUSEOVER_BG_COLOR; - highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); - } - else if (pitem.ref == m_prev_selected) - { - fgcolor = fgcolor3 = UI_MOUSEOVER_COLOR; - bgcolor = UI_MOUSEOVER_BG_COLOR; - ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), - hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - } - - if (linenum == 0 && top_line != 0) - { - // if we're on the top line, display the up arrow - draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0); - - if (hover == itemnum) - hover = HOVER_ARROW_UP; - } - else if (linenum == m_visible_lines - 1 && itemnum != visible_items - 1) - { - // if we're on the bottom line, display the down arrow - draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); - - if (hover == itemnum) - hover = HOVER_ARROW_DOWN; - } - else if (pitem.type == menu_item_type::SEPARATOR) - { - // if we're just a divider, draw a line - container->add_line(visible_left, line_y + 0.5f * line_height, visible_left + visible_width, line_y + 0.5f * line_height, - UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - } - else if (pitem.subtext.empty()) - { - // draw the item centered - int item_invert = pitem.flags & FLAG_INVERT; - auto icon = draw_icon(linenum, item[itemnum].ref, effective_left, line_y); - ui().draw_text_full(container, itemtext, effective_left + icon, line_y, effective_width - icon, ui::text_layout::LEFT, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); - } - else - { - auto item_invert = pitem.flags & FLAG_INVERT; - const char *subitem_text = pitem.subtext.c_str(); - float item_width, subitem_width; - - // compute right space for subitem - ui().draw_text_full(container, subitem_text, effective_left, line_y, ui().get_string_width(pitem.subtext.c_str()), - ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NONE, item_invert ? fgcolor3 : fgcolor, bgcolor, &subitem_width, nullptr); - subitem_width += gutter_width; - - // draw the item left-justified - ui().draw_text_full(container, itemtext, effective_left, line_y, effective_width - subitem_width, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, &item_width, nullptr); - - // draw the subitem right-justified - ui().draw_text_full(container, subitem_text, effective_left + item_width, line_y, effective_width - item_width, - ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); - } - } - - for (size_t count = visible_items; count < item.size(); count++) - { - const menu_item &pitem = item[count]; - const char *itemtext = pitem.text.c_str(); - float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float line_y0 = line; - float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float line_y1 = line + line_height; - rgb_t fgcolor = UI_TEXT_COLOR; - rgb_t bgcolor = UI_TEXT_BG_COLOR; - - if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) - hover = count; - - // if we're selected, draw with a different background - if (count == selected && m_focus == focused_menu::main) - { - fgcolor = rgb_t(0xff, 0xff, 0x00); - bgcolor = rgb_t(0xff, 0xff, 0xff); - ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), - hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - } - // else if the mouse is over this item, draw with a different background - else if (count == hover) - { - fgcolor = UI_MOUSEOVER_COLOR; - bgcolor = UI_MOUSEOVER_BG_COLOR; - highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); - } - - if (pitem.type == menu_item_type::SEPARATOR) - container->add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, - UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - else - ui().draw_text_full(container, itemtext, effective_left, line, effective_width, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); - line += line_height; - } - - x1 = x2; - x2 += right_panel_size; - - draw_right_panel(get_selection_ref(), x1, y1, x2, y2); - - x1 = primary_left - UI_BOX_LR_BORDER; - x2 = primary_left + primary_width + UI_BOX_LR_BORDER; - - // if there is something special to add, do it by calling the virtual method - custom_render(get_selection_ref(), customtop, custombottom, x1, y1, x2, y2); - - // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items); - - // reset redraw icon stage - if (!is_swlist) ui_globals::redraw_icon = false; - - // noinput - if (noinput) - { - int alpha = (1.0f - machine().options().pause_brightness()) * 255.0f; - if (alpha > 255) - alpha = 255; - if (alpha >= 0) - container->add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(alpha, 0x00, 0x00, 0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - } -} - -//------------------------------------------------- -// get title and search path for right panel -//------------------------------------------------- - -void menu::get_title_search(std::string &snaptext, std::string &searchstr) -{ - // get arts title text - snaptext.assign(_(arts_info[ui_globals::curimage_view].first)); - - // get search path - std::string addpath; - if (ui_globals::curimage_view == SNAPSHOT_VIEW) - { - emu_options moptions; - searchstr = machine().options().value(arts_info[ui_globals::curimage_view].second); - addpath = moptions.value(arts_info[ui_globals::curimage_view].second); - } - else - { - ui_options moptions; - searchstr = ui().options().value(arts_info[ui_globals::curimage_view].second); - addpath = moptions.value(arts_info[ui_globals::curimage_view].second); - } - - std::string tmp(searchstr); - path_iterator path(tmp.c_str()); - path_iterator path_iter(addpath.c_str()); - std::string c_path, curpath; - - // iterate over path and add path for zipped formats - while (path.next(curpath)) - { - path_iter.reset(); - while (path_iter.next(c_path)) - searchstr.append(";").append(curpath).append(PATH_SEPARATOR).append(c_path); - } -} - -//------------------------------------------------- -// handle keys for main menu -//------------------------------------------------- - -void menu::handle_main_keys(UINT32 flags) -{ - auto ignorepause = menu::stack_has_special_main_menu(); - - // bail if no items - if (item.size() == 0) - return; - - // if we hit select, return TRUE or pop the stack, depending on the item - if (exclusive_input_pressed(IPT_UI_SELECT, 0)) - { - if (is_last_selected() && m_focus == focused_menu::main) - { - m_event.iptkey = IPT_UI_CANCEL; - menu::stack_pop(machine()); - } - return; - } - - // hitting cancel also pops the stack - if (exclusive_input_pressed(IPT_UI_CANCEL, 0)) - { - if (!ui_error && !menu_has_search_active()) - menu::stack_pop(machine()); - return; - } - - // validate the current selection - validate_selection(1); - - // swallow left/right keys if they are not appropriate - bool ignoreleft = ((item[selected].flags & FLAG_LEFT_ARROW) == 0); - bool ignoreright = ((item[selected].flags & FLAG_RIGHT_ARROW) == 0); - bool leftclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL); - bool rightclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL); - - // accept left/right keys as-is with repeat - if (!ignoreleft && exclusive_input_pressed(IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) - { - // Swap the right panel - if (m_focus == focused_menu::righttop) - m_event.iptkey = IPT_UI_LEFT_PANEL; - return; - } - - if (!ignoreright && exclusive_input_pressed(IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) - { - // Swap the right panel - if (m_focus == focused_menu::righttop) - m_event.iptkey = IPT_UI_RIGHT_PANEL; - return; - } - - // up backs up by one item - if (exclusive_input_pressed(IPT_UI_UP, 6)) - { - // Filter - if (!leftclose && m_focus == focused_menu::left) - { - m_event.iptkey = IPT_UI_UP_FILTER; - return; - } - - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_UP_PANEL; - topline_datsview--; - return; - } - - if (selected == visible_items + 1 || is_first_selected() || ui_error) - return; - - selected--; - - if (selected == top_line && top_line != 0) - top_line--; - } - - // down advances by one item - if (exclusive_input_pressed(IPT_UI_DOWN, 6)) - { - // Filter - if (!leftclose && m_focus == focused_menu::left) - { - m_event.iptkey = IPT_UI_DOWN_FILTER; - return; - } - - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_DOWN_PANEL; - topline_datsview++; - return; - } - - if (is_last_selected() || selected == visible_items - 1 || ui_error) - return; - - selected++; - - if (selected == top_line + m_visible_items + (top_line != 0)) - top_line++; - } - - // page up backs up by m_visible_items - if (exclusive_input_pressed(IPT_UI_PAGE_UP, 6)) - { - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_DOWN_PANEL; - topline_datsview -= right_visible_lines - 1; - return; - } - - if (selected < visible_items && !ui_error) - { - selected -= m_visible_items; - - if (selected < 0) - selected = 0; - - top_line -= m_visible_items - (top_line + m_visible_lines == visible_items); - } - } - - // page down advances by m_visible_items - if (exclusive_input_pressed(IPT_UI_PAGE_DOWN, 6)) - { - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_DOWN_PANEL; - topline_datsview += right_visible_lines - 1; - return; - } - - if (selected < visible_items && !ui_error) - { - selected += m_visible_lines - 2 + (selected == 0); - - if (selected >= visible_items) - selected = visible_items - 1; - - top_line += m_visible_lines - 2; - } - } - - // home goes to the start - if (exclusive_input_pressed(IPT_UI_HOME, 0)) - { - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_DOWN_PANEL; - topline_datsview = 0; - return; - } - - if (selected < visible_items && !ui_error) - { - selected = 0; - top_line = 0; - } - } - - // end goes to the last - if (exclusive_input_pressed(IPT_UI_END, 0)) - { - // Infos - if (!rightclose && m_focus == focused_menu::rightbottom) - { - m_event.iptkey = IPT_UI_DOWN_PANEL; - topline_datsview = totallines; - return; - } - - if (selected < visible_items && !ui_error) - selected = top_line = visible_items - 1; - } - - // pause enables/disables pause - if (!ui_error && !ignorepause && exclusive_input_pressed(IPT_UI_PAUSE, 0)) - { - if (machine().paused()) - machine().resume(); - else - machine().pause(); - } - - // handle a toggle cheats request - if (!ui_error && machine().ui_input().pressed_repeat(IPT_UI_TOGGLE_CHEAT, 0)) - mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled()); - - // see if any other UI keys are pressed - if (m_event.iptkey == IPT_INVALID) - for (int code = IPT_UI_FIRST + 1; code < IPT_UI_LAST; code++) - { - if (ui_error || code == IPT_UI_CONFIGURE || (code == IPT_UI_LEFT && ignoreleft) || (code == IPT_UI_RIGHT && ignoreright) || (code == IPT_UI_PAUSE && ignorepause)) - continue; - - if (exclusive_input_pressed(code, 0)) - break; - } -} - -//------------------------------------------------- -// handle input events for main menu -//------------------------------------------------- - -void menu::handle_main_events() -{ - auto stop = false; - ui_event local_menu_event; - - if (m_pressed) - { - bool pressed = mouse_pressed(); - INT32 m_target_x, m_target_y; - bool m_button; - auto mouse_target = machine().ui_input().find_mouse(&m_target_x, &m_target_y, &m_button); - if (mouse_target && m_button && (hover == HOVER_ARROW_DOWN || hover == HOVER_ARROW_UP)) - { - if (pressed) - machine().ui_input().push_mouse_down_event(mouse_target, m_target_x, m_target_y); - } - else - reset_pressed(); - } - - // loop while we have interesting events - while (!stop && machine().ui_input().pop_event(&local_menu_event)) - { - switch (local_menu_event.event_type) - { - // if we are hovering over a valid item, select it with a single click - case UI_EVENT_MOUSE_DOWN: - { - if (ui_error) - { - m_event.iptkey = IPT_OTHER; - stop = true; - } - else - { - if (hover >= 0 && hover < item.size()) - { - if (hover >= visible_items - 1 && selected < visible_items) - m_prev_selected = item[selected].ref; - selected = hover; - m_focus = focused_menu::main; - } - else if (hover == HOVER_ARROW_UP) - { - selected -= m_visible_items; - if (selected < 0) - selected = 0; - top_line -= m_visible_items - (top_line + m_visible_lines == visible_items); - set_pressed(); - } - else if (hover == HOVER_ARROW_DOWN) - { - selected += m_visible_lines - 2 + (selected == 0); - if (selected >= visible_items) - selected = visible_items - 1; - top_line += m_visible_lines - 2; - set_pressed(); - } - else if (hover == HOVER_UI_RIGHT) - m_event.iptkey = IPT_UI_RIGHT; - else if (hover == HOVER_UI_LEFT) - m_event.iptkey = IPT_UI_LEFT; - else if (hover == HOVER_DAT_DOWN) - topline_datsview += right_visible_lines - 1; - else if (hover == HOVER_DAT_UP) - topline_datsview -= right_visible_lines - 1; - else if (hover == HOVER_LPANEL_ARROW) - { - if (ui_globals::panels_status == HIDE_LEFT_PANEL) - ui_globals::panels_status = SHOW_PANELS; - else if (ui_globals::panels_status == HIDE_BOTH) - ui_globals::panels_status = HIDE_RIGHT_PANEL; - else if (ui_globals::panels_status == SHOW_PANELS) - ui_globals::panels_status = HIDE_LEFT_PANEL; - else if (ui_globals::panels_status == HIDE_RIGHT_PANEL) - ui_globals::panels_status = HIDE_BOTH; - } - else if (hover == HOVER_RPANEL_ARROW) - { - if (ui_globals::panels_status == HIDE_RIGHT_PANEL) - ui_globals::panels_status = SHOW_PANELS; - else if (ui_globals::panels_status == HIDE_BOTH) - ui_globals::panels_status = HIDE_LEFT_PANEL; - else if (ui_globals::panels_status == SHOW_PANELS) - ui_globals::panels_status = HIDE_RIGHT_PANEL; - else if (ui_globals::panels_status == HIDE_LEFT_PANEL) - ui_globals::panels_status = HIDE_BOTH; - } - else if (hover == HOVER_B_FAV) - { - m_event.iptkey = IPT_UI_FAVORITES; - stop = true; - } - else if (hover == HOVER_B_EXPORT) - { - m_event.iptkey = IPT_UI_EXPORT; - stop = true; - } - else if (hover == HOVER_B_DATS) - { - m_event.iptkey = IPT_UI_DATS; - stop = true; - } - else if (hover >= HOVER_RP_FIRST && hover <= HOVER_RP_LAST) - { - ui_globals::rpanel = (HOVER_RP_FIRST - hover) * (-1); - stop = true; - } - else if (hover >= HOVER_SW_FILTER_FIRST && hover <= HOVER_SW_FILTER_LAST) - { - l_sw_hover = (HOVER_SW_FILTER_FIRST - hover) * (-1); - m_event.iptkey = IPT_OTHER; - stop = true; - } - else if (hover >= HOVER_FILTER_FIRST && hover <= HOVER_FILTER_LAST) - { - l_hover = (HOVER_FILTER_FIRST - hover) * (-1); - m_event.iptkey = IPT_OTHER; - stop = true; - } - } - break; - } - - // if we are hovering over a valid item, fake a UI_SELECT with a double-click - case UI_EVENT_MOUSE_DOUBLE_CLICK: - if (hover >= 0 && hover < item.size()) - { - selected = hover; - m_event.iptkey = IPT_UI_SELECT; - } - - if (selected == item.size() - 1) - { - m_event.iptkey = IPT_UI_CANCEL; - menu::stack_pop(machine()); - } - stop = true; - break; - - // caught scroll event - case UI_EVENT_MOUSE_WHEEL: - if (hover >= 0 && hover < item.size() - skip_main_items - 1) - { - if (local_menu_event.zdelta > 0) - { - if (selected >= visible_items || selected == 0 || ui_error) - break; - selected -= local_menu_event.num_lines; - if (selected < top_line + (top_line != 0)) - top_line -= local_menu_event.num_lines; - } - else - { - if (selected >= visible_items - 1 || ui_error) - break; - selected += local_menu_event.num_lines; - if (selected > visible_items - 1) - selected = visible_items - 1; - if (selected >= top_line + m_visible_items + (top_line != 0)) - top_line += local_menu_event.num_lines; - } - } - break; - - // translate CHAR events into specials - case UI_EVENT_CHAR: - if (exclusive_input_pressed(IPT_UI_CONFIGURE, 0)) - { - m_event.iptkey = IPT_UI_CONFIGURE; - stop = true; - } - else - { - m_event.iptkey = IPT_SPECIAL; - m_event.unichar = local_menu_event.ch; - stop = true; - } - break; - - case UI_EVENT_MOUSE_RDOWN: - if (hover >= 0 && hover < item.size() - skip_main_items - 1) - { - selected = hover; - m_prev_selected = item[selected].ref; - m_focus = focused_menu::main; - m_event.iptkey = IPT_CUSTOM; - m_event.mouse.x0 = local_menu_event.mouse_x; - m_event.mouse.y0 = local_menu_event.mouse_y; - stop = true; - } - break; - - // ignore everything else - default: - break; - } - } -} - -//------------------------------------------------- -// draw right box title -//------------------------------------------------- - -float menu::draw_right_box_title(float x1, float y1, float x2, float y2) -{ - auto line_height = ui().get_line_height(); - float midl = (x2 - x1) * 0.5f; - - // add outlined box for options - ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); - - // add separator line - container->add_line(x1 + midl, y1, x1 + midl, y1 + line_height, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - - std::string buffer[RP_LAST + 1]; - buffer[RP_IMAGES] = _("Images"); - buffer[RP_INFOS] = _("Infos"); - - // check size - float text_size = 1.0f; - for (auto & elem : buffer) - { - auto textlen = ui().get_string_width(elem.c_str()) + 0.01f; - float tmp_size = (textlen > midl) ? (midl / textlen) : 1.0f; - text_size = MIN(text_size, tmp_size); - } - - for (int cells = RP_FIRST; cells <= RP_LAST; ++cells) - { - rgb_t bgcolor = UI_TEXT_BG_COLOR; - rgb_t fgcolor = UI_TEXT_COLOR; - - if (mouse_hit && x1 <= mouse_x && x1 + midl > mouse_x && y1 <= mouse_y && y1 + line_height > mouse_y) - { - if (ui_globals::rpanel != cells) - { - bgcolor = UI_MOUSEOVER_BG_COLOR; - fgcolor = UI_MOUSEOVER_COLOR; - hover = HOVER_RP_FIRST + cells; - } - } - - if (ui_globals::rpanel != cells) - { - container->add_line(x1, y1 + line_height, x1 + midl, y1 + line_height, UI_LINE_WIDTH, - UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - if (fgcolor != UI_MOUSEOVER_COLOR) - fgcolor = UI_CLONE_COLOR; - } - - if (m_focus == focused_menu::righttop && ui_globals::rpanel == cells) - { - fgcolor = rgb_t(0xff, 0xff, 0x00); - bgcolor = rgb_t(0xff, 0xff, 0xff); - ui().draw_textured_box(container, x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, - bgcolor, rgb_t(43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - } - else if (bgcolor == UI_MOUSEOVER_BG_COLOR) - container->add_rect(x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, - bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - - ui().draw_text_full(container, buffer[cells].c_str(), x1 + UI_LINE_WIDTH, y1, midl - UI_LINE_WIDTH, - ui::text_layout::CENTER, ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); - x1 += midl; - } - - return (y1 + line_height + UI_LINE_WIDTH); } -//------------------------------------------------- -// common function for images render -//------------------------------------------------- - -std::string menu::arts_render_common(float origx1, float origy1, float origx2, float origy2) -{ - auto line_height = ui().get_line_height(); - std::string snaptext, searchstr; - auto title_size = 0.0f; - auto txt_lenght = 0.0f; - auto gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f; - - get_title_search(snaptext, searchstr); - - // apply title to right panel - for (int x = FIRST_VIEW; x < LAST_VIEW; x++) - { - ui().draw_text_full(container, _(arts_info[x].first), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, - ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white, rgb_t::black, &txt_lenght, nullptr); - txt_lenght += 0.01f; - title_size = MAX(txt_lenght, title_size); - } - - rgb_t fgcolor = (m_focus == focused_menu::rightbottom) ? rgb_t(0xff, 0xff, 0x00) : UI_TEXT_COLOR; - rgb_t bgcolor = (m_focus == focused_menu::rightbottom) ? rgb_t(0xff, 0xff, 0xff) : UI_TEXT_BG_COLOR; - float middle = origx2 - origx1; - - // check size - float sc = title_size + 2.0f * gutter_width; - float tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f; - title_size *= tmp_size; - - if (bgcolor != UI_TEXT_BG_COLOR) - ui().draw_textured_box(container, origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f), - origy1 + line_height, bgcolor, rgb_t(43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); - - ui().draw_text_full(container, snaptext.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size); - - draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::curimage_view, FIRST_VIEW, LAST_VIEW, title_size); - - return searchstr; -} - -//------------------------------------------------- -// draw favorites star -//------------------------------------------------- - -void menu::draw_star(float x0, float y0) -{ - float y1 = y0 + ui().get_line_height(); - float x1 = x0 + ui().get_line_height() * container->manager().ui_aspect(); - container->add_quad(x0, y0, x1, y1, rgb_t::white, star_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE); -} - -//------------------------------------------------- -// draw toolbar -//------------------------------------------------- - -void menu::draw_toolbar(float x1, float y1, float x2, float y2, bool software) -{ - // draw a box - ui().draw_outlined_box(container, x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); - - // take off the borders - x1 += UI_BOX_LR_BORDER; - x2 -= UI_BOX_LR_BORDER; - y1 += UI_BOX_TB_BORDER; - y2 -= UI_BOX_TB_BORDER; - - render_texture **t_texture = (software) ? sw_toolbar_texture : toolbar_texture; - auto t_bitmap = (software) ? sw_toolbar_bitmap : toolbar_bitmap; - - int m_valid = 0; - for (auto & e : t_bitmap) - if (e->valid()) m_valid++; - - float space_x = (y2 - y1) * container->manager().ui_aspect(container); - auto total = (float)(m_valid * space_x) + ((float)(m_valid - 1) * 0.001f); - x1 += (x2 - x1) * 0.5f - total * 0.5f; - x2 = x1 + space_x; - - for (int z = 0; z < UI_TOOLBAR_BUTTONS; ++z) - if (t_bitmap[z]->valid()) - { - rgb_t color(0xEFEFEFEF); - if (mouse_hit && x1 <= mouse_x && x2 > mouse_x && y1 <= mouse_y && y2 > mouse_y) - { - hover = HOVER_B_FAV + z; - color = rgb_t::white; - float ypos = y2 + ui().get_line_height() + 2.0f * UI_BOX_TB_BORDER; - ui().draw_text_box(container, _(hover_msg[z]), ui::text_layout::CENTER, 0.5f, ypos, UI_BACKGROUND_COLOR); - } - - container->add_quad(x1, y1, x2, y2, color, t_texture[z], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - x1 += space_x + ((z < UI_TOOLBAR_BUTTONS - 1) ? 0.001f : 0.0f); - x2 = x1 + space_x; - } -} - - -//------------------------------------------------- -// perform rendering of image -//------------------------------------------------- - -void menu::arts_render_images(bitmap_argb32 *tmp_bitmap, float origx1, float origy1, float origx2, float origy2) -{ - bool no_available = false; - float line_height = ui().get_line_height(); - - // if it fails, use the default image - if (!tmp_bitmap->valid()) - { - tmp_bitmap->allocate(256, 256); - for (int x = 0; x < 256; x++) - for (int y = 0; y < 256; y++) - tmp_bitmap->pix32(y, x) = no_avail_bitmap->pix32(y, x); - no_available = true; - } - - if (tmp_bitmap->valid()) - { - float panel_width = origx2 - origx1 - 0.02f; - float panel_height = origy2 - origy1 - 0.02f - (2.0f * UI_BOX_TB_BORDER) - (2.0f * line_height); - int screen_width = machine().render().ui_target().width(); - int screen_height = machine().render().ui_target().height(); - - if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY) - std::swap(screen_height, screen_width); - - int panel_width_pixel = panel_width * screen_width; - int panel_height_pixel = panel_height * screen_height; - - // Calculate resize ratios for resizing - auto ratioW = (float)panel_width_pixel / tmp_bitmap->width(); - auto ratioH = (float)panel_height_pixel / tmp_bitmap->height(); - auto ratioI = (float)tmp_bitmap->height() / tmp_bitmap->width(); - auto dest_xPixel = tmp_bitmap->width(); - auto dest_yPixel = tmp_bitmap->height(); - - // force 4:3 ratio min - if (ui().options().forced_4x3_snapshot() && ratioI < 0.75f && ui_globals::curimage_view == SNAPSHOT_VIEW) - { - // smaller ratio will ensure that the image fits in the view - dest_yPixel = tmp_bitmap->width() * 0.75f; - ratioH = (float)panel_height_pixel / dest_yPixel; - float ratio = MIN(ratioW, ratioH); - dest_xPixel = tmp_bitmap->width() * ratio; - dest_yPixel *= ratio; - } - // resize the bitmap if necessary - else if (ratioW < 1 || ratioH < 1 || (ui().options().enlarge_snaps() && !no_available)) - { - // smaller ratio will ensure that the image fits in the view - float ratio = MIN(ratioW, ratioH); - dest_xPixel = tmp_bitmap->width() * ratio; - dest_yPixel = tmp_bitmap->height() * ratio; - } - - bitmap_argb32 *dest_bitmap; - - // resample if necessary - if (dest_xPixel != tmp_bitmap->width() || dest_yPixel != tmp_bitmap->height()) - { - dest_bitmap = auto_alloc(machine(), bitmap_argb32); - dest_bitmap->allocate(dest_xPixel, dest_yPixel); - render_color color = { 1.0f, 1.0f, 1.0f, 1.0f }; - render_resample_argb_bitmap_hq(*dest_bitmap, *tmp_bitmap, color, true); - } - else - dest_bitmap = tmp_bitmap; - - snapx_bitmap->allocate(panel_width_pixel, panel_height_pixel); - int x1 = (0.5f * panel_width_pixel) - (0.5f * dest_xPixel); - int y1 = (0.5f * panel_height_pixel) - (0.5f * dest_yPixel); - - for (int x = 0; x < dest_xPixel; x++) - for (int y = 0; y < dest_yPixel; y++) - snapx_bitmap->pix32(y + y1, x + x1) = dest_bitmap->pix32(y, x); - - auto_free(machine(), dest_bitmap); - - // apply bitmap - snapx_texture->set_bitmap(*snapx_bitmap, snapx_bitmap->cliprect(), TEXFORMAT_ARGB32); - } - else - snapx_bitmap->reset(); -} //------------------------------------------------- // draw common arrows @@ -2421,125 +1354,6 @@ void menu::draw_common_arrow(float origx1, float origy1, float origx2, float ori } //------------------------------------------------- -// draw icons -//------------------------------------------------- - -float menu::draw_icon(int linenum, void *selectedref, float x0, float y0) -{ - if (!ui_globals::has_icons || (item[0].flags & FLAG_UI_SWLIST)) - return 0.0f; - - float ud_arrow_width = ui().get_line_height() * container->manager().ui_aspect(container); - const game_driver *driver = nullptr; - - if (item[0].flags & FLAG_UI_FAVORITE) - { - ui_software_info *soft = (ui_software_info *)selectedref; - if (soft->startempty == 1) - driver = soft->driver; - } - else - driver = (const game_driver *)selectedref; - - auto x1 = x0 + ud_arrow_width; - auto y1 = y0 + ui().get_line_height(); - - if (m_old_icons[linenum] != driver || ui_globals::redraw_icon) - { - m_old_icons[linenum] = driver; - - // set clone status - bool cloneof = strcmp(driver->parent, "0"); - if (cloneof) - { - auto cx = driver_list::find(driver->parent); - if (cx != -1 && ((driver_list::driver(cx).flags & MACHINE_IS_BIOS_ROOT) != 0)) - cloneof = false; - } - - // get search path - path_iterator path(ui().options().icons_directory()); - std::string curpath; - std::string searchstr(ui().options().icons_directory()); - - // iterate over path and add path for zipped formats - while (path.next(curpath)) - searchstr.append(";").append(curpath.c_str()).append(PATH_SEPARATOR).append("icons"); - - bitmap_argb32 *tmp = auto_alloc(machine(), bitmap_argb32); - emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ); - std::string fullname = std::string(driver->name).append(".ico"); - render_load_ico(*tmp, snapfile, nullptr, fullname.c_str()); - - if (!tmp->valid() && cloneof) - { - fullname.assign(driver->parent).append(".ico"); - render_load_ico(*tmp, snapfile, nullptr, fullname.c_str()); - } - - if (tmp->valid()) - { - float panel_width = x1 - x0; - float panel_height = y1 - y0; - auto screen_width = machine().render().ui_target().width(); - auto screen_height = machine().render().ui_target().height(); - - if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY) - std::swap(screen_height, screen_width); - - int panel_width_pixel = panel_width * screen_width; - int panel_height_pixel = panel_height * screen_height; - - // Calculate resize ratios for resizing - auto ratioW = (float)panel_width_pixel / tmp->width(); - auto ratioH = (float)panel_height_pixel / tmp->height(); - auto dest_xPixel = tmp->width(); - auto dest_yPixel = tmp->height(); - - if (ratioW < 1 || ratioH < 1) - { - // smaller ratio will ensure that the image fits in the view - float ratio = MIN(ratioW, ratioH); - dest_xPixel = tmp->width() * ratio; - dest_yPixel = tmp->height() * ratio; - } - - bitmap_argb32 *dest_bitmap; - dest_bitmap = auto_alloc(machine(), bitmap_argb32); - - // resample if necessary - if (dest_xPixel != tmp->width() || dest_yPixel != tmp->height()) - { - dest_bitmap->allocate(dest_xPixel, dest_yPixel); - render_color color = { 1.0f, 1.0f, 1.0f, 1.0f }; - render_resample_argb_bitmap_hq(*dest_bitmap, *tmp, color, true); - } - else - dest_bitmap = tmp; - - icons_bitmap[linenum]->allocate(panel_width_pixel, panel_height_pixel); - - for (int x = 0; x < dest_xPixel; x++) - for (int y = 0; y < dest_yPixel; y++) - icons_bitmap[linenum]->pix32(y, x) = dest_bitmap->pix32(y, x); - - auto_free(machine(), dest_bitmap); - - icons_texture[linenum]->set_bitmap(*icons_bitmap[linenum], icons_bitmap[linenum]->cliprect(), TEXFORMAT_ARGB32); - } - else if (icons_bitmap[linenum] != nullptr) - icons_bitmap[linenum]->reset(); - - auto_free(machine(), tmp); - } - - if (icons_bitmap[linenum] != nullptr && icons_bitmap[linenum]->valid()) - container->add_quad(x0, y0, x1, y1, rgb_t::white, icons_texture[linenum], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - - return ud_arrow_width * 1.5f; -} - -//------------------------------------------------- // draw info arrow //------------------------------------------------- @@ -2572,8 +1386,8 @@ void menu::draw_palette_menu() auto gutter_width = lr_arrow_width * 1.3f; int itemnum, linenum; - if (ui().options().use_background_image() && &machine().system() == &GAME_NAME(___empty) && bgrnd_bitmap->valid()) - container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + if (&machine().system() == &GAME_NAME(___empty)) + draw_background(); // compute the width and height of the full menu auto visible_width = 0.0f; @@ -2747,156 +1561,6 @@ void menu::draw_palette_menu() } //------------------------------------------------- -// draw - draw dats menu -//------------------------------------------------- - -void menu::draw_dats_menu() -{ - auto line_height = ui().get_line_height(); - auto ud_arrow_width = line_height * machine().render().ui_aspect(); - auto gutter_width = 0.52f * line_height * machine().render().ui_aspect(); - mouse_x = -1, mouse_y = -1; - float visible_width = 1.0f - 2.0f * UI_BOX_LR_BORDER; - float visible_left = (1.0f - visible_width) * 0.5f; - - // draw background image if available - if (ui().options().use_background_image() && bgrnd_bitmap->valid()) - container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - - hover = item.size() + 1; - visible_items = item.size() - 2; - float extra_height = 2.0f * line_height; - float visible_extra_menu_height = customtop + custombottom + extra_height; - - // locate mouse - mouse_hit = false; - mouse_button = false; - mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); - if (mouse_target != nullptr) - if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) - mouse_hit = true; - - // account for extra space at the top and bottom - float visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height; - m_visible_lines = int(std::trunc(visible_main_menu_height / line_height)); - visible_main_menu_height = float(m_visible_lines) * line_height; - - // compute top/left of inner menu area by centering - float visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f; - - // if the menu is at the bottom of the extra, adjust - visible_top += customtop; - - // compute left box size - float x1 = visible_left; - float y1 = visible_top - UI_BOX_TB_BORDER; - float x2 = x1 + visible_width; - float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER + extra_height; - float line = visible_top + float(m_visible_lines) * line_height; - - ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); - - m_visible_lines = (std::min)(visible_items, m_visible_lines); - top_line = (std::max)(0, top_line); - if (top_line + m_visible_lines >= visible_items) - top_line = visible_items - m_visible_lines; - - // 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; - - int const n_loop = (std::min)(visible_items, m_visible_lines); - for (int linenum = 0; linenum < n_loop; linenum++) - { - float line_y = visible_top + (float)linenum * line_height; - int itemnum = top_line + linenum; - const menu_item &pitem = item[itemnum]; - const char *itemtext = pitem.text.c_str(); - rgb_t fgcolor = UI_TEXT_COLOR; - rgb_t bgcolor = UI_TEXT_BG_COLOR; - float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float line_y0 = line_y; - float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float line_y1 = line_y + line_height; - - // if we're on the top line, display the up arrow - if (linenum == 0 && top_line != 0) - { - draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0); - - if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y) - { - fgcolor = UI_MOUSEOVER_COLOR; - bgcolor = UI_MOUSEOVER_BG_COLOR; - highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); - hover = HOVER_ARROW_UP; - } - } - // if we're on the bottom line, display the down arrow - else if (linenum == m_visible_lines - 1 && itemnum != visible_items - 1) - { - draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); - - if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y) - { - fgcolor = UI_MOUSEOVER_COLOR; - bgcolor = UI_MOUSEOVER_BG_COLOR; - highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); - hover = HOVER_ARROW_DOWN; - } - } - - // draw dats text - else if (pitem.subtext.empty()) - { - ui().draw_text_full(container, itemtext, effective_left, line_y, effective_width, ui::text_layout::LEFT, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); - } - } - - for (size_t count = visible_items; count < item.size(); count++) - { - const menu_item &pitem = item[count]; - const char *itemtext = pitem.text.c_str(); - float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float line_y0 = line; - float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float line_y1 = line + line_height; - rgb_t fgcolor = UI_SELECTED_COLOR; - rgb_t bgcolor = UI_SELECTED_BG_COLOR; - - if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) - hover = count; - - if (pitem.type == menu_item_type::SEPARATOR) - container->add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, - UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - else - { - highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); - ui().draw_text_full(container, itemtext, effective_left, line, effective_width, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); - } - line += line_height; - } - - // if there is something special to add, do it by calling the virtual method - custom_render(get_selection_ref(), customtop, custombottom, x1, y1, x2, y2); - - // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items); -} - -void menu::set_pressed() -{ - (m_repeat == 0) ? m_repeat = osd_ticks() + osd_ticks_per_second() / 2 : m_repeat = osd_ticks() + osd_ticks_per_second() / 4; - m_pressed = true; -} - - -//------------------------------------------------- // extra_text_draw_box - generically adds header // or footer text //------------------------------------------------- @@ -2923,6 +1587,14 @@ void menu::extra_text_draw_box(float origx1, float origx2, float origy, float ys } +void menu::draw_background() +{ + // draw background image if available + if (ui().options().use_background_image() && m_global_state->bgrnd_bitmap() && m_global_state->bgrnd_bitmap()->valid()) + container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, m_global_state->bgrnd_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + + //------------------------------------------------- // extra_text_position - given extra text that has // been put into a layout, position it diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h index 7c292a22753..d0df364d3fe 100644 --- a/src/frontend/mame/ui/menu.h +++ b/src/frontend/mame/ui/menu.h @@ -8,18 +8,21 @@ ***************************************************************************/ -#pragma once - #ifndef MAME_FRONTEND_UI_MENU_H #define MAME_FRONTEND_UI_MENU_H +#pragma once + #include "ui/ui.h" #include "ui/menuitem.h" #include "language.h" #include "render.h" +#include <functional> +#include <map> #include <memory> +#include <mutex> namespace ui { @@ -39,9 +42,7 @@ public: FLAG_MULTILINE = (1 << 3), FLAG_REDTEXT = (1 << 4), FLAG_DISABLE = (1 << 5), - FLAG_UI = (1 << 6), FLAG_UI_DATS = (1 << 7), - FLAG_UI_SWLIST = (1 << 8), FLAG_UI_FAVORITE = (1 << 9), FLAG_UI_PALETTE = (1 << 10), FLAG_UI_HEADING = (1 << 11) @@ -72,10 +73,9 @@ public: // Global initialization static void init(running_machine &machine, ui_options &mopt); - static void exit(running_machine &machine); // reset the menus, clearing everything - static void stack_reset(running_machine &machine); + static void stack_reset(running_machine &machine) { get_global_state(machine)->stack_reset(); } // push a new menu onto the stack template <typename T, typename... Params> @@ -92,17 +92,14 @@ public: } // pop a menu from the stack - static void stack_pop(running_machine &machine); + static void stack_pop(running_machine &machine) { get_global_state(machine)->stack_pop(); } // test if one of the menus in the stack requires hide disable - static bool stack_has_special_main_menu(); + static bool stack_has_special_main_menu(running_machine &machine) { return get_global_state(machine)->stack_has_special_main_menu(); } // highlight static void highlight(render_container *container, float x0, float y0, float x1, float y1, rgb_t bgcolor); - // draw arrow - static void draw_arrow(render_container *container, float x0, float y0, float x1, float y1, rgb_t fgcolor, UINT32 orientation); - // master handler static UINT32 ui_handler(render_container *container, mame_ui_manager &mui); @@ -122,41 +119,28 @@ public: private: static std::unique_ptr<bitmap_rgb32> hilight_bitmap; - static render_texture *hilight_texture, *arrow_texture; + static render_texture *hilight_texture; - void draw(UINT32 flags, float x0 = 0.0f, float y0 = 0.0f); + virtual void draw(UINT32 flags); void draw_text_box(); - void handle_events(UINT32 flags); - void handle_keys(UINT32 flags); - inline bool exclusive_input_pressed(int key, int repeat); - static void clear_free_list(running_machine &machine); static void render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param); public: void *m_prev_selected; - int visible_items; - bool ui_error; - // mouse handling bool mouse_hit, mouse_button; render_target *mouse_target; INT32 mouse_target_x, mouse_target_y; float mouse_x, mouse_y; - // draw toolbar - void draw_toolbar(float x1, float y1, float x2, float y2, bool software = false); - // draw left panel virtual float draw_left_panel(float x1, float y1, float x2, float y2) { return 0; } // draw right panel virtual void draw_right_panel(void *selectedref, float origx1, float origy1, float origx2, float origy2) { }; - // draw star - void draw_star(float x0, float y0); - // Global initialization static void init_ui(running_machine &machine, ui_options &mopt); @@ -171,6 +155,10 @@ public: } protected: + using cleanup_callback = std::function<void(running_machine &)>; + using bitmap_ptr = std::unique_ptr<bitmap_argb32>; + using texture_ptr = std::unique_ptr<render_texture, std::function<void(render_texture *)> >; + // flags to pass to process enum { @@ -190,15 +178,6 @@ protected: REMEMBER_REF }; - // tab navigation - enum class focused_menu - { - main, - left, - righttop, - rightbottom - }; - // menu-related events struct event { @@ -234,27 +213,33 @@ protected: } }; - int topline_datsview; // right box top line - int top_line; // main box top line + int top_line; // main box top line int l_sw_hover; int l_hover; - int totallines; int skip_main_items; - int selected; // which item is selected + int selected; // which item is selected + + int m_visible_lines; // main box visible lines + int m_visible_items; // number of visible items menu(mame_ui_manager &mui, render_container *container); void reset(reset_options options); void reset_parent(reset_options options) { m_parent->reset(options); } - static void reset_topmost(reset_options options) { if (menu_stack) menu_stack->reset(options); } + void reset_topmost(reset_options options) { m_global_state->reset_topmost(options); } + + template <typename T> T *topmost_menu() const { return m_global_state->topmost_menu<T>(); } + template <typename T> static T *topmost_menu(running_machine &machine) { return get_global_state(machine)->topmost_menu<T>(); } + void stack_pop() { m_global_state->stack_pop(); } + void stack_reset() { m_global_state->stack_reset(); } + bool stack_has_special_main_menu() const { return m_global_state->stack_has_special_main_menu(); } + + void add_cleanup_callback(cleanup_callback &&callback) { m_global_state->add_cleanup_callback(std::move(callback)); } // process a menu, drawing it and returning any interesting events const event *process(UINT32 flags, float x0 = 0.0f, float y0 = 0.0f); void process_parent() { m_parent->process(PROCESS_NOINPUT); } - focused_menu get_focus() const { return m_focus; } - void set_focus(focused_menu focus) { m_focus = focus; } - // retrieves the ref of the currently selected menu item or nullptr void *get_selection_ref() const { return selection_valid() ? item[selected].ref : nullptr; } bool selection_valid() const { return (0 <= selected) && (item.size() > selected); } @@ -267,37 +252,81 @@ protected: // scroll position control void centre_selection() { top_line = selected - (m_visible_lines / 2); } - // draw right box - float draw_right_box_title(float x1, float y1, float x2, float y2); + // test if the given key is pressed and we haven't already reported a key + bool exclusive_input_pressed(int &iptkey, int key, int repeat); // draw arrow + void draw_arrow(render_container *container, float x0, float y0, float x1, float y1, rgb_t fgcolor, UINT32 orientation); void draw_common_arrow(float origx1, float origy1, float origx2, float origy2, int current, int dmin, int dmax, float title); void info_arrow(int ub, float origx1, float origx2, float oy1, float line_height, float text_size, float ud_arrow_width); - // images render - std::string arts_render_common(float origx1, float origy1, float origx2, float origy2); - void arts_render_images(bitmap_argb32 *bitmap, float origx1, float origy1, float origx2, float origy2); - // draw header and footer text void extra_text_render(float top, float bottom, float origx1, float origy1, float origx2, float origy2, const char *header, const char *footer); void extra_text_position(float origx1, float origx2, float origy, float yspan, text_layout &layout, int direction, float &x1, float &y1, float &x2, float &y2); - // custom events + void draw_background(); + + // overridable event handling + virtual void handle_events(UINT32 flags, event &ev); + virtual void handle_keys(UINT32 flags, int &iptkey); virtual bool custom_mouse_down() { return false; } - template <typename T> - static T *topmost_menu() { return dynamic_cast<T *>(menu_stack.get()); } + static bool is_selectable(menu_item const &item) + { + return ((item.flags & (menu::FLAG_MULTILINE | menu::FLAG_DISABLE)) == 0 && item.type != menu_item_type::SEPARATOR); + } int right_visible_lines; // right box lines - static std::unique_ptr<bitmap_argb32> snapx_bitmap; + static bitmap_ptr snapx_bitmap; static render_texture *snapx_texture; static std::unique_ptr<bitmap_rgb32> hilight_main_bitmap; static render_texture *hilight_main_texture; private: + class global_state + { + public: + global_state(running_machine &machine, ui_options const &options); + global_state(global_state const &) = delete; + global_state(global_state &&) = delete; + ~global_state(); + + void add_cleanup_callback(cleanup_callback &&callback); + + render_texture * arrow_texture() { return m_arrow_texture.get(); } + bitmap_argb32 *bgrnd_bitmap() { return m_bgrnd_bitmap.get(); } + render_texture * bgrnd_texture() { return m_bgrnd_texture.get(); } + + void reset_topmost(reset_options options) { if (m_stack) m_stack->reset(options); } + + template <typename T> + T *topmost_menu() const { return dynamic_cast<T *>(m_stack.get()); } + + void stack_push(std::unique_ptr<menu> &&menu); + void stack_pop(); + void stack_reset(); + void clear_free_list(); + bool stack_has_special_main_menu() const; + + private: + using cleanup_callback_vector = std::vector<cleanup_callback>; + + running_machine &m_machine; + cleanup_callback_vector m_cleanup_callbacks; + + texture_ptr m_arrow_texture; + bitmap_ptr m_bgrnd_bitmap; + texture_ptr m_bgrnd_texture; + + std::unique_ptr<menu> m_stack; + std::unique_ptr<menu> m_free; + }; + using global_state_ptr = std::shared_ptr<global_state>; + using global_state_map = std::map<running_machine *, global_state_ptr>; + struct pool { pool *next; // chain to next one @@ -305,69 +334,36 @@ private: UINT8 *end; // end of the pool }; - - void reset_pressed() { m_pressed = false; m_repeat = 0; } - bool mouse_pressed() { return (osd_ticks() >= m_repeat); } - void set_pressed(); - - static std::unique_ptr<bitmap_argb32> no_avail_bitmap, bgrnd_bitmap, star_bitmap; - static render_texture *bgrnd_texture, *star_texture; - static std::vector<std::unique_ptr<bitmap_argb32>> icons_bitmap; - static render_texture *icons_texture[]; - // request the specific handling of the game selection main menu bool is_special_main_menu() const; void set_special_main_menu(bool disable); // push a new menu onto the stack - static void stack_push(std::unique_ptr<menu> &&menu); - - // toolbar - static std::vector<std::shared_ptr<bitmap_argb32>> toolbar_bitmap, sw_toolbar_bitmap; - static render_texture *toolbar_texture[], *sw_toolbar_texture[]; - - // draw game list - void draw_select_game(UINT32 flags); + static void stack_push(std::unique_ptr<menu> &&menu) { get_global_state(menu->machine())->stack_push(std::move(menu)); } // draw palette menu void draw_palette_menu(); - // draw dats menu - void draw_dats_menu(); - - void get_title_search(std::string &title, std::string &search); - - // handle keys - void handle_main_keys(UINT32 flags); - - // handle mouse - void handle_main_events(); - - float draw_icon(int linenum, void *selectedref, float x1, float y1); void extra_text_draw_box(float origx1, float origx2, float origy, float yspan, const char *text, int direction); bool first_item_visible() const { return top_line <= 0; } bool last_item_visible() const { return (top_line + m_visible_lines) >= item.size(); } + static void exit(running_machine &machine); + static global_state_ptr get_global_state(running_machine &machine); + + global_state_ptr const m_global_state; bool m_special_main_menu; mame_ui_manager &m_ui; // UI we are attached to std::unique_ptr<menu> m_parent; // pointer to parent menu - bool m_pressed; // mouse button held down - osd_ticks_t m_repeat; event m_event; // the UI event that occurred pool *m_pool; // list of memory pools - focused_menu m_focus; - - int m_visible_lines; // main box visible lines - int m_visible_items; // number of visible items int m_resetpos; // reset position void *m_resetref; // reset reference - static std::vector<const game_driver *> m_old_icons; - - static std::unique_ptr<menu> menu_stack; - static std::unique_ptr<menu> menu_free; + static std::mutex s_global_state_guard; + static global_state_map s_global_states; }; } // namespace ui diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 25f18f7aacc..62c04b98cff 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -548,7 +548,7 @@ void menu_quit_game::handle() machine().schedule_exit(); /* reset the menu stack */ - menu::stack_reset(machine()); + stack_reset(); } //------------------------------------------------- diff --git a/src/frontend/mame/ui/selector.cpp b/src/frontend/mame/ui/selector.cpp index f5f07c0c2b3..236ce06f672 100644 --- a/src/frontend/mame/ui/selector.cpp +++ b/src/frontend/mame/ui/selector.cpp @@ -95,7 +95,7 @@ void menu_selector::handle() } ui_globals::switch_image = true; - menu::stack_pop(machine()); + stack_pop(); } else if (menu_event->iptkey == IPT_SPECIAL) { diff --git a/src/frontend/mame/ui/selgame.cpp b/src/frontend/mame/ui/selgame.cpp index 992cab5c758..6f451a3018e 100644 --- a/src/frontend/mame/ui/selgame.cpp +++ b/src/frontend/mame/ui/selgame.cpp @@ -55,7 +55,8 @@ int menu_select_game::m_isabios = 0; // ctor //------------------------------------------------- -menu_select_game::menu_select_game(mame_ui_manager &mui, render_container *container, const char *gamename) : menu(mui, container) +menu_select_game::menu_select_game(mame_ui_manager &mui, render_container *container, const char *gamename) + : menu_select_launch(mui, container, false) { set_focus(focused_menu::main); highlight = 0; @@ -184,7 +185,7 @@ void menu_select_game::handle() { ui_globals::reset = false; machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); return; } @@ -203,10 +204,10 @@ void menu_select_game::handle() const event *menu_event = process(PROCESS_LR_REPEAT); if (menu_event && menu_event->itemref) { - if (ui_error) + if (m_ui_error) { // reset the error on any future menu_event - ui_error = false; + m_ui_error = false; machine().ui_input().reset(); } else if (menu_event->iptkey == IPT_UI_SELECT) @@ -257,7 +258,7 @@ void menu_select_game::handle() if ((FPTR)drv > skip_main_items && ui_globals::curdats_view > UI_FIRST_LOAD) { ui_globals::curdats_view--; - topline_datsview = 0; + m_topline_datsview = 0; } } else @@ -266,12 +267,12 @@ void menu_select_game::handle() if (drv->startempty == 1 && ui_globals::curdats_view > UI_FIRST_LOAD) { ui_globals::curdats_view--; - topline_datsview = 0; + m_topline_datsview = 0; } else if ((FPTR)drv > skip_main_items && ui_globals::cur_sw_dats_view > 0) { ui_globals::cur_sw_dats_view--; - topline_datsview = 0; + m_topline_datsview = 0; } } } @@ -295,7 +296,7 @@ void menu_select_game::handle() if ((FPTR)drv > skip_main_items && ui_globals::curdats_view < UI_LAST_LOAD) { ui_globals::curdats_view++; - topline_datsview = 0; + m_topline_datsview = 0; } } else @@ -304,12 +305,12 @@ void menu_select_game::handle() if (drv->startempty == 1 && ui_globals::curdats_view < UI_LAST_LOAD) { ui_globals::curdats_view++; - topline_datsview = 0; + m_topline_datsview = 0; } else if ((FPTR)drv > skip_main_items && ui_globals::cur_sw_dats_view < 1) { ui_globals::cur_sw_dats_view++; - topline_datsview = 0; + m_topline_datsview = 0; } } } @@ -457,7 +458,7 @@ void menu_select_game::handle() } // if we're in an error state, overlay an error message - if (ui_error) + if (m_ui_error) ui().draw_text_box(container, _("The selected machine is missing one or more required ROM or CHD images. " "Please select a different machine.\n\nPress any key to continue."), ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR); @@ -497,7 +498,7 @@ void menu_select_game::populate() ui_globals::redraw_icon = true; ui_globals::switch_image = true; int old_item_selected = -1; - UINT32 flags_ui = FLAG_UI | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; + UINT32 flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; if (!isfavorite()) { @@ -588,7 +589,7 @@ void menu_select_game::populate() item_append(menu_item_type::SEPARATOR, flags_ui); // add special items - if (menu::stack_has_special_main_menu()) + if (stack_has_special_main_menu()) { item_append(_("Configure Options"), "", flags_ui, (void *)(FPTR)CONF_OPTS); item_append(_("Configure Machine"), "", flags_ui, (void *)(FPTR)CONF_MACHINE); @@ -1064,14 +1065,14 @@ void menu_select_game::inkey_select(const event *menu_event) reselect_last::swlist.clear(); mame_machine_manager::instance()->schedule_new_driver(*driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } } // otherwise, display an error else { reset(reset_options::REMEMBER_REF); - ui_error = true; + m_ui_error = true; } } } @@ -1125,7 +1126,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) reselect_last::set(true); mame_machine_manager::instance()->schedule_new_driver(*ui_swinfo->driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } } @@ -1133,7 +1134,7 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) else { reset(reset_options::REMEMBER_REF); - ui_error = true; + m_ui_error = true; } } else @@ -1182,14 +1183,14 @@ void menu_select_game::inkey_select_favorite(const event *menu_event) reselect_last::swlist = ui_swinfo->listname; mame_machine_manager::instance()->schedule_new_driver(drv.driver()); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } // otherwise, display an error else { reset(reset_options::REMEMBER_POSITION); - ui_error = true; + m_ui_error = true; } } } @@ -1531,7 +1532,7 @@ void menu_select_game::populate_search() } (index < VISIBLE_GAMES_IN_SEARCH) ? m_searchlist[index] = nullptr : m_searchlist[VISIBLE_GAMES_IN_SEARCH] = nullptr; - UINT32 flags_ui = FLAG_UI | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; + UINT32 flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; for (int curitem = 0; m_searchlist[curitem]; ++curitem) { bool cloneof = strcmp(m_searchlist[curitem]->parent, "0"); @@ -2040,8 +2041,8 @@ void menu_select_game::infos_render(void *selectedref, float origx1, float origy buffer.clear(); olddriver = driver; oldview = ui_globals::curdats_view; - topline_datsview = 0; - totallines = 0; + m_topline_datsview = 0; + m_total_lines = 0; std::vector<std::string> m_item; if (ui_globals::curdats_view == UI_GENERAL_LOAD) @@ -2072,29 +2073,29 @@ void menu_select_game::infos_render(void *selectedref, float origx1, float origy return; } else if (ui_globals::curdats_view != UI_STORY_LOAD && ui_globals::curdats_view != UI_COMMAND_LOAD) - totallines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); + m_total_lines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); else - totallines = ui().wrap_text(container, buffer.c_str(), 0.0f, 0.0f, 1.0f - (2.0f * gutter_width), xstart, xend, text_size); + m_total_lines = ui().wrap_text(container, buffer.c_str(), 0.0f, 0.0f, 1.0f - (2.0f * gutter_width), xstart, xend, text_size); int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size)); - if (totallines < r_visible_lines) - r_visible_lines = totallines; - if (topline_datsview < 0) - topline_datsview = 0; - if (topline_datsview + r_visible_lines >= totallines) - topline_datsview = totallines - r_visible_lines; + if (m_total_lines < r_visible_lines) + r_visible_lines = m_total_lines; + if (m_topline_datsview < 0) + m_topline_datsview = 0; + if (m_topline_datsview + r_visible_lines >= m_total_lines) + m_topline_datsview = m_total_lines - r_visible_lines; sc = origx2 - origx1 - (2.0f * UI_BOX_LR_BORDER); for (int r = 0; r < r_visible_lines; ++r) { - int itemline = r + topline_datsview; + int itemline = r + m_topline_datsview; std::string tempbuf(buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline])); // up arrow - if (r == 0 && topline_datsview != 0) + if (r == 0 && m_topline_datsview != 0) info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); // bottom arrow - else if (r == r_visible_lines - 1 && itemline != totallines - 1) + else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1) info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); // special case for mamescore else if (ui_globals::curdats_view == UI_STORY_LOAD) @@ -2159,7 +2160,7 @@ void menu_select_game::infos_render(void *selectedref, float origx1, float origy } // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - right_visible_lines = r_visible_lines - (topline_datsview != 0) - (topline_datsview + r_visible_lines != totallines); + right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines); } else if (soft) { @@ -2233,26 +2234,26 @@ void menu_select_game::infos_render(void *selectedref, float origx1, float origy return; } else - totallines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); + m_total_lines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size)); - if (totallines < r_visible_lines) - r_visible_lines = totallines; - if (topline_datsview < 0) - topline_datsview = 0; - if (topline_datsview + r_visible_lines >= totallines) - topline_datsview = totallines - r_visible_lines; + if (m_total_lines < r_visible_lines) + r_visible_lines = m_total_lines; + if (m_topline_datsview < 0) + m_topline_datsview = 0; + if (m_topline_datsview + r_visible_lines >= m_total_lines) + m_topline_datsview = m_total_lines - r_visible_lines; for (int r = 0; r < r_visible_lines; ++r) { - int itemline = r + topline_datsview; + int itemline = r + m_topline_datsview; std::string tempbuf(buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline])); // up arrow - if (r == 0 && topline_datsview != 0) + if (r == 0 && m_topline_datsview != 0) info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); // bottom arrow - else if (r == r_visible_lines - 1 && itemline != totallines - 1) + else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1) info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); else ui().draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, ui::text_layout::LEFT, @@ -2261,7 +2262,7 @@ void menu_select_game::infos_render(void *selectedref, float origx1, float origy } // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - right_visible_lines = r_visible_lines - (topline_datsview != 0) - (topline_datsview + r_visible_lines != totallines); + right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines); } } diff --git a/src/frontend/mame/ui/selgame.h b/src/frontend/mame/ui/selgame.h index b826dfaf5fc..153e353c93b 100644 --- a/src/frontend/mame/ui/selgame.h +++ b/src/frontend/mame/ui/selgame.h @@ -13,11 +13,11 @@ #ifndef MAME_FRONTEND_UI_SELGAME_H #define MAME_FRONTEND_UI_SELGAME_H -#include "ui/menu.h" +#include "ui/selmenu.h" namespace ui { -class menu_select_game : public menu +class menu_select_game : public menu_select_launch { public: menu_select_game(mame_ui_manager &mui, render_container *container, const char *gamename); diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp new file mode 100644 index 00000000000..3f7b70d5def --- /dev/null +++ b/src/frontend/mame/ui/selmenu.cpp @@ -0,0 +1,1287 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +/*************************************************************************** + + ui/selmenu.cpp + + MAME system/software selection menu. + +***************************************************************************/ + +#include "emu.h" + +#include "ui/selmenu.h" + +#include "ui/icorender.h" +#include "ui/utils.h" + +// these hold static bitmap images +#include "ui/defimg.h" +#include "ui/starimg.h" +#include "ui/toolbar.h" + +#include "cheat.h" +#include "mame.h" + +#include "drivenum.h" +#include "emuopts.h" +#include "rendutil.h" +#include "uiinput.h" + +#include <algorithm> +#include <cmath> +#include <cstring> +#include <utility> + + +namespace ui { +namespace { +std::pair<char const *, char const *> const arts_info[] = +{ + { __("Snapshots"), OPTION_SNAPSHOT_DIRECTORY }, + { __("Cabinets"), OPTION_CABINETS_PATH }, + { __("Control Panels"), OPTION_CPANELS_PATH }, + { __("PCBs"), OPTION_PCBS_PATH }, + { __("Flyers"), OPTION_FLYERS_PATH }, + { __("Titles"), OPTION_TITLES_PATH }, + { __("Ends"), OPTION_ENDS_PATH }, + { __("Artwork Preview"), OPTION_ARTPREV_PATH }, + { __("Bosses"), OPTION_BOSSES_PATH }, + { __("Logos"), OPTION_LOGOS_PATH }, + { __("Versus"), OPTION_VERSUS_PATH }, + { __("Game Over"), OPTION_GAMEOVER_PATH }, + { __("HowTo"), OPTION_HOWTO_PATH }, + { __("Scores"), OPTION_SCORES_PATH }, + { __("Select"), OPTION_SELECT_PATH }, + { __("Marquees"), OPTION_MARQUEES_PATH }, + { __("Covers"), OPTION_COVER_PATH }, +}; + +char const *const hover_msg[] = { + __("Add or remove favorites"), + __("Export displayed list to file"), + __("Show DATs view"), +}; + +} // anonymous namespace + + +std::mutex menu_select_launch::s_cache_guard; +menu_select_launch::cache_ptr_map menu_select_launch::s_caches; + + +menu_select_launch::cache::cache(running_machine &machine) + : m_no_avail_bitmap(std::make_unique<bitmap_argb32>(256, 256)) + , m_star_bitmap(std::make_unique<bitmap_argb32>(32, 32)) + , m_star_texture() + , m_toolbar_bitmap() + , m_sw_toolbar_bitmap() + , m_toolbar_texture() + , m_sw_toolbar_texture() +{ + render_manager &render(machine.render()); + auto const texture_free([&render](render_texture *texture) { render.texture_free(texture); }); + + std::memcpy(&m_no_avail_bitmap->pix32(0), no_avail_bmp, 256 * 256 * sizeof(UINT32)); + std::memcpy(&m_star_bitmap->pix32(0), favorite_star_bmp, 32 * 32 * sizeof(UINT32)); + + m_star_texture = texture_ptr(render.texture_alloc(), texture_free); + m_star_texture->set_bitmap(*m_star_bitmap, m_star_bitmap->cliprect(), TEXFORMAT_ARGB32); + + m_toolbar_bitmap.reserve(UI_TOOLBAR_BUTTONS); + m_sw_toolbar_bitmap.reserve(UI_TOOLBAR_BUTTONS); + m_toolbar_texture.reserve(UI_TOOLBAR_BUTTONS); + m_sw_toolbar_texture.reserve(UI_TOOLBAR_BUTTONS); + + for (std::size_t i = 0; i < UI_TOOLBAR_BUTTONS; ++i) + { + m_toolbar_bitmap.emplace_back(std::make_unique<bitmap_argb32>(32, 32)); + m_sw_toolbar_bitmap.emplace_back(std::make_unique<bitmap_argb32>(32, 32)); + m_toolbar_texture.emplace_back(texture_ptr(render.texture_alloc(), texture_free)); + m_sw_toolbar_texture.emplace_back(texture_ptr(render.texture_alloc(), texture_free)); + + std::memcpy(&m_toolbar_bitmap.back()->pix32(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(UINT32)); + if (m_toolbar_bitmap.back()->valid()) + m_toolbar_texture.back()->set_bitmap(*m_toolbar_bitmap.back(), m_toolbar_bitmap.back()->cliprect(), TEXFORMAT_ARGB32); + else + m_toolbar_bitmap.back()->reset(); + + if ((i == 0U) || (i == 2U)) + { + std::memcpy(&m_sw_toolbar_bitmap.back()->pix32(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(UINT32)); + if (m_sw_toolbar_bitmap.back()->valid()) + m_sw_toolbar_texture.back()->set_bitmap(*m_sw_toolbar_bitmap.back(), m_sw_toolbar_bitmap.back()->cliprect(), TEXFORMAT_ARGB32); + else + m_sw_toolbar_bitmap.back()->reset(); + } + else + { + m_sw_toolbar_bitmap.back()->reset(); + } + } +} + + +menu_select_launch::cache::~cache() +{ +} + + +menu_select_launch::~menu_select_launch() +{ + // need to manually clean up icon textures for now + for (auto &texture : m_icons_texture) + { + if (texture) + machine().render().texture_free(texture); + } +} + + +menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container *container, bool is_swlist) + : menu(mui, container) + , m_total_lines(0) + , m_topline_datsview(0) + , m_ui_error(false) + , m_cache() + , m_is_swlist(is_swlist) + , m_focus(focused_menu::main) + , m_pressed(false) + , m_repeat(0) +{ + // set up persistent cache for machine run + { + std::lock_guard<std::mutex> guard(s_cache_guard); + auto const found(s_caches.find(&machine())); + if (found != s_caches.end()) + { + assert(found->second); + m_cache = found->second; + } + else + { + m_cache = std::make_shared<cache>(machine()); + s_caches.emplace(&machine(), m_cache); + add_cleanup_callback(&menu_select_launch::exit); + } + } + + // initialise icon cache + if (is_swlist) + { + std::fill(std::begin(m_icons_texture), std::end(m_icons_texture), nullptr); + } + else + { + std::generate(std::begin(m_icons_texture), std::end(m_icons_texture), [&render = machine().render()]() { return render.texture_alloc(); }); + std::generate(std::begin(m_icons_bitmap), std::end(m_icons_bitmap), []() { return std::make_unique<bitmap_argb32>(); }); + } + std::fill(std::begin(m_old_icons), std::end(m_old_icons), nullptr); +} + + +//------------------------------------------------- +// draw right box title +//------------------------------------------------- + +float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, float y2) +{ + auto line_height = ui().get_line_height(); + float midl = (x2 - x1) * 0.5f; + + // add outlined box for options + ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); + + // add separator line + container->add_line(x1 + midl, y1, x1 + midl, y1 + line_height, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + std::string buffer[RP_LAST + 1]; + buffer[RP_IMAGES] = _("Images"); + buffer[RP_INFOS] = _("Infos"); + + // check size + float text_size = 1.0f; + for (auto & elem : buffer) + { + auto textlen = ui().get_string_width(elem.c_str()) + 0.01f; + float tmp_size = (textlen > midl) ? (midl / textlen) : 1.0f; + text_size = MIN(text_size, tmp_size); + } + + for (int cells = RP_FIRST; cells <= RP_LAST; ++cells) + { + rgb_t bgcolor = UI_TEXT_BG_COLOR; + rgb_t fgcolor = UI_TEXT_COLOR; + + if (mouse_hit && x1 <= mouse_x && x1 + midl > mouse_x && y1 <= mouse_y && y1 + line_height > mouse_y) + { + if (ui_globals::rpanel != cells) + { + bgcolor = UI_MOUSEOVER_BG_COLOR; + fgcolor = UI_MOUSEOVER_COLOR; + hover = HOVER_RP_FIRST + cells; + } + } + + if (ui_globals::rpanel != cells) + { + container->add_line(x1, y1 + line_height, x1 + midl, y1 + line_height, UI_LINE_WIDTH, + UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + if (fgcolor != UI_MOUSEOVER_COLOR) + fgcolor = UI_CLONE_COLOR; + } + + if (m_focus == focused_menu::righttop && ui_globals::rpanel == cells) + { + fgcolor = rgb_t(0xff, 0xff, 0x00); + bgcolor = rgb_t(0xff, 0xff, 0xff); + ui().draw_textured_box(container, x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, + bgcolor, rgb_t(43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + } + else if (bgcolor == UI_MOUSEOVER_BG_COLOR) + container->add_rect(x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, + bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + + ui().draw_text_full(container, buffer[cells].c_str(), x1 + UI_LINE_WIDTH, y1, midl - UI_LINE_WIDTH, + ui::text_layout::CENTER, ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); + x1 += midl; + } + + return (y1 + line_height + UI_LINE_WIDTH); +} + + +//------------------------------------------------- +// common function for images render +//------------------------------------------------- + +std::string menu_select_launch::arts_render_common(float origx1, float origy1, float origx2, float origy2) +{ + auto line_height = ui().get_line_height(); + std::string snaptext, searchstr; + auto title_size = 0.0f; + auto txt_lenght = 0.0f; + auto gutter_width = 0.4f * line_height * machine().render().ui_aspect() * 1.3f; + + get_title_search(snaptext, searchstr); + + // apply title to right panel + for (int x = FIRST_VIEW; x < LAST_VIEW; x++) + { + ui().draw_text_full(container, _(arts_info[x].first), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, + ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white, rgb_t::black, &txt_lenght, nullptr); + txt_lenght += 0.01f; + title_size = MAX(txt_lenght, title_size); + } + + rgb_t fgcolor = (m_focus == focused_menu::rightbottom) ? rgb_t(0xff, 0xff, 0x00) : UI_TEXT_COLOR; + rgb_t bgcolor = (m_focus == focused_menu::rightbottom) ? rgb_t(0xff, 0xff, 0xff) : UI_TEXT_BG_COLOR; + float middle = origx2 - origx1; + + // check size + float sc = title_size + 2.0f * gutter_width; + float tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f; + title_size *= tmp_size; + + if (bgcolor != UI_TEXT_BG_COLOR) + ui().draw_textured_box(container, origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f), + origy1 + line_height, bgcolor, rgb_t(43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + + ui().draw_text_full(container, snaptext.c_str(), origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size); + + draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::curimage_view, FIRST_VIEW, LAST_VIEW, title_size); + + return searchstr; +} + + +//------------------------------------------------- +// perform rendering of image +//------------------------------------------------- + +void menu_select_launch::arts_render_images(bitmap_argb32 *tmp_bitmap, float origx1, float origy1, float origx2, float origy2) +{ + bool no_available = false; + float line_height = ui().get_line_height(); + + // if it fails, use the default image + if (!tmp_bitmap->valid()) + { + tmp_bitmap->allocate(256, 256); + const bitmap_argb32 &src(m_cache->no_avail_bitmap()); + for (int x = 0; x < 256; x++) + { + for (int y = 0; y < 256; y++) + tmp_bitmap->pix32(y, x) = src.pix32(y, x); + } + no_available = true; + } + + if (tmp_bitmap->valid()) + { + float panel_width = origx2 - origx1 - 0.02f; + float panel_height = origy2 - origy1 - 0.02f - (2.0f * UI_BOX_TB_BORDER) - (2.0f * line_height); + int screen_width = machine().render().ui_target().width(); + int screen_height = machine().render().ui_target().height(); + + if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY) + std::swap(screen_height, screen_width); + + int panel_width_pixel = panel_width * screen_width; + int panel_height_pixel = panel_height * screen_height; + + // Calculate resize ratios for resizing + auto ratioW = (float)panel_width_pixel / tmp_bitmap->width(); + auto ratioH = (float)panel_height_pixel / tmp_bitmap->height(); + auto ratioI = (float)tmp_bitmap->height() / tmp_bitmap->width(); + auto dest_xPixel = tmp_bitmap->width(); + auto dest_yPixel = tmp_bitmap->height(); + + // force 4:3 ratio min + if (ui().options().forced_4x3_snapshot() && ratioI < 0.75f && ui_globals::curimage_view == SNAPSHOT_VIEW) + { + // smaller ratio will ensure that the image fits in the view + dest_yPixel = tmp_bitmap->width() * 0.75f; + ratioH = (float)panel_height_pixel / dest_yPixel; + float ratio = MIN(ratioW, ratioH); + dest_xPixel = tmp_bitmap->width() * ratio; + dest_yPixel *= ratio; + } + // resize the bitmap if necessary + else if (ratioW < 1 || ratioH < 1 || (ui().options().enlarge_snaps() && !no_available)) + { + // smaller ratio will ensure that the image fits in the view + float ratio = MIN(ratioW, ratioH); + dest_xPixel = tmp_bitmap->width() * ratio; + dest_yPixel = tmp_bitmap->height() * ratio; + } + + bitmap_argb32 *dest_bitmap; + + // resample if necessary + if (dest_xPixel != tmp_bitmap->width() || dest_yPixel != tmp_bitmap->height()) + { + dest_bitmap = auto_alloc(machine(), bitmap_argb32); + dest_bitmap->allocate(dest_xPixel, dest_yPixel); + render_color color = { 1.0f, 1.0f, 1.0f, 1.0f }; + render_resample_argb_bitmap_hq(*dest_bitmap, *tmp_bitmap, color, true); + } + else + dest_bitmap = tmp_bitmap; + + snapx_bitmap->allocate(panel_width_pixel, panel_height_pixel); + int x1 = (0.5f * panel_width_pixel) - (0.5f * dest_xPixel); + int y1 = (0.5f * panel_height_pixel) - (0.5f * dest_yPixel); + + for (int x = 0; x < dest_xPixel; x++) + for (int y = 0; y < dest_yPixel; y++) + snapx_bitmap->pix32(y + y1, x + x1) = dest_bitmap->pix32(y, x); + + auto_free(machine(), dest_bitmap); + + // apply bitmap + snapx_texture->set_bitmap(*snapx_bitmap, snapx_bitmap->cliprect(), TEXFORMAT_ARGB32); + } + else + snapx_bitmap->reset(); +} + + +//------------------------------------------------- +// draw toolbar +//------------------------------------------------- + +void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2, bool software) +{ + // draw a box + ui().draw_outlined_box(container, x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B)); + + // take off the borders + x1 += UI_BOX_LR_BORDER; + x2 -= UI_BOX_LR_BORDER; + y1 += UI_BOX_TB_BORDER; + y2 -= UI_BOX_TB_BORDER; + + texture_ptr_vector const &t_texture = software ? m_cache->sw_toolbar_texture() : m_cache->toolbar_texture(); + bitmap_ptr_vector const &t_bitmap = software ? m_cache->sw_toolbar_bitmap() : m_cache->toolbar_bitmap(); + + auto const num_valid(std::count_if(std::begin(t_bitmap), std::end(t_bitmap), [](bitmap_ptr const &e) { return e && e->valid(); })); + + float const space_x = (y2 - y1) * container->manager().ui_aspect(container); + float const total = (float(num_valid) * space_x) + (float(num_valid - 1) * 0.001f); + x1 += (x2 - x1) * 0.5f - total * 0.5f; + x2 = x1 + space_x; + + for (int z = 0; z < UI_TOOLBAR_BUTTONS; ++z) + { + if (t_bitmap[z] && t_bitmap[z]->valid()) + { + rgb_t color(0xEFEFEFEF); + if (mouse_hit && x1 <= mouse_x && x2 > mouse_x && y1 <= mouse_y && y2 > mouse_y) + { + hover = HOVER_B_FAV + z; + color = rgb_t::white; + float ypos = y2 + ui().get_line_height() + 2.0f * UI_BOX_TB_BORDER; + ui().draw_text_box(container, _(hover_msg[z]), ui::text_layout::CENTER, 0.5f, ypos, UI_BACKGROUND_COLOR); + } + + container->add_quad(x1, y1, x2, y2, color, t_texture[z].get(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + x1 += space_x + ((z < UI_TOOLBAR_BUTTONS - 1) ? 0.001f : 0.0f); + x2 = x1 + space_x; + } + } +} + + +//------------------------------------------------- +// draw favorites star +//------------------------------------------------- + +void menu_select_launch::draw_star(float x0, float y0) +{ + float y1 = y0 + ui().get_line_height(); + float x1 = x0 + ui().get_line_height() * container->manager().ui_aspect(); + container->add_quad(x0, y0, x1, y1, rgb_t::white, m_cache->star_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE); +} + + +void menu_select_launch::set_pressed() +{ + (m_repeat == 0) ? m_repeat = osd_ticks() + osd_ticks_per_second() / 2 : m_repeat = osd_ticks() + osd_ticks_per_second() / 4; + m_pressed = true; +} + + +//------------------------------------------------- +// draw icons +//------------------------------------------------- + +float menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, float y0) +{ + if (!ui_globals::has_icons || m_is_swlist) + return 0.0f; + + float ud_arrow_width = ui().get_line_height() * container->manager().ui_aspect(container); + const game_driver *driver = nullptr; + + if (item[0].flags & FLAG_UI_FAVORITE) + { + ui_software_info *soft = (ui_software_info *)selectedref; + if (soft->startempty == 1) + driver = soft->driver; + } + else + driver = (const game_driver *)selectedref; + + auto x1 = x0 + ud_arrow_width; + auto y1 = y0 + ui().get_line_height(); + + if (m_old_icons[linenum] != driver || ui_globals::redraw_icon) + { + m_old_icons[linenum] = driver; + + // set clone status + bool cloneof = strcmp(driver->parent, "0"); + if (cloneof) + { + auto cx = driver_list::find(driver->parent); + if (cx != -1 && ((driver_list::driver(cx).flags & MACHINE_IS_BIOS_ROOT) != 0)) + cloneof = false; + } + + // get search path + path_iterator path(ui().options().icons_directory()); + std::string curpath; + std::string searchstr(ui().options().icons_directory()); + + // iterate over path and add path for zipped formats + while (path.next(curpath)) + searchstr.append(";").append(curpath.c_str()).append(PATH_SEPARATOR).append("icons"); + + bitmap_argb32 *tmp = auto_alloc(machine(), bitmap_argb32); + emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ); + std::string fullname = std::string(driver->name).append(".ico"); + render_load_ico(*tmp, snapfile, nullptr, fullname.c_str()); + + if (!tmp->valid() && cloneof) + { + fullname.assign(driver->parent).append(".ico"); + render_load_ico(*tmp, snapfile, nullptr, fullname.c_str()); + } + + if (tmp->valid()) + { + float panel_width = x1 - x0; + float panel_height = y1 - y0; + auto screen_width = machine().render().ui_target().width(); + auto screen_height = machine().render().ui_target().height(); + + if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY) + std::swap(screen_height, screen_width); + + int panel_width_pixel = panel_width * screen_width; + int panel_height_pixel = panel_height * screen_height; + + // Calculate resize ratios for resizing + auto ratioW = (float)panel_width_pixel / tmp->width(); + auto ratioH = (float)panel_height_pixel / tmp->height(); + auto dest_xPixel = tmp->width(); + auto dest_yPixel = tmp->height(); + + if (ratioW < 1 || ratioH < 1) + { + // smaller ratio will ensure that the image fits in the view + float ratio = MIN(ratioW, ratioH); + dest_xPixel = tmp->width() * ratio; + dest_yPixel = tmp->height() * ratio; + } + + bitmap_argb32 *dest_bitmap; + dest_bitmap = auto_alloc(machine(), bitmap_argb32); + + // resample if necessary + if (dest_xPixel != tmp->width() || dest_yPixel != tmp->height()) + { + dest_bitmap->allocate(dest_xPixel, dest_yPixel); + render_color color = { 1.0f, 1.0f, 1.0f, 1.0f }; + render_resample_argb_bitmap_hq(*dest_bitmap, *tmp, color, true); + } + else + dest_bitmap = tmp; + + m_icons_bitmap[linenum]->allocate(panel_width_pixel, panel_height_pixel); + + for (int x = 0; x < dest_xPixel; x++) + for (int y = 0; y < dest_yPixel; y++) + m_icons_bitmap[linenum]->pix32(y, x) = dest_bitmap->pix32(y, x); + + auto_free(machine(), dest_bitmap); + + m_icons_texture[linenum]->set_bitmap(*m_icons_bitmap[linenum], m_icons_bitmap[linenum]->cliprect(), TEXFORMAT_ARGB32); + } + else if (m_icons_bitmap[linenum] != nullptr) + m_icons_bitmap[linenum]->reset(); + + auto_free(machine(), tmp); + } + + if (m_icons_bitmap[linenum] != nullptr && m_icons_bitmap[linenum]->valid()) + container->add_quad(x0, y0, x1, y1, rgb_t::white, m_icons_texture[linenum], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + return ud_arrow_width * 1.5f; +} + + +//------------------------------------------------- +// get title and search path for right panel +//------------------------------------------------- + +void menu_select_launch::get_title_search(std::string &snaptext, std::string &searchstr) +{ + // get arts title text + snaptext.assign(_(arts_info[ui_globals::curimage_view].first)); + + // get search path + std::string addpath; + if (ui_globals::curimage_view == SNAPSHOT_VIEW) + { + emu_options moptions; + searchstr = machine().options().value(arts_info[ui_globals::curimage_view].second); + addpath = moptions.value(arts_info[ui_globals::curimage_view].second); + } + else + { + ui_options moptions; + searchstr = ui().options().value(arts_info[ui_globals::curimage_view].second); + addpath = moptions.value(arts_info[ui_globals::curimage_view].second); + } + + std::string tmp(searchstr); + path_iterator path(tmp.c_str()); + path_iterator path_iter(addpath.c_str()); + std::string c_path, curpath; + + // iterate over path and add path for zipped formats + while (path.next(curpath)) + { + path_iter.reset(); + while (path_iter.next(c_path)) + searchstr.append(";").append(curpath).append(PATH_SEPARATOR).append(c_path); + } +} + + +//------------------------------------------------- +// handle keys for main menu +//------------------------------------------------- + +void menu_select_launch::handle_keys(UINT32 flags, int &iptkey) +{ + bool const ignorepause = stack_has_special_main_menu(); + + // bail if no items + if (item.size() == 0) + return; + + // if we hit select, return TRUE or pop the stack, depending on the item + if (exclusive_input_pressed(iptkey, IPT_UI_SELECT, 0)) + { + if (is_last_selected() && m_focus == focused_menu::main) + { + iptkey = IPT_UI_CANCEL; + stack_pop(); + } + return; + } + + // hitting cancel also pops the stack + if (exclusive_input_pressed(iptkey, IPT_UI_CANCEL, 0)) + { + if (!m_ui_error && !menu_has_search_active()) + stack_pop(); + return; + } + + // validate the current selection + validate_selection(1); + + // swallow left/right keys if they are not appropriate + bool ignoreleft = ((item[selected].flags & FLAG_LEFT_ARROW) == 0); + bool ignoreright = ((item[selected].flags & FLAG_RIGHT_ARROW) == 0); + bool leftclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL); + bool rightclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL); + + // accept left/right keys as-is with repeat + if (!ignoreleft && exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + { + // Swap the right panel + if (m_focus == focused_menu::righttop) + iptkey = IPT_UI_LEFT_PANEL; + return; + } + + if (!ignoreright && exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) + { + // Swap the right panel + if (m_focus == focused_menu::righttop) + iptkey = IPT_UI_RIGHT_PANEL; + return; + } + + // up backs up by one item + if (exclusive_input_pressed(iptkey, IPT_UI_UP, 6)) + { + // Filter + if (!leftclose && m_focus == focused_menu::left) + { + iptkey = IPT_UI_UP_FILTER; + return; + } + + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_UP_PANEL; + m_topline_datsview--; + return; + } + + if (selected == visible_items + 1 || is_first_selected() || m_ui_error) + return; + + selected--; + + if (selected == top_line && top_line != 0) + top_line--; + } + + // down advances by one item + if (exclusive_input_pressed(iptkey, IPT_UI_DOWN, 6)) + { + // Filter + if (!leftclose && m_focus == focused_menu::left) + { + iptkey = IPT_UI_DOWN_FILTER; + return; + } + + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_DOWN_PANEL; + m_topline_datsview++; + return; + } + + if (is_last_selected() || selected == visible_items - 1 || m_ui_error) + return; + + selected++; + + if (selected == top_line + m_visible_items + (top_line != 0)) + top_line++; + } + + // page up backs up by m_visible_items + if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_UP, 6)) + { + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_DOWN_PANEL; + m_topline_datsview -= right_visible_lines - 1; + return; + } + + if (selected < visible_items && !m_ui_error) + { + selected -= m_visible_items; + + if (selected < 0) + selected = 0; + + top_line -= m_visible_items - (top_line + m_visible_lines == visible_items); + } + } + + // page down advances by m_visible_items + if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_DOWN, 6)) + { + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_DOWN_PANEL; + m_topline_datsview += right_visible_lines - 1; + return; + } + + if (selected < visible_items && !m_ui_error) + { + selected += m_visible_lines - 2 + (selected == 0); + + if (selected >= visible_items) + selected = visible_items - 1; + + top_line += m_visible_lines - 2; + } + } + + // home goes to the start + if (exclusive_input_pressed(iptkey, IPT_UI_HOME, 0)) + { + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_DOWN_PANEL; + m_topline_datsview = 0; + return; + } + + if (selected < visible_items && !m_ui_error) + { + selected = 0; + top_line = 0; + } + } + + // end goes to the last + if (exclusive_input_pressed(iptkey, IPT_UI_END, 0)) + { + // Infos + if (!rightclose && m_focus == focused_menu::rightbottom) + { + iptkey = IPT_UI_DOWN_PANEL; + m_topline_datsview = m_total_lines; + return; + } + + if (selected < visible_items && !m_ui_error) + selected = top_line = visible_items - 1; + } + + // pause enables/disables pause + if (!m_ui_error && !ignorepause && exclusive_input_pressed(iptkey, IPT_UI_PAUSE, 0)) + { + if (machine().paused()) + machine().resume(); + else + machine().pause(); + } + + // handle a toggle cheats request + if (!m_ui_error && machine().ui_input().pressed_repeat(IPT_UI_TOGGLE_CHEAT, 0)) + mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled()); + + // see if any other UI keys are pressed + if (iptkey == IPT_INVALID) + { + for (int code = IPT_UI_FIRST + 1; code < IPT_UI_LAST; code++) + { + if (m_ui_error || code == IPT_UI_CONFIGURE || (code == IPT_UI_LEFT && ignoreleft) || (code == IPT_UI_RIGHT && ignoreright) || (code == IPT_UI_PAUSE && ignorepause)) + continue; + + if (exclusive_input_pressed(iptkey, code, 0)) + break; + } + } +} + + +//------------------------------------------------- +// handle input events for main menu +//------------------------------------------------- + +void menu_select_launch::handle_events(UINT32 flags, event &ev) +{ + auto stop = false; + ui_event local_menu_event; + + if (m_pressed) + { + bool pressed = mouse_pressed(); + INT32 m_target_x, m_target_y; + bool m_button; + auto mouse_target = machine().ui_input().find_mouse(&m_target_x, &m_target_y, &m_button); + if (mouse_target && m_button && (hover == HOVER_ARROW_DOWN || hover == HOVER_ARROW_UP)) + { + if (pressed) + machine().ui_input().push_mouse_down_event(mouse_target, m_target_x, m_target_y); + } + else + reset_pressed(); + } + + // loop while we have interesting events + while (!stop && machine().ui_input().pop_event(&local_menu_event)) + { + switch (local_menu_event.event_type) + { + // if we are hovering over a valid item, select it with a single click + case UI_EVENT_MOUSE_DOWN: + { + if (m_ui_error) + { + ev.iptkey = IPT_OTHER; + stop = true; + } + else + { + if (hover >= 0 && hover < item.size()) + { + if (hover >= visible_items - 1 && selected < visible_items) + m_prev_selected = item[selected].ref; + selected = hover; + m_focus = focused_menu::main; + } + else if (hover == HOVER_ARROW_UP) + { + selected -= m_visible_items; + if (selected < 0) + selected = 0; + top_line -= m_visible_items - (top_line + m_visible_lines == visible_items); + set_pressed(); + } + else if (hover == HOVER_ARROW_DOWN) + { + selected += m_visible_lines - 2 + (selected == 0); + if (selected >= visible_items) + selected = visible_items - 1; + top_line += m_visible_lines - 2; + set_pressed(); + } + else if (hover == HOVER_UI_RIGHT) + ev.iptkey = IPT_UI_RIGHT; + else if (hover == HOVER_UI_LEFT) + ev.iptkey = IPT_UI_LEFT; + else if (hover == HOVER_DAT_DOWN) + m_topline_datsview += right_visible_lines - 1; + else if (hover == HOVER_DAT_UP) + m_topline_datsview -= right_visible_lines - 1; + else if (hover == HOVER_LPANEL_ARROW) + { + if (ui_globals::panels_status == HIDE_LEFT_PANEL) + ui_globals::panels_status = SHOW_PANELS; + else if (ui_globals::panels_status == HIDE_BOTH) + ui_globals::panels_status = HIDE_RIGHT_PANEL; + else if (ui_globals::panels_status == SHOW_PANELS) + ui_globals::panels_status = HIDE_LEFT_PANEL; + else if (ui_globals::panels_status == HIDE_RIGHT_PANEL) + ui_globals::panels_status = HIDE_BOTH; + } + else if (hover == HOVER_RPANEL_ARROW) + { + if (ui_globals::panels_status == HIDE_RIGHT_PANEL) + ui_globals::panels_status = SHOW_PANELS; + else if (ui_globals::panels_status == HIDE_BOTH) + ui_globals::panels_status = HIDE_LEFT_PANEL; + else if (ui_globals::panels_status == SHOW_PANELS) + ui_globals::panels_status = HIDE_RIGHT_PANEL; + else if (ui_globals::panels_status == HIDE_LEFT_PANEL) + ui_globals::panels_status = HIDE_BOTH; + } + else if (hover == HOVER_B_FAV) + { + ev.iptkey = IPT_UI_FAVORITES; + stop = true; + } + else if (hover == HOVER_B_EXPORT) + { + ev.iptkey = IPT_UI_EXPORT; + stop = true; + } + else if (hover == HOVER_B_DATS) + { + ev.iptkey = IPT_UI_DATS; + stop = true; + } + else if (hover >= HOVER_RP_FIRST && hover <= HOVER_RP_LAST) + { + ui_globals::rpanel = (HOVER_RP_FIRST - hover) * (-1); + stop = true; + } + else if (hover >= HOVER_SW_FILTER_FIRST && hover <= HOVER_SW_FILTER_LAST) + { + l_sw_hover = (HOVER_SW_FILTER_FIRST - hover) * (-1); + ev.iptkey = IPT_OTHER; + stop = true; + } + else if (hover >= HOVER_FILTER_FIRST && hover <= HOVER_FILTER_LAST) + { + l_hover = (HOVER_FILTER_FIRST - hover) * (-1); + ev.iptkey = IPT_OTHER; + stop = true; + } + } + break; + } + + // if we are hovering over a valid item, fake a UI_SELECT with a double-click + case UI_EVENT_MOUSE_DOUBLE_CLICK: + if (hover >= 0 && hover < item.size()) + { + selected = hover; + ev.iptkey = IPT_UI_SELECT; + } + + if (selected == item.size() - 1) + { + ev.iptkey = IPT_UI_CANCEL; + stack_pop(); + } + stop = true; + break; + + // caught scroll event + case UI_EVENT_MOUSE_WHEEL: + if (hover >= 0 && hover < item.size() - skip_main_items - 1) + { + if (local_menu_event.zdelta > 0) + { + if (selected >= visible_items || selected == 0 || m_ui_error) + break; + selected -= local_menu_event.num_lines; + if (selected < top_line + (top_line != 0)) + top_line -= local_menu_event.num_lines; + } + else + { + if (selected >= visible_items - 1 || m_ui_error) + break; + selected += local_menu_event.num_lines; + if (selected > visible_items - 1) + selected = visible_items - 1; + if (selected >= top_line + m_visible_items + (top_line != 0)) + top_line += local_menu_event.num_lines; + } + } + break; + + // translate CHAR events into specials + case UI_EVENT_CHAR: + if (exclusive_input_pressed(ev.iptkey, IPT_UI_CONFIGURE, 0)) + { + ev.iptkey = IPT_UI_CONFIGURE; + stop = true; + } + else + { + ev.iptkey = IPT_SPECIAL; + ev.unichar = local_menu_event.ch; + stop = true; + } + break; + + case UI_EVENT_MOUSE_RDOWN: + if (hover >= 0 && hover < item.size() - skip_main_items - 1) + { + selected = hover; + m_prev_selected = item[selected].ref; + m_focus = focused_menu::main; + ev.iptkey = IPT_CUSTOM; + ev.mouse.x0 = local_menu_event.mouse_x; + ev.mouse.y0 = local_menu_event.mouse_y; + stop = true; + } + break; + + // ignore everything else + default: + break; + } + } +} + + +//------------------------------------------------- +// draw main menu +//------------------------------------------------- + +void menu_select_launch::draw(UINT32 flags) +{ + bool noinput = (flags & PROCESS_NOINPUT); + float line_height = ui().get_line_height(); + float ud_arrow_width = line_height * machine().render().ui_aspect(); + float gutter_width = 0.52f * ud_arrow_width; + mouse_x = -1, mouse_y = -1; + float right_panel_size = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL) ? 2.0f * UI_BOX_LR_BORDER : 0.3f; + float visible_width = 1.0f - 4.0f * UI_BOX_LR_BORDER; + float primary_left = (1.0f - visible_width) * 0.5f; + float primary_width = visible_width; + + draw_background(); + + hover = item.size() + 1; + visible_items = (m_is_swlist) ? item.size() - 2 : item.size() - 2 - skip_main_items; + float extra_height = (m_is_swlist) ? 2.0f * line_height : (2.0f + skip_main_items) * line_height; + float visible_extra_menu_height = customtop + custombottom + extra_height; + + // locate mouse + mouse_hit = false; + mouse_button = false; + if (!noinput) + { + mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); + if (mouse_target) + if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y)) + mouse_hit = true; + } + + // account for extra space at the top and bottom + float visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height; + m_visible_lines = int(std::trunc(visible_main_menu_height / line_height)); + visible_main_menu_height = float(m_visible_lines) * line_height; + + if (!m_is_swlist) + ui_globals::visible_main_lines = m_visible_lines; + else + ui_globals::visible_sw_lines = m_visible_lines; + + // compute top/left of inner menu area by centering + float visible_left = primary_left; + float visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f; + + // if the menu is at the bottom of the extra, adjust + visible_top += customtop; + + // compute left box size + float x1 = visible_left - UI_BOX_LR_BORDER; + float y1 = visible_top - UI_BOX_TB_BORDER; + float x2 = x1 + 2.0f * UI_BOX_LR_BORDER; + float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER + extra_height; + + // add left box + visible_left = draw_left_panel(x1, y1, x2, y2); + visible_width -= right_panel_size + visible_left - 2.0f * UI_BOX_LR_BORDER; + + // compute and add main box + x1 = visible_left - UI_BOX_LR_BORDER; + x2 = visible_left + visible_width + UI_BOX_LR_BORDER; + float line = visible_top + (float(m_visible_lines) * line_height); + ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR); + + if (visible_items < m_visible_lines) + m_visible_lines = visible_items; + if (top_line < 0 || is_first_selected()) + top_line = 0; + if (selected < visible_items && top_line + m_visible_lines >= visible_items) + top_line = visible_items - m_visible_lines; + + // 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; + + if (m_prev_selected != nullptr && m_focus == focused_menu::main && selected < visible_items) + m_prev_selected = nullptr; + + int const n_loop = (std::min)(m_visible_lines, visible_items); + for (int linenum = 0; linenum < n_loop; linenum++) + { + float line_y = visible_top + (float)linenum * line_height; + int itemnum = top_line + linenum; + const menu_item &pitem = item[itemnum]; + const char *itemtext = pitem.text.c_str(); + rgb_t fgcolor = UI_TEXT_COLOR; + rgb_t bgcolor = UI_TEXT_BG_COLOR; + rgb_t fgcolor3 = UI_CLONE_COLOR; + float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; + float line_y0 = line_y; + float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; + float line_y1 = line_y + line_height; + + // set the hover if this is our item + if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) + hover = itemnum; + + // if we're selected, draw with a different background + if (itemnum == selected && m_focus == focused_menu::main) + { + fgcolor = rgb_t(0xff, 0xff, 0x00); + bgcolor = rgb_t(0xff, 0xff, 0xff); + fgcolor3 = rgb_t(0xcc, 0xcc, 0x00); + ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), + hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + } + // else if the mouse is over this item, draw with a different background + else if (itemnum == hover) + { + fgcolor = fgcolor3 = UI_MOUSEOVER_COLOR; + bgcolor = UI_MOUSEOVER_BG_COLOR; + highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); + } + else if (pitem.ref == m_prev_selected) + { + fgcolor = fgcolor3 = UI_MOUSEOVER_COLOR; + bgcolor = UI_MOUSEOVER_BG_COLOR; + ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), + hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + } + + if (linenum == 0 && top_line != 0) + { + // if we're on the top line, display the up arrow + draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0); + + if (hover == itemnum) + hover = HOVER_ARROW_UP; + } + else if (linenum == m_visible_lines - 1 && itemnum != visible_items - 1) + { + // if we're on the bottom line, display the down arrow + draw_arrow(container, 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); + + if (hover == itemnum) + hover = HOVER_ARROW_DOWN; + } + else if (pitem.type == menu_item_type::SEPARATOR) + { + // if we're just a divider, draw a line + container->add_line(visible_left, line_y + 0.5f * line_height, visible_left + visible_width, line_y + 0.5f * line_height, + UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } + else if (pitem.subtext.empty()) + { + // draw the item centered + int item_invert = pitem.flags & FLAG_INVERT; + auto icon = draw_icon(linenum, item[itemnum].ref, effective_left, line_y); + ui().draw_text_full(container, itemtext, effective_left + icon, line_y, effective_width - icon, ui::text_layout::LEFT, ui::text_layout::TRUNCATE, + mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); + } + else + { + auto item_invert = pitem.flags & FLAG_INVERT; + const char *subitem_text = pitem.subtext.c_str(); + float item_width, subitem_width; + + // compute right space for subitem + ui().draw_text_full(container, subitem_text, effective_left, line_y, ui().get_string_width(pitem.subtext.c_str()), + ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NONE, item_invert ? fgcolor3 : fgcolor, bgcolor, &subitem_width, nullptr); + subitem_width += gutter_width; + + // draw the item left-justified + ui().draw_text_full(container, itemtext, effective_left, line_y, effective_width - subitem_width, + ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, &item_width, nullptr); + + // draw the subitem right-justified + ui().draw_text_full(container, subitem_text, effective_left + item_width, line_y, effective_width - item_width, + ui::text_layout::RIGHT, ui::text_layout::NEVER, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); + } + } + + for (size_t count = visible_items; count < item.size(); count++) + { + const menu_item &pitem = item[count]; + const char *itemtext = pitem.text.c_str(); + float line_x0 = x1 + 0.5f * UI_LINE_WIDTH; + float line_y0 = line; + float line_x1 = x2 - 0.5f * UI_LINE_WIDTH; + float line_y1 = line + line_height; + rgb_t fgcolor = UI_TEXT_COLOR; + rgb_t bgcolor = UI_TEXT_BG_COLOR; + + if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && is_selectable(pitem)) + hover = count; + + // if we're selected, draw with a different background + if (count == selected && m_focus == focused_menu::main) + { + fgcolor = rgb_t(0xff, 0xff, 0x00); + bgcolor = rgb_t(0xff, 0xff, 0xff); + ui().draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(43, 43, 43), + hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE)); + } + // else if the mouse is over this item, draw with a different background + else if (count == hover) + { + fgcolor = UI_MOUSEOVER_COLOR; + bgcolor = UI_MOUSEOVER_BG_COLOR; + highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor); + } + + if (pitem.type == menu_item_type::SEPARATOR) + container->add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, + UI_LINE_WIDTH, UI_TEXT_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + else + ui().draw_text_full(container, itemtext, effective_left, line, effective_width, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); + line += line_height; + } + + x1 = x2; + x2 += right_panel_size; + + draw_right_panel(get_selection_ref(), x1, y1, x2, y2); + + x1 = primary_left - UI_BOX_LR_BORDER; + x2 = primary_left + primary_width + UI_BOX_LR_BORDER; + + // if there is something special to add, do it by calling the virtual method + custom_render(get_selection_ref(), customtop, custombottom, x1, y1, x2, y2); + + // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow + m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items); + + // reset redraw icon stage + if (!m_is_swlist) ui_globals::redraw_icon = false; + + // noinput + if (noinput) + { + int alpha = (1.0f - machine().options().pause_brightness()) * 255.0f; + if (alpha > 255) + alpha = 255; + if (alpha >= 0) + container->add_rect(0.0f, 0.0f, 1.0f, 1.0f, rgb_t(alpha, 0x00, 0x00, 0x00), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + } +} + + +void menu_select_launch::exit(running_machine &machine) +{ + std::lock_guard<std::mutex> guard(s_cache_guard); + s_caches.erase(&machine); +} + +} // namespace ui
\ No newline at end of file diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h new file mode 100644 index 00000000000..26f1706c2c4 --- /dev/null +++ b/src/frontend/mame/ui/selmenu.h @@ -0,0 +1,134 @@ +// license:BSD-3-Clause +// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +/*************************************************************************** + + ui/selmenu.h + + MAME system/software selection menu. + +***************************************************************************/ + +#ifndef MAME_FRONTEND_UI_SELMENU_H +#define MAME_FRONTEND_UI_SELMENU_H + +#pragma once + +#include "ui/menu.h" + +#include <map> +#include <memory> +#include <mutex> +#include <vector> + + +namespace ui { +class menu_select_launch : public menu +{ +public: + + virtual ~menu_select_launch() override; + +protected: + + // tab navigation + enum class focused_menu + { + main, + left, + righttop, + rightbottom + }; + + menu_select_launch(mame_ui_manager &mui, render_container *container, bool is_swlist); + + focused_menu get_focus() const { return m_focus; } + void set_focus(focused_menu focus) { m_focus = focus; } + + // draw right box + float draw_right_box_title(float x1, float y1, float x2, float y2); + + // images render + std::string arts_render_common(float origx1, float origy1, float origx2, float origy2); + void arts_render_images(bitmap_argb32 *bitmap, float origx1, float origy1, float origx2, float origy2); + + // draw toolbar + void draw_toolbar(float x1, float y1, float x2, float y2, bool software = false); + + // draw star + void draw_star(float x0, float y0); + + int visible_items; + int m_total_lines; + int m_topline_datsview; // right box top line + bool m_ui_error; + +private: + using bitmap_ptr_vector = std::vector<bitmap_ptr>; + using texture_ptr_vector = std::vector<texture_ptr>; + + class cache + { + public: + cache(running_machine &machine); + ~cache(); + + bitmap_argb32 &no_avail_bitmap() { return *m_no_avail_bitmap; } + render_texture *star_texture() { return m_star_texture.get(); } + + bitmap_ptr_vector const &toolbar_bitmap() { return m_toolbar_bitmap; } + bitmap_ptr_vector const &sw_toolbar_bitmap() { return m_sw_toolbar_bitmap; } + texture_ptr_vector const &toolbar_texture() { return m_toolbar_texture; } + texture_ptr_vector const &sw_toolbar_texture() { return m_sw_toolbar_texture; } + + private: + bitmap_ptr m_no_avail_bitmap; + bitmap_ptr m_star_bitmap; + texture_ptr m_star_texture; + + bitmap_ptr_vector m_toolbar_bitmap; + bitmap_ptr_vector m_sw_toolbar_bitmap; + texture_ptr_vector m_toolbar_texture; + texture_ptr_vector m_sw_toolbar_texture; + }; + using cache_ptr = std::shared_ptr<cache>; + using cache_ptr_map = std::map<running_machine *, cache_ptr>; + + static constexpr std::size_t MAX_ICONS_RENDER = 40; + + void reset_pressed() { m_pressed = false; m_repeat = 0; } + bool mouse_pressed() const { return (osd_ticks() >= m_repeat); } + void set_pressed(); + + float draw_icon(int linenum, void *selectedref, float x1, float y1); + + void get_title_search(std::string &title, std::string &search); + + // handle keys + virtual void handle_keys(UINT32 flags, int &iptkey) override; + + // handle mouse + virtual void handle_events(UINT32 flags, event &ev) override; + + // draw game list + virtual void draw(UINT32 flags) override; + + // cleanup function + static void exit(running_machine &machine); + + cache_ptr m_cache; + bool m_is_swlist; + focused_menu m_focus; + bool m_pressed; // mouse button held down + osd_ticks_t m_repeat; + + render_texture *m_icons_texture[MAX_ICONS_RENDER]; + bitmap_ptr m_icons_bitmap[MAX_ICONS_RENDER]; + game_driver const *m_old_icons[MAX_ICONS_RENDER]; + + static std::mutex s_cache_guard; + static cache_ptr_map s_caches; +}; + +} // namespace ui + +#endif // MAME_FRONTEND_UI_SELMENU_H
\ No newline at end of file diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp index d29d768ce76..bf6763171b2 100644 --- a/src/frontend/mame/ui/selsoft.cpp +++ b/src/frontend/mame/ui/selsoft.cpp @@ -125,7 +125,8 @@ bool has_multiple_bios(const game_driver *driver, s_bios &biosname) // ctor //------------------------------------------------- -menu_select_software::menu_select_software(mame_ui_manager &mui, render_container *container, const game_driver *driver) : menu(mui, container) +menu_select_software::menu_select_software(mame_ui_manager &mui, render_container *container, const game_driver *driver) + : menu_select_launch(mui, container, true) { if (reselect_last::get()) reselect_last::set(false); @@ -174,10 +175,10 @@ void menu_select_software::handle() if (menu_event && menu_event->itemref) { - if (ui_error) + if (m_ui_error) { // reset the error on any future event - ui_error = false; + m_ui_error = false; machine().ui_input().reset(); } else if (menu_event->iptkey == IPT_UI_SELECT) @@ -208,7 +209,7 @@ void menu_select_software::handle() { // Infos ui_globals::cur_sw_dats_view--; - topline_datsview = 0; + m_topline_datsview = 0; } } else if (menu_event->iptkey == IPT_UI_RIGHT) @@ -225,7 +226,7 @@ void menu_select_software::handle() { // Infos ui_globals::cur_sw_dats_view++; - topline_datsview = 0; + m_topline_datsview = 0; } } else if (menu_event->iptkey == IPT_UI_UP_FILTER && highlight > UI_SW_FIRST) @@ -322,7 +323,7 @@ void menu_select_software::handle() { // Infos ui_globals::cur_sw_dats_view--; - topline_datsview = 0; + m_topline_datsview = 0; } } else if (menu_event->iptkey == IPT_UI_RIGHT) @@ -339,7 +340,7 @@ void menu_select_software::handle() { // Infos ui_globals::cur_sw_dats_view++; - topline_datsview = 0; + m_topline_datsview = 0; } } else if (menu_event->iptkey == IPT_UI_LEFT_PANEL) @@ -371,7 +372,7 @@ void menu_select_software::handle() } // if we're in an error state, overlay an error message - if (ui_error) + if (m_ui_error) ui().draw_text_box(container, _("The selected software is missing one or more required files. " "Please select a different software.\n\nPress any key to continue."), ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR); @@ -415,7 +416,7 @@ void menu_select_software::handle() void menu_select_software::populate() { - UINT32 flags_ui = FLAG_UI_SWLIST | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; + UINT32 flags_ui = FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW; m_has_empty_start = true; int old_software = -1; @@ -897,7 +898,7 @@ void menu_select_software::inkey_select(const event *menu_event) reselect_last::set(true); mame_machine_manager::instance()->schedule_new_driver(*ui_swinfo->driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } } @@ -948,14 +949,14 @@ void menu_select_software::inkey_select(const event *menu_event) reselect_last::set(true); mame_machine_manager::instance()->schedule_new_driver(drivlist.driver()); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } // otherwise, display an error else { reset(reset_options::REMEMBER_POSITION); - ui_error = true; + m_ui_error = true; } } } @@ -1652,27 +1653,27 @@ void menu_select_software::infos_render(void *selectedref, float origx1, float o return; } else - totallines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); + m_total_lines = ui().wrap_text(container, buffer.c_str(), origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), xstart, xend, text_size); int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size)); - if (totallines < r_visible_lines) - r_visible_lines = totallines; - if (topline_datsview < 0) - topline_datsview = 0; - if (topline_datsview + r_visible_lines >= totallines) - topline_datsview = totallines - r_visible_lines; + if (m_total_lines < r_visible_lines) + r_visible_lines = m_total_lines; + if (m_topline_datsview < 0) + m_topline_datsview = 0; + if (m_topline_datsview + r_visible_lines >= m_total_lines) + m_topline_datsview = m_total_lines - r_visible_lines; for (int r = 0; r < r_visible_lines; ++r) { - int itemline = r + topline_datsview; + int itemline = r + m_topline_datsview; std::string tempbuf; tempbuf.assign(buffer.substr(xstart[itemline], xend[itemline] - xstart[itemline])); // up arrow - if (r == 0 && topline_datsview != 0) + if (r == 0 && m_topline_datsview != 0) info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); // bottom arrow - else if (r == r_visible_lines - 1 && itemline != totallines - 1) + else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1) info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); else ui().draw_text_full(container, tempbuf.c_str(), origx1 + gutter_width, oy1, origx2 - origx1, @@ -1682,7 +1683,7 @@ void menu_select_software::infos_render(void *selectedref, float origx1, float o } // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - right_visible_lines = r_visible_lines - (topline_datsview != 0) - (topline_datsview + r_visible_lines != totallines); + right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines); } //------------------------------------------------- @@ -1972,7 +1973,7 @@ void software_parts::handle() mame_machine_manager::instance()->schedule_new_driver(*m_uiinfo->driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } } } @@ -2074,7 +2075,7 @@ void bios_selection::handle() moptions.set_value(OPTION_BIOS, elem.second, OPTION_PRIORITY_CMDLINE, error); mame_machine_manager::instance()->schedule_new_driver(*s_driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } else { @@ -2112,7 +2113,7 @@ void bios_selection::handle() reselect_last::set(true); mame_machine_manager::instance()->schedule_new_driver(drivlist.driver()); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } } } diff --git a/src/frontend/mame/ui/selsoft.h b/src/frontend/mame/ui/selsoft.h index faf178565f2..9681a8c2068 100644 --- a/src/frontend/mame/ui/selsoft.h +++ b/src/frontend/mame/ui/selsoft.h @@ -13,13 +13,14 @@ #define MAME_FRONTEND_UI_SELSOFT_H #include "ui/custmenu.h" +#include "ui/selmenu.h" namespace ui { using s_bios = std::vector<std::pair<std::string, int>>; using s_parts = std::unordered_map<std::string, std::string>; // Menu Class -class menu_select_software : public menu +class menu_select_software : public menu_select_launch { public: menu_select_software(mame_ui_manager &mui, render_container *container, const game_driver *driver); diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp index f2325f5e2c1..4526676a960 100644 --- a/src/frontend/mame/ui/simpleselgame.cpp +++ b/src/frontend/mame/ui/simpleselgame.cpp @@ -164,7 +164,7 @@ void simple_menu_select_game::inkey_select(const event *menu_event) { mame_machine_manager::instance()->schedule_new_driver(*driver); machine().schedule_hard_reset(); - menu::stack_reset(machine()); + stack_reset(); } // otherwise, display an error @@ -264,7 +264,7 @@ void simple_menu_select_game::populate() } // if we're forced into this, allow general input configuration as well - if (menu::stack_has_special_main_menu()) + if (stack_has_special_main_menu()) { item_append(menu_item_type::SEPARATOR); item_append(_("Configure Options"), "", 0, (void *)1); diff --git a/src/frontend/mame/ui/sliders.cpp b/src/frontend/mame/ui/sliders.cpp index 8d4143259e8..2cf36b9c85d 100644 --- a/src/frontend/mame/ui/sliders.cpp +++ b/src/frontend/mame/ui/sliders.cpp @@ -53,7 +53,7 @@ void menu_sliders::handle() // toggle visibility case IPT_UI_ON_SCREEN_DISPLAY: if (m_menuless_mode) - menu::stack_pop(machine()); + stack_pop(); else m_hidden = !m_hidden; break; @@ -268,7 +268,7 @@ UINT32 menu_sliders::ui_handler(render_container *container, mame_ui_manager &mu UINT32 result; // if this is the first call, push the sliders menu - if (topmost_menu<menu_sliders>() == nullptr) + if (topmost_menu<menu_sliders>(mui.machine()) == nullptr) menu::stack_push<menu_sliders>(mui, container, true); // handle standard menus @@ -278,7 +278,7 @@ UINT32 menu_sliders::ui_handler(render_container *container, mame_ui_manager &mu if (result == UI_HANDLER_CANCEL) menu::stack_pop(mui.machine()); - menu_sliders *uim = topmost_menu<menu_sliders>(); + menu_sliders *uim = topmost_menu<menu_sliders>(mui.machine()); return uim && uim->m_menuless_mode ? 0 : UI_HANDLER_CANCEL; } diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp index 859fdcc6f11..5eb4fe7fd62 100644 --- a/src/frontend/mame/ui/swlist.cpp +++ b/src/frontend/mame/ui/swlist.cpp @@ -110,7 +110,7 @@ void menu_software_parts::handle() software_part_menu_entry *entry = (software_part_menu_entry *) event->itemref; m_result = entry->type; *m_selected_part = entry->part; - menu::stack_pop(machine()); + stack_pop(); } } @@ -244,7 +244,7 @@ void menu_software_list::handle() { entry_info *info = (entry_info *) event->itemref; m_result = info->short_name; - menu::stack_pop(machine()); + stack_pop(); } else if (event->iptkey == IPT_SPECIAL) { @@ -316,7 +316,7 @@ void menu_software_list::handle() if (m_filename_buffer[0] != '\0') memset(m_filename_buffer, '\0', ARRAY_LENGTH(m_filename_buffer)); m_result = m_filename_buffer; - menu::stack_pop(machine()); + stack_pop(); } } } @@ -402,7 +402,7 @@ void menu_software::handle() if (event != nullptr && event->iptkey == IPT_UI_SELECT) { //menu::stack_push<menu_software_list>(ui(), container, (software_list_config *)event->itemref, image); *m_result = (software_list_device *)event->itemref; - menu::stack_pop(machine()); + stack_pop(); } } diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index df941f3ceb7..c54ad7ebcd4 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -289,7 +289,7 @@ void mame_ui_manager::display_startup_screens(bool first_time) // loop over states set_handler(UI_CALLBACK_TYPE_GENERAL, &mame_ui_manager::handler_ingame); - for (state = 0; state < maxstate && !machine().scheduled_event_pending() && !ui::menu::stack_has_special_main_menu(); state++) + for (state = 0; state < maxstate && !machine().scheduled_event_pending() && !ui::menu::stack_has_special_main_menu(machine()); state++) { // default to standard colors messagebox_backcolor = UI_BACKGROUND_COLOR; @@ -328,7 +328,7 @@ void mame_ui_manager::display_startup_screens(bool first_time) while (machine().input().poll_switches() != INPUT_CODE_INVALID) { } // loop while we have a handler - while (m_handler_callback_type == UI_CALLBACK_TYPE_MODAL && !machine().scheduled_event_pending() && !ui::menu::stack_has_special_main_menu()) + while (m_handler_callback_type == UI_CALLBACK_TYPE_MODAL && !machine().scheduled_event_pending() && !ui::menu::stack_has_special_main_menu(machine())) { machine().video().frame_update(); } @@ -339,7 +339,7 @@ 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()) + if (ui::menu::stack_has_special_main_menu(machine())) show_menu(); } @@ -381,7 +381,7 @@ void mame_ui_manager::update_and_render(render_container *container) if (machine().phase() >= MACHINE_PHASE_RESET && (single_step() || machine().paused())) { int alpha = (1.0f - machine().options().pause_brightness()) * 255.0f; - if (ui::menu::stack_has_special_main_menu()) + if (ui::menu::stack_has_special_main_menu(machine())) alpha = 255; if (alpha > 255) alpha = 255; |