summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/ui/menu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/ui/menu.cpp')
-rw-r--r--src/emu/ui/menu.cpp2019
1 files changed, 1824 insertions, 195 deletions
diff --git a/src/emu/ui/menu.cpp b/src/emu/ui/menu.cpp
index 069b05aa913..547030298bb 100644
--- a/src/emu/ui/menu.cpp
+++ b/src/emu/ui/menu.cpp
@@ -2,9 +2,9 @@
// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
/*********************************************************************
- ui/menu.c
+ ui/menu.c
- Internal MAME menus for the user interface.
+ Internal MAME menus for the user interface.
*********************************************************************/
@@ -15,18 +15,60 @@
#include "ui/ui.h"
#include "ui/menu.h"
#include "ui/mainmenu.h"
-
+#include "ui/utils.h"
+#include "ui/defimg.h"
+#include "ui/starimg.h"
+#include "ui/optsmenu.h"
+#include "ui/datfile.h"
+#include "rendfont.h"
+#include "ui/custmenu.h"
+#include "ui/icorender.h"
+#include "ui/toolbar.h"
/***************************************************************************
- CONSTANTS
+ CONSTANTS
***************************************************************************/
-#define UI_MENU_POOL_SIZE 65536
-#define UI_MENU_ALLOC_ITEMS 256
+#define UI_MENU_POOL_SIZE 65536
+#define MAX_ICONS_RENDER 40
+
+struct ui_arts_info
+{
+ const char *title, *path, *addpath;
+};
+
+static const ui_arts_info arts_info[] =
+{
+ { "Snapshots", OPTION_SNAPSHOT_DIRECTORY, "snap" },
+ { "Cabinets", OPTION_CABINETS_PATH, "cabinets;cabdevs" },
+ { "Control Panels", OPTION_CPANELS_PATH, "cpanel" },
+ { "PCBs", OPTION_PCBS_PATH, "pcb" },
+ { "Flyers", OPTION_FLYERS_PATH, "flyers" },
+ { "Titles", OPTION_TITLES_PATH, "titles" },
+ { "Ends", OPTION_ENDS_PATH, "ends" },
+ { "Artwork Preview", OPTION_ARTPREV_PATH, "artwork preview" },
+ { "Bosses", OPTION_BOSSES_PATH, "bosses" },
+ { "Logos", OPTION_LOGOS_PATH, "logo" },
+ { "Versus", OPTION_VERSUS_PATH, "versus" },
+ { "Game Over", OPTION_GAMEOVER_PATH, "gameover" },
+ { "HowTo", OPTION_HOWTO_PATH, "howto" },
+ { "Scores", OPTION_SCORES_PATH, "scores" },
+ { "Select", OPTION_SELECT_PATH, "select" },
+ { "Marquees", OPTION_MARQUEES_PATH, "marquees" },
+ { nullptr }
+};
+
+static const char *hover_msg[] = {
+ "Add or remove favorites",
+ "Export displayed list to file",
+ "Show DATs view",
+ "Setup directories",
+ "Configure options"
+};
/***************************************************************************
- GLOBAL VARIABLES
+ GLOBAL VARIABLES
***************************************************************************/
ui_menu *ui_menu::menu_stack;
@@ -34,9 +76,24 @@ ui_menu *ui_menu::menu_free;
std::unique_ptr<bitmap_rgb32> ui_menu::hilight_bitmap;
render_texture *ui_menu::hilight_texture;
render_texture *ui_menu::arrow_texture;
+render_texture *ui_menu::snapx_texture;
+render_texture *ui_menu::hilight_main_texture;
+render_texture *ui_menu::bgrnd_texture;
+render_texture *ui_menu::star_texture;
+render_texture *ui_menu::toolbar_texture[UI_TOOLBAR_BUTTONS];
+render_texture *ui_menu::sw_toolbar_texture[UI_TOOLBAR_BUTTONS];
+render_texture *ui_menu::icons_texture[MAX_ICONS_RENDER];
+std::unique_ptr<bitmap_argb32> ui_menu::snapx_bitmap;
+std::unique_ptr<bitmap_argb32> ui_menu::no_avail_bitmap;
+std::unique_ptr<bitmap_argb32> ui_menu::star_bitmap;
+std::unique_ptr<bitmap_argb32> ui_menu::bgrnd_bitmap;
+bitmap_argb32 *ui_menu::icons_bitmap[MAX_ICONS_RENDER];
+std::unique_ptr<bitmap_rgb32> ui_menu::hilight_main_bitmap;
+bitmap_argb32 *ui_menu::toolbar_bitmap[UI_TOOLBAR_BUTTONS];
+bitmap_argb32 *ui_menu::sw_toolbar_bitmap[UI_TOOLBAR_BUTTONS];
/***************************************************************************
- INLINE FUNCTIONS
+ INLINE FUNCTIONS
***************************************************************************/
//-------------------------------------------------
@@ -69,7 +126,7 @@ inline bool ui_menu::exclusive_input_pressed(int key, int repeat)
/***************************************************************************
- CORE SYSTEM MANAGEMENT
+ CORE SYSTEM MANAGEMENT
***************************************************************************/
//-------------------------------------------------
@@ -78,14 +135,12 @@ inline bool ui_menu::exclusive_input_pressed(int key, int repeat)
void ui_menu::init(running_machine &machine)
{
- int x;
-
// initialize the menu stack
ui_menu::stack_reset(machine);
// create a texture for hilighting items
hilight_bitmap = std::make_unique<bitmap_rgb32>(256, 1);
- for (x = 0; x < 256; x++)
+ for (int x = 0; x < 256; x++)
{
int alpha = 0xff;
if (x < 25) alpha = 0xff * x / 25;
@@ -98,6 +153,9 @@ void ui_menu::init(running_machine &machine)
// create a texture for arrow icons
arrow_texture = machine.render().texture_alloc(render_triangle);
+ // initialize ui
+ init_ui(machine);
+
// add an exit callback to free memory
machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(ui_menu::exit), &machine));
}
@@ -114,14 +172,28 @@ void ui_menu::exit(running_machine &machine)
ui_menu::clear_free_list(machine);
// free textures
- machine.render().texture_free(hilight_texture);
- machine.render().texture_free(arrow_texture);
+ 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]);
+ }
}
/***************************************************************************
- CORE MENU MANAGEMENT
+ CORE MENU MANAGEMENT
***************************************************************************/
//-------------------------------------------------
@@ -134,6 +206,8 @@ ui_menu::ui_menu(running_machine &machine, render_container *_container) : m_mac
container = _container;
reset(UI_MENU_RESET_SELECT_FIRST);
+
+ top_line = 0;
}
@@ -148,12 +222,8 @@ ui_menu::~ui_menu()
{
ui_menu_pool *ppool = pool;
pool = pool->next;
- auto_free(machine(), ppool);
+ global_free(ppool);
}
-
- // free the item array
- if (item)
- auto_free(machine(), item);
}
@@ -172,14 +242,14 @@ void ui_menu::reset(ui_menu_reset_options options)
else if (options == UI_MENU_RESET_REMEMBER_REF)
resetref = item[selected].ref;
- // reset all the pools and the numitems back to 0
+ // reset all the pools and the item.size() back to 0
for (ui_menu_pool *ppool = pool; ppool != nullptr; ppool = ppool->next)
ppool->top = (UINT8 *)(ppool + 1);
- numitems = 0;
+ item.clear();
visitems = 0;
selected = 0;
std::string backtext;
- strprintf(backtext, "Return to %s", emulator_info::get_capstartgamenoun());
+ strprintf(backtext, "Return to Machine");
// add an item to return
if (parent == nullptr)
@@ -214,66 +284,42 @@ void ui_menu::set_special_main_menu(bool special)
//-------------------------------------------------
-// populated - returns true if the menu
-// has any non-default items in it
-//-------------------------------------------------
-
-bool ui_menu::populated()
-{
- return numitems > 1;
-}
-
-
-//-------------------------------------------------
// item_append - append a new item to the
// end of the menu
//-------------------------------------------------
void ui_menu::item_append(const char *text, const char *subtext, UINT32 flags, void *ref)
{
- ui_menu_item *pitem;
- int index;
-
// only allow multiline as the first item
if ((flags & MENU_FLAG_MULTILINE) != 0)
- assert(numitems == 1);
+ assert(item.size() == 1);
// only allow a single multi-line item
- else if (numitems >= 2)
+ else if (item.size() >= 2)
assert((item[0].flags & MENU_FLAG_MULTILINE) == 0);
- // realloc the item array if necessary
- if (numitems >= allocitems)
- {
- int olditems = allocitems;
- allocitems += UI_MENU_ALLOC_ITEMS;
- ui_menu_item *newitems = auto_alloc_array(machine(), ui_menu_item, allocitems);
- for (int itemnum = 0; itemnum < olditems; itemnum++)
- newitems[itemnum] = item[itemnum];
- auto_free(machine(), item);
- item = newitems;
- }
- index = numitems++;
-
- // copy the previous last item to the next one
- if (index != 0)
+ // allocate a new item and populate it
+ ui_menu_item pitem;
+ pitem.text = (text != nullptr) ? pool_strdup(text) : nullptr;
+ pitem.subtext = (subtext != nullptr) ? pool_strdup(subtext) : nullptr;
+ pitem.flags = flags;
+ pitem.ref = ref;
+
+ // append to array
+ int index = item.size();
+ if (!item.empty())
{
- index--;
- item[index + 1] = item[index];
+ item.insert(item.end() - 1, pitem);
+ --index;
}
-
- // allocate a new item and populate it
- pitem = &item[index];
- pitem->text = (text != nullptr) ? pool_strdup(text) : nullptr;
- pitem->subtext = (subtext != nullptr) ? pool_strdup(subtext) : nullptr;
- pitem->flags = flags;
- pitem->ref = ref;
+ else
+ item.push_back(pitem);
// update the selection if we need to
if (resetpos == index || (resetref != nullptr && resetref == ref))
selected = index;
- if (resetpos == numitems - 1)
- selected = numitems - 1;
+ if (resetpos == item.size() - 1)
+ selected = item.size() - 1;
}
@@ -288,27 +334,42 @@ const ui_menu_event *ui_menu::process(UINT32 flags)
menu_event.iptkey = IPT_INVALID;
// first make sure our selection is valid
- validate_selection(1);
+// if (!(flags & UI_MENU_PROCESS_NOINPUT))
+ validate_selection(1);
// draw the menu
- if (numitems > 1 && (item[0].flags & MENU_FLAG_MULTILINE) != 0)
+ if (item.size() > 1 && (item[0].flags & MENU_FLAG_MULTILINE) != 0)
draw_text_box();
+ else if ((item[0].flags & MENU_FLAG_UI ) != 0 || (item[0].flags & MENU_FLAG_UI_SWLIST ) != 0)
+ draw_select_game(flags & UI_MENU_PROCESS_NOINPUT);
+ else if ((item[0].flags & MENU_FLAG_UI_PALETTE ) != 0)
+ draw_palette_menu();
+ else if ((item[0].flags & MENU_FLAG_UI_DATS) != 0)
+ draw_dats_menu();
else
- draw(flags & UI_MENU_PROCESS_CUSTOM_ONLY);
+ draw(flags & UI_MENU_PROCESS_CUSTOM_ONLY, flags & UI_MENU_PROCESS_NOIMAGE, flags & UI_MENU_PROCESS_NOINPUT);
// process input
- if (!(flags & UI_MENU_PROCESS_NOKEYS))
+ if (!(flags & UI_MENU_PROCESS_NOKEYS) && !(flags & UI_MENU_PROCESS_NOINPUT))
{
// read events
- handle_events();
+ if ((item[0].flags & MENU_FLAG_UI ) != 0 || (item[0].flags & MENU_FLAG_UI_SWLIST ) != 0)
+ handle_main_events(flags);
+ else
+ handle_events(flags);
// handle the keys if we don't already have an menu_event
if (menu_event.iptkey == IPT_INVALID)
- handle_keys(flags);
+ {
+ if ((item[0].flags & MENU_FLAG_UI ) != 0 || (item[0].flags & MENU_FLAG_UI_SWLIST ) != 0)
+ handle_main_keys(flags);
+ else
+ handle_keys(flags);
+ }
}
// update the selected item in the menu_event
- if (menu_event.iptkey != IPT_INVALID && selected >= 0 && selected < numitems)
+ if (menu_event.iptkey != IPT_INVALID && selected >= 0 && selected < item.size())
{
menu_event.itemref = item[selected].ref;
return &menu_event;
@@ -338,7 +399,7 @@ void *ui_menu::m_pool_alloc(size_t size)
}
// allocate a new pool
- ppool = (ui_menu_pool *)auto_alloc_array_clear(machine(), UINT8, sizeof(*ppool) + UI_MENU_POOL_SIZE);
+ ppool = (ui_menu_pool *)global_alloc_array_clear<UINT8>(sizeof(*ppool) + UI_MENU_POOL_SIZE);
// wire it up
ppool->next = pool;
@@ -367,7 +428,7 @@ const char *ui_menu::pool_strdup(const char *string)
void *ui_menu::get_selection()
{
- return (selected >= 0 && selected < numitems) ? item[selected].ref : nullptr;
+ return (selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr;
}
@@ -378,10 +439,8 @@ void *ui_menu::get_selection()
void ui_menu::set_selection(void *selected_itemref)
{
- int itemnum;
-
selected = -1;
- for (itemnum = 0; itemnum < numitems; itemnum++)
+ for (int itemnum = 0; itemnum < item.size(); itemnum++)
if (item[itemnum].ref == selected_itemref)
{
selected = itemnum;
@@ -392,38 +451,39 @@ void ui_menu::set_selection(void *selected_itemref)
/***************************************************************************
- INTERNAL MENU PROCESSING
+ INTERNAL MENU PROCESSING
***************************************************************************/
//-------------------------------------------------
// draw - draw a menu
//-------------------------------------------------
-void ui_menu::draw(bool customonly)
+void ui_menu::draw(bool customonly, bool noimage, bool noinput)
{
+ // first draw the FPS counter
+ if (machine().ui().show_fps_counter())
+ {
+ machine().ui().draw_text_full(container, machine().video().speed_text().c_str(), 0.0f, 0.0f, 1.0f,
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_OPAQUE, ARGB_WHITE, ARGB_BLACK, nullptr, nullptr);
+ }
+
float line_height = machine().ui().get_line_height();
float lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect();
float ud_arrow_width = line_height * machine().render().ui_aspect();
float gutter_width = lr_arrow_width * 1.3f;
- float x1, y1, x2, y2;
-
- float effective_width, effective_left;
- float visible_width, visible_main_menu_height;
- float visible_extra_menu_height;
- float visible_top, visible_left;
- int selected_subitem_too_big = FALSE;
- int visible_lines;
- int top_line;
+
+ bool selected_subitem_too_big = false;
int itemnum, linenum;
bool mouse_hit, mouse_button;
- render_target *mouse_target;
- INT32 mouse_target_x, mouse_target_y;
float mouse_x = -1, mouse_y = -1;
+ if (machine().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, ARGB_WHITE, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
// compute the width and height of the full menu
- visible_width = 0;
- visible_main_menu_height = 0;
- for (itemnum = 0; itemnum < numitems; itemnum++)
+ float visible_width = 0;
+ float visible_main_menu_height = 0;
+ for (itemnum = 0; itemnum < item.size(); itemnum++)
{
const ui_menu_item &pitem = item[itemnum];
float total_width;
@@ -444,7 +504,7 @@ void ui_menu::draw(bool customonly)
}
// account for extra space at the top and bottom
- visible_extra_menu_height = customtop + custombottom;
+ float visible_extra_menu_height = customtop + custombottom;
// add a little bit of slop for rounding
visible_width += 0.01f;
@@ -462,44 +522,46 @@ void ui_menu::draw(bool customonly)
visible_main_menu_height = (float)visible_lines * line_height;
// compute top/left of inner menu area by centering
- visible_left = (1.0f - visible_width) * 0.5f;
- visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f;
+ float visible_left = (1.0f - visible_width) * 0.5f;
+ 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;
// first add us a box
- x1 = visible_left - UI_BOX_LR_BORDER;
- y1 = visible_top - UI_BOX_TB_BORDER;
- x2 = visible_left + visible_width + UI_BOX_LR_BORDER;
- y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER;
+ float x1 = visible_left - UI_BOX_LR_BORDER;
+ float y1 = visible_top - UI_BOX_TB_BORDER;
+ float x2 = visible_left + visible_width + UI_BOX_LR_BORDER;
+ float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER;
if (!customonly)
machine().ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
// determine the first visible line based on the current selection
- top_line = selected - visible_lines / 2;
- if (top_line < 0)
+ if (top_line < 0 || selected == 0)
top_line = 0;
- if (top_line + visible_lines >= numitems)
- top_line = numitems - visible_lines;
+ if (top_line + visible_lines >= item.size())
+ top_line = item.size() - visible_lines;
// determine effective positions taking into account the hilighting arrows
- effective_width = visible_width - 2.0f * gutter_width;
- effective_left = visible_left + gutter_width;
+ float effective_width = visible_width - 2.0f * gutter_width;
+ float effective_left = visible_left + gutter_width;
// locate mouse
mouse_hit = false;
mouse_button = false;
- if (!customonly)
+ if (!customonly && !noinput)
{
- mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button);
+ INT32 mouse_target_x, mouse_target_y;
+ render_target *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;
}
// loop over visible lines
- hover = numitems + 1;
+ hover = item.size() + 1;
+ float line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
+ float line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
if (!customonly)
for (linenum = 0; linenum < visible_lines; linenum++)
{
@@ -511,9 +573,7 @@ void ui_menu::draw(bool customonly)
rgb_t bgcolor = UI_TEXT_BG_COLOR;
rgb_t fgcolor2 = UI_SUBITEM_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
@@ -530,7 +590,7 @@ void ui_menu::draw(bool customonly)
}
// else if the mouse is over this item, draw with a different background
- else if (itemnum == hover)
+ else if (itemnum == hover && ((linenum == 0 && top_line != 0) || (linenum == visible_lines - 1 && itemnum != item.size() - 1)))
{
fgcolor = UI_MOUSEOVER_COLOR;
bgcolor = UI_MOUSEOVER_BG_COLOR;
@@ -545,8 +605,7 @@ void ui_menu::draw(bool customonly)
// if we're on the top line, display the up arrow
if (linenum == 0 && top_line != 0)
{
- draw_arrow(
- container,
+ 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,
@@ -554,14 +613,13 @@ void ui_menu::draw(bool customonly)
fgcolor,
ROT0);
if (hover == itemnum)
- hover = -2;
+ hover = HOVER_ARROW_UP;
}
// if we're on the bottom line, display the down arrow
- else if (linenum == visible_lines - 1 && itemnum != numitems - 1)
+ else if (linenum == visible_lines - 1 && itemnum != item.size() - 1)
{
- draw_arrow(
- container,
+ 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,
@@ -569,7 +627,7 @@ void ui_menu::draw(bool customonly)
fgcolor,
ROT0 ^ ORIENTATION_FLIP_Y);
if (hover == itemnum)
- hover = -1;
+ hover = HOVER_ARROW_DOWN;
}
// if we're just a divider, draw a line
@@ -579,7 +637,7 @@ void ui_menu::draw(bool customonly)
// if we don't have a subitem, just draw the string centered
else if (pitem.subtext == nullptr)
machine().ui().draw_text_full(container, itemtext, effective_left, line_y, effective_width,
- JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+ JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
// otherwise, draw the item on the left and the subitem text on the right
else
@@ -600,9 +658,19 @@ void ui_menu::draw(bool customonly)
{
subitem_text = "...";
if (itemnum == selected)
- selected_subitem_too_big = TRUE;
+ selected_subitem_too_big = true;
}
+ // customize subitem text color
+ if (!core_stricmp(subitem_text, "On"))
+ fgcolor2 = rgb_t(0xff,0x00,0xff,0x00);
+
+ if (!core_stricmp(subitem_text, "Off"))
+ fgcolor2 = rgb_t(0xff,0xff,0x00,0x00);
+
+ if (!core_stricmp(subitem_text, "Auto"))
+ fgcolor2 = rgb_t(0xff,0xff,0xff,0x00);
+
// draw the subitem right-justified
machine().ui().draw_text_full(container, subitem_text, effective_left + item_width, line_y, effective_width - item_width,
JUSTIFY_RIGHT, WRAP_TRUNCATE, DRAW_NORMAL, subitem_invert ? fgcolor3 : fgcolor2, bgcolor, &subitem_width, nullptr);
@@ -610,8 +678,7 @@ void ui_menu::draw(bool customonly)
// apply arrows
if (itemnum == selected && (pitem.flags & MENU_FLAG_LEFT_ARROW))
{
- draw_arrow(
- container,
+ draw_arrow(container,
effective_left + effective_width - subitem_width - gutter_width,
line_y + 0.1f * line_height,
effective_left + effective_width - subitem_width - gutter_width + lr_arrow_width,
@@ -621,8 +688,7 @@ void ui_menu::draw(bool customonly)
}
if (itemnum == selected && (pitem.flags & MENU_FLAG_RIGHT_ARROW))
{
- draw_arrow(
- container,
+ draw_arrow(container,
effective_left + effective_width + gutter_width - lr_arrow_width,
line_y + 0.1f * line_height,
effective_left + effective_width + gutter_width,
@@ -645,7 +711,7 @@ void ui_menu::draw(bool customonly)
// compute the multi-line target width/height
machine().ui().draw_text_full(container, pitem.subtext, 0, 0, visible_width * 0.75f,
- JUSTIFY_RIGHT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
+ JUSTIFY_RIGHT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
// determine the target location
target_x = visible_left + visible_width - target_width - UI_BOX_LR_BORDER;
@@ -657,16 +723,19 @@ void ui_menu::draw(bool customonly)
machine().ui().draw_outlined_box(container, target_x - UI_BOX_LR_BORDER,
target_y - UI_BOX_TB_BORDER,
target_x + target_width + UI_BOX_LR_BORDER,
- target_y + target_height + UI_BOX_TB_BORDER, subitem_invert ? UI_SELECTED_BG_COLOR : UI_BACKGROUND_COLOR);
+ target_y + target_height + UI_BOX_TB_BORDER,
+ subitem_invert ? UI_SELECTED_BG_COLOR : UI_BACKGROUND_COLOR);
machine().ui().draw_text_full(container, pitem.subtext, target_x, target_y, target_width,
JUSTIFY_RIGHT, WRAP_WORD, DRAW_NORMAL, UI_SELECTED_COLOR, UI_SELECTED_BG_COLOR, nullptr, nullptr);
}
// if there is something special to add, do it by calling the virtual method
- custom_render((selected >= 0 && selected < numitems) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
+ custom_render((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
// return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
- visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != numitems);
+ visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != item.size());
+// if (history_flag && (top_line + visible_lines >= item.size()))
+// selected = item.size() - 1;
}
void ui_menu::custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2)
@@ -691,7 +760,7 @@ void ui_menu::draw_text_box()
// compute the multi-line target width/height
machine().ui().draw_text_full(container, text, 0, 0, 1.0f - 2.0f * UI_BOX_LR_BORDER - 2.0f * gutter_width,
- JUSTIFY_LEFT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
+ JUSTIFY_LEFT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);
target_height += 2.0f * line_height;
if (target_height > 1.0f - 2.0f * UI_BOX_TB_BORDER)
target_height = floorf((1.0f - 2.0f * UI_BOX_TB_BORDER) / line_height) * line_height;
@@ -716,25 +785,25 @@ void ui_menu::draw_text_box()
// add a box around that
machine().ui().draw_outlined_box(container, target_x - UI_BOX_LR_BORDER - gutter_width,
- target_y - UI_BOX_TB_BORDER,
- target_x + target_width + gutter_width + UI_BOX_LR_BORDER,
- target_y + target_height + UI_BOX_TB_BORDER, (item[0].flags & MENU_FLAG_REDTEXT) ? UI_RED_COLOR : UI_BACKGROUND_COLOR);
+ target_y - UI_BOX_TB_BORDER,
+ target_x + target_width + gutter_width + UI_BOX_LR_BORDER,
+ target_y + target_height + UI_BOX_TB_BORDER,
+ (item[0].flags & MENU_FLAG_REDTEXT) ? UI_RED_COLOR : UI_BACKGROUND_COLOR);
machine().ui().draw_text_full(container, text, target_x, target_y, target_width,
JUSTIFY_LEFT, WRAP_WORD, DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
// draw the "return to prior menu" text with a hilight behind it
- highlight(
- container,
- target_x + 0.5f * UI_LINE_WIDTH,
- target_y + target_height - line_height,
- target_x + target_width - 0.5f * UI_LINE_WIDTH,
- target_y + target_height,
- UI_SELECTED_BG_COLOR);
+ highlight(container,
+ target_x + 0.5f * UI_LINE_WIDTH,
+ target_y + target_height - line_height,
+ target_x + target_width - 0.5f * UI_LINE_WIDTH,
+ target_y + target_height,
+ UI_SELECTED_BG_COLOR);
machine().ui().draw_text_full(container, backtext, target_x, target_y + target_height - line_height, target_width,
JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, UI_SELECTED_COLOR, UI_SELECTED_BG_COLOR, nullptr, nullptr);
// artificially set the hover to the last item so a double-click exits
- hover = numitems - 1;
+ hover = item.size() - 1;
}
@@ -743,9 +812,9 @@ void ui_menu::draw_text_box()
// input events for a menu
//-------------------------------------------------
-void ui_menu::handle_events()
+void ui_menu::handle_events(UINT32 flags)
{
- int stop = FALSE;
+ bool stop = false;
ui_event local_menu_event;
// loop while we have interesting events
@@ -755,35 +824,82 @@ void ui_menu::handle_events()
{
// if we are hovering over a valid item, select it with a single click
case UI_EVENT_MOUSE_DOWN:
- if (hover >= 0 && hover < numitems)
- selected = hover;
- else if (hover == -2)
- {
- selected -= visitems - 1;
- validate_selection(1);
- }
- else if (hover == -1)
+ if ((flags & UI_MENU_PROCESS_ONLYCHAR) == 0)
{
- selected += visitems - 1;
- validate_selection(1);
+ if (hover >= 0 && hover < item.size())
+ selected = hover;
+ else if (hover == HOVER_ARROW_UP)
+ {
+ if ((flags & MENU_FLAG_UI_DATS) != 0)
+ {
+ top_line -= visitems - (top_line + visible_lines == item.size() - 1);
+ return;
+ }
+ selected -= visitems;
+ if (selected < 0)
+ selected = 0;
+ top_line -= visitems - (top_line + visible_lines == item.size() - 1);
+ }
+ else if (hover == HOVER_ARROW_DOWN)
+ {
+ if ((flags & MENU_FLAG_UI_DATS) != 0)
+ {
+ top_line += visible_lines - 2;
+ return;
+ }
+ selected += visible_lines - 2 + (selected == 0);
+ if (selected > item.size() - 1)
+ selected = item.size() - 1;
+ top_line += visible_lines - 2;
+ }
}
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 < numitems)
+ if ((flags & UI_MENU_PROCESS_ONLYCHAR) == 0 && hover >= 0 && hover < item.size())
{
selected = hover;
- if (local_menu_event.event_type == UI_EVENT_MOUSE_DOUBLE_CLICK)
+ menu_event.iptkey = IPT_UI_SELECT;
+ if (selected == item.size() - 1)
{
- menu_event.iptkey = IPT_UI_SELECT;
- if (selected == numitems - 1)
+ menu_event.iptkey = IPT_UI_CANCEL;
+ ui_menu::stack_pop(machine());
+ }
+ stop = true;
+ }
+ break;
+
+ // caught scroll event
+ case UI_EVENT_MOUSE_WHEEL:
+ if ((flags & UI_MENU_PROCESS_ONLYCHAR) == 0)
+ {
+ if (local_menu_event.zdelta > 0)
+ {
+ if ((flags & MENU_FLAG_UI_DATS) != 0)
{
- menu_event.iptkey = IPT_UI_CANCEL;
- ui_menu::stack_pop(machine());
+ top_line -= local_menu_event.num_lines;
+ return;
}
+ selected -= local_menu_event.num_lines;
+ validate_selection(-1);
+ if (selected < top_line + (top_line != 0))
+ top_line -= local_menu_event.num_lines;
+ }
+ else
+ {
+ if ((flags & MENU_FLAG_UI_DATS) != 0)
+ {
+ top_line += local_menu_event.num_lines;
+ return;
+ }
+ selected += local_menu_event.num_lines;
+ validate_selection(1);
+ if (selected > item.size() - 1)
+ selected = item.size() - 1;
+ if (selected >= top_line + visitems + (top_line != 0))
+ top_line += local_menu_event.num_lines;
}
- stop = TRUE;
}
break;
@@ -791,7 +907,7 @@ void ui_menu::handle_events()
case UI_EVENT_CHAR:
menu_event.iptkey = IPT_SPECIAL;
menu_event.unichar = local_menu_event.ch;
- stop = TRUE;
+ stop = true;
break;
// ignore everything else
@@ -809,19 +925,17 @@ void ui_menu::handle_events()
void ui_menu::handle_keys(UINT32 flags)
{
- int ignorepause = ui_menu::stack_has_special_main_menu();
- int ignoreright;
- int ignoreleft;
+ bool ignorepause = ui_menu::stack_has_special_main_menu();
int code;
// bail if no items
- if (numitems == 0)
+ if (item.empty())
return;
// if we hit select, return TRUE or pop the stack, depending on the item
if (exclusive_input_pressed(IPT_UI_SELECT, 0))
{
- if (selected == numitems - 1)
+ if (selected == item.size() - 1)
{
menu_event.iptkey = IPT_UI_CANCEL;
ui_menu::stack_pop(machine());
@@ -829,10 +943,15 @@ void ui_menu::handle_keys(UINT32 flags)
return;
}
+ // bail out
+ if ((flags & UI_MENU_PROCESS_ONLYCHAR) != 0)
+ return;
+
// hitting cancel also pops the stack
if (exclusive_input_pressed(IPT_UI_CANCEL, 0))
{
- ui_menu::stack_pop(machine());
+ if (!menu_has_search_active())
+ ui_menu::stack_pop(machine());
return;
}
@@ -840,8 +959,11 @@ void ui_menu::handle_keys(UINT32 flags)
validate_selection(1);
// swallow left/right keys if they are not appropriate
- ignoreleft = ((item[selected].flags & MENU_FLAG_LEFT_ARROW) == 0);
- ignoreright = ((item[selected].flags & MENU_FLAG_RIGHT_ARROW) == 0);
+ bool ignoreleft = ((item[selected].flags & MENU_FLAG_LEFT_ARROW) == 0);
+ bool ignoreright = ((item[selected].flags & MENU_FLAG_RIGHT_ARROW) == 0);
+
+ if ((item[0].flags & MENU_FLAG_UI_DATS) != 0)
+ ignoreleft = ignoreright = false;
// accept left/right keys as-is with repeat
if (!ignoreleft && exclusive_input_pressed(IPT_UI_LEFT, (flags & UI_MENU_PROCESS_LR_REPEAT) ? 6 : 0))
@@ -852,42 +974,60 @@ void ui_menu::handle_keys(UINT32 flags)
// up backs up by one item
if (exclusive_input_pressed(IPT_UI_UP, 6))
{
- selected = (selected + numitems - 1) % numitems;
+ if ((item[0].flags & MENU_FLAG_UI_DATS) != 0)
+ {
+ top_line--;
+ return;
+ }
+ (selected == 0) ? selected = top_line = item.size() - 1 : --selected;
validate_selection(-1);
+ top_line -= (selected == top_line && top_line != 0);
}
// down advances by one item
if (exclusive_input_pressed(IPT_UI_DOWN, 6))
{
- selected = (selected + 1) % numitems;
- validate_selection(1);
+ if ((item[0].flags & MENU_FLAG_UI_DATS) != 0)
+ {
+ top_line++;
+ return;
+ }
+ (selected == item.size() - 1) ? selected = top_line = 0 : ++selected;
+ top_line += (selected == top_line + visitems + (top_line != 0));
}
// page up backs up by visitems
if (exclusive_input_pressed(IPT_UI_PAGE_UP, 6))
{
- selected -= visitems - 1;
+ selected -= visitems;
+ top_line -= visitems - (top_line + visible_lines == item.size() - 1);
+ if (selected < 0)
+ selected = 0;
validate_selection(1);
}
// page down advances by visitems
if (exclusive_input_pressed(IPT_UI_PAGE_DOWN, 6))
{
- selected += visitems - 1;
+ selected += visible_lines - 2 + (selected == 0);
+ top_line += visible_lines - 2;
+
+ if (selected > item.size() - 1)
+ selected = item.size() - 1;
validate_selection(-1);
}
// home goes to the start
if (exclusive_input_pressed(IPT_UI_HOME, 0))
{
- selected = 0;
+ selected = top_line = 0;
validate_selection(1);
}
// end goes to the last
if (exclusive_input_pressed(IPT_UI_END, 0))
{
- selected = numitems - 1;
+ selected = top_line = item.size() - 1;
validate_selection(-1);
}
@@ -927,12 +1067,12 @@ void ui_menu::validate_selection(int scandir)
// clamp to be in range
if (selected < 0)
selected = 0;
- else if (selected >= numitems)
- selected = numitems - 1;
+ else if (selected >= item.size())
+ selected = item.size() - 1;
// skip past unselectable items
while (!item[selected].is_selectable())
- selected = (selected + numitems + scandir) % numitems;
+ selected = (selected + item.size() + scandir) % item.size();
}
@@ -948,14 +1088,14 @@ void ui_menu::clear_free_list(running_machine &machine)
{
ui_menu *menu = menu_free;
menu_free = menu->parent;
- auto_free(machine, menu);
+ global_free(menu);
}
}
/***************************************************************************
- MENU STACK MANAGEMENT
+ MENU STACK MANAGEMENT
***************************************************************************/
//-------------------------------------------------
@@ -1018,14 +1158,14 @@ bool ui_menu::stack_has_special_main_menu()
void ui_menu::do_handle()
{
- if(!populated())
+ if(item.size() < 2)
populate();
handle();
}
/***************************************************************************
- UI SYSTEM INTERACTION
+ UI SYSTEM INTERACTION
***************************************************************************/
//-------------------------------------------------
@@ -1037,7 +1177,7 @@ UINT32 ui_menu::ui_handler(running_machine &machine, render_container *container
{
// if we have no menus stacked up, start with the main menu
if (menu_stack == nullptr)
- stack_push(auto_alloc_clear(machine, <ui_menu_main>(machine, container)));
+ stack_push(global_alloc_clear<ui_menu_main>(machine, container));
// update the menu state
if (menu_stack != nullptr)
@@ -1054,7 +1194,7 @@ UINT32 ui_menu::ui_handler(running_machine &machine, render_container *container
}
/***************************************************************************
- MENU HELPERS
+ MENU HELPERS
***************************************************************************/
//-------------------------------------------------
@@ -1118,8 +1258,7 @@ void ui_menu::render_triangle(bitmap_argb32 &dest, bitmap_argb32 &source, const
void ui_menu::highlight(render_container *container, float x0, float y0, float x1, float y1, rgb_t bgcolor)
{
- container->add_quad(x0, y0, x1, y1, bgcolor, hilight_texture,
- PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ container->add_quad(x0, y0, x1, y1, bgcolor, hilight_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE) | PRIMFLAG_PACKABLE);
}
@@ -1129,12 +1268,1502 @@ void ui_menu::highlight(render_container *container, float x0, float y0, float x
void ui_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));
+ container->add_quad(x0, y0, x1, y1, fgcolor, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(orientation) | PRIMFLAG_PACKABLE);
+}
+
+//-------------------------------------------------
+// init - initialize the ui menu system
+//-------------------------------------------------
+
+void ui_menu::init_ui(running_machine &machine)
+{
+ render_manager &mrender = machine.render();
+ // create a texture for hilighting items in main menu
+ hilight_main_bitmap = std::make_unique<bitmap_rgb32>(1, 26);
+ int r1 = 0, g1 = 169, b1 = 255; //Any start color
+ int r2 = 0, g2 = 39, b2 = 130; //Any stop color
+ for (int y = 0; y < 26; y++)
+ {
+ int r = r1 + (y * (r2 - r1) / 26);
+ int g = g1 + (y * (g2 - g1) / 26);
+ int b = b1 + (y * (b2 - b1) / 26);
+ hilight_main_bitmap->pix32(y, 0) = rgb_t(0xff, r, g, b);
+ }
+
+ hilight_main_texture = mrender.texture_alloc();
+ hilight_main_texture->set_bitmap(*hilight_main_bitmap, hilight_main_bitmap->cliprect(), TEXFORMAT_ARGB32);
+
+ // 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 (int i = 0; i < MAX_ICONS_RENDER; i++)
+ {
+ icons_bitmap[i] = auto_alloc(machine, bitmap_argb32);
+ icons_texture[i] = 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);
+
+ ui_options &mopt = machine.ui().options();
+ 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[x] = auto_alloc(machine, bitmap_argb32(32, 32));
+ sw_toolbar_bitmap[x] = auto_alloc(machine, bitmap_argb32(32, 32));
+ toolbar_texture[x] = mrender.texture_alloc();
+ sw_toolbar_texture[x] = mrender.texture_alloc();
+ UINT32 *dst = &toolbar_bitmap[x]->pix32(0);
+ memcpy(dst, toolbar_bitmap_bmp[x], 32 * 32 * sizeof(UINT32));
+ if (toolbar_bitmap[x]->valid())
+ toolbar_texture[x]->set_bitmap(*toolbar_bitmap[x], toolbar_bitmap[x]->cliprect(), TEXFORMAT_ARGB32);
+ else
+ toolbar_bitmap[x]->reset();
+
+ if (x == 0 || x == 2)
+ {
+ dst = &sw_toolbar_bitmap[x]->pix32(0);
+ memcpy(dst, toolbar_bitmap_bmp[x], 32 * 32 * sizeof(UINT32));
+ if (sw_toolbar_bitmap[x]->valid())
+ sw_toolbar_texture[x]->set_bitmap(*sw_toolbar_bitmap[x], sw_toolbar_bitmap[x]->cliprect(), TEXFORMAT_ARGB32);
+ else
+ sw_toolbar_bitmap[x]->reset();
+ }
+ else
+ sw_toolbar_bitmap[x]->reset();
+
+ }
+}
+
+
+//-------------------------------------------------
+// draw main menu
+//-------------------------------------------------
+
+void ui_menu::draw_select_game(bool noinput)
+{
+ float line_height = machine().ui().get_line_height();
+ float ud_arrow_width = line_height * machine().render().ui_aspect();
+ float gutter_width = 0.52f * line_height * machine().render().ui_aspect();
+ 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 & MENU_FLAG_UI_SWLIST) != 0);
+ bool is_favorites = ((item[0].flags & MENU_FLAG_UI_FAVORITE) != 0);
+ ui_manager &mui = machine().ui();
+
+ // draw background image if available
+ if (machine().ui().options().use_background_image() && bgrnd_bitmap->valid())
+ container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, ARGB_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 != 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;
+ visible_lines = floor(visible_main_menu_height / line_height);
+ visible_main_menu_height = (float)(visible_lines * line_height);
+
+ if (!is_swlist)
+ ui_globals::visible_main_lines = visible_lines;
+ else
+ ui_globals::visible_sw_lines = 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)(visible_lines * line_height);
+
+ //machine().ui().draw_outlined_box(container, x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B));
+ mui.draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
+
+ if (visible_items < visible_lines)
+ visible_lines = visible_items;
+ if (top_line < 0 || selected == 0)
+ top_line = 0;
+ if (selected < visible_items && top_line + visible_lines >= visible_items)
+ top_line = visible_items - 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 n_loop = (visible_items >= visible_lines) ? 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 ui_menu_item &pitem = item[itemnum];
+ const char *itemtext = pitem.text;
+ 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 && pitem.is_selectable())
+ hover = itemnum;
+
+ // if we're selected, draw with a different background
+ if (itemnum == selected)
+ {
+ fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
+ bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
+ fgcolor3 = rgb_t(0xff, 0xcc, 0xcc, 0x00);
+ }
+ // 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;
+ }
+
+ // if we have some background hilighting to do, add a quad behind everything else
+ if (bgcolor != UI_TEXT_BG_COLOR)
+ mui.draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(255, 43, 43, 43),
+ hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+
+ // 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 (hover == itemnum)
+ hover = HOVER_ARROW_UP;
+ }
+ // if we're on the bottom line, display the down arrow
+ else if (linenum == 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 (hover == itemnum)
+ hover = HOVER_ARROW_DOWN;
+ }
+ // if we're just a divider, draw a line
+ else if (strcmp(itemtext, MENU_SEPARATOR_ITEM) == 0)
+ 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));
+ // draw the item centered
+ else if (pitem.subtext == nullptr)
+ {
+ int item_invert = pitem.flags & MENU_FLAG_INVERT;
+ float space = 0.0f;
+
+ if (ui_globals::has_icons && !is_swlist)
+ {
+ if (is_favorites)
+ {
+ ui_software_info *soft = (ui_software_info *)item[itemnum].ref;
+ if (soft->startempty == 1)
+ draw_icon(linenum, (void *)soft->driver, effective_left, line_y);
+ }
+ else
+ draw_icon(linenum, item[itemnum].ref, effective_left, line_y);
+
+ space = mui.get_line_height() * container->manager().ui_aspect() * 1.5f;
+ }
+ mui.draw_text_full(container, itemtext, effective_left + space, line_y, effective_width - space, JUSTIFY_LEFT, WRAP_TRUNCATE,
+ DRAW_NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr);
+ }
+ else
+ {
+ int item_invert = pitem.flags & MENU_FLAG_INVERT;
+ const char *subitem_text = pitem.subtext;
+ float item_width, subitem_width;
+
+ // compute right space for subitem
+ mui.draw_text_full(container, subitem_text, effective_left, line_y, machine().ui().get_string_width(pitem.subtext),
+ JUSTIFY_RIGHT, WRAP_NEVER, DRAW_NONE, item_invert ? fgcolor3 : fgcolor, bgcolor, &subitem_width, nullptr);
+ subitem_width += gutter_width;
+
+ // draw the item left-justified
+ mui.draw_text_full(container, itemtext, effective_left, line_y, effective_width - subitem_width,
+ JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, &item_width, nullptr);
+
+ // draw the subitem right-justified
+ mui.draw_text_full(container, subitem_text, effective_left + item_width, line_y, effective_width - item_width,
+ JUSTIFY_RIGHT, WRAP_NEVER, DRAW_NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr);
+ }
+ }
+
+ for (size_t count = visible_items; count < item.size(); count++)
+ {
+ const ui_menu_item &pitem = item[count];
+ const char *itemtext = pitem.text;
+ 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 && pitem.is_selectable())
+ hover = count;
+
+ // if we're selected, draw with a different background
+ if (count == selected)
+ {
+ fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
+ bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
+ }
+ // 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;
+ }
+
+ // if we have some background hilighting to do, add a quad behind everything else
+ if (bgcolor != UI_TEXT_BG_COLOR)
+ mui.draw_textured_box(container, line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1, bgcolor, rgb_t(255, 43, 43, 43),
+ hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+
+ if (strcmp(itemtext, MENU_SEPARATOR_ITEM) == 0)
+ 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
+ mui.draw_text_full(container, itemtext, effective_left, line, effective_width, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+ line += line_height;
+ }
+
+ x1 = x2;
+ x2 += right_panel_size;
+
+ draw_right_panel((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, 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((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
+
+ // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
+ visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != visible_items);
+
+ // reset redraw icon stage
+ if (!is_swlist)
+ ui_globals::redraw_icon = false;
+}
+
+//-------------------------------------------------
+// get title and search path for right panel
+//-------------------------------------------------
+
+void ui_menu::get_title_search(std::string &snaptext, std::string &searchstr)
+{
+ // get arts title text
+ snaptext.assign(arts_info[ui_globals::curimage_view].title);
+
+ // get search path
+ if (ui_globals::curimage_view == SNAPSHOT_VIEW)
+ searchstr = machine().options().value(arts_info[ui_globals::curimage_view].path);
+ else
+ searchstr = machine().ui().options().value(arts_info[ui_globals::curimage_view].path);
+
+ path_iterator path(searchstr.c_str());
+ std::string curpath;
+
+ // iterate over path and add path for zipped formats
+ while (path.next(curpath))
+ {
+ path_iterator path_iter(arts_info[ui_globals::curimage_view].addpath);
+ std::string c_path;
+ while (path_iter.next(c_path))
+ searchstr.append(";").append(curpath).append(PATH_SEPARATOR).append(c_path);
+ }
+}
+
+//-------------------------------------------------
+// handle keys for main menu
+//-------------------------------------------------
+
+void ui_menu::handle_main_keys(UINT32 flags)
+{
+ bool ignorepause = ui_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 (selected == item.size() - 1)
+ {
+ menu_event.iptkey = IPT_UI_CANCEL;
+ ui_menu::stack_pop(machine());
+ }
+ return;
+ }
+
+ // hitting cancel also pops the stack
+ if (exclusive_input_pressed(IPT_UI_CANCEL, 0))
+ {
+ if (!menu_has_search_active())
+ ui_menu::stack_pop(machine());
+ // else if (!ui_error)
+ // ui_menu::stack_pop(machine()); TODO
+ return;
+ }
+
+ // validate the current selection
+ validate_selection(1);
+
+ // swallow left/right keys if they are not appropriate
+ bool ignoreleft = ((item[selected].flags & MENU_FLAG_LEFT_ARROW) == 0 || ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL);
+ bool ignoreright = ((item[selected].flags & MENU_FLAG_RIGHT_ARROW) == 0 || ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL);
+ bool ignoreup = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL);
+ bool ignoredown = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL);
+
+ input_manager &minput = machine().input();
+ // accept left/right keys as-is with repeat
+ if (!ignoreleft && exclusive_input_pressed(IPT_UI_LEFT, (flags & UI_MENU_PROCESS_LR_REPEAT) ? 6 : 0))
+ {
+ // Swap the right panel
+ if (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1))
+ menu_event.iptkey = IPT_UI_LEFT_PANEL;
+ return;
+ }
+
+ if (!ignoreright && exclusive_input_pressed(IPT_UI_RIGHT, (flags & UI_MENU_PROCESS_LR_REPEAT) ? 6 : 0))
+ return;
+
+ // up backs up by one item
+ if (exclusive_input_pressed(IPT_UI_UP, 6))
+ {
+ // Filter
+ if (!ignoreup && (minput.code_pressed(KEYCODE_LALT) || minput.code_pressed(JOYCODE_BUTTON2)))
+ {
+ menu_event.iptkey = IPT_UI_UP_FILTER;
+ return;
+ }
+
+ // Infos
+ if (!ignoreleft && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_event.iptkey = IPT_UI_UP_PANEL;
+ topline_datsview--;
+ return;
+ }
+
+ if (selected == visible_items + 1 || selected == 0 || 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 (!ignoredown && (minput.code_pressed(KEYCODE_LALT) || minput.code_pressed(JOYCODE_BUTTON2)))
+ {
+ menu_event.iptkey = IPT_UI_DOWN_FILTER;
+ return;
+ }
+
+ // Infos
+ if (!ignoreright && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_event.iptkey = IPT_UI_DOWN_PANEL;
+ topline_datsview++;
+ return;
+ }
+
+ if (selected == item.size() - 1 || selected == visible_items - 1 || ui_error)
+ return;
+
+ selected++;
+
+ if (selected == top_line + visitems + (top_line != 0))
+ top_line++;
+ }
+
+ // page up backs up by visitems
+ if (exclusive_input_pressed(IPT_UI_PAGE_UP, 6))
+ {
+ // Infos
+ if (!ignoreleft && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_event.iptkey = IPT_UI_DOWN_PANEL;
+ topline_datsview -= right_visible_lines - 1;
+ return;
+ }
+
+ if (selected < visible_items && !ui_error)
+ {
+ selected -= visitems;
+
+ if (selected < 0)
+ selected = 0;
+
+ top_line -= visitems - (top_line + visible_lines == visible_items);
+ }
+ }
+
+ // page down advances by visitems
+ if (exclusive_input_pressed(IPT_UI_PAGE_DOWN, 6))
+ {
+ // Infos
+ if (!ignoreleft && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_event.iptkey = IPT_UI_DOWN_PANEL;
+ topline_datsview += right_visible_lines - 1;
+ return;
+ }
+
+ if (selected < visible_items && !ui_error)
+ {
+ selected += visible_lines - 2 + (selected == 0);
+
+ if (selected >= visible_items)
+ selected = visible_items - 1;
+
+ top_line += visible_lines - 2;
+ }
+ }
+
+ // home goes to the start
+ if (exclusive_input_pressed(IPT_UI_HOME, 0))
+ {
+ // Infos
+ if (!ignoreleft && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_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 (!ignoreleft && (minput.code_pressed(KEYCODE_LCONTROL) || minput.code_pressed(JOYCODE_BUTTON1)))
+ {
+ menu_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))
+ machine().cheat().set_enable(!machine().cheat().enabled());
+
+ // see if any other UI keys are pressed
+ if (menu_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 ui_menu::handle_main_events(UINT32 flags)
+{
+ bool stop = false;
+ ui_event local_menu_event;
+
+ // 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)
+ {
+ menu_event.iptkey = IPT_OTHER;
+ stop = true;
+ }
+ else
+ {
+ if (hover >= 0 && hover < item.size())
+ selected = hover;
+ else if (hover == HOVER_ARROW_UP)
+ {
+ selected -= visitems;
+ if (selected < 0)
+ selected = 0;
+ top_line -= visitems - (top_line + visible_lines == visible_items);
+ }
+ else if (hover == HOVER_ARROW_DOWN)
+ {
+ selected += visible_lines - 2 + (selected == 0);
+ if (selected >= visible_items)
+ selected = visible_items - 1;
+ top_line += visible_lines - 2;
+ }
+ else if (hover == HOVER_UI_RIGHT)
+ menu_event.iptkey = IPT_UI_RIGHT;
+ else if (hover == HOVER_UI_LEFT)
+ menu_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)
+ {
+ menu_event.iptkey = IPT_UI_FAVORITES;
+ stop = true;
+ }
+ else if (hover == HOVER_B_EXPORT)
+ {
+ menu_event.iptkey = IPT_UI_EXPORT;
+ stop = true;
+ }
+ else if (hover == HOVER_B_DATS)
+ {
+ menu_event.iptkey = IPT_UI_DATS;
+ stop = true;
+ }
+ else if (hover == HOVER_B_SETTINGS)
+ {
+ menu_event.iptkey = IPT_UI_SELECT;
+ selected = visible_items + 1;
+ stop = true;
+ }
+ else if (hover == HOVER_B_FOLDERS)
+ {
+ menu_event.iptkey = IPT_UI_SELECT;
+ selected = visible_items + 2;
+ 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);
+ menu_event.iptkey = IPT_OTHER;
+ stop = true;
+ }
+ else if (hover >= HOVER_FILTER_FIRST && hover <= HOVER_FILTER_LAST)
+ {
+ l_hover = (HOVER_FILTER_FIRST - hover) * (-1);
+ menu_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;
+ menu_event.iptkey = IPT_UI_SELECT;
+ }
+
+ if (selected == item.size() - 1)
+ {
+ menu_event.iptkey = IPT_UI_CANCEL;
+ ui_menu::stack_pop(machine());
+ }
+ stop = true;
+ break;
+
+ // caught scroll event
+ case UI_EVENT_MOUSE_WHEEL:
+ 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 + visitems + (top_line != 0))
+ top_line += local_menu_event.num_lines;
+ }
+ break;
+
+ // translate CHAR events into specials
+ case UI_EVENT_CHAR:
+ menu_event.iptkey = IPT_SPECIAL;
+ menu_event.unichar = local_menu_event.ch;
+ stop = true;
+ break;
+
+ // ignore everything else
+ default:
+ break;
+ }
+ }
+}
+
+//-------------------------------------------------
+// draw right box title
+//-------------------------------------------------
+
+float ui_menu::draw_right_box_title(float x1, float y1, float x2, float y2)
+{
+ ui_manager &mui = machine().ui();
+ float line_height = mui.get_line_height();
+ float midl = (x2 - x1) * 0.5f;
+
+ // add outlined box for options
+ mui.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].assign("Images");
+ buffer[RP_INFOS].assign("Infos");
+
+ for (int cells = RP_IMAGES; cells <= RP_INFOS; 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 (bgcolor != UI_TEXT_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));
+
+ mui.draw_text_full(container, buffer[cells].c_str(), x1 + UI_LINE_WIDTH, y1, midl - UI_LINE_WIDTH,
+ JUSTIFY_CENTER, WRAP_NEVER, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+ x1 += midl;
+ }
+
+ return (y1 + line_height + UI_LINE_WIDTH);
+}
+
+//-------------------------------------------------
+// common function for images render
+//-------------------------------------------------
+
+std::string ui_menu::arts_render_common(float origx1, float origy1, float origx2, float origy2)
+{
+ std::string snaptext, searchstr;
+ get_title_search(snaptext, searchstr);
+
+ // apply title to right panel
+ float title_size = 0.0f;
+ float txt_lenght = 0.0f;
+
+ for (int x = FIRST_VIEW; x < LAST_VIEW; x++)
+ {
+ machine().ui().draw_text_full(container, arts_info[x].title, origx1, origy1, origx2 - origx1, JUSTIFY_CENTER,
+ WRAP_TRUNCATE, DRAW_NONE, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, &txt_lenght, nullptr);
+ txt_lenght += 0.01f;
+ title_size = MAX(txt_lenght, title_size);
+ }
+
+ machine().ui().draw_text_full(container, snaptext.c_str(), origx1, origy1, origx2 - origx1, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, UI_TEXT_COLOR, UI_TEXT_BG_COLOR, nullptr, nullptr);
+
+ draw_common_arrow(origx1, origy1, origx2, origy2, ui_globals::curimage_view, FIRST_VIEW, LAST_VIEW, title_size);
+
+ return searchstr;
}
+
+//-------------------------------------------------
+// draw favorites star
+//-------------------------------------------------
+
+void ui_menu::draw_star(float x0, float y0)
+{
+ float y1 = y0 + machine().ui().get_line_height();
+ float x1 = x0 + machine().ui().get_line_height() * container->manager().ui_aspect();
+ container->add_quad(x0, y0, x1, y1, ARGB_WHITE, star_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE);
+}
+
+//-------------------------------------------------
+// draw toolbar
+//-------------------------------------------------
+
+void ui_menu::draw_toolbar(float x1, float y1, float x2, float y2, bool software)
+{
+ ui_manager &mui = machine().ui();
+ // draw a box
+ mui.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;
+ bitmap_argb32 **t_bitmap = (software) ? sw_toolbar_bitmap : toolbar_bitmap;
+
+ int m_valid = 0;
+ for (int x = 0; x < UI_TOOLBAR_BUTTONS; ++x)
+ if (t_bitmap[x]->valid())
+ m_valid++;
+
+ float x_pixel = 1.0f / container->manager().ui_target().width();
+ int h_len = mui.get_line_height() * container->manager().ui_target().height();
+ h_len = (h_len % 2 == 0) ? h_len : h_len - 1;
+ x1 = (x1 + x2) * 0.5f - x_pixel * (m_valid * ((h_len / 2) + 2));
+
+ for (int z = 0; z < UI_TOOLBAR_BUTTONS; ++z)
+ {
+ if (t_bitmap[z]->valid())
+ {
+ x2 = x1 + x_pixel * h_len;
+ 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 = ARGB_WHITE;
+ float ypos = y2 + machine().ui().get_line_height() + 2.0f * UI_BOX_TB_BORDER;
+ mui.draw_text_box(container, hover_msg[z], JUSTIFY_CENTER, 0.5f, ypos, UI_BACKGROUND_COLOR);
+ }
+
+ container->add_quad(x1, y1, x2, y2, color, t_texture[z], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ x1 += x_pixel * (h_len + 2);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// perform rendering of image
+//-------------------------------------------------
+
+void ui_menu::arts_render_images(bitmap_argb32 *tmp_bitmap, float origx1, float origy1, float origx2, float origy2, bool software)
+{
+ bool no_available = false;
+ float line_height = machine().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();
+ int panel_width_pixel = panel_width * screen_width;
+ int panel_height_pixel = panel_height * screen_height;
+ float ratio = 0.0f;
+
+ // Calculate resize ratios for resizing
+ float ratioW = (float)panel_width_pixel / tmp_bitmap->width();
+ float ratioH = (float)panel_height_pixel / tmp_bitmap->height();
+ float ratioI = (float)tmp_bitmap->height() / tmp_bitmap->width();
+ int dest_xPixel = tmp_bitmap->width();
+ int dest_yPixel = tmp_bitmap->height();
+
+ // force 4:3 ratio min
+ if (machine().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;
+ ratio = MIN(ratioW, ratioH);
+ dest_xPixel = tmp_bitmap->width() * ratio;
+ dest_yPixel *= ratio;
+ }
+ // resize the bitmap if necessary
+ else if (ratioW < 1 || ratioH < 1 || (machine().ui().options().enlarge_snaps() && !no_available))
+ {
+ // smaller ratio will ensure that the image fits in the view
+ 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
+//-------------------------------------------------
+
+void ui_menu::draw_common_arrow(float origx1, float origy1, float origx2, float origy2, int current, int dmin, int dmax, float title_size)
+{
+ float line_height = machine().ui().get_line_height();
+ float lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect();
+ float gutter_width = lr_arrow_width * 1.3f;
+
+ // set left-right arrows dimension
+ float ar_x0 = 0.5f * (origx2 + origx1) + 0.5f * title_size + gutter_width - lr_arrow_width;
+ float ar_y0 = origy1 + 0.1f * line_height;
+ float ar_x1 = 0.5f * (origx2 + origx1) + 0.5f * title_size + gutter_width;
+ float ar_y1 = origy1 + 0.9f * line_height;
+
+ float al_x0 = 0.5f * (origx2 + origx1) - 0.5f * title_size - gutter_width;
+ float al_y0 = origy1 + 0.1f * line_height;
+ float al_x1 = 0.5f * (origx2 + origx1) - 0.5f * title_size - gutter_width + lr_arrow_width;
+ float al_y1 = origy1 + 0.9f * line_height;
+
+ rgb_t fgcolor_right, fgcolor_left;
+ fgcolor_right = fgcolor_left = UI_TEXT_COLOR;
+
+ // set hover
+ if (mouse_hit && ar_x0 <= mouse_x && ar_x1 > mouse_x && ar_y0 <= mouse_y && ar_y1 > mouse_y && current != dmax)
+ {
+ machine().ui().draw_textured_box(container, ar_x0 + 0.01f, ar_y0, ar_x1 - 0.01f, ar_y1, UI_MOUSEOVER_BG_COLOR, rgb_t(255, 43, 43, 43),
+ hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ hover = HOVER_UI_RIGHT;
+ fgcolor_right = UI_MOUSEOVER_COLOR;
+ }
+ else if (mouse_hit && al_x0 <= mouse_x && al_x1 > mouse_x && al_y0 <= mouse_y && al_y1 > mouse_y && current != dmin)
+ {
+ machine().ui().draw_textured_box(container, al_x0 + 0.01f, al_y0, al_x1 - 0.01f, al_y1, UI_MOUSEOVER_BG_COLOR, rgb_t(255, 43, 43, 43),
+ hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ hover = HOVER_UI_LEFT;
+ fgcolor_left = UI_MOUSEOVER_COLOR;
+ }
+
+ // apply arrow
+ if (current == dmin)
+ container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90) | PRIMFLAG_PACKABLE);
+ else if (current == dmax)
+ container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X) | PRIMFLAG_PACKABLE);
+ else
+ {
+ container->add_quad(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90) | PRIMFLAG_PACKABLE);
+ container->add_quad(al_x0, al_y0, al_x1, al_y1, fgcolor_left, arrow_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X) | PRIMFLAG_PACKABLE);
+ }
+}
+
+//-------------------------------------------------
+// draw icons
+//-------------------------------------------------
+
+void ui_menu::draw_icon(int linenum, void *selectedref, float x0, float y0)
+{
+ static const game_driver *olddriver[MAX_ICONS_RENDER] = { nullptr };
+ float x1 = x0 + machine().ui().get_line_height() * container->manager().ui_aspect(container);
+ float y1 = y0 + machine().ui().get_line_height();
+ const game_driver *driver = (const game_driver *)selectedref;
+
+ if (olddriver[linenum] != driver || ui_globals::redraw_icon)
+ {
+ olddriver[linenum] = driver;
+
+ // set clone status
+ bool cloneof = strcmp(driver->parent, "0");
+ if (cloneof)
+ {
+ int 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(machine().ui().options().icons_directory());
+ std::string curpath;
+ std::string searchstr(machine().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;
+ int screen_width = machine().render().ui_target().width();
+ int screen_height = machine().render().ui_target().height();
+ int panel_width_pixel = panel_width * screen_width;
+ int panel_height_pixel = panel_height * screen_height;
+
+ // Calculate resize ratios for resizing
+ float ratioW = (float)panel_width_pixel / tmp->width();
+ float ratioH = (float)panel_height_pixel / tmp->height();
+ int dest_xPixel = tmp->width();
+ int 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]->reset();
+ 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, ARGB_WHITE, icons_texture[linenum], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE);
+}
+
+//-------------------------------------------------
+// draw info arrow
+//-------------------------------------------------
+
+void ui_menu::info_arrow(int ub, float origx1, float origx2, float oy1, float line_height, float text_size, float ud_arrow_width)
+{
+ rgb_t fgcolor = UI_TEXT_COLOR;
+ UINT32 orientation = (!ub) ? ROT0 : ROT0 ^ ORIENTATION_FLIP_Y;
+
+ if (mouse_hit && origx1 <= mouse_x && origx2 > mouse_x && oy1 <= mouse_y && oy1 + (line_height * text_size) > mouse_y)
+ {
+ machine().ui().draw_textured_box(container, origx1 + 0.01f, oy1, origx2 - 0.01f, oy1 + (line_height * text_size), UI_MOUSEOVER_BG_COLOR,
+ rgb_t(255, 43, 43, 43), hilight_main_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));
+ hover = (!ub) ? HOVER_DAT_UP : HOVER_DAT_DOWN;
+ fgcolor = UI_MOUSEOVER_COLOR;
+ }
+
+ draw_arrow(container, 0.5f * (origx1 + origx2) - 0.5f * (ud_arrow_width * text_size), oy1 + 0.25f * (line_height * text_size),
+ 0.5f * (origx1 + origx2) + 0.5f * (ud_arrow_width * text_size), oy1 + 0.75f * (line_height * text_size), fgcolor, orientation);
+}
+
+//-------------------------------------------------
+// draw - draw palette menu
+//-------------------------------------------------
+
+void ui_menu::draw_palette_menu()
+{
+ ui_manager &mui = machine().ui();
+ float line_height = mui.get_line_height();
+ float lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect();
+ float ud_arrow_width = line_height * machine().render().ui_aspect();
+ float gutter_width = lr_arrow_width * 1.3f;
+ int itemnum, linenum;
+
+ if (machine().ui().options().use_background_image() && machine().options().system() == nullptr && bgrnd_bitmap->valid())
+ container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, ARGB_WHITE, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ // compute the width and height of the full menu
+ float visible_width = 0;
+ float visible_main_menu_height = 0;
+ for (itemnum = 0; itemnum < item.size(); itemnum++)
+ {
+ const ui_menu_item &pitem = item[itemnum];
+
+ // compute width of left hand side
+ float total_width = gutter_width + mui.get_string_width(pitem.text) + gutter_width;
+
+ // add in width of right hand side
+ if (pitem.subtext)
+ total_width += 2.0f * gutter_width + mui.get_string_width(pitem.subtext);
+
+ // track the maximum
+ if (total_width > visible_width)
+ visible_width = total_width;
+
+ // track the height as well
+ visible_main_menu_height += line_height;
+ }
+
+ // account for extra space at the top and bottom
+ float visible_extra_menu_height = customtop + custombottom;
+
+ // add a little bit of slop for rounding
+ visible_width += 0.01f;
+ visible_main_menu_height += 0.01f;
+
+ // if we are too wide or too tall, clamp it down
+ if (visible_width + 2.0f * UI_BOX_LR_BORDER > 1.0f)
+ visible_width = 1.0f - 2.0f * UI_BOX_LR_BORDER;
+
+ // if the menu and extra menu won't fit, take away part of the regular menu, it will scroll
+ if (visible_main_menu_height + visible_extra_menu_height + 2.0f * UI_BOX_TB_BORDER > 1.0f)
+ visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height;
+
+ int visible_lines = floor(visible_main_menu_height / line_height);
+ visible_main_menu_height = (float)visible_lines * line_height;
+
+ // compute top/left of inner menu area by centering
+ float visible_left = (1.0f - visible_width) * 0.5f;
+ 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;
+
+ // first add us a box
+ float x1 = visible_left - UI_BOX_LR_BORDER;
+ float y1 = visible_top - UI_BOX_TB_BORDER;
+ float x2 = visible_left + visible_width + UI_BOX_LR_BORDER;
+ float y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER;
+ mui.draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
+
+ // determine the first visible line based on the current selection
+ int top_line = selected - visible_lines / 2;
+ if (top_line < 0)
+ top_line = 0;
+ if (top_line + visible_lines >= item.size())
+ top_line = item.size() - 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;
+
+ // 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;
+
+ // loop over visible lines
+ hover = item.size() + 1;
+ float line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
+ float line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
+
+ for (linenum = 0; linenum < visible_lines; linenum++)
+ {
+ float line_y = visible_top + (float)linenum * line_height;
+ itemnum = top_line + linenum;
+ const ui_menu_item &pitem = item[itemnum];
+ const char *itemtext = pitem.text;
+ rgb_t fgcolor = UI_TEXT_COLOR;
+ rgb_t bgcolor = UI_TEXT_BG_COLOR;
+ float line_y0 = line_y;
+ 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 && pitem.is_selectable())
+ hover = itemnum;
+
+ // if we're selected, draw with a different background
+ if (itemnum == selected)
+ {
+ fgcolor = UI_SELECTED_COLOR;
+ bgcolor = UI_SELECTED_BG_COLOR;
+ }
+
+ // else if the mouse is over this item, draw with a different background
+ else if (itemnum == hover)
+ {
+ fgcolor = UI_MOUSEOVER_COLOR;
+ bgcolor = UI_MOUSEOVER_BG_COLOR;
+ }
+
+ // if we have some background hilighting to do, add a quad behind everything else
+ if (bgcolor != UI_TEXT_BG_COLOR)
+ highlight(container, line_x0, line_y0, line_x1, line_y1, bgcolor);
+
+ // if we're on the top line, display the up arrow
+ if (linenum == 0 && top_line != 0)
+ {
+ 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;
+ }
+
+ // if we're on the bottom line, display the down arrow
+ else if (linenum == visible_lines - 1 && itemnum != item.size() - 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 (hover == itemnum)
+ hover = HOVER_ARROW_DOWN;
+ }
+
+ // if we're just a divider, draw a line
+ else if (strcmp(itemtext, MENU_SEPARATOR_ITEM) == 0)
+ 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_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+
+ // if we don't have a subitem, just draw the string centered
+ else if (pitem.subtext == nullptr)
+ mui.draw_text_full(container, itemtext, effective_left, line_y, effective_width,
+ JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+
+ // otherwise, draw the item on the left and the subitem text on the right
+ else
+ {
+ const char *subitem_text = pitem.subtext;
+ rgb_t color = rgb_t((UINT32)strtoul(subitem_text, nullptr, 16));
+
+ // draw the left-side text
+ mui.draw_text_full(container, itemtext, effective_left, line_y, effective_width,
+ JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+
+ // give 2 spaces worth of padding
+ float subitem_width = mui.get_string_width("FF00FF00");
+
+ mui.draw_outlined_box(container, effective_left + effective_width - subitem_width, line_y0,
+ effective_left + effective_width, line_y1, color);
+ }
+ }
+
+ // if there is something special to add, do it by calling the virtual method
+ custom_render((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
+
+ // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
+ visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != item.size());
+}
+
+//-------------------------------------------------
+// draw - draw dats menu
+//-------------------------------------------------
+
+void ui_menu::draw_dats_menu()
+{
+ float line_height = machine().ui().get_line_height();
+ float ud_arrow_width = line_height * machine().render().ui_aspect();
+ float 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;
+ ui_manager &mui = machine().ui();
+
+ // draw background image if available
+ if (machine().ui().options().use_background_image() && bgrnd_bitmap->valid())
+ container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, ARGB_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;
+ visible_lines = floor(visible_main_menu_height / line_height);
+ visible_main_menu_height = (float)(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)(visible_lines * line_height);
+
+ //machine().ui().draw_outlined_box(container, x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B));
+ mui.draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
+
+ if (visible_items < visible_lines)
+ visible_lines = visible_items;
+ if (top_line < 0)
+ top_line = 0;
+ if (top_line + visible_lines >= visible_items)
+ top_line = visible_items - 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 n_loop = (visible_items >= visible_lines) ? 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 ui_menu_item &pitem = item[itemnum];
+ const char *itemtext = pitem.text;
+ 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 == 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 == nullptr)
+ {
+ mui.draw_text_full(container, itemtext, effective_left, line_y, effective_width, JUSTIFY_LEFT, WRAP_NEVER,
+ DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+ }
+ }
+
+ for (size_t count = visible_items; count < item.size(); count++)
+ {
+ const ui_menu_item &pitem = item[count];
+ const char *itemtext = pitem.text;
+ 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 && pitem.is_selectable())
+ hover = count;
+
+ if (strcmp(itemtext, MENU_SEPARATOR_ITEM) == 0)
+ 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);
+ mui.draw_text_full(container, itemtext, effective_left, line, effective_width, JUSTIFY_CENTER, WRAP_TRUNCATE,
+ DRAW_NORMAL, fgcolor, bgcolor, nullptr, nullptr);
+ }
+ line += line_height;
+ }
+
+ // if there is something special to add, do it by calling the virtual method
+ custom_render((selected >= 0 && selected < item.size()) ? item[selected].ref : nullptr, customtop, custombottom, x1, y1, x2, y2);
+
+ // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
+ visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != visible_items);
+} \ No newline at end of file