mirror of
https://github.com/holub/mame
synced 2025-06-03 03:16:30 +03:00
emu/render.cpp, emu/rendlay.cpp: Added scroll support for all elements.
This commit is contained in:
parent
ded9ecfc1c
commit
5afce6cfab
@ -406,8 +406,8 @@ usually comes from an I/O port field or an emulated output (see
|
||||
:ref:`layfile-interact-elemstate` for information on connecting an element to an
|
||||
emulated I/O port or output). Any component of an element may be restricted to
|
||||
only drawing when the element’s state is a particular value. Some components
|
||||
(e.g. multi-segment displays and reels) use the state directly to determine
|
||||
their appearance.
|
||||
(e.g. multi-segment displays) use the state directly to determine their
|
||||
appearance.
|
||||
|
||||
Each element has its own internal coordinate system. The bounds of the
|
||||
element’s coordinate system are computed as the union of the bounds of the
|
||||
@ -591,10 +591,6 @@ simplecounter
|
||||
to set text alignment. If present, the ``align`` attribute must be an
|
||||
integer, where 0 (zero) means centred, 1 (one) means left-aligned, and 2
|
||||
(two) means right-aligned; if absent, the text will be centred.
|
||||
reel
|
||||
Used for drawing slot machine reels. Supported attributes include
|
||||
``symbollist``, ``stateoffset``, ``numsymbolsvisible``, ``reelreversed``,
|
||||
and ``beltreel``.
|
||||
|
||||
An example element that draws a static left-aligned text string:
|
||||
|
||||
@ -839,6 +835,48 @@ have their colour and position/size animated by supplying multiple ``color``
|
||||
and/or ``bounds`` child elements with ``state`` attributes. See
|
||||
:ref:`layfile-interact-itemanim` for details.
|
||||
|
||||
Layout elements (``element`` elements) may be configured to show only part of
|
||||
the element’s width or height using ``xscroll`` and/or ``yscroll`` child
|
||||
elements. This can be used for devices like slot machine reels. The
|
||||
``xscroll`` and ``yscroll`` elements support the same attributes:
|
||||
|
||||
size
|
||||
The size of the horizontal or vertical scroll window, as a proportion of the
|
||||
element’s width or height, respectively. Must be in the range 0.01 to 1.0,
|
||||
inclusive, if present (1% of the width/height to the full width/height). By
|
||||
default, the entire width and height of the element is shown.
|
||||
wrap
|
||||
Whether the element should wrap horizontally or vertically. Must be either
|
||||
``yes`` or ``no`` if present. By default, items do not wrap horizontally or
|
||||
vertically.
|
||||
inputtag
|
||||
If present, the horizontal or vertical scroll position will be taken from
|
||||
the value of the corresponding I/O port. Specifies the tag path of an I/O
|
||||
port relative to the device that caused the layout file to be loaded. The
|
||||
raw value from the input port is used, active-low switch values are not
|
||||
normalised.
|
||||
name
|
||||
If present, the horizontal or vertical scroll position will be taken from
|
||||
the correspondingly named output.
|
||||
mask
|
||||
If present, the horizontal or vertical scroll position will be masked with
|
||||
the value and shifted to the right to remove trailing zeroes (for example a
|
||||
mask of 0x05 will result in no shift, while a mask of 0x68 will result in
|
||||
the value being shifted three bits to the right). Note that this applies to
|
||||
output values (specified with the ``name`` attribute) as well as input port
|
||||
values (specified with the ``inputtag`` attribute). Must be an integer
|
||||
value if present. If not present, it is equivalent to all 32 bits being
|
||||
set.
|
||||
min
|
||||
Minimum horizontal or vertical scroll position value. When the horizontal
|
||||
or vertical scroll position has this value, the left or top edge or the
|
||||
scroll window will be aligned with the left or top edge of the element.
|
||||
Must be an integer value if present. Defaults to zero.
|
||||
max
|
||||
Maximum horizontal or vertical scroll position value. Must be an integer
|
||||
value if present. Defaults to the ``mask`` value shifted to the right to
|
||||
remove trailing zeroes.
|
||||
|
||||
|
||||
.. _layfile-parts-collections:
|
||||
|
||||
@ -1149,9 +1187,8 @@ Clickable items
|
||||
item will activate the emulated switch.
|
||||
State-dependent components
|
||||
Some components will be drawn differently depending on the containing
|
||||
element’s state. These include the dot matrix, multi-segment LED display,
|
||||
simple counter and reel elements. See :ref:`layfile-parts-elements` for
|
||||
details.
|
||||
element’s state. These include the dot matrix, multi-segment LED display
|
||||
and simple counter elements. See :ref:`layfile-parts-elements` for details.
|
||||
Conditionally-drawn components
|
||||
Components may be conditionally drawn or hidden depending on the containing
|
||||
element’s state by supplying ``state`` and/or ``statemask`` attributes. See
|
||||
@ -1298,7 +1335,7 @@ If the ``animate`` child element has a ``mask`` attribute, the item’s animatio
|
||||
state will be masked with the ``mask`` value and shifted to the right to remove
|
||||
trailing zeroes (for example a mask of 0x05 will result in no shift, while a
|
||||
mask of 0xb0 will result in the value being shifted four bits to the right).
|
||||
Note that the ``mask`` attribute applies to output value (specified with the
|
||||
Note that the ``mask`` attribute applies to output values (specified with the
|
||||
``name`` attribute) as well as input port values (specified with the
|
||||
``inputtag`` attribute). If the ``mask`` attribute is present, it must be an
|
||||
integer value. If the ``mask`` attribute is not present, it is equivalent to
|
||||
|
@ -259,7 +259,7 @@ Here’s our layout file:
|
||||
<bounds x="0" y="0" width="0.1" height="0.1" />
|
||||
<color alpha="0" />
|
||||
</rect>
|
||||
<!-- draw the outlined of a square -->
|
||||
<!-- draw the outline of a square -->
|
||||
<rect><bounds x="0.02" y="0.02" width="0.06" height="0.01" /></rect>
|
||||
<rect><bounds x="0.02" y="0.07" width="0.06" height="0.01" /></rect>
|
||||
<rect><bounds x="0.02" y="0.02" width="0.01" height="0.06" /></rect>
|
||||
@ -289,7 +289,7 @@ Here’s our layout file:
|
||||
<element id="vertical" ref="line">
|
||||
<!-- element draws a vertical line, no need to rotate it -->
|
||||
<orientation rotate="0" />
|
||||
<!-- centre it in the square horizotnally, using the full height -->
|
||||
<!-- centre it in the square horizontally, using the full height -->
|
||||
<bounds x="4.55" y="1.9" width="0.1" height="1" />
|
||||
</element>
|
||||
|
||||
@ -301,7 +301,7 @@ Here’s our layout file:
|
||||
<bounds x="4.1" y="2.35" width="1" height="0.1" />
|
||||
</element>
|
||||
|
||||
<!-- draw a small box at the intersection of the vertical and horiztonal lines -->
|
||||
<!-- draw a small box at the intersection of the vertical and horizontal lines -->
|
||||
<element id="box" ref="box">
|
||||
<bounds x="4.55" y="2.35" width="0.1" height="0.1" />
|
||||
</element>
|
||||
@ -595,7 +595,7 @@ Get item bounds
|
||||
argument to restore the default bounds handler (based on the item’s
|
||||
animation state and ``bounds`` child elements).
|
||||
Get item colour
|
||||
``item::set_color_callback(cb)``
|
||||
``item:set_color_callback(cb)``
|
||||
|
||||
Set callback for getting the item’s colour (the element texture’s colours
|
||||
multiplied by this colour). Do not attempt to access the item’s ``color``
|
||||
@ -605,3 +605,59 @@ Get item colour
|
||||
ARGB colour (usually created by calling ``emu.render_color``), and takes no
|
||||
parameters. Call with ``nil`` as the argument to restore the default colour
|
||||
handler (based on the item’s animation state and ``color`` child elements).
|
||||
Get item horizontal scroll window size
|
||||
``item:set_scroll_size_x_callback(cb)``
|
||||
|
||||
Set callback for getting the item’s horizontal scroll window size. This
|
||||
allows the script to control how much of the element is displayed by the
|
||||
item. Do not attempt to access the item’s ``scroll_size_x`` property from
|
||||
the callback, as it will result in infinite recursion.
|
||||
|
||||
The callback function must return a floating-point number representing the
|
||||
horizontal window size as a proportion of the associated element’s width,
|
||||
and takes no parameters. A value of 1.0 will display the entire width of
|
||||
the element; smaller values will display proportionally smaller parts of the
|
||||
element. Call with ``nil`` as the argument to to restore the default
|
||||
horizontal scroll window size handler (based on the ``xscroll`` child
|
||||
element).
|
||||
Get item vertical scroll window size
|
||||
``item:set_scroll_size_y_callback(cb)``
|
||||
|
||||
Set callback for getting the item’s vertical scroll window size. This
|
||||
allows the script to control how much of the element is displayed by the
|
||||
item. Do not attempt to access the item’s ``scroll_size_y`` property from
|
||||
the callback, as it will result in infinite recursion.
|
||||
|
||||
The callback function must return a floating-point number representing the
|
||||
vertical window size as a proportion of the associated element’s height, and
|
||||
takes no parameters. A value of 1.0 will display the entire height of the
|
||||
element; smaller values will display proportionally smaller parts of the
|
||||
element. Call with ``nil`` as the argument to to restore the default
|
||||
vertical scroll window size handler (based on the ``xscroll`` child
|
||||
element).
|
||||
Get item horizontal scroll position
|
||||
``item:set_scroll_pos_x_callback(cb)``
|
||||
|
||||
Set callback for getting the item’s horizontal scroll position. This allows
|
||||
the script to control which part of the element is displayed by the item.
|
||||
Do not attempt to access the item’s ``scroll_pos_x`` property from the
|
||||
callback, as this will result in infinite recursion.
|
||||
|
||||
The callback must return a floating-point number, and takes no parameters.
|
||||
A value of 0.0 aligns the left edge of the element with the left edge of the
|
||||
item; larger values pan right. Call with ``nil`` as the argument to restore
|
||||
the default horizontal scroll position handler (based on bindings in the
|
||||
``xscroll`` child element).
|
||||
Get item vertical scroll position
|
||||
``item:set_scroll_pos_y_callback(cb)``
|
||||
|
||||
Set callback for getting the item’s vertical scroll position. This allows
|
||||
the script to control which part of the element is displayed by the item.
|
||||
Do not attempt to access the item’s ``scroll_pos_y`` property from the
|
||||
callback, as this will result in infinite recursion.
|
||||
|
||||
The callback must return a floating-point number, and takes no parameters.
|
||||
A value of 0.0 aligns the top edge of the element with the top edge of the
|
||||
item; larger values pan down. Call with ``nil`` as the argument to restore
|
||||
the default vertical scroll position handler (based on bindings in the
|
||||
``yscroll`` child element).
|
||||
|
@ -2815,7 +2815,7 @@ view.has_art
|
||||
Layout view item
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Wraps MAME’s ``layout_view::item`` class, representing an item in a view. An
|
||||
Wraps MAME’s ``layout_view_item`` class, representing an item in a view. An
|
||||
item is drawn as a rectangular textured surface. The texture is supplied by an
|
||||
emulated screen or a layout element.
|
||||
|
||||
@ -2832,7 +2832,7 @@ Methods
|
||||
item:set_state(state)
|
||||
Set the value used as the element state and animation state in the absence
|
||||
of bindings. The argument must be an integer.
|
||||
item.set_element_state_callback(cb)
|
||||
item:set_element_state_callback(cb)
|
||||
Set a function to call to obtain the element state for the item. The
|
||||
function must accept no arguments and return an integer. Call with ``nil``
|
||||
to restore the default element state callback (based on bindings in the XML
|
||||
@ -2844,7 +2844,7 @@ item.set_element_state_callback(cb)
|
||||
This callback will not be used to obtain the animation state for the item,
|
||||
even if the item lacks explicit animation state bindings in the XML layout
|
||||
file.
|
||||
item.set_animation_state_callback(cb)
|
||||
item:set_animation_state_callback(cb)
|
||||
Set a function to call to obtain the animation state for the item. The
|
||||
function must accept no arguments and return an integer. Call with ``nil``
|
||||
to restore the default animation state callback (based on bindings in the
|
||||
@ -2852,7 +2852,7 @@ item.set_animation_state_callback(cb)
|
||||
|
||||
Note that the function must not access the item’s ``animation_state``
|
||||
property, as this will result in infinite recursion.
|
||||
item.set_bounds_callback(cb)
|
||||
item:set_bounds_callback(cb)
|
||||
Set a function to call to obtain the bounds for the item. The function must
|
||||
accept no arguments and return a
|
||||
:ref:`render bounds <luareference-render-bounds>` object in render target
|
||||
@ -2862,7 +2862,7 @@ item.set_bounds_callback(cb)
|
||||
|
||||
Note that the function must not access the item’s ``bounds`` property, as
|
||||
this will result in infinite recursion.
|
||||
item.set_color_callback(cb)
|
||||
item:set_color_callback(cb)
|
||||
Set a function to call to obtain the multiplier colour for the item. The
|
||||
function must accept no arguments and return a
|
||||
:ref:`render colour <luareference-render-color>` object. Call with ``nil``
|
||||
@ -2871,6 +2871,50 @@ item.set_color_callback(cb)
|
||||
|
||||
Note that the function must not access the item’s ``color`` property, as
|
||||
this will result in infinite recursion.
|
||||
item:set_scroll_size_x_callback(cb)
|
||||
Set a function to call to obtain the size of the horizontal scroll window as
|
||||
a proportion of the associated element’s width. The function must accept no
|
||||
arguments and return a floating-point value. Call with ``nil`` to restore
|
||||
the default horizontal scroll window size callback (based on the ``xscroll``
|
||||
child element in the XML layout file).
|
||||
|
||||
Note that the function must not access the item’s ``scroll_size_x``
|
||||
property, as this will result in infinite recursion.
|
||||
item:set_scroll_size_y_callback(cb)
|
||||
Set a function to call to obtain the size of the vertical scroll window as a
|
||||
proportion of the associated element’s height. The function must accept no
|
||||
arguments and return a floating-point value. Call with ``nil`` to restore
|
||||
the default vertical scroll window size callback (based on the ``yscroll``
|
||||
child element in the XML layout file).
|
||||
|
||||
Note that the function must not access the item’s ``scroll_size_y``
|
||||
property, as this will result in infinite recursion.
|
||||
item:set_scroll_pos_x_callback(cb)
|
||||
Set a function to call to obtain the horizontal scroll position. A value of
|
||||
zero places the horizontal scroll window at the left edge of the associated
|
||||
element. If the item does not wrap horizontally, a value of 1.0 places the
|
||||
horizontal scroll window at the right edge of the associated element; if the
|
||||
item wraps horizontally, a value of 1.0 corresponds to wrapping back to the
|
||||
left edge of the associated element. The function must accept no arguments
|
||||
and return a floating-point value. Call with ``nil`` to restore the default
|
||||
horizontal scroll position callback (based on bindings in the ``xscroll``
|
||||
child element in the XML layout file).
|
||||
|
||||
Note that the function must not access the item’s ``scroll_pos_x`` property,
|
||||
as this will result in infinite recursion.
|
||||
item:set_scroll_pos_y_callback(cb)
|
||||
Set a function to call to obtain the vertical scroll position. A value of
|
||||
zero places the vertical scroll window at the top edge of the associated
|
||||
element. If the item does not wrap vertically, a value of 1.0 places the
|
||||
vertical scroll window at the bottom edge of the associated element; if the
|
||||
item wraps vertically, a value of 1.0 corresponds to wrapping back to the
|
||||
left edge of the associated element. The function must accept no arguments
|
||||
and return a floating-point value. Call with ``nil`` to restore the default
|
||||
vertical scroll position callback (based on bindings in the ``yscroll``
|
||||
child element in the XML layout file).
|
||||
|
||||
Note that the function must not access the item’s ``scroll_pos_y`` property,
|
||||
as this will result in infinite recursion.
|
||||
|
||||
Properties
|
||||
^^^^^^^^^^
|
||||
@ -2892,6 +2936,28 @@ item.color (read-only)
|
||||
The item’s colour for the current state. The colour of the screen or
|
||||
element texture is multiplied by this colour. This is a
|
||||
:ref:`render colour <luareference-render-color>` object.
|
||||
item.scroll_wrap_x (read-only)
|
||||
A Boolean indicating whether the item wraps horizontally.
|
||||
item.scroll_wrap_y (read-only)
|
||||
A Boolean indicating whether the item wraps vertically.
|
||||
item.scroll_size_x (read/write)
|
||||
Get the item’s horizontal scroll window size for the current state, or set
|
||||
the horizontal scroll window size to use in the absence of bindings. This
|
||||
is a floating-point value representing a proportion of the associated
|
||||
element’s width.
|
||||
item.scroll_size_y (read/write)
|
||||
Get the item’s vertical scroll window size for the current state, or set the
|
||||
vertical scroll window size to use in the absence of bindings. This is a
|
||||
floating-point value representing a proportion of the associated element’s
|
||||
height.
|
||||
item.scroll_pos_x (read/write)
|
||||
Get the item’s horizontal scroll position for the current state, or set the
|
||||
horizontal scroll position size to use in the absence of bindings. This is
|
||||
a floating-point value.
|
||||
item.scroll_pos_y (read/write)
|
||||
Get the item’s vertical scroll position for the current state, or set the
|
||||
vertical position size to use in the absence of bindings. This is a
|
||||
floating-point value.
|
||||
item.blend_mode (read-only)
|
||||
Get the item’s blend mode. This is an integer value, where 0 means no
|
||||
blending, 1 means alpha blending, 2 means RGB multiplication, 3 means
|
||||
|
@ -253,7 +253,7 @@ class LayoutChecker(Minifyer):
|
||||
if self.checkIntAttribute('orientation', attrs, 'rotate', 0) not in self.ORIENTATIONS:
|
||||
self.handleError('Element orientation attribute rotate "%s" is unsupported' % (attrs['rotate'], ))
|
||||
for name in ('swapxy', 'flipx', 'flipy'):
|
||||
if (attrs.get(name, 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs['yesno'])):
|
||||
if (attrs.get(name, 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs[name])):
|
||||
self.handleError('Element orientation attribute %s "%s" is not "yes" or "no"' % (name, attrs[name]))
|
||||
|
||||
def checkColor(self, attrs):
|
||||
@ -332,6 +332,8 @@ class LayoutChecker(Minifyer):
|
||||
self.have_bounds.append(None if 'group' == name else { })
|
||||
self.have_orientation.append(False)
|
||||
self.have_color.append(None if 'group' == name else { })
|
||||
self.have_xscroll.append(None if ('group' == name) or ('screen' == name) else False)
|
||||
self.have_yscroll.append(None if ('group' == name) or ('screen' == name) else False)
|
||||
|
||||
def rootStartHandler(self, name, attrs):
|
||||
if 'mamelayout' != name:
|
||||
@ -665,6 +667,24 @@ class LayoutChecker(Minifyer):
|
||||
else:
|
||||
self.handleError('Duplicate element color (previous %s)' % (self.have_color[-1], ))
|
||||
self.checkColor(attrs)
|
||||
elif ('xscroll' == name) or ('yscroll' == name):
|
||||
have_scroll = self.have_xscroll if 'xscroll' == name else self.have_yscroll
|
||||
if have_scroll[-1] is None:
|
||||
self.handleError('Encountered unexpected element %s' % (name, ))
|
||||
elif have_scroll[-1]:
|
||||
self.handleError('Duplicate element %s' % (name, ))
|
||||
else:
|
||||
have_scroll[-1] = self.formatLocation()
|
||||
self.checkFloatAttribute(name, attrs, 'size', 1.0)
|
||||
if (attrs.get('wrap', 'no') not in self.YESNO) and (not self.VARPATTERN.match(attrs['wrap'])):
|
||||
self.handleError('Element %s attribute wrap "%s" is not "yes" or "no"' % (name, attrs['wrap']))
|
||||
if 'inputtag' in attrs:
|
||||
if 'name' in attrs:
|
||||
self.handleError('Element %s has both attribute inputtag and attribute name' % (name, ))
|
||||
self.checkTag(attrs['inputtag'], name, 'inputtag')
|
||||
self.checkIntAttribute(name, attrs, 'mask', None)
|
||||
self.checkIntAttribute(name, attrs, 'min', None)
|
||||
self.checkIntAttribute(name, attrs, 'max', None)
|
||||
else:
|
||||
self.handleError('Encountered unexpected element %s' % (name, ))
|
||||
self.ignored_depth = 1
|
||||
@ -673,6 +693,8 @@ class LayoutChecker(Minifyer):
|
||||
self.have_bounds.pop()
|
||||
self.have_orientation.pop()
|
||||
self.have_color.pop()
|
||||
self.have_xscroll.pop()
|
||||
self.have_yscroll.pop()
|
||||
self.handlers.pop()
|
||||
|
||||
def setDocumentLocator(self, locator):
|
||||
@ -688,6 +710,8 @@ class LayoutChecker(Minifyer):
|
||||
self.have_bounds = [ ]
|
||||
self.have_orientation = [ ]
|
||||
self.have_color = [ ]
|
||||
self.have_xscroll = [ ]
|
||||
self.have_yscroll = [ ]
|
||||
self.generated_element_names = False
|
||||
self.generated_group_names = False
|
||||
super(LayoutChecker, self).startDocument()
|
||||
@ -709,6 +733,8 @@ class LayoutChecker(Minifyer):
|
||||
del self.have_bounds
|
||||
del self.have_orientation
|
||||
del self.have_color
|
||||
del self.have_xscroll
|
||||
del self.have_yscroll
|
||||
del self.generated_element_names
|
||||
del self.generated_group_names
|
||||
super(LayoutChecker, self).endDocument()
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
@ -4634,11 +4779,67 @@ 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,18 +5086,121 @@ 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));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// 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
|
||||
|
@ -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> >;
|
||||
|
||||
|
@ -39,7 +39,7 @@ struct layout_view_items
|
||||
layout_view_items(layout_view &v) : view(v) { }
|
||||
layout_view::item_list &items() { return view.items(); }
|
||||
|
||||
static layout_view::item &unwrap(layout_view::item_list::iterator const &it) { return *it; }
|
||||
static layout_view_item &unwrap(layout_view::item_list::iterator const &it) { return *it; }
|
||||
static int push_key(lua_State *L, layout_view::item_list::iterator const &it, std::size_t ix) { return sol::stack::push(L, ix + 1); }
|
||||
|
||||
layout_view &view;
|
||||
@ -97,7 +97,7 @@ public:
|
||||
{
|
||||
layout_view_items &self(get_self(L));
|
||||
char const *const id(stack::unqualified_get<char const *>(L));
|
||||
layout_view::item *const item(self.view.get_item(id));
|
||||
layout_view_item *const item(self.view.get_item(id));
|
||||
if (item)
|
||||
return stack::push_reference(L, *item);
|
||||
else
|
||||
@ -279,48 +279,86 @@ void lua_engine::initialize_render(sol::table &emu)
|
||||
layout_view_type["has_art"] = sol::property(&layout_view::has_art);
|
||||
|
||||
|
||||
auto layout_view_item_type = sol().registry().new_usertype<layout_view::item>("layout_item", sol::no_constructor);
|
||||
layout_view_item_type["set_state"] = &layout_view::item::set_state;
|
||||
auto layout_view_item_type = sol().registry().new_usertype<layout_view_item>("layout_item", sol::no_constructor);
|
||||
layout_view_item_type["set_state"] = &layout_view_item::set_state;
|
||||
layout_view_item_type["set_element_state_callback"] =
|
||||
make_simple_callback_setter<int>(
|
||||
&layout_view::item::set_element_state_callback,
|
||||
&layout_view_item::set_element_state_callback,
|
||||
[] () { return 0; },
|
||||
"set_element_state_callback",
|
||||
"element state");
|
||||
layout_view_item_type["set_animation_state_callback"] =
|
||||
make_simple_callback_setter<int>(
|
||||
&layout_view::item::set_animation_state_callback,
|
||||
&layout_view_item::set_animation_state_callback,
|
||||
[] () { return 0; },
|
||||
"set_animation_state_callback",
|
||||
"animation state");
|
||||
layout_view_item_type["set_bounds_callback"] =
|
||||
make_simple_callback_setter<render_bounds>(
|
||||
&layout_view::item::set_bounds_callback,
|
||||
&layout_view_item::set_bounds_callback,
|
||||
[] () { return render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }; },
|
||||
"set_bounds_callback",
|
||||
"bounds");
|
||||
layout_view_item_type["set_color_callback"] =
|
||||
make_simple_callback_setter<render_color>(
|
||||
&layout_view::item::set_color_callback,
|
||||
&layout_view_item::set_color_callback,
|
||||
[] () { return render_color{ 1.0f, 1.0f, 1.0f, 1.0f }; },
|
||||
"set_color_callback",
|
||||
"color");
|
||||
layout_view_item_type["set_scroll_size_x_callback"] =
|
||||
make_simple_callback_setter<float>(
|
||||
&layout_view_item::set_scroll_size_x_callback,
|
||||
[] () { return 1.0f; },
|
||||
"set_scroll_size_x_callback",
|
||||
"horizontal scroll window size");
|
||||
layout_view_item_type["set_scroll_size_y_callback"] =
|
||||
make_simple_callback_setter<float>(
|
||||
&layout_view_item::set_scroll_size_y_callback,
|
||||
[] () { return 1.0f; },
|
||||
"set_scroll_size_y_callback",
|
||||
"vertical scroll window size");
|
||||
layout_view_item_type["set_scroll_pos_x_callback"] =
|
||||
make_simple_callback_setter<float>(
|
||||
&layout_view_item::set_scroll_pos_x_callback,
|
||||
[] () { return 1.0f; },
|
||||
"set_scroll_pos_x_callback",
|
||||
"horizontal scroll position");
|
||||
layout_view_item_type["set_scroll_pos_y_callback"] =
|
||||
make_simple_callback_setter<float>(
|
||||
&layout_view_item::set_scroll_pos_y_callback,
|
||||
[] () { return 1.0f; },
|
||||
"set_scroll_pos_y_callback",
|
||||
"vertical scroll position");
|
||||
layout_view_item_type["id"] = sol::property(
|
||||
[] (layout_view::item &i, sol::this_state s) -> sol::object
|
||||
[] (layout_view_item &i, sol::this_state s) -> sol::object
|
||||
{
|
||||
if (i.id().empty())
|
||||
return sol::lua_nil;
|
||||
else
|
||||
return sol::make_object(s, i.id());
|
||||
});
|
||||
layout_view_item_type["bounds_animated"] = sol::property(&layout_view::item::bounds_animated);
|
||||
layout_view_item_type["color_animated"] = sol::property(&layout_view::item::color_animated);
|
||||
layout_view_item_type["bounds"] = sol::property(&layout_view::item::bounds);
|
||||
layout_view_item_type["color"] = sol::property(&layout_view::item::color);
|
||||
layout_view_item_type["blend_mode"] = sol::property(&layout_view::item::blend_mode);
|
||||
layout_view_item_type["orientation"] = sol::property(&layout_view::item::orientation);
|
||||
layout_view_item_type["element_state"] = sol::property(&layout_view::item::element_state);
|
||||
layout_view_item_type["animation_state"] = sol::property(&layout_view::item::animation_state);
|
||||
layout_view_item_type["bounds_animated"] = sol::property(&layout_view_item::bounds_animated);
|
||||
layout_view_item_type["color_animated"] = sol::property(&layout_view_item::color_animated);
|
||||
layout_view_item_type["bounds"] = sol::property(&layout_view_item::bounds);
|
||||
layout_view_item_type["color"] = sol::property(&layout_view_item::color);
|
||||
layout_view_item_type["scroll_wrap_x"] = sol::property(&layout_view_item::scroll_wrap_x);
|
||||
layout_view_item_type["scroll_wrap_y"] = sol::property(&layout_view_item::scroll_wrap_y);
|
||||
layout_view_item_type["scroll_size_x"] = sol::property(
|
||||
&layout_view_item::scroll_size_x,
|
||||
&layout_view_item::set_scroll_size_x);
|
||||
layout_view_item_type["scroll_size_y"] = sol::property(
|
||||
&layout_view_item::scroll_size_y,
|
||||
&layout_view_item::set_scroll_size_y);
|
||||
layout_view_item_type["scroll_pos_x"] = sol::property(
|
||||
&layout_view_item::scroll_pos_x,
|
||||
&layout_view_item::set_scroll_pos_y);
|
||||
layout_view_item_type["scroll_pos_y"] = sol::property(
|
||||
&layout_view_item::scroll_pos_y,
|
||||
&layout_view_item::set_scroll_pos_y);
|
||||
layout_view_item_type["blend_mode"] = sol::property(&layout_view_item::blend_mode);
|
||||
layout_view_item_type["orientation"] = sol::property(&layout_view_item::orientation);
|
||||
layout_view_item_type["element_state"] = sol::property(&layout_view_item::element_state);
|
||||
layout_view_item_type["animation_state"] = sol::property(&layout_view_item::animation_state);
|
||||
|
||||
|
||||
auto layout_file_type = sol().registry().new_usertype<layout_file>("layout_file", sol::no_constructor);
|
||||
|
Loading…
Reference in New Issue
Block a user