ui/ui.cpp: Make failure to mount required media fatal if file manager can't be displayed.

ui/filemngr.cpp: Show warnings in a box above the menu so they can be wrapped rather than being truncated to the point of being useless.
This commit is contained in:
Vas Crabb 2024-12-19 02:38:41 +11:00
parent 582390256c
commit a183c9f966
4 changed files with 54 additions and 20 deletions

View File

@ -38,9 +38,9 @@ namespace ui {
// ctor // ctor
//------------------------------------------------- //-------------------------------------------------
menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings) menu_file_manager::menu_file_manager(mame_ui_manager &mui, render_container &container, std::string &&warnings)
: menu(mui, container) : menu(mui, container)
, m_warnings(warnings ? warnings : "") , m_warnings(std::move(warnings))
, m_selected_device(nullptr) , m_selected_device(nullptr)
{ {
// The warning string is used when accessing from the force_file_manager call, i.e. // The warning string is used when accessing from the force_file_manager call, i.e.
@ -66,7 +66,18 @@ void menu_file_manager::recompute_metrics(uint32_t width, uint32_t height, float
{ {
menu::recompute_metrics(width, height, aspect); menu::recompute_metrics(width, height, aspect);
set_custom_space(0.0F, line_height() + 3.0F * tb_border()); if (!m_warnings.empty())
{
m_warnings_layout.reset();
float const max_width(1.0F - (4.0F * lr_border()));
m_warnings_layout.emplace(create_layout(max_width, text_layout::text_justify::LEFT));
m_warnings_layout->add_text(m_warnings, ui().colors().text_color());
}
set_custom_space(
m_warnings_layout ? ((m_warnings_layout->lines() * line_height()) + 3.0F * tb_border()) : 0.0F,
line_height() + 3.0F * tb_border());
} }
@ -76,6 +87,20 @@ void menu_file_manager::recompute_metrics(uint32_t width, uint32_t height, float
void menu_file_manager::custom_render(uint32_t flags, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2) void menu_file_manager::custom_render(uint32_t flags, void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{ {
// show the warnings if any
if (m_warnings_layout)
{
ui().draw_outlined_box(
container(),
((1.0F + m_warnings_layout->actual_width()) * 0.5F) + lr_border(), origy1 - (3.0F * tb_border()) - (m_warnings_layout->lines() * line_height()),
((1.0F - m_warnings_layout->actual_width()) * 0.5F) - lr_border(), origy1 - tb_border(),
ui().colors().background_color());
m_warnings_layout->emit(
container(),
(1.0F - m_warnings_layout->actual_width()) * 0.5F,
origy1 - (2.0F * tb_border()) - (m_warnings_layout->lines() * line_height()));
}
// access the path // access the path
std::string_view path = m_selected_device && m_selected_device->exists() ? m_selected_device->filename() : std::string_view(); std::string_view path = m_selected_device && m_selected_device->exists() ? m_selected_device->filename() : std::string_view();
extra_text_render(top, bottom, origx1, origy1, origx2, origy2, std::string_view(), path); extra_text_render(top, bottom, origx1, origy1, origx2, origy2, std::string_view(), path);
@ -122,9 +147,6 @@ void menu_file_manager::populate()
{ {
m_notifiers.clear(); m_notifiers.clear();
if (!m_warnings.empty())
item_append(m_warnings, FLAG_DISABLE, nullptr);
// cycle through all devices for this system // cycle through all devices for this system
bool missing_mandatory = false; bool missing_mandatory = false;
std::unordered_set<std::string> devtags; std::unordered_set<std::string> devtags;
@ -246,11 +268,11 @@ bool menu_file_manager::handle(event const *ev)
} }
// force file manager menu // force file manager menu
void menu_file_manager::force_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings) void menu_file_manager::force_file_manager(mame_ui_manager &mui, render_container &container, std::string &&warnings)
{ {
// drop any existing menus and start the file manager // drop any existing menus and start the file manager
menu::stack_reset(mui); menu::stack_reset(mui);
menu::stack_push_special_main<menu_file_manager>(mui, container, warnings); menu::stack_push_special_main<menu_file_manager>(mui, container, std::move(warnings));
mui.show_menu(); mui.show_menu();
// make sure MAME is paused // make sure MAME is paused

View File

@ -13,9 +13,11 @@
#pragma once #pragma once
#include "ui/menu.h" #include "ui/menu.h"
#include "ui/text.h"
#include "notifier.h" #include "notifier.h"
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -25,9 +27,9 @@ namespace ui {
class menu_file_manager : public menu class menu_file_manager : public menu
{ {
public: public:
static void force_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings); static void force_file_manager(mame_ui_manager &mui, render_container &container, std::string &&warnings);
menu_file_manager(mame_ui_manager &mui, render_container &container, const char *warnings); menu_file_manager(mame_ui_manager &mui, render_container &container, std::string &&warnings);
virtual ~menu_file_manager(); virtual ~menu_file_manager();
protected: protected:
@ -42,6 +44,7 @@ private:
std::string const m_warnings; std::string const m_warnings;
std::vector<util::notifier_subscription> m_notifiers; std::vector<util::notifier_subscription> m_notifiers;
std::optional<text_layout> m_warnings_layout;
device_image_interface *m_selected_device; device_image_interface *m_selected_device;
}; };

View File

@ -243,7 +243,7 @@ bool menu_main::handle(event const *ev)
break; break;
case IMAGE_MENU_FILE_MANAGER: case IMAGE_MENU_FILE_MANAGER:
menu::stack_push<menu_file_manager>(ui(), container(), nullptr); menu::stack_push<menu_file_manager>(ui(), container(), std::string());
break; break;
case TAPE_CONTROL: case TAPE_CONTROL:

View File

@ -629,15 +629,15 @@ static void output_joined_collection(const TColl &collection, TEmitMemberFunc em
void mame_ui_manager::display_startup_screens(bool first_time) void mame_ui_manager::display_startup_screens(bool first_time)
{ {
const int maxstate = 3; const int maxstate = 3;
int str = machine().options().seconds_to_run(); int const str = machine().options().seconds_to_run();
bool show_gameinfo = !machine().options().skip_gameinfo(); bool show_gameinfo = !machine().options().skip_gameinfo();
bool show_warnings = true, show_mandatory_fileman = true; bool show_warnings = true;
bool video_none = strcmp(downcast<osd_options &>(machine().options()).video(), OSDOPTVAL_NONE) == 0; bool video_none = strcmp(downcast<osd_options &>(machine().options()).video(), OSDOPTVAL_NONE) == 0;
// disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver, // disable everything if we are using -str for 300 or fewer seconds, or if we're the empty driver,
// or if we are debugging, or if there's no mame window to send inputs to // or if we are debugging, or if there's no mame window to send inputs to
if (!first_time || (str > 0 && str < 60*5) || &machine().system() == &GAME_NAME(___empty) || (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0 || video_none) if (!first_time || (str > 0 && str < 60*5) || &machine().system() == &GAME_NAME(___empty) || (machine().debug_flags & DEBUG_FLAG_ENABLED) || video_none)
show_gameinfo = show_warnings = show_mandatory_fileman = false; show_gameinfo = show_warnings = false;
#if defined(__EMSCRIPTEN__) #if defined(__EMSCRIPTEN__)
// also disable for the JavaScript port since the startup screens do not run asynchronously // also disable for the JavaScript port since the startup screens do not run asynchronously
@ -773,16 +773,25 @@ void mame_ui_manager::display_startup_screens(bool first_time)
case 2: case 2:
std::vector<std::reference_wrapper<const std::string>> mandatory_images = mame_machine_manager::instance()->missing_mandatory_images(); std::vector<std::reference_wrapper<const std::string>> mandatory_images = mame_machine_manager::instance()->missing_mandatory_images();
if (!mandatory_images.empty() && show_mandatory_fileman) if (!mandatory_images.empty())
{ {
std::ostringstream warning; std::ostringstream warning;
if ((str > 0) || (machine().debug_flags & DEBUG_FLAG_ENABLED) || video_none)
{
warning << "Images must be mounted for the following devices: ";
output_joined_collection(mandatory_images,
[&warning] (const std::reference_wrapper<const std::string> &img) { warning << img.get(); },
[&warning] () { warning << ", "; });
throw emu_fatalerror(std::move(warning).str());
}
warning << _("This system requires media images to be mounted for the following device(s): "); warning << _("This system requires media images to be mounted for the following device(s): ");
output_joined_collection(mandatory_images, output_joined_collection(mandatory_images,
[&warning](const std::reference_wrapper<const std::string> &img) { warning << "\"" << img.get() << "\""; }, [&warning] (const std::reference_wrapper<const std::string> &img) { warning << '"' << img.get() << '"'; },
[&warning]() { warning << ","; }); [&warning] () { warning << ", "; });
ui::menu_file_manager::force_file_manager(*this, machine().render().ui_container(), warning.str().c_str()); ui::menu_file_manager::force_file_manager(*this, machine().render().ui_container(), std::move(warning).str());
} }
break; break;
} }