emu/rendlay.cpp, ui/ui.cpp: Allow layout views to control pointer display.

This commit is contained in:
Vas Crabb 2024-04-14 07:36:45 +10:00
parent 7662be246f
commit 8e7af961c6
11 changed files with 101 additions and 27 deletions

View file

@ -587,9 +587,6 @@ driver.is_bios_root (read-only)
driver.requires_artwork (read-only)
A Boolean indicating whether the system requires external artwork to be
usable.
driver.clickable_artwork (read-only)
A Boolean indicating whether the system requires clickable artwork features
to be usable.
driver.unofficial (read-only)
A Boolean indicating whether this is an unofficial but common user
modification to a system.

View file

@ -754,6 +754,10 @@ manager.machine.video.snapshot_target
Properties
~~~~~~~~~~
target.ui_container (read-only)
The :ref:`render container <luascript-ref-rendercontainer>` for drawing user
interface elements over this render target, or ``nil`` for hidden render
targets (targets that are not shown to the user directly).
target.index (read-only)
The 1-based index of the render target. This has O(n) complexity.
target.width (read-only)
@ -810,6 +814,9 @@ Instantiation
manager.machine.render.ui_container
Gets the render container used to draw the user interface, including menus,
sliders and pop-up messages.
manager.machine.render.targets[index].ui_container
Gets the render container used to draw user interface elements over a
particular render target.
manager.machine.screens[tag].container
Gets the render container used to draw a given screen.
@ -1145,10 +1152,16 @@ view.bounds (read-only)
effective bounds of the view in its current configuration. The coordinates
are in view units, which are arbitrary but assumed to have square aspect
ratio.
view.has_art
view.has_art (read-only)
A Boolean indicating whether the view has any non-screen items, including
items that are not visible because the user has hidden the item collection
that they belong to.
view.show_pointers (read/write)
A Boolean that sets whether mouse and pon pointers should be displayed for
the view.
view.hide_inactive_pointers (read/write)
A Boolean that sets whether mouse pointers for the view should be hidden
after a period of inactivity.
.. _luascript-ref-renderlayitem:

View file

@ -690,6 +690,11 @@ element. This means a view can reference elements and groups that appear after
it in the file, and parameters from the enclosing scope will have their final
values from the end of the ``mamelayout`` element.
A ``view`` element may have a ``showpointers`` attribute to set whether mouse
and pen pointers should be shown for the view. If present, the value must be
either ``yes`` or ``no``. If the ``showpointers`` attribute is not present, pen
and mouse pointers are shown for views that contain items bound to I/O ports.
The following child elements are allowed inside a ``view`` element:
bounds

View file

@ -409,6 +409,7 @@ class LayoutChecker(Minifyer):
self.views[attrs['name']] = self.format_location()
elif not self.VARPATTERN.match(attrs['name']):
self.handle_error('Element view has duplicate name "%s" (previous %s)' % (attrs['name'], self.views[attrs['name']]))
self.check_bool_attribute(name, attrs, 'showpointers', None)
self.handlers.append((self.groupViewStartHandler, self.groupViewEndHandler))
self.variable_scopes.append({ })
self.item_ids = { }

View file

@ -4000,7 +4000,17 @@ layout_view::layout_view(
, m_elemmap(elemmap)
, m_defvismask(0U)
, m_has_art(false)
, m_show_ptr(false)
, m_ptr_time_out(true) // FIXME: add attribute for this
, m_exp_show_ptr(-1)
{
// check for explicit pointer display setting
if (viewnode.get_attribute_string_ptr("showpointers"))
{
m_show_ptr = env.get_attribute_bool(viewnode, "showpointers", false);
m_exp_show_ptr = m_show_ptr ? 1 : 0;
}
// parse the layout
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
view_environment local(env, m_name.c_str());
@ -4178,6 +4188,7 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// loop over items and filter by visibility mask
bool first = true;
bool scrfirst = true;
bool haveinput = false;
for (item &curitem : m_items)
{
if ((visibility_mask & curitem.visibility_mask()) == curitem.visibility_mask())
@ -4209,9 +4220,15 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
// accumulate interactive elements
if (!curitem.clickthrough() || curitem.has_input())
m_interactive_items.emplace_back(curitem);
if (curitem.has_input())
haveinput = true;
}
}
// if show pointers isn't explicitly, update it based on visible items
if (0 > m_exp_show_ptr)
m_show_ptr = haveinput;
// if we have an explicit bounds, override it
if (m_expbounds.x1 > m_expbounds.x0)
m_bounds = m_expbounds;
@ -4282,6 +4299,29 @@ void layout_view::recompute(u32 visibility_mask, bool zoom_to_screen)
}
//-------------------------------------------------
// set_show_pointers - set whether pointers
// should be displayed
//-------------------------------------------------
void layout_view::set_show_pointers(bool value) noexcept
{
m_show_ptr = value;
m_exp_show_ptr = value ? 1 : 0;
}
//-------------------------------------------------
// set_pointers_time_out - set whether pointers
// should be hidden after inactivity
//-------------------------------------------------
void layout_view::set_hide_inactive_pointers(bool value) noexcept
{
m_ptr_time_out = value;
}
//-------------------------------------------------
// set_prepare_items_callback - set handler called
// before adding items to render target

