From 93014af4d56bbda0524d1cb35d4d4f68abfd1f33 Mon Sep 17 00:00:00 2001 From: philter Date: Tue, 23 Jul 2024 15:56:13 +0000 Subject: [PATCH] Layout drawable - [x] Changes LayoutComponent to extend Drawable (implements ShapePaintContainer) - [x] Fixes some API naming conflicts - [x] Adds DrawableProxy to allow inserting custom draw commands into draw order (allows LayoutComponent fills to be drawn below children and strokes to be drawn above - [x] Works with Fill/Stroke inspectors - [x] Adds corner radius core props - [x] Clipping - [x] CPP Updates - [x] Clipping in CPP - [x] Deal with conflicting x/y properties in Node & Artboard (CPP) https://github.com/rive-app/rive/assets/186340/5aec1cd5-6b00-4627-bfce-9cdeec8e3e96 Showing clipping and blend modes / opacity https://github.com/user-attachments/assets/843b6c74-cec0-4333-8ef1-6fee9b910a59 Diffs= 114da4e39 Layout drawable (#7544) Co-authored-by: Philip Chung --- .rive_head | 2 +- dev/core_generator/lib/src/definition.dart | 23 +++ dev/core_generator/lib/src/key.dart | 31 +++- dev/defs/artboard.json | 18 --- dev/defs/layout/layout_component_style.json | 49 +++++++ dev/defs/layout_component.json | 2 +- dev/defs/node.json | 16 +- include/rive/artboard.hpp | 24 +-- include/rive/drawable.hpp | 21 ++- include/rive/generated/artboard_base.hpp | 39 +---- include/rive/generated/core_registry.hpp | 64 ++++++-- .../layout/layout_component_style_base.hpp | 90 ++++++++++++ .../rive/generated/layout_component_base.hpp | 13 +- include/rive/generated/node_base.hpp | 2 + .../rive/layout/layout_component_style.hpp | 9 +- include/rive/layout_component.hpp | 32 +++- include/rive/transform_component.hpp | 5 +- src/artboard.cpp | 67 +++++++-- src/drawable.cpp | 2 +- src/layout/layout_component_style.cpp | 6 +- src/layout_component.cpp | 137 +++++++++++++++--- src/nested_artboard.cpp | 4 +- src/shapes/image.cpp | 2 +- src/shapes/path.cpp | 4 + src/shapes/shape.cpp | 2 +- src/shapes/shape_paint_container.cpp | 3 + src/text/text.cpp | 2 +- src/transform_component.cpp | 4 + test/clip_test.cpp | 6 +- 29 files changed, 538 insertions(+), 141 deletions(-) diff --git a/.rive_head b/.rive_head index 518b856a..8cbe00c0 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -b5f342002be71c61608ad6c37835349eb4e7c719 +114da4e39ba61dd337e8f6f47c1c7b2fb2223915 diff --git a/dev/core_generator/lib/src/definition.dart b/dev/core_generator/lib/src/definition.dart index 5a04630f..bf94a2b7 100644 --- a/dev/core_generator/lib/src/definition.dart +++ b/dev/core_generator/lib/src/definition.dart @@ -183,6 +183,11 @@ class Definition { for (final property in properties) { code.writeln('static const uint16_t ${property.name}PropertyKey = ' '${property.key!.intValue};'); + for (final altKey in property.key!.alternates) { + code.writeln( + 'static const uint16_t ${altKey.stringValue}PropertyKey = ' + '${altKey.intValue};'); + } } if (storedProperties.any((prop) => !prop.isEncoded)) { code.writeln('private:'); @@ -486,6 +491,12 @@ class Definition { for (final property in properties) { ctxCode.writeln('case ${property.definition.name}Base' '::${property.name}PropertyKey:'); + if (property.key != null) { + for (final altKey in property.key!.alternates) { + ctxCode.writeln('case ${property.definition.name}Base' + '::${altKey.stringValue}PropertyKey:'); + } + } ctxCode.writeln('object->as<${property.definition.name}Base>()->' '${property.name}(value);'); ctxCode.writeln('break;'); @@ -506,6 +517,10 @@ class Definition { for (final property in properties) { ctxCode.writeln('case ${property.definition.name}Base' '::${property.name}PropertyKey:'); + for (final altKey in property.key!.alternates) { + ctxCode.writeln('case ${property.definition.name}Base' + '::${altKey.stringValue}PropertyKey:'); + } ctxCode .writeln('return object->as<${property.definition.name}Base>()->' '${property.name}();'); @@ -528,6 +543,10 @@ class Definition { for (final property in properties) { ctxCode.writeln('case ${property.definition.name}Base' '::${property.name}PropertyKey:'); + for (final altKey in property.key!.alternates) { + ctxCode.writeln('case ${property.definition.name}Base' + '::${altKey.stringValue}PropertyKey:'); + } } } ctxCode.writeln('return Core${fieldType.capitalizedName}Type::id;'); @@ -567,6 +586,10 @@ class Definition { for (final property in properties) { ctxCode.writeln('case ${property.definition.name}Base' '::${property.name}PropertyKey:'); + for (final altKey in property.key!.alternates) { + ctxCode.writeln('case ${property.definition.name}Base' + '::${altKey.stringValue}PropertyKey:'); + } ctxCode .writeln('return object->is<${property.definition.name}Base>();'); } diff --git a/dev/core_generator/lib/src/key.dart b/dev/core_generator/lib/src/key.dart index 8e1a8d0d..ca836847 100644 --- a/dev/core_generator/lib/src/key.dart +++ b/dev/core_generator/lib/src/key.dart @@ -4,6 +4,7 @@ import 'property.dart'; class Key { final String? stringValue; final int? intValue; + final List alternates = []; bool get isMissing => intValue == null; @@ -23,12 +24,36 @@ class Key { } dynamic iv = data['int']; dynamic sv = data['string']; + dynamic av = data['alternates']; if (iv is int && sv is String) { - return Key(sv, iv); + final key = Key(sv, iv); + if (av is List) { + for (final a in av) { + if (a is Map) { + dynamic altiv = a['int']; + dynamic altsv = a['string']; + key.alternates.add(Key(altsv, altiv)); + } + } + } + return key; } return null; } - Map serialize() => - {'int': intValue, 'string': stringValue}; + Map serialize() { + final json = {'int': intValue, 'string': stringValue}; + final altsJson = []; + for (final alt in alternates) { + final altJson = { + 'int': alt.intValue, + 'string': alt.stringValue + }; + altsJson.add(altJson); + } + if (altsJson.isNotEmpty) { + json['alternates'] = altsJson; + } + return json; + } } diff --git a/dev/defs/artboard.json b/dev/defs/artboard.json index 4079ccbe..bb527360 100644 --- a/dev/defs/artboard.json +++ b/dev/defs/artboard.json @@ -6,24 +6,6 @@ }, "extends": "layout_component.json", "properties": { - "x": { - "type": "double", - "initialValue": "0", - "key": { - "int": 9, - "string": "x" - }, - "description": "X coordinate in editor world space." - }, - "y": { - "type": "double", - "initialValue": "0", - "key": { - "int": 10, - "string": "y" - }, - "description": "Y coordinate in editor world space." - }, "originX": { "type": "double", "initialValue": "0", diff --git a/dev/defs/layout/layout_component_style.json b/dev/defs/layout/layout_component_style.json index 9bddf110..cb46d463 100644 --- a/dev/defs/layout/layout_component_style.json +++ b/dev/defs/layout/layout_component_style.json @@ -717,6 +717,55 @@ "string": "maxheightunitsvalue" }, "description": "" + }, + "linkCornerRadius": { + "type": "bool", + "initialValue": "true", + "key": { + "int": 639, + "string": "linkcornerradius" + }, + "description": "Whether the TL corner radius defines all the radiuses" + }, + "cornerRadiusTL": { + "type": "double", + "initialValue": "0", + "animates": true, + "key": { + "int": 640, + "string": "cornerradiustl" + }, + "description": "Top left radius of the corners of this layout" + }, + "cornerRadiusTR": { + "type": "double", + "initialValue": "0", + "animates": true, + "key": { + "int": 641, + "string": "cornerradiustr" + }, + "description": "Top right radius of the corners of this layout" + }, + "cornerRadiusBL": { + "type": "double", + "initialValue": "0", + "animates": true, + "key": { + "int": 642, + "string": "cornerradiusbl" + }, + "description": "Bottom left radius of the corners of this layout" + }, + "cornerRadiusBR": { + "type": "double", + "initialValue": "0", + "animates": true, + "key": { + "int": 643, + "string": "cornerradiusbr" + }, + "description": "Bottom right radius of the corners of this layout" } } } \ No newline at end of file diff --git a/dev/defs/layout_component.json b/dev/defs/layout_component.json index ac24d51d..8aca893a 100644 --- a/dev/defs/layout_component.json +++ b/dev/defs/layout_component.json @@ -4,7 +4,7 @@ "int": 409, "string": "layoutcomponent" }, - "extends": "world_transform_component.json", + "extends": "drawable.json", "properties": { "clip": { "type": "bool", diff --git a/dev/defs/node.json b/dev/defs/node.json index f604980a..90ff1820 100644 --- a/dev/defs/node.json +++ b/dev/defs/node.json @@ -14,7 +14,13 @@ "group": "position", "key": { "int": 13, - "string": "x" + "string": "x", + "alternates": [ + { + "int": 9, + "string": "xArtboard" + } + ] } }, "y": { @@ -25,7 +31,13 @@ "group": "position", "key": { "int": 14, - "string": "y" + "string": "y", + "alternates": [ + { + "int": 10, + "string": "yArtboard" + } + ] } }, "styleValue": { diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp index 9411ceb4..4b7cc3d9 100644 --- a/include/rive/artboard.hpp +++ b/include/rive/artboard.hpp @@ -13,7 +13,6 @@ #include "rive/hit_info.hpp" #include "rive/math/aabb.hpp" #include "rive/renderer.hpp" -#include "rive/shapes/shape_paint_container.hpp" #include "rive/text/text_value_run.hpp" #include "rive/event.hpp" #include "rive/audio/audio_engine.hpp" @@ -48,7 +47,7 @@ class SMITrigger; typedef void (*ArtboardCallback)(Artboard*); #endif -class Artboard : public ArtboardBase, public CoreContext, public ShapePaintContainer +class Artboard : public ArtboardBase, public CoreContext { friend class File; friend class ArtboardImporter; @@ -71,8 +70,6 @@ class Artboard : public ArtboardBase, public CoreContext, public ShapePaintConta unsigned int m_DirtDepth = 0; RawPath m_backgroundRawPath; - rcp m_BackgroundPath; - rcp m_ClipPath; Factory* m_Factory = nullptr; Drawable* m_FirstDrawable = nullptr; bool m_IsInstance = false; @@ -88,8 +85,7 @@ class Artboard : public ArtboardBase, public CoreContext, public ShapePaintConta void sortDependencies(); void sortDrawOrder(); void updateDataBinds(); - - Artboard* getArtboard() override { return this; } + void performUpdate(ComponentDirt value) override; #ifdef TESTING public: @@ -114,15 +110,20 @@ class Artboard : public ArtboardBase, public CoreContext, public ShapePaintConta // EXPERIMENTAL -- for internal testing only for now. // DO NOT RELY ON THIS as it may change/disappear in the future. - Core* hitTest(HitInfo*, const Mat2D* = nullptr); + Core* hitTest(HitInfo*, const Mat2D&) override; void onComponentDirty(Component* component); /// Update components that depend on each other in DAG order. bool updateComponents(); - void update(ComponentDirt value) override; void onDirty(ComponentDirt dirt) override; + // Artboards don't update their world transforms in the same way + // as other TransformComponents so we override this. + // This is because LayoutComponent extends Drawable, but + // Artboard is a special type of LayoutComponent + void updateWorldTransform() override {} + void markLayoutDirty(LayoutComponent* layoutComponent) { m_dirtyLayout.insert(layoutComponent); @@ -150,12 +151,13 @@ class Artboard : public ArtboardBase, public CoreContext, public ShapePaintConta kHideBG, kHideFG, }; - void draw(Renderer* renderer, DrawOption = DrawOption::kNormal); + void draw(Renderer* renderer, DrawOption option); + void draw(Renderer* renderer) override; void addToRenderPath(RenderPath* path, const Mat2D& transform); #ifdef TESTING - RenderPath* clipPath() const { return m_ClipPath.get(); } - RenderPath* backgroundPath() const { return m_BackgroundPath.get(); } + RenderPath* clipPath() const { return m_clipPath.get(); } + RenderPath* backgroundPath() const { return m_backgroundPath.get(); } #endif const std::vector& objects() const { return m_Objects; } diff --git a/include/rive/drawable.hpp b/include/rive/drawable.hpp index ca5e9966..b4e79b81 100644 --- a/include/rive/drawable.hpp +++ b/include/rive/drawable.hpp @@ -28,7 +28,7 @@ class Drawable : public DrawableBase public: BlendMode blendMode() const { return (BlendMode)blendModeValue(); } - ClipResult clip(Renderer* renderer) const; + ClipResult applyClip(Renderer* renderer) const; virtual void draw(Renderer* renderer) = 0; virtual Core* hitTest(HitInfo*, const Mat2D&) = 0; void addClippingShape(ClippingShape* shape); @@ -49,6 +49,25 @@ class Drawable : public DrawableBase StatusCode onAddedDirty(CoreContext* context) override; }; + +class ProxyDrawing +{ +public: + virtual void drawProxy(Renderer* renderer) = 0; +}; + +class DrawableProxy : public Drawable +{ +private: + ProxyDrawing* m_proxyDrawing; + +public: + DrawableProxy(ProxyDrawing* proxy) : m_proxyDrawing(proxy) {} + + void draw(Renderer* renderer) override { m_proxyDrawing->drawProxy(renderer); } + + Core* hitTest(HitInfo*, const Mat2D&) override { return nullptr; } +}; } // namespace rive #endif diff --git a/include/rive/generated/artboard_base.hpp b/include/rive/generated/artboard_base.hpp index ff19a02a..b7ae1b94 100644 --- a/include/rive/generated/artboard_base.hpp +++ b/include/rive/generated/artboard_base.hpp @@ -21,6 +21,9 @@ class ArtboardBase : public LayoutComponent { case ArtboardBase::typeKey: case LayoutComponentBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: case WorldTransformComponentBase::typeKey: case ContainerComponentBase::typeKey: case ComponentBase::typeKey: @@ -32,44 +35,18 @@ class ArtboardBase : public LayoutComponent uint16_t coreType() const override { return typeKey; } - static const uint16_t xPropertyKey = 9; - static const uint16_t yPropertyKey = 10; static const uint16_t originXPropertyKey = 11; static const uint16_t originYPropertyKey = 12; static const uint16_t defaultStateMachineIdPropertyKey = 236; static const uint16_t viewModelIdPropertyKey = 583; private: - float m_X = 0.0f; - float m_Y = 0.0f; float m_OriginX = 0.0f; float m_OriginY = 0.0f; uint32_t m_DefaultStateMachineId = -1; uint32_t m_ViewModelId = -1; public: - inline float x() const { return m_X; } - void x(float value) - { - if (m_X == value) - { - return; - } - m_X = value; - xChanged(); - } - - inline float y() const { return m_Y; } - void y(float value) - { - if (m_Y == value) - { - return; - } - m_Y = value; - yChanged(); - } - inline float originX() const { return m_OriginX; } void originX(float value) { @@ -117,8 +94,6 @@ class ArtboardBase : public LayoutComponent Core* clone() const override; void copy(const ArtboardBase& object) { - m_X = object.m_X; - m_Y = object.m_Y; m_OriginX = object.m_OriginX; m_OriginY = object.m_OriginY; m_DefaultStateMachineId = object.m_DefaultStateMachineId; @@ -130,12 +105,6 @@ class ArtboardBase : public LayoutComponent { switch (propertyKey) { - case xPropertyKey: - m_X = CoreDoubleType::deserialize(reader); - return true; - case yPropertyKey: - m_Y = CoreDoubleType::deserialize(reader); - return true; case originXPropertyKey: m_OriginX = CoreDoubleType::deserialize(reader); return true; @@ -153,8 +122,6 @@ class ArtboardBase : public LayoutComponent } protected: - virtual void xChanged() {} - virtual void yChanged() {} virtual void originXChanged() {} virtual void originYChanged() {} virtual void defaultStateMachineIdChanged() {} diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp index 3096b791..abeae9a8 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp @@ -516,6 +516,9 @@ class CoreRegistry case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: object->as()->intrinsicallySizedValue(value); break; + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + object->as()->linkCornerRadius(value); + break; case NestedSimpleAnimationBase::isPlayingPropertyKey: object->as()->isPlaying(value); break; @@ -1147,9 +1150,11 @@ class CoreRegistry object->as()->scaleY(value); break; case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: object->as()->x(value); break; case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: object->as()->y(value); break; case LayoutComponentStyleBase::gapHorizontalPropertyKey: @@ -1236,6 +1241,18 @@ class CoreRegistry case LayoutComponentStyleBase::interpolationTimePropertyKey: object->as()->interpolationTime(value); break; + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + object->as()->cornerRadiusTL(value); + break; + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + object->as()->cornerRadiusTR(value); + break; + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + object->as()->cornerRadiusBL(value); + break; + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + object->as()->cornerRadiusBR(value); + break; case NestedLinearAnimationBase::mixPropertyKey: object->as()->mix(value); break; @@ -1416,12 +1433,6 @@ class CoreRegistry case LayoutComponentBase::heightPropertyKey: object->as()->height(value); break; - case ArtboardBase::xPropertyKey: - object->as()->x(value); - break; - case ArtboardBase::yPropertyKey: - object->as()->y(value); - break; case ArtboardBase::originXPropertyKey: object->as()->originX(value); break; @@ -1625,6 +1636,8 @@ class CoreRegistry return object->as()->offset(); case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: return object->as()->intrinsicallySizedValue(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->as()->linkCornerRadius(); case NestedSimpleAnimationBase::isPlayingPropertyKey: return object->as()->isPlaying(); case KeyFrameBoolBase::valuePropertyKey: @@ -2058,8 +2071,10 @@ class CoreRegistry case TransformComponentBase::scaleYPropertyKey: return object->as()->scaleY(); case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: return object->as()->x(); case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: return object->as()->y(); case LayoutComponentStyleBase::gapHorizontalPropertyKey: return object->as()->gapHorizontal(); @@ -2117,6 +2132,14 @@ class CoreRegistry return object->as()->aspectRatio(); case LayoutComponentStyleBase::interpolationTimePropertyKey: return object->as()->interpolationTime(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->as()->cornerRadiusTL(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->as()->cornerRadiusTR(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->as()->cornerRadiusBL(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->as()->cornerRadiusBR(); case NestedLinearAnimationBase::mixPropertyKey: return object->as()->mix(); case NestedSimpleAnimationBase::speedPropertyKey: @@ -2237,10 +2260,6 @@ class CoreRegistry return object->as()->width(); case LayoutComponentBase::heightPropertyKey: return object->as()->height(); - case ArtboardBase::xPropertyKey: - return object->as()->x(); - case ArtboardBase::yPropertyKey: - return object->as()->y(); case ArtboardBase::originXPropertyKey: return object->as()->originX(); case ArtboardBase::originYPropertyKey: @@ -2367,6 +2386,7 @@ class CoreRegistry case FollowPathConstraintBase::orientPropertyKey: case FollowPathConstraintBase::offsetPropertyKey: case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: case NestedSimpleAnimationBase::isPlayingPropertyKey: case KeyFrameBoolBase::valuePropertyKey: case ListenerAlignTargetBase::preserveOffsetPropertyKey: @@ -2574,7 +2594,9 @@ class CoreRegistry case TransformComponentBase::scaleXPropertyKey: case TransformComponentBase::scaleYPropertyKey: case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: case LayoutComponentStyleBase::gapHorizontalPropertyKey: case LayoutComponentStyleBase::gapVerticalPropertyKey: case LayoutComponentStyleBase::maxWidthPropertyKey: @@ -2603,6 +2625,10 @@ class CoreRegistry case LayoutComponentStyleBase::flexBasisPropertyKey: case LayoutComponentStyleBase::aspectRatioPropertyKey: case LayoutComponentStyleBase::interpolationTimePropertyKey: + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: case NestedLinearAnimationBase::mixPropertyKey: case NestedSimpleAnimationBase::speedPropertyKey: case AdvanceableStateBase::speedPropertyKey: @@ -2663,8 +2689,6 @@ class CoreRegistry case CubicDetachedVertexBase::outDistancePropertyKey: case LayoutComponentBase::widthPropertyKey: case LayoutComponentBase::heightPropertyKey: - case ArtboardBase::xPropertyKey: - case ArtboardBase::yPropertyKey: case ArtboardBase::originXPropertyKey: case ArtboardBase::originYPropertyKey: case JoystickBase::xPropertyKey: @@ -2770,6 +2794,8 @@ class CoreRegistry return object->is(); case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: return object->is(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->is(); case NestedSimpleAnimationBase::isPlayingPropertyKey: return object->is(); case KeyFrameBoolBase::valuePropertyKey: @@ -3175,8 +3201,10 @@ class CoreRegistry case TransformComponentBase::scaleYPropertyKey: return object->is(); case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: return object->is(); case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: return object->is(); case LayoutComponentStyleBase::gapHorizontalPropertyKey: return object->is(); @@ -3234,6 +3262,14 @@ class CoreRegistry return object->is(); case LayoutComponentStyleBase::interpolationTimePropertyKey: return object->is(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->is(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->is(); case NestedLinearAnimationBase::mixPropertyKey: return object->is(); case NestedSimpleAnimationBase::speedPropertyKey: @@ -3354,10 +3390,6 @@ class CoreRegistry return object->is(); case LayoutComponentBase::heightPropertyKey: return object->is(); - case ArtboardBase::xPropertyKey: - return object->is(); - case ArtboardBase::yPropertyKey: - return object->is(); case ArtboardBase::originXPropertyKey: return object->is(); case ArtboardBase::originYPropertyKey: diff --git a/include/rive/generated/layout/layout_component_style_base.hpp b/include/rive/generated/layout/layout_component_style_base.hpp index b62fa973..a6f0cb56 100644 --- a/include/rive/generated/layout/layout_component_style_base.hpp +++ b/include/rive/generated/layout/layout_component_style_base.hpp @@ -98,6 +98,11 @@ class LayoutComponentStyleBase : public Component static const uint16_t minHeightUnitsValuePropertyKey = 628; static const uint16_t maxWidthUnitsValuePropertyKey = 629; static const uint16_t maxHeightUnitsValuePropertyKey = 630; + static const uint16_t linkCornerRadiusPropertyKey = 639; + static const uint16_t cornerRadiusTLPropertyKey = 640; + static const uint16_t cornerRadiusTRPropertyKey = 641; + static const uint16_t cornerRadiusBLPropertyKey = 642; + static const uint16_t cornerRadiusBRPropertyKey = 643; private: float m_GapHorizontal = 0.0f; @@ -168,6 +173,11 @@ class LayoutComponentStyleBase : public Component uint32_t m_MinHeightUnitsValue = 0; uint32_t m_MaxWidthUnitsValue = 0; uint32_t m_MaxHeightUnitsValue = 0; + bool m_LinkCornerRadius = true; + float m_CornerRadiusTL = 0.0f; + float m_CornerRadiusTR = 0.0f; + float m_CornerRadiusBL = 0.0f; + float m_CornerRadiusBR = 0.0f; public: inline float gapHorizontal() const { return m_GapHorizontal; } @@ -918,6 +928,61 @@ class LayoutComponentStyleBase : public Component maxHeightUnitsValueChanged(); } + inline bool linkCornerRadius() const { return m_LinkCornerRadius; } + void linkCornerRadius(bool value) + { + if (m_LinkCornerRadius == value) + { + return; + } + m_LinkCornerRadius = value; + linkCornerRadiusChanged(); + } + + inline float cornerRadiusTL() const { return m_CornerRadiusTL; } + void cornerRadiusTL(float value) + { + if (m_CornerRadiusTL == value) + { + return; + } + m_CornerRadiusTL = value; + cornerRadiusTLChanged(); + } + + inline float cornerRadiusTR() const { return m_CornerRadiusTR; } + void cornerRadiusTR(float value) + { + if (m_CornerRadiusTR == value) + { + return; + } + m_CornerRadiusTR = value; + cornerRadiusTRChanged(); + } + + inline float cornerRadiusBL() const { return m_CornerRadiusBL; } + void cornerRadiusBL(float value) + { + if (m_CornerRadiusBL == value) + { + return; + } + m_CornerRadiusBL = value; + cornerRadiusBLChanged(); + } + + inline float cornerRadiusBR() const { return m_CornerRadiusBR; } + void cornerRadiusBR(float value) + { + if (m_CornerRadiusBR == value) + { + return; + } + m_CornerRadiusBR = value; + cornerRadiusBRChanged(); + } + Core* clone() const override; void copy(const LayoutComponentStyleBase& object) { @@ -989,6 +1054,11 @@ class LayoutComponentStyleBase : public Component m_MinHeightUnitsValue = object.m_MinHeightUnitsValue; m_MaxWidthUnitsValue = object.m_MaxWidthUnitsValue; m_MaxHeightUnitsValue = object.m_MaxHeightUnitsValue; + m_LinkCornerRadius = object.m_LinkCornerRadius; + m_CornerRadiusTL = object.m_CornerRadiusTL; + m_CornerRadiusTR = object.m_CornerRadiusTR; + m_CornerRadiusBL = object.m_CornerRadiusBL; + m_CornerRadiusBR = object.m_CornerRadiusBR; Component::copy(object); } @@ -1200,6 +1270,21 @@ class LayoutComponentStyleBase : public Component case maxHeightUnitsValuePropertyKey: m_MaxHeightUnitsValue = CoreUintType::deserialize(reader); return true; + case linkCornerRadiusPropertyKey: + m_LinkCornerRadius = CoreBoolType::deserialize(reader); + return true; + case cornerRadiusTLPropertyKey: + m_CornerRadiusTL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusTRPropertyKey: + m_CornerRadiusTR = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBLPropertyKey: + m_CornerRadiusBL = CoreDoubleType::deserialize(reader); + return true; + case cornerRadiusBRPropertyKey: + m_CornerRadiusBR = CoreDoubleType::deserialize(reader); + return true; } return Component::deserialize(propertyKey, reader); } @@ -1273,6 +1358,11 @@ class LayoutComponentStyleBase : public Component virtual void minHeightUnitsValueChanged() {} virtual void maxWidthUnitsValueChanged() {} virtual void maxHeightUnitsValueChanged() {} + virtual void linkCornerRadiusChanged() {} + virtual void cornerRadiusTLChanged() {} + virtual void cornerRadiusTRChanged() {} + virtual void cornerRadiusBLChanged() {} + virtual void cornerRadiusBRChanged() {} }; } // namespace rive diff --git a/include/rive/generated/layout_component_base.hpp b/include/rive/generated/layout_component_base.hpp index e0c508a9..680f0319 100644 --- a/include/rive/generated/layout_component_base.hpp +++ b/include/rive/generated/layout_component_base.hpp @@ -3,13 +3,13 @@ #include "rive/core/field_types/core_bool_type.hpp" #include "rive/core/field_types/core_double_type.hpp" #include "rive/core/field_types/core_uint_type.hpp" -#include "rive/world_transform_component.hpp" +#include "rive/drawable.hpp" namespace rive { -class LayoutComponentBase : public WorldTransformComponent +class LayoutComponentBase : public Drawable { protected: - typedef WorldTransformComponent Super; + typedef Drawable Super; public: static const uint16_t typeKey = 409; @@ -21,6 +21,9 @@ class LayoutComponentBase : public WorldTransformComponent switch (typeKey) { case LayoutComponentBase::typeKey: + case DrawableBase::typeKey: + case NodeBase::typeKey: + case TransformComponentBase::typeKey: case WorldTransformComponentBase::typeKey: case ContainerComponentBase::typeKey: case ComponentBase::typeKey: @@ -95,7 +98,7 @@ class LayoutComponentBase : public WorldTransformComponent m_Width = object.m_Width; m_Height = object.m_Height; m_StyleId = object.m_StyleId; - WorldTransformComponent::copy(object); + Drawable::copy(object); } bool deserialize(uint16_t propertyKey, BinaryReader& reader) override @@ -115,7 +118,7 @@ class LayoutComponentBase : public WorldTransformComponent m_StyleId = CoreUintType::deserialize(reader); return true; } - return WorldTransformComponent::deserialize(propertyKey, reader); + return Drawable::deserialize(propertyKey, reader); } protected: diff --git a/include/rive/generated/node_base.hpp b/include/rive/generated/node_base.hpp index f27da202..38c4f60d 100644 --- a/include/rive/generated/node_base.hpp +++ b/include/rive/generated/node_base.hpp @@ -32,7 +32,9 @@ class NodeBase : public TransformComponent uint16_t coreType() const override { return typeKey; } static const uint16_t xPropertyKey = 13; + static const uint16_t xArtboardPropertyKey = 9; static const uint16_t yPropertyKey = 14; + static const uint16_t yArtboardPropertyKey = 10; private: float m_X = 0.0f; diff --git a/include/rive/layout/layout_component_style.hpp b/include/rive/layout/layout_component_style.hpp index 861545d5..63274144 100644 --- a/include/rive/layout/layout_component_style.hpp +++ b/include/rive/layout/layout_component_style.hpp @@ -10,8 +10,8 @@ namespace rive enum class LayoutAnimationStyle : uint8_t { none, - custom, - inherit + inherit, + custom }; enum class LayoutStyleInterpolation : uint8_t @@ -163,6 +163,11 @@ class LayoutComponentStyle : public LayoutComponentStyleBase void positionRightUnitsValueChanged() override; void positionTopUnitsValueChanged() override; void positionBottomUnitsValueChanged() override; + + void cornerRadiusTLChanged() override; + void cornerRadiusTRChanged() override; + void cornerRadiusBLChanged() override; + void cornerRadiusBRChanged() override; }; } // namespace rive diff --git a/include/rive/layout_component.hpp b/include/rive/layout_component.hpp index c070587b..976544c7 100644 --- a/include/rive/layout_component.hpp +++ b/include/rive/layout_component.hpp @@ -1,8 +1,12 @@ #ifndef _RIVE_LAYOUT_COMPONENT_HPP_ #define _RIVE_LAYOUT_COMPONENT_HPP_ +#include "rive/drawable.hpp" #include "rive/generated/layout_component_base.hpp" #include "rive/layout/layout_component_style.hpp" #include "rive/layout/layout_measure_mode.hpp" +#include "rive/math/raw_path.hpp" +#include "rive/shapes/rectangle.hpp" +#include "rive/shapes/shape_paint_container.hpp" #ifdef WITH_RIVE_LAYOUT #include "yoga/YGNode.h" #include "yoga/YGStyle.h" @@ -30,7 +34,7 @@ struct LayoutAnimationData AABB toBounds = AABB(); }; -class LayoutComponent : public LayoutComponentBase +class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public ShapePaintContainer { protected: LayoutComponentStyle* m_style = nullptr; @@ -45,6 +49,15 @@ class LayoutComponent : public LayoutComponentBase KeyFrameInterpolator* m_inheritedInterpolator; LayoutStyleInterpolation m_inheritedInterpolation = LayoutStyleInterpolation::hold; float m_inheritedInterpolationTime = 0; + Rectangle* m_backgroundRect = new Rectangle(); + rcp m_backgroundPath; + rcp m_clipPath; + DrawableProxy m_proxy; + + Artboard* getArtboard() override { return artboard(); } + +private: + virtual void performUpdate(ComponentDirt value); #ifdef WITH_RIVE_LAYOUT private: @@ -62,13 +75,21 @@ class LayoutComponent : public LayoutComponentBase 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; }; + void update(ComponentDirt value) override; #ifdef WITH_RIVE_LAYOUT - LayoutComponent(); + LayoutComponent() : m_layoutData(std::unique_ptr(new LayoutData())), m_proxy(this) + { + layoutNode().getConfig()->setPointScaleFactor(0); + } + ~LayoutComponent() { delete m_backgroundRect; } void syncStyle(); virtual void propagateSize(); void updateLayoutBounds(); - void update(ComponentDirt value) override; StatusCode onAddedDirty(CoreContext* context) override; bool advance(double elapsedSeconds); @@ -97,6 +118,9 @@ class LayoutComponent : public LayoutComponentBase 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; @@ -111,7 +135,7 @@ class LayoutComponent : public LayoutComponentBase Vec2D measureLayout(float width, LayoutMeasureMode widthMode, float height, - LayoutMeasureMode heightMode); + LayoutMeasureMode heightMode) override; }; } // namespace rive diff --git a/include/rive/transform_component.hpp b/include/rive/transform_component.hpp index 534165c2..151c31bc 100644 --- a/include/rive/transform_component.hpp +++ b/include/rive/transform_component.hpp @@ -18,6 +18,9 @@ class TransformComponent : public TransformComponentBase WorldTransformComponent* m_ParentTransformComponent = nullptr; std::vector m_Constraints; +protected: + void updateConstraints(); + public: bool collapse(bool value) override; const std::vector& constraints() const { return m_Constraints; } @@ -25,7 +28,7 @@ class TransformComponent : public TransformComponentBase void buildDependencies() override; void update(ComponentDirt value) override; void updateTransform(); - void updateWorldTransform(); + virtual void updateWorldTransform(); void markTransformDirty(); /// Opacity inherited by any child of this transform component. This'll diff --git a/src/artboard.cpp b/src/artboard.cpp index 3a0b299d..7cd9b029 100644 --- a/src/artboard.cpp +++ b/src/artboard.cpp @@ -15,6 +15,7 @@ #include "rive/shapes/paint/shape_paint.hpp" #include "rive/importers/import_stack.hpp" #include "rive/importers/backboard_importer.hpp" +#include "rive/layout_component.hpp" #include "rive/nested_artboard.hpp" #include "rive/joystick.hpp" #include "rive/data_bind_flags.hpp" @@ -84,8 +85,8 @@ StatusCode Artboard::initialize() StatusCode code; // these will be re-built in update() -- are they needed here? - m_BackgroundPath = factory()->makeEmptyRenderPath(); - m_ClipPath = factory()->makeEmptyRenderPath(); + m_backgroundPath = factory()->makeEmptyRenderPath(); + m_clipPath = factory()->makeEmptyRenderPath(); m_layoutSizeWidth = width(); m_layoutSizeHeight = height(); @@ -218,7 +219,7 @@ StatusCode Artboard::initialize() { object->as()->buildDependencies(); } - if (object->is()) + if (object->is() && object != this) { Drawable* drawable = object->as(); m_Drawables.push_back(drawable); @@ -235,6 +236,48 @@ StatusCode Artboard::initialize() } } } + // Iterate over the drawables in order to inject proxies for layouts + std::vector layouts; + for (int i = 0; i < m_Drawables.size(); i++) + { + auto drawable = m_Drawables[i]; + LayoutComponent* currentLayout; + bool isInCurrentLayout = true; + if (!layouts.empty()) + { + currentLayout = layouts.back(); + isInCurrentLayout = false; + } + for (ContainerComponent* parent = drawable; parent != nullptr; parent = parent->parent()) + { + if (parent == currentLayout) + { + isInCurrentLayout = true; + break; + } + } + // We inject a DrawableProxy after all of the children of a LayoutComponent + // so that we can draw a stroke above and background below the children + // This also allows us to clip the children + if (currentLayout != nullptr && !isInCurrentLayout) + { + // This is the first item in the list of drawables that isn't a child + // of the layout, so we insert a proxy before it + m_Drawables.insert(m_Drawables.begin() + i, currentLayout->proxy()); + layouts.pop_back(); + i += 1; + } + if (drawable->is()) + { + layouts.push_back(drawable->as()); + } + } + while (!layouts.empty()) + { + auto layout = layouts.back(); + m_Drawables.push_back(layout->proxy()); + layouts.pop_back(); + } sortDependencies(); @@ -474,7 +517,7 @@ float Artboard::layoutHeight() const #endif } -void Artboard::update(ComponentDirt value) +void Artboard::performUpdate(ComponentDirt value) { if (hasDirt(value, ComponentDirt::DrawOrder)) { @@ -495,11 +538,11 @@ void Artboard::update(ComponentDirt value) { clip = bg; } - m_ClipPath = factory()->makeRenderPath(clip); + m_clipPath = factory()->makeRenderPath(clip); m_backgroundRawPath.addRect(bg); - m_BackgroundPath->rewind(); - m_backgroundRawPath.addTo(m_BackgroundPath.get()); + m_backgroundPath->rewind(); + m_backgroundRawPath.addTo(m_backgroundPath.get()); } if (hasDirt(value, ComponentDirt::RenderOpacity)) { @@ -655,14 +698,14 @@ bool Artboard::advance(double elapsedSeconds, bool nested) return advanceInternal(elapsedSeconds, true, nested); } -Core* Artboard::hitTest(HitInfo* hinfo, const Mat2D* xform) +Core* Artboard::hitTest(HitInfo* hinfo, const Mat2D& xform) { if (clip()) { // TODO: can we get the rawpath for the clip? } - auto mx = xform ? *xform : Mat2D(); + auto mx = xform; if (m_FrameOrigin) { mx *= Mat2D::fromTranslate(layoutWidth() * originX(), layoutHeight() * originY()); @@ -694,12 +737,14 @@ Core* Artboard::hitTest(HitInfo* hinfo, const Mat2D* xform) return nullptr; } +void Artboard::draw(Renderer* renderer) { draw(renderer, DrawOption::kNormal); } + void Artboard::draw(Renderer* renderer, DrawOption option) { renderer->save(); if (clip()) { - renderer->clipPath(m_ClipPath.get()); + renderer->clipPath(m_clipPath.get()); } if (m_FrameOrigin) @@ -714,7 +759,7 @@ void Artboard::draw(Renderer* renderer, DrawOption option) { for (auto shapePaint : m_ShapePaints) { - shapePaint->draw(renderer, m_BackgroundPath.get(), &m_backgroundRawPath); + shapePaint->draw(renderer, m_backgroundPath.get(), &m_backgroundRawPath); } } diff --git a/src/drawable.cpp b/src/drawable.cpp index 2f01c79d..522bd5ff 100644 --- a/src/drawable.cpp +++ b/src/drawable.cpp @@ -40,7 +40,7 @@ StatusCode Drawable::onAddedDirty(CoreContext* context) void Drawable::addClippingShape(ClippingShape* shape) { m_ClippingShapes.push_back(shape); } -ClipResult Drawable::clip(Renderer* renderer) const +ClipResult Drawable::applyClip(Renderer* renderer) const { if (m_ClippingShapes.size() == 0) { diff --git a/src/layout/layout_component_style.cpp b/src/layout/layout_component_style.cpp index 8fe4a32b..a9310be9 100644 --- a/src/layout/layout_component_style.cpp +++ b/src/layout/layout_component_style.cpp @@ -196,4 +196,8 @@ void LayoutComponentStyle::paddingBottomUnitsValueChanged() { markLayoutNodeDirt void LayoutComponentStyle::positionLeftUnitsValueChanged() { markLayoutNodeDirty(); } void LayoutComponentStyle::positionRightUnitsValueChanged() { markLayoutNodeDirty(); } void LayoutComponentStyle::positionTopUnitsValueChanged() { markLayoutNodeDirty(); } -void LayoutComponentStyle::positionBottomUnitsValueChanged() { markLayoutNodeDirty(); } \ No newline at end of file +void LayoutComponentStyle::positionBottomUnitsValueChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::cornerRadiusTLChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::cornerRadiusTRChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::cornerRadiusBLChanged() { markLayoutNodeDirty(); } +void LayoutComponentStyle::cornerRadiusBRChanged() { markLayoutNodeDirty(); } \ No newline at end of file diff --git a/src/layout_component.cpp b/src/layout_component.cpp index 350b7cc2..52040d41 100644 --- a/src/layout_component.cpp +++ b/src/layout_component.cpp @@ -1,8 +1,14 @@ #include "rive/animation/keyframe_interpolator.hpp" #include "rive/artboard.hpp" +#include "rive/drawable.hpp" +#include "rive/factory.hpp" #include "rive/layout_component.hpp" #include "rive/node.hpp" #include "rive/math/aabb.hpp" +#include "rive/shapes/paint/fill.hpp" +#include "rive/shapes/paint/shape_paint.hpp" +#include "rive/shapes/paint/stroke.hpp" +#include "rive/shapes/rectangle.hpp" #ifdef WITH_RIVE_LAYOUT #include "rive/transform_component.hpp" #include "yoga/YGEnums.h" @@ -19,14 +25,111 @@ void LayoutComponent::buildDependencies() { parent()->addDependent(this); } + // Set the blend mode on all the shape paints. If we ever animate this + // property, we'll need to update it in the update cycle/mark dirty when the + // blend mode changes. + for (auto paint : m_ShapePaints) + { + paint->blendMode(blendMode()); + } } -#ifdef WITH_RIVE_LAYOUT -LayoutComponent::LayoutComponent() : m_layoutData(std::unique_ptr(new LayoutData())) +void LayoutComponent::drawProxy(Renderer* renderer) { - layoutNode().getConfig()->setPointScaleFactor(0); + if (clip()) + { + renderer->save(); + renderer->clipPath(m_clipPath.get()); + } + renderer->save(); + renderer->transform(worldTransform()); + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->isVisible()) + { + continue; + } + if (shapePaint->is()) + { + shapePaint->draw(renderer, m_backgroundPath.get(), &m_backgroundRect->rawPath()); + } + } + renderer->restore(); +} + +void LayoutComponent::draw(Renderer* renderer) +{ + // Restore clip before drawing stroke so we don't clip the stroke + if (clip()) + { + renderer->restore(); + } + renderer->save(); + renderer->transform(worldTransform()); + for (auto shapePaint : m_ShapePaints) + { + if (!shapePaint->isVisible()) + { + continue; + } + if (shapePaint->is()) + { + shapePaint->draw(renderer, m_backgroundPath.get(), &m_backgroundRect->rawPath()); + } + } + renderer->restore(); +} + +Core* LayoutComponent::hitTest(HitInfo*, const Mat2D&) { return nullptr; } + +void LayoutComponent::update(ComponentDirt value) +{ + Super::update(value); + performUpdate(value); +} + +void LayoutComponent::performUpdate(ComponentDirt value) +{ + if (hasDirt(value, ComponentDirt::RenderOpacity)) + { + propagateOpacity(renderOpacity()); + } + 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)) + { + 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; + + updateConstraints(); + } } +#ifdef WITH_RIVE_LAYOUT StatusCode LayoutComponent::onAddedDirty(CoreContext* context) { auto code = Super::onAddedDirty(context); @@ -48,25 +151,13 @@ StatusCode LayoutComponent::onAddedDirty(CoreContext* context) { parent()->as()->syncLayoutChildren(); } + m_backgroundPath = artboard()->factory()->makeEmptyRenderPath(); + m_clipPath = artboard()->factory()->makeEmptyRenderPath(); + m_backgroundRect->originX(0); + m_backgroundRect->originY(0); return StatusCode::Ok; } -void LayoutComponent::update(ComponentDirt value) -{ - if (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; - } -} - static YGSize measureFunc(YGNode* node, float width, YGMeasureMode widthMode, @@ -567,6 +658,14 @@ void LayoutComponent::markLayoutStyleDirty() } } #else +Vec2D LayoutComponent::measureLayout(float width, + LayoutMeasureMode widthMode, + float height, + LayoutMeasureMode heightMode) +{ + return Vec2D(); +} + void LayoutComponent::markLayoutNodeDirty() {} void LayoutComponent::markLayoutStyleDirty() {} #endif diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp index 19437dce..95138b07 100644 --- a/src/nested_artboard.cpp +++ b/src/nested_artboard.cpp @@ -60,7 +60,7 @@ void NestedArtboard::draw(Renderer* renderer) { return; } - ClipResult clipResult = clip(renderer); + ClipResult clipResult = applyClip(renderer); if (clipResult == ClipResult::noClip) { // We didn't clip, so make sure to save as we'll be doing some @@ -83,7 +83,7 @@ Core* NestedArtboard::hitTest(HitInfo* hinfo, const Mat2D& xform) } hinfo->mounts.push_back(this); auto mx = xform * worldTransform() * makeTranslate(m_Artboard); - if (auto c = m_Artboard->hitTest(hinfo, &mx)) + if (auto c = m_Artboard->hitTest(hinfo, mx)) { return c; } diff --git a/src/shapes/image.cpp b/src/shapes/image.cpp index e7612307..d86687e3 100644 --- a/src/shapes/image.cpp +++ b/src/shapes/image.cpp @@ -24,7 +24,7 @@ void Image::draw(Renderer* renderer) return; } - ClipResult clipResult = clip(renderer); + ClipResult clipResult = applyClip(renderer); if (clipResult == ClipResult::noClip) { diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp index fd5af983..f5898feb 100644 --- a/src/shapes/path.cpp +++ b/src/shapes/path.cpp @@ -56,6 +56,10 @@ bool Path::isFlagged(PathFlags flags) const { return (int)(m_pathFlags & flags) bool Path::canDeferPathUpdate() { + if (m_Shape == nullptr) + { + return false; + } // A path cannot defer its update if the shapes requires an update. Note the // nuance here where we track that the shape may be marked for follow path // (meaning all child paths need to follow path). This doesn't mean the diff --git a/src/shapes/shape.cpp b/src/shapes/shape.cpp index 6a22160a..d69648be 100644 --- a/src/shapes/shape.cpp +++ b/src/shapes/shape.cpp @@ -91,7 +91,7 @@ void Shape::draw(Renderer* renderer) { return; } - ClipResult clipResult = clip(renderer); + ClipResult clipResult = applyClip(renderer); if (clipResult != ClipResult::emptyClip) { diff --git a/src/shapes/shape_paint_container.cpp b/src/shapes/shape_paint_container.cpp index 37e58538..6a702eb0 100644 --- a/src/shapes/shape_paint_container.cpp +++ b/src/shapes/shape_paint_container.cpp @@ -2,6 +2,7 @@ #include "rive/artboard.hpp" #include "rive/factory.hpp" #include "rive/component.hpp" +#include "rive/layout_component.hpp" #include "rive/shapes/paint/stroke.hpp" #include "rive/shapes/shape.hpp" #include "rive/text/text_style.hpp" @@ -14,6 +15,8 @@ ShapePaintContainer* ShapePaintContainer::from(Component* component) { case Artboard::typeKey: return component->as(); + case LayoutComponent::typeKey: + return component->as(); case Shape::typeKey: return component->as(); case TextStyle::typeKey: diff --git a/src/text/text.cpp b/src/text/text.cpp index 48624a56..59403c7a 100644 --- a/src/text/text.cpp +++ b/src/text/text.cpp @@ -509,7 +509,7 @@ const TextStyle* Text::styleFromShaperId(uint16_t id) const void Text::draw(Renderer* renderer) { - ClipResult clipResult = clip(renderer); + ClipResult clipResult = applyClip(renderer); if (clipResult == ClipResult::noClip) { // We didn't clip, so make sure to save as we'll be doing some diff --git a/src/transform_component.cpp b/src/transform_component.cpp index 0e9c1ab9..73bc031b 100644 --- a/src/transform_component.cpp +++ b/src/transform_component.cpp @@ -79,7 +79,11 @@ void TransformComponent::updateWorldTransform() { m_WorldTransform = m_Transform; } + updateConstraints(); +} +void TransformComponent::updateConstraints() +{ for (auto constraint : m_Constraints) { constraint->constrain(this); diff --git a/test/clip_test.cpp b/test/clip_test.cpp index d4dbdeb3..19ff1443 100644 --- a/test/clip_test.cpp +++ b/test/clip_test.cpp @@ -106,7 +106,7 @@ TEST_CASE("Shape does not have any clipping paths visible", "[clipping]") REQUIRE(clippedNode->is()); rive::Shape* clippedShape = static_cast(clippedNode); rive::NoOpRenderer renderer; - auto clipResult = clippedShape->clip(&renderer); + auto clipResult = clippedShape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::emptyClip); } @@ -128,7 +128,7 @@ TEST_CASE("Shape has at least a clipping path visible", "[clipping]") REQUIRE(clippedNode->is()); rive::Shape* clippedShape = static_cast(clippedNode); rive::NoOpRenderer renderer; - auto clipResult = clippedShape->clip(&renderer); + auto clipResult = clippedShape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::clip); } @@ -146,6 +146,6 @@ TEST_CASE("Shape returns an empty clip when one clipping shape is empty", "[clip rive::Shape* shape = static_cast(node); rive::NoOpRenderer renderer; - auto clipResult = shape->clip(&renderer); + auto clipResult = shape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::emptyClip); }