mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
(nw) Further layout work:
* Allow <orientation> and <color> to work on group references * Fix some corner cases where group bounds could be miscalculated * Fix a corner case where MAME could incorrectly refuse to instantiate groups * Add more checks to complay.py * Document more of the layout format
This commit is contained in:
parent
153fa4c4f8
commit
6ea9ff9042
@ -601,6 +601,181 @@ An example element for a button that gives visual feedback when clicked::
|
|||||||
</element>
|
</element>
|
||||||
|
|
||||||
|
|
||||||
|
.. _layout-parts-views:
|
||||||
|
|
||||||
|
Views
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
A view defines an arrangement of elements and/or emulated screen images that can
|
||||||
|
be displayed in a window or on a screen. Views also connect elements to
|
||||||
|
emulated I/O ports and/or outputs. A layout file may contain multiple views.
|
||||||
|
If a view references a non-existent screen, it will be considered *unviable*.
|
||||||
|
MAME will print a warning message, skip over the unviable view, and continue to
|
||||||
|
load views from the layout file. This is particularly useful for systems where
|
||||||
|
a screen is optional, for example computer systems with front panel controls and
|
||||||
|
an optional serial terminal.
|
||||||
|
|
||||||
|
Views are identified by name in MAME's user interface and in command-line
|
||||||
|
options. For layouts files associated with devices other than the root driver
|
||||||
|
device, view names are prefixed with the device's tag (with the initial colon
|
||||||
|
omitted) -- for example a view called "Keyboard LEDs" loaded for the device
|
||||||
|
``:tty:ie15`` will be called "tty:ie15 Keyboard LEDs" in MAME's user interface.
|
||||||
|
Views are listed in the order they are loaded. Within a layout file, views are
|
||||||
|
loaded in the order they appear, from top to bottom.
|
||||||
|
|
||||||
|
Views are created with ``view`` elements inside the top-level ``mamelayout``
|
||||||
|
element. Each ``view`` element must have a ``name`` attribute, supplying its
|
||||||
|
human-readable name for use in the user interface and command-line options.
|
||||||
|
This is an example of a valid opening tag for a ``view`` element::
|
||||||
|
|
||||||
|
<view name="Control panel">
|
||||||
|
|
||||||
|
A view creates a nested parameter scope inside the parameter scope of the
|
||||||
|
top-level ``mamelayout`` element. For historical reasons, ``view`` elements are
|
||||||
|
processed *after* all other child elements of the top-level ``mamelayout``
|
||||||
|
element. This means a view can reference elements and groups that appear after
|
||||||
|
it in the file, and parameters from the enclosing scope will have their final
|
||||||
|
values from the end of the ``mamelayout`` element.
|
||||||
|
|
||||||
|
The following child elements are allowed inside a ``view`` element:
|
||||||
|
|
||||||
|
bounds
|
||||||
|
Sets the origin and size of the view if present. If absent, the bounds of
|
||||||
|
the view are computed as the union of the bounds of all screens and elements
|
||||||
|
within the view. See :ref:`layout-concepts-coordinates` for details. It
|
||||||
|
only makes sense to have one ``bounds`` as a direct child of a view element.
|
||||||
|
param
|
||||||
|
Defines or reassigns a value parameter in the view's scope. See
|
||||||
|
:ref:`layout-concepts-params` for details.
|
||||||
|
backdrop overlay bezel cpanel marquee
|
||||||
|
Adds an element to the relevant layer (see :ref:`layout-parts-elements` and
|
||||||
|
:ref:`layout-concepts-layers`). The name of the element to add is specified
|
||||||
|
using the required ``element`` attribute. It is an error if no element with
|
||||||
|
this name is defined in the layout file. May optionally be connected to an
|
||||||
|
emulated I/O port using ``inputtag`` and ``inputmask`` attributes, and/or an
|
||||||
|
emulated output using a ``name`` attribute. Within a layer, elements are
|
||||||
|
drawn in the order they appear in the layout file, from front to back. See
|
||||||
|
below for more details.
|
||||||
|
screen
|
||||||
|
Adds an emulated screen image to the view. The screen must be identified
|
||||||
|
using either an ``index`` attribute or a ``tag`` attribute (it is an error
|
||||||
|
for a ``screen`` element to have both ``index`` and ``tag`` attributes).
|
||||||
|
If present, the ``index`` attribute must be a non-negative integer. Screens
|
||||||
|
are numbered by the order they appear in machine configuration, starting at
|
||||||
|
zero (0). If present, the ``tag`` attribute must be the tag path to the
|
||||||
|
screen relative to the device that causes the layout to be loaded. Screens
|
||||||
|
are drawn in the order they appear in the layout file, from front to back.
|
||||||
|
group
|
||||||
|
Adds the content of the group to the view (see :ref:`layout-parts-groups`).
|
||||||
|
The name of the group to add is specified using the required ``ref``
|
||||||
|
attribute. It is an error if no group with this name is defined in the
|
||||||
|
layout file. See below for more details on positioning.
|
||||||
|
repeat
|
||||||
|
Repeats its contents the number of times specified by the required ``count``
|
||||||
|
attribute. The ``count`` attribute must be a positive integer. A
|
||||||
|
``repeat`` element in a view may contain ``backdrop``, ``screen``,
|
||||||
|
``overlay``, ``bezel``, ``cpanel``, ``marquee``, ``group``, and further
|
||||||
|
``repeat`` elements, which function the same way they do when placed in a
|
||||||
|
view directly. See :ref:`layout-parts-repeats` for discussion on using
|
||||||
|
``repeat`` elements.
|
||||||
|
|
||||||
|
Screens (``screen`` elements), layout elements (``backdrop``, ``overlay``,
|
||||||
|
``bezel``, ``cpanel`` or ``marquee`` elements) and groups (``group`` elements)
|
||||||
|
may be have their orientation altered using an ``orientation`` child element.
|
||||||
|
For screens, the orientation modifiers are applied in addition to the
|
||||||
|
orientation modifiers specified on the screen device and on the machine. The
|
||||||
|
``orientation`` element supports the following attributes, all of which are
|
||||||
|
optional:
|
||||||
|
|
||||||
|
rotate
|
||||||
|
If present, applies clockwise rotation in ninety degree implements. Must be
|
||||||
|
an integer equal to 0, 90, 180 or 270.
|
||||||
|
swapxy
|
||||||
|
Allows the screen, element or group to be mirrored along a line at
|
||||||
|
forty-five degrees to vertical from upper left to lower right. Must be
|
||||||
|
either ``yes`` or ``no`` if present. Mirroring applies logically after
|
||||||
|
rotation.
|
||||||
|
flipx
|
||||||
|
Allows the screen, element or group to be mirrored around its vertical axis,
|
||||||
|
from left to right. Must be either ``yes`` or ``no`` if present. Mirroring
|
||||||
|
applies logically after rotation.
|
||||||
|
flipy
|
||||||
|
Allows the screen, element or group to be mirrored around its horizontal
|
||||||
|
axis, from top to bottom. Must be either ``yes`` or ``no`` if present.
|
||||||
|
Mirroring applies logically after rotation.
|
||||||
|
|
||||||
|
Screens (``screen`` elements), layout elements (``backdrop``, ``overlay``,
|
||||||
|
``bezel``, ``cpanel`` or ``marquee`` elements) and groups (``group`` elements)
|
||||||
|
may be positioned and sized using a ``bounds`` child element (see
|
||||||
|
:ref:`layout-concepts-coordinates` for details). In the absence of a ``bounds``
|
||||||
|
child element, screens' and layout elements' bounds default to a unit square
|
||||||
|
(origin at 0,0 and height and width both equal to 1). In the absence of a
|
||||||
|
``bounds`` child element, groups are expanded with no translation/scaling (note
|
||||||
|
that groups may position screens/elements outside their bounds). This example
|
||||||
|
shows a view instantiating and positioning a screen, an individual layout
|
||||||
|
element, and two element groups::
|
||||||
|
|
||||||
|
<view name="LED Displays, Terminal and Keypad">
|
||||||
|
<cpanel element="beige"><bounds x="320" y="0" width="172" height="372" /></cpanel>
|
||||||
|
<group ref="displays"><bounds x="0" y="0" width="320" height="132" /></group>
|
||||||
|
<group ref="keypad"><bounds x="336" y="16" width="140" height="260" /></group>
|
||||||
|
<screen index="0"><bounds x="0" y="132" width="320" height="240" /></screen>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
Screens (``screen`` elements), layout elements (``backdrop``, ``overlay``,
|
||||||
|
``bezel``, ``cpanel`` or ``marquee`` elements) and groups (``group`` elements)
|
||||||
|
may have a ``color`` child element (see :ref:`layout-concepts-colours`)
|
||||||
|
specifying a modifier colour. The components colours of the screen or layout
|
||||||
|
element(s) are multiplied by this colour.
|
||||||
|
|
||||||
|
If an element instantiating a layout element (``backdrop``, ``overlay``,
|
||||||
|
``bezel``, ``cpanel`` or ``marquee``) has ``inputtag`` and ``inputmask``
|
||||||
|
attributes, clicking it is equivalent to pressing a key/button mapped to the
|
||||||
|
corresponding input(s). The ``inputtag`` specifies the tag path of an I/O port
|
||||||
|
relative to the device that caused the layout file to be loaded. The
|
||||||
|
``inputmask`` attribute must be an integer specifying the bits of the I/O port
|
||||||
|
that the element should activate. This sample is shows instantiation of
|
||||||
|
clickable buttons::
|
||||||
|
|
||||||
|
<cpanel element="btn_3" inputtag="X2" inputmask="0x10">
|
||||||
|
<bounds x="2.30" y="4.325" width="1.0" height="1.0" />
|
||||||
|
</cpanel>
|
||||||
|
<cpanel element="btn_0" inputtag="X0" inputmask="0x20">
|
||||||
|
<bounds x="0.725" y="5.375" width="1.0" height="1.0" /></cpanel>
|
||||||
|
<cpanel element="btn_rst" inputtag="RESET" inputmask="0x01">
|
||||||
|
<bounds x="1.775" y="5.375" width="1.0" height="1.0" />
|
||||||
|
</cpanel>
|
||||||
|
|
||||||
|
|
||||||
|
If an element instantiating a layout element (``backdrop``, ``overlay``,
|
||||||
|
``bezel``, ``cpanel`` or ``marquee``) has a ``name`` attribute, it will take its
|
||||||
|
state from the value of the correspondingly named emulated output. Note that
|
||||||
|
output names are global, which can become an issue when a machine uses multiple
|
||||||
|
instances of the same type of device. See :ref:`layout-parts-elements` for
|
||||||
|
details on how an element's state affects its appearance. This example shows
|
||||||
|
how digital displays may be connected to emulated outputs::
|
||||||
|
|
||||||
|
<cpanel name="digit6" element="digit"><bounds x="16" y="16" width="48" height="80" /></cpanel>
|
||||||
|
<cpanel name="digit5" element="digit"><bounds x="64" y="16" width="48" height="80" /></cpanel>
|
||||||
|
<cpanel name="digit4" element="digit"><bounds x="112" y="16" width="48" height="80" /></cpanel>
|
||||||
|
<cpanel name="digit3" element="digit"><bounds x="160" y="16" width="48" height="80" /></cpanel>
|
||||||
|
<cpanel name="digit2" element="digit"><bounds x="208" y="16" width="48" height="80" /></cpanel>
|
||||||
|
<cpanel name="digit1" element="digit"><bounds x="256" y="16" width="48" height="80" /></cpanel>
|
||||||
|
|
||||||
|
If an element instantiating a layout element has ``inputtag`` and ``inputmask``
|
||||||
|
attributes but lacks a ``name`` attribute, it will take its state from the value
|
||||||
|
of the corresponding I/O port, masked with the ``inputmask`` value, and shifted
|
||||||
|
to the right so that the least significant one bit of the mask aligns with the
|
||||||
|
least significant bit of the value (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). This is often used to allow clickable buttons and toggle switches
|
||||||
|
to provide visible feedback.
|
||||||
|
|
||||||
|
When handling mouse input, MAME treats all layout elements as being rectangular,
|
||||||
|
and only activates the frontmost element whose area includes the location of the
|
||||||
|
mouse pointer.
|
||||||
|
|
||||||
|
|
||||||
.. _layout-parts-repeats:
|
.. _layout-parts-repeats:
|
||||||
|
|
||||||
Repeating blocks
|
Repeating blocks
|
||||||
@ -736,6 +911,22 @@ tiles on each iteration. Rows are connected to I/O ports ``board:IN.7`` at the
|
|||||||
top to ``board.IN.0`` at the bottom.
|
top to ``board.IN.0`` at the bottom.
|
||||||
|
|
||||||
|
|
||||||
|
.. _layout-errors:
|
||||||
|
|
||||||
|
Error handling
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* For internal (developer-supplied) layout files, errors detected by the
|
||||||
|
``complay.py`` script result in a build failure.
|
||||||
|
* MAME will stop loading a layout file if a syntax error is encountered. No
|
||||||
|
views from the layout will be available. Examples of syntax errors include
|
||||||
|
undefined element or group references, invalid bounds, invalid colours,
|
||||||
|
recursively nested groups, and redefined generator parameters.
|
||||||
|
* When loading a layout file, if a view references a non-existent screen, MAME
|
||||||
|
will print a warning message and continue. Views referencing non-existent
|
||||||
|
screens are considered unviable and not available to the user.
|
||||||
|
|
||||||
|
|
||||||
.. _layout-autogen:
|
.. _layout-autogen:
|
||||||
|
|
||||||
Automatically-generated views
|
Automatically-generated views
|
||||||
|
@ -98,6 +98,8 @@ class LayoutChecker(Minifyer):
|
|||||||
FLOATCHARS = re.compile('^.*[.eE].*$')
|
FLOATCHARS = re.compile('^.*[.eE].*$')
|
||||||
SHAPES = frozenset(('disk', 'dotmatrix', 'dotmatrix5dot', 'dotmatrixdot', 'led14seg', 'led14segsc', 'led16seg', 'led16segsc', 'led7seg', 'led8seg_gts1', 'rect'))
|
SHAPES = frozenset(('disk', 'dotmatrix', 'dotmatrix5dot', 'dotmatrixdot', 'led14seg', 'led14segsc', 'led16seg', 'led16segsc', 'led7seg', 'led8seg_gts1', 'rect'))
|
||||||
OBJECTS = frozenset(('backdrop', 'bezel', 'cpanel', 'marquee', 'overlay'))
|
OBJECTS = frozenset(('backdrop', 'bezel', 'cpanel', 'marquee', 'overlay'))
|
||||||
|
ORIENTATIONS = frozenset((0, 90, 180, 270))
|
||||||
|
YESNO = frozenset(("yes", "no"))
|
||||||
|
|
||||||
def __init__(self, output, **kwargs):
|
def __init__(self, output, **kwargs):
|
||||||
super(LayoutChecker, self).__init__(output=output, **kwargs)
|
super(LayoutChecker, self).__init__(output=output, **kwargs)
|
||||||
@ -246,6 +248,17 @@ class LayoutChecker(Minifyer):
|
|||||||
if has_ltrb and has_origin_size:
|
if has_ltrb and has_origin_size:
|
||||||
self.handleError('Element bounds has both left/top/right/bottom and origin/size attributes')
|
self.handleError('Element bounds has both left/top/right/bottom and origin/size attributes')
|
||||||
|
|
||||||
|
def checkOrientation(self, attrs):
|
||||||
|
if self.have_orientation[-1]:
|
||||||
|
self.handleError('Duplicate element orientation')
|
||||||
|
else:
|
||||||
|
self.have_orientation[-1] = True
|
||||||
|
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:
|
||||||
|
self.handleError('Element orientation attribute %s "%s" is not "yes" or "no"' % (name, attrs[name]))
|
||||||
|
|
||||||
def checkColorChannel(self, attrs, name):
|
def checkColorChannel(self, attrs, name):
|
||||||
channel = self.checkFloatAttribute('color', attrs, name, None)
|
channel = self.checkFloatAttribute('color', attrs, name, None)
|
||||||
if (channel is not None) and ((0.0 > channel) or (1.0 < channel)):
|
if (channel is not None) and ((0.0 > channel) or (1.0 < channel)):
|
||||||
@ -363,6 +376,8 @@ class LayoutChecker(Minifyer):
|
|||||||
for group in self.referenced_groups:
|
for group in self.referenced_groups:
|
||||||
if (group not in self.groups) and (not self.VARPATTERN.match(group)):
|
if (group not in self.groups) and (not self.VARPATTERN.match(group)):
|
||||||
self.handleError('Group "%s" not found (first referenced at %s)' % (group, self.referenced_groups[group]))
|
self.handleError('Group "%s" not found (first referenced at %s)' % (group, self.referenced_groups[group]))
|
||||||
|
if not self.views:
|
||||||
|
self.handleError('No view elements found')
|
||||||
self.handlers.pop()
|
self.handlers.pop()
|
||||||
|
|
||||||
def elementStartHandler(self, name, attrs):
|
def elementStartHandler(self, name, attrs):
|
||||||
@ -437,11 +452,16 @@ class LayoutChecker(Minifyer):
|
|||||||
self.referenced_elements[attrs['element']] = self.formatLocation()
|
self.referenced_elements[attrs['element']] = self.formatLocation()
|
||||||
if 'inputtag' in attrs:
|
if 'inputtag' in attrs:
|
||||||
if 'inputmask' not in attrs:
|
if 'inputmask' not in attrs:
|
||||||
self.handleError('Element %s has inputtag without inputmask attribute' % (name, ))
|
self.handleError('Element %s has inputtag attribute without inputmask attribute' % (name, ))
|
||||||
self.checkTag(attrs['inputtag'], name, 'inputtag')
|
self.checkTag(attrs['inputtag'], name, 'inputtag')
|
||||||
self.checkIntAttribute(name, attrs, 'inputmask', None)
|
elif 'inputmask' in attrs:
|
||||||
|
self.handleError('Element %s has inputmask attribute without inputtag attirbute' % (name, ))
|
||||||
|
inputmask = self.checkIntAttribute(name, attrs, 'inputmask', None)
|
||||||
|
if (inputmask is not None) and (0 == inputmask):
|
||||||
|
self.handleError('Element %s has attribute inputmask "%s" is zero' % (name, attrs['inputmask']))
|
||||||
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
||||||
self.have_bounds.append(False)
|
self.have_bounds.append(False)
|
||||||
|
self.have_orientation.append(False)
|
||||||
elif 'screen' == name:
|
elif 'screen' == name:
|
||||||
if 'index' in attrs:
|
if 'index' in attrs:
|
||||||
index = self.checkIntAttribute(name, attrs, 'index', None)
|
index = self.checkIntAttribute(name, attrs, 'index', None)
|
||||||
@ -456,6 +476,7 @@ class LayoutChecker(Minifyer):
|
|||||||
self.handleError('Element screen attribute tag "%s" contains invalid characters' % (tag, ))
|
self.handleError('Element screen attribute tag "%s" contains invalid characters' % (tag, ))
|
||||||
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
||||||
self.have_bounds.append(False)
|
self.have_bounds.append(False)
|
||||||
|
self.have_orientation.append(False)
|
||||||
elif 'group' == name:
|
elif 'group' == name:
|
||||||
if 'ref' not in attrs:
|
if 'ref' not in attrs:
|
||||||
self.handleError('Element group missing attribute ref')
|
self.handleError('Element group missing attribute ref')
|
||||||
@ -463,6 +484,7 @@ class LayoutChecker(Minifyer):
|
|||||||
self.referenced_groups[attrs['ref']] = self.formatLocation()
|
self.referenced_groups[attrs['ref']] = self.formatLocation()
|
||||||
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
self.handlers.append((self.objectStartHandler, self.objectEndHandler))
|
||||||
self.have_bounds.append(False)
|
self.have_bounds.append(False)
|
||||||
|
self.have_orientation.append(False)
|
||||||
elif 'repeat' == name:
|
elif 'repeat' == name:
|
||||||
if 'count' not in attrs:
|
if 'count' not in attrs:
|
||||||
self.handleError('Element repeat missing attribute count')
|
self.handleError('Element repeat missing attribute count')
|
||||||
@ -496,10 +518,13 @@ class LayoutChecker(Minifyer):
|
|||||||
def objectStartHandler(self, name, attrs):
|
def objectStartHandler(self, name, attrs):
|
||||||
if 'bounds' == name:
|
if 'bounds' == name:
|
||||||
self.checkBounds(attrs)
|
self.checkBounds(attrs)
|
||||||
|
elif 'orientation' == name:
|
||||||
|
self.checkOrientation(attrs)
|
||||||
self.ignored_depth = 1
|
self.ignored_depth = 1
|
||||||
|
|
||||||
def objectEndHandler(self, name):
|
def objectEndHandler(self, name):
|
||||||
self.have_bounds.pop()
|
self.have_bounds.pop()
|
||||||
|
self.have_orientation.pop()
|
||||||
self.handlers.pop()
|
self.handlers.pop()
|
||||||
|
|
||||||
def setDocumentLocator(self, locator):
|
def setDocumentLocator(self, locator):
|
||||||
@ -512,6 +537,7 @@ class LayoutChecker(Minifyer):
|
|||||||
self.variable_scopes = [ ]
|
self.variable_scopes = [ ]
|
||||||
self.repeat_depth = [ ]
|
self.repeat_depth = [ ]
|
||||||
self.have_bounds = [ ]
|
self.have_bounds = [ ]
|
||||||
|
self.have_orientation = [ ]
|
||||||
self.have_color = [ ]
|
self.have_color = [ ]
|
||||||
self.generated_element_names = False
|
self.generated_element_names = False
|
||||||
self.generated_group_names = False
|
self.generated_group_names = False
|
||||||
@ -529,6 +555,7 @@ class LayoutChecker(Minifyer):
|
|||||||
del self.variable_scopes
|
del self.variable_scopes
|
||||||
del self.repeat_depth
|
del self.repeat_depth
|
||||||
del self.have_bounds
|
del self.have_bounds
|
||||||
|
del self.have_orientation
|
||||||
del self.have_color
|
del self.have_color
|
||||||
del self.generated_element_names
|
del self.generated_element_names
|
||||||
del self.generated_group_names
|
del self.generated_group_names
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -759,14 +760,16 @@ class layout_group
|
|||||||
public:
|
public:
|
||||||
using environment = emu::render::detail::layout_environment;
|
using environment = emu::render::detail::layout_environment;
|
||||||
using group_map = std::unordered_map<std::string, layout_group>;
|
using group_map = std::unordered_map<std::string, layout_group>;
|
||||||
|
using transform = std::array<std::array<float, 3>, 3>;
|
||||||
|
|
||||||
layout_group(util::xml::data_node const &groupnode);
|
layout_group(util::xml::data_node const &groupnode);
|
||||||
~layout_group();
|
~layout_group();
|
||||||
|
|
||||||
util::xml::data_node const &get_groupnode() const { return m_groupnode; }
|
util::xml::data_node const &get_groupnode() const { return m_groupnode; }
|
||||||
|
|
||||||
render_bounds make_transform(render_bounds const &dest) const;
|
transform make_transform(int orientation, render_bounds const &dest) const;
|
||||||
render_bounds make_transform(render_bounds const &dest, render_bounds const &transform) const;
|
transform make_transform(int orientation, transform const &trans) const;
|
||||||
|
transform make_transform(int orientation, render_bounds const &dest, transform const &trans) const;
|
||||||
|
|
||||||
void set_bounds_unresolved();
|
void set_bounds_unresolved();
|
||||||
void resolve_bounds(environment &env, group_map &groupmap);
|
void resolve_bounds(environment &env, group_map &groupmap);
|
||||||
@ -818,7 +821,9 @@ public:
|
|||||||
environment &env,
|
environment &env,
|
||||||
util::xml::data_node const &itemnode,
|
util::xml::data_node const &itemnode,
|
||||||
element_map &elemmap,
|
element_map &elemmap,
|
||||||
render_bounds const &transform);
|
int orientation,
|
||||||
|
layout_group::transform const &trans,
|
||||||
|
render_color const &color);
|
||||||
~item();
|
~item();
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
@ -886,7 +891,9 @@ private:
|
|||||||
util::xml::data_node const &parentnode,
|
util::xml::data_node const &parentnode,
|
||||||
element_map &elemmap,
|
element_map &elemmap,
|
||||||
group_map &groupmap,
|
group_map &groupmap,
|
||||||
render_bounds const &transform,
|
int orientation,
|
||||||
|
layout_group::transform const &trans,
|
||||||
|
render_color const &color,
|
||||||
bool root,
|
bool root,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool init);
|
bool init);
|
||||||
|
@ -69,23 +69,26 @@ enum
|
|||||||
|
|
||||||
std::locale const f_portable_locale("C");
|
std::locale const f_portable_locale("C");
|
||||||
|
|
||||||
|
constexpr layout_group::transform identity_transform{{ {{ 1.0F, 0.0F, 0.0F }}, {{ 0.0F, 1.0F, 0.0F }}, {{ 0.0F, 0.0F, 1.0F }} }};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
// INLINE HELPERS
|
// INLINE HELPERS
|
||||||
//**************************************************************************
|
//**************************************************************************
|
||||||
|
|
||||||
//-------------------------------------------------
|
inline void render_bounds_transform(render_bounds &bounds, layout_group::transform const &trans)
|
||||||
// render_bounds_transform - apply translation/
|
|
||||||
// scaling
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
inline void render_bounds_transform(render_bounds &bounds, render_bounds const &transform)
|
|
||||||
{
|
{
|
||||||
bounds.x0 = (bounds.x0 * transform.x1) + transform.x0;
|
bounds = render_bounds{
|
||||||
bounds.y0 = (bounds.y0 * transform.y1) + transform.y0;
|
(bounds.x0 * trans[0][0]) + (bounds.y0 * trans[0][1]) + trans[0][2],
|
||||||
bounds.x1 = (bounds.x1 * transform.x1) + transform.x0;
|
(bounds.x0 * trans[1][0]) + (bounds.y0 * trans[1][1]) + trans[1][2],
|
||||||
bounds.y1 = (bounds.y1 * transform.y1) + transform.y0;
|
(bounds.x1 * trans[0][0]) + (bounds.y1 * trans[0][1]) + trans[0][2],
|
||||||
|
(bounds.x1 * trans[1][0]) + (bounds.y1 * trans[1][1]) + trans[1][2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr render_color render_color_multiply(render_color const &x, render_color const &y)
|
||||||
|
{
|
||||||
|
return render_color{ x.a * y.a, x.r * y.r, x.g * y.g, x.b * y.b };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -788,37 +791,34 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_color(util::xml::data_node const *node, render_color &result)
|
render_color parse_color(util::xml::data_node const *node)
|
||||||
{
|
{
|
||||||
// default to white
|
// default to opaque white
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
return render_color{ 1.0F, 1.0F, 1.0F, 1.0F };
|
||||||
result.r = result.g = result.b = result.a = 1.0F;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// parse attributes
|
// parse attributes
|
||||||
result.r = get_attribute_float(*node, "red", 1.0F);
|
render_color const result{
|
||||||
result.g = get_attribute_float(*node, "green", 1.0F);
|
get_attribute_float(*node, "alpha", 1.0F),
|
||||||
result.b = get_attribute_float(*node, "blue", 1.0F);
|
get_attribute_float(*node, "red", 1.0F),
|
||||||
result.a = get_attribute_float(*node, "alpha", 1.0F);
|
get_attribute_float(*node, "green", 1.0F),
|
||||||
|
get_attribute_float(*node, "blue", 1.0F) };
|
||||||
|
|
||||||
// check for errors
|
// check for errors
|
||||||
if ((0.0F > (std::min)({ result.r, result.g, result.b, result.a })) || (1.0F < (std::max)({ result.r, result.g, result.b, result.a })))
|
if ((0.0F > (std::min)({ result.r, result.g, result.b, result.a })) || (1.0F < (std::max)({ result.r, result.g, result.b, result.a })))
|
||||||
throw layout_syntax_error(util::string_format("illegal RGBA color %f,%f,%f,%f", result.r, result.g, result.b, result.a));
|
throw layout_syntax_error(util::string_format("illegal RGBA color %f,%f,%f,%f", result.r, result.g, result.b, result.a));
|
||||||
}
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_orientation(util::xml::data_node const *node, int &result)
|
int parse_orientation(util::xml::data_node const *node)
|
||||||
{
|
{
|
||||||
// default to no transform
|
// default to no transform
|
||||||
if (!node)
|
if (!node)
|
||||||
{
|
return ROT0;
|
||||||
result = ROT0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// parse attributes
|
// parse attributes
|
||||||
|
int result;
|
||||||
int const rotate(get_attribute_int(*node, "rotate", 0));
|
int const rotate(get_attribute_int(*node, "rotate", 0));
|
||||||
switch (rotate)
|
switch (rotate)
|
||||||
{
|
{
|
||||||
@ -834,7 +834,7 @@ public:
|
|||||||
result ^= ORIENTATION_FLIP_X;
|
result ^= ORIENTATION_FLIP_X;
|
||||||
if (!std::strcmp("yes", get_attribute_string(*node, "flipy", "no")))
|
if (!std::strcmp("yes", get_attribute_string(*node, "flipy", "no")))
|
||||||
result ^= ORIENTATION_FLIP_Y;
|
result ^= ORIENTATION_FLIP_Y;
|
||||||
}
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -965,25 +965,65 @@ layout_group::~layout_group()
|
|||||||
// matrix for given destination bounds
|
// matrix for given destination bounds
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
render_bounds layout_group::make_transform(render_bounds const &dest) const
|
layout_group::transform layout_group::make_transform(int orientation, render_bounds const &dest) const
|
||||||
{
|
{
|
||||||
assert(m_bounds_resolved);
|
assert(m_bounds_resolved);
|
||||||
|
|
||||||
return render_bounds{
|
// make orientation matrix
|
||||||
dest.x0 - (m_bounds.x0 * (dest.x1 - dest.x0) / (m_bounds.x1 - m_bounds.x0)),
|
transform result{{ {{ 1.0F, 0.0F, 0.0F }}, {{ 0.0F, 1.0F, 0.0F }}, {{ 0.0F, 0.0F, 1.0F }} }};
|
||||||
dest.y0 - (m_bounds.y0 * (dest.y1 - dest.y0) / (m_bounds.y1 - m_bounds.y0)),
|
if (orientation & ORIENTATION_SWAP_XY)
|
||||||
(dest.x1 - dest.x0) / (m_bounds.x1 - m_bounds.x0),
|
{
|
||||||
(dest.y1 - dest.y0) / (m_bounds.y1 - m_bounds.y0) };
|
std::swap(result[0][0], result[0][1]);
|
||||||
|
std::swap(result[1][0], result[1][1]);
|
||||||
|
}
|
||||||
|
if (orientation & ORIENTATION_FLIP_X)
|
||||||
|
{
|
||||||
|
result[0][0] = -result[0][0];
|
||||||
|
result[0][1] = -result[0][1];
|
||||||
|
}
|
||||||
|
if (orientation & ORIENTATION_FLIP_Y)
|
||||||
|
{
|
||||||
|
result[1][0] = -result[1][0];
|
||||||
|
result[1][1] = -result[1][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
render_bounds layout_group::make_transform(render_bounds const &dest, render_bounds const &transform) const
|
// apply to bounds and force into destination rectangle
|
||||||
|
render_bounds bounds(m_bounds);
|
||||||
|
render_bounds_transform(bounds, result);
|
||||||
|
result[0][0] *= (dest.x1 - dest.x0) / std::abs(bounds.x1 - bounds.x0);
|
||||||
|
result[0][1] *= (dest.x1 - dest.x0) / std::abs(bounds.x1 - bounds.x0);
|
||||||
|
result[0][2] = dest.x0 - ((std::min)(bounds.x0, bounds.x1) * (dest.x1 - dest.x0) / std::abs(bounds.x1 - bounds.x0));
|
||||||
|
result[1][0] *= (dest.y1 - dest.y0) / std::abs(bounds.y1 - bounds.y0);
|
||||||
|
result[1][1] *= (dest.y1 - dest.y0) / std::abs(bounds.y1 - bounds.y0);
|
||||||
|
result[1][2] = dest.y0 - ((std::min)(bounds.y0, bounds.y1) * (dest.y1 - dest.y0) / std::abs(bounds.y1 - bounds.y0));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_group::transform layout_group::make_transform(int orientation, transform const &trans) const
|
||||||
{
|
{
|
||||||
render_bounds const next(make_transform(dest));
|
assert(m_bounds_resolved);
|
||||||
return render_bounds{
|
|
||||||
(transform.x0 * next.x1) + next.x0,
|
render_bounds const dest{
|
||||||
(transform.y0 * next.y1) + next.y0,
|
m_bounds.x0,
|
||||||
transform.x1 * next.x1,
|
m_bounds.y0,
|
||||||
transform.y1 * next.y1 };
|
(orientation & ORIENTATION_SWAP_XY) ? (m_bounds.x0 + m_bounds.y1 - m_bounds.y0) : m_bounds.x1,
|
||||||
|
(orientation & ORIENTATION_SWAP_XY) ? (m_bounds.y0 + m_bounds.x1 - m_bounds.x0) : m_bounds.y1 };
|
||||||
|
return make_transform(orientation, dest, trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout_group::transform layout_group::make_transform(int orientation, render_bounds const &dest, transform const &trans) const
|
||||||
|
{
|
||||||
|
transform const next(make_transform(orientation, dest));
|
||||||
|
transform result{{ {{ 0.0F, 0.0F, 0.0F }}, {{ 0.0F, 0.0F, 0.0F }}, {{ 0.0F, 0.0F, 0.0F }} }};
|
||||||
|
for (unsigned y = 0; 3U > y; ++y)
|
||||||
|
{
|
||||||
|
for (unsigned x = 0; 3U > x; ++x)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; 3U > i; ++i)
|
||||||
|
result[y][x] += trans[y][i] * next[i][x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1013,8 +1053,8 @@ void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::ve
|
|||||||
// a wild loop appears!
|
// a wild loop appears!
|
||||||
std::ostringstream path;
|
std::ostringstream path;
|
||||||
for (layout_group const *const group : seen)
|
for (layout_group const *const group : seen)
|
||||||
path << ' ' << group->m_groupnode.get_name();
|
path << ' ' << group->m_groupnode.get_attribute_string("name", nullptr);
|
||||||
path << ' ' << m_groupnode.get_name();
|
path << ' ' << m_groupnode.get_attribute_string("name", nullptr);
|
||||||
throw layout_syntax_error(util::string_format("recursively nested groups %s", path.str()));
|
throw layout_syntax_error(util::string_format("recursively nested groups %s", path.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1024,6 +1064,7 @@ void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::ve
|
|||||||
environment local(env);
|
environment local(env);
|
||||||
resolve_bounds(local, m_groupnode, groupmap, seen, false, true);
|
resolve_bounds(local, m_groupnode, groupmap, seen, false, true);
|
||||||
}
|
}
|
||||||
|
seen.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void layout_group::resolve_bounds(
|
void layout_group::resolve_bounds(
|
||||||
@ -1070,6 +1111,15 @@ void layout_group::resolve_bounds(
|
|||||||
union_render_bounds(m_bounds, itembounds);
|
union_render_bounds(m_bounds, itembounds);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "group"))
|
else if (!strcmp(itemnode->get_name(), "group"))
|
||||||
|
{
|
||||||
|
util::xml::data_node const *const itemboundsnode(itemnode->get_child("bounds"));
|
||||||
|
if (itemboundsnode)
|
||||||
|
{
|
||||||
|
render_bounds itembounds;
|
||||||
|
env.parse_bounds(itemboundsnode, itembounds);
|
||||||
|
union_render_bounds(m_bounds, itembounds);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr));
|
char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr));
|
||||||
if (!ref)
|
if (!ref)
|
||||||
@ -1079,9 +1129,16 @@ void layout_group::resolve_bounds(
|
|||||||
if (groupmap.end() == found)
|
if (groupmap.end() == found)
|
||||||
throw layout_syntax_error(util::string_format("unable to find group %s", ref));
|
throw layout_syntax_error(util::string_format("unable to find group %s", ref));
|
||||||
|
|
||||||
|
int const orientation(env.parse_orientation(itemnode->get_child("orientation")));
|
||||||
environment local(env);
|
environment local(env);
|
||||||
found->second.resolve_bounds(local, groupmap, seen);
|
found->second.resolve_bounds(local, groupmap, seen);
|
||||||
union_render_bounds(m_bounds, found->second.m_bounds);
|
render_bounds const itembounds{
|
||||||
|
found->second.m_bounds.x0,
|
||||||
|
found->second.m_bounds.y0,
|
||||||
|
(orientation & ORIENTATION_SWAP_XY) ? (found->second.m_bounds.x0 + found->second.m_bounds.y1 - found->second.m_bounds.y0) : found->second.m_bounds.x1,
|
||||||
|
(orientation & ORIENTATION_SWAP_XY) ? (found->second.m_bounds.y0 + found->second.m_bounds.x1 - found->second.m_bounds.x0) : found->second.m_bounds.y1 };
|
||||||
|
union_render_bounds(m_bounds, itembounds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "repeat"))
|
else if (!strcmp(itemnode->get_name(), "repeat"))
|
||||||
{
|
{
|
||||||
@ -2576,12 +2633,10 @@ layout_element::texture &layout_element::texture::operator=(texture &&that)
|
|||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
layout_element::component::component(environment &env, util::xml::data_node const &compnode, const char *dirname)
|
layout_element::component::component(environment &env, util::xml::data_node const &compnode, const char *dirname)
|
||||||
: m_state(0)
|
: m_state(env.get_attribute_int(compnode, "state", -1))
|
||||||
|
, m_color(env.parse_color(compnode.get_child("color")))
|
||||||
{
|
{
|
||||||
// fetch common data
|
|
||||||
m_state = env.get_attribute_int(compnode, "state", -1);
|
|
||||||
env.parse_bounds(compnode.get_child("bounds"), m_bounds);
|
env.parse_bounds(compnode.get_child("bounds"), m_bounds);
|
||||||
env.parse_color(compnode.get_child("color"), m_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2904,7 +2959,7 @@ layout_view::layout_view(
|
|||||||
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
|
m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0;
|
||||||
environment local(env);
|
environment local(env);
|
||||||
local.set_parameter("viewname", std::string(m_name));
|
local.set_parameter("viewname", std::string(m_name));
|
||||||
add_items(local, viewnode, elemmap, groupmap, render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }, true, false, true);
|
add_items(local, viewnode, elemmap, groupmap, ROT0, identity_transform, render_color{ 1.0F, 1.0F, 1.0F, 1.0F }, true, false, true);
|
||||||
recompute(render_layer_config());
|
recompute(render_layer_config());
|
||||||
for (group_map::value_type &group : groupmap)
|
for (group_map::value_type &group : groupmap)
|
||||||
group.second.set_bounds_unresolved();
|
group.second.set_bounds_unresolved();
|
||||||
@ -3065,7 +3120,9 @@ void layout_view::add_items(
|
|||||||
util::xml::data_node const &parentnode,
|
util::xml::data_node const &parentnode,
|
||||||
element_map &elemmap,
|
element_map &elemmap,
|
||||||
group_map &groupmap,
|
group_map &groupmap,
|
||||||
render_bounds const &transform,
|
int orientation,
|
||||||
|
layout_group::transform const &trans,
|
||||||
|
render_color const &color,
|
||||||
bool root,
|
bool root,
|
||||||
bool repeat,
|
bool repeat,
|
||||||
bool init)
|
bool init)
|
||||||
@ -3096,27 +3153,27 @@ void layout_view::add_items(
|
|||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "backdrop"))
|
else if (!strcmp(itemnode->get_name(), "backdrop"))
|
||||||
{
|
{
|
||||||
m_backdrop_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_backdrop_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "screen"))
|
else if (!strcmp(itemnode->get_name(), "screen"))
|
||||||
{
|
{
|
||||||
m_screen_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_screen_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "overlay"))
|
else if (!strcmp(itemnode->get_name(), "overlay"))
|
||||||
{
|
{
|
||||||
m_overlay_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_overlay_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "bezel"))
|
else if (!strcmp(itemnode->get_name(), "bezel"))
|
||||||
{
|
{
|
||||||
m_bezel_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_bezel_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "cpanel"))
|
else if (!strcmp(itemnode->get_name(), "cpanel"))
|
||||||
{
|
{
|
||||||
m_cpanel_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_cpanel_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "marquee"))
|
else if (!strcmp(itemnode->get_name(), "marquee"))
|
||||||
{
|
{
|
||||||
m_marquee_list.emplace_back(env, *itemnode, elemmap, transform);
|
m_marquee_list.emplace_back(env, *itemnode, elemmap, orientation, trans, color);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "group"))
|
else if (!strcmp(itemnode->get_name(), "group"))
|
||||||
{
|
{
|
||||||
@ -3130,17 +3187,33 @@ void layout_view::add_items(
|
|||||||
unresolved = false;
|
unresolved = false;
|
||||||
found->second.resolve_bounds(env, groupmap);
|
found->second.resolve_bounds(env, groupmap);
|
||||||
|
|
||||||
render_bounds grouptrans(transform);
|
layout_group::transform grouptrans(trans);
|
||||||
util::xml::data_node const *const itemboundsnode(itemnode->get_child("bounds"));
|
util::xml::data_node const *const itemboundsnode(itemnode->get_child("bounds"));
|
||||||
|
util::xml::data_node const *const itemorientnode(itemnode->get_child("orientation"));
|
||||||
|
int const grouporient(env.parse_orientation(itemorientnode));
|
||||||
if (itemboundsnode)
|
if (itemboundsnode)
|
||||||
{
|
{
|
||||||
render_bounds itembounds;
|
render_bounds itembounds;
|
||||||
env.parse_bounds(itemboundsnode, itembounds);
|
env.parse_bounds(itemboundsnode, itembounds);
|
||||||
grouptrans = found->second.make_transform(itembounds, transform);
|
grouptrans = found->second.make_transform(grouporient, itembounds, trans);
|
||||||
|
}
|
||||||
|
else if (itemorientnode)
|
||||||
|
{
|
||||||
|
grouptrans = found->second.make_transform(grouporient, trans);
|
||||||
}
|
}
|
||||||
|
|
||||||
environment local(env);
|
environment local(env);
|
||||||
add_items(local, found->second.get_groupnode(), elemmap, groupmap, grouptrans, false, false, true);
|
add_items(
|
||||||
|
local,
|
||||||
|
found->second.get_groupnode(),
|
||||||
|
elemmap,
|
||||||
|
groupmap,
|
||||||
|
orientation_add(grouporient, orientation),
|
||||||
|
grouptrans,
|
||||||
|
render_color_multiply(env.parse_color(itemnode->get_child("color")), color),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
else if (!strcmp(itemnode->get_name(), "repeat"))
|
else if (!strcmp(itemnode->get_name(), "repeat"))
|
||||||
{
|
{
|
||||||
@ -3150,7 +3223,7 @@ void layout_view::add_items(
|
|||||||
environment local(env);
|
environment local(env);
|
||||||
for (int i = 0; count > i; ++i)
|
for (int i = 0; count > i; ++i)
|
||||||
{
|
{
|
||||||
add_items(local, *itemnode, elemmap, groupmap, transform, false, true, !i);
|
add_items(local, *itemnode, elemmap, groupmap, orientation, trans, color, false, true, !i);
|
||||||
local.increment_parameters();
|
local.increment_parameters();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3200,7 +3273,9 @@ layout_view::item::item(
|
|||||||
environment &env,
|
environment &env,
|
||||||
util::xml::data_node const &itemnode,
|
util::xml::data_node const &itemnode,
|
||||||
element_map &elemmap,
|
element_map &elemmap,
|
||||||
render_bounds const &transform)
|
int orientation,
|
||||||
|
layout_group::transform const &trans,
|
||||||
|
render_color const &color)
|
||||||
: m_element(nullptr)
|
: m_element(nullptr)
|
||||||
, m_output(env.device(), env.get_attribute_string(itemnode, "name", ""))
|
, m_output(env.device(), env.get_attribute_string(itemnode, "name", ""))
|
||||||
, m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
|
, m_have_output(env.get_attribute_string(itemnode, "name", "")[0])
|
||||||
@ -3208,7 +3283,8 @@ layout_view::item::item(
|
|||||||
, m_input_port(nullptr)
|
, m_input_port(nullptr)
|
||||||
, m_input_mask(0)
|
, m_input_mask(0)
|
||||||
, m_screen(nullptr)
|
, m_screen(nullptr)
|
||||||
, m_orientation(ROT0)
|
, m_orientation(orientation_add(env.parse_orientation(itemnode.get_child("orientation")), orientation))
|
||||||
|
, m_color(render_color_multiply(env.parse_color(itemnode.get_child("color")), color))
|
||||||
{
|
{
|
||||||
// find the associated element
|
// find the associated element
|
||||||
char const *const name(env.get_attribute_string(itemnode, "element", nullptr));
|
char const *const name(env.get_attribute_string(itemnode, "element", nullptr));
|
||||||
@ -3234,9 +3310,11 @@ layout_view::item::item(
|
|||||||
if (m_have_output && m_element)
|
if (m_have_output && m_element)
|
||||||
m_output = m_element->default_state();
|
m_output = m_element->default_state();
|
||||||
env.parse_bounds(itemnode.get_child("bounds"), m_rawbounds);
|
env.parse_bounds(itemnode.get_child("bounds"), m_rawbounds);
|
||||||
render_bounds_transform(m_rawbounds, transform);
|
render_bounds_transform(m_rawbounds, trans);
|
||||||
env.parse_color(itemnode.get_child("color"), m_color);
|
if (m_rawbounds.x0 > m_rawbounds.x1)
|
||||||
env.parse_orientation(itemnode.get_child("orientation"), m_orientation);
|
std::swap(m_rawbounds.x0, m_rawbounds.x1);
|
||||||
|
if (m_rawbounds.y0 > m_rawbounds.y1)
|
||||||
|
std::swap(m_rawbounds.y0, m_rawbounds.y1);
|
||||||
|
|
||||||
// sanity checks
|
// sanity checks
|
||||||
if (strcmp(itemnode.get_name(), "screen") == 0)
|
if (strcmp(itemnode.get_name(), "screen") == 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user