View file

@ -527,6 +527,12 @@ public:
const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
u32 default_visibility_mask() const { return m_defvismask; }
bool has_art() const { return m_has_art; }
bool show_pointers() const { return m_show_ptr; }
bool hide_inactive_pointers() const { return m_ptr_time_out; }
// setters
void set_show_pointers(bool value) noexcept;
void set_hide_inactive_pointers(bool value) noexcept ATTR_COLD;
// set handlers
void set_prepare_items_callback(prepare_items_delegate &&handler) ATTR_COLD;
@ -621,6 +627,9 @@ private:
render_bounds m_expbounds; // explicit bounds of the view
u32 m_defvismask; // default visibility mask
bool m_has_art; // true if the layout contains non-screen elements
bool m_show_ptr; // whether pointers should be displayed
bool m_ptr_time_out; // whether pointers should be hidden after inactivity
s8 m_exp_show_ptr; // explicitly configured pointer visibility
};

View file

@ -1502,7 +1502,6 @@ void lua_engine::initialize()
game_driver_type["no_cocktail"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::NO_COCKTAIL) != 0; });
game_driver_type["is_bios_root"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_BIOS_ROOT) != 0; });
game_driver_type["requires_artwork"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::REQUIRES_ARTWORK) != 0; });
game_driver_type["clickable_artwork"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::CLICKABLE_ARTWORK) != 0; });
game_driver_type["unofficial"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::UNOFFICIAL) != 0; });
game_driver_type["no_sound_hw"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::NO_SOUND_HW) != 0; });
game_driver_type["mechanical"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::MECHANICAL) != 0; });

View file

@ -994,6 +994,8 @@ void lua_engine::initialize_render(sol::table &emu)
layout_view_type["effective_aspect"] = sol::property(&layout_view::effective_aspect);
layout_view_type["bounds"] = sol::property(&layout_view::bounds);
layout_view_type["has_art"] = sol::property(&layout_view::has_art);
layout_view_type["show_pointers"] = sol::property(&layout_view::show_pointers, &layout_view::set_show_pointers);
layout_view_type["hide_inactive_pointers"] = sol::property(&layout_view::hide_inactive_pointers, &layout_view::set_hide_inactive_pointers);
auto layout_view_item_type = sol().registry().new_usertype<layout_view_item>("layout_item", sol::no_constructor);
@ -1100,6 +1102,7 @@ void lua_engine::initialize_render(sol::table &emu)
auto target_type = sol().registry().new_usertype<render_target>("target", sol::no_constructor);
target_type["ui_container"] = sol::property(&render_target::ui_container);
target_type["index"] = sol::property([] (render_target const &t) { return t.index() + 1; });
target_type["width"] = sol::property(&render_target::width);
target_type["height"] = sol::property(&render_target::height);

View file

