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 <philterdesign@gmail.com>
diff --git a/.rive_head b/.rive_head index 518b856..8cbe00c 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 5a04630..bf94a2b 100644 --- a/dev/core_generator/lib/src/definition.dart +++ b/dev/core_generator/lib/src/definition.dart
@@ -183,6 +183,11 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 8e1a8d0..ca83684 100644 --- a/dev/core_generator/lib/src/key.dart +++ b/dev/core_generator/lib/src/key.dart
@@ -4,6 +4,7 @@ class Key { final String? stringValue; final int? intValue; + final List<Key> alternates = []; bool get isMissing => intValue == null; @@ -23,12 +24,36 @@ } 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<String, dynamic>) { + dynamic altiv = a['int']; + dynamic altsv = a['string']; + key.alternates.add(Key(altsv, altiv)); + } + } + } + return key; } return null; } - Map<String, dynamic> serialize() => - <String, dynamic>{'int': intValue, 'string': stringValue}; + Map<String, dynamic> serialize() { + final json = <String, dynamic>{'int': intValue, 'string': stringValue}; + final altsJson = []; + for (final alt in alternates) { + final altJson = <String, dynamic>{ + '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 4079ccb..bb52736 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 9bddf11..cb46d46 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 ac24d51..8aca893 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 f604980..90ff182 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 9411ceb..4b7cc3d 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 @@ 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 @@ unsigned int m_DirtDepth = 0; RawPath m_backgroundRawPath; - rcp<RenderPath> m_BackgroundPath; - rcp<RenderPath> m_ClipPath; Factory* m_Factory = nullptr; Drawable* m_FirstDrawable = nullptr; bool m_IsInstance = false; @@ -88,8 +85,7 @@ void sortDependencies(); void sortDrawOrder(); void updateDataBinds(); - - Artboard* getArtboard() override { return this; } + void performUpdate(ComponentDirt value) override; #ifdef TESTING public: @@ -114,15 +110,20 @@ // 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 @@ 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<Core*>& objects() const { return m_Objects; }
diff --git a/include/rive/drawable.hpp b/include/rive/drawable.hpp index ca5e996..b4e79b8 100644 --- a/include/rive/drawable.hpp +++ b/include/rive/drawable.hpp
@@ -28,7 +28,7 @@ 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 @@ 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 ff19a02..b7ae1b9 100644 --- a/include/rive/generated/artboard_base.hpp +++ b/include/rive/generated/artboard_base.hpp
@@ -21,6 +21,9 @@ { 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 @@ 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 @@ 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 @@ { 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 @@ } 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 3096b79..abeae9a 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp
@@ -516,6 +516,9 @@ case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: object->as<LayoutComponentStyleBase>()->intrinsicallySizedValue(value); break; + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + object->as<LayoutComponentStyleBase>()->linkCornerRadius(value); + break; case NestedSimpleAnimationBase::isPlayingPropertyKey: object->as<NestedSimpleAnimationBase>()->isPlaying(value); break; @@ -1147,9 +1150,11 @@ object->as<TransformComponentBase>()->scaleY(value); break; case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: object->as<NodeBase>()->x(value); break; case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: object->as<NodeBase>()->y(value); break; case LayoutComponentStyleBase::gapHorizontalPropertyKey: @@ -1236,6 +1241,18 @@ case LayoutComponentStyleBase::interpolationTimePropertyKey: object->as<LayoutComponentStyleBase>()->interpolationTime(value); break; + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + object->as<LayoutComponentStyleBase>()->cornerRadiusTL(value); + break; + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + object->as<LayoutComponentStyleBase>()->cornerRadiusTR(value); + break; + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + object->as<LayoutComponentStyleBase>()->cornerRadiusBL(value); + break; + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + object->as<LayoutComponentStyleBase>()->cornerRadiusBR(value); + break; case NestedLinearAnimationBase::mixPropertyKey: object->as<NestedLinearAnimationBase>()->mix(value); break; @@ -1416,12 +1433,6 @@ case LayoutComponentBase::heightPropertyKey: object->as<LayoutComponentBase>()->height(value); break; - case ArtboardBase::xPropertyKey: - object->as<ArtboardBase>()->x(value); - break; - case ArtboardBase::yPropertyKey: - object->as<ArtboardBase>()->y(value); - break; case ArtboardBase::originXPropertyKey: object->as<ArtboardBase>()->originX(value); break; @@ -1625,6 +1636,8 @@ return object->as<FollowPathConstraintBase>()->offset(); case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: return object->as<LayoutComponentStyleBase>()->intrinsicallySizedValue(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->as<LayoutComponentStyleBase>()->linkCornerRadius(); case NestedSimpleAnimationBase::isPlayingPropertyKey: return object->as<NestedSimpleAnimationBase>()->isPlaying(); case KeyFrameBoolBase::valuePropertyKey: @@ -2058,8 +2071,10 @@ case TransformComponentBase::scaleYPropertyKey: return object->as<TransformComponentBase>()->scaleY(); case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: return object->as<NodeBase>()->x(); case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: return object->as<NodeBase>()->y(); case LayoutComponentStyleBase::gapHorizontalPropertyKey: return object->as<LayoutComponentStyleBase>()->gapHorizontal(); @@ -2117,6 +2132,14 @@ return object->as<LayoutComponentStyleBase>()->aspectRatio(); case LayoutComponentStyleBase::interpolationTimePropertyKey: return object->as<LayoutComponentStyleBase>()->interpolationTime(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->as<LayoutComponentStyleBase>()->cornerRadiusTL(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->as<LayoutComponentStyleBase>()->cornerRadiusTR(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->as<LayoutComponentStyleBase>()->cornerRadiusBL(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->as<LayoutComponentStyleBase>()->cornerRadiusBR(); case NestedLinearAnimationBase::mixPropertyKey: return object->as<NestedLinearAnimationBase>()->mix(); case NestedSimpleAnimationBase::speedPropertyKey: @@ -2237,10 +2260,6 @@ return object->as<LayoutComponentBase>()->width(); case LayoutComponentBase::heightPropertyKey: return object->as<LayoutComponentBase>()->height(); - case ArtboardBase::xPropertyKey: - return object->as<ArtboardBase>()->x(); - case ArtboardBase::yPropertyKey: - return object->as<ArtboardBase>()->y(); case ArtboardBase::originXPropertyKey: return object->as<ArtboardBase>()->originX(); case ArtboardBase::originYPropertyKey: @@ -2367,6 +2386,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ return object->is<FollowPathConstraintBase>(); case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey: return object->is<LayoutComponentStyleBase>(); + case LayoutComponentStyleBase::linkCornerRadiusPropertyKey: + return object->is<LayoutComponentStyleBase>(); case NestedSimpleAnimationBase::isPlayingPropertyKey: return object->is<NestedSimpleAnimationBase>(); case KeyFrameBoolBase::valuePropertyKey: @@ -3175,8 +3201,10 @@ case TransformComponentBase::scaleYPropertyKey: return object->is<TransformComponentBase>(); case NodeBase::xPropertyKey: + case NodeBase::xArtboardPropertyKey: return object->is<NodeBase>(); case NodeBase::yPropertyKey: + case NodeBase::yArtboardPropertyKey: return object->is<NodeBase>(); case LayoutComponentStyleBase::gapHorizontalPropertyKey: return object->is<LayoutComponentStyleBase>(); @@ -3234,6 +3262,14 @@ return object->is<LayoutComponentStyleBase>(); case LayoutComponentStyleBase::interpolationTimePropertyKey: return object->is<LayoutComponentStyleBase>(); + case LayoutComponentStyleBase::cornerRadiusTLPropertyKey: + return object->is<LayoutComponentStyleBase>(); + case LayoutComponentStyleBase::cornerRadiusTRPropertyKey: + return object->is<LayoutComponentStyleBase>(); + case LayoutComponentStyleBase::cornerRadiusBLPropertyKey: + return object->is<LayoutComponentStyleBase>(); + case LayoutComponentStyleBase::cornerRadiusBRPropertyKey: + return object->is<LayoutComponentStyleBase>(); case NestedLinearAnimationBase::mixPropertyKey: return object->is<NestedLinearAnimationBase>(); case NestedSimpleAnimationBase::speedPropertyKey: @@ -3354,10 +3390,6 @@ return object->is<LayoutComponentBase>(); case LayoutComponentBase::heightPropertyKey: return object->is<LayoutComponentBase>(); - case ArtboardBase::xPropertyKey: - return object->is<ArtboardBase>(); - case ArtboardBase::yPropertyKey: - return object->is<ArtboardBase>(); case ArtboardBase::originXPropertyKey: return object->is<ArtboardBase>(); 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 b62fa97..a6f0cb5 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 e0c508a..680f031 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 @@ 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 @@ 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 @@ 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 f27da20..38c4f60 100644 --- a/include/rive/generated/node_base.hpp +++ b/include/rive/generated/node_base.hpp
@@ -32,7 +32,9 @@ 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 861545d..6327414 100644 --- a/include/rive/layout/layout_component_style.hpp +++ b/include/rive/layout/layout_component_style.hpp
@@ -10,8 +10,8 @@ enum class LayoutAnimationStyle : uint8_t { none, - custom, - inherit + inherit, + custom }; enum class LayoutStyleInterpolation : uint8_t @@ -163,6 +163,11 @@ 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 c070587..976544c 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 @@ AABB toBounds = AABB(); }; -class LayoutComponent : public LayoutComponentBase +class LayoutComponent : public LayoutComponentBase, public ProxyDrawing, public ShapePaintContainer { protected: LayoutComponentStyle* m_style = nullptr; @@ -45,6 +49,15 @@ KeyFrameInterpolator* m_inheritedInterpolator; LayoutStyleInterpolation m_inheritedInterpolation = LayoutStyleInterpolation::hold; float m_inheritedInterpolationTime = 0; + Rectangle* m_backgroundRect = new Rectangle(); + rcp<RenderPath> m_backgroundPath; + rcp<RenderPath> 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 @@ 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<LayoutData>(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 @@ return m_layoutLocationX != 0 || m_layoutLocationY != 0 || m_layoutSizeWidth != 0 || m_layoutSizeHeight != 0; }; +#else + LayoutComponent() : m_layoutData(std::unique_ptr<LayoutData>(new LayoutData())), m_proxy(this) + {} #endif void buildDependencies() override; @@ -111,7 +135,7 @@ 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 534165c..151c31b 100644 --- a/include/rive/transform_component.hpp +++ b/include/rive/transform_component.hpp
@@ -18,6 +18,9 @@ WorldTransformComponent* m_ParentTransformComponent = nullptr; std::vector<Constraint*> m_Constraints; +protected: + void updateConstraints(); + public: bool collapse(bool value) override; const std::vector<Constraint*>& constraints() const { return m_Constraints; } @@ -25,7 +28,7 @@ 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 3a0b299..7cd9b02 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 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 @@ { object->as<Component>()->buildDependencies(); } - if (object->is<Drawable>()) + if (object->is<Drawable>() && object != this) { Drawable* drawable = object->as<Drawable>(); m_Drawables.push_back(drawable); @@ -235,6 +236,48 @@ } } } + // Iterate over the drawables in order to inject proxies for layouts + std::vector<LayoutComponent*> 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<LayoutComponent>()) + { + layouts.push_back(drawable->as<LayoutComponent>()); + } + } + while (!layouts.empty()) + { + auto layout = layouts.back(); + m_Drawables.push_back(layout->proxy()); + layouts.pop_back(); + } sortDependencies(); @@ -474,7 +517,7 @@ #endif } -void Artboard::update(ComponentDirt value) +void Artboard::performUpdate(ComponentDirt value) { if (hasDirt(value, ComponentDirt::DrawOrder)) { @@ -495,11 +538,11 @@ { 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 @@ 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 @@ 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 @@ { 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 2f01c79..522bd5f 100644 --- a/src/drawable.cpp +++ b/src/drawable.cpp
@@ -40,7 +40,7 @@ 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 8fe4a32..a9310be 100644 --- a/src/layout/layout_component_style.cpp +++ b/src/layout/layout_component_style.cpp
@@ -196,4 +196,8 @@ 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 350b7cc..52040d4 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 @@ { 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()); + } +} + +void LayoutComponent::drawProxy(Renderer* renderer) +{ + 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<Fill>()) + { + 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<Stroke>()) + { + 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<WorldTransformComponent>() + ? (parent()->as<WorldTransformComponent>())->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 -LayoutComponent::LayoutComponent() : m_layoutData(std::unique_ptr<LayoutData>(new LayoutData())) -{ - layoutNode().getConfig()->setPointScaleFactor(0); -} - StatusCode LayoutComponent::onAddedDirty(CoreContext* context) { auto code = Super::onAddedDirty(context); @@ -48,25 +151,13 @@ { parent()->as<LayoutComponent>()->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<WorldTransformComponent>() - ? (parent()->as<WorldTransformComponent>())->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 @@ } } #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 19437dc..95138b0 100644 --- a/src/nested_artboard.cpp +++ b/src/nested_artboard.cpp
@@ -60,7 +60,7 @@ { 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 @@ } 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 e761230..d86687e 100644 --- a/src/shapes/image.cpp +++ b/src/shapes/image.cpp
@@ -24,7 +24,7 @@ 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 fd5af98..f5898fe 100644 --- a/src/shapes/path.cpp +++ b/src/shapes/path.cpp
@@ -56,6 +56,10 @@ 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 6a22160..d69648b 100644 --- a/src/shapes/shape.cpp +++ b/src/shapes/shape.cpp
@@ -91,7 +91,7 @@ { 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 37e5853..6a702eb 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 @@ { case Artboard::typeKey: return component->as<Artboard>(); + case LayoutComponent::typeKey: + return component->as<LayoutComponent>(); case Shape::typeKey: return component->as<Shape>(); case TextStyle::typeKey:
diff --git a/src/text/text.cpp b/src/text/text.cpp index 48624a5..59403c7 100644 --- a/src/text/text.cpp +++ b/src/text/text.cpp
@@ -509,7 +509,7 @@ 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 0e9c1ab..73bc031 100644 --- a/src/transform_component.cpp +++ b/src/transform_component.cpp
@@ -79,7 +79,11 @@ { 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 d4dbdeb..19ff144 100644 --- a/test/clip_test.cpp +++ b/test/clip_test.cpp
@@ -106,7 +106,7 @@ REQUIRE(clippedNode->is<rive::Shape>()); rive::Shape* clippedShape = static_cast<rive::Shape*>(clippedNode); rive::NoOpRenderer renderer; - auto clipResult = clippedShape->clip(&renderer); + auto clipResult = clippedShape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::emptyClip); } @@ -128,7 +128,7 @@ REQUIRE(clippedNode->is<rive::Shape>()); rive::Shape* clippedShape = static_cast<rive::Shape*>(clippedNode); rive::NoOpRenderer renderer; - auto clipResult = clippedShape->clip(&renderer); + auto clipResult = clippedShape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::clip); } @@ -146,6 +146,6 @@ rive::Shape* shape = static_cast<rive::Shape*>(node); rive::NoOpRenderer renderer; - auto clipResult = shape->clip(&renderer); + auto clipResult = shape->applyClip(&renderer); REQUIRE(clipResult == rive::ClipResult::emptyClip); }