diff --git a/.rive_head b/.rive_head index 9664e694..fadf9ed6 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -50bc398c464061bb2ab5ac51e42901053ae63f1f +1a5f273bb6534a395d1c3cdcc11a1ba3cd80a96c diff --git a/dev/defs/nested_artboard.json b/dev/defs/nested_artboard.json index 112415c8..8a1ea487 100644 --- a/dev/defs/nested_artboard.json +++ b/dev/defs/nested_artboard.json @@ -17,29 +17,13 @@ }, "description": "Identifier used to track the Artboard nested." }, - "fit": { - "type": "uint", - "key": { - "int": 538, - "string": "fit" - }, - "description": "Fit type for the nested artboard's runtime artboard." - }, - "alignment": { - "type": "uint", - "key": { - "int": 539, - "string": "alignment" - }, - "description": "Alignment type for the nested artboard's runtime artboard." - }, "dataBindPathIds": { "type": "List", "typeRuntime": "Bytes", "encoded": true, "initialValue": "[]", "key": { - "int": 580, + "int": 582, "string": "databindpathids" }, "description": "Path to the selected property." diff --git a/dev/defs/nested_artboard_layout.json b/dev/defs/nested_artboard_layout.json new file mode 100644 index 00000000..b0579be4 --- /dev/null +++ b/dev/defs/nested_artboard_layout.json @@ -0,0 +1,8 @@ +{ + "name": "NestedArtboardLayout", + "key": { + "int": 452, + "string": "nestedartboardlayout" + }, + "extends": "nested_artboard.json" +} \ No newline at end of file diff --git a/dev/defs/nested_artboard_leaf.json b/dev/defs/nested_artboard_leaf.json new file mode 100644 index 00000000..cddf1585 --- /dev/null +++ b/dev/defs/nested_artboard_leaf.json @@ -0,0 +1,34 @@ +{ + "name": "NestedArtboardLeaf", + "key": { + "int": 451, + "string": "nested_artboard_leaf" + }, + "extends": "nested_artboard.json", + "properties": { + "fit": { + "type": "uint", + "key": { + "int": 538, + "string": "fit" + }, + "description": "Fit type for the nested artboard's runtime artboard." + }, + "alignmentX": { + "type": "double", + "key": { + "int": 644, + "string": "alignmentx" + }, + "description": "Alignment value on X." + }, + "alignmentY": { + "type": "double", + "key": { + "int": 645, + "string": "alignmenty" + }, + "description": "Alignment value on Y." + } + } +} \ No newline at end of file diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp index 4b7cc3d9..2e78c7e8 100644 --- a/include/rive/artboard.hpp +++ b/include/rive/artboard.hpp @@ -77,6 +77,10 @@ class Artboard : public ArtboardBase, public CoreContext std::unordered_set m_dirtyLayout; float m_originalWidth = 0; float m_originalHeight = 0; + bool m_updatesOwnLayout = true; + Artboard* parentArtboard() const; + NestedArtboard* m_host = nullptr; + bool sharesLayoutWithHost() const; #ifdef EXTERNAL_RIVE_AUDIO_ENGINE rcp m_audioEngine; @@ -85,8 +89,14 @@ class Artboard : public ArtboardBase, public CoreContext void sortDependencies(); void sortDrawOrder(); void updateDataBinds(); - void performUpdate(ComponentDirt value) override; + void updateRenderPath() override; + void update(ComponentDirt value) override; +public: + void host(NestedArtboard* nestedArtboard); + NestedArtboard* host() const; + +private: #ifdef TESTING public: Artboard(Factory* factory) : m_Factory(factory) {} @@ -96,7 +106,7 @@ class Artboard : public ArtboardBase, public CoreContext void addStateMachine(StateMachine* object); public: - Artboard() {} + Artboard(); ~Artboard() override; StatusCode initialize(); @@ -124,21 +134,10 @@ class Artboard : public ArtboardBase, public CoreContext // Artboard is a special type of LayoutComponent void updateWorldTransform() override {} - void markLayoutDirty(LayoutComponent* layoutComponent) - { - m_dirtyLayout.insert(layoutComponent); - } + void markLayoutDirty(LayoutComponent* layoutComponent); -#ifdef WITH_RIVE_LAYOUT - AABB layoutBounds() override - { - if (!hasLayoutMeasurements()) - { - return AABB(x(), y(), x() + width(), y() + height()); - } - return Super::layoutBounds(); - } -#endif + void* takeLayoutNode(); + bool syncStyleChanges(); bool advance(double elapsedSeconds, bool nested = true); bool advanceInternal(double elapsedSeconds, bool isRoot, bool nested = true); @@ -171,7 +170,10 @@ class Artboard : public ArtboardBase, public CoreContext float originalHeight() const { return m_originalHeight; } float layoutWidth() const; float layoutHeight() const; + float layoutX() const; + float layoutY() const; AABB bounds() const; + Vec2D origin() const; // Can we hide these from the public? (they use playable) bool isTranslucent() const; @@ -366,9 +368,11 @@ class Artboard : public ArtboardBase, public CoreContext float m_volume = 1.0f; #ifdef WITH_RIVE_TOOLS ArtboardCallback m_layoutChangedCallback = nullptr; + ArtboardCallback m_layoutDirtyCallback = nullptr; public: void onLayoutChanged(ArtboardCallback callback) { m_layoutChangedCallback = callback; } + void onLayoutDirty(ArtboardCallback callback) { m_layoutDirtyCallback = callback; } #endif }; diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp index abeae9a8..7abe2d5a 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp @@ -117,6 +117,8 @@ #include "rive/layout_component.hpp" #include "rive/nested_animation.hpp" #include "rive/nested_artboard.hpp" +#include "rive/nested_artboard_layout.hpp" +#include "rive/nested_artboard_leaf.hpp" #include "rive/node.hpp" #include "rive/open_url_event.hpp" #include "rive/shapes/clipping_shape.hpp" @@ -258,6 +260,8 @@ class CoreRegistry return new NestedArtboard(); case SoloBase::typeKey: return new Solo(); + case NestedArtboardLayoutBase::typeKey: + return new NestedArtboardLayout(); case LayoutComponentStyleBase::typeKey: return new LayoutComponentStyle(); case ListenerFireEventBase::typeKey: @@ -428,6 +432,8 @@ class CoreRegistry return new BindablePropertyEnum(); case BindablePropertyColorBase::typeKey: return new BindablePropertyColor(); + case NestedArtboardLeafBase::typeKey: + return new NestedArtboardLeaf(); case WeightBase::typeKey: return new Weight(); case BoneBase::typeKey: @@ -639,12 +645,6 @@ class CoreRegistry case NestedArtboardBase::artboardIdPropertyKey: object->as()->artboardId(value); break; - case NestedArtboardBase::fitPropertyKey: - object->as()->fit(value); - break; - case NestedArtboardBase::alignmentPropertyKey: - object->as()->alignment(value); - break; case NestedAnimationBase::animationIdPropertyKey: object->as()->animationId(value); break; @@ -951,6 +951,9 @@ class CoreRegistry case BindablePropertyEnumBase::propertyValuePropertyKey: object->as()->propertyValue(value); break; + case NestedArtboardLeafBase::fitPropertyKey: + object->as()->fit(value); + break; case WeightBase::valuesPropertyKey: object->as()->values(value); break; @@ -1466,6 +1469,12 @@ class CoreRegistry case BindablePropertyNumberBase::propertyValuePropertyKey: object->as()->propertyValue(value); break; + case NestedArtboardLeafBase::alignmentXPropertyKey: + object->as()->alignmentX(value); + break; + case NestedArtboardLeafBase::alignmentYPropertyKey: + object->as()->alignmentY(value); + break; case BoneBase::lengthPropertyKey: object->as()->length(value); break; @@ -1721,10 +1730,6 @@ class CoreRegistry return object->as()->drawableFlags(); case NestedArtboardBase::artboardIdPropertyKey: return object->as()->artboardId(); - case NestedArtboardBase::fitPropertyKey: - return object->as()->fit(); - case NestedArtboardBase::alignmentPropertyKey: - return object->as()->alignment(); case NestedAnimationBase::animationIdPropertyKey: return object->as()->animationId(); case SoloBase::activeComponentIdPropertyKey: @@ -1929,6 +1934,8 @@ class CoreRegistry return object->as()->flags(); case BindablePropertyEnumBase::propertyValuePropertyKey: return object->as()->propertyValue(); + case NestedArtboardLeafBase::fitPropertyKey: + return object->as()->fit(); case WeightBase::valuesPropertyKey: return object->as()->values(); case WeightBase::indicesPropertyKey: @@ -2282,6 +2289,10 @@ class CoreRegistry return object->as()->height(); case BindablePropertyNumberBase::propertyValuePropertyKey: return object->as()->propertyValue(); + case NestedArtboardLeafBase::alignmentXPropertyKey: + return object->as()->alignmentX(); + case NestedArtboardLeafBase::alignmentYPropertyKey: + return object->as()->alignmentY(); case BoneBase::lengthPropertyKey: return object->as()->length(); case RootBoneBase::xPropertyKey: @@ -2426,8 +2437,6 @@ class CoreRegistry case DrawableBase::blendModeValuePropertyKey: case DrawableBase::drawableFlagsPropertyKey: case NestedArtboardBase::artboardIdPropertyKey: - case NestedArtboardBase::fitPropertyKey: - case NestedArtboardBase::alignmentPropertyKey: case NestedAnimationBase::animationIdPropertyKey: case SoloBase::activeComponentIdPropertyKey: case LayoutComponentStyleBase::scaleTypePropertyKey: @@ -2530,6 +2539,7 @@ class CoreRegistry case DataBindBase::propertyKeyPropertyKey: case DataBindBase::flagsPropertyKey: case BindablePropertyEnumBase::propertyValuePropertyKey: + case NestedArtboardLeafBase::fitPropertyKey: case WeightBase::valuesPropertyKey: case WeightBase::indicesPropertyKey: case TendonBase::boneIdPropertyKey: @@ -2700,6 +2710,8 @@ class CoreRegistry case JoystickBase::widthPropertyKey: case JoystickBase::heightPropertyKey: case BindablePropertyNumberBase::propertyValuePropertyKey: + case NestedArtboardLeafBase::alignmentXPropertyKey: + case NestedArtboardLeafBase::alignmentYPropertyKey: case BoneBase::lengthPropertyKey: case RootBoneBase::xPropertyKey: case RootBoneBase::yPropertyKey: @@ -2872,10 +2884,6 @@ class CoreRegistry return object->is(); case NestedArtboardBase::artboardIdPropertyKey: return object->is(); - case NestedArtboardBase::fitPropertyKey: - return object->is(); - case NestedArtboardBase::alignmentPropertyKey: - return object->is(); case NestedAnimationBase::animationIdPropertyKey: return object->is(); case SoloBase::activeComponentIdPropertyKey: @@ -3080,6 +3088,8 @@ class CoreRegistry return object->is(); case BindablePropertyEnumBase::propertyValuePropertyKey: return object->is(); + case NestedArtboardLeafBase::fitPropertyKey: + return object->is(); case WeightBase::valuesPropertyKey: return object->is(); case WeightBase::indicesPropertyKey: @@ -3412,6 +3422,10 @@ class CoreRegistry return object->is(); case BindablePropertyNumberBase::propertyValuePropertyKey: return object->is(); + case NestedArtboardLeafBase::alignmentXPropertyKey: + return object->is(); + case NestedArtboardLeafBase::alignmentYPropertyKey: + return object->is(); case BoneBase::lengthPropertyKey: return object->is(); case RootBoneBase::xPropertyKey: diff --git a/include/rive/generated/nested_artboard_base.hpp b/include/rive/generated/nested_artboard_base.hpp index a115ba29..a0c203ab 100644 --- a/include/rive/generated/nested_artboard_base.hpp +++ b/include/rive/generated/nested_artboard_base.hpp @@ -36,14 +36,10 @@ class NestedArtboardBase : public Drawable uint16_t coreType() const override { return typeKey; } static const uint16_t artboardIdPropertyKey = 197; - static const uint16_t fitPropertyKey = 538; - static const uint16_t alignmentPropertyKey = 539; - static const uint16_t dataBindPathIdsPropertyKey = 580; + static const uint16_t dataBindPathIdsPropertyKey = 582; private: uint32_t m_ArtboardId = -1; - uint32_t m_Fit = 0; - uint32_t m_Alignment = 0; public: inline uint32_t artboardId() const { return m_ArtboardId; } @@ -57,28 +53,6 @@ class NestedArtboardBase : public Drawable artboardIdChanged(); } - inline uint32_t fit() const { return m_Fit; } - void fit(uint32_t value) - { - if (m_Fit == value) - { - return; - } - m_Fit = value; - fitChanged(); - } - - inline uint32_t alignment() const { return m_Alignment; } - void alignment(uint32_t value) - { - if (m_Alignment == value) - { - return; - } - m_Alignment = value; - alignmentChanged(); - } - virtual void decodeDataBindPathIds(Span value) = 0; virtual void copyDataBindPathIds(const NestedArtboardBase& object) = 0; @@ -86,8 +60,6 @@ class NestedArtboardBase : public Drawable void copy(const NestedArtboardBase& object) { m_ArtboardId = object.m_ArtboardId; - m_Fit = object.m_Fit; - m_Alignment = object.m_Alignment; copyDataBindPathIds(object); Drawable::copy(object); } @@ -99,12 +71,6 @@ class NestedArtboardBase : public Drawable case artboardIdPropertyKey: m_ArtboardId = CoreUintType::deserialize(reader); return true; - case fitPropertyKey: - m_Fit = CoreUintType::deserialize(reader); - return true; - case alignmentPropertyKey: - m_Alignment = CoreUintType::deserialize(reader); - return true; case dataBindPathIdsPropertyKey: decodeDataBindPathIds(CoreBytesType::deserialize(reader)); return true; @@ -114,8 +80,6 @@ class NestedArtboardBase : public Drawable protected: virtual void artboardIdChanged() {} - virtual void fitChanged() {} - virtual void alignmentChanged() {} virtual void dataBindPathIdsChanged() {} }; } // namespace rive diff --git a/include/rive/generated/nested_artboard_layout_base.hpp b/include/rive/generated/nested_artboard_layout_base.hpp new file mode 100644 index 00000000..7c5ce6f6 --- /dev/null +++ b/include/rive/generated/nested_artboard_layout_base.hpp @@ -0,0 +1,42 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LAYOUT_BASE_HPP_ +#define _RIVE_NESTED_ARTBOARD_LAYOUT_BASE_HPP_ +#include "rive/nested_artboard.hpp" +namespace rive +{ +class NestedArtboardLayoutBase : public NestedArtboard +{ +protected: + typedef NestedArtboard Super; + +public: + static const uint16_t typeKey = 452; + + /// Helper to quickly determine if a core object extends another without RTTI + /// at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedArtboardLayoutBase::typeKey: + case NestedArtboardBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + Core* clone() const override; + +protected: +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/generated/nested_artboard_leaf_base.hpp b/include/rive/generated/nested_artboard_leaf_base.hpp new file mode 100644 index 00000000..d72fa60b --- /dev/null +++ b/include/rive/generated/nested_artboard_leaf_base.hpp @@ -0,0 +1,114 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LEAF_BASE_HPP_ +#define _RIVE_NESTED_ARTBOARD_LEAF_BASE_HPP_ +#include "rive/core/field_types/core_double_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +#include "rive/nested_artboard.hpp" +namespace rive +{ +class NestedArtboardLeafBase : public NestedArtboard +{ +protected: + typedef NestedArtboard Super; + +public: + static const uint16_t typeKey = 451; + + /// Helper to quickly determine if a core object extends another without RTTI + /// at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case NestedArtboardLeafBase::typeKey: + case NestedArtboardBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: + case WorldTransformComponentBase::typeKey: + case ContainerComponentBase::typeKey: + case ComponentBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t fitPropertyKey = 538; + static const uint16_t alignmentXPropertyKey = 644; + static const uint16_t alignmentYPropertyKey = 645; + +private: + uint32_t m_Fit = 0; + float m_AlignmentX = 0.0f; + float m_AlignmentY = 0.0f; + +public: + inline uint32_t fit() const { return m_Fit; } + void fit(uint32_t value) + { + if (m_Fit == value) + { + return; + } + m_Fit = value; + fitChanged(); + } + + inline float alignmentX() const { return m_AlignmentX; } + void alignmentX(float value) + { + if (m_AlignmentX == value) + { + return; + } + m_AlignmentX = value; + alignmentXChanged(); + } + + inline float alignmentY() const { return m_AlignmentY; } + void alignmentY(float value) + { + if (m_AlignmentY == value) + { + return; + } + m_AlignmentY = value; + alignmentYChanged(); + } + + Core* clone() const override; + void copy(const NestedArtboardLeafBase& object) + { + m_Fit = object.m_Fit; + m_AlignmentX = object.m_AlignmentX; + m_AlignmentY = object.m_AlignmentY; + NestedArtboard::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case fitPropertyKey: + m_Fit = CoreUintType::deserialize(reader); + return true; + case alignmentXPropertyKey: + m_AlignmentX = CoreDoubleType::deserialize(reader); + return true; + case alignmentYPropertyKey: + m_AlignmentY = CoreDoubleType::deserialize(reader); + return true; + } + return NestedArtboard::deserialize(propertyKey, reader); + } + +protected: + virtual void fitChanged() {} + virtual void alignmentXChanged() {} + virtual void alignmentYChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/layout_component.hpp b/include/rive/layout_component.hpp index 976544c7..c0c4bdb4 100644 --- a/include/rive/layout_component.hpp +++ b/include/rive/layout_component.hpp @@ -12,7 +12,7 @@ #include "yoga/YGStyle.h" #include "yoga/Yoga.h" #endif -#include + namespace rive { @@ -57,15 +57,12 @@ class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public Artboard* getArtboard() override { return artboard(); } private: - virtual void performUpdate(ComponentDirt value); - #ifdef WITH_RIVE_LAYOUT -private: +protected: YGNode& layoutNode() { return m_layoutData->node; } YGStyle& layoutStyle() { return m_layoutData->style; } void syncLayoutChildren(); void propagateSizeToChildren(ContainerComponent* component); - AABB findMaxIntrinsicSize(ContainerComponent* component, AABB maxIntrinsicSize); bool applyInterpolation(double elapsedSeconds); protected: @@ -75,11 +72,25 @@ class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public public: LayoutComponentStyle* style() { return m_style; } void style(LayoutComponentStyle* style) { m_style = style; } + void draw(Renderer* renderer) override; void drawProxy(Renderer* renderer) override; Core* hitTest(HitInfo*, const Mat2D&) override; DrawableProxy* proxy() { return &m_proxy; }; + virtual void updateRenderPath(); void update(ComponentDirt value) override; + void onDirty(ComponentDirt value) override; + AABB layoutBounds() + { + return AABB::fromLTWH(m_layoutLocationX, + m_layoutLocationY, + m_layoutSizeWidth, + m_layoutSizeHeight); + } + AABB localBounds() const override + { + return AABB::fromLTWH(0.0f, 0.0f, m_layoutSizeWidth, m_layoutSizeHeight); + } #ifdef WITH_RIVE_LAYOUT LayoutComponent() : m_layoutData(std::unique_ptr(new LayoutData())), m_proxy(this) @@ -91,6 +102,7 @@ class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public virtual void propagateSize(); void updateLayoutBounds(); StatusCode onAddedDirty(CoreContext* context) override; + StatusCode onAddedClean(CoreContext* context) override; bool advance(double elapsedSeconds); bool animates(); @@ -106,22 +118,9 @@ class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public KeyFrameInterpolator* inheritedInterpolator, float inheritedInterpolationTime); void clearInheritedInterpolation(); - virtual AABB layoutBounds() - { - return AABB(m_layoutLocationX, - m_layoutLocationY, - m_layoutLocationX + m_layoutSizeWidth, - m_layoutLocationY + m_layoutSizeHeight); - }; - bool hasLayoutMeasurements() - { - return m_layoutLocationX != 0 || m_layoutLocationY != 0 || m_layoutSizeWidth != 0 || - m_layoutSizeHeight != 0; - }; #else LayoutComponent() : m_layoutData(std::unique_ptr(new LayoutData())), m_proxy(this) {} - #endif void buildDependencies() override; diff --git a/include/rive/nested_artboard.hpp b/include/rive/nested_artboard.hpp index 57598156..64577275 100644 --- a/include/rive/nested_artboard.hpp +++ b/include/rive/nested_artboard.hpp @@ -11,30 +11,6 @@ namespace rive { -enum class NestedArtboardFitType : uint8_t -{ - fill, // Default value - scales to fill available view without maintaining aspect ratio - contain, - cover, - fitWidth, - fitHeight, - resizeArtboard, - none, -}; - -enum class NestedArtboardAlignmentType : uint8_t -{ - center, // Default value - topLeft, - topCenter, - topRight, - centerLeft, - centerRight, - bottomLeft, - bottomCenter, - bottomRight, -}; - class ArtboardInstance; class NestedAnimation; class NestedInput; @@ -42,13 +18,10 @@ class NestedStateMachine; class StateMachineInstance; class NestedArtboard : public NestedArtboardBase { - -private: +protected: Artboard* m_Artboard = nullptr; // might point to m_Instance, and might not std::unique_ptr m_Instance; // may be null std::vector m_NestedAnimations; - float m_layoutScaleX = NAN; - float m_layoutScaleY = NAN; protected: std::vector m_DataBindPathIdsBuffer; @@ -62,8 +35,7 @@ class NestedArtboard : public NestedArtboardBase void addNestedAnimation(NestedAnimation* nestedAnimation); void nest(Artboard* artboard); - - ArtboardInstance* artboard() { return m_Instance.get(); } + ArtboardInstance* artboardInstance() { return m_Instance.get(); } StatusCode import(ImportStack& importStack) override; Core* clone() const override; @@ -77,14 +49,6 @@ class NestedArtboard : public NestedArtboardBase NestedInput* input(std::string name) const; NestedInput* input(std::string name, std::string stateMachineName) const; - NestedArtboardAlignmentType alignmentType() const - { - return (NestedArtboardAlignmentType)alignment(); - } - NestedArtboardFitType fitType() const { return (NestedArtboardFitType)fit(); } - float effectiveScaleX() { return std::isnan(m_layoutScaleX) ? scaleX() : m_layoutScaleX; } - float effectiveScaleY() { return std::isnan(m_layoutScaleY) ? scaleY() : m_layoutScaleY; } - Vec2D measureLayout(float width, LayoutMeasureMode widthMode, float height, @@ -96,6 +60,7 @@ class NestedArtboard : public NestedArtboardBase /// nested within. Returns true when the conversion succeeds, and false /// when one is not possible. bool worldToLocal(Vec2D world, Vec2D* local); + void syncStyleChanges(); void decodeDataBindPathIds(Span value) override; void copyDataBindPathIds(const NestedArtboardBase& object) override; std::vector dataBindPathIds() { return m_DataBindPathIdsBuffer; }; diff --git a/include/rive/nested_artboard_layout.hpp b/include/rive/nested_artboard_layout.hpp new file mode 100644 index 00000000..9a680747 --- /dev/null +++ b/include/rive/nested_artboard_layout.hpp @@ -0,0 +1,19 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LAYOUT_HPP_ +#define _RIVE_NESTED_ARTBOARD_LAYOUT_HPP_ +#include "rive/generated/nested_artboard_layout_base.hpp" + +namespace rive +{ +class NestedArtboardLayout : public NestedArtboardLayoutBase +{ +public: +#ifdef WITH_RIVE_LAYOUT + void* layoutNode(); +#endif + Core* clone() const override; + void markNestedLayoutDirty(); + void update(ComponentDirt value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/nested_artboard_leaf.hpp b/include/rive/nested_artboard_leaf.hpp new file mode 100644 index 00000000..a7fa3d57 --- /dev/null +++ b/include/rive/nested_artboard_leaf.hpp @@ -0,0 +1,15 @@ +#ifndef _RIVE_NESTED_ARTBOARD_LEAF_HPP_ +#define _RIVE_NESTED_ARTBOARD_LEAF_HPP_ +#include "rive/generated/nested_artboard_leaf_base.hpp" +#include +namespace rive +{ +class NestedArtboardLeaf : public NestedArtboardLeafBase +{ +public: + Core* clone() const override; + void update(ComponentDirt value) override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/transform_component.hpp b/include/rive/transform_component.hpp index 151c31bc..36580a66 100644 --- a/include/rive/transform_component.hpp +++ b/include/rive/transform_component.hpp @@ -12,7 +12,7 @@ class WorldTransformComponent; class AABB; class TransformComponent : public TransformComponentBase { -private: +protected: Mat2D m_Transform; float m_RenderOpacity = 0.0f; WorldTransformComponent* m_ParentTransformComponent = nullptr; @@ -27,7 +27,7 @@ class TransformComponent : public TransformComponentBase StatusCode onAddedClean(CoreContext* context) override; void buildDependencies() override; void update(ComponentDirt value) override; - void updateTransform(); + virtual void updateTransform(); virtual void updateWorldTransform(); void markTransformDirty(); diff --git a/src/artboard.cpp b/src/artboard.cpp index 7cd9b029..263f683f 100644 --- a/src/artboard.cpp +++ b/src/artboard.cpp @@ -17,6 +17,8 @@ #include "rive/importers/backboard_importer.hpp" #include "rive/layout_component.hpp" #include "rive/nested_artboard.hpp" +#include "rive/nested_artboard_leaf.hpp" +#include "rive/nested_artboard_layout.hpp" #include "rive/joystick.hpp" #include "rive/data_bind_flags.hpp" #include "rive/animation/nested_bool.hpp" @@ -33,6 +35,8 @@ using namespace rive; +Artboard::Artboard() {} + Artboard::~Artboard() { #ifdef WITH_RIVE_AUDIO @@ -172,6 +176,8 @@ StatusCode Artboard::initialize() break; } case NestedArtboardBase::typeKey: + case NestedArtboardLeafBase::typeKey: + case NestedArtboardLayoutBase::typeKey: m_NestedArtboards.push_back(object->as()); break; @@ -336,6 +342,10 @@ StatusCode Artboard::initialize() m_DrawTargets.push_back(static_cast(*itr++)); } + // Some default layout dimensions. + m_layoutSizeWidth = width(); + m_layoutSizeHeight = height(); + return StatusCode::Ok; } @@ -490,6 +500,10 @@ void Artboard::onDirty(ComponentDirt dirt) { m_Dirt |= ComponentDirt::Components void Artboard::propagateSize() { addDirt(ComponentDirt::Path); + if (sharesLayoutWithHost()) + { + m_host->markTransformDirty(); + } #ifdef WITH_RIVE_TOOLS if (m_layoutChangedCallback != nullptr) { @@ -499,6 +513,38 @@ void Artboard::propagateSize() } #endif +bool Artboard::sharesLayoutWithHost() const +{ + return m_host != nullptr && m_host->is(); +} +void Artboard::host(NestedArtboard* nestedArtboard) +{ + m_host = nestedArtboard; +#ifdef WITH_RIVE_LAYOUT + if (!sharesLayoutWithHost()) + { + return; + } + Artboard* parent = parentArtboard(); + if (parent != nullptr) + { + parent->markLayoutDirty(this); + parent->syncLayoutChildren(); + } +#endif +} + +NestedArtboard* Artboard::host() const { return m_host; } + +Artboard* Artboard::parentArtboard() const +{ + if (m_host == nullptr) + { + return nullptr; + } + return m_host->artboard(); +} + float Artboard::layoutWidth() const { #ifdef WITH_RIVE_LAYOUT @@ -517,36 +563,52 @@ float Artboard::layoutHeight() const #endif } -void Artboard::performUpdate(ComponentDirt value) +float Artboard::layoutX() const { - if (hasDirt(value, ComponentDirt::DrawOrder)) +#ifdef WITH_RIVE_LAYOUT + return m_layoutLocationX; +#else + return 0.0f; +#endif +} + +float Artboard::layoutY() const +{ +#ifdef WITH_RIVE_LAYOUT + return m_layoutLocationY; +#else + return 0.0f; +#endif +} + +void Artboard::updateRenderPath() +{ + AABB bg = AABB::fromLTWH(-layoutWidth() * originX(), + -layoutHeight() * originY(), + layoutWidth(), + layoutHeight()); + AABB clip; + if (m_FrameOrigin) { - sortDrawOrder(); + clip = {0.0f, 0.0f, layoutWidth(), layoutHeight()}; } - if (hasDirt(value, ComponentDirt::Path)) + else { - AABB bg = AABB::fromLTWH(-layoutWidth() * originX(), - -layoutHeight() * originY(), - layoutWidth(), - layoutHeight()); - AABB clip; - if (m_FrameOrigin) - { - clip = {0.0f, 0.0f, layoutWidth(), layoutHeight()}; - } - else - { - clip = bg; - } - m_clipPath = factory()->makeRenderPath(clip); - - m_backgroundRawPath.addRect(bg); - m_backgroundPath->rewind(); - m_backgroundRawPath.addTo(m_backgroundPath.get()); + clip = bg; } - if (hasDirt(value, ComponentDirt::RenderOpacity)) + m_clipPath = factory()->makeRenderPath(clip); + m_backgroundRawPath.rewind(); + m_backgroundRawPath.addRect(bg); + m_backgroundPath->rewind(); + m_backgroundRawPath.addTo(m_backgroundPath.get()); +} + +void Artboard::update(ComponentDirt value) +{ + Super::update(value); + if (hasDirt(value, ComponentDirt::DrawOrder)) { - propagateOpacity(childOpacity()); + sortDrawOrder(); } } @@ -606,38 +668,97 @@ bool Artboard::updateComponents() return false; } -bool Artboard::advanceInternal(double elapsedSeconds, bool isRoot, bool nested) +void* Artboard::takeLayoutNode() { - bool didUpdate = false; - m_HasChangedDrawOrderInLastUpdate = false; +#ifdef WITH_RIVE_LAYOUT + m_updatesOwnLayout = false; + return static_cast(&layoutNode()); +#else + return nullptr; +#endif +} + +void Artboard::markLayoutDirty(LayoutComponent* layoutComponent) +{ +#ifdef WITH_RIVE_TOOLS + if (m_dirtyLayout.empty() && m_layoutDirtyCallback != nullptr) + { + m_layoutDirtyCallback(this); + } +#endif + m_dirtyLayout.insert(layoutComponent); + if (sharesLayoutWithHost()) + { + m_host->as()->markNestedLayoutDirty(); + } +} + +bool Artboard::syncStyleChanges() +{ + bool updated = false; #ifdef WITH_RIVE_LAYOUT if (!m_dirtyLayout.empty()) { - syncStyle(); for (auto layout : m_dirtyLayout) { - layout->syncStyle(); + switch (layout->coreType()) + { + case ArtboardBase::typeKey: + { + auto artboard = layout->as(); + if (artboard == this) + { + artboard->syncStyle(); + } + else + { + // This is a nested artboard, sync its changes too. + artboard->syncStyleChanges(); + } + break; + } + + default: + layout->syncStyle(); + break; + } } m_dirtyLayout.clear(); + updated = true; + } +#endif + return updated; +} + +bool Artboard::advanceInternal(double elapsedSeconds, bool isRoot, bool nested) +{ + bool didUpdate = false; + m_HasChangedDrawOrderInLastUpdate = false; +#ifdef WITH_RIVE_LAYOUT + if (hasDirt(ComponentDirt::LayoutStyle)) + { + cascadeAnimationStyle(interpolation(), interpolator(), interpolationTime()); + } + + if (syncStyleChanges() && m_updatesOwnLayout) + { calculateLayout(); - if (hasDirt(ComponentDirt::LayoutStyle)) - { - cascadeAnimationStyle(interpolation(), interpolator(), interpolationTime()); - } - for (auto dep : m_DependencyOrder) + } + + for (auto dep : m_DependencyOrder) + { + if (dep->is()) { - if (dep->is()) + auto layout = dep->as(); + layout->updateLayoutBounds(); + if ((dep == this && Super::advance(elapsedSeconds)) || + (dep != this && layout->advance(elapsedSeconds))) { - auto layout = dep->as(); - layout->updateLayoutBounds(); - if ((dep == this && Super::advance(elapsedSeconds)) || - (dep != this && layout->advance(elapsedSeconds))) - { - didUpdate = true; - } + didUpdate = true; } } } + #endif if (m_JoysticksApplyBeforeUpdate) { @@ -791,6 +912,12 @@ void Artboard::addToRenderPath(RenderPath* path, const Mat2D& transform) } } +Vec2D Artboard::origin() const +{ + return m_FrameOrigin ? Vec2D(0.0f, 0.0f) + : Vec2D(-layoutWidth() * originX(), -layoutHeight() * originY()); +} + AABB Artboard::bounds() const { return m_FrameOrigin ? AABB(0.0f, 0.0f, layoutWidth(), layoutHeight()) @@ -823,7 +950,7 @@ bool Artboard::hasAudio() const } for (auto nestedArtboard : m_NestedArtboards) { - if (nestedArtboard->artboard()->hasAudio()) + if (nestedArtboard->artboardInstance()->hasAudio()) { return true; } @@ -954,7 +1081,7 @@ NestedArtboard* Artboard::nestedArtboardAtPath(const std::string& path) const } else { - auto artboard = nested->artboard(); + auto artboard = nested->artboardInstance(); return artboard->nestedArtboardAtPath(restOfPath); } } @@ -1039,7 +1166,7 @@ void Artboard::internalDataContext(DataContext* value, DataContext* parent, bool m_DataContext->parent(parent); for (auto nestedArtboard : m_NestedArtboards) { - if (nestedArtboard->artboard() == nullptr) + if (nestedArtboard->artboardInstance() == nullptr) { continue; } @@ -1084,7 +1211,7 @@ void Artboard::volume(float value) m_volume = value; for (auto nestedArtboard : m_NestedArtboards) { - auto artboard = nestedArtboard->artboard(); + auto artboard = nestedArtboard->artboardInstance(); if (artboard != nullptr) { artboard->volume(value); @@ -1100,9 +1227,9 @@ void Artboard::populateDataBinds(std::vector* dataBinds) } for (auto nestedArtboard : m_NestedArtboards) { - if (nestedArtboard->artboard() != nullptr) + if (nestedArtboard->artboardInstance() != nullptr) { - nestedArtboard->artboard()->populateDataBinds(dataBinds); + nestedArtboard->artboardInstance()->populateDataBinds(dataBinds); } } } @@ -1236,7 +1363,7 @@ void Artboard::audioEngine(rcp audioEngine) m_audioEngine = audioEngine; for (auto nestedArtboard : m_NestedArtboards) { - auto artboard = nestedArtboard->artboard(); + auto artboard = nestedArtboard->artboardInstance(); if (artboard != nullptr) { artboard->audioEngine(audioEngine); diff --git a/src/generated/nested_artboard_layout_base.cpp b/src/generated/nested_artboard_layout_base.cpp new file mode 100644 index 00000000..069c3746 --- /dev/null +++ b/src/generated/nested_artboard_layout_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/nested_artboard_layout_base.hpp" +#include "rive/nested_artboard_layout.hpp" + +using namespace rive; + +Core* NestedArtboardLayoutBase::clone() const +{ + auto cloned = new NestedArtboardLayout(); + cloned->copy(*this); + return cloned; +} diff --git a/src/generated/nested_artboard_leaf_base.cpp b/src/generated/nested_artboard_leaf_base.cpp new file mode 100644 index 00000000..d025a17f --- /dev/null +++ b/src/generated/nested_artboard_leaf_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/nested_artboard_leaf_base.hpp" +#include "rive/nested_artboard_leaf.hpp" + +using namespace rive; + +Core* NestedArtboardLeafBase::clone() const +{ + auto cloned = new NestedArtboardLeaf(); + cloned->copy(*this); + return cloned; +} diff --git a/src/layout_component.cpp b/src/layout_component.cpp index 52040d41..872e88ef 100644 --- a/src/layout_component.cpp +++ b/src/layout_component.cpp @@ -9,6 +9,7 @@ #include "rive/shapes/paint/shape_paint.hpp" #include "rive/shapes/paint/stroke.hpp" #include "rive/shapes/rectangle.hpp" +#include "rive/nested_artboard_layout.hpp" #ifdef WITH_RIVE_LAYOUT #include "rive/transform_component.hpp" #include "yoga/YGEnums.h" @@ -82,51 +83,52 @@ void LayoutComponent::draw(Renderer* renderer) Core* LayoutComponent::hitTest(HitInfo*, const Mat2D&) { return nullptr; } -void LayoutComponent::update(ComponentDirt value) +void LayoutComponent::updateRenderPath() { - Super::update(value); - performUpdate(value); + m_backgroundRect->width(m_layoutSizeWidth); + m_backgroundRect->height(m_layoutSizeHeight); + m_backgroundRect->linkCornerRadius(style()->linkCornerRadius()); + m_backgroundRect->cornerRadiusTL(style()->cornerRadiusTL()); + m_backgroundRect->cornerRadiusTR(style()->cornerRadiusTR()); + m_backgroundRect->cornerRadiusBL(style()->cornerRadiusBL()); + m_backgroundRect->cornerRadiusBR(style()->cornerRadiusBR()); + m_backgroundRect->update(ComponentDirt::Path); + + m_backgroundPath->rewind(); + m_backgroundRect->rawPath().addTo(m_backgroundPath.get()); + + RawPath clipPath; + clipPath.addPath(m_backgroundRect->rawPath(), &m_WorldTransform); + m_clipPath = artboard()->factory()->makeRenderPath(clipPath, FillRule::nonZero); } -void LayoutComponent::performUpdate(ComponentDirt value) +void LayoutComponent::update(ComponentDirt value) { + Super::update(value); if (hasDirt(value, ComponentDirt::RenderOpacity)) { - propagateOpacity(renderOpacity()); + propagateOpacity(childOpacity()); } - if (hasDirt(value, ComponentDirt::Path)) - { - m_backgroundRect->width(m_layoutSizeWidth); - m_backgroundRect->height(m_layoutSizeHeight); - m_backgroundRect->linkCornerRadius(style()->linkCornerRadius()); - m_backgroundRect->cornerRadiusTL(style()->cornerRadiusTL()); - m_backgroundRect->cornerRadiusTR(style()->cornerRadiusTR()); - m_backgroundRect->cornerRadiusBL(style()->cornerRadiusBL()); - m_backgroundRect->cornerRadiusBR(style()->cornerRadiusBR()); - m_backgroundRect->update(value); - - m_backgroundPath->rewind(); - m_backgroundRect->rawPath().addTo(m_backgroundPath.get()); - AABB clipBounds = AABB::fromLTWH(worldTranslation().x, - worldTranslation().y, - worldTranslation().x + m_layoutSizeWidth, - worldTranslation().y + m_layoutSizeHeight); - m_clipPath = artboard()->factory()->makeRenderPath(clipBounds); - } - if (hasDirt(value, ComponentDirt::WorldTransform)) + if (parent() != nullptr && hasDirt(value, ComponentDirt::WorldTransform)) { Mat2D parentWorld = parent()->is() ? (parent()->as())->worldTransform() : Mat2D(); - auto transform = Mat2D(); - transform[4] = m_layoutLocationX; - transform[5] = m_layoutLocationY; - - auto multipliedTransform = Mat2D::multiply(parentWorld, transform); - m_WorldTransform = multipliedTransform; - + auto location = Vec2D(m_layoutLocationX, m_layoutLocationY); + if (parent()->is()) + { + auto art = parent()->as(); + location -= + Vec2D(art->layoutWidth() * art->originX(), art->layoutHeight() * art->originY()); + } + auto transform = Mat2D::fromTranslation(location); + m_WorldTransform = Mat2D::multiply(parentWorld, transform); updateConstraints(); } + if (hasDirt(value, ComponentDirt::Path)) + { + updateRenderPath(); + } } #ifdef WITH_RIVE_LAYOUT @@ -145,16 +147,24 @@ StatusCode LayoutComponent::onAddedDirty(CoreContext* context) } m_style = static_cast(coreStyle); addChild(m_style); - artboard()->markLayoutDirty(this); - markLayoutStyleDirty(); - if (parent() != nullptr && parent()->is()) + + return StatusCode::Ok; +} + +StatusCode LayoutComponent::onAddedClean(CoreContext* context) +{ + auto code = Super::onAddedClean(context); + if (code != StatusCode::Ok) { - parent()->as()->syncLayoutChildren(); + return code; } + artboard()->markLayoutDirty(this); + markLayoutStyleDirty(); m_backgroundPath = artboard()->factory()->makeEmptyRenderPath(); m_clipPath = artboard()->factory()->makeEmptyRenderPath(); m_backgroundRect->originX(0); m_backgroundRect->originY(0); + syncLayoutChildren(); return StatusCode::Ok; } @@ -185,6 +195,7 @@ Vec2D LayoutComponent::measureLayout(float width, { continue; } + // && child->is()->canMeasure() for nested artboard layout if (child->is()) { auto transformComponent = child->as(); @@ -368,27 +379,33 @@ void LayoutComponent::syncStyle() void LayoutComponent::syncLayoutChildren() { - YGNodeRemoveAllChildren(&layoutNode()); + auto ourNode = &layoutNode(); + YGNodeRemoveAllChildren(ourNode); int index = 0; - for (size_t i = 0; i < children().size(); i++) + for (auto child : children()) { - Component* child = children()[i]; - if (child->is()) + YGNode* node = nullptr; + switch (child->coreType()) + { + case LayoutComponentBase::typeKey: + node = &child->as()->layoutNode(); + break; + case NestedArtboardLayoutBase::typeKey: + node = static_cast(child->as()->layoutNode()); + break; + } + if (node != nullptr) { - YGNodeInsertChild(&layoutNode(), &child->as()->layoutNode(), index); - index += 1; + // YGNodeInsertChild(ourNode, node, index++); + ourNode->insertChild(node, index++); + node->setOwner(ourNode); + ourNode->markDirtyAndPropagate(); } } + markLayoutNodeDirty(); } -void LayoutComponent::propagateSize() -{ - if (artboard() == this) - { - return; - } - propagateSizeToChildren(this); -} +void LayoutComponent::propagateSize() { propagateSizeToChildren(this); } void LayoutComponent::propagateSizeToChildren(ContainerComponent* component) { @@ -415,6 +432,15 @@ void LayoutComponent::calculateLayout() YGNodeCalculateLayout(&layoutNode(), width(), height(), YGDirection::YGDirectionInherit); } +void LayoutComponent::onDirty(ComponentDirt value) +{ + Super::onDirty(value); + if ((value & ComponentDirt::WorldTransform) == ComponentDirt::WorldTransform && clip()) + { + addDirt(ComponentDirt::Path); + } +} + void LayoutComponent::updateLayoutBounds() { auto node = &layoutNode(); @@ -422,6 +448,22 @@ void LayoutComponent::updateLayoutBounds() auto top = YGNodeLayoutGetTop(node); auto width = YGNodeLayoutGetWidth(node); auto height = YGNodeLayoutGetHeight(node); + +#ifdef DEBUG + // Temporarily here to keep track of an issue. + if (left != left || top != top || width != width || height != height) + { + fprintf(stderr, + "Layout returned nan: %f %f %f %f | %p %s\n", + left, + top, + width, + height, + YGNodeGetParent(node), + name().c_str()); + return; + } +#endif if (animates()) { auto toBounds = m_animationData.toBounds; @@ -438,13 +480,21 @@ void LayoutComponent::updateLayoutBounds() markWorldTransformDirty(); } } - else if (left != m_layoutLocationX || top != m_layoutLocationY || width != m_layoutSizeWidth || - height != m_layoutSizeHeight) + else + + if (left != m_layoutLocationX || top != m_layoutLocationY || width != m_layoutSizeWidth || + height != m_layoutSizeHeight) { + if (m_layoutSizeWidth != width || m_layoutSizeHeight != height) + { + // Width changed, we need to rebuild the path. + addDirt(ComponentDirt::Path); + } m_layoutLocationX = left; m_layoutLocationY = top; m_layoutSizeWidth = width; m_layoutSizeHeight = height; + propagateSize(); markWorldTransformDirty(); } @@ -572,14 +622,25 @@ bool LayoutComponent::applyInterpolation(double elapsedSeconds) { return false; } + if (m_animationData.elapsedSeconds >= interpolationTime()) { m_layoutLocationX = m_animationData.toBounds.left(); m_layoutLocationY = m_animationData.toBounds.top(); - m_layoutSizeWidth = m_animationData.toBounds.width(); - m_layoutSizeHeight = m_animationData.toBounds.height(); + + float width = m_animationData.toBounds.width(); + float height = m_animationData.toBounds.height(); + if (width != m_layoutSizeWidth || height != m_layoutSizeHeight) + { + addDirt(ComponentDirt::Path); + } + m_layoutSizeWidth = width; + m_layoutSizeHeight = height; + m_animationData.elapsedSeconds = 0; + propagateSize(); markWorldTransformDirty(); + return false; } float f = 1; @@ -631,13 +692,13 @@ bool LayoutComponent::applyInterpolation(double elapsedSeconds) needsAdvance = true; m_layoutSizeWidth = width; m_layoutSizeHeight = height; + addDirt(ComponentDirt::Path); } m_animationData.elapsedSeconds = m_animationData.elapsedSeconds + (float)elapsedSeconds; if (needsAdvance) { propagateSize(); markWorldTransformDirty(); - markLayoutNodeDirty(); } return needsAdvance; } @@ -668,9 +729,10 @@ Vec2D LayoutComponent::measureLayout(float width, void LayoutComponent::markLayoutNodeDirty() {} void LayoutComponent::markLayoutStyleDirty() {} +void LayoutComponent::onDirty(ComponentDirt value) {} #endif void LayoutComponent::clipChanged() { markLayoutNodeDirty(); } void LayoutComponent::widthChanged() { markLayoutNodeDirty(); } void LayoutComponent::heightChanged() { markLayoutNodeDirty(); } -void LayoutComponent::styleIdChanged() { markLayoutNodeDirty(); } \ No newline at end of file +void LayoutComponent::styleIdChanged() { markLayoutNodeDirty(); } diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp index 95138b07..6f30c4c1 100644 --- a/src/nested_artboard.cpp +++ b/src/nested_artboard.cpp @@ -45,7 +45,9 @@ void NestedArtboard::nest(Artboard* artboard) { m_Instance.reset(static_cast(artboard)); // take ownership } - m_Artboard->advanceInternal(0.0f, false); + // This allows for swapping after initial load (after onAddedClean has + // already been called). + m_Artboard->host(this); } static Mat2D makeTranslate(const Artboard* artboard) @@ -124,6 +126,7 @@ StatusCode NestedArtboard::onAddedClean(CoreContext* context) { animation->initializeAnimation(m_Instance.get()); } + m_Artboard->host(this); } return Super::onAddedClean(context); } @@ -247,19 +250,17 @@ Vec2D NestedArtboard::measureLayout(float width, m_Instance ? m_Instance->height() : 0.0f)); } -void NestedArtboard::controlSize(Vec2D size) +void NestedArtboard::syncStyleChanges() { - auto newScaleX = size.x / m_Artboard->originalWidth(); - auto newScaleY = size.y / m_Artboard->originalHeight(); - if (newScaleX != scaleX() || newScaleY != scaleY()) + if (m_Artboard == nullptr) { - // TODO: Support nested artboard fit & alignment - scaleX(newScaleX); - scaleY(newScaleY); - addDirt(ComponentDirt::WorldTransform, false); + return; } + m_Artboard->syncStyleChanges(); } +void NestedArtboard::controlSize(Vec2D size) {} + void NestedArtboard::decodeDataBindPathIds(Span value) { BinaryReader reader(value); @@ -277,7 +278,7 @@ void NestedArtboard::copyDataBindPathIds(const NestedArtboardBase& object) void NestedArtboard::internalDataContext(DataContext* value, DataContext* parent) { - artboard()->internalDataContext(value, parent, false); + artboardInstance()->internalDataContext(value, parent, false); for (auto animation : m_NestedAnimations) { if (animation->is()) @@ -290,7 +291,7 @@ void NestedArtboard::internalDataContext(DataContext* value, DataContext* parent void NestedArtboard::dataContextFromInstance(ViewModelInstance* viewModelInstance, DataContext* parent) { - artboard()->dataContextFromInstance(viewModelInstance, parent, false); + artboardInstance()->dataContextFromInstance(viewModelInstance, parent, false); for (auto animation : m_NestedAnimations) { if (animation->is()) diff --git a/src/nested_artboard_layout.cpp b/src/nested_artboard_layout.cpp new file mode 100644 index 00000000..eed115e4 --- /dev/null +++ b/src/nested_artboard_layout.cpp @@ -0,0 +1,60 @@ +#include "rive/nested_artboard_layout.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +Core* NestedArtboardLayout::clone() const +{ + NestedArtboardLayout* nestedArtboard = + static_cast(NestedArtboardLayoutBase::clone()); + if (m_Artboard == nullptr) + { + return nestedArtboard; + } + auto ni = m_Artboard->instance(); + nestedArtboard->nest(ni.release()); + return nestedArtboard; +} + +#ifdef WITH_RIVE_LAYOUT +void* NestedArtboardLayout::layoutNode() +{ + if (artboardInstance() == nullptr) + { + return nullptr; + } + return artboardInstance()->takeLayoutNode(); +} +#endif + +void NestedArtboardLayout::markNestedLayoutDirty() +{ + if (artboardInstance() != nullptr) + { + artboardInstance()->markLayoutNodeDirty(); + } +} + +void NestedArtboardLayout::update(ComponentDirt value) +{ + Super::update(value); + auto artboard = artboardInstance(); + if (hasDirt(value, ComponentDirt::WorldTransform) && artboard != nullptr) + { + auto layoutPosition = Vec2D(artboard->layoutX(), artboard->layoutY()); + + if (parent()->is()) + { + auto parentArtboard = parent()->as(); + auto correctedArtboardSpace = + Mat2D::fromTranslation(parentArtboard->origin() + layoutPosition); + m_WorldTransform = correctedArtboardSpace * m_WorldTransform; + } + else + { + m_WorldTransform = Mat2D::fromTranslation(layoutPosition) * m_WorldTransform; + } + auto back = Mat2D::fromTranslation(-artboard->origin()); + m_WorldTransform = back * m_WorldTransform; + } +} \ No newline at end of file diff --git a/src/nested_artboard_leaf.cpp b/src/nested_artboard_leaf.cpp new file mode 100644 index 00000000..2ae92b6e --- /dev/null +++ b/src/nested_artboard_leaf.cpp @@ -0,0 +1,40 @@ +#include "rive/nested_artboard_leaf.hpp" +#include "rive/renderer.hpp" +#include "rive/layout_component.hpp" +#include "rive/artboard.hpp" + +using namespace rive; + +Core* NestedArtboardLeaf::clone() const +{ + NestedArtboardLeaf* nestedArtboard = + static_cast(NestedArtboardLeafBase::clone()); + if (m_Artboard == nullptr) + { + return nestedArtboard; + } + auto ni = m_Artboard->instance(); + nestedArtboard->nest(ni.release()); + return nestedArtboard; +} + +void NestedArtboardLeaf::update(ComponentDirt value) +{ + Super::update(value); + auto artboard = artboardInstance(); + if (hasDirt(value, ComponentDirt::WorldTransform) && artboard != nullptr) + { + auto p = parent(); + + AABB bounds = p != nullptr && p->is() + ? p->as()->localBounds() + : AABB(); + + auto viewTransform = computeAlignment((Fit)fit(), + Alignment(alignmentX(), alignmentY()), + bounds, + artboard->bounds()); + + m_WorldTransform *= viewTransform; + } +} diff --git a/test/nested_artboard.cpp b/test/nested_artboard.cpp index db0c21cb..fa886261 100644 --- a/test/nested_artboard.cpp +++ b/test/nested_artboard.cpp @@ -27,13 +27,13 @@ TEST_CASE("collapsed nested artboards do not advance", "[solo]") // if checking whether the time of each artboard has advanced // Unfortunately there is no way of accessing the time of the animations directly auto redNestedArtboard = stateMachine->artboard()->find("red-artboard"); - auto redNestedArtboardArtboard = redNestedArtboard->artboard(); + auto redNestedArtboardArtboard = redNestedArtboard->artboardInstance(); auto movingShapes = redNestedArtboardArtboard->find(); auto redRect = movingShapes.at(0); REQUIRE(redRect->x() > 50); auto greenNestedArtboard = stateMachine->artboard()->find("green-artboard"); - auto greenNestedArtboardArtboard = greenNestedArtboard->artboard(); + auto greenNestedArtboardArtboard = greenNestedArtboard->artboardInstance(); auto greenMovingShapes = greenNestedArtboardArtboard->find(); auto greenRect = greenMovingShapes.at(0); REQUIRE(greenRect->x() == 50); diff --git a/test/nested_artboard_opacity_test.cpp b/test/nested_artboard_opacity_test.cpp index 5fdd19e5..209f2092 100644 --- a/test/nested_artboard_opacity_test.cpp +++ b/test/nested_artboard_opacity_test.cpp @@ -16,8 +16,8 @@ TEST_CASE("Nested artboard background renders with opacity", "[file]") REQUIRE(artboard->find("Nested artboard container") != nullptr); auto nestedArtboardContainer = artboard->find("Nested artboard container"); - REQUIRE(nestedArtboardContainer->artboard() != nullptr); - auto nestedArtboard = nestedArtboardContainer->artboard(); + REQUIRE(nestedArtboardContainer->artboardInstance() != nullptr); + auto nestedArtboard = nestedArtboardContainer->artboardInstance(); nestedArtboard->updateComponents(); auto paints = nestedArtboard->shapePaints(); REQUIRE(paints.size() == 1); diff --git a/test/solo_test.cpp b/test/solo_test.cpp index e53b2509..30d57b01 100644 --- a/test/solo_test.cpp +++ b/test/solo_test.cpp @@ -237,9 +237,9 @@ TEST_CASE("hit test on nested artboards in solos", "[solo]") REQUIRE(artboard->is()); REQUIRE(artboard->find("Nested-Artboard-Active") != nullptr); auto nestedArtboardActive = artboard->find("Nested-Artboard-Active"); - REQUIRE(nestedArtboardActive->artboard() != nullptr); + REQUIRE(nestedArtboardActive->artboardInstance() != nullptr); - auto nestedArtboardActiveArtboardInstance = nestedArtboardActive->artboard(); + auto nestedArtboardActiveArtboardInstance = nestedArtboardActive->artboardInstance(); auto activeRect = nestedArtboardActiveArtboardInstance->find("Clickable-Rectangle"); REQUIRE(activeRect != nullptr); @@ -250,8 +250,8 @@ TEST_CASE("hit test on nested artboards in solos", "[solo]") REQUIRE(artboard->find("Nested-Artboard-Inactive") != nullptr); auto nestedArtboardInactive = artboard->find("Nested-Artboard-Inactive"); - REQUIRE(nestedArtboardInactive->artboard() != nullptr); - auto nestedArtboardInactiveArtboardInstance = nestedArtboardInactive->artboard(); + REQUIRE(nestedArtboardInactive->artboardInstance() != nullptr); + auto nestedArtboardInactiveArtboardInstance = nestedArtboardInactive->artboardInstance(); auto inactiveRect = nestedArtboardInactiveArtboardInstance->find("Clickable-Rectangle"); REQUIRE(inactiveRect != nullptr);