@ -4202,7 +4202,6 @@ void menu_select_launch::general_info(ui_system_info const *system, game_driver
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"));
str << ((flags.machine_flags() & machine_flags::CLICKABLE_ARTWORK) ? _("Requires Clickable Artwork\tYes\n") : _("Requires Clickable 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"));

View file

@ -38,6 +38,7 @@
#include "render.h"
#include "cheat.h"
#include "rendfont.h"
#include "rendlay.h"
#include "romload.h"
#include "screen.h"
#include "speaker.h"
@ -165,7 +166,13 @@ enum class mame_ui_manager::ui_callback_type : int
struct mame_ui_manager::active_pointer
{
active_pointer(ui_event const &event) : target(event.target), type(event.pointer_type), ptrid(event.pointer_id), x(-1.0F), y(-1.0F)
active_pointer(ui_event const &event)
: target(event.target)
, updated(std::chrono::steady_clock::time_point::min())
, type(event.pointer_type)
, ptrid(event.pointer_id)
, x(-1.0F)
, y(-1.0F)
{
}
@ -175,6 +182,7 @@ struct mame_ui_manager::active_pointer
}
render_target *target;
std::chrono::steady_clock::time_point updated;
osd::ui_event_handler::pointer type;
u16 ptrid;
float x, y;
@ -198,8 +206,6 @@ mame_ui_manager::mame_ui_manager(running_machine &machine)
, m_popup_text_end(0)
, m_mouse_bitmap(32, 32)
, m_mouse_arrow_texture(nullptr)
, m_mouse_show(false)
, m_update_pointers(false)
, m_pointers_changed(false)
, m_target_font_height(0)
, m_has_warnings(false)
@ -240,7 +246,6 @@ void mame_ui_manager::init()
return 0;
}));
m_non_char_keys_down = std::make_unique<uint8_t[]>((std::size(non_char_keys) + 7) / 8);
m_mouse_show = machine().system().flags & machine_flags::CLICKABLE_ARTWORK ? true : false;
// request notification callbacks
machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(&mame_ui_manager::frame_update, this));
@ -733,7 +738,7 @@ bool mame_ui_manager::update_and_render(render_container &container)
// display the internal pointers
bool const pointer_update = m_pointers_changed;
m_pointers_changed = false;
if (m_mouse_show || (is_menu_active() && machine().options().ui_mouse()))
if (!is_menu_active() || machine().options().ui_mouse())
{
const float cursor_size = 0.6 * get_line_height();
for (auto const &pointer : m_display_pointers)
@ -1128,12 +1133,12 @@ void mame_ui_manager::process_ui_events()
{
if (osd::ui_event_handler::pointer::TOUCH != event.pointer_type)
{
m_update_pointers = true;
auto pos(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), std::make_pair(event.target, event.pointer_id)));
if ((m_active_pointers.end() == pos) || (pos->target != event.target) || (pos->ptrid != event.pointer_id))
pos = m_active_pointers.emplace(pos, event);
else
assert(pos->type == event.pointer_type);
pos->updated = std::chrono::steady_clock::now();
event.target->map_point_container(event.pointer_x, event.pointer_y, *event.target->ui_container(), pos->x, pos->y);
}
@ -1150,10 +1155,7 @@ void mame_ui_manager::process_ui_events()
{
auto const pos(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), std::make_pair(event.target, event.pointer_id)));
if (m_active_pointers.end() != pos)
{
m_update_pointers = true;
m_active_pointers.erase(pos);
}
event.target->pointer_left(
event.pointer_type, event.pointer_id, event.pointer_device,
@ -1168,10 +1170,7 @@ void mame_ui_manager::process_ui_events()
{
auto const pos(std::lower_bound(m_active_pointers.begin(), m_active_pointers.end(), std::make_pair(event.target, event.pointer_id)));
if (m_active_pointers.end() != pos)
{
m_update_pointers = true;
m_active_pointers.erase(pos);
}
event.target->pointer_aborted(
event.pointer_type, event.pointer_id, event.pointer_device,
@ -1379,15 +1378,20 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
// process UI events and update pointers if necessary
process_ui_events();
if (m_update_pointers)
display_pointer_vector pointers;
pointers.reserve(m_active_pointers.size());
auto const now(std::chrono::steady_clock::now());
for (auto const &pointer : m_active_pointers)
{
display_pointer_vector pointers;
pointers.reserve(m_active_pointers.size());
for (auto const &pointer : m_active_pointers)
pointers.emplace_back(display_pointer{ *pointer.target, pointer.type, pointer.x, pointer.y });
set_pointers(pointers.begin(), pointers.end());
m_update_pointers = false;
layout_view const &view(pointer.target->current_view());
if (view.show_pointers())
{
// TODO: make timeout configurable
if (!view.hide_inactive_pointers() || (osd::ui_event_handler::pointer::PEN == pointer.type) || ((now - pointer.updated) <= std::chrono::seconds(3)))
pointers.emplace_back(display_pointer{ *pointer.target, pointer.type, pointer.x, pointer.y });
}
}
set_pointers(pointers.begin(), pointers.end());
if (!ui_disabled)
{
@ -2400,6 +2404,12 @@ bool mame_ui_manager::set_ui_event_handler(std::function<bool ()> &&handler)
if (ui_callback_type::GENERAL != m_handler_callback_type)
return false;
for (auto *target = machine().render().first_target(); target; target = target->next())
{
if (!target->hidden())
target->forget_pointers();
}
set_handler(
ui_callback_type::CUSTOM,
handler_callback_func(

View file

@ -298,8 +298,6 @@ private:
display_pointer_vector m_display_pointers;
bitmap_argb32 m_mouse_bitmap;
render_texture * m_mouse_arrow_texture;
bool m_mouse_show;
bool m_update_pointers;
bool m_pointers_changed;
ui_options m_ui_options;