summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2021-11-18 10:34:38 +1100
committer Vas Crabb <vas@vastheman.com>2021-11-18 10:34:38 +1100
commit5afce6cfab6320ee062da5f7b7438294672f9af1 (patch)
tree5902ddf0b74f27e3d43bc0556dcfd29198e86efd /src/emu
parentded9ecfc1cf7864f206b92480eaebf32092ef8f2 (diff)
emu/render.cpp, emu/rendlay.cpp: Added scroll support for all elements.
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/emufwd.h9
-rw-r--r--src/emu/render.cpp85
-rw-r--r--src/emu/render.h2
-rw-r--r--src/emu/rendlay.cpp547
-rw-r--r--src/emu/rendlay.h295
5 files changed, 656 insertions, 282 deletions
diff --git a/src/emu/emufwd.h b/src/emu/emufwd.h
index b3969a8fc99..8b8e59b9250 100644
--- a/src/emu/emufwd.h
+++ b/src/emu/emufwd.h
@@ -193,9 +193,6 @@ class network_manager;
class output_manager;
// declared in render.h
-class layout_element;
-class layout_view;
-class layout_file;
class render_container;
class render_manager;
class render_target;
@@ -204,6 +201,12 @@ class render_texture;
// declared in rendfont.h
class render_font;
+// declared in rendlay.h
+class layout_element;
+class layout_view_item;
+class layout_view;
+class layout_file;
+
// declared in romentry.h
class rom_entry;
diff --git a/src/emu/render.cpp b/src/emu/render.cpp
index 0fef6bafe41..42a837062a3 100644
--- a/src/emu/render.cpp
+++ b/src/emu/render.cpp
@@ -1097,7 +1097,7 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i
screen_device const &screen = screens[index() % screens.size()];
for (unsigned i = 0; !view && (m_views.size() > i); ++i)
{
- for (layout_view::item &viewitem : m_views[i].first.items())
+ for (layout_view_item &viewitem : m_views[i].first.items())
{
screen_device const *const viewscreen(viewitem.screen());
if (viewscreen == &screen)
@@ -1286,7 +1286,7 @@ void render_target::compute_minimum_size(s32 &minwidth, s32 &minheight)
throw emu_fatalerror("Mandatory artwork is missing");
// scan the current view for all screens
- for (layout_view::item &curitem : current_view().items())
+ for (layout_view_item &curitem : current_view().items())
{
screen_device const *const screen = curitem.screen();
if (screen)
@@ -1370,7 +1370,7 @@ render_primitive_list &render_target::get_primitives()
{
// we're running - iterate over items in the view
current_view().prepare_items();
- for (layout_view::item &curitem : current_view().visible_items())
+ for (layout_view_item &curitem : current_view().visible_items())
{
// first apply orientation to the bounds
render_bounds bounds = curitem.bounds();
@@ -1391,7 +1391,7 @@ render_primitive_list &render_target::get_primitives()
if (curitem.screen())
add_container_primitives(list, root_xform, item_xform, curitem.screen()->container(), curitem.blend_mode());
else
- add_element_primitives(list, item_xform, *curitem.element(), curitem.element_state(), curitem.blend_mode());
+ add_element_primitives(list, item_xform, curitem);
}
}
else
@@ -1494,10 +1494,10 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta
auto const found(std::find_if(
items.begin(),
items.end(),
- [&container] (layout_view::item &item) { return &item.screen()->container() == &container; }));
+ [&container] (layout_view_item &item) { return &item.screen()->container() == &container; }));
if (items.end() != found)
{
- layout_view::item &item(*found);
+ layout_view_item &item(*found);
render_bounds const bounds(item.bounds());
if (bounds.includes(target_f.first, target_f.second))
{
@@ -1555,7 +1555,7 @@ bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&in
{
if (m_hit_test[i] && m_hit_test[items.size() + i])
{
- layout_view::item &item(items[i]);
+ layout_view_item &item(items[i]);
render_bounds const bounds(item.bounds());
if (bounds.includes(target_f.first, target_f.second))
{
@@ -2523,11 +2523,13 @@ void render_target::add_container_primitives(render_primitive_list &list, const
// for an element in the current state
//-------------------------------------------------
-void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode)
+void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item)
{
+ layout_element &element(*item.element());
+ int const blendmode(item.blend_mode());
+
// limit state range to non-negative values
- if (state < 0)
- state = 0;
+ int const state((std::max)(item.element_state(), 0));
// get a pointer to the relevant texture
render_texture *texture = element.state_texture(state);
@@ -2537,29 +2539,70 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob
// configure the basics
prim->color = xform.color;
- prim->flags = PRIMFLAG_TEXORIENT(xform.orientation) | PRIMFLAG_BLENDMODE(blendmode) | PRIMFLAG_TEXFORMAT(texture->format());
+ prim->flags =
+ PRIMFLAG_TEXORIENT(xform.orientation) |
+ PRIMFLAG_TEXFORMAT(texture->format()) |
+ PRIMFLAG_BLENDMODE(blendmode) |
+ PRIMFLAG_TEXWRAP((item.scroll_wrap_x() || item.scroll_wrap_y()) ? 1 : 0);
// compute the bounds
- s32 width = render_round_nearest(xform.xscale);
- s32 height = render_round_nearest(xform.yscale);
- prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), float(width), float(height));
+ float const primwidth(render_round_nearest(xform.xscale));
+ float const primheight(render_round_nearest(xform.yscale));
+ prim->bounds.set_wh(render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), primwidth, primheight);
prim->full_bounds = prim->bounds;
- if (xform.orientation & ORIENTATION_SWAP_XY)
- std::swap(width, height);
- width = (std::min)(width, m_maxtexwidth);
- height = (std::min)(height, m_maxtexheight);
// get the scaled texture and append it
- texture->get_scaled(width, height, prim->texture, list, prim->flags);
+ float const xsize(item.scroll_size_x());
+ float const ysize(item.scroll_size_y());
+ s32 texwidth = render_round_nearest(((xform.orientation & ORIENTATION_SWAP_XY) ? primwidth : primheight) / xsize);
+ s32 texheight = render_round_nearest(((xform.orientation & ORIENTATION_SWAP_XY) ? primheight : primwidth) / ysize);
+ texwidth = (std::min)(texwidth, m_maxtexwidth);
+ texheight = (std::min)(texheight, m_maxtexheight);
+ texture->get_scaled(texwidth, texheight, prim->texture, list, prim->flags);
// compute the clip rect
render_bounds cliprect = prim->bounds & m_bounds;
// determine UV coordinates and apply clipping
- prim->texcoords = oriented_texcoords[xform.orientation];
- bool clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
+ float const xwindow((xform.orientation & ORIENTATION_SWAP_XY) ? primwidth : primheight);
+ float const ywindow((xform.orientation & ORIENTATION_SWAP_XY) ? primheight : primwidth);
+ float const xrange(float(texwidth) - (item.scroll_wrap_x() ? 0.0f : xwindow));
+ float const yrange(float(texheight) - (item.scroll_wrap_y() ? 0.0f : ywindow));
+ float const xoffset(render_round_nearest(item.scroll_pos_x() * xrange) / float(texwidth));
+ float const yoffset(render_round_nearest(item.scroll_pos_y() * yrange) / float(texheight));
+ float const xend(xoffset + (xwindow / float(texwidth)));
+ float const yend(yoffset + (ywindow / float(texheight)));
+ switch (xform.orientation)
+ {
+ default:
+ case 0:
+ prim->texcoords = render_quad_texuv{ { xoffset, yoffset }, { xend, yoffset }, { xoffset, yend }, { xend, yend } };
+ break;
+ case ORIENTATION_FLIP_X:
+ prim->texcoords = render_quad_texuv{ { xend, yoffset }, { xoffset, yoffset }, { xend, yend }, { xoffset, yend } };
+ break;
+ case ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xoffset, yend }, { xend, yend }, { xoffset, yoffset }, { xend, yoffset } };
+ break;
+ case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yend }, { xoffset, yend }, { xend, yoffset }, { xoffset, yoffset } };
+ break;
+ case ORIENTATION_SWAP_XY:
+ prim->texcoords = render_quad_texuv{ { xoffset, yoffset }, { xoffset, yend }, { xend, yoffset }, { xend, yend } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X:
+ prim->texcoords = render_quad_texuv{ { xoffset, yend }, { xoffset, yoffset }, { xend, yend }, { xend, yoffset } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yoffset }, { xend, yend }, { xoffset, yoffset }, { xoffset, yend } };
+ break;
+ case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y:
+ prim->texcoords = render_quad_texuv{ { xend, yend }, { xend, yoffset }, { xoffset, yend }, { xoffset, yoffset } };
+ break;
+ }
// add to the list or free if we're clipped out
+ bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords);
list.append_or_return(*prim, clipped);
}
}
diff --git a/src/emu/render.h b/src/emu/render.h
index 5833a036077..d1d8987ea9b 100644
--- a/src/emu/render.h
+++ b/src/emu/render.h
@@ -590,7 +590,7 @@ private:
bool load_layout_file(const char *dirname, const internal_layout &layout_data, device_t *device = nullptr);
bool load_layout_file(device_t &device, util::xml::data_node const &rootnode, const char *searchpath, const char *dirname);
void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode);
- void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode);
+ void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item);
std::pair<float, float> map_point_internal(s32 target_x, s32 target_y);
// config callbacks
diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp
index b6709626d97..41075c2573b 100644
--- a/src/emu/rendlay.cpp
+++ b/src/emu/rendlay.cpp
@@ -1120,6 +1120,121 @@ inline render_color interpolate_color(emu::render::detail::color_vector const &s
}
}
+
+unsigned get_state_shift(ioport_value mask)
+{
+ // get shift to right-align LSB
+ unsigned result(0U);
+ while (mask && !BIT(mask, 0))
+ {
+ ++result;
+ mask >>= 1;
+ }
+ return result;
+}
+
+std::string make_child_output_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ if (childnode)
+ return std::string(env.get_attribute_string(*childnode, "name"));
+ else
+ return std::string();
+}
+
+std::string make_child_input_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_subtag(*childnode, "inputtag") : std::string();
+}
+
+ioport_value make_child_mask(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_int(*childnode, "mask", ~ioport_value(0)) : ~ioport_value(0);
+}
+
+bool make_child_wrap(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_bool(*childnode, "wrap", false) : false;
+}
+
+float make_child_size(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return std::clamp(childnode ? env.get_attribute_float(*childnode, "size", 1.0f) : 1.0f, 0.01f, 1.0f);
+}
+
+ioport_value make_child_min(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ return childnode ? env.get_attribute_int(*childnode, "min", ioport_value(0)) : ioport_value(0);
+}
+
+ioport_value make_child_max(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode,
+ char const *child,
+ ioport_value mask)
+{
+ util::xml::data_node const *const childnode(itemnode.get_child(child));
+ ioport_value const dflt(mask >> get_state_shift(mask));
+ return childnode ? env.get_attribute_int(*childnode, "max", dflt) : dflt;
+}
+
+std::string make_input_tag(
+ emu::render::detail::view_environment &env,
+ util::xml::data_node const &itemnode)
+{
+ return env.get_attribute_subtag(itemnode, "inputtag");
+}
+
+int get_blend_mode(emu::render::detail::view_environment &env, util::xml::data_node const &itemnode)
+{
+ // see if there's a blend mode attribute
+ std::string const *const mode(itemnode.get_attribute_string_ptr("blend"));
+ if (mode)
+ {
+ if (*mode == "none")
+ return BLENDMODE_NONE;
+ else if (*mode == "alpha")
+ return BLENDMODE_ALPHA;
+ else if (*mode == "multiply")
+ return BLENDMODE_RGB_MULTIPLY;
+ else if (*mode == "add")
+ return BLENDMODE_ADD;
+ else
+ throw layout_syntax_error(util::string_format("unknown blend mode %s", *mode));
+ }
+
+ // fall back to implicit blend mode based on element type
+ if (!strcmp(itemnode.get_name(), "screen"))
+ return -1; // magic number recognised by render.cpp to allow per-element blend mode
+ else if (!strcmp(itemnode.get_name(), "overlay"))
+ return BLENDMODE_RGB_MULTIPLY;
+ else
+ return BLENDMODE_ALPHA;
+}
+
} // anonymous namespace
@@ -4096,7 +4211,7 @@ layout_view::~layout_view()
// get_item - get item by ID
//-------------------------------------------------
-layout_view::item *layout_view::get_item(std::string const &id)
+layout_view_item *layout_view::get_item(std::string const &id)
{
auto const found(m_items_by_id.find(id));
return (m_items_by_id.end() != found) ? &found->second : nullptr;
@@ -4502,10 +4617,10 @@ std::string layout_view::make_name(layout_environment &env, util::xml::data_node
//**************************************************************************
//-------------------------------------------------
-// item - constructor
+// layout_view_item - constructor
//-------------------------------------------------
-layout_view::item::item(
+layout_view_item::layout_view_item(
view_environment &env,
util::xml::data_node const &itemnode,
element_map &elemmap,
@@ -4514,11 +4629,29 @@ layout_view::item::item(
render_color const &color)
: m_element(find_element(env, itemnode, elemmap))
, m_output(env.device(), std::string(env.get_attribute_string(itemnode, "name")))
- , m_animoutput(env.device(), make_animoutput_tag(env, itemnode))
+ , m_animoutput(env.device(), make_child_output_tag(env, itemnode, "animate"))
+ , m_scrollxoutput(env.device(), make_child_output_tag(env, itemnode, "xscroll"))
+ , m_scrollyoutput(env.device(), make_child_output_tag(env, itemnode, "yscroll"))
, m_animinput_port(nullptr)
+ , m_scrollxinput_port(nullptr)
+ , m_scrollyinput_port(nullptr)
+ , m_scrollwrapx(make_child_wrap(env, itemnode, "xscroll"))
+ , m_scrollwrapy(make_child_wrap(env, itemnode, "yscroll"))
, m_elem_state(m_element ? m_element->default_state() : 0)
- , m_animmask(make_animmask(env, itemnode))
+ , m_scrollsizex(make_child_size(env, itemnode, "xscroll"))
+ , m_scrollsizey(make_child_size(env, itemnode, "yscroll"))
+ , m_scrollposx(0.0f)
+ , m_scrollposy(0.0f)
+ , m_animmask(make_child_mask(env, itemnode, "animate"))
+ , m_scrollxmask(make_child_mask(env, itemnode, "xscroll"))
+ , m_scrollymask(make_child_mask(env, itemnode, "yscroll"))
+ , m_scrollxmin(make_child_min(env, itemnode, "xscroll"))
+ , m_scrollymin(make_child_min(env, itemnode, "yscroll"))
+ , m_scrollxmax(make_child_max(env, itemnode, "xscroll", m_scrollxmask))
+ , m_scrollymax(make_child_max(env, itemnode, "yscroll", m_scrollymask))
, m_animshift(get_state_shift(m_animmask))
+ , m_scrollxshift(get_state_shift(m_scrollxmask))
+ , m_scrollyshift(get_state_shift(m_scrollymask))
, m_input_port(nullptr)
, m_input_field(nullptr)
, m_input_mask(env.get_attribute_int(itemnode, "inputmask", 0))
@@ -4531,11 +4664,15 @@ layout_view::item::item(
, m_visibility_mask(env.visibility_mask())
, m_id(env.get_attribute_string(itemnode, "id"))
, m_input_tag(make_input_tag(env, itemnode))
- , m_animinput_tag(make_animinput_tag(env, itemnode))
+ , m_animinput_tag(make_child_input_tag(env, itemnode, "animate"))
+ , m_scrollxinput_tag(make_child_input_tag(env, itemnode, "xscroll"))
+ , m_scrollyinput_tag(make_child_input_tag(env, itemnode, "yscroll"))
, m_rawbounds(make_bounds(env, itemnode, trans))
, m_have_output(!env.get_attribute_string(itemnode, "name").empty())
, m_input_raw(env.get_attribute_bool(itemnode, "inputraw", 0))
- , m_have_animoutput(!make_animoutput_tag(env, itemnode).empty())
+ , m_have_animoutput(!make_child_output_tag(env, itemnode, "animate").empty())
+ , m_have_scrollxoutput(!make_child_output_tag(env, itemnode, "xscroll").empty())
+ , m_have_scrollyoutput(!make_child_output_tag(env, itemnode, "yscroll").empty())
, m_has_clickthrough(!env.get_attribute_string(itemnode, "clickthrough").empty())
{
// fetch common data
@@ -4562,6 +4699,14 @@ layout_view::item::item(
{
throw layout_syntax_error(util::string_format("item of type %s requires an element tag", itemnode.get_name()));
}
+ else if (m_scrollxmin == m_scrollxmax)
+ {
+ throw layout_syntax_error(util::string_format("item X scroll minimum and maximum both equal to %u", m_scrollxmin));
+ }
+ else if (m_scrollymin == m_scrollymax)
+ {
+ throw layout_syntax_error(util::string_format("item Y scroll minimum and maximum both equal to %u", m_scrollymin));
+ }
// this can be called before resolving tags, make it return something valid
m_bounds = m_rawbounds;
@@ -4570,10 +4715,10 @@ layout_view::item::item(
//-------------------------------------------------
-// item - destructor
+// layout_view_item - destructor
//-------------------------------------------------
-layout_view::item::~item()
+layout_view_item::~layout_view_item()
{
}
@@ -4583,7 +4728,7 @@ layout_view::item::~item()
// obtain element state value
//-------------------------------------------------
-void layout_view::item::set_element_state_callback(state_delegate &&handler)
+void layout_view_item::set_element_state_callback(state_delegate &&handler)
{
if (!handler.isnull())
m_get_elem_state = std::move(handler);
@@ -4597,7 +4742,7 @@ void layout_view::item::set_element_state_callback(state_delegate &&handler)
// obtain animation state
//-------------------------------------------------
-void layout_view::item::set_animation_state_callback(state_delegate &&handler)
+void layout_view_item::set_animation_state_callback(state_delegate &&handler)
{
if (!handler.isnull())
m_get_anim_state = std::move(handler);
@@ -4611,7 +4756,7 @@ void layout_view::item::set_animation_state_callback(state_delegate &&handler)
// bounds
//-------------------------------------------------
-void layout_view::item::set_bounds_callback(bounds_delegate &&handler)
+void layout_view_item::set_bounds_callback(bounds_delegate &&handler)
{
if (!handler.isnull())
m_get_bounds = std::move(handler);
@@ -4625,7 +4770,7 @@ void layout_view::item::set_bounds_callback(bounds_delegate &&handler)
// color
//-------------------------------------------------
-void layout_view::item::set_color_callback(color_delegate &&handler)
+void layout_view_item::set_color_callback(color_delegate &&handler)
{
if (!handler.isnull())
m_get_color = std::move(handler);
@@ -4635,10 +4780,66 @@ void layout_view::item::set_color_callback(color_delegate &&handler)
//-------------------------------------------------
+// set_scroll_size_x_callback - set callback to
+// obtain horizontal scroll window size
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_size_x_callback(scroll_size_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_size_x = std::move(handler);
+ else
+ m_get_scroll_size_x = default_get_scroll_size_x();
+}
+
+
+//-------------------------------------------------
+// set_scroll_size_y_callback - set callback to
+// obtain vertical scroll window size
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_size_y_callback(scroll_size_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_size_y = std::move(handler);
+ else
+ m_get_scroll_size_y = default_get_scroll_size_y();
+}
+
+
+//-------------------------------------------------
+// set_scroll_pos_x_callback - set callback to
+// obtain horizontal scroll position
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_pos_x_callback(scroll_pos_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_pos_x = std::move(handler);
+ else
+ m_get_scroll_pos_x = default_get_scroll_pos_x();
+}
+
+
+//-------------------------------------------------
+// set_scroll_pos_y_callback - set callback to
+// obtain vertical scroll position
+//-------------------------------------------------
+
+void layout_view_item::set_scroll_pos_y_callback(scroll_pos_delegate &&handler)
+{
+ if (!handler.isnull())
+ m_get_scroll_pos_y = std::move(handler);
+ else
+ m_get_scroll_pos_y = default_get_scroll_pos_y();
+}
+
+
+//-------------------------------------------------
// resolve_tags - resolve tags, if any are set
//-------------------------------------------------
-void layout_view::item::resolve_tags()
+void layout_view_item::resolve_tags()
{
// resolve element state output and set default value
if (m_have_output)
@@ -4648,13 +4849,21 @@ void layout_view::item::resolve_tags()
m_output = m_element->default_state();
}
- // resolve animation state output
+ // resolve animation state and scroll outputs
if (m_have_animoutput)
m_animoutput.resolve();
+ if (m_have_scrollxoutput)
+ m_scrollxoutput.resolve();
+ if (m_have_scrollyoutput)
+ m_scrollyoutput.resolve();
- // resolve animation state input
+ // resolve animation state and scroll inputs
if (!m_animinput_tag.empty())
m_animinput_port = m_element->machine().root_device().ioport(m_animinput_tag);
+ if (!m_scrollxinput_tag.empty())
+ m_scrollxinput_port = m_element->machine().root_device().ioport(m_scrollxinput_tag);
+ if (!m_scrollyinput_tag.empty())
+ m_scrollyinput_port = m_element->machine().root_device().ioport(m_scrollyinput_tag);
// resolve element state input
if (!m_input_tag.empty())
@@ -4684,6 +4893,10 @@ void layout_view::item::resolve_tags()
m_get_anim_state = default_get_anim_state();
m_get_bounds = default_get_bounds();
m_get_color = default_get_color();
+ m_get_scroll_size_x = default_get_scroll_size_x();
+ m_get_scroll_size_y = default_get_scroll_size_y();
+ m_get_scroll_pos_x = default_get_scroll_pos_x();
+ m_get_scroll_pos_y = default_get_scroll_pos_y();
}
@@ -4692,18 +4905,18 @@ void layout_view::item::resolve_tags()
// state handler
//-------------------------------------------------
-layout_view::item::state_delegate layout_view::item::default_get_elem_state()
+layout_view_item::state_delegate layout_view_item::default_get_elem_state()
{
if (m_have_output)
- return state_delegate(&item::get_output, this);
+ return state_delegate(&layout_view_item::get_output, this);
else if (!m_input_port)
- return state_delegate(&item::get_state, this);
+ return state_delegate(&layout_view_item::get_state, this);
else if (m_input_raw)
- return state_delegate(&item::get_input_raw, this);
+ return state_delegate(&layout_view_item::get_input_raw, this);
else if (m_input_field)
- return state_delegate(&item::get_input_field_cached, this);
+ return state_delegate(&layout_view_item::get_input_field_cached, this);
else
- return state_delegate(&item::get_input_field_conditional, this);
+ return state_delegate(&layout_view_item::get_input_field_conditional, this);
}
@@ -4712,12 +4925,12 @@ layout_view::item::state_delegate layout_view::item::default_get_elem_state()
// state handler
//-------------------------------------------------
-layout_view::item::state_delegate layout_view::item::default_get_anim_state()
+layout_view_item::state_delegate layout_view_item::default_get_anim_state()
{
if (m_have_animoutput)
- return state_delegate(&item::get_anim_output, this);
+ return state_delegate(&layout_view_item::get_anim_output, this);
else if (m_animinput_port)
- return state_delegate(&item::get_anim_input, this);
+ return state_delegate(&layout_view_item::get_anim_input, this);
else
return default_get_elem_state();
}
@@ -4727,11 +4940,11 @@ layout_view::item::state_delegate layout_view::item::default_get_anim_state()
// default_get_bounds - get default bounds handler
//-------------------------------------------------
-layout_view::item::bounds_delegate layout_view::item::default_get_bounds()
+layout_view_item::bounds_delegate layout_view_item::default_get_bounds()
{
return (m_bounds.size() == 1U)
? bounds_delegate(&emu::render::detail::bounds_step::get, &m_bounds.front())
- : bounds_delegate(&item::get_interpolated_bounds, this);
+ : bounds_delegate(&layout_view_item::get_interpolated_bounds, this);
}
@@ -4739,11 +4952,65 @@ layout_view::item::bounds_delegate layout_view::item::default_get_bounds()
// default_get_color - get default color handler
//-------------------------------------------------
-layout_view::item::color_delegate layout_view::item::default_get_color()
+layout_view_item::color_delegate layout_view_item::default_get_color()
{
return (m_color.size() == 1U)
? color_delegate(&emu::render::detail::color_step::get, &const_cast<emu::render::detail::color_step &>(m_color.front()))
- : color_delegate(&item::get_interpolated_color, this);
+ : color_delegate(&layout_view_item::get_interpolated_color, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_size_x - get default
+// horizontal scroll window size handler
+//-------------------------------------------------
+
+layout_view_item::scroll_size_delegate layout_view_item::default_get_scroll_size_x()
+{
+ return scroll_size_delegate(&layout_view_item::get_scrollsizex, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_size_y - get default
+// vertical scroll window size handler
+//-------------------------------------------------
+
+layout_view_item::scroll_size_delegate layout_view_item::default_get_scroll_size_y()
+{
+ return scroll_size_delegate(&layout_view_item::get_scrollsizey, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_pos_x - get default
+// horizontal scroll position handler
+//-------------------------------------------------
+
+layout_view_item::scroll_pos_delegate layout_view_item::default_get_scroll_pos_x()
+{
+ if (m_have_scrollxoutput)
+ return scroll_pos_delegate(m_scrollwrapx ? &layout_view_item::get_scrollx_output<true> : &layout_view_item::get_scrollx_output<false>, this);
+ else if (m_scrollxinput_port)
+ return scroll_pos_delegate(m_scrollwrapx ? &layout_view_item::get_scrollx_input<true> : &layout_view_item::get_scrollx_input<false>, this);
+ else
+ return scroll_pos_delegate(&layout_view_item::get_scrollposx, this);
+}
+
+
+//-------------------------------------------------
+// default_get_scroll_pos_y - get default
+// vertical scroll position handler
+//-------------------------------------------------
+
+layout_view_item::scroll_pos_delegate layout_view_item::default_get_scroll_pos_y()
+{
+ if (m_have_scrollyoutput)
+ return scroll_pos_delegate(m_scrollwrapy ? &layout_view_item::get_scrolly_output<true> : &layout_view_item::get_scrolly_output<false>, this);
+ else if (m_scrollyinput_port)
+ return scroll_pos_delegate(m_scrollwrapy ? &layout_view_item::get_scrolly_input<true> : &layout_view_item::get_scrolly_input<false>, this);
+ else
+ return scroll_pos_delegate(&layout_view_item::get_scrollposy, this);
}
@@ -4751,7 +5018,7 @@ layout_view::item::color_delegate layout_view::item::default_get_color()
// get_state - get state when no bindings
//-------------------------------------------------
-int layout_view::item::get_state() const
+int layout_view_item::get_state() const
{
return m_elem_state;
}
@@ -4761,7 +5028,7 @@ int layout_view::item::get_state() const
// get_output - get element state output
//-------------------------------------------------
-int layout_view::item::get_output() const
+int layout_view_item::get_output() const
{
assert(m_have_output);
return int(s32(m_output));
@@ -4772,7 +5039,7 @@ int layout_view::item::get_output() const
// get_input_raw - get element state input
//-------------------------------------------------
-int layout_view::item::get_input_raw() const
+int layout_view_item::get_input_raw() const
{
assert(m_input_port);
return int(std::make_signed_t<ioport_value>((m_input_port->read() & m_input_mask) >> m_input_shift));
@@ -4783,7 +5050,7 @@ int layout_view::item::get_input_raw() const
// get_input_field_cached - element state
//-------------------------------------------------
-int layout_view::item::get_input_field_cached() const
+int layout_view_item::get_input_field_cached() const
{
assert(m_input_port);
assert(m_input_field);
@@ -4795,7 +5062,7 @@ int layout_view::item::get_input_field_cached() const
// get_input_field_conditional - element state
//-------------------------------------------------
-int layout_view::item::get_input_field_conditional() const
+int layout_view_item::get_input_field_conditional() const
{
assert(m_input_port);
assert(!m_input_field);
@@ -4808,7 +5075,7 @@ int layout_view::item::get_input_field_conditional() const
// get_anim_output - get animation output
//-------------------------------------------------
-int layout_view::item::get_anim_output() const
+int layout_view_item::get_anim_output() const
{
assert(m_have_animoutput);
return int(unsigned((u32(s32(m_animoutput) & m_animmask) >> m_animshift)));
@@ -4819,7 +5086,7 @@ int layout_view::item::get_anim_output() const
// get_anim_input - get animation input
//-------------------------------------------------
-int layout_view::item::get_anim_input() const
+int layout_view_item::get_anim_input() const
{
assert(m_animinput_port);
return int(std::make_signed_t<ioport_value>((m_animinput_port->read() & m_animmask) >> m_animshift));
@@ -4827,10 +5094,113 @@ int layout_view::item::get_anim_input() const
//-------------------------------------------------
+// get_scrollsizex - get horizontal scroll window
+// size
+//-------------------------------------------------
+
+float layout_view_item::get_scrollsizex() const
+{
+ return m_scrollsizex;
+}
+
+
+//-------------------------------------------------
+// get_scrollsizey - get vertical scroll window
+// size
+//-------------------------------------------------
+
+float layout_view_item::get_scrollsizey() const
+{
+ return m_scrollsizey;
+}
+
+
+//-------------------------------------------------
+// get_scrollposx - get horizontal scroll
+// position
+//-------------------------------------------------
+
+float layout_view_item::get_scrollposx() const
+{
+ return m_scrollposx;
+}
+
+
+//-------------------------------------------------
+// get_scrollposy - get vertical scroll position
+//-------------------------------------------------
+
+float layout_view_item::get_scrollposy() const
+{
+ return m_scrollposy;
+}
+
+
+//-------------------------------------------------
+// get_scrollx_output - get scaled horizontal
+// scroll output
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrollx_output() const
+{
+ assert(m_have_scrollxoutput);
+ u32 const unscaled(((u32(s32(m_scrollxoutput)) & m_scrollxmask) >> m_scrollxshift) - m_scrollxmin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollxmax - m_scrollxmin) + (!Wrap ? 0 : (m_scrollxmin < m_scrollxmax) ? 1 : -1));
+ return float(s32(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrollx_input - get scaled horizontal
+// scroll input
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrollx_input() const
+{
+ assert(m_scrollxinput_port);
+ ioport_value const unscaled(((m_scrollxinput_port->read() & m_scrollxmask) >> m_scrollxshift) - m_scrollxmin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollxmax - m_scrollxmin) + (!Wrap ? 0 : (m_scrollxmin < m_scrollxmax) ? 1 : -1));
+ return float(std::make_signed_t<ioport_value>(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrolly_output - get scaled vertical
+// scroll output
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrolly_output() const
+{
+ assert(m_have_scrollyoutput);
+ u32 const unscaled(((u32(s32(m_scrollyoutput)) & m_scrollymask) >> m_scrollyshift) - m_scrollymin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollymax - m_scrollymin) + (!Wrap ? 0 : (m_scrollymin < m_scrollymax) ? 1 : -1));
+ return float(s32(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
+// get_scrolly_input - get scaled vertical scroll
+// input
+//-------------------------------------------------
+
+template <bool Wrap>
+float layout_view_item::get_scrolly_input() const
+{
+ assert(m_scrollyinput_port);
+ ioport_value const unscaled(((m_scrollyinput_port->read() & m_scrollymask) >> m_scrollyshift) - m_scrollymin);
+ float const range(std::make_signed_t<ioport_value>(m_scrollymax - m_scrollymin) + (!Wrap ? 0 : (m_scrollymin < m_scrollymax) ? 1 : -1));
+ return float(std::make_signed_t<ioport_value>(unscaled)) / range;
+}
+
+
+//-------------------------------------------------
// get_interpolated_bounds - animated bounds
//-------------------------------------------------
-render_bounds layout_view::item::get_interpolated_bounds() const
+render_bounds layout_view_item::get_interpolated_bounds() const
{
assert(m_bounds.size() > 1U);
return interpolate_bounds(m_bounds, m_get_anim_state());
@@ -4841,7 +5211,7 @@ render_bounds layout_view::item::get_interpolated_bounds() const
// get_interpolated_color - animated color
//-------------------------------------------------
-render_color layout_view::item::get_interpolated_color() const
+render_color layout_view_item::get_interpolated_color() const
{
assert(m_color.size() > 1U);
return interpolate_color(m_color, m_get_anim_state());
@@ -4852,7 +5222,7 @@ render_color layout_view::item::get_interpolated_color() const
// find_element - find element definition
//-------------------------------------------------
-layout_element *layout_view::item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
+layout_element *layout_view_item::find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap)
{
std::string const name(env.get_attribute_string(itemnode, !strcmp(itemnode.get_name(), "element") ? "ref" : "element"));
if (name.empty())
@@ -4871,7 +5241,7 @@ layout_element *layout_view::item::find_element(view_environment &env, util::xml
// make_bounds - get transformed bounds
//-------------------------------------------------
-layout_view::item::bounds_vector layout_view::item::make_bounds(
+layout_view_item::bounds_vector layout_view_item::make_bounds(
view_environment &env,
util::xml::data_node const &itemnode,
layout_group::transform const &trans)
@@ -4904,7 +5274,7 @@ layout_view::item::bounds_vector layout_view::item::make_bounds(
// make_color - get color inflection points
//-------------------------------------------------
-layout_view::item::color_vector layout_view::item::make_color(
+layout_view_item::color_vector layout_view_item::make_color(
view_environment &env,
util::xml::data_node const &itemnode,
render_color const &mult)
@@ -4934,101 +5304,6 @@ layout_view::item::color_vector layout_view::item::make_color(
}
-//-------------------------------------------------
-// make_animoutput_tag - get animation output tag
-//-------------------------------------------------
-
-std::string layout_view::item::make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- if (animate)
- return std::string(env.get_attribute_string(*animate, "name"));
- else
- return std::string();
-}
-
-
-//-------------------------------------------------
-// make_animmask - get animation state mask
-//-------------------------------------------------
-
-ioport_value layout_view::item::make_animmask(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- return animate ? env.get_attribute_int(*animate, "mask", ~ioport_value(0)) : ~ioport_value(0);
-}
-
-
-//-------------------------------------------------
-// make_animinput_tag - get absolute tag for
-// animation input
-//-------------------------------------------------
-
-std::string layout_view::item::make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- util::xml::data_node const *const animate(itemnode.get_child("animate"));
- return animate ? env.get_attribute_subtag(*animate, "inputtag") : std::string();
-}
-
-
-//-------------------------------------------------
-// make_input_tag - get absolute input tag
-//-------------------------------------------------
-
-std::string layout_view::item::make_input_tag(view_environment &env, util::xml::data_node const &itemnode)
-{
- return env.get_attribute_subtag(itemnode, "inputtag");
-}
-
-
-//-------------------------------------------------
-// get_blend_mode - explicit or implicit blend
-//-------------------------------------------------
-
-int layout_view::item::get_blend_mode(view_environment &env, util::xml::data_node const &itemnode)
-{
- // see if there's a blend mode attribute
- std::string const *const mode(itemnode.get_attribute_string_ptr("blend"));
- if (mode)
- {
- if (*mode == "none")
- return BLENDMODE_NONE;
- else if (*mode == "alpha")
- return BLENDMODE_ALPHA;
- else if (*mode == "multiply")
- return BLENDMODE_RGB_MULTIPLY;
- else if (*mode == "add")
- return BLENDMODE_ADD;
- else
- throw layout_syntax_error(util::string_format("unknown blend mode %s", *mode));
- }
-
- // fall back to implicit blend mode based on element type
- if (!strcmp(itemnode.get_name(), "screen"))
- return -1; // magic number recognised by render.cpp to allow per-element blend mode
- else if (!strcmp(itemnode.get_name(), "overlay"))
- return BLENDMODE_RGB_MULTIPLY;
- else
- return BLENDMODE_ALPHA;
-}
-
-
-//-------------------------------------------------
-// get_state_shift - shift to right-align LSB
-//-------------------------------------------------
-
-unsigned layout_view::item::get_state_shift(ioport_value mask)
-{
- unsigned result(0U);
- while (mask && !BIT(mask, 0))
- {
- ++result;
- mask >>= 1;
- }
- return result;
-}
-
-
//**************************************************************************
// LAYOUT VIEW VISIBILITY TOGGLE
diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h
index 5b121d18880..befae560bcd 100644
--- a/src/emu/rendlay.h
+++ b/src/emu/rendlay.h
@@ -233,6 +233,178 @@ private:
};
+/// \brief A single item in a view
+///
+/// Each view has a list of item structures describing the visual
+/// elements to draw, where they are located, additional blending modes,
+/// and bindings for inputs and outputs.
+class layout_view_item
+{
+ friend class layout_view;
+
+public:
+ using view_environment = emu::render::detail::view_environment;
+ using element_map = std::unordered_map<std::string, layout_element>;
+ using state_delegate = delegate<int ()>;
+ using bounds_delegate = delegate<render_bounds ()>;
+ using color_delegate = delegate<render_color ()>;
+ using scroll_size_delegate = delegate<float ()>;
+ using scroll_pos_delegate = delegate<float ()>;
+
+ // construction/destruction
+ layout_view_item(
+ view_environment &env,
+ util::xml::data_node const &itemnode,
+ element_map &elemmap,
+ int orientation,
+ layout_group::transform const &trans,
+ render_color const &color);
+ ~layout_view_item();
+
+ // getters
+ std::string const &id() const { return m_id; }
+ layout_element *element() const { return m_element; }
+ screen_device *screen() const { return m_screen; }
+ bool bounds_animated() const { return m_bounds.size() > 1U; }
+ bool color_animated() const { return m_color.size() > 1U; }
+ render_bounds bounds() const { return m_get_bounds(); }
+ render_color color() const { return m_get_color(); }
+ bool scroll_wrap_x() const { return m_scrollwrapx; }
+ bool scroll_wrap_y() const { return m_scrollwrapy; }
+ float scroll_size_x() const { return m_get_scroll_size_x(); }
+ float scroll_size_y() const { return m_get_scroll_size_y(); }
+ float scroll_pos_x() const { return m_get_scroll_pos_x(); }
+ float scroll_pos_y() const { return m_get_scroll_pos_y(); }
+ int blend_mode() const { return m_blend_mode; }
+ u32 visibility_mask() const { return m_visibility_mask; }
+ int orientation() const { return m_orientation; }
+ render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
+
+ // interactivity
+ bool has_input() const { return bool(m_input_port); }
+ std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
+ bool clickthrough() const { return m_clickthrough; }
+
+ // fetch state based on configured source
+ int element_state() const { return m_get_elem_state(); }
+ int animation_state() const { return m_get_anim_state(); }
+
+ // set state
+ void set_state(int state) { m_elem_state = state; }
+ void set_scroll_size_x(float size) { m_scrollsizex = std::clamp(size, 0.01f, 1.0f); }
+ void set_scroll_size_y(float size) { m_scrollsizey = std::clamp(size, 0.01f, 1.0f); }
+ void set_scroll_pos_x(float pos) { m_scrollposx = pos; }
+ void set_scroll_pos_y(float pos) { m_scrollposy = pos; }
+
+ // set handlers
+ void set_element_state_callback(state_delegate &&handler);
+ void set_animation_state_callback(state_delegate &&handler);
+ void set_bounds_callback(bounds_delegate &&handler);
+ void set_color_callback(color_delegate &&handler);
+ void set_scroll_size_x_callback(scroll_size_delegate &&handler);
+ void set_scroll_size_y_callback(scroll_size_delegate &&handler);
+ void set_scroll_pos_x_callback(scroll_pos_delegate &&handler);
+ void set_scroll_pos_y_callback(scroll_pos_delegate &&handler);
+
+ // resolve tags, if any
+ void resolve_tags();
+
+private:
+ using bounds_vector = emu::render::detail::bounds_vector;
+ using color_vector = emu::render::detail::color_vector;
+
+ state_delegate default_get_elem_state();
+ state_delegate default_get_anim_state();
+ bounds_delegate default_get_bounds();
+ color_delegate default_get_color();
+ scroll_size_delegate default_get_scroll_size_x();
+ scroll_size_delegate default_get_scroll_size_y();
+ scroll_pos_delegate default_get_scroll_pos_x();
+ scroll_pos_delegate default_get_scroll_pos_y();
+ int get_state() const;
+ int get_output() const;
+ int get_input_raw() const;
+ int get_input_field_cached() const;
+ int get_input_field_conditional() const;
+ int get_anim_output() const;
+ int get_anim_input() const;
+ float get_scrollsizex() const;
+ float get_scrollsizey() const;
+ float get_scrollposx() const;
+ float get_scrollposy() const;
+ template <bool Wrap> float get_scrollx_output() const;
+ template <bool Wrap> float get_scrolly_output() const;
+ template <bool Wrap> float get_scrollx_input() const;
+ template <bool Wrap> float get_scrolly_input() const;
+ render_bounds get_interpolated_bounds() const;
+ render_color get_interpolated_color() const;
+
+ static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
+ static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
+ static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
+
+ // internal state
+ layout_element *const m_element; // pointer to the associated element (non-screens only)
+ state_delegate m_get_elem_state; // resolved element state function
+ state_delegate m_get_anim_state; // resolved animation state function
+ bounds_delegate m_get_bounds; // resolved bounds function
+ color_delegate m_get_color; // resolved color function
+ scroll_size_delegate m_get_scroll_size_x; // resolved horizontal scroll window size function
+ scroll_size_delegate m_get_scroll_size_y; // resolved vertical scroll window size function
+ scroll_pos_delegate m_get_scroll_pos_x; // resolved horizontal scroll position function
+ scroll_pos_delegate m_get_scroll_pos_y; // resolved vertical scroll position function
+ output_finder<> m_output; // associated output
+ output_finder<> m_animoutput; // associated output for animation if different
+ output_finder<> m_scrollxoutput; // associated output for horizontal scroll position
+ output_finder<> m_scrollyoutput; // associated output for vertical scroll position
+ ioport_port * m_animinput_port; // input port used for animation
+ ioport_port * m_scrollxinput_port; // input port used for horizontal scrolling
+ ioport_port * m_scrollyinput_port; // input port used for vertical scrolling
+ bool const m_scrollwrapx; // whether horizontal scrolling works like a loop
+ bool const m_scrollwrapy; // whether vertical scrolling works like a loop
+ int m_elem_state; // element state used in absence of bindings
+ float m_scrollsizex; // horizontal scroll window size used in absence of bindings
+ float m_scrollsizey; // vertical scroll window size used in absence of bindings
+ float m_scrollposx; // horizontal scroll position used in absence of bindings
+ float m_scrollposy; // vertical scroll position used in absence of bindings
+ ioport_value const m_animmask; // mask for animation state
+ ioport_value const m_scrollxmask; // mask for horizontal scroll position
+ ioport_value const m_scrollymask; // mask for vertical scroll position
+ ioport_value const m_scrollxmin; // minimum value for horizontal scroll position
+ ioport_value const m_scrollymin; // minimum value for vertical scroll position
+ ioport_value const m_scrollxmax; // maximum value for horizontal scroll position
+ ioport_value const m_scrollymax; // maximum value for vertical scroll position
+ u8 const m_animshift; // shift for animation state
+ u8 const m_scrollxshift; // shift for horizontal scroll position
+ u8 const m_scrollyshift; // shift for vertical scroll position
+ ioport_port * m_input_port; // input port of this item
+ ioport_field const * m_input_field; // input port field of this item
+ ioport_value const m_input_mask; // input mask of this item
+ u8 const m_input_shift; // input mask rightshift for raw (trailing 0s)
+ bool m_clickthrough; // should click pass through to lower elements
+ screen_device * m_screen; // pointer to screen
+ int const m_orientation; // orientation of this item
+ bounds_vector m_bounds; // bounds of the item
+ color_vector const m_color; // color of the item
+ int m_blend_mode; // blending mode to use when drawing
+ u32 m_visibility_mask; // combined mask of parent visibility groups
+
+ // cold items
+ std::string const m_id; // optional unique item identifier
+ std::string const m_input_tag; // input tag of this item
+ std::string const m_animinput_tag; // tag of input port for animation state
+ std::string const m_scrollxinput_tag; // tag of input port for horizontal scroll position
+ std::string const m_scrollyinput_tag; // tag of input port for vertical scroll position
+ bounds_vector const m_rawbounds; // raw (original) bounds of the item
+ bool const m_have_output; // whether we actually have an output
+ bool const m_input_raw; // get raw data from input port
+ bool const m_have_animoutput; // whether we actually have an output for animation
+ bool const m_have_scrollxoutput; // whether we actually have an output for horizontal scroll
+ bool const m_have_scrollyoutput; // whether we actually have an output for vertical scroll
+ bool const m_has_clickthrough; // whether clickthrough was explicitly configured
+};
+
+
/// \brief A single view within a #layout_file
///
/// The view is described using arbitrary coordinates that are scaled to
@@ -243,133 +415,14 @@ class layout_view
public:
using layout_environment = emu::render::detail::layout_environment;
using view_environment = emu::render::detail::view_environment;
- using element_map = std::unordered_map<std::string, layout_element>;
+ using element_map = layout_view_item::element_map;
using group_map = std::unordered_map<std::string, layout_group>;
using screen_ref_vector = std::vector<std::reference_wrapper<screen_device const>>;
using prepare_items_delegate = delegate<void ()>;
using preload_delegate = delegate<void ()>;
using recomputed_delegate = delegate<void ()>;
- /// \brief A single item in a view
- ///
- /// Each view has a list of item structures describing the visual
- /// elements to draw, where they are located, additional blending
- /// modes, and bindings for inputs and outputs.
- class item
- {
- friend class layout_view;
-
- public:
- using state_delegate = delegate<int ()>;
- using bounds_delegate = delegate<render_bounds ()>;
- using color_delegate = delegate<render_color ()>;
-
- // construction/destruction
- item(
- view_environment &env,
- util::xml::data_node const &itemnode,
- element_map &elemmap,
- int orientation,
- layout_group::transform const &trans,
- render_color const &color);
- ~item();
-
- // getters
- std::string const &id() const { return m_id; }
- layout_element *element() const { return m_element; }
- screen_device *screen() const { return m_screen; }
- bool bounds_animated() const { return m_bounds.size() > 1U; }
- bool color_animated() const { return m_color.size() > 1U; }
- render_bounds bounds() const { return m_get_bounds(); }
- render_color color() const { return m_get_color(); }
- int blend_mode() const { return m_blend_mode; }
- u32 visibility_mask() const { return m_visibility_mask; }
- int orientation() const { return m_orientation; }
- render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }
-
- // interactivity
- bool has_input() const { return bool(m_input_port); }
- std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
- bool clickthrough() const { return m_clickthrough; }
-
- // fetch state based on configured source
- int element_state() const { return m_get_elem_state(); }
- int animation_state() const { return m_get_anim_state(); }
-
- // set state
- void set_state(int state) { m_elem_state = state; }
-
- // set handlers
- void set_element_state_callback(state_delegate &&handler);
- void set_animation_state_callback(state_delegate &&handler);
- void set_bounds_callback(bounds_delegate &&handler);
- void set_color_callback(color_delegate &&handler);
-
- // resolve tags, if any
- void resolve_tags();
-
- private:
- using bounds_vector = emu::render::detail::bounds_vector;
- using color_vector = emu::render::detail::color_vector;
-
- state_delegate default_get_elem_state();
- state_delegate default_get_anim_state();
- bounds_delegate default_get_bounds();
- color_delegate default_get_color();
- int get_state() const;
- int get_output() const;
- int get_input_raw() const;
- int get_input_field_cached() const;
- int get_input_field_conditional() const;
- int get_anim_output() const;
- int get_anim_input() const;
- render_bounds get_interpolated_bounds() const;
- render_color get_interpolated_color() const;
-
- static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
- static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
- static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);
- static std::string make_animoutput_tag(view_environment &env, util::xml::data_node const &itemnode);
- static std::string make_animinput_tag(view_environment &env, util::xml::data_node const &itemnode);
- static ioport_value make_animmask(view_environment &env, util::xml::data_node const &itemnode);
- static std::string make_input_tag(view_environment &env, util::xml::data_node const &itemnode);
- static int get_blend_mode(view_environment &env, util::xml::data_node const &itemnode);
- static unsigned get_state_shift(ioport_value mask);
-
- // internal state
- layout_element *const m_element; // pointer to the associated element (non-screens only)
- state_delegate m_get_elem_state; // resolved element state function
- state_delegate m_get_anim_state; // resolved animation state function
- bounds_delegate m_get_bounds; // resolved bounds function
- color_delegate m_get_color; // resolved color function
- output_finder<> m_output; // associated output
- output_finder<> m_animoutput; // associated output for animation if different
- ioport_port * m_animinput_port; // input port used for animation
- int m_elem_state; // element state used in absence of bindings
- ioport_value const m_animmask; // mask for animation state
- u8 const m_animshift; // shift for animation state
- ioport_port * m_input_port; // input port of this item
- ioport_field const * m_input_field; // input port field of this item
- ioport_value const m_input_mask; // input mask of this item
- u8 const m_input_shift; // input mask rightshift for raw (trailing 0s)
- bool m_clickthrough; // should click pass through to lower elements
- screen_device * m_screen; // pointer to screen
- int const m_orientation; // orientation of this item
- bounds_vector m_bounds; // bounds of the item
- color_vector const m_color; // color of the item
- int m_blend_mode; // blending mode to use when drawing
- u32 m_visibility_mask; // combined mask of parent visibility groups
-
- // cold items
- std::string const m_id; // optional unique item identifier
- std::string const m_input_tag; // input tag of this item
- std::string const m_animinput_tag; // tag of input port for animation state
- bounds_vector const m_rawbounds; // raw (original) bounds of the item
- bool const m_have_output; // whether we actually have an output
- bool const m_input_raw; // get raw data from input port
- bool const m_have_animoutput; // whether we actually have an output for animation
- bool const m_has_clickthrough; // whether clickthrough was explicitly configured
- };
+ using item = layout_view_item;
using item_list = std::list<item>;
using item_ref_vector = std::vector<std::reference_wrapper<item> >;