summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/ui/selmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/ui/selmenu.cpp')
-rw-r--r--src/frontend/mame/ui/selmenu.cpp4077
1 files changed, 2741 insertions, 1336 deletions
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index 236a33225bc..5655c226d3f 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -15,19 +15,16 @@
#include "ui/info.h"
#include "ui/inifile.h"
-// these hold static bitmap images
-#include "ui/defimg.ipp"
-#include "ui/starimg.ipp"
-#include "ui/toolbar.ipp"
-
#include "audit.h"
#include "cheat.h"
+#include "infoxml.h"
#include "mame.h"
#include "mameopts.h"
#include "corestr.h"
#include "drivenum.h"
#include "emuopts.h"
+#include "fileio.h"
#include "rendfont.h"
#include "rendutil.h"
#include "romload.h"
@@ -36,16 +33,27 @@
#include "uiinput.h"
#include "luaengine.h"
+#include "util/nanosvg.h"
+#include "util/path.h"
+
#include <algorithm>
#include <cmath>
#include <cstring>
-#include <utility>
+
+
+// these hold static bitmap images
+#include "ui/defimg.ipp"
+#include "ui/toolbar.ipp"
namespace ui {
namespace {
+std::pair<char const *, char const *> RIGHT_PANEL_NAMES[RP_LAST + 1] = {
+ { "image", N_("Images") },
+ { "info", N_("Info") } };
+
enum
{
FIRST_VIEW = 0,
@@ -69,49 +77,62 @@ enum
LAST_VIEW = COVERS_VIEW
};
-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 },
+std::tuple<char const *, char const *, char const *> const ARTS_INFO[] =
+{
+ { "snap", N_p("selmenu-artwork", "Snapshots"), OPTION_SNAPSHOT_DIRECTORY },
+ { "cabinet", N_p("selmenu-artwork", "Cabinet"), OPTION_CABINETS_PATH },
+ { "cpanel", N_p("selmenu-artwork", "Control Panel"), OPTION_CPANELS_PATH },
+ { "pcb", N_p("selmenu-artwork", "PCB"), OPTION_PCBS_PATH },
+ { "flyer", N_p("selmenu-artwork", "Flyer"), OPTION_FLYERS_PATH },
+ { "title", N_p("selmenu-artwork", "Title Screen"), OPTION_TITLES_PATH },
+ { "ending", N_p("selmenu-artwork", "Ending"), OPTION_ENDS_PATH },
+ { "artpreview", N_p("selmenu-artwork", "Artwork Preview"), OPTION_ARTPREV_PATH },
+ { "boss", N_p("selmenu-artwork", "Bosses"), OPTION_BOSSES_PATH },
+ { "logo", N_p("selmenu-artwork", "Logo"), OPTION_LOGOS_PATH },
+ { "versus", N_p("selmenu-artwork", "Versus"), OPTION_VERSUS_PATH },
+ { "gameover", N_p("selmenu-artwork", "Game Over"), OPTION_GAMEOVER_PATH },
+ { "howto", N_p("selmenu-artwork", "HowTo"), OPTION_HOWTO_PATH },
+ { "scores", N_p("selmenu-artwork", "Scores"), OPTION_SCORES_PATH },
+ { "select", N_p("selmenu-artwork", "Select"), OPTION_SELECT_PATH },
+ { "marquee", N_p("selmenu-artwork", "Marquee"), OPTION_MARQUEES_PATH },
+ { "cover", N_p("selmenu-artwork", "Covers"), OPTION_COVER_PATH },
};
char const *const hover_msg[] = {
- __("Add or remove favorites"),
- __("Export displayed list to file"),
- __("Show DATs view"),
+ N_("Add or remove favorite"),
+ N_("Export displayed list to file"),
+ N_("Audit media"),
+ N_("Show DATs view"),
+};
+
+std::tuple<unsigned, int, bool> SYS_TOOLBAR_BITMAPS[] = {
+ { TOOLBAR_BITMAP_FAVORITE, IPT_UI_FAVORITES, true },
+ { TOOLBAR_BITMAP_SAVE, IPT_UI_EXPORT, false },
+ { TOOLBAR_BITMAP_AUDIT, IPT_UI_AUDIT, false },
+ { TOOLBAR_BITMAP_INFO, IPT_UI_DATS, true }
+};
+
+std::tuple<unsigned, int, bool> SW_TOOLBAR_BITMAPS[] = {
+ { TOOLBAR_BITMAP_FAVORITE, IPT_UI_FAVORITES, true },
+ { TOOLBAR_BITMAP_INFO, IPT_UI_DATS, true }
};
void load_image(bitmap_argb32 &bitmap, emu_file &file, std::string const &base)
{
- if (file.open(base + ".png") == osd_file::error::NONE)
+ if (!file.open(base + ".png"))
{
render_load_png(bitmap, file);
file.close();
}
- if (!bitmap.valid() && (file.open(base + ".jpg") == osd_file::error::NONE))
+ if (!bitmap.valid() && !file.open(base + ".jpg"))
{
render_load_jpeg(bitmap, file);
file.close();
}
- if (!bitmap.valid() && (file.open(base + ".bmp") == osd_file::error::NONE))
+ if (!bitmap.valid() && !file.open(base + ".bmp"))
{
render_load_msdib(bitmap, file);
file.close();
@@ -123,7 +144,7 @@ void load_driver_image(bitmap_argb32 &bitmap, emu_file &file, game_driver const
{
// try to load snapshot first from saved "0000.png" file
std::string fullname = driver.name;
- load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+ load_image(bitmap, file, util::path_concat(fullname, "0000"));
// if fail, attempt to load from standard file
if (!bitmap.valid())
@@ -144,7 +165,7 @@ void load_driver_image(bitmap_argb32 &bitmap, emu_file &file, game_driver const
if (isclone)
{
fullname = driver.parent;
- load_image(bitmap, file, fullname + PATH_SEPARATOR + "0000");
+ load_image(bitmap, file, util::path_concat(fullname, "0000"));
if (!bitmap.valid())
load_image(bitmap, file, fullname);
@@ -154,8 +175,6 @@ void load_driver_image(bitmap_argb32 &bitmap, emu_file &file, game_driver const
} // anonymous namespace
-constexpr std::size_t menu_select_launch::MAX_VISIBLE_SEARCH; // stupid non-inline semantics
-
class menu_select_launch::software_parts : public menu
{
@@ -163,12 +182,9 @@ public:
software_parts(mame_ui_manager &mui, render_container &container, s_parts &&parts, ui_software_info const &ui_info);
virtual ~software_parts() override;
-protected:
- virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
-
private:
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle() override;
+ virtual void populate() override;
+ virtual bool handle(event const *ev) override;
ui_software_info const &m_uiinfo;
s_parts const m_parts;
@@ -181,14 +197,11 @@ public:
bios_selection(mame_ui_manager &mui, render_container &container, s_bios &&biosname, ui_software_info const &swinfo, bool inlist);
virtual ~bios_selection() override;
-protected:
- virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
-
private:
bios_selection(mame_ui_manager &mui, render_container &container, s_bios &&biosname, void const *driver, bool software, bool inlist);
- virtual void populate(float &customtop, float &custombottom) override;
- virtual void handle() override;
+ virtual void populate() override;
+ virtual bool handle(event const *ev) override;
void const *m_driver;
bool m_software, m_inlist;
@@ -200,14 +213,11 @@ std::string menu_select_launch::reselect_last::s_software;
std::string menu_select_launch::reselect_last::s_swlist;
bool menu_select_launch::reselect_last::s_reselect = false;
-std::mutex menu_select_launch::s_cache_guard;
-menu_select_launch::cache_ptr_map menu_select_launch::s_caches;
-
// instantiate possible variants of these so derived classes don't get link errors
template bool menu_select_launch::select_bios(game_driver const &, bool);
template bool menu_select_launch::select_bios(ui_software_info const &, bool);
-template float menu_select_launch::draw_left_panel<machine_filter>(machine_filter::type current, std::map<machine_filter::type, machine_filter::ptr> const &filters, float x1, float y1, float x2, float y2);
-template float menu_select_launch::draw_left_panel<software_filter>(software_filter::type current, std::map<software_filter::type, software_filter::ptr> const &filters, float x1, float y1, float x2, float y2);
+template void menu_select_launch::draw_left_panel<machine_filter>(u32 flags, machine_filter::type current, std::map<machine_filter::type, machine_filter::ptr> const &filters);
+template void menu_select_launch::draw_left_panel<software_filter>(u32 flags, software_filter::type current, std::map<software_filter::type, software_filter::ptr> const &filters);
menu_select_launch::system_flags::system_flags(machine_static_info const &info)
@@ -262,6 +272,7 @@ menu_select_launch::software_parts::software_parts(mame_ui_manager &mui, render_
, m_uiinfo(ui_info)
, m_parts(std::move(parts))
{
+ set_heading(_("Select Software Package Part"));
}
//-------------------------------------------------
@@ -276,53 +287,38 @@ menu_select_launch::software_parts::~software_parts()
// populate
//-------------------------------------------------
-void menu_select_launch::software_parts::populate(float &customtop, float &custombottom)
+void menu_select_launch::software_parts::populate()
{
std::vector<s_parts::const_iterator> parts;
parts.reserve(m_parts.size());
for (s_parts::const_iterator it = m_parts.begin(); m_parts.end() != it; ++it)
parts.push_back(it);
- std::sort(parts.begin(), parts.end(), [] (auto const &left, auto const &right) { return 0 > core_stricmp(left->first.c_str(), right->first.c_str()); });
+ std::sort(parts.begin(), parts.end(), [] (auto const &left, auto const &right) { return 0 > core_stricmp(left->first, right->first); });
for (auto const &elem : parts)
item_append(elem->first, elem->second, 0, (void *)&*elem);
item_append(menu_item_type::SEPARATOR);
- customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
}
//-------------------------------------------------
// handle
//-------------------------------------------------
-void menu_select_launch::software_parts::handle()
+bool menu_select_launch::software_parts::handle(event const *ev)
{
- // process the menu
- const event *menu_event = process(0);
- if (menu_event && (menu_event->iptkey) == IPT_UI_SELECT && menu_event->itemref)
+ if (ev && (ev->iptkey == IPT_UI_SELECT) && ev->itemref)
{
for (auto const &elem : m_parts)
{
- if ((void*)&elem == menu_event->itemref)
+ if ((void*)&elem == ev->itemref)
{
launch_system(ui(), *m_uiinfo.driver, &m_uiinfo, &elem.first, nullptr);
break;
}
}
}
-}
-//-------------------------------------------------
-// perform our special rendering
-//-------------------------------------------------
-
-void menu_select_launch::software_parts::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
-{
- char const *const text[] = { _("Software part selection:") };
- draw_text_box(
- std::begin(text), std::end(text),
- origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
- ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false,
- ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
+ return false;
}
@@ -347,6 +343,7 @@ menu_select_launch::bios_selection::bios_selection(mame_ui_manager &mui, render_
, m_inlist(inlist)
, m_bios(std::move(biosname))
{
+ set_heading(_("Select System BIOS"));
}
//-------------------------------------------------
@@ -361,28 +358,25 @@ menu_select_launch::bios_selection::~bios_selection()
// populate
//-------------------------------------------------
-void menu_select_launch::bios_selection::populate(float &customtop, float &custombottom)
+void menu_select_launch::bios_selection::populate()
{
- for (auto & elem : m_bios)
+ for (auto &elem : m_bios)
item_append(elem.first, 0, (void *)&elem.first);
item_append(menu_item_type::SEPARATOR);
- customtop = ui().get_line_height() + (3.0f * ui().box_tb_border());
}
//-------------------------------------------------
// handle
//-------------------------------------------------
-void menu_select_launch::bios_selection::handle()
+bool menu_select_launch::bios_selection::handle(event const *ev)
{
- // process the menu
- const event *menu_event = process(0);
- if (menu_event && menu_event->iptkey == IPT_UI_SELECT && menu_event->itemref)
+ if (ev && (ev->iptkey == IPT_UI_SELECT) && ev->itemref)
{
for (auto & elem : m_bios)
{
- if ((void*)&elem.first == menu_event->itemref)
+ if ((void*)&elem.first == ev->itemref)
{
if (!m_software)
{
@@ -415,20 +409,8 @@ void menu_select_launch::bios_selection::handle()
}
}
}
-}
-//-------------------------------------------------
-// perform our special rendering
-//-------------------------------------------------
-
-void menu_select_launch::bios_selection::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
-{
- char const *const text[] = { _("BIOS selection:") };
- draw_text_box(
- std::begin(text), std::end(text),
- origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(),
- ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false,
- ui().colors().text_color(), UI_GREEN_COLOR, 1.0f);
+ return false;
}
@@ -438,63 +420,86 @@ menu_select_launch::cache::cache(running_machine &machine)
, m_snapx_driver(nullptr)
, m_snapx_software(nullptr)
, m_no_avail_bitmap(256, 256)
- , m_star_bitmap(32, 32)
- , m_star_texture(nullptr, machine.render())
- , m_toolbar_bitmap()
- , m_sw_toolbar_bitmap()
- , m_toolbar_texture()
- , m_sw_toolbar_texture()
+ , m_toolbar_bitmaps()
+ , m_toolbar_textures()
{
render_manager &render(machine.render());
// create a texture for snapshot
m_snapx_texture.reset(render.texture_alloc(render_texture::hq_scale));
- std::memcpy(&m_no_avail_bitmap.pix(0), no_avail_bmp, 256 * 256 * sizeof(uint32_t));
+ std::memcpy(&m_no_avail_bitmap.pix(0), no_avail_bmp, 256 * 256 * sizeof(u32));
- std::memcpy(&m_star_bitmap.pix(0), favorite_star_bmp, 32 * 32 * sizeof(uint32_t));
- m_star_texture.reset(render.texture_alloc());
- m_star_texture->set_bitmap(m_star_bitmap, m_star_bitmap.cliprect(), TEXFORMAT_ARGB32);
+ m_toolbar_bitmaps.resize(UI_TOOLBAR_BUTTONS * 2);
+ m_toolbar_textures.reserve(UI_TOOLBAR_BUTTONS * 2);
+}
- 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(32, 32);
- m_sw_toolbar_bitmap.emplace_back(32, 32);
- m_toolbar_texture.emplace_back(render.texture_alloc(), render);
- m_sw_toolbar_texture.emplace_back(render.texture_alloc(), render);
+menu_select_launch::cache::~cache()
+{
+}
- std::memcpy(&m_toolbar_bitmap.back().pix(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
- 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().pix(0), toolbar_bitmap_bmp[i], 32 * 32 * sizeof(uint32_t));
- 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
+void menu_select_launch::cache::cache_toolbar(running_machine &machine, float width, float height)
+{
+ // not bothering to transform for non-square pixels greatly simplifies this
+ render_manager &render(machine.render());
+ render_target const &target(render.ui_target());
+ s32 const pix_size(std::ceil(std::max(width * target.width(), height * target.height())));
+ if (m_toolbar_textures.empty() || (m_toolbar_bitmaps[0].width() != pix_size) || (m_toolbar_bitmaps[0].height() != pix_size))
+ {
+ m_toolbar_textures.clear();
+ util::nsvg_rasterizer_ptr rasterizer(nsvgCreateRasterizer());
+ std::string xml;
+ for (unsigned i = 0; UI_TOOLBAR_BUTTONS > i; ++i)
{
- m_sw_toolbar_bitmap.back().reset();
+ // parse SVG and calculate scale
+ xml = toolbar_icons_svg[i];
+ util::nsvg_image_ptr svg(nsvgParse(xml.data(), "px", 72));
+ float const xscale(float(pix_size) / svg->width);
+ float const yscale(float(pix_size) / svg->height);
+ float const drawscale((std::max)(xscale, yscale));
+
+ // rasterise the SVG and clear it out of memory
+ bitmap_argb32 &bitmap(m_toolbar_bitmaps[2 * i]);
+ bitmap.resize(pix_size, pix_size);
+ nsvgRasterize(
+ rasterizer.get(),
+ svg.get(),
+ 0, 0, drawscale,
+ reinterpret_cast<unsigned char *>(&bitmap.pix(0)),
+ pix_size, pix_size,
+ bitmap.rowbytes());
+ svg.reset();
+
+ // correct colour format
+ bitmap_argb32 &disabled_bitmap(m_toolbar_bitmaps[(2 * i) + 1]);
+ disabled_bitmap.resize(pix_size, pix_size);
+ for (s32 y = 0; bitmap.height() > y; ++y)
+ {
+ u32 *cdst(&bitmap.pix(y));
+ u32 *mdst(&disabled_bitmap.pix(y));
+ for (s32 x = 0; bitmap.width() > x; ++x, ++cdst, ++mdst)
+ {
+ u8 const *const src(reinterpret_cast<u8 const *>(cdst));
+ rgb_t const c(src[3], src[0], src[1], src[2]);
+ u8 const l(std::clamp(std::lround((0.2126 * src[0]) + (0.7152 * src[1]) + (0.0722 * src[2])), 0L, 255L));
+ rgb_t const m(src[3], l, l, l);
+ *cdst = c;
+ *mdst = m;
+ }
+ }
+
+ // make textures
+ render_texture &texture(*m_toolbar_textures.emplace_back(render.texture_alloc(), render));
+ render_texture &disabled_texture(*m_toolbar_textures.emplace_back(render.texture_alloc(), render));
+ texture.set_bitmap(bitmap, bitmap.cliprect(), TEXFORMAT_ARGB32);
+ disabled_texture.set_bitmap(disabled_bitmap, disabled_bitmap.cliprect(), TEXFORMAT_ARGB32);
}
}
}
-menu_select_launch::cache::~cache()
-{
-}
-
-
menu_select_launch::~menu_select_launch()
{
}
@@ -502,6 +507,7 @@ menu_select_launch::~menu_select_launch()
menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &container, bool is_swlist)
: menu(mui, container)
+ , m_skip_main_items(0)
, m_prev_selected(nullptr)
, m_total_lines(0)
, m_topline_datsview(0)
@@ -512,56 +518,159 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c
, m_info_view(-1)
, m_items_list()
, m_info_buffer()
- , m_cache()
+ , m_info_layout()
+ , m_icon_width(0)
+ , m_icon_height(0)
+ , m_divider_width(0.0F)
+ , m_divider_arrow_width(0.0F)
+ , m_divider_arrow_height(0.0F)
+ , m_info_line_height(0.0F)
+ , m_cache(mui.get_session_data<menu_select_launch, cache_wrapper>(machine()))
, m_is_swlist(is_swlist)
, m_focus(focused_menu::MAIN)
- , m_pressed(false)
- , m_repeat(0)
+ , m_pointer_action(pointer_action::NONE)
+ , m_scroll_repeat(std::chrono::steady_clock::time_point::min())
+ , m_base_pointer(0.0F, 0.0F)
+ , m_last_pointer(0.0F, 0.0F)
+ , m_clicked_line(0)
+ , m_wheel_target(focused_menu::MAIN)
+ , m_wheel_movement(0)
+ , m_primary_vbounds(0.0F, -1.0F)
+ , m_primary_items_top(-1.0F)
+ , m_primary_items_hbounds(0.0F, -1.0F)
+ , m_primary_lines(0)
+ , m_left_panel_width(-1.0F)
+ , m_left_items_hbounds(0.0F, -1.0F)
+ , m_left_items_top(1.0F)
+ , m_left_item_count(0)
+ , m_left_visible_lines(0)
+ , m_left_visible_top(0)
+ , m_right_panel_width(-1.0F)
+ , m_right_tabs_bottom(-1.0F)
+ , m_right_heading_top(-1.0F)
+ , m_right_content_vbounds(0.0F, -1.0F)
+ , m_right_content_hbounds(0.0F, -1.0F)
, m_right_visible_lines(0)
+ , m_toolbar_button_vbounds(0.0F, -1.0F)
+ , m_toolbar_button_width(-1.0)
+ , m_toolbar_button_spacing(-1.0)
+ , m_toolbar_backtrack_left(-1.0)
+ , m_toolbar_main_left(-1.0)
+ , m_panels_status(SHOW_PANELS)
+ , m_right_panel(RP_FIRST)
, m_has_icons(false)
, m_switch_image(false)
- , m_default_image(true)
, m_image_view(FIRST_VIEW)
, m_flags(256)
{
- // 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);
- }
- }
+ set_needs_prev_menu_item(false);
+ set_process_flags(PROCESS_LR_REPEAT);
+}
+
+
+std::pair<bool, bool> menu_select_launch::next_right_panel_view()
+{
+ if (right_panel() == RP_IMAGES)
+ return next_image_view();
+ else if (right_panel() == RP_INFOS)
+ return next_info_view();
+ else
+ return std::make_pair(false, false);
+}
+
+
+std::pair<bool, bool> menu_select_launch::previous_right_panel_view()
+{
+ if (right_panel() == RP_IMAGES)
+ return previous_image_view();
+ else if (right_panel() == RP_INFOS)
+ return previous_info_view();
+ else
+ return std::make_pair(false, false);
}
-void menu_select_launch::next_image_view()
+std::pair<bool, bool> menu_select_launch::next_image_view()
{
if (LAST_VIEW > m_image_view)
{
++m_image_view;
set_switch_image();
- m_default_image = false;
+ return std::make_pair(true, (LAST_VIEW > m_image_view));
+ }
+ else
+ {
+ return std::make_pair(false, false);
}
}
-void menu_select_launch::previous_image_view()
+std::pair<bool, bool> menu_select_launch::previous_image_view()
{
if (FIRST_VIEW < m_image_view)
{
--m_image_view;
set_switch_image();
- m_default_image = false;
+ return std::make_pair(true, (FIRST_VIEW < m_image_view));
+ }
+ else
+ {
+ return std::make_pair(false, false);
+ }
+}
+
+
+std::pair<bool, bool> menu_select_launch::next_info_view()
+{
+ ui_software_info const *software;
+ ui_system_info const *system;
+ get_selection(software, system);
+ if (software && !software->startempty)
+ {
+ if ((ui_globals::cur_sw_dats_total - 1) > ui_globals::cur_sw_dats_view)
+ {
+ ++ui_globals::cur_sw_dats_view;
+ m_topline_datsview = 0;
+ return std::make_pair(true, (ui_globals::cur_sw_dats_total - 1) > ui_globals::cur_sw_dats_view);
+ }
+ }
+ else if (system || (software && software->driver))
+ {
+ if ((ui_globals::curdats_total - 1) > ui_globals::curdats_view)
+ {
+ ++ui_globals::curdats_view;
+ m_topline_datsview = 0;
+ return std::make_pair(true, (ui_globals::curdats_total - 1) > ui_globals::curdats_view);
+ }
+ }
+ return std::make_pair(false, false);
+}
+
+
+std::pair<bool, bool> menu_select_launch::previous_info_view()
+{
+ ui_software_info const *software;
+ ui_system_info const *system;
+ get_selection(software, system);
+ if (software && !software->startempty)
+ {
+ if (0 < ui_globals::cur_sw_dats_view)
+ {
+ --ui_globals::cur_sw_dats_view;
+ m_topline_datsview = 0;
+ return std::make_pair(true, 0 < ui_globals::cur_sw_dats_view);
+ }
+ }
+ else if (system || (software && software->driver))
+ {
+ if (0 < ui_globals::curdats_view)
+ {
+ --ui_globals::curdats_view;
+ m_topline_datsview = 0;
+ return std::make_pair(true, 0 < ui_globals::curdats_view);
+ }
}
+ return std::make_pair(false, false);
}
@@ -621,7 +730,7 @@ void menu_select_launch::launch_system(mame_ui_manager &mui, game_driver const &
else
moptions.set_value(OPTION_SOFTWARENAME, util::string_format("%s:%s", swinfo->listname, swinfo->shortname), OPTION_PRIORITY_CMDLINE);
- moptions.set_value(OPTION_SNAPNAME, util::string_format("%s%s%s", swinfo->listname, PATH_SEPARATOR, swinfo->shortname), OPTION_PRIORITY_CMDLINE);
+ moptions.set_value(OPTION_SNAPNAME, util::path_concat(swinfo->listname, swinfo->shortname), OPTION_PRIORITY_CMDLINE);
}
reselect_last::set_software(driver, *swinfo);
}
@@ -635,7 +744,52 @@ void menu_select_launch::launch_system(mame_ui_manager &mui, game_driver const &
mame_machine_manager::instance()->schedule_new_driver(driver);
mui.machine().schedule_hard_reset();
- stack_reset(mui.machine());
+ stack_reset(mui);
+}
+
+
+//-------------------------------------------------
+// recompute metrics
+//-------------------------------------------------
+
+void menu_select_launch::recompute_metrics(uint32_t width, uint32_t height, float aspect)
+{
+ menu::recompute_metrics(width, height, aspect);
+
+ // calculate icon size in pixels
+ render_target const &target(machine().render().ui_target());
+ bool const rotated((target.orientation() & ORIENTATION_SWAP_XY) != 0);
+ m_icon_width = int((rotated ? height : width) * line_height() * aspect);
+ m_icon_height = int((rotated ? width : height) * line_height());
+
+ // force info text to be laid out again
+ m_info_layout = std::nullopt;
+
+ // calculate size of dividers between panes
+ m_divider_width = 0.8F * line_height() * x_aspect();
+ m_divider_arrow_width = 0.32F * line_height() * x_aspect();
+ m_divider_arrow_height = 0.64F * line_height();
+
+ // calculate info text size
+ m_info_line_height = ui().get_line_height(ui().options().infos_size());
+
+ // invalidate panel metrics
+ m_primary_vbounds = std::make_pair(0.0F, -1.0F);
+ m_primary_items_hbounds = std::make_pair(0.0F, -1.0F);
+ m_left_panel_width = -1.0F;
+ m_left_items_hbounds = std::make_pair(0.0F, -1.0F);
+ m_right_panel_width = -1.0F;
+ m_right_heading_top = -1.0F;
+ m_right_content_vbounds = std::make_pair(0.0F, -1.0F);
+ m_right_content_hbounds = std::make_pair(0.0F, -1.0F);
+ m_toolbar_button_vbounds = std::make_pair(0.0F, -1.0F);
+
+ // abandon pointer input
+ m_pointer_action = pointer_action::NONE;
+
+ // force right panel images to be redrawn
+ m_cache.set_snapx_driver(nullptr);
+ m_cache.set_snapx_software(nullptr);
}
@@ -643,52 +797,52 @@ void menu_select_launch::launch_system(mame_ui_manager &mui, game_driver const &
// perform our special rendering
//-------------------------------------------------
-void menu_select_launch::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::custom_render(u32 flags, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
- std::string tempbuf[5];
+ std::string tempbuf[4];
// determine the text for the header
make_topbox_text(tempbuf[0], tempbuf[1], tempbuf[2]);
- float const y1 = origy1 - 3.0f * ui().box_tb_border() - ui().get_line_height();
+ float const y1 = origy1 - 3.0f * tb_border() - line_height();
draw_text_box(
tempbuf, tempbuf + 3,
origx1, origx2, origy1 - top, y1,
- ui::text_layout::CENTER, ui::text_layout::NEVER, true,
- ui().colors().text_color(), ui().colors().background_color(), 1.0f);
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, true,
+ ui().colors().text_color(), ui().colors().background_color());
// draw toolbar
- draw_toolbar(origx1, y1, origx2, origy1 - ui().box_tb_border());
+ draw_toolbar(flags, origx1, y1, origx2, origy1 - tb_border());
// determine the text to render below
ui_software_info const *swinfo;
- game_driver const *driver;
- get_selection(swinfo, driver);
+ ui_system_info const *system;
+ get_selection(swinfo, system);
bool isstar = false;
rgb_t color = ui().colors().background_color();
- if (swinfo && ((swinfo->startempty != 1) || !driver))
+ if (swinfo && !swinfo->startempty)
{
isstar = mame_machine_manager::instance()->favorite().is_favorite_system_software(*swinfo);
// first line is long name or system
- tempbuf[0] = make_software_description(*swinfo);
+ tempbuf[0] = make_software_description(*swinfo, system);
// next line is year, publisher
- tempbuf[1] = string_format(_("%1$s, %2$-.100s"), swinfo->year, swinfo->publisher);
+ tempbuf[1] = string_format(_("%1$s, %2$s"), swinfo->year, swinfo->publisher);
// next line is parent/clone
if (!swinfo->parentname.empty())
- tempbuf[2] = string_format(_("Software is clone of: %1$-.100s"), !swinfo->parentlongname.empty() ? swinfo->parentlongname : swinfo->parentname);
+ tempbuf[2] = string_format(_("Software is clone of: %1$s"), !swinfo->parentlongname.empty() ? swinfo->parentlongname : swinfo->parentname);
else
tempbuf[2] = _("Software is parent");
// next line is supported status
- if (swinfo->supported == SOFTWARE_SUPPORTED_NO)
+ if (swinfo->supported == software_support::UNSUPPORTED)
{
tempbuf[3] = _("Supported: No");
color = UI_RED_COLOR;
}
- else if (swinfo->supported == SOFTWARE_SUPPORTED_PARTIAL)
+ else if (swinfo->supported == software_support::PARTIALLY_SUPPORTED)
{
tempbuf[3] = _("Supported: Partial");
color = UI_YELLOW_COLOR;
@@ -698,78 +852,102 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto
tempbuf[3] = _("Supported: Yes");
color = UI_GREEN_COLOR;
}
-
- // last line is romset name
- tempbuf[4] = string_format(_("romset: %1$-.100s"), swinfo->shortname);
}
- else if (driver)
+ else if (system || (swinfo && swinfo->driver))
{
- isstar = mame_machine_manager::instance()->favorite().is_favorite_system(*driver);
-
- // first line is game description/game name
- tempbuf[0] = make_driver_description(*driver);
+ game_driver const &driver(system ? *system->driver : *swinfo->driver);
+ isstar = mame_machine_manager::instance()->favorite().is_favorite_system(driver);
- // next line is year, manufacturer
- tempbuf[1] = string_format(_("%1$s, %2$-.100s"), driver->year, driver->manufacturer);
+ // first line is year, manufacturer
+ tempbuf[0] = string_format(_("%1$s, %2$s"), driver.year, driver.manufacturer);
// next line is clone/parent status
- int cloneof = driver_list::non_bios_clone(*driver);
+ int cloneof = driver_list::non_bios_clone(driver);
- if (cloneof != -1)
- tempbuf[2] = string_format(_("Driver is clone of: %1$-.100s"), driver_list::driver(cloneof).type.fullname());
+ if (0 > cloneof)
+ tempbuf[1] = _("System is parent");
+ else if (system)
+ tempbuf[1] = string_format(_("System is clone of: %1$s"), system->parent);
else
- tempbuf[2] = _("Driver is parent");
+ tempbuf[1] = string_format(_("System is clone of: %1$s"), driver_list::driver(cloneof).type.fullname());
// next line is overall driver status
- system_flags const &flags(get_system_flags(*driver));
+ system_flags const &flags(get_system_flags(driver));
if (flags.machine_flags() & machine_flags::NOT_WORKING)
- tempbuf[3] = _("Overall: NOT WORKING");
+ tempbuf[2] = _("Overall: NOT WORKING");
else if ((flags.unemulated_features() | flags.imperfect_features()) & device_t::feature::PROTECTION)
- tempbuf[3] = _("Overall: Unemulated Protection");
+ tempbuf[2] = _("Overall: Unemulated Protection");
else
- tempbuf[3] = _("Overall: Working");
+ tempbuf[2] = _("Overall: Working");
// next line is graphics, sound status
if (flags.unemulated_features() & device_t::feature::GRAPHICS)
- tempbuf[4] = _("Graphics: Unimplemented, ");
+ tempbuf[3] = _("Graphics: Unimplemented, ");
else if ((flags.unemulated_features() | flags.imperfect_features()) & (device_t::feature::GRAPHICS | device_t::feature::PALETTE))
- tempbuf[4] = _("Graphics: Imperfect, ");
+ tempbuf[3] = _("Graphics: Imperfect, ");
else
- tempbuf[4] = _("Graphics: OK, ");
+ tempbuf[3] = _("Graphics: OK, ");
- if (driver->flags & machine_flags::NO_SOUND_HW)
- tempbuf[4].append(_("Sound: None"));
+ if (driver.flags & machine_flags::NO_SOUND_HW)
+ tempbuf[3].append(_("Sound: None"));
else if (flags.unemulated_features() & device_t::feature::SOUND)
- tempbuf[4].append(_("Sound: Unimplemented"));
+ tempbuf[3].append(_("Sound: Unimplemented"));
else if (flags.imperfect_features() & device_t::feature::SOUND)
- tempbuf[4].append(_("Sound: Imperfect"));
+ tempbuf[3].append(_("Sound: Imperfect"));
else
- tempbuf[4].append(_("Sound: OK"));
+ tempbuf[3].append(_("Sound: OK"));
color = flags.status_color();
}
else
{
- std::string copyright(emulator_info::get_copyright());
- size_t found = copyright.find('\n');
+ std::string_view copyright(emulator_info::get_copyright());
+ unsigned line(0);
- tempbuf[0].clear();
- tempbuf[1] = string_format(_("%1$s %2$s"), emulator_info::get_appname(), build_version);
- tempbuf[2] = copyright.substr(0, found);
- tempbuf[3] = copyright.substr(found + 1);
- tempbuf[4].clear();
+ // first line is version string
+ tempbuf[line++] = string_format("%s %s", emulator_info::get_appname(), build_version);
+
+ // output message
+ while (line < std::size(tempbuf))
+ {
+ auto const found = copyright.find('\n');
+ if (std::string::npos != found)
+ {
+ tempbuf[line++] = copyright.substr(0, found);
+ copyright.remove_prefix(found + 1);
+ }
+ else
+ {
+ tempbuf[line++] = copyright;
+ copyright = std::string_view();
+ }
+ }
}
// draw the footer
draw_text_box(
std::begin(tempbuf), std::end(tempbuf),
- origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom,
- ui::text_layout::CENTER, ui::text_layout::NEVER, true,
- ui().colors().text_color(), color, 1.0f);
+ origx1, origx2, origy2 + tb_border(), origy2 + bottom,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, true,
+ ui().colors().text_color(), color);
// is favorite? draw the star
if (isstar)
- draw_star(origx1 + ui().box_lr_border() * machine().render().ui_aspect(&container()), origy2 + (2.0f * ui().box_tb_border()));
+ draw_star(origx1 + lr_border(), origy2 + (2.0f * tb_border()));
+}
+
+
+void menu_select_launch::menu_activated()
+{
+ m_panels_status = ui().options().hide_panels();
+ m_wheel_target = focused_menu::MAIN;
+ m_wheel_movement = 0;
+}
+
+
+void menu_select_launch::menu_deactivated()
+{
+ ui().options().set_value(OPTION_HIDE_PANELS, m_panels_status, OPTION_PRIORITY_CMDLINE);
}
@@ -778,34 +956,52 @@ void menu_select_launch::rotate_focus(int dir)
switch (get_focus())
{
case focused_menu::MAIN:
- if (selected_index() <= m_available_items)
- {
- m_prev_selected = get_selection_ref();
- if ((0 < dir) || (ui_globals::panels_status == HIDE_BOTH))
- set_selected_index(m_available_items + 1);
- else if (ui_globals::panels_status == HIDE_RIGHT_PANEL)
- set_focus(focused_menu::LEFT);
- else
- set_focus(focused_menu::RIGHTBOTTOM);
- }
- else
+ if (selected_index() >= m_available_items)
{
- if ((0 > dir) || (ui_globals::panels_status == HIDE_BOTH))
+ if ((0 > dir) || (m_panels_status == HIDE_BOTH))
select_prev();
- else if (ui_globals::panels_status == HIDE_LEFT_PANEL)
+ else if (m_panels_status == HIDE_LEFT_PANEL)
set_focus(focused_menu::RIGHTTOP);
else
set_focus(focused_menu::LEFT);
}
+ else if (m_skip_main_items || (m_panels_status != HIDE_BOTH))
+ {
+ m_prev_selected = get_selection_ref();
+ if (0 < dir)
+ {
+ if (m_skip_main_items)
+ set_selected_index(m_available_items + 1);
+ else if (m_panels_status == HIDE_LEFT_PANEL)
+ set_focus(focused_menu::RIGHTTOP);
+ else
+ set_focus(focused_menu::LEFT);
+ }
+ else if (m_panels_status == HIDE_RIGHT_PANEL)
+ {
+ set_focus(focused_menu::LEFT);
+ }
+ else if (m_panels_status != HIDE_BOTH)
+ {
+ set_focus(focused_menu::RIGHTBOTTOM);
+ }
+ else
+ {
+ set_selected_index(m_available_items + 1);
+ }
+ }
break;
case focused_menu::LEFT:
if (0 > dir)
{
set_focus(focused_menu::MAIN);
- set_selected_index(m_available_items + 1);
+ if (m_skip_main_items)
+ set_selected_index(m_available_items + 1);
+ else
+ select_prev();
}
- else if (ui_globals::panels_status != HIDE_RIGHT_PANEL)
+ else if (m_panels_status != HIDE_RIGHT_PANEL)
{
set_focus(focused_menu::RIGHTTOP);
}
@@ -821,14 +1017,17 @@ void menu_select_launch::rotate_focus(int dir)
{
set_focus(focused_menu::RIGHTBOTTOM);
}
- else if (ui_globals::panels_status != HIDE_LEFT_PANEL)
+ else if (m_panels_status != HIDE_LEFT_PANEL)
{
set_focus(focused_menu::LEFT);
}
else
{
set_focus(focused_menu::MAIN);
- set_selected_index(m_available_items + 1);
+ if (m_skip_main_items)
+ set_selected_index(m_available_items + 1);
+ else
+ select_prev();
}
break;
@@ -850,223 +1049,221 @@ void menu_select_launch::rotate_focus(int dir)
void menu_select_launch::inkey_dats()
{
ui_software_info const *software;
- game_driver const *driver;
- get_selection(software, driver);
- if (software)
- {
- if (software->startempty && mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", software->driver->name, true))
- menu::stack_push<menu_dats_view>(ui(), container(), software->driver);
- else if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", std::string(software->shortname).append(1, ',').append(software->listname).c_str()) || !software->usage.empty())
- menu::stack_push<menu_dats_view>(ui(), container(), software);
- }
- else if (driver)
- {
- if (mame_machine_manager::instance()->lua()->call_plugin_check<const char *>("data_list", driver->name, true))
- menu::stack_push<menu_dats_view>(ui(), container(), driver);
- }
+ ui_system_info const *system;
+ get_selection(software, system);
+ if (software && !software->startempty)
+ menu::stack_push<menu_dats_view>(ui(), container(), *software);
+ else if (system)
+ menu::stack_push<menu_dats_view>(ui(), container(), system);
}
//-------------------------------------------------
-// draw common arrows
+// draw info arrow
//-------------------------------------------------
-void menu_select_launch::draw_common_arrow(float origx1, float origy1, float origx2, float origy2, int current, int dmin, int dmax, float title_size)
+void menu_select_launch::draw_info_arrow(u32 flags, int line)
{
- auto line_height = ui().get_line_height();
- auto lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect(&container());
- auto gutter_width = lr_arrow_width * 1.3f;
+ float const linetop(m_right_content_vbounds.first + (float(line) * m_info_line_height));
+ float const linebottom(m_right_content_vbounds.first + (float(line + 1) * m_info_line_height));
+ bool const hovered(pointer_in_rect(m_right_content_hbounds.first, linetop, m_right_content_hbounds.second, linebottom));
+ bool const clicked((pointer_action::RIGHT_TRACK_LINE == m_pointer_action) && (line == m_clicked_line));
- // set left-right arrows dimension
- float const ar_x0 = 0.5f * (origx2 + origx1) + 0.5f * title_size + gutter_width - lr_arrow_width;
- float const ar_y0 = origy1 + 0.1f * line_height;
- float const ar_x1 = 0.5f * (origx2 + origx1) + 0.5f * title_size + gutter_width;
- float const ar_y1 = origy1 + 0.9f * line_height;
-
- float const al_x0 = 0.5f * (origx2 + origx1) - 0.5f * title_size - gutter_width;
- float const al_y0 = origy1 + 0.1f * line_height;
- float const al_x1 = 0.5f * (origx2 + origx1) - 0.5f * title_size - gutter_width + lr_arrow_width;
- float const al_y1 = origy1 + 0.9f * line_height;
-
- rgb_t fgcolor_right, fgcolor_left;
- fgcolor_right = fgcolor_left = ui().colors().text_color();
-
- // set hover
- if (mouse_in_rect(ar_x0, ar_y0, ar_x1, ar_y1) && current != dmax)
+ rgb_t bgcolor = ui().colors().text_bg_color();
+ rgb_t fgcolor = ui().colors().text_color();
+ if (clicked && hovered)
{
- ui().draw_textured_box(container(), ar_x0 + 0.01f, ar_y0, ar_x1 - 0.01f, ar_y1, ui().colors().mouseover_bg_color(), rgb_t(43, 43, 43),
- hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
- set_hover(HOVER_UI_RIGHT);
- fgcolor_right = ui().colors().mouseover_color();
+ // draw selected highlight for tracked item
+ bgcolor = ui().colors().selected_bg_color();
+ fgcolor = ui().colors().selected_color();
+ highlight(m_right_content_hbounds.first, linetop, m_right_content_hbounds.second, linebottom, bgcolor);
}
- else if (mouse_in_rect(al_x0, al_y0, al_x1, al_y1) && current != dmin)
+ else if (clicked || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered && pointer_idle()))
{
- ui().draw_textured_box(container(), al_x0 + 0.01f, al_y0, al_x1 - 0.01f, al_y1, ui().colors().mouseover_bg_color(), rgb_t(43, 43, 43),
- hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
- set_hover(HOVER_UI_LEFT);
- fgcolor_left = ui().colors().mouseover_color();
+ // draw hover highlight when hovered over or dragged off
+ bgcolor = ui().colors().mouseover_bg_color();
+ fgcolor = ui().colors().mouseover_color();
+ highlight(m_right_content_hbounds.first, linetop, m_right_content_hbounds.second, linebottom, bgcolor);
}
- // apply arrow
- if (dmax == dmin)
- return;
- else if (current == dmin)
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, ROT90);
- else if (current == dmax)
- draw_arrow(al_x0, al_y0, al_x1, al_y1, fgcolor_left, ROT90 ^ ORIENTATION_FLIP_X);
- else
- {
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor_right, ROT90);
- draw_arrow(al_x0, al_y0, al_x1, al_y1, fgcolor_left, ROT90 ^ ORIENTATION_FLIP_X);
- }
+ draw_arrow(
+ 0.5F * (m_right_content_hbounds.first + m_right_content_hbounds.second - (x_aspect() * m_info_line_height)),
+ linetop + (0.25F * m_info_line_height),
+ 0.5F * (m_right_content_hbounds.first + m_right_content_hbounds.second + (x_aspect() * m_info_line_height)),
+ linetop + (0.75F * m_info_line_height),
+ fgcolor,
+ line ? (ROT0 ^ ORIENTATION_FLIP_Y) : ROT0);
}
//-------------------------------------------------
-// draw info arrow
+// draw vertical divider
//-------------------------------------------------
-void menu_select_launch::draw_info_arrow(int ub, float origx1, float origx2, float oy1, float line_height, float text_size, float ud_arrow_width)
+void menu_select_launch::draw_divider(u32 flags, float x1, bool right)
{
+ // work out colours
rgb_t fgcolor = ui().colors().text_color();
- uint32_t orientation = (!ub) ? ROT0 : ROT0 ^ ORIENTATION_FLIP_Y;
-
- if (mouse_in_rect(origx1, oy1, origx2, oy1 + (line_height * text_size)))
+ rgb_t bgcolor(0xef, 0x12, 0x47, 0x7b); // FIXME: magic numbers in colour?
+ bool const hovered(pointer_in_rect(x1, m_primary_vbounds.first, x1 + m_divider_width, m_primary_vbounds.second));
+ bool const clicked((pointer_action::DIVIDER_TRACK == m_pointer_action) && ((right ? 1 : 0) == m_clicked_line));
+ if (hovered && clicked)
+ {
+ fgcolor = ui().colors().selected_color();
+ bgcolor = ui().colors().selected_bg_color();
+ }
+ else if (clicked || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered))
{
- ui().draw_textured_box(container(), origx1 + 0.01f, oy1, origx2 - 0.01f, oy1 + (line_height * text_size), ui().colors().mouseover_bg_color(),
- rgb_t(43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
- set_hover((!ub) ? HOVER_DAT_UP : HOVER_DAT_DOWN);
fgcolor = ui().colors().mouseover_color();
}
- draw_arrow(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 the divider pane
+ ui().draw_outlined_box(container(), x1, m_primary_vbounds.first, x1 + m_divider_width, m_primary_vbounds.second, bgcolor);
+
+ // draw the arrow
+ uint32_t orientation(ROT90);
+ if (right ? !show_right_panel() : show_left_panel())
+ orientation ^= ORIENTATION_FLIP_X;
+ float const ar_x0 = x1 + (0.5F * (m_divider_width - m_divider_arrow_width));
+ float const ar_y0 = 0.5F * (m_primary_vbounds.first + m_primary_vbounds.second - m_divider_arrow_height);
+ draw_arrow(ar_x0, ar_y0, ar_x0 + m_divider_arrow_width, ar_y0 + m_divider_arrow_height, fgcolor, orientation);
}
-bool menu_select_launch::draw_error_text()
-{
- if (m_ui_error)
- ui().draw_text_box(container(), m_error_text, ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR);
- return m_ui_error;
-}
+//-------------------------------------------------
+// draw left panel (filter list)
+//-------------------------------------------------
template <typename Filter>
-float menu_select_launch::draw_left_panel(
- typename Filter::type current,
- std::map<typename Filter::type, typename Filter::ptr> const &filters,
- float x1, float y1, float x2, float y2)
+void menu_select_launch::draw_left_panel(u32 flags, typename Filter::type current, std::map<typename Filter::type, typename Filter::ptr> const &filters)
{
- if ((ui_globals::panels_status != SHOW_PANELS) && (ui_globals::panels_status != HIDE_RIGHT_PANEL))
- return draw_collapsed_left_panel(x1, y1, x2, y2);
-
- // calculate line height
- float const line_height(ui().get_line_height());
- float const text_size(ui().options().infos_size());
- float const sc(y2 - y1 - (2.0f * ui().box_tb_border()));
- float line_height_max(line_height * text_size);
- if ((Filter::COUNT * line_height_max) > sc)
+ if (!show_left_panel())
{
- float const lm(sc / Filter::COUNT);
- line_height_max = line_height * (lm / line_height);
+ // left panel hidden, but no need to recompute metrics if target isn't resized
+ m_left_panel_width = 0.0F;
+
+ draw_divider(flags, lr_border(), false);
+ return;
}
- // calculate horizontal offset for unadorned names
- std::string tmp(convert_command_glyph("_# "));
- float const text_sign = ui().get_string_width(tmp, text_size);
+ // get the width of the selection indicator glyphs
+ float const checkmark_width = ui().get_string_width(convert_command_glyph("_# "), m_info_line_height);
- // get the maximum width of a filter name
- float left_width(0.0f);
- for (typename Filter::type x = Filter::FIRST; Filter::COUNT > x; ++x)
- left_width = std::max(ui().get_string_width(Filter::display_name(x), text_size) + text_sign, left_width);
+ if (m_left_items_hbounds.first >= m_left_items_hbounds.second)
+ {
+ // calculate number of lines that will fit - centre vertically if we need scroll arrows
+ float const height(m_primary_vbounds.second - m_primary_vbounds.first);
+ int const lines((height - (tb_border() * 2.0F)) / m_info_line_height);
+ if (Filter::COUNT <= lines)
+ m_left_items_top = m_primary_vbounds.first + tb_border();
+ else
+ m_left_items_top = m_primary_vbounds.first + ((height - (float(lines) * m_info_line_height)) * 0.5F);
+ float const pixelheight(target_size().second);
+ m_left_items_top = std::round(m_left_items_top * pixelheight) / pixelheight;
+ m_left_item_count = Filter::COUNT;
+ m_left_visible_lines = std::min<int>(Filter::COUNT, lines);
+
+ // get the maximum filter name width, restricted to a quarter of the target width
+ float line_width(0.0F);
+ for (typename Filter::type x = Filter::FIRST; Filter::COUNT > x; ++x)
+ line_width = std::max(ui().get_string_width(Filter::display_name(x), m_info_line_height) + checkmark_width, line_width);
+ line_width = std::min(line_width + (lr_border() * 2.0F), 0.25F);
+ m_left_items_hbounds = std::make_pair(2.0F * lr_border(), (2.0F * lr_border()) + line_width);
+
+ // make sure the scroll position makes sense
+ m_left_visible_top = (std::min)(m_left_visible_top, m_left_item_count - m_left_visible_lines);
+ }
+ m_left_panel_width = (m_left_items_hbounds.second - m_left_items_hbounds.first) + (lr_border() * 2.0F);
+
+ // ensure the highlighted item is visible
+ if ((m_filter_highlight - Filter::FIRST) < (m_left_visible_top + 1))
+ m_left_visible_top = (Filter::FIRST == m_filter_highlight) ? 0 : (m_filter_highlight - 1);
+ else if ((m_filter_highlight - Filter::FIRST) > (m_left_visible_top + m_left_visible_lines - 2))
+ m_left_visible_top = (std::min)(m_filter_highlight - Filter::FIRST + 2 - m_left_visible_lines, m_left_item_count - m_left_visible_lines);
// outline the box and inset by the border width
- float const origy1(y1);
- float const origy2(y2);
- float const aspect(machine().render().ui_aspect(&container()));
- float const lr_border(ui().box_lr_border() * aspect);
- x2 = x1 + left_width + 2.0f * lr_border;
- ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
- x1 += lr_border;
- x2 -= lr_border;
- y1 += ui().box_tb_border();
- y2 -= ui().box_tb_border();
+ ui().draw_outlined_box(
+ container(),
+ lr_border(), m_primary_vbounds.first, lr_border() + m_left_panel_width, m_primary_vbounds.second,
+ ui().colors().background_color());
// now draw the rows
+ typename Filter::type filter(Filter::FIRST);
+ for (int i = 0; i < m_left_visible_top; ++i)
+ ++filter;
auto const active_filter(filters.find(current));
- for (typename Filter::type filter = Filter::FIRST; Filter::COUNT > filter; ++filter)
+ std::string str;
+ bool const atbottom((m_left_visible_top + m_left_visible_lines) == m_left_item_count);
+ for (int line = 0; line < m_left_visible_lines; ++line, ++filter)
{
- std::string str;
- if (filters.end() != active_filter)
- {
- str = active_filter->second->adorned_display_name(filter);
- }
- else
- {
- if (current == filter)
- str = convert_command_glyph("_> ");
- str.append(Filter::display_name(filter));
- }
+ float const line_top(m_left_items_top + (float(line) * m_info_line_height));
+ bool const uparrow(!line && m_left_visible_top);
+ bool const downarrow(!atbottom && ((m_left_visible_lines - 1) == line));
- // handle mouse hover in passing
+ // work out the colours for this item
rgb_t bgcolor = ui().colors().text_bg_color();
rgb_t fgcolor = ui().colors().text_color();
- if (mouse_in_rect(x1, y1, x2, y1 + line_height_max))
+ bool const hovered(pointer_in_rect(m_left_items_hbounds.first, line_top, m_left_items_hbounds.second, line_top + m_info_line_height));
+ bool const pointerline((pointer_action::LEFT_TRACK_LINE == m_pointer_action) && (line == m_clicked_line));
+ if (pointerline && hovered)
{
- bgcolor = ui().colors().mouseover_bg_color();
- fgcolor = ui().colors().mouseover_color();
- set_hover(HOVER_FILTER_FIRST + filter);
- highlight(x1, y1, x2, y1 + line_height_max, bgcolor);
+ // draw selected highlight for tracked item
+ bgcolor = ui().colors().selected_bg_color();
+ fgcolor = ui().colors().selected_color();
+ highlight(m_left_items_hbounds.first, line_top, m_left_items_hbounds.second, line_top + m_info_line_height, bgcolor);
}
-
- // draw primary highlight if keyboard focus is here
- if ((m_filter_highlight == filter) && (get_focus() == focused_menu::LEFT))
+ else if ((m_filter_highlight == filter) && (get_focus() == focused_menu::LEFT))
{
+ // draw primary highlight if keyboard focus is here
fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
ui().draw_textured_box(
container(),
- x1, y1, x2, y1 + line_height_max,
+ m_left_items_hbounds.first, line_top, m_left_items_hbounds.second, line_top + m_info_line_height,
bgcolor, rgb_t(255, 43, 43, 43),
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
+ else if (pointerline || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered && pointer_idle()))
+ {
+ // draw hover highlight when hovered over or dragged off
+ bgcolor = ui().colors().mouseover_bg_color();
+ fgcolor = ui().colors().mouseover_color();
+ highlight(m_left_items_hbounds.first, line_top, m_left_items_hbounds.second, line_top + m_info_line_height, bgcolor);
+ }
- // finally draw the text itself and move to the next line
- float const x1t = x1 + ((str == Filter::display_name(filter)) ? text_sign : 0.0f);
- ui().draw_text_full(
- container(), str,
- x1t, y1, x2 - x1,
- ui::text_layout::LEFT, ui::text_layout::NEVER,
- mame_ui_manager::NORMAL, fgcolor, bgcolor,
- nullptr, nullptr, text_size);
- y1 += line_height_max;
- }
-
- x1 = x2 + lr_border;
- x2 = x1 + 2.0f * lr_border;
- y1 = origy1;
- y2 = origy2;
- float const space = x2 - x1;
- float const lr_arrow_width = 0.4f * space * aspect;
-
- // set left-right arrows dimension
- float const ar_x0 = 0.5f * (x2 + x1) - 0.5f * lr_arrow_width;
- float const ar_y0 = 0.5f * (y2 + y1) + 0.1f * space;
- float const ar_x1 = ar_x0 + lr_arrow_width;
- float const ar_y1 = 0.5f * (y2 + y1) + 0.9f * space;
-
- ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xef, 0x12, 0x47, 0x7b));
-
- rgb_t fgcolor = ui().colors().text_color();
- if (mouse_in_rect(x1, y1, x2, y2))
- {
- fgcolor = ui().colors().mouseover_color();
- set_hover(HOVER_LPANEL_ARROW);
+ // finally draw the text itself
+ if (uparrow || downarrow)
+ {
+ draw_arrow(
+ 0.5F * (m_left_items_hbounds.first + m_left_items_hbounds.second + (x_aspect() * m_info_line_height)),
+ line_top + (0.25F * m_info_line_height),
+ 0.5F * (m_left_items_hbounds.first + m_left_items_hbounds.second - (x_aspect() * m_info_line_height)),
+ line_top + (0.75F * m_info_line_height),
+ fgcolor,
+ downarrow ? (ROT0 ^ ORIENTATION_FLIP_Y) : ROT0);
+ }
+ else
+ {
+ if (filters.end() != active_filter)
+ str = active_filter->second->adorned_display_name(filter);
+ else if (current == filter)
+ (str = convert_command_glyph("_> ")).append(Filter::display_name(filter));
+ else
+ str = Filter::display_name(filter);
+ float const x1t = m_left_items_hbounds.first + lr_border() + ((str == Filter::display_name(filter)) ? checkmark_width : 0.0F);
+ ui().draw_text_full(
+ container(), str,
+ x1t, line_top, m_left_items_hbounds.second - x1t - lr_border() + (1.0F / float(target_size().second)),
+ text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE,
+ mame_ui_manager::NORMAL, fgcolor, bgcolor,
+ nullptr, nullptr,
+ m_info_line_height);
+ }
}
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90 ^ ORIENTATION_FLIP_X);
- return x2 + lr_border;
+ // draw the divider
+ draw_divider(flags, lr_border() + m_left_panel_width, false);
}
@@ -1087,11 +1284,7 @@ void menu_select_launch::check_for_icons(char const *listname)
{
// if we're doing a software list, append it to the configured path
if (listname)
- {
- if (!current.empty() && !util::is_directory_separator(current.back()))
- current.append(PATH_SEPARATOR);
- current.append(listname);
- }
+ util::path_append(current, listname);
osd_printf_verbose("Checking for icons in directory %s\n", current);
// open and walk the directory
@@ -1136,11 +1329,7 @@ std::string menu_select_launch::make_icon_paths(char const *listname) const
{
// if we're doing a software list, append it to the configured path
if (listname)
- {
- if (!current.empty() && !util::is_directory_separator(current.back()))
- current.append(PATH_SEPARATOR);
- current.append(listname);
- }
+ util::path_append(current, listname);
// append the configured path
if (!result.empty())
@@ -1172,24 +1361,14 @@ bool menu_select_launch::scale_icon(bitmap_argb32 &&src, texture_and_bitmap &dst
assert(dst.texture);
if (src.valid())
{
- // calculate available space for the icon in pixels
- float const height(ui().get_line_height());
- float const width(height * container().manager().ui_aspect(&container()));
- render_target const &target(machine().render().ui_target());
- uint32_t const dst_height(target.height());
- uint32_t const dst_width(target.width());
- bool const rotated((target.orientation() & ORIENTATION_SWAP_XY) != 0);
- int const max_height(int((rotated ? dst_width : dst_height) * height));
- int const max_width(int((rotated ? dst_height : dst_width) * width));
-
// reduce the source bitmap if it's too big
bitmap_argb32 tmp;
- float const ratio((std::min)({ float(max_height) / src.height(), float(max_width) / src.width(), 1.0F }));
+ float const ratio((std::min)({ float(m_icon_height) / src.height(), float(m_icon_width) / src.width(), 1.0F }));
if (1.0F > ratio)
{
- float const pix_height(src.height() * ratio);
- float const pix_width(src.width() * ratio);
- tmp.allocate(int32_t(pix_width), int32_t(pix_height));
+ float const pix_height(std::ceil(src.height() * ratio));
+ float const pix_width(std::ceil(src.width() * ratio));
+ tmp.allocate(s32(pix_width), s32(pix_height));
render_resample_argb_bitmap_hq(tmp, src, render_color{ 1.0F, 1.0F, 1.0F, 1.0F }, true);
}
else
@@ -1198,7 +1377,7 @@ bool menu_select_launch::scale_icon(bitmap_argb32 &&src, texture_and_bitmap &dst
}
// copy into the destination
- dst.bitmap.allocate(max_width, max_height);
+ dst.bitmap.allocate(m_icon_width, m_icon_height);
for (int y = 0; tmp.height() > y; ++y)
for (int x = 0; tmp.width() > x; ++x)
dst.bitmap.pix(y, x) = tmp.pix(y, x);
@@ -1254,46 +1433,87 @@ bool menu_select_launch::select_part(mame_ui_manager &mui, render_container &con
// draw toolbar
//-------------------------------------------------
-void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2)
+void menu_select_launch::draw_toolbar(u32 flags, float x1, float y1, float x2, float y2)
{
- // draw a box
- ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xEF, 0x12, 0x47, 0x7B));
+ // work out which buttons we're going to draw
+ bool const have_parent(m_is_swlist || !stack_has_special_main_menu());
+ auto const *const toolbar_bitmaps(m_is_swlist ? SW_TOOLBAR_BITMAPS : SYS_TOOLBAR_BITMAPS);
+ unsigned const toolbar_count(m_is_swlist ? std::size(SW_TOOLBAR_BITMAPS) : std::size(SYS_TOOLBAR_BITMAPS));
- // take off the borders
- float const aspect(machine().render().ui_aspect(&container()));
- float const lr_border(ui().box_lr_border() * aspect);
- x1 += lr_border;
- x2 -= lr_border;
- y1 += ui().box_tb_border();
- y2 -= ui().box_tb_border();
+ // draw a box
+ ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xef, 0x12, 0x47, 0x7b));
- texture_ptr_vector const &t_texture(m_is_swlist ? m_cache->sw_toolbar_texture() : m_cache->toolbar_texture());
- bitmap_vector const &t_bitmap(m_is_swlist ? m_cache->sw_toolbar_bitmap() : m_cache->toolbar_bitmap());
+ // cache metrics and bitmaps if necessary
+ if (m_toolbar_button_vbounds.first >= m_toolbar_button_vbounds.second)
+ {
+ m_toolbar_button_vbounds.first = y1 + tb_border();
+ m_toolbar_button_vbounds.second = y2 - tb_border();
+ float const button_height(m_toolbar_button_vbounds.second - m_toolbar_button_vbounds.first);
+ m_toolbar_button_width = button_height * float(x_aspect());
+ m_toolbar_button_spacing = m_toolbar_button_width * 1.5F;
+ float const total_width((float(toolbar_count) + (float(toolbar_count - 1) * 0.5F)) * m_toolbar_button_width);
+ m_toolbar_backtrack_left = x2 - lr_border() - m_toolbar_button_width;
+ m_toolbar_main_left = (std::min)(m_toolbar_backtrack_left - (float(toolbar_count) * m_toolbar_button_spacing), (x1 + x2 - total_width) * 0.5F);
+ m_cache.cache_toolbar(machine(), m_toolbar_button_width, button_height);
+ }
- auto const num_valid(std::count_if(std::begin(t_bitmap), std::end(t_bitmap), [](bitmap_argb32 const &e) { return e.valid(); }));
+ // tooltip needs to be above for pen/touch to avoid being obscured
+ float tooltip_pos;
+ switch (pointer_type())
+ {
+ case ui_event::pointer::PEN:
+ case ui_event::pointer::TOUCH:
+ tooltip_pos = m_toolbar_button_vbounds.first - line_height() - (2.0F * tb_border());
+ break;
+ default:
+ tooltip_pos = m_toolbar_button_vbounds.second + line_height() + tb_border();
+ break;
+ }
- float const space_x = (y2 - y1) * aspect;
- 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].valid())
+ // add backtrack button
+ bool const hovered(pointer_in_rect(m_toolbar_backtrack_left, m_toolbar_button_vbounds.first, m_toolbar_backtrack_left + m_toolbar_button_width, m_toolbar_button_vbounds.second));
+ bool const tracked((pointer_action::TOOLBAR_TRACK == m_pointer_action) && (0 > m_clicked_line));
+ rgb_t const color((hovered && tracked) ? rgb_t::white() : rgb_t(0xffcccccc));
+ if (tracked || (hovered && !(flags & PROCESS_NOINPUT) && pointer_idle()))
{
- rgb_t color(0xEFEFEFEF);
- if (mouse_in_rect(x1, y1, x2, y2))
- {
- set_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().colors().background_color());
- }
+ ui().draw_text_box(
+ container(),
+ have_parent ? _("Return to Previous Menu") : _("Exit"),
+ text_layout::text_justify::RIGHT, 1.0F - lr_border(), tooltip_pos,
+ ui().colors().background_color());
+ }
+ container().add_quad(
+ m_toolbar_backtrack_left, m_toolbar_button_vbounds.first, m_toolbar_backtrack_left + m_toolbar_button_width, m_toolbar_button_vbounds.second,
+ color,
+ m_cache.toolbar_textures()[2 * (have_parent ? TOOLBAR_BITMAP_PREVMENU : TOOLBAR_BITMAP_EXIT)].get(),
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
- 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;
+ // now add the other buttons
+ for (int z = 0; toolbar_count > z; ++z)
+ {
+ auto const [bitmap, action, need_selection] = toolbar_bitmaps[z];
+ float const button_left(m_toolbar_main_left + (float(z) * m_toolbar_button_spacing));
+ float const button_right(button_left + m_toolbar_button_width);
+ bool const enabled(!need_selection || get_selection_ptr());
+ bool const hovered(pointer_in_rect(button_left, m_toolbar_button_vbounds.first, button_right, m_toolbar_button_vbounds.second));
+ bool const tracked((pointer_action::TOOLBAR_TRACK == m_pointer_action) && (z == m_clicked_line));
+ rgb_t color((hovered && tracked && enabled) ? rgb_t::white() : rgb_t(0xffcccccc));
+ if (tracked || (hovered && !(flags & PROCESS_NOINPUT) && pointer_idle()))
+ {
+ ui().draw_text_box(
+ container(),
+ _(hover_msg[bitmap]),
+ text_layout::text_justify::CENTER, (button_left + button_right) * 0.5F, tooltip_pos,
+ ui().colors().background_color());
}
+ container().add_quad(
+ button_left, m_toolbar_button_vbounds.first, button_right, m_toolbar_button_vbounds.second,
+ color,
+ m_cache.toolbar_textures()[(2 * bitmap) + (enabled ? 0 : 1)].get(),
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
}
@@ -1304,16 +1524,16 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2)
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());
- 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;
+ if (TOOLBAR_BITMAP_FAVORITE < m_cache.toolbar_textures().size())
+ {
+ float const y1 = y0 + line_height();
+ float const x1 = x0 + line_height() * container().manager().ui_aspect(&container());
+ container().add_quad(
+ x0, y0, x1, y1,
+ rgb_t::white(),
+ m_cache.toolbar_textures()[TOOLBAR_BITMAP_FAVORITE].get(),
+ PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_PACKABLE);
+ }
}
@@ -1326,9 +1546,8 @@ void menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, flo
render_texture *const icon(get_icon_texture(linenum, selectedref));
if (icon)
{
- float const ud_arrow_width = ui().get_line_height() * container().manager().ui_aspect(&container());
- float const x1 = x0 + ud_arrow_width;
- float const y1 = y0 + ui().get_line_height();
+ float const x1 = x0 + ud_arrow_width();
+ float const y1 = y0 + line_height();
container().add_quad(x0, y0, x1, y1, rgb_t::white(), icon, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
};
}
@@ -1338,24 +1557,23 @@ void menu_select_launch::draw_icon(int linenum, void *selectedref, float x0, flo
// get title and search path for right panel
//-------------------------------------------------
-void menu_select_launch::get_title_search(std::string &snaptext, std::string &searchstr)
+std::string menu_select_launch::get_arts_searchpath()
{
- // get arts title text
- snaptext.assign(_(arts_info[m_image_view].first));
+ std::string searchstr;
// get search path
std::string addpath;
if (m_image_view == SNAPSHOT_VIEW)
{
emu_options moptions;
- searchstr = machine().options().value(arts_info[m_image_view].second);
- addpath = moptions.value(arts_info[m_image_view].second);
+ searchstr = machine().options().value(std::get<2>(ARTS_INFO[m_image_view]));
+ addpath = moptions.value(std::get<2>(ARTS_INFO[m_image_view]));
}
else
{
ui_options moptions;
- searchstr = ui().options().value(arts_info[m_image_view].second);
- addpath = moptions.value(arts_info[m_image_view].second);
+ searchstr = ui().options().value(std::get<2>(ARTS_INFO[m_image_view]));
+ addpath = moptions.value(std::get<2>(ARTS_INFO[m_image_view]));
}
std::string tmp(searchstr);
@@ -1370,20 +1588,304 @@ void menu_select_launch::get_title_search(std::string &snaptext, std::string &se
while (path_iter.next(c_path))
searchstr.append(";").append(curpath).append(PATH_SEPARATOR).append(c_path);
}
+
+ return searchstr;
}
//-------------------------------------------------
-// handle keys for main menu
+// handle UI input events for main menu
//-------------------------------------------------
-void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
+bool menu_select_launch::handle_events(u32 flags, event &ev)
{
- bool const ignorepause = stack_has_special_main_menu();
+ // loop while we have interesting events
+ bool stop(false), need_update(false), search_changed(false);
+ ui_event local_menu_event;
+ while (!stop && machine().ui_input().pop_event(&local_menu_event))
+ {
+ switch (local_menu_event.event_type)
+ {
+ // deal with pointer-like input (mouse, pen, touch, etc.)
+ case ui_event::type::POINTER_UPDATE:
+ {
+ auto const [key, redraw] = handle_pointer_update(flags, local_menu_event);
+ need_update = need_update || redraw;
+ if (IPT_INVALID != key)
+ {
+ ev.iptkey = key;
+ stop = true;
+ }
+ }
+ break;
+
+ // pointer left the normal way, possibly releasing buttons
+ case ui_event::type::POINTER_LEAVE:
+ {
+ auto const [key, redraw] = handle_pointer_leave(flags, local_menu_event);
+ need_update = need_update || redraw;
+ if (IPT_INVALID != key)
+ {
+ ev.iptkey = key;
+ stop = true;
+ }
+ }
+ break;
+
+ // pointer left in some abnormal way - cancel any associated actions
+ case ui_event::type::POINTER_ABORT:
+ {
+ auto const [key, redraw] = handle_pointer_abort(flags, local_menu_event);
+ need_update = need_update || redraw;
+ if (IPT_INVALID != key)
+ {
+ ev.iptkey = key;
+ stop = true;
+ }
+ }
+ break;
+ // caught scroll event
+ case ui_event::type::MOUSE_WHEEL:
+ if ((&machine().render().ui_target() == local_menu_event.target) && pointer_idle() && !m_ui_error)
+ {
+ // check whether it's over something scrollable
+ float x, y;
+ bool const hit(local_menu_event.target->map_point_container(local_menu_event.mouse_x, local_menu_event.mouse_y, container(), x, y));
+ if (!hit)
+ {
+ m_wheel_movement = 0;
+ break;
+ }
+ focused_menu hover;
+ if ((x >= m_primary_items_hbounds.first) && (x < m_primary_items_hbounds.second) && (y >= m_primary_items_top) && (y < (m_primary_items_top + (float(m_primary_lines) * line_height()))))
+ {
+ hover = focused_menu::MAIN;
+ }
+ else if (show_left_panel() && (x >= m_left_items_hbounds.first) && (x < m_left_items_hbounds.second) && (y >= m_left_items_top) && (y < (m_left_items_top + (float(m_left_visible_lines) * m_info_line_height))))
+ {
+ hover = focused_menu::LEFT;
+ }
+ else if (show_right_panel() && (x >= m_right_content_hbounds.first) && (x < m_right_content_hbounds.second) && (y >= m_right_content_vbounds.first) && (y < m_right_content_vbounds.second))
+ {
+ hover = focused_menu::RIGHTBOTTOM;
+ }
+ else
+ {
+ m_wheel_movement = 0;
+ break;
+ }
+
+ // clear out leftovers if it isn't the last thing to be scrolled
+ if (hover != m_wheel_target)
+ m_wheel_movement = 0;
+ m_wheel_target = hover;
+
+ // the value is scaled to 120 units per "click"
+ m_wheel_movement += local_menu_event.zdelta * local_menu_event.num_lines;
+ int const lines((m_wheel_movement + ((0 < local_menu_event.zdelta) ? 36 : -36)) / 120);
+ if (!lines)
+ break;
+ m_wheel_movement -= lines * 120;
+
+ switch (hover)
+ {
+ case focused_menu::MAIN:
+ if (lines > 0)
+ {
+ if ((selected_index() >= m_available_items) || is_first_selected())
+ break;
+ stop = true;
+ ev.iptkey = IPT_CUSTOM; // stop processing events so info can be rebuilt
+ set_selected_index(selected_index() - lines);
+ if (selected_index() < top_line + (top_line != 0))
+ top_line -= lines;
+ }
+ else
+ {
+ if (selected_index() >= (m_available_items - 1))
+ break;
+ stop = true;
+ ev.iptkey = IPT_CUSTOM; // stop processing events so info can be rebuilt
+ set_selected_index(std::min(selected_index() - lines, m_available_items - 1));
+ if (selected_index() >= top_line + m_visible_items + (top_line != 0))
+ top_line -= lines;
+ }
+ break;
+ case focused_menu::LEFT:
+ {
+ m_left_visible_top = std::clamp(m_left_visible_top - lines, 0, m_left_item_count - m_left_visible_lines);
+ int const first(left_at_top() ? 0 : (m_left_visible_top + 1));
+ int const last(m_left_visible_top + m_left_visible_lines - (left_at_bottom() ? 1 : 2));
+ m_filter_highlight = std::clamp(m_filter_highlight, first, last);
+ m_filter_highlight = std::clamp(m_filter_highlight - lines, 0, m_left_item_count - 1);
+ }
+ break;
+ case focused_menu::RIGHTBOTTOM:
+ if (RP_INFOS == m_right_panel)
+ m_topline_datsview -= lines;
+ break;
+ case focused_menu::RIGHTTOP:
+ break; // never gets here
+ }
+ }
+ break;
+
+ // text input goes to the search field unless there's an error message displayed
+ case ui_event::type::IME_CHAR:
+ if (!pointer_idle())
+ break;
+
+ if (exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_NEXT, 0) || exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_PREV, 0))
+ {
+ stop = true;
+ }
+ else if (m_ui_error)
+ {
+ ev.iptkey = IPT_CUSTOM;
+ stop = true;
+ }
+ else if (accept_search())
+ {
+ if (input_character(m_search, local_menu_event.ch, uchar_is_printable))
+ search_changed = true;
+ }
+ break;
+
+ // ignore everything else
+ default:
+ break;
+ }
+
+ // need to update search before processing certain kinds of events, but others don't matter
+ if (search_changed)
+ {
+ switch (machine().ui_input().peek_event_type())
+ {
+ case ui_event::type::MOUSE_WHEEL:
+ case ui_event::type::POINTER_UPDATE:
+ case ui_event::type::POINTER_LEAVE:
+ case ui_event::type::POINTER_ABORT:
+ stop = true;
+ break;
+ case ui_event::type::NONE:
+ case ui_event::type::WINDOW_FOCUS:
+ case ui_event::type::WINDOW_DEFOCUS:
+ case ui_event::type::IME_CHAR:
+ break;
+ }
+ }
+ }
+
+ // deal with repeating main scroll arrows
+ if ((pointer_action::MAIN_TRACK_LINE == m_pointer_action) && (is_main_up_arrow(m_clicked_line) || (is_main_down_arrow(m_clicked_line))))
+ {
+ if (check_scroll_repeat(m_primary_items_top, m_primary_items_hbounds, line_height()))
+ {
+ if (!m_clicked_line)
+ {
+ // scroll up
+ --top_line;
+ if (main_at_top())
+ m_pointer_action = pointer_action::NONE;
+ }
+ else
+ {
+ // scroll down
+ ++top_line;
+ if (main_at_bottom())
+ m_pointer_action = pointer_action::NONE;
+ }
+ if (main_force_visible_selection())
+ {
+ if (IPT_INVALID == ev.iptkey)
+ ev.iptkey = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ }
+ need_update = true;
+ }
+ }
+
+ // deal with repeating info view arrows
+ if (pointer_action::RIGHT_TRACK_ARROW == m_pointer_action)
+ {
+ float const left(m_clicked_line ? (m_right_content_hbounds.second - lr_border() - lr_arrow_width()) : (m_right_content_hbounds.first + lr_border()));
+ float const right(m_clicked_line ? (m_right_content_hbounds.second - lr_border()) : (m_right_content_hbounds.first + lr_border() + lr_arrow_width()));
+ if (pointer_in_rect(left, right_arrows_top(), right, right_arrows_bottom()))
+ {
+ if (std::chrono::steady_clock::now() >= m_scroll_repeat)
+ {
+ m_scroll_repeat += std::chrono::milliseconds(200);
+ if (!(m_clicked_line ? next_right_panel_view() : previous_right_panel_view()).second)
+ m_pointer_action = pointer_action::NONE;
+ need_update = true;
+ }
+ }
+ }
+
+ // deal with repeating filter scroll arrows
+ if ((pointer_action::LEFT_TRACK_LINE == m_pointer_action) && (is_left_up_arrow(m_clicked_line) || (is_left_down_arrow(m_clicked_line))))
+ {
+ if (check_scroll_repeat(m_left_items_top, m_left_items_hbounds, m_info_line_height))
+ {
+ if (!m_clicked_line)
+ {
+ // scroll up
+ --m_left_visible_top;
+ m_filter_highlight = std::min(m_left_visible_top + m_left_visible_lines - 2, m_filter_highlight);
+ if (left_at_top())
+ m_pointer_action = pointer_action::NONE;
+ }
+ else
+ {
+ // scroll down
+ ++m_left_visible_top;
+ m_filter_highlight = std::max(m_left_visible_top + 1, m_filter_highlight);
+ if (left_at_bottom())
+ m_pointer_action = pointer_action::NONE;
+ }
+ need_update = true;
+ }
+ }
+
+ // deal with repeating filter scroll arrows
+ if (pointer_action::RIGHT_TRACK_LINE == m_pointer_action)
+ {
+ if (check_scroll_repeat(m_right_content_vbounds.first, m_right_content_hbounds, m_info_line_height))
+ {
+ if (!m_clicked_line)
+ {
+ // scroll up
+ --m_topline_datsview;
+ if (info_at_top())
+ m_pointer_action = pointer_action::NONE;
+ }
+ else
+ {
+ // scroll down
+ ++m_topline_datsview;
+ if (info_at_bottom())
+ m_pointer_action = pointer_action::NONE;
+ }
+ need_update = true;
+ }
+ }
+
+ if (search_changed)
+ reset(reset_options::SELECT_FIRST);
+
+ return need_update;
+}
+
+
+//-------------------------------------------------
+// handle keys for main menu
+//-------------------------------------------------
+
+bool menu_select_launch::handle_keys(u32 flags, int &iptkey)
+{
// bail if no items
if (item_count() == 0)
- return;
+ return false;
// if we hit select, return true or pop the stack, depending on the item
if (exclusive_input_pressed(iptkey, IPT_UI_SELECT, 0))
@@ -1394,119 +1896,198 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
}
else if (m_focus == focused_menu::LEFT)
{
- m_prev_selected = nullptr;
- filter_selected();
+ filter_selected(m_filter_highlight);
}
- if (is_last_selected() && (m_focus == focused_menu::MAIN))
- {
- iptkey = IPT_UI_CANCEL;
- stack_pop();
- }
- return;
+ return false;
}
- if (exclusive_input_pressed(iptkey, IPT_UI_CANCEL, 0))
+ if (exclusive_input_pressed(iptkey, IPT_UI_BACK, 0))
{
if (m_ui_error)
{
// dismiss error
+ return false;
+ }
+ else if (!is_special_main_menu() && m_search.empty())
+ {
+ // pop the stack if this isn't the root session menu
+ stack_pop();
+ return false;
}
- else if (menu_has_search_active())
+ }
+
+ if (exclusive_input_pressed(iptkey, IPT_UI_CANCEL, 0))
+ {
+ if (!m_search.empty())
{
// escape pressed with non-empty search text clears it
m_search.clear();
- reset(reset_options::SELECT_FIRST);
+ reset(reset_options::REMEMBER_REF);
}
- else
+ else if (is_special_main_menu())
{
- // otherwise pop the stack
+ // this is the root session menu, exit
stack_pop();
+ machine().schedule_exit();
}
- return;
+ return false;
}
// validate the current selection
validate_selection(1);
-
- // swallow left/right keys if they are not appropriate
- bool const ignoreleft = ((selected_item().flags & FLAG_LEFT_ARROW) == 0);
- bool const ignoreright = ((selected_item().flags & FLAG_RIGHT_ARROW) == 0);
- bool const leftclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_LEFT_PANEL);
- bool const rightclose = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL);
+ bool updated(false);
// accept left/right keys as-is with repeat
- if (!ignoreleft && exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0))
+ if (exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0))
{
- // Swap the right panel
if (m_focus == focused_menu::RIGHTTOP)
- ui_globals::rpanel = RP_IMAGES;
- return;
+ {
+ // Swap the right panel and swallow it
+ iptkey = IPT_INVALID;
+ if (right_panel() != RP_IMAGES)
+ {
+ m_right_panel = RP_IMAGES;
+ updated = true;
+ }
+ }
+ else if (show_right_panel())
+ {
+ // Swap the right panel page and swallow it
+ if (right_panel() == RP_IMAGES)
+ {
+ iptkey = IPT_INVALID;
+ if (previous_image_view().first)
+ updated = true;
+ }
+ else if (right_panel() == RP_INFOS)
+ {
+ iptkey = IPT_INVALID;
+ if (previous_info_view().first)
+ updated = true;
+ }
+ }
}
- if (!ignoreright && exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0))
+ // swallow left/right keys if they are not appropriate
+ if (exclusive_input_pressed(iptkey, IPT_UI_RIGHT, (flags & PROCESS_LR_REPEAT) ? 6 : 0))
{
- // Swap the right panel
if (m_focus == focused_menu::RIGHTTOP)
- ui_globals::rpanel = RP_INFOS;
- return;
+ {
+ // Swap the right panel and swallow it
+ iptkey = IPT_INVALID;
+ if (right_panel() != RP_INFOS)
+ {
+ m_right_panel = RP_INFOS;
+ updated = true;
+ }
+ }
+ else if (show_right_panel())
+ {
+ // Swap the right panel page and swallow it
+ if (right_panel() == RP_IMAGES)
+ {
+ iptkey = IPT_INVALID;
+ if (next_image_view().first)
+ updated = true;
+ }
+ else if (right_panel() == RP_INFOS)
+ {
+ iptkey = IPT_INVALID;
+ if (next_info_view().first)
+ updated = true;
+ }
+ }
}
// up backs up by one item
if (exclusive_input_pressed(iptkey, IPT_UI_UP, 6))
{
- if (!leftclose && m_focus == focused_menu::LEFT)
+ if (m_focus == focused_menu::LEFT)
{
- return;
+ // swallow it
+ iptkey = IPT_INVALID;
+ if (m_filter_highlight)
+ {
+ --m_filter_highlight;
+ updated = true;
+ }
}
- else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
{
- m_topline_datsview--;
- return;
+ // swallow it
+ iptkey = IPT_INVALID;
+ if (m_topline_datsview)
+ {
+ m_topline_datsview--;
+ updated = true;
+ }
}
else if (selected_index() == m_available_items + 1 || is_first_selected() || m_ui_error)
{
- return;
+ return updated;
+ }
+ else
+ {
+ set_selected_index(selected_index() - 1);
+ if (selected_index() == top_line && top_line != 0)
+ top_line--;
}
-
- set_selected_index(selected_index() - 1);
-
- if (selected_index() == top_line && top_line != 0)
- top_line--;
}
// down advances by one item
if (exclusive_input_pressed(iptkey, IPT_UI_DOWN, 6))
{
- if (!leftclose && m_focus == focused_menu::LEFT)
+ if (m_focus == focused_menu::LEFT)
{
- return;
+ // swallow it
+ iptkey = IPT_INVALID;
+ if ((m_left_item_count - 1) > m_filter_highlight)
+ {
+ ++m_filter_highlight;
+ updated = true;
+ }
}
- else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
{
+ // swallow it
+ iptkey = IPT_INVALID;
+ updated = true;
m_topline_datsview++;
- return;
}
else if (is_last_selected() || selected_index() == m_available_items - 1 || m_ui_error)
{
- return;
+ return updated;
+ }
+ else
+ {
+ set_selected_index(selected_index() + 1);
+ if (selected_index() == top_line + m_visible_items + (top_line != 0))
+ top_line++;
}
-
- set_selected_index(selected_index() + 1);
- if (selected_index() == 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)
+ if (m_focus == focused_menu::LEFT)
{
- m_topline_datsview -= m_right_visible_lines - 1;
- return;
+ // Filters - swallow it
+ iptkey = IPT_INVALID;
+ if (!left_at_top())
+ {
+ updated = true;
+ m_left_visible_top -= std::min(std::max(m_left_visible_lines - 3, 1), m_left_visible_top);
+ m_filter_highlight = std::min(m_left_visible_top + m_left_visible_lines - 2, m_filter_highlight);
+ }
}
-
- if (selected_index() < m_available_items && !m_ui_error)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
+ {
+ // Infos - swallow it
+ iptkey = IPT_INVALID;
+ updated = true;
+ m_topline_datsview -= m_right_visible_lines - 3;
+ }
+ else if (selected_index() < m_available_items && !m_ui_error)
{
set_selected_index(std::max(selected_index() - m_visible_items, 0));
@@ -1517,14 +2098,25 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
// 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)
+ if (m_focus == focused_menu::LEFT)
{
- m_topline_datsview += m_right_visible_lines - 1;
- return;
+ // Filters - swallow it
+ iptkey = IPT_INVALID;
+ if (!left_at_bottom())
+ {
+ updated = true;
+ m_left_visible_top += std::min(std::max(m_left_visible_lines - 3, 1), m_left_item_count - m_left_visible_lines - m_left_visible_top);
+ m_filter_highlight = std::max(m_left_visible_top + 1, m_filter_highlight);
+ }
}
-
- if (selected_index() < m_available_items && !m_ui_error)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
+ {
+ // Infos - swallow it
+ iptkey = IPT_INVALID;
+ updated = true;
+ m_topline_datsview += m_right_visible_lines - 3;
+ }
+ else if (selected_index() < m_available_items && !m_ui_error)
{
set_selected_index(std::min(selected_index() + m_visible_lines - 2 + (selected_index() == 0), m_available_items - 1));
@@ -1535,63 +2127,92 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
// home goes to the start
if (exclusive_input_pressed(iptkey, IPT_UI_HOME, 0))
{
- if (!leftclose && m_focus == focused_menu::LEFT)
+ if (m_focus == focused_menu::LEFT)
{
- return;
+ // Filters - swallow it
+ iptkey = IPT_INVALID;
+ if (m_filter_highlight)
+ {
+ updated = true;
+ m_left_visible_top = 0;
+ m_filter_highlight = 0;
+ }
}
- else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
{
+ // Infos - swallow it
+ iptkey = IPT_INVALID;
+ if (m_topline_datsview)
+ updated = true;
m_topline_datsview = 0;
- return;
}
-
- if (selected_index() < m_available_items && !m_ui_error)
+ else if (selected_index() < m_available_items && !m_ui_error)
+ {
select_first_item();
+ }
}
// end goes to the last
if (exclusive_input_pressed(iptkey, IPT_UI_END, 0))
{
- if (!leftclose && m_focus == focused_menu::LEFT)
+ if (m_focus == focused_menu::LEFT)
{
- return;
+ // Filters - swallow it
+ iptkey = IPT_INVALID;
+ if ((m_left_item_count - 1) != m_filter_highlight)
+ {
+ updated = true;
+ if (!left_at_bottom())
+ m_left_visible_top = m_left_item_count - m_left_visible_lines;
+ m_filter_highlight = m_left_item_count - 1;
+ }
}
- else if (!rightclose && m_focus == focused_menu::RIGHTBOTTOM)
+ else if ((m_focus == focused_menu::RIGHTTOP) || (m_focus == focused_menu::RIGHTBOTTOM))
{
+ // Infos - swallow it
+ iptkey = IPT_INVALID;
+ updated = true;
m_topline_datsview = m_total_lines;
- return;
}
-
- if (selected_index() < m_available_items && !m_ui_error)
+ else if (selected_index() < m_available_items && !m_ui_error)
+ {
set_selected_index(top_line = m_available_items - 1);
+ }
}
// focus next rotates throw targets forward
if (exclusive_input_pressed(iptkey, IPT_UI_FOCUS_NEXT, 12))
{
if (!m_ui_error)
+ {
rotate_focus(1);
+ updated = true;
+ }
}
// focus next rotates throw targets forward
if (exclusive_input_pressed(iptkey, IPT_UI_FOCUS_PREV, 12))
{
if (!m_ui_error)
+ {
rotate_focus(-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();
+ updated = true;
+ }
}
// 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());
+ mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled(), true);
+
+ // handle pasting text into the search
+ if (exclusive_input_pressed(iptkey, IPT_UI_PASTE, 0))
+ {
+ if (!m_ui_error && accept_search())
+ {
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ }
+ }
// see if any other UI keys are pressed
if (iptkey == IPT_INVALID)
@@ -1605,366 +2226,1034 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
{
case IPT_UI_FOCUS_NEXT:
case IPT_UI_FOCUS_PREV:
- continue;
- case IPT_UI_LEFT:
- if (ignoreleft)
- continue;
- break;
- case IPT_UI_RIGHT:
- if (ignoreright)
- continue;
- break;
case IPT_UI_PAUSE:
- if (ignorepause)
- continue;
- break;
+ continue;
}
if (exclusive_input_pressed(iptkey, code, 0))
break;
}
}
+ return updated;
}
//-------------------------------------------------
-// handle input events for main menu
+// handle pointer input for main menu
//-------------------------------------------------
-void menu_select_launch::handle_events(uint32_t flags, event &ev)
+std::tuple<int, bool, bool> menu_select_launch::custom_pointer_updated(bool changed, ui_event const &uievt)
{
- if (m_pressed)
+ if (ui_event::type::POINTER_ABORT == uievt.event_type)
+ return std::make_tuple(IPT_INVALID, false, false);
+
+ // if nothing's happening, check for clicks
+ if (pointer_idle())
{
- bool const pressed = mouse_pressed();
- int32_t target_x, target_y;
- bool button;
- render_target *const mouse_target = machine().ui_input().find_mouse(&target_x, &target_y, &button);
- if (mouse_target && button && (hover() == HOVER_ARROW_DOWN || hover() == HOVER_ARROW_UP))
- {
- if (pressed)
- machine().ui_input().push_mouse_down_event(mouse_target, target_x, target_y);
- }
+ if ((uievt.pointer_pressed & 0x01) && !(uievt.pointer_buttons & ~u32(0x01)))
+ return handle_primary_down(changed, uievt);
+ else if ((uievt.pointer_pressed & 0x02) && !(uievt.pointer_buttons & ~u32(0x02)))
+ return handle_right_down(changed, uievt);
+ else if ((uievt.pointer_pressed & 0x04) && !(uievt.pointer_buttons & ~u32(0x04)))
+ return handle_middle_down(changed, uievt);
else
+ return std::make_tuple(IPT_INVALID, false, false);
+ }
+
+ // handle in-progress actions
+ switch (m_pointer_action)
+ {
+ case pointer_action::NONE:
+ break;
+ case pointer_action::MAIN_TRACK_LINE:
+ return update_main_track_line(changed, uievt);
+ case pointer_action::MAIN_TRACK_RBUTTON:
+ return update_main_track_rbutton(changed, uievt);
+ case pointer_action::MAIN_DRAG:
+ return update_main_drag(changed, uievt);
+ case pointer_action::LEFT_TRACK_LINE:
+ return update_left_track_line(changed, uievt);
+ case pointer_action::LEFT_DRAG:
+ return update_left_drag(changed, uievt);
+ case pointer_action::RIGHT_TRACK_TAB:
+ return update_right_track_tab(changed, uievt);
+ case pointer_action::RIGHT_TRACK_ARROW:
+ return update_right_track_arrow(changed, uievt);
+ case pointer_action::RIGHT_TRACK_LINE:
+ return update_right_track_line(changed, uievt);
+ case pointer_action::RIGHT_SWITCH:
+ return update_right_switch(changed, uievt);
+ case pointer_action::RIGHT_DRAG:
+ return update_right_drag(changed, uievt);
+ case pointer_action::TOOLBAR_TRACK:
+ return update_toolbar_track(changed, uievt);
+ case pointer_action::DIVIDER_TRACK:
+ return update_divider_track(changed, uievt);
+ }
+ return std::make_tuple(IPT_INVALID, false, false);
+}
+
+
+//-------------------------------------------------
+// handle primary click
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::handle_primary_down(bool changed, ui_event const &uievt)
+{
+ if (m_ui_error)
+ {
+ m_ui_error = false;
+ m_error_text.clear();
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+
+ auto const [x, y] = pointer_location();
+
+ // check main item list
+ if ((x >= m_primary_items_hbounds.first) && (x < m_primary_items_hbounds.second) && (y > m_primary_items_top))
+ {
+ int const line((y - m_primary_items_top) / line_height());
+ if (line < (m_primary_lines + m_skip_main_items))
{
- reset_pressed();
+ int key(IPT_INVALID);
+ m_pointer_action = pointer_action::MAIN_TRACK_LINE;
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = line;
+ if (is_main_up_arrow(line))
+ {
+ // top line is a scroll arrow
+ --top_line;
+ if (main_force_visible_selection())
+ key = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ if (!main_at_top())
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ else
+ m_pointer_action = pointer_action::NONE;
+ }
+ else if (is_main_down_arrow(line))
+ {
+ // bottom line is a scroll arrow
+ ++top_line;
+ if (main_force_visible_selection())
+ key = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ if (!main_at_bottom())
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ else
+ m_pointer_action = pointer_action::NONE;
+ }
+ return std::make_tuple(key, true, true);
}
}
- // loop while we have interesting events
- bool stop(false), search_changed(false);
- ui_event local_menu_event;
- while (!stop && machine().ui_input().pop_event(&local_menu_event))
+ // check filter list
+ if (show_left_panel() && (x >= m_left_items_hbounds.first) && (x < m_left_items_hbounds.second) && (y >= m_left_items_top))
{
- switch (local_menu_event.event_type)
+ int const line((y - m_left_items_top) / m_info_line_height);
+ if (line < m_left_visible_lines)
{
- // if we are hovering over a valid item, select it with a single click
- case ui_event::type::MOUSE_DOWN:
- if (m_ui_error)
+ m_pointer_action = pointer_action::LEFT_TRACK_LINE;
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = line;
+ if (is_left_up_arrow(line))
{
- ev.iptkey = IPT_OTHER;
- stop = true;
+ // top line is a scroll arrow
+ --m_left_visible_top;
+ m_filter_highlight = std::min(m_left_visible_top + m_left_visible_lines - 2, m_filter_highlight);
+ if (!left_at_top())
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ else
+ m_pointer_action = pointer_action::NONE;
+ }
+ else if (is_left_down_arrow(line))
+ {
+ // bottom line is a scroll arrow
+ ++m_left_visible_top;
+ m_filter_highlight = std::max(m_left_visible_top + 1, m_filter_highlight);
+ if (!left_at_bottom())
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ else
+ m_pointer_action = pointer_action::NONE;
}
else
{
- if (hover() >= 0 && hover() < item_count())
- {
- if (hover() >= m_available_items - 1 && selected_index() < m_available_items)
- m_prev_selected = get_selection_ref();
- set_selected_index(hover());
- m_focus = focused_menu::MAIN;
- }
- else if (hover() == HOVER_ARROW_UP)
- {
- set_selected_index(std::max(selected_index() - m_visible_items, 0));
- top_line -= m_visible_items - (top_line + m_visible_lines == m_available_items);
- set_pressed();
- }
- else if (hover() == HOVER_ARROW_DOWN)
- {
- set_selected_index(std::min(selected_index() + m_visible_lines - 2 + (selected_index() == 0), m_available_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 += m_right_visible_lines - 1;
- else if (hover() == HOVER_DAT_UP)
- m_topline_datsview -= m_right_visible_lines - 1;
- else if (hover() == HOVER_LPANEL_ARROW)
+ // ignore multi-click actions - someone hammered on the scroll arrow and hit the end
+ if (1 < uievt.pointer_clicks)
+ m_pointer_action = pointer_action::NONE;
+ }
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ }
+
+ // check right panel content
+ if (show_right_panel())
+ {
+ // check right tabs
+ if ((x >= right_panel_left()) && (x < right_panel_right()) && (y >= m_primary_vbounds.first) && (y < m_right_tabs_bottom))
+ {
+ int const tab((x - right_panel_left()) / right_tab_width());
+ if (tab != m_right_panel)
+ {
+ m_pointer_action = pointer_action::RIGHT_TRACK_TAB;
+ m_clicked_line = tab;
+ }
+ return std::make_tuple(IPT_INVALID, true, pointer_action::NONE != m_pointer_action);
+ }
+
+ if ((x >= m_right_content_hbounds.first) && (x < m_right_content_hbounds.second))
+ {
+ // check right panel heading arrows
+ if ((ui_event::pointer::TOUCH != uievt.pointer_type) && (y >= right_arrows_top()) && (y < right_arrows_bottom()))
+ {
+ if ((x >= (m_right_content_hbounds.first + lr_border())) && (x < (m_right_content_hbounds.first + lr_border() + lr_arrow_width())))
{
- if (get_focus() == focused_menu::LEFT)
+ auto const [updated, notend] = previous_right_panel_view();
+ if (notend)
{
- set_focus(focused_menu::MAIN);
- select_prev();
+ m_pointer_action = pointer_action::RIGHT_TRACK_ARROW;
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(600);
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = 0;
}
-
- 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;
+ return std::make_tuple(IPT_INVALID, true, updated);
}
- else if (hover() == HOVER_RPANEL_ARROW)
+ else if ((x >= (m_right_content_hbounds.second - lr_border() - lr_arrow_width())) && (x < (m_right_content_hbounds.second - lr_border())))
{
- if ((get_focus() == focused_menu::RIGHTTOP) || (get_focus() == focused_menu::RIGHTBOTTOM))
+ auto const [updated, notend] = next_right_panel_view();
+ if (notend)
{
- set_focus(focused_menu::MAIN);
- select_prev();
+ m_pointer_action = pointer_action::RIGHT_TRACK_ARROW;
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(600);
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = 1;
}
+ return std::make_tuple(IPT_INVALID, true, updated);
+ }
+ }
- 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;
+ // check right panel heading touch swipe
+ if ((ui_event::pointer::TOUCH == uievt.pointer_type) && (y >= m_right_heading_top) && (y < (m_right_heading_top + line_height())))
+ {
+ m_pointer_action = pointer_action::RIGHT_SWITCH;
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = 0;
+ if (right_panel() == RP_IMAGES)
+ {
+ m_clicked_line = m_image_view;
}
- else if (hover() == HOVER_B_FAV)
+ else if (right_panel() == RP_INFOS)
{
- ev.iptkey = IPT_UI_FAVORITES;
- stop = true;
+ ui_software_info const *software;
+ ui_system_info const *system;
+ get_selection(software, system);
+ if (software && !software->startempty)
+ m_clicked_line = ui_globals::cur_sw_dats_view;
+ else if (system || (software && software->driver))
+ m_clicked_line = ui_globals::curdats_view;
}
- else if (hover() == HOVER_B_EXPORT)
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+
+ // check info scroll
+ if ((RP_INFOS == m_right_panel) && (y >= m_right_content_vbounds.first) && (y < (m_right_content_vbounds.first + (float(m_right_visible_lines) * m_info_line_height))))
+ {
+ int const line((y - m_right_content_vbounds.first) / m_info_line_height);
+ if (line < m_right_visible_lines)
{
- inkey_export();
- stop = true;
+ bool redraw(false);
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = line;
+ if (!line && !info_at_top())
+ {
+ redraw = true;
+ --m_topline_datsview;
+ if (!info_at_top())
+ {
+ m_pointer_action = pointer_action::RIGHT_TRACK_LINE;
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ }
+ }
+ else if ((line == (m_right_visible_lines - 1)) && !info_at_bottom())
+ {
+ redraw = true;
+ ++m_topline_datsview;
+ if (!info_at_bottom())
+ {
+ m_pointer_action = pointer_action::RIGHT_TRACK_LINE;
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
+ }
+ }
+ else if (ui_event::pointer::TOUCH == uievt.pointer_type)
+ {
+ m_pointer_action = pointer_action::RIGHT_DRAG;
+ m_clicked_line = m_topline_datsview;
+ }
+ return std::make_tuple(IPT_INVALID, true, redraw);
}
- else if (hover() == HOVER_B_DATS)
+ }
+ }
+ }
+
+ // check toolbar
+ if ((y >= m_toolbar_button_vbounds.first) && (y < m_toolbar_button_vbounds.second))
+ {
+ if ((x >= m_toolbar_backtrack_left) && (x < (m_toolbar_backtrack_left + m_toolbar_button_width)))
+ {
+ m_pointer_action = pointer_action::TOOLBAR_TRACK;
+ m_clicked_line = -1;
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ else
+ {
+ unsigned const toolbar_count(m_is_swlist ? std::size(SW_TOOLBAR_BITMAPS) : std::size(SYS_TOOLBAR_BITMAPS));
+ float const button(std::floor((x - m_toolbar_main_left) / m_toolbar_button_spacing));
+ int const n(button);
+ if ((n >= 0) && (n < toolbar_count) && (x < (m_toolbar_main_left + (button * m_toolbar_button_spacing) + m_toolbar_button_width)))
+ {
+ m_pointer_action = pointer_action::TOOLBAR_TRACK;
+ m_clicked_line = n;
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ }
+ }
+
+ // check dividers
+ if ((y >= m_primary_vbounds.first) && (y < m_primary_vbounds.second))
+ {
+ if ((x >= left_divider_left()) && (x < left_divider_right()))
+ {
+ m_pointer_action = pointer_action::DIVIDER_TRACK;
+ m_clicked_line = 0;
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ else if ((x >= right_divider_left()) && (x < right_divider_right()))
+ {
+ m_pointer_action = pointer_action::DIVIDER_TRACK;
+ m_clicked_line = 1;
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ }
+
+ return std::make_tuple(IPT_INVALID, false, false);
+}
+
+
+//-------------------------------------------------
+// handle right click
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::handle_right_down(bool changed, ui_event const &uievt)
+{
+ if (m_ui_error)
+ return std::make_tuple(IPT_INVALID, false, false);
+
+ // check main item list
+ auto const [x, y] = pointer_location();
+ if ((x >= m_primary_items_hbounds.first) && (x < m_primary_items_hbounds.second) && (y > m_primary_items_top))
+ {
+ int const line((y - m_primary_items_top) / line_height());
+ if ((line < m_primary_lines) && !is_main_up_arrow(line) && (!is_main_down_arrow(line)))
+ {
+ m_pointer_action = pointer_action::MAIN_TRACK_RBUTTON;
+ m_base_pointer = m_last_pointer = std::make_pair(x, y);
+ m_clicked_line = line;
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ }
+
+ return std::make_tuple(IPT_INVALID, false, false);
+}
+
+
+//-------------------------------------------------
+// handle middle click
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::handle_middle_down(bool changed, ui_event const &uievt)
+{
+ if (m_ui_error)
+ return std::make_tuple(IPT_INVALID, false, false);
+
+ auto const [x, y] = pointer_location();
+ if ((y >= m_primary_vbounds.first) && (y < m_primary_vbounds.second))
+ {
+ if ((x >= left_divider_right()) && (x < right_divider_left()))
+ {
+ // main list
+ if (m_skip_main_items && (y >= (m_primary_items_top + ((float(m_primary_lines) + ((item(m_available_items).type() == menu_item_type::SEPARATOR) ? 0.5F : 0.0F)) * line_height()))))
+ {
+ if (selected_index() < m_available_items)
{
- inkey_dats();
- stop = true;
+ m_prev_selected = get_selection_ref();
+ set_selected_index(m_available_items + 1);
}
- else if (hover() >= HOVER_RP_FIRST && hover() <= HOVER_RP_LAST)
+ }
+ else
+ {
+ if ((get_focus() != focused_menu::MAIN) || (selected_index() > m_available_items))
+ select_prev();
+ }
+ set_focus(focused_menu::MAIN);
+ }
+ else if ((x >= left_panel_left()) && (x < left_panel_right()))
+ {
+ // left panel
+ assert(show_left_panel());
+ if ((get_focus() == focused_menu::MAIN) && (selected_index() <= m_available_items))
+ m_prev_selected = get_selection_ref();
+ set_focus(focused_menu::LEFT);
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ else if ((x >= right_panel_left()) && (x < right_panel_right()))
+ {
+ // right panel
+ assert(show_right_panel());
+ if ((get_focus() == focused_menu::MAIN) && (selected_index() <= m_available_items))
+ m_prev_selected = get_selection_ref();
+ set_focus((y < m_right_tabs_bottom) ? focused_menu::RIGHTTOP : focused_menu::RIGHTBOTTOM);
+ return std::make_tuple(IPT_INVALID, true, true);
+ }
+ }
+
+ return std::make_tuple(IPT_INVALID, false, false);
+}
+
+
+//-------------------------------------------------
+// track click on main item
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_main_track_line(bool changed, ui_event const &uievt)
+{
+ auto const [x, y] = pointer_location();
+ float const itemtop(m_primary_items_top + (float(m_clicked_line) * line_height()));
+ float const itembottom(m_primary_items_top + (float(m_clicked_line + 1) * line_height()));
+ int key(IPT_INVALID);
+ bool redraw(false);
+
+ if (is_main_up_arrow(m_clicked_line) || is_main_down_arrow(m_clicked_line))
+ {
+ // top or bottom line is a scroll arrow
+ bool const reentered(reentered_rect(m_last_pointer.first, m_last_pointer.second, x, y, m_primary_items_hbounds.first, itemtop, m_primary_items_hbounds.second, itembottom));
+ if (reentered)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ if (now >= m_scroll_repeat)
+ {
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ if (!m_clicked_line)
{
- ui_globals::rpanel = (HOVER_RP_FIRST - hover()) * (-1);
- stop = true;
+ --top_line;
+ if (main_at_top())
+ m_pointer_action = pointer_action::NONE;
}
- else if (hover() >= HOVER_FILTER_FIRST && hover() <= HOVER_FILTER_LAST)
+ else
{
- m_prev_selected = nullptr;
- m_filter_highlight = hover() - HOVER_FILTER_FIRST;
- filter_selected();
- stop = true;
+ ++top_line;
+ if (main_at_bottom())
+ m_pointer_action = pointer_action::NONE;
}
+ if (main_force_visible_selection())
+ key = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ redraw = true;
}
- break;
-
- // if we are hovering over a valid item, fake a UI_SELECT with a double-click
- case ui_event::type::MOUSE_DOUBLE_CLICK:
- if (hover() >= 0 && hover() < item_count())
+ }
+ }
+ else
+ {
+ // check for conversion to touch scroll
+ if (ui_event::pointer::TOUCH == uievt.pointer_type)
+ {
+ auto const [h, v] = check_drag_conversion(x, y, m_base_pointer.first, m_base_pointer.second, line_height());
+ if (h || (v && (m_clicked_line >= m_primary_lines)))
+ {
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, false, true);
+ }
+ else if (v)
{
- set_selected_index(hover());
- ev.iptkey = IPT_UI_SELECT;
+ m_pointer_action = pointer_action::MAIN_DRAG;
+ m_last_pointer = m_base_pointer;
+ m_clicked_line = top_line;
+ return update_main_drag(changed, uievt);
}
+ }
- if (is_last_selected())
+ // check to see if they released over the item
+ if (uievt.pointer_released & 0x01)
+ {
+ m_pointer_action = pointer_action::NONE;
+ if ((0 < uievt.pointer_clicks) || ((x >= m_primary_items_hbounds.first) && (x < m_primary_items_hbounds.second) && (y >= itemtop) && (y < itembottom)))
{
- ev.iptkey = IPT_UI_CANCEL;
- stack_pop();
+ if (m_clicked_line < m_visible_lines)
+ {
+ // systems or software items are always selectable
+ if (2 == uievt.pointer_clicks)
+ key = IPT_UI_SELECT;
+ else if (selected_index() != (m_clicked_line + top_line))
+ key = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ set_selected_index(m_clicked_line + top_line);
+ set_focus(focused_menu::MAIN);
+ }
+ else if ((m_clicked_line >= m_primary_lines) && (m_clicked_line < (m_primary_lines + m_skip_main_items)))
+ {
+ // need to ensure this is a selectable item
+ int const itemnum(m_available_items + m_clicked_line - m_primary_lines);
+ if (is_selectable(item(itemnum)))
+ {
+ if (selected_index() < m_available_items)
+ m_prev_selected = get_selection_ref();
+ set_selected_index(itemnum);
+ set_focus(focused_menu::MAIN);
+ if (2 == uievt.pointer_clicks)
+ key = IPT_UI_SELECT;
+ }
+ }
}
- stop = true;
- break;
+ return std::make_tuple(key, false, true);
+ }
+ }
- // caught scroll event
- case ui_event::type::MOUSE_WHEEL:
- if (hover() >= 0 && hover() < item_count() - skip_main_items - 1)
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ if (pointer_action::NONE != m_pointer_action)
+ m_last_pointer = std::make_pair(x, y);
+ return std::make_tuple(key, pointer_action::NONE != m_pointer_action, redraw);
+}
+
+
+//-------------------------------------------------
+// track right click
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_main_track_rbutton(bool changed, ui_event const &uievt)
+{
+ // see if it was released inside the line
+ if (uievt.pointer_released & 0x02)
+ {
+ m_pointer_action = pointer_action::NONE;
+ auto const [x, y] = pointer_location();
+ float const linetop(m_primary_items_top + (float(m_clicked_line) * line_height()));
+ float const linebottom(m_primary_items_top + (float(m_clicked_line + 1) * line_height()));
+ if ((x >= m_primary_items_hbounds.first) && (x < m_primary_items_hbounds.second) && (y >= linetop) && (y < linebottom))
+ {
+ show_config_menu(m_clicked_line + top_line);
+ return std::make_tuple(IPT_CUSTOM, false, false); // return IPT_CUSTOM to stop processing events
+ }
+ }
+
+ // stop tracking if another button is pressed
+ if (uievt.pointer_pressed & ~u32(0x02))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, pointer_action::DIVIDER_TRACK != m_pointer_action);
+}
+
+
+//-------------------------------------------------
+// track main touch drag scroll
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_main_drag(bool changed, ui_event const &uievt)
+{
+ auto const newtop(drag_scroll(
+ pointer_location().second, m_base_pointer.second, m_last_pointer.second, -line_height(),
+ m_clicked_line, 0, m_available_items - m_primary_lines));
+ bool const moved(newtop != top_line);
+ int key(IPT_INVALID);
+ if (moved)
+ {
+ // scroll and move the selection if necessary to keep it in the visible range
+ top_line = newtop;
+ if (main_force_visible_selection())
+ key = IPT_CUSTOM; // stop processing events so the info pane can be rebuilt
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(key, pointer_action::NONE != m_pointer_action, moved);
+}
+
+
+//-------------------------------------------------
+// track click on left panel item
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_left_track_line(bool changed, ui_event const &uievt)
+{
+ auto const [x, y] = pointer_location();
+ float const itemtop(m_left_items_top + (float(m_clicked_line) * m_info_line_height));
+ float const itembottom(m_left_items_top + (float(m_clicked_line + 1) * m_info_line_height));
+ bool redraw(false);
+
+ if (is_left_up_arrow(m_clicked_line) || is_left_down_arrow(m_clicked_line))
+ {
+ // top or bottom line is a scroll arrow
+ bool const reentered(reentered_rect(m_last_pointer.first, m_last_pointer.second, x, y, m_left_items_hbounds.first, itemtop, m_left_items_hbounds.second, itembottom));
+ if (reentered)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ if (now >= m_scroll_repeat)
{
- if (local_menu_event.zdelta > 0)
+ m_scroll_repeat = now + std::chrono::milliseconds(100);
+ if (!m_clicked_line)
{
- if (selected_index() >= m_available_items || is_first_selected() || m_ui_error)
- break;
- set_selected_index(selected_index() - local_menu_event.num_lines);
- if (selected_index() < top_line + (top_line != 0))
- top_line -= local_menu_event.num_lines;
+ --m_left_visible_top;
+ m_filter_highlight = std::min(m_left_visible_top + m_left_visible_lines - 2, m_filter_highlight);
+ if (left_at_top())
+ m_pointer_action = pointer_action::NONE;
}
else
{
- if (selected_index() >= m_available_items - 1 || m_ui_error)
- break;
- set_selected_index(std::min(selected_index() + local_menu_event.num_lines, m_available_items - 1));
- if (selected_index() >= top_line + m_visible_items + (top_line != 0))
- top_line += local_menu_event.num_lines;
+ ++m_left_visible_top;
+ m_filter_highlight = std::max(m_left_visible_top + 1, m_filter_highlight);
+ if (left_at_bottom())
+ m_pointer_action = pointer_action::NONE;
}
+ redraw = true;
}
- else if (hover() == HOVER_INFO_TEXT)
+ }
+ }
+ else
+ {
+ // check for conversion to touch scroll
+ if (ui_event::pointer::TOUCH == uievt.pointer_type)
+ {
+ auto const [h, v] = check_drag_conversion(x, y, m_base_pointer.first, m_base_pointer.second, m_info_line_height);
+ if (h)
{
- if (local_menu_event.zdelta > 0)
- m_topline_datsview -= local_menu_event.num_lines;
- else
- m_topline_datsview += local_menu_event.num_lines;
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, false, true);
}
- break;
-
- // translate CHAR events into specials
- case ui_event::type::IME_CHAR:
- if (exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_NEXT, 0) || exclusive_input_pressed(ev.iptkey, IPT_UI_FOCUS_PREV, 0))
+ else if (v)
{
- stop = true;
+ m_pointer_action = pointer_action::LEFT_DRAG;
+ m_last_pointer = m_base_pointer;
+ m_clicked_line = m_left_visible_top;
+ return update_left_drag(changed, uievt);
}
- else if (m_ui_error)
+ }
+
+ // this is a filter - check to see if they released over the item
+ if ((uievt.pointer_released & 0x01) && (x >= m_left_items_hbounds.first) && (x < m_left_items_hbounds.second) && (y >= itemtop) && (y < itembottom))
+ {
+ m_pointer_action = pointer_action::NONE;
+ filter_selected(m_left_visible_top + m_clicked_line);
+ return std::make_tuple(IPT_CUSTOM, false, true); // return IPT_CUSTOM to stop processing events
+ }
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ if (pointer_action::NONE != m_pointer_action)
+ m_last_pointer = std::make_pair(x, y);
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, redraw);
+}
+
+
+//-------------------------------------------------
+// track left panel touch drag scroll
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_left_drag(bool changed, ui_event const &uievt)
+{
+ auto const newtop(drag_scroll(
+ pointer_location().second, m_base_pointer.second, m_last_pointer.second, -m_info_line_height,
+ m_clicked_line, 0, m_left_item_count - m_left_visible_lines));
+ bool const moved(newtop != m_left_visible_top);
+ if (moved)
+ {
+ // scroll and move the selection if necessary to keep it in the visible range
+ m_left_visible_top = newtop;
+ int const first(left_at_top() ? 0 : (newtop + 1));
+ int const last(newtop + m_left_visible_lines - (left_at_bottom() ? 1 : 2));
+ m_filter_highlight = std::clamp(m_filter_highlight, first, last);
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, moved);
+}
+
+
+//-------------------------------------------------
+// track click on right panel tab
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_right_track_tab(bool changed, ui_event const &uievt)
+{
+ // see if it was released inside the divider
+ if (uievt.pointer_released & 0x01)
+ {
+ m_pointer_action = pointer_action::NONE;
+ auto const [x, y] = pointer_location();
+ float const left(right_panel_left() + (float(m_clicked_line) * right_tab_width()));
+ float const right(right_panel_left() + (float(m_clicked_line + 1) * right_tab_width()));
+ if ((x >= left) && (x < right) && (y >= m_primary_vbounds.first) && (y < m_right_tabs_bottom))
+ {
+ m_right_panel = m_clicked_line;
+ return std::make_tuple(IPT_CUSTOM, false, true); // return IPT_CUSTOM to stop processing events
+ }
+ }
+
+ // stop tracking if another button is pressed
+ if (uievt.pointer_pressed & ~u32(0x01))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, pointer_action::DIVIDER_TRACK != m_pointer_action);
+}
+
+
+//-------------------------------------------------
+// track right panel heading left/right arrows
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_right_track_arrow(bool changed, ui_event const &uievt)
+{
+ auto const [x, y] = pointer_location();
+ float const left(m_clicked_line ? (m_right_content_hbounds.second - lr_border() - lr_arrow_width()) : (m_right_content_hbounds.first + lr_border()));
+ float const right(m_clicked_line ? (m_right_content_hbounds.second - lr_border()) : (m_right_content_hbounds.first + lr_border() + lr_arrow_width()));
+
+ // check for reentry
+ bool redraw(false);
+ bool const reentered(reentered_rect(m_last_pointer.first, m_last_pointer.second, x, y, left, right_arrows_top(), right, right_arrows_bottom()));
+ if (reentered)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ if (now >= m_scroll_repeat)
+ {
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);
+ bool notend;
+ std::tie(redraw, notend) = m_clicked_line ? next_right_panel_view() : previous_right_panel_view();
+ if (!notend)
+ m_pointer_action = pointer_action::NONE;
+ }
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ if (pointer_action::NONE != m_pointer_action)
+ m_last_pointer = std::make_pair(x, y);
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, redraw);
+}
+
+
+//-------------------------------------------------
+// track right scroll arrows
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_right_track_line(bool changed, ui_event const &uievt)
+{
+ auto const [x, y] = pointer_location();
+ float const itemtop(m_right_content_vbounds.first + (float(m_clicked_line) * m_info_line_height));
+ float const itembottom(m_right_content_vbounds.first + (float(m_clicked_line + 1) * m_info_line_height));
+ bool redraw(false);
+
+ bool const reentered(reentered_rect(m_last_pointer.first, m_last_pointer.second, x, y, m_right_content_hbounds.first, itemtop, m_right_content_hbounds.second, itembottom));
+ if (reentered)
+ {
+ auto const now(std::chrono::steady_clock::now());
+ if (now >= m_scroll_repeat)
+ {
+ m_scroll_repeat = std::chrono::steady_clock::now() + std::chrono::milliseconds(100);
+ if (!m_clicked_line)
{
- ev.iptkey = IPT_SPECIAL;
- stop = true;
+ --m_topline_datsview;
+ if (info_at_top())
+ m_pointer_action = pointer_action::NONE;
}
- else if (accept_search())
+ else
{
- if (input_character(m_search, local_menu_event.ch, uchar_is_printable))
- search_changed = true;
+ ++m_topline_datsview;
+ if (info_at_bottom())
+ m_pointer_action = pointer_action::NONE;
}
- break;
+ redraw = true;
+ }
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ if (pointer_action::NONE != m_pointer_action)
+ m_last_pointer = std::make_pair(x, y);
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, redraw);
+}
+
- case ui_event::type::MOUSE_RDOWN:
- if (hover() >= 0 && hover() < item_count() - skip_main_items - 1)
+//-------------------------------------------------
+// track panel heading touch drag switch
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_right_switch(bool changed, ui_event const &uievt)
+{
+ // get new page
+ ui_software_info const *software;
+ ui_system_info const *system;
+ get_selection(software, system);
+ int const min((RP_IMAGES == m_right_panel) ? FIRST_VIEW : 0);
+ int const max(
+ (RP_IMAGES == m_right_panel) ? LAST_VIEW :
+ (software && !software->startempty) ? (ui_globals::cur_sw_dats_total - 1) :
+ (system || (software && software->driver)) ? (ui_globals::curdats_total - 1) :
+ 0);
+ auto const newpage(drag_scroll(
+ pointer_location().first, m_base_pointer.first, m_last_pointer.first, 0.125F * (m_right_content_hbounds.first - m_right_content_hbounds.second),
+ m_clicked_line, min, max));
+
+ // switch page
+ u8 dummy(newpage);
+ u8 &current(
+ (RP_IMAGES == m_right_panel) ? m_image_view :
+ (software && !software->startempty) ? ui_globals::cur_sw_dats_view :
+ (system || (software && software->driver)) ? ui_globals::curdats_view :
+ dummy);
+ bool const redraw(newpage != current);
+ if (redraw)
+ {
+ current = newpage;
+ if (RP_IMAGES == m_right_panel)
+ set_switch_image();
+ else
+ m_topline_datsview = 0;
+ }
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, redraw);
+}
+
+
+//-------------------------------------------------
+// track right panel touch drag scroll
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_right_drag(bool changed, ui_event const &uievt)
+{
+ auto const newtop(drag_scroll(
+ pointer_location().second, m_base_pointer.second, m_last_pointer.second, -m_info_line_height,
+ m_clicked_line, 0, m_total_lines - m_right_visible_lines));
+ bool const moved(newtop != m_topline_datsview);
+ m_topline_datsview = newtop;
+
+ // stop tracking if the primary button is released or another button is pressed
+ if ((uievt.pointer_released & 0x01) || (uievt.pointer_pressed & ~u32(0x01)))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, moved);
+}
+
+
+//-------------------------------------------------
+// track click on toolbar button
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_toolbar_track(bool changed, ui_event const &uievt)
+{
+ // see if it was released inside the button
+ if (uievt.pointer_released & 0x01)
+ {
+ m_pointer_action = pointer_action::NONE;
+ auto const [x, y] = pointer_location();
+ float const left((0 > m_clicked_line) ? m_toolbar_backtrack_left : (m_toolbar_main_left + (float(m_clicked_line) * m_toolbar_button_spacing)));
+ if ((x >= left) && (x < (left + m_toolbar_button_width)) && (y >= m_toolbar_button_vbounds.first) && (y < m_toolbar_button_vbounds.second))
+ {
+ if (0 > m_clicked_line)
{
- set_selected_index(hover());
- m_prev_selected = get_selection_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;
+ // backtrack button
+ stack_pop();
+ if (is_special_main_menu())
+ machine().schedule_exit();
+ return std::make_tuple(IPT_UI_BACK, false, true);
+ }
+ else
+ {
+ // main buttons
+ auto const *const toolbar_bitmaps(m_is_swlist ? SW_TOOLBAR_BITMAPS : SYS_TOOLBAR_BITMAPS);
+ auto const [bitmap, action, need_selection] = toolbar_bitmaps[m_clicked_line];
+ switch (action)
+ {
+ case IPT_UI_EXPORT:
+ inkey_export();
+ break;
+ case IPT_UI_DATS:
+ inkey_dats();
+ break;
+ default:
+ return std::make_tuple(action, false, true);
+ }
+ return std::make_tuple(IPT_CUSTOM, false, true); // return IPT_CUSTOM to stop processing events
}
- break;
-
- // ignore everything else
- default:
- break;
}
+ }
- // need to update search before processing certain kinds of events, but others don't matter
- if (search_changed)
+ // stop tracking if another button is pressed
+ if (uievt.pointer_pressed & ~u32(0x01))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, pointer_action::TOOLBAR_TRACK != m_pointer_action);
+}
+
+
+//-------------------------------------------------
+// track click on divider
+//-------------------------------------------------
+
+std::tuple<int, bool, bool> menu_select_launch::update_divider_track(bool changed, ui_event const &uievt)
+{
+ // see if it was released inside the divider
+ if (uievt.pointer_released & 0x01)
+ {
+ m_pointer_action = pointer_action::NONE;
+ auto const [x, y] = pointer_location();
+ float const left(m_clicked_line ? right_divider_left() : left_divider_left());
+ float const right(m_clicked_line ? right_divider_right() : left_divider_right());
+ if ((x >= left) && (x < right) && (y >= m_primary_vbounds.first) && (y < m_primary_vbounds.second))
{
- switch (machine().ui_input().peek_event_type())
+ if (m_clicked_line)
{
- case ui_event::type::MOUSE_DOWN:
- case ui_event::type::MOUSE_RDOWN:
- case ui_event::type::MOUSE_DOUBLE_CLICK:
- case ui_event::type::MOUSE_WHEEL:
- stop = true;
- break;
- case ui_event::type::NONE:
- case ui_event::type::WINDOW_FOCUS:
- case ui_event::type::WINDOW_DEFOCUS:
- case ui_event::type::MOUSE_MOVE:
- case ui_event::type::MOUSE_LEAVE:
- case ui_event::type::MOUSE_UP:
- case ui_event::type::MOUSE_RUP:
- case ui_event::type::IME_CHAR:
- break;
+ if ((get_focus() == focused_menu::RIGHTTOP) || (get_focus() == focused_menu::RIGHTBOTTOM))
+ {
+ set_focus(focused_menu::MAIN);
+ select_prev();
+ }
+ m_panels_status ^= HIDE_RIGHT_PANEL;
}
+ else
+ {
+ if (get_focus() == focused_menu::LEFT)
+ {
+ set_focus(focused_menu::MAIN);
+ select_prev();
+ }
+ m_panels_status ^= HIDE_LEFT_PANEL;
+ }
+ return std::make_tuple(IPT_CUSTOM, false, true); // return IPT_CUSTOM to stop processing events
}
}
- if (search_changed)
- reset(reset_options::SELECT_FIRST);
+
+ // stop tracking if another button is pressed
+ if (uievt.pointer_pressed & ~u32(0x01))
+ m_pointer_action = pointer_action::NONE;
+ return std::make_tuple(IPT_INVALID, pointer_action::NONE != m_pointer_action, pointer_action::DIVIDER_TRACK != m_pointer_action);
}
//-------------------------------------------------
-// draw main menu
+// move selection to visible range
//-------------------------------------------------
-void menu_select_launch::draw(uint32_t flags)
+bool menu_select_launch::main_force_visible_selection()
{
- bool noinput = (flags & PROCESS_NOINPUT);
- float const aspect = machine().render().ui_aspect(&container());
- float const lr_border = ui().box_lr_border() * aspect;
- float line_height = ui().get_line_height();
- float const ud_arrow_width = line_height * aspect;
- float const gutter_width = 0.52f * ud_arrow_width;
- float const icon_offset = m_has_icons ? (1.5f * ud_arrow_width) : 0.0f;
- float right_panel_size = (ui_globals::panels_status == HIDE_BOTH || ui_globals::panels_status == HIDE_RIGHT_PANEL) ? 2.0f * lr_border : 0.3f;
- float visible_width = 1.0f - 4.0f * lr_border;
- float primary_left = (1.0f - visible_width) * 0.5f;
- float primary_width = visible_width;
+ int const first(main_at_top() ? 0 : (top_line + 1));
+ int const last(top_line + m_primary_lines - (main_at_bottom() ? 1 : 2));
+ if (selected_index() < m_available_items)
+ {
+ int const restricted(std::clamp(selected_index(), first, last));
+ if (selected_index() != restricted)
+ {
+ set_selected_index(restricted);
+ return true;
+ }
+ }
+ else
+ {
+ int selection(0);
+ while ((m_available_items > selection) && (item(selection).ref() != m_prev_selected))
+ ++selection;
+ auto const ref(item(std::clamp(selection, first, last)).ref());
+ if (ref != m_prev_selected)
+ {
+ m_prev_selected = ref;
+ return true;
+ }
+ }
+ return false;
+}
- draw_background();
- clear_hover();
- m_available_items = (m_is_swlist) ? item_count() - 2 : item_count() - 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 = get_customtop() + get_custombottom() + extra_height;
+//-------------------------------------------------
+// draw main menu
+//-------------------------------------------------
- // locate mouse
- if (noinput)
- ignore_mouse();
- else
- map_mouse();
+void menu_select_launch::draw(u32 flags)
+{
- // 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;
+ // recompute height of primary menu area if necessary
+ if (m_primary_vbounds.first >= m_primary_vbounds.second)
+ {
+ float const pixelheight(target_size().second);
+ float const lines(std::floor((1.0F - (4.0F * tb_border()) - get_customtop() - get_custombottom()) / line_height()));
+ float const itemsheight(line_height() * lines);
+ float const space(1.0F - itemsheight - get_customtop() - get_custombottom());
+ m_primary_items_top = std::round((get_customtop() + (0.5F * space)) * pixelheight) / pixelheight;
+ m_primary_vbounds = std::make_pair(m_primary_items_top - tb_border(), m_primary_items_top + itemsheight + tb_border());
+ m_primary_lines = int(lines) - m_skip_main_items;
+ }
- if (!m_is_swlist)
- ui_globals::visible_main_lines = m_visible_lines;
+ // ensure the selection is visible
+ m_available_items = item_count() - m_skip_main_items;
+ m_visible_lines = (std::min)(m_primary_lines, m_available_items);
+ int selection;
+ if (selected_index() < m_available_items)
+ {
+ selection = selected_index();
+ }
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 += get_customtop();
-
- // compute left box size
- float x1 = visible_left - lr_border;
- float y1 = visible_top - ui().box_tb_border();
- float x2 = x1 + 2.0f * 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 * lr_border;
-
- // compute and add main box
- x1 = visible_left - lr_border;
- x2 = visible_left + visible_width + lr_border;
- float line = visible_top + (float(m_visible_lines) * line_height);
- ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
-
- if (m_available_items < m_visible_lines)
- m_visible_lines = m_available_items;
- if (top_line < 0 || is_first_selected())
+ {
+ selection = 0;
+ while ((m_available_items > selection) && (item(selection).ref() != m_prev_selected))
+ ++selection;
+ }
+ if (top_line < 0 || !selection)
+ {
top_line = 0;
- if (selected_index() < m_available_items && top_line + m_visible_lines >= m_available_items)
- top_line = m_available_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;
-
+ }
+ else if (selection < m_available_items)
+ {
+ if ((selection >= (top_line + m_visible_lines)) || (selection <= top_line))
+ top_line = (std::max)(selection - (m_visible_lines / 2), 0);
+ if ((top_line + m_visible_lines) >= m_available_items)
+ top_line = m_available_items - m_visible_lines;
+ else if (selection >= (top_line + m_visible_lines - 2))
+ top_line = selection - m_visible_lines + ((selection == (m_available_items - 1)) ? 1: 2);
+ }
if ((m_focus == focused_menu::MAIN) && (selected_index() < m_available_items))
m_prev_selected = nullptr;
- int const n_loop = (std::min)(m_visible_lines, m_available_items);
- for (int linenum = 0; linenum < n_loop; linenum++)
+ // draw background, left and right panels, and outline of main box
+ draw_background();
+ draw_left_panel(flags);
+ draw_right_panel(flags);
+ ui().draw_outlined_box(
+ container(),
+ left_divider_right(), m_primary_vbounds.first, right_divider_left(), m_primary_vbounds.second,
+ ui().colors().background_color());
+
+ // calculate horizontal geometry of main item list
+ m_primary_items_hbounds = std::make_pair(left_divider_right() + lr_border(), right_divider_left() - lr_border());
+ float const item_text_left(m_primary_items_hbounds.first + gutter_width());
+ float const item_text_width(m_primary_items_hbounds.second - m_primary_items_hbounds.first - (2.0F * gutter_width()));
+ float const icon_offset(m_has_icons ? (1.5F * ud_arrow_width()) : 0.0F);
+
+ // draw main scrolling items
+ for (int linenum = 0; linenum < m_visible_lines; linenum++)
{
- float line_y = visible_top + (float)linenum * line_height;
- int itemnum = top_line + linenum;
- const menu_item &pitem = item(itemnum);
- const std::string_view itemtext = pitem.text;
+ int const itemnum(top_line + linenum);
+ menu_item const &pitem(item(itemnum));
+ std::string_view const itemtext(pitem.text());
+ float const linetop(m_primary_items_top + (float(linenum) * line_height()));
+ float const linebottom(linetop + line_height());
+
+ // work out colours
rgb_t fgcolor = ui().colors().text_color();
rgb_t bgcolor = ui().colors().text_bg_color();
rgb_t fgcolor3 = ui().colors().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_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
- set_hover(itemnum);
-
- if (is_selected(itemnum) && m_focus == focused_menu::MAIN)
+ bool const hovered(is_selectable(pitem) && pointer_in_rect(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom));
+ bool const pointerline((pointer_action::MAIN_TRACK_LINE == m_pointer_action) && (linenum == m_clicked_line));
+ bool const rclickline((pointer_action::MAIN_TRACK_RBUTTON == m_pointer_action) && (linenum == m_clicked_line));
+ if (!rclickline && is_selected(itemnum) && (get_focus() == focused_menu::MAIN))
{
// if we're selected, draw with a different background
fgcolor = rgb_t(0xff, 0xff, 0x00);
@@ -1972,167 +3261,177 @@ void menu_select_launch::draw(uint32_t flags)
fgcolor3 = rgb_t(0xcc, 0xcc, 0x00);
ui().draw_textured_box(
container(),
- line_x0 + 0.01f, line_y0, line_x1 - 0.01f, line_y1,
+ m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom,
bgcolor, rgb_t(43, 43, 43),
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
- else if (itemnum == hover())
+ else if ((pointerline || rclickline) && hovered)
{
- // else if the mouse is over this item, draw with a different background
- fgcolor = fgcolor3 = ui().options().mouseover_color();
+ // draw selected highlight for tracked item
+ fgcolor = fgcolor3 = ui().colors().selected_color();
+ bgcolor = ui().colors().selected_bg_color();
+ highlight(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom, bgcolor);
+ }
+ else if (pointerline || rclickline || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered && pointer_idle()))
+ {
+ // draw hover highlight when hovered over or dragged off
+ fgcolor = fgcolor3 = ui().colors().mouseover_color();
bgcolor = ui().colors().mouseover_bg_color();
- highlight(line_x0, line_y0, line_x1, line_y1, bgcolor);
+ highlight(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom, bgcolor);
}
- else if (pitem.ref == m_prev_selected)
+ else if (pitem.ref() == m_prev_selected)
{
- fgcolor = fgcolor3 = ui().options().mouseover_color();
+ fgcolor = fgcolor3 = ui().colors().mouseover_color();
bgcolor = ui().colors().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),
+ ui().draw_textured_box(
+ container(),
+ m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom,
+ bgcolor, rgb_t(43, 43, 43),
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
- if (linenum == 0 && top_line != 0)
+ if ((!linenum && top_line) || ((linenum == (m_visible_lines - 1)) && (itemnum != m_available_items - 1)))
{
- // if we're on the top line, display the up arrow
- draw_arrow(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)
- set_hover(HOVER_ARROW_UP);
- }
- else if (linenum == m_visible_lines - 1 && itemnum != m_available_items - 1)
- {
- // if we're on the bottom line, display the down arrow
- draw_arrow(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)
- set_hover(HOVER_ARROW_DOWN);
+ // if we're on the top or bottom line, display the up or down arrow
+ draw_arrow(
+ 0.5F * (m_primary_items_hbounds.first + m_primary_items_hbounds.second - ud_arrow_width()), linetop + (0.25F * line_height()),
+ 0.5F * (m_primary_items_hbounds.first + m_primary_items_hbounds.second + ud_arrow_width()), linetop + (0.75F * line_height()),
+ fgcolor,
+ linenum ? (ROT0 ^ ORIENTATION_FLIP_Y) : ROT0);
}
- else if (pitem.type == menu_item_type::SEPARATOR)
+ 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,
+ container().add_line(
+ m_primary_items_hbounds.first, linetop + (0.5F * line_height()),
+ m_primary_items_hbounds.second, linetop + (0.5F * line_height()),
UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
}
- else if (pitem.subtext.empty())
- {
- // draw the item centered
- int const item_invert = pitem.flags & FLAG_INVERT;
- if (m_has_icons)
- draw_icon(linenum, item(itemnum).ref, effective_left, line_y);
- ui().draw_text_full(
- container(),
- itemtext,
- effective_left + icon_offset, line_y, effective_width - icon_offset,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
- nullptr, nullptr);
- }
else
{
- int const item_invert = pitem.flags & FLAG_INVERT;
- std::string_view const subitem_text = pitem.subtext;
- float item_width, subitem_width;
-
- // compute right space for subitem
- ui().draw_text_full(
- container(),
- subitem_text,
- effective_left + icon_offset, line_y, ui().get_string_width(pitem.subtext),
- 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
+ bool const item_invert(pitem.flags() & FLAG_INVERT);
if (m_has_icons)
- draw_icon(linenum, item(itemnum).ref, effective_left, line_y);
- ui().draw_text_full(
- container(),
- itemtext,
- effective_left + icon_offset, line_y, effective_width - icon_offset - 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 + icon_offset + item_width, line_y, effective_width - icon_offset - item_width,
- ui::text_layout::RIGHT, ui::text_layout::NEVER,
- mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
- nullptr, nullptr);
+ draw_icon(linenum, pitem.ref(), item_text_left, linetop);
+ if (pitem.subtext().empty())
+ {
+ // draw the item left-aligned
+ ui().draw_text_full(
+ container(),
+ itemtext,
+ item_text_left + icon_offset, linetop, item_text_width - icon_offset,
+ text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE,
+ mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
+ nullptr, nullptr,
+ line_height());
+ }
+ else
+ {
+ // compute right space for subitem
+ std::string_view const subitem_text(pitem.subtext());
+ float const subitem_width(get_string_width(subitem_text) + gutter_width());
+
+ // draw the item left-aligned
+ float item_width;
+ ui().draw_text_full(
+ container(),
+ itemtext,
+ item_text_left + icon_offset, linetop, item_text_width - icon_offset - subitem_width,
+ text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE,
+ mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
+ &item_width, nullptr,
+ line_height());
+
+ // draw the subitem right-aligned
+ ui().draw_text_full(
+ container(),
+ subitem_text,
+ item_text_left + icon_offset + item_width, linetop, item_text_width - icon_offset - item_width,
+ text_layout::text_justify::RIGHT, text_layout::word_wrapping::NEVER,
+ mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor,
+ nullptr, nullptr,
+ line_height());
+ }
}
}
- for (size_t count = m_available_items; count < item_count(); count++)
+ // draw extra fixed items
+ for (size_t linenum = 0; linenum < m_skip_main_items; linenum++)
{
- const menu_item &pitem = item(count);
- const std::string_view 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;
+ int const itemnum(m_available_items + linenum);
+ menu_item const &pitem(item(itemnum));
+ std::string_view const itemtext(pitem.text());
+ float const linetop(m_primary_items_top + (float(m_primary_lines + linenum) * line_height()));
+ float const linebottom(linetop + line_height());
+
+ // work out colours
rgb_t fgcolor = ui().colors().text_color();
rgb_t bgcolor = ui().colors().text_bg_color();
-
- if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem))
- set_hover(count);
-
- // if we're selected, draw with a different background
- if (is_selected(count) && m_focus == focused_menu::MAIN)
+ bool const hovered(is_selectable(pitem) && pointer_in_rect(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom));
+ bool const pointerline((pointer_action::MAIN_TRACK_LINE == m_pointer_action) && ((m_primary_lines + linenum) == m_clicked_line));
+ if (is_selected(itemnum) && (get_focus() == focused_menu::MAIN))
{
+ // if we're selected, draw with a different background
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),
+ ui().draw_textured_box(
+ container(),
+ m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom,
+ bgcolor, rgb_t(43, 43, 43),
hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
}
- // else if the mouse is over this item, draw with a different background
- else if (count == hover())
+ else if (pointerline && hovered)
{
- fgcolor = ui().options().mouseover_color();
+ // draw selected highlight for tracked item
+ fgcolor = ui().colors().selected_color();
+ bgcolor = ui().colors().selected_bg_color();
+ highlight(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom, bgcolor);
+ }
+ else if (pointerline || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered && pointer_idle()))
+ {
+ // draw hover highlight when hovered over or dragged off
+ fgcolor = ui().colors().mouseover_color();
bgcolor = ui().colors().mouseover_bg_color();
- highlight(line_x0, line_y0, line_x1, line_y1, bgcolor);
+ highlight(m_primary_items_hbounds.first, linetop, m_primary_items_hbounds.second, linebottom, bgcolor);
}
- if (pitem.type == menu_item_type::SEPARATOR)
+ 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,
+ // if we're just a divider, draw a line
+ container().add_line(
+ m_primary_items_hbounds.first, linetop + (0.5F * line_height()),
+ m_primary_items_hbounds.second, linetop + (0.5F * line_height()),
UI_LINE_WIDTH, ui().colors().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);
+ // draw the item centred
+ ui().draw_text_full(
+ container(),
+ itemtext,
+ item_text_left, linetop, item_text_width,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE,
+ mame_ui_manager::NORMAL, fgcolor, bgcolor,
+ nullptr, nullptr,
+ line_height());
}
- line += line_height;
}
- x1 = x2;
- x2 += right_panel_size;
-
- draw_right_panel(x1, y1, x2, y2);
-
- x1 = primary_left - lr_border;
- x2 = primary_left + primary_width + lr_border;
-
// if there is something special to add, do it by calling the virtual method
- custom_render(get_selection_ref(), get_customtop(), get_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 != m_available_items);
+ custom_render(
+ flags,
+ get_selection_ref(),
+ get_customtop(), get_custombottom(),
+ lr_border(), m_primary_vbounds.first, 1.0F - lr_border(), m_primary_vbounds.second);
- // noinput
- if (noinput)
+ // show error text if necessary
+ if (m_ui_error)
{
- 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));
+ container().add_rect(0.0F, 0.0F, 1.0F, 1.0F, rgb_t(114, 0, 0, 0), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ ui().draw_text_box(container(), m_error_text, text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR);
}
+
+ // 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 != m_available_items);
}
@@ -2140,115 +3439,197 @@ void menu_select_launch::draw(uint32_t flags)
// draw right panel
//-------------------------------------------------
-void menu_select_launch::draw_right_panel(float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::draw_right_panel(u32 flags)
{
- float const aspect(machine().render().ui_aspect(&container()));
- bool const hide((ui_globals::panels_status == HIDE_RIGHT_PANEL) || (ui_globals::panels_status == HIDE_BOTH));
- float const x2(hide ? origx2 : (origx1 + 2.0f * ui().box_lr_border() * aspect));
- float const space(x2 - origx1);
- float const lr_arrow_width(0.4f * space * aspect);
+ if (show_right_panel())
+ {
+ m_right_panel_width = 0.3F - m_divider_width;
- // set left-right arrows dimension
- float const ar_x0(0.5f * (x2 + origx1) - 0.5f * lr_arrow_width);
- float const ar_y0(0.5f * (origy2 + origy1) + 0.1f * space);
- float const ar_x1(ar_x0 + lr_arrow_width);
- float const ar_y1(0.5f * (origy2 + origy1) + 0.9f * space);
+ ui().draw_outlined_box(
+ container(), right_panel_left(), m_primary_vbounds.first, right_panel_right(), m_primary_vbounds.second,
+ ui().colors().background_color());
+ draw_right_box_tabs(flags);
- ui().draw_outlined_box(container(), origx1, origy1, origx2, origy2, rgb_t(0xEF, 0x12, 0x47, 0x7B));
+ if (0.0F >= m_right_heading_top)
+ {
+ float const pixelheight(target_size().second);
+ m_right_heading_top = std::round((m_right_tabs_bottom + UI_LINE_WIDTH + tb_border()) * pixelheight) / pixelheight;
+ m_right_content_vbounds = std::make_pair(
+ std::round((m_right_heading_top + line_height() + tb_border()) * pixelheight) / pixelheight,
+ m_primary_vbounds.second - tb_border());
+ m_right_content_hbounds = std::make_pair(right_panel_left() + lr_border(), right_panel_right() - lr_border());
+ }
- rgb_t fgcolor(ui().colors().text_color());
- if (mouse_in_rect(origx1, origy1, x2, origy2))
- {
- fgcolor = ui().options().mouseover_color();
- set_hover(HOVER_RPANEL_ARROW);
+ if (m_right_panel == RP_IMAGES)
+ arts_render(flags);
+ else
+ infos_render(flags);
}
-
- if (hide)
+ else
{
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90 ^ ORIENTATION_FLIP_X);
- return;
+ m_right_panel_width = 0.0F;
}
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90);
- origy1 = draw_right_box_title(x2, origy1, origx2, origy2);
-
- if (ui_globals::rpanel == RP_IMAGES)
- arts_render(x2, origy1, origx2, origy2);
- else
- infos_render(x2, origy1, origx2, origy2);
+ draw_divider(flags, 1.0F - lr_border() - m_right_panel_width - m_divider_width, true);
}
//-------------------------------------------------
-// draw right box title
+// draw right box tabs
//-------------------------------------------------
-float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, float y2)
+void menu_select_launch::draw_right_box_tabs(u32 flags)
{
- auto line_height = ui().get_line_height();
- float const midl = (x2 - x1) * 0.5f;
+ m_right_tabs_bottom = m_primary_vbounds.first + line_height();
- // add outlined box for options
- ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color());
+ float const x1(1.0F - lr_border() - m_right_panel_width);
+ float const x2(1.0F - lr_border());
+ float const tabwidth = right_tab_width();
- // add separator line
- container().add_line(x1 + midl, y1, x1 + midl, y1 + line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
-
- std::string buffer[RP_LAST + 1];
- buffer[RP_IMAGES] = _("Images");
- buffer[RP_INFOS] = _("Infos");
+ std::string const buffer[RP_LAST + 1] = { _(RIGHT_PANEL_NAMES[0].second), _(RIGHT_PANEL_NAMES[1].second) };
// check size
float text_size = 1.0f;
for (auto & elem : buffer)
{
- auto textlen = ui().get_string_width(elem) + 0.01f;
- float tmp_size = (textlen > midl) ? (midl / textlen) : 1.0f;
+ auto textlen = get_string_width(elem) + 0.01f;
+ float tmp_size = (textlen > tabwidth) ? (tabwidth / textlen) : 1.0f;
text_size = std::min(text_size, tmp_size);
}
for (int cells = RP_FIRST; cells <= RP_LAST; ++cells)
{
- rgb_t bgcolor = ui().colors().text_bg_color();
- rgb_t fgcolor = ui().colors().text_color();
+ float const tableft(x1 + (float(cells - RP_FIRST) * tabwidth));
- if (mouse_in_rect(x1, y1, x1 + midl, y1 + line_height))
+ rgb_t fgcolor = ui().colors().text_color();
+ rgb_t bgcolor = ui().colors().text_bg_color();
+ if ((focused_menu::RIGHTTOP == m_focus) && (cells == m_right_panel))
+ {
+ // draw primary highlight if keyboard focus is here
+ fgcolor = rgb_t(0xff, 0xff, 0x00);
+ bgcolor = rgb_t(0xff, 0xff, 0xff);
+ ui().draw_textured_box(
+ container(),
+ tableft + UI_LINE_WIDTH, m_primary_vbounds.first + UI_LINE_WIDTH, tableft + tabwidth - UI_LINE_WIDTH, m_right_tabs_bottom,
+ bgcolor, rgb_t(43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
+ }
+ else if (cells != m_right_panel)
{
- if (ui_globals::rpanel != cells)
+ bool const hovered(pointer_in_rect(tableft, m_primary_vbounds.first, tableft + tabwidth, m_right_tabs_bottom));
+ bool const pointertab((pointer_action::RIGHT_TRACK_TAB == m_pointer_action) && (cells == m_clicked_line));
+ if (pointertab && hovered)
+ {
+ // draw selected highlight for tracked item
+ fgcolor = ui().colors().selected_color();
+ bgcolor = ui().colors().selected_bg_color();
+ highlight(tableft + UI_LINE_WIDTH, m_primary_vbounds.first + UI_LINE_WIDTH, tableft + tabwidth - UI_LINE_WIDTH, m_right_tabs_bottom, bgcolor);
+ }
+ else if (pointertab || (!m_ui_error && !(flags & PROCESS_NOINPUT) && hovered && pointer_idle()))
{
+ // draw hover highlight when hovered over or dragged off
+ fgcolor = ui().colors().mouseover_color();
bgcolor = ui().colors().mouseover_bg_color();
- fgcolor = ui().options().mouseover_color();
- set_hover(HOVER_RP_FIRST + cells);
+ highlight(tableft + UI_LINE_WIDTH, m_primary_vbounds.first + UI_LINE_WIDTH, tableft + tabwidth - UI_LINE_WIDTH, m_right_tabs_bottom, bgcolor);
}
- }
-
- if (ui_globals::rpanel != cells)
- {
- container().add_line(x1, y1 + line_height, x1 + midl, y1 + line_height, UI_LINE_WIDTH,
- ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- if (fgcolor != ui().colors().mouseover_color())
+ else
+ {
+ // dim unselected tab title
fgcolor = ui().colors().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(1));
- }
- else if (bgcolor == ui().colors().mouseover_bg_color())
+ ui().draw_text_full(
+ container(),
+ buffer[cells],
+ tableft + UI_LINE_WIDTH, m_primary_vbounds.first, tabwidth - UI_LINE_WIDTH,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER,
+ mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr,
+ line_height() * text_size);
+
+ // add lines when appropriate
+ if (RP_FIRST < cells)
{
- 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(1));
+ container().add_line(
+ tableft, m_primary_vbounds.first, tableft, m_right_tabs_bottom,
+ UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ if (m_right_panel == cells)
+ {
+ container().add_line(
+ x1, m_primary_vbounds.first + line_height(), tableft, m_right_tabs_bottom,
+ UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
}
+ }
+ if (RP_LAST != m_right_panel)
+ {
+ container().add_line(
+ x1 + (float(m_right_panel + 1) * tabwidth), m_right_tabs_bottom, x2, m_right_tabs_bottom,
+ UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+}
+
+
+//-------------------------------------------------
+// draw right box heading
+//-------------------------------------------------
+
+void menu_select_launch::draw_right_box_heading(u32 flags, bool larrow, bool rarrow, std::string_view text)
+{
+ float const text_left(m_right_content_hbounds.first + (2.0F * lr_border()) + lr_arrow_width());
+ float const text_width(m_right_content_hbounds.second - m_right_content_hbounds.first - (4.0F * lr_border()) - (2.0F * lr_arrow_width()));
+
+ rgb_t fgcolor(ui().colors().text_color());
+ rgb_t bgcolor(ui().colors().text_bg_color());
+ if (pointer_action::RIGHT_SWITCH == m_pointer_action)
+ {
+ // touch swipe to switch
+ fgcolor = ui().colors().selected_color();
+ bgcolor = ui().colors().selected_bg_color();
+ highlight(m_right_content_hbounds.first, m_right_heading_top, m_right_content_hbounds.second, m_right_heading_top + line_height(), bgcolor);
+ }
+ else if (focused_menu::RIGHTBOTTOM == m_focus)
+ {
+ // keyboard focus
+ fgcolor = rgb_t(0xff, 0xff, 0x00);
+ bgcolor = rgb_t(0xff, 0xff, 0xff);
+ ui().draw_textured_box(
+ container(),
+ m_right_content_hbounds.first, m_right_heading_top, m_right_content_hbounds.second, m_right_heading_top + line_height(),
+ bgcolor, rgb_t(43, 43, 43),
+ hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
+ }
- ui().draw_text_full(container(), buffer[cells], 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;
+ ui().draw_text_full(container(),
+ text, text_left, m_right_heading_top, text_width,
+ text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor,
+ nullptr, nullptr,
+ line_height());
+
+ if (larrow)
+ {
+ // not using the selected colour here because the background isn't changed
+ float const left(m_right_content_hbounds.first + lr_border());
+ float const right(m_right_content_hbounds.first + lr_border() + lr_arrow_width());
+ bool const hovered(pointer_in_rect(left, right_arrows_top(), right, right_arrows_bottom()));
+ bool const tracked((pointer_action::RIGHT_TRACK_ARROW == m_pointer_action) && !m_clicked_line);
+ rgb_t fg(fgcolor);
+ if ((focused_menu::RIGHTBOTTOM != m_focus) && (tracked || (!m_ui_error && !(flags & PROCESS_NOINPUT) && pointer_idle() && hovered)))
+ fg = ui().colors().mouseover_color();
+ draw_arrow(left, right_arrows_top(), right, right_arrows_bottom(), fg, ROT90 ^ ORIENTATION_FLIP_X);
}
- return (y1 + line_height + UI_LINE_WIDTH);
+ if (rarrow)
+ {
+ // not using the selected colour here because the background isn't changed
+ float const left(m_right_content_hbounds.second - lr_border() - lr_arrow_width());
+ float const right(m_right_content_hbounds.second - lr_border());
+ bool const hovered(pointer_in_rect(left, right_arrows_top(), right, right_arrows_bottom()));
+ bool const tracked((pointer_action::RIGHT_TRACK_ARROW == m_pointer_action) && m_clicked_line);
+ rgb_t fg(fgcolor);
+ if ((focused_menu::RIGHTBOTTOM != m_focus) && (tracked || (!m_ui_error && !(flags & PROCESS_NOINPUT) && pointer_idle() && hovered)))
+ fg = ui().colors().mouseover_color();
+ draw_arrow(left, right_arrows_top(), right, right_arrows_bottom(), fg, ROT90);
+ }
}
@@ -2256,26 +3637,23 @@ float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, flo
// perform our special rendering
//-------------------------------------------------
-void menu_select_launch::arts_render(float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::arts_render(u32 flags)
{
+ // draw the heading
+ draw_right_box_heading(flags, FIRST_VIEW < m_image_view, LAST_VIEW > m_image_view, _("selmenu-artwork", std::get<1>(ARTS_INFO[m_image_view])));
+
ui_software_info const *software;
- game_driver const *driver;
- get_selection(software, driver);
+ ui_system_info const *system;
+ get_selection(software, system);
- if (software && (!software->startempty || !driver))
+ if (software && (!software->startempty || !system))
{
- m_cache->set_snapx_driver(nullptr);
-
- if (m_default_image)
- m_image_view = (software->startempty == 0) ? SNAPSHOT_VIEW : CABINETS_VIEW;
-
- // arts title and searchpath
- std::string const searchstr = arts_render_common(origx1, origy1, origx2, origy2);
+ m_cache.set_snapx_driver(nullptr);
// loads the image if necessary
- if (!m_cache->snapx_software_is(software) || !snapx_valid() || m_switch_image)
+ if (!m_cache.snapx_software_is(software) || !snapx_valid() || m_switch_image)
{
- emu_file snapfile(searchstr.c_str(), OPEN_FLAG_READ);
+ emu_file snapfile(get_arts_searchpath(), OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
if (software->startempty == 1)
@@ -2286,99 +3664,40 @@ void menu_select_launch::arts_render(float origx1, float origy1, float origx2, f
else
{
// First attempt from name list
- load_image(tmp_bitmap, snapfile, software->listname + PATH_SEPARATOR + software->shortname);
+ load_image(tmp_bitmap, snapfile, util::path_concat(software->listname, software->shortname));
// Second attempt from driver name + part name
if (!tmp_bitmap.valid())
- load_image(tmp_bitmap, snapfile, software->driver->name + software->part + PATH_SEPARATOR + software->shortname);
+ load_image(tmp_bitmap, snapfile, util::path_concat(software->driver->name + software->part, software->shortname));
}
- m_cache->set_snapx_software(software);
+ m_cache.set_snapx_software(software);
m_switch_image = false;
- arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
+ arts_render_images(std::move(tmp_bitmap));
}
// if the image is available, loaded and valid, display it
- draw_snapx(origx1, origy1, origx2, origy2);
+ draw_snapx();
}
- else if (driver)
+ else if (system)
{
- m_cache->set_snapx_software(nullptr);
-
- if (m_default_image)
- m_image_view = ((driver->flags & machine_flags::MASK_TYPE) != machine_flags::TYPE_ARCADE) ? CABINETS_VIEW : SNAPSHOT_VIEW;
-
- std::string const searchstr = arts_render_common(origx1, origy1, origx2, origy2);
+ m_cache.set_snapx_software(nullptr);
// loads the image if necessary
- if (!m_cache->snapx_driver_is(driver) || !snapx_valid() || m_switch_image)
+ if (!m_cache.snapx_driver_is(system->driver) || !snapx_valid() || m_switch_image)
{
- emu_file snapfile(searchstr, OPEN_FLAG_READ);
+ emu_file snapfile(get_arts_searchpath(), OPEN_FLAG_READ);
bitmap_argb32 tmp_bitmap;
- load_driver_image(tmp_bitmap, snapfile, *driver);
+ load_driver_image(tmp_bitmap, snapfile, *system->driver);
- m_cache->set_snapx_driver(driver);
+ m_cache.set_snapx_driver(system->driver);
m_switch_image = false;
- arts_render_images(std::move(tmp_bitmap), origx1, origy1, origx2, origy2);
+ arts_render_images(std::move(tmp_bitmap));
}
// if the image is available, loaded and valid, display it
- draw_snapx(origx1, origy1, origx2, origy2);
- }
-}
-
-
-//-------------------------------------------------
-// common function for images render
-//-------------------------------------------------
-
-std::string menu_select_launch::arts_render_common(float origx1, float origy1, float origx2, float origy2)
-{
- float const line_height = ui().get_line_height();
- float const gutter_width = 0.4f * line_height * machine().render().ui_aspect(&container()) * 1.3f;
-
- std::string snaptext, searchstr;
- get_title_search(snaptext, searchstr);
-
- // apply title to right panel
- float title_size = 0.0f;
- for (int x = FIRST_VIEW; x < LAST_VIEW; x++)
- {
- float text_length;
- 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(),
- &text_length, nullptr);
- title_size = (std::max)(text_length + 0.01f, title_size);
+ draw_snapx();
}
-
- rgb_t const fgcolor = (m_focus == focused_menu::RIGHTBOTTOM) ? rgb_t(0xff, 0xff, 0x00) : ui().colors().text_color();
- rgb_t const bgcolor = (m_focus == focused_menu::RIGHTBOTTOM) ? rgb_t(0xff, 0xff, 0xff) : ui().colors().text_bg_color();
- float const middle = origx2 - origx1;
-
- // check size
- float const sc = title_size + 2.0f * gutter_width;
- float const tmp_size = (sc > middle) ? ((middle - 2.0f * gutter_width) / sc) : 1.0f;
- title_size *= tmp_size;
-
- if (bgcolor != ui().colors().text_bg_color())
- {
- ui().draw_textured_box(
- container(),
- origx1 + ((middle - title_size) * 0.5f), origy1 + ui().box_tb_border(),
- origx1 + ((middle + title_size) * 0.5f), origy1 + ui().box_tb_border() + line_height,
- bgcolor, rgb_t(43, 43, 43),
- hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
- }
-
- ui().draw_text_full(container(),
- snaptext, origx1, origy1 + ui().box_tb_border(), 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 + ui().box_tb_border(), origx2, origy2, m_image_view, FIRST_VIEW, LAST_VIEW, title_size);
-
- return searchstr;
}
@@ -2386,91 +3705,87 @@ std::string menu_select_launch::arts_render_common(float origx1, float origy1, f
// perform rendering of image
//-------------------------------------------------
-void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap)
{
- bool no_available = false;
- float line_height = ui().get_line_height();
-
// if it fails, use the default image
- if (!tmp_bitmap.valid())
+ bool no_available(!tmp_bitmap.valid());
+ if (no_available)
{
tmp_bitmap.allocate(256, 256);
- const bitmap_argb32 &src(m_cache->no_avail_bitmap());
+ 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.pix(y, x) = src.pix(y, x);
}
- no_available = true;
}
- bitmap_argb32 &snapx_bitmap(m_cache->snapx_bitmap());
- if (tmp_bitmap.valid())
+ bitmap_argb32 &snapx_bitmap(m_cache.snapx_bitmap());
+ if (!tmp_bitmap.valid())
{
- float panel_width = origx2 - origx1 - 0.02f;
- float panel_height = origy2 - origy1 - 0.02f - (3.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();
+ snapx_bitmap.reset();
+ return;
+ }
- if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY)
- std::swap(screen_height, screen_width);
+ float const panel_width(m_right_content_hbounds.second - m_right_content_hbounds.first);
+ float const panel_height(m_right_content_vbounds.second - m_right_content_vbounds.first);
+
+ auto [screen_width, screen_height] = target_size();
+ if (machine().render().ui_target().orientation() & ORIENTATION_SWAP_XY)
+ {
+ using std::swap;
+ swap(screen_height, screen_width);
+ }
- int panel_width_pixel = panel_width * screen_width;
- int panel_height_pixel = panel_height * screen_height;
+ int const panel_width_pixel(panel_width * screen_width);
+ int const 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();
+ // Calculate resize ratios for resizing
+ auto const ratioW(float(panel_width_pixel) / float(tmp_bitmap.width()));
+ auto const ratioH(float(panel_height_pixel) / float(tmp_bitmap.height()));
+ auto const ratioI(float(tmp_bitmap.height()) / float(tmp_bitmap.width()));
+ auto dest_xPixel(tmp_bitmap.width());
+ auto dest_yPixel(tmp_bitmap.height());
+ if (ui().options().forced_4x3_snapshot() && (ratioI < 0.75F) && (m_image_view == SNAPSHOT_VIEW))
+ {
// force 4:3 ratio min
- if (ui().options().forced_4x3_snapshot() && ratioI < 0.75f && m_image_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 = std::min(ratioW, ratioH);
- dest_xPixel = tmp_bitmap.width() * ratio;
- dest_yPixel *= ratio;
- }
+ dest_yPixel = tmp_bitmap.width() * 0.75F;
+ float const ratio = std::min(ratioW, float(panel_height_pixel) / float(dest_yPixel));
+ dest_xPixel = tmp_bitmap.width() * ratio;
+ dest_yPixel *= ratio;
+ }
+ else if ((ratioW < 1.0F) || (ratioH < 1.0F) || (ui().options().enlarge_snaps() && !no_available))
+ {
// 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 = std::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.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 = std::move(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);
+ float const ratio(std::min(ratioW, ratioH));
+ dest_xPixel = tmp_bitmap.width() * ratio;
+ dest_yPixel = tmp_bitmap.height() * ratio;
+ }
- for (int x = 0; x < dest_xPixel; x++)
- for (int y = 0; y < dest_yPixel; y++)
- snapx_bitmap.pix(y + y1, x + x1) = dest_bitmap.pix(y, x);
- // apply bitmap
- m_cache->snapx_texture()->set_bitmap(snapx_bitmap, snapx_bitmap.cliprect(), TEXFORMAT_ARGB32);
+ // resample if necessary
+ bitmap_argb32 dest_bitmap;
+ if ((dest_xPixel != tmp_bitmap.width()) || (dest_yPixel != tmp_bitmap.height()))
+ {
+ dest_bitmap.allocate(dest_xPixel, dest_yPixel);
+ render_resample_argb_bitmap_hq(dest_bitmap, tmp_bitmap, render_color{ 1.0F, 1.0F, 1.0F, 1.0F }, true);
}
else
{
- snapx_bitmap.reset();
+ dest_bitmap = std::move(tmp_bitmap);
}
+
+ snapx_bitmap.allocate(panel_width_pixel, panel_height_pixel);
+ int x1(0.5F * (float(panel_width_pixel) - float(dest_xPixel)));
+ int y1(0.5F * (float(panel_height_pixel) - float(dest_yPixel)));
+
+ for (int x = 0; x < dest_xPixel; x++)
+ for (int y = 0; y < dest_yPixel; y++)
+ snapx_bitmap.pix(y + y1, x + x1) = dest_bitmap.pix(y, x);
+
+ // apply bitmap
+ m_cache.snapx_texture()->set_bitmap(snapx_bitmap, snapx_bitmap.cliprect(), TEXFORMAT_ARGB32);
}
@@ -2478,22 +3793,66 @@ void menu_select_launch::arts_render_images(bitmap_argb32 &&tmp_bitmap, float or
// draw snapshot
//-------------------------------------------------
-void menu_select_launch::draw_snapx(float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::draw_snapx()
{
// if the image is available, loaded and valid, display it
if (snapx_valid())
{
- float const line_height = ui().get_line_height();
- float const x1 = origx1 + 0.01f;
- float const x2 = origx2 - 0.01f;
- float const y1 = origy1 + (2.0f * ui().box_tb_border()) + line_height;
- float const y2 = origy2 - ui().box_tb_border() - line_height;
+ container().add_quad(
+ m_right_content_hbounds.first, m_right_content_vbounds.first, m_right_content_hbounds.second, m_right_content_vbounds.second,
+ rgb_t::white(), m_cache.snapx_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ }
+}
+
+
+char const *menu_select_launch::right_panel_config_string() const
+{
+ assert(std::size(RIGHT_PANEL_NAMES) > m_right_panel);
+ return RIGHT_PANEL_NAMES[m_right_panel].first;
+}
+
+char const *menu_select_launch::right_image_config_string() const
+{
+ assert(std::size(ARTS_INFO) > m_image_view);
+ return std::get<0>(ARTS_INFO[m_image_view]);
+}
+
+void menu_select_launch::set_right_panel(u8 index)
+{
+ assert(std::size(RIGHT_PANEL_NAMES) > index);
+ m_right_panel = index;
+}
- // apply texture
- container().add_quad(x1, y1, x2, y2, rgb_t::white(), m_cache->snapx_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+void menu_select_launch::set_right_image(u8 index)
+{
+ assert(std::size(ARTS_INFO) > index);
+ if (index != m_image_view)
+ {
+ m_image_view = index;
+ set_switch_image();
}
}
+void menu_select_launch::set_right_panel(std::string_view value)
+{
+ auto const found = std::find_if(
+ std::begin(RIGHT_PANEL_NAMES),
+ std::end(RIGHT_PANEL_NAMES),
+ [&value] (auto const &that) { return value == that.first; });
+ if (std::end(RIGHT_PANEL_NAMES) != found)
+ m_right_panel = found - std::begin(RIGHT_PANEL_NAMES);
+}
+
+void menu_select_launch::set_right_image(std::string_view value)
+{
+ auto const found = std::find_if(
+ std::begin(ARTS_INFO),
+ std::end(ARTS_INFO),
+ [&value] (auto const &that) { return value == std::get<0>(that); });
+ if (std::end(ARTS_INFO) != found)
+ m_image_view = found - std::begin(ARTS_INFO);
+}
+
std::string menu_select_launch::make_system_audit_fail_text(media_auditor const &auditor, media_auditor::summary summary)
{
@@ -2588,7 +3947,7 @@ bool menu_select_launch::has_multiple_bios(game_driver const &driver, s_bios &bi
for (romload::system_bios const &bios : romload::entries(driver.rom).get_system_bioses())
{
std::string name(bios.get_description());
- uint32_t const bios_flags(bios.get_value());
+ u32 const bios_flags(bios.get_value());
if (default_name && !std::strcmp(bios.get_name(), default_name))
{
@@ -2604,68 +3963,27 @@ bool menu_select_launch::has_multiple_bios(game_driver const &driver, s_bios &bi
}
-void menu_select_launch::exit(running_machine &machine)
-{
- std::lock_guard<std::mutex> guard(s_cache_guard);
- s_caches.erase(&machine);
-}
-
-
-//-------------------------------------------------
-// draw collapsed left panel
-//-------------------------------------------------
-
-float menu_select_launch::draw_collapsed_left_panel(float x1, float y1, float x2, float y2)
-{
- float const aspect = machine().render().ui_aspect(&container());
- float const space = x2 - x1;
- float const lr_arrow_width = 0.4f * space * aspect;
-
- // set left-right arrows dimension
- float const ar_x0 = 0.5f * (x2 + x1) - (0.5f * lr_arrow_width);
- float const ar_y0 = 0.5f * (y2 + y1) + (0.1f * space);
- float const ar_x1 = ar_x0 + lr_arrow_width;
- float const ar_y1 = 0.5f * (y2 + y1) + (0.9f * space);
-
- ui().draw_outlined_box(container(), x1, y1, x2, y2, rgb_t(0xef, 0x12, 0x47, 0x7b)); // FIXME: magic numbers in colour?
-
- rgb_t fgcolor = ui().colors().text_color();
- if (mouse_in_rect(x1, y1, x2, y2))
- {
- fgcolor = ui().options().mouseover_color();
- set_hover(HOVER_LPANEL_ARROW);
- }
-
- draw_arrow(ar_x0, ar_y0, ar_x1, ar_y1, fgcolor, ROT90);
-
- return x2 + ui().box_lr_border() * aspect;
-}
-
-
//-------------------------------------------------
// draw infos
//-------------------------------------------------
-void menu_select_launch::infos_render(float origx1, float origy1, float origx2, float origy2)
+void menu_select_launch::infos_render(u32 flags)
{
- float const line_height = ui().get_line_height();
- float text_size = ui().options().infos_size();
- std::vector<int> xstart;
- std::vector<int> xend;
- const char *first = "";
+ std::string_view first;
ui_software_info const *software;
- game_driver const *driver;
+ ui_system_info const *system;
int total;
- get_selection(software, driver);
+ get_selection(software, system);
- if (software && (!software->startempty || !driver))
+ if (software && !software->startempty)
{
m_info_driver = nullptr;
- first = __("Usage");
+ first = _("Software List Info");
if ((m_info_software != software) || (m_info_view != ui_globals::cur_sw_dats_view))
{
m_info_buffer.clear();
+ m_info_layout = std::nullopt;
if (software == m_info_software)
{
m_info_view = ui_globals::cur_sw_dats_view;
@@ -2683,7 +4001,7 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
if (m_info_view == 0)
{
- m_info_buffer = software->usage;
+ m_info_buffer = software->infotext;
}
else
{
@@ -2693,34 +4011,38 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
}
total = ui_globals::cur_sw_dats_total;
}
- else if (driver)
+ else if (system || (software && software->driver))
{
+ game_driver const &driver(system ? *system->driver : *software->driver);
m_info_software = nullptr;
- first = __("General Info");
+ first = _("General Info");
- if (driver != m_info_driver || ui_globals::curdats_view != m_info_view)
+ if (&driver != m_info_driver || ui_globals::curdats_view != m_info_view)
{
m_info_buffer.clear();
- if (driver == m_info_driver)
+ m_info_layout = std::nullopt;
+ if (&driver == m_info_driver)
{
m_info_view = ui_globals::curdats_view;
}
else
{
- m_info_driver = driver;
+ m_info_driver = &driver;
m_info_view = 0;
ui_globals::curdats_view = 0;
m_items_list.clear();
- mame_machine_manager::instance()->lua()->call_plugin("data_list", driver->name, m_items_list);
+ mame_machine_manager::instance()->lua()->call_plugin("data_list", driver.name, m_items_list);
ui_globals::curdats_total = m_items_list.size() + 1;
}
if (m_info_view == 0)
- general_info(driver, m_info_buffer);
+ {
+ general_info(system, driver, m_info_buffer);
+ }
else
{
- m_info_buffer = "";
+ m_info_buffer.clear();
mame_machine_manager::instance()->lua()->call_plugin("data", m_info_view - 1, m_info_buffer);
}
}
@@ -2731,163 +4053,246 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2,
return;
}
- origy1 += ui().box_tb_border();
- float const aspect(machine().render().ui_aspect(&container()));
- float const gutter_width = 0.4f * line_height * aspect * 1.3f;
- float const ud_arrow_width = line_height * aspect;
- float oy1 = origy1 + line_height;
+ // draw the heading
+ std::string_view const snaptext(m_info_view ? std::string_view(m_items_list[m_info_view - 1]) : first);
+ draw_right_box_heading(flags, 0 < m_info_view, (total - 1) > m_info_view, snaptext);
- std::string_view const snaptext(m_info_view ? std::string_view(m_items_list[m_info_view - 1]) : std::string_view(_(first)));
-
- // get width of widest title
- float title_size(0.0f);
- for (std::size_t x = 0; total > x; ++x)
+ float const sc(m_right_panel_width - (2.0F * gutter_width()));
+ if (!m_info_layout || (m_info_layout->width() != sc))
{
- std::string_view const name(x ? std::string_view(m_items_list[x - 1]) : std::string_view(_(first)));
- float txt_length(0.0f);
- ui().draw_text_full(
- container(), name,
- origx1, origy1, origx2 - origx1,
- ui::text_layout::CENTER, ui::text_layout::NEVER,
- mame_ui_manager::NONE, ui().colors().text_color(), ui().colors().text_bg_color(),
- &txt_length, nullptr);
- txt_length += 0.01f;
- title_size = (std::max)(txt_length, title_size);
+ m_info_layout.emplace(
+ *ui().get_font(),
+ x_aspect() * m_info_line_height, m_info_line_height,
+ sc,
+ text_layout::text_justify::LEFT, text_layout::word_wrapping::WORD);
+ menu_dats_view::add_info_text(*m_info_layout, m_info_buffer, ui().colors().text_color());
+ m_total_lines = m_info_layout->lines();
}
- rgb_t fgcolor = ui().colors().text_color();
- rgb_t bgcolor = ui().colors().text_bg_color();
- if (get_focus() == focused_menu::RIGHTBOTTOM)
- {
- fgcolor = rgb_t(0xff, 0xff, 0xff, 0x00);
- bgcolor = rgb_t(0xff, 0xff, 0xff, 0xff);
- }
+ m_right_visible_lines = floor((m_right_content_vbounds.second - m_right_content_vbounds.first) / m_info_line_height);
+ if (m_total_lines < m_right_visible_lines)
+ m_right_visible_lines = m_total_lines;
+ if (m_topline_datsview < 0)
+ m_topline_datsview = 0;
+ if ((m_topline_datsview + m_right_visible_lines) >= m_total_lines)
+ m_topline_datsview = m_total_lines - m_right_visible_lines;
+
+ // get the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
+ bool const up_arrow(!info_at_top());
+ bool const down_arrow(!info_at_bottom());
+ int const r_visible_lines(m_right_visible_lines - (up_arrow ? 1 : 0) - (down_arrow ? 1 : 0));
+
+ if (up_arrow)
+ draw_info_arrow(flags, 0);
+ if (down_arrow)
+ draw_info_arrow(flags, m_right_visible_lines - 1);
+
+ m_info_layout->emit(
+ container(),
+ m_topline_datsview ? (m_topline_datsview + 1) : 0, r_visible_lines,
+ right_panel_left() + gutter_width(), m_right_content_vbounds.first + (m_topline_datsview ? m_info_line_height : 0.0f));
+}
- 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;
+//-------------------------------------------------
+// generate general info
+//-------------------------------------------------
- if (bgcolor != ui().colors().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(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1));
- }
+void menu_select_launch::general_info(ui_system_info const *system, game_driver const &driver, std::string &buffer)
+{
+ system_flags const &flags(get_system_flags(driver));
+ std::ostringstream str;
- ui().draw_text_full(container(), snaptext, origx1, origy1, origx2 - origx1, ui::text_layout::CENTER,
- ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size);
+ str << "#j2\n";
- char justify = 'l'; // left justify
- if ((m_info_buffer.length() >= 3) && (m_info_buffer[0] == '#'))
- {
- if (m_info_buffer[1] == 'j')
- justify = m_info_buffer[2];
- }
+ if (system)
+ str << system->description;
+ else
+ str << driver.type.fullname();
+ str << "\t\n\n";
+
+ util::stream_format(str, _("Short Name\t%1$s\n"), driver.name);
+ util::stream_format(str, _("Year\t%1$s\n"), driver.year);
+ util::stream_format(str, _("Manufacturer\t%1$s\n"), driver.manufacturer);
- draw_common_arrow(origx1, origy1, origx2, origy2, m_info_view, 0, total - 1, title_size);
- if (justify == 'f')
+ int cloneof = driver_list::non_bios_clone(driver);
+ if (0 <= cloneof)
{
- m_total_lines = ui().wrap_text(
- container(), m_info_buffer,
- 0.0f, 0.0f, 1.0f - (2.0f * gutter_width),
- xstart, xend,
- text_size);
+ util::stream_format(
+ str,
+ _("System is Clone of\t%1$s\n"),
+ system ? std::string_view(system->parent) : std::string_view(driver_list::driver(cloneof).type.fullname()));
}
else
{
- m_total_lines = ui().wrap_text(
- container(), m_info_buffer,
- origx1, origy1, origx2 - origx1 - (2.0f * gutter_width),
- xstart, xend,
- text_size);
+ str << _("System is Parent\t\n");
}
- int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size));
- 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;
-
- if (mouse_in_rect(origx1 + gutter_width, oy1, origx2 - gutter_width, origy2))
- set_hover(HOVER_INFO_TEXT);
+ if (flags.has_analog())
+ str << _("Analog Controls\tYes\n");
+ if (flags.has_keyboard())
+ str << _("Keyboard Inputs\tYes\n");
- sc = origx2 - origx1 - (2.0f * gutter_width);
- for (int r = 0; r < r_visible_lines; ++r)
+ if (flags.machine_flags() & machine_flags::NOT_WORKING)
+ str << _("Overall\tNOT WORKING\n");
+ else if ((flags.unemulated_features() | flags.imperfect_features()) & device_t::feature::PROTECTION)
+ str << _("Overall\tUnemulated Protection\n");
+ else
+ str << _("Overall\tWorking\n");
+
+ if (flags.unemulated_features() & device_t::feature::GRAPHICS)
+ str << _("Graphics\tUnimplemented\n");
+ else if (flags.unemulated_features() & device_t::feature::PALETTE)
+ str << _("Graphics\tWrong Colors\n");
+ else if (flags.imperfect_features() & device_t::feature::PALETTE)
+ str << _("Graphics\tImperfect Colors\n");
+ else if (flags.imperfect_features() & device_t::feature::GRAPHICS)
+ str << _("Graphics\tImperfect\n");
+ else
+ str << _("Graphics\tOK\n");
+
+ if (flags.machine_flags() & machine_flags::NO_SOUND_HW)
+ str << _("Sound\tNone\n");
+ else if (flags.unemulated_features() & device_t::feature::SOUND)
+ str << _("Sound\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::SOUND)
+ str << _("Sound\tImperfect\n");
+ else
+ str << _("Sound\tOK\n");
+
+ if (flags.unemulated_features() & device_t::feature::CAPTURE)
+ str << _("Capture\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::CAPTURE)
+ str << _("Capture\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::CAMERA)
+ str << _("Camera\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::CAMERA)
+ str << _("Camera\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::MICROPHONE)
+ str << _("Microphone\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::MICROPHONE)
+ str << _("Microphone\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::CONTROLS)
+ str << _("Controls\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::CONTROLS)
+ str << _("Controls\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::KEYBOARD)
+ str << _("Keyboard\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::KEYBOARD)
+ str << _("Keyboard\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::MOUSE)
+ str << _("Mouse\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::MOUSE)
+ str << _("Mouse\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::MEDIA)
+ str << _("Media\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::MEDIA)
+ str << _("Media\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::DISK)
+ str << _("Disk\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::DISK)
+ str << _("Disk\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::PRINTER)
+ str << _("Printer\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::PRINTER)
+ str << _("Printer\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::TAPE)
+ str << _("Mag. Tape\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::TAPE)
+ str << _("Mag. Tape\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::PUNCH)
+ str << _("Punch Tape\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::PUNCH)
+ str << _("Punch Tape\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::DRUM)
+ str << _("Mag. Drum\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::DRUM)
+ str << _("Mag. Drum\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::ROM)
+ str << _("(EP)ROM\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::ROM)
+ str << _("(EP)ROM\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::COMMS)
+ str << _("Communications\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::COMMS)
+ str << _("Communications\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::LAN)
+ str << _("LAN\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::LAN)
+ str << _("LAN\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::WAN)
+ str << _("WAN\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::WAN)
+ str << _("WAN\tImperfect\n");
+
+ if (flags.unemulated_features() & device_t::feature::TIMING)
+ str << _("Timing\tUnimplemented\n");
+ else if (flags.imperfect_features() & device_t::feature::TIMING)
+ str << _("Timing\tImperfect\n");
+
+ str << ((flags.machine_flags() & machine_flags::MECHANICAL) ? _("Mechanical System\tYes\n") : _("Mechanical System\tNo\n"));
+ str << ((flags.machine_flags() & machine_flags::REQUIRES_ARTWORK) ? _("Requires Artwork\tYes\n") : _("Requires Artwork\tNo\n"));
+ if (flags.machine_flags() & machine_flags::NO_COCKTAIL)
+ str << _("Support Cocktail\tNo\n");
+ str << ((flags.machine_flags() & machine_flags::IS_BIOS_ROOT) ? _("System is BIOS\tYes\n") : _("System is BIOS\tNo\n"));
+ str << ((flags.machine_flags() & machine_flags::SUPPORTS_SAVE) ? _("Support Save\tYes\n") : _("Support Save\tNo\n"));
+ str << ((flags.machine_flags() & ORIENTATION_SWAP_XY) ? _("Screen Orientation\tVertical\n") : _("Screen Orientation\tHorizontal\n"));
+ bool found = false;
+ for (romload::region const &region : romload::entries(driver.rom).get_regions())
{
- int itemline = r + m_topline_datsview;
- std::string_view const tempbuf(std::string_view(m_info_buffer).substr(xstart[itemline], xend[itemline] - xstart[itemline]));
- if (tempbuf[0] == '#')
- continue;
-
- if (r == 0 && m_topline_datsview != 0) // up arrow
+ if (region.is_diskdata())
{
- draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
- }
- else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1) // bottom arrow
- {
- draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width);
+ found = true;
+ break;
}
- else if (justify == '2') // two-column layout
- {
- // split at first tab
- std::string_view::size_type const splitpos(tempbuf.find('\t'));
- std::string_view const leftcol(tempbuf.substr(0, (std::string_view::npos == splitpos) ? 0U : splitpos));
- std::string_view const rightcol(tempbuf.substr((std::string_view::npos == splitpos) ? 0U : (splitpos + 1U)));
-
- // measure space needed, condense if necessary
- float const leftlen(ui().get_string_width(leftcol, text_size));
- float const rightlen(ui().get_string_width(rightcol, text_size));
- float const textlen(leftlen + rightlen);
- float const tmp_size3((textlen > sc) ? (text_size * (sc / textlen)) : text_size);
+ }
+ str << (found ? _("Requires CHD\tYes\n") : _("Requires CHD\tNo\n"));
- // draw in two parts
- ui().draw_text_full(
- container(), leftcol,
- origx1 + gutter_width, oy1, sc,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(),
- nullptr, nullptr,
- tmp_size3);
- ui().draw_text_full(
- container(), rightcol,
- origx1 + gutter_width, oy1, sc,
- ui::text_layout::RIGHT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(),
- nullptr, nullptr,
- tmp_size3);
- }
- else if (justify == 'f' || justify == 'p') // full or partial justify
- {
- // check size
- float const textlen = ui().get_string_width(tempbuf, text_size);
- float tmp_size3 = (textlen > sc) ? text_size * (sc / textlen) : text_size;
- ui().draw_text_full(
- container(), tempbuf,
- origx1 + gutter_width, oy1, origx2 - origx1,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(),
- nullptr, nullptr,
- tmp_size3);
- }
+ // audit the game first to see if we're going to work
+ if (ui().options().info_audit())
+ {
+ driver_enumerator enumerator(machine().options(), driver);
+ enumerator.next();
+ media_auditor auditor(enumerator);
+ media_auditor::summary summary = auditor.audit_media(AUDIT_VALIDATE_FAST);
+ media_auditor::summary summary_samples = auditor.audit_samples();
+
+ // if everything looks good, schedule the new driver
+ if (audit_passed(summary))
+ str << _("Media Audit Result\tOK\n");
else
- {
- ui().draw_text_full(
- container(), tempbuf,
- origx1 + gutter_width, oy1, origx2 - origx1,
- ui::text_layout::LEFT, ui::text_layout::TRUNCATE,
- mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(),
- nullptr, nullptr,
- text_size);
- }
+ str << _("Media Audit Result\tBAD\n");
- oy1 += (line_height * text_size);
+ if (summary_samples == media_auditor::NONE_NEEDED)
+ str << _("Samples Audit Result\tNone Needed\n");
+ else if (audit_passed(summary_samples))
+ str << _("Samples Audit Result\tOK\n");
+ else
+ str << _("Samples Audit Result\tBAD\n");
}
- // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow
- m_right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines);
+ else
+ {
+ str << _("Media Audit\tDisabled\nSamples Audit\tDisabled\n");
+ }
+
+ util::stream_format(str, _("Source File\t%1$s\n"), info_xml_creator::format_sourcefile(driver.type.source()));
+
+ buffer = std::move(str).str();
}
} // namespace ui