feature: add support for pausing nested artboards (#10833) 0a3cb5ac3e

* feature: add support for pausing nested artboards

Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
bodymovin
2025-10-20 16:10:14 +00:00
parent f47345a807
commit 007969f903
9 changed files with 127 additions and 6 deletions

View File

@@ -1 +1 @@
650a980d413d906648698116815311e26ae3199d
0a3cb5ac3e77f0250320bb65559bde3974ebf6e5

View File

@@ -15,7 +15,8 @@
"int": 197,
"string": "artboardid"
},
"description": "Identifier used to track the Artboard nested."
"description": "Identifier used to track the Artboard nested.",
"bindable": true
},
"dataBindPathIds": {
"type": "List<Id>",
@@ -27,6 +28,17 @@
"string": "databindpathids"
},
"description": "Path to the selected property."
},
"isPaused": {
"type": "bool",
"initialValue": "false",
"animates": true,
"key": {
"int": 895,
"string": "ispaused"
},
"description": "Value for playback state.",
"bindable": true
}
}
}

View File

@@ -1653,6 +1653,9 @@ public:
case ScrollBarConstraintBase::autoSizePropertyKey:
object->as<ScrollBarConstraintBase>()->autoSize(value);
break;
case NestedArtboardBase::isPausedPropertyKey:
object->as<NestedArtboardBase>()->isPaused(value);
break;
case AxisBase::normalizedPropertyKey:
object->as<AxisBase>()->normalized(value);
break;
@@ -3035,6 +3038,8 @@ public:
return object->as<ScrollConstraintBase>()->interactive();
case ScrollBarConstraintBase::autoSizePropertyKey:
return object->as<ScrollBarConstraintBase>()->autoSize();
case NestedArtboardBase::isPausedPropertyKey:
return object->as<NestedArtboardBase>()->isPaused();
case AxisBase::normalizedPropertyKey:
return object->as<AxisBase>()->normalized();
case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey:
@@ -3819,6 +3824,7 @@ public:
case ScrollConstraintBase::infinitePropertyKey:
case ScrollConstraintBase::interactivePropertyKey:
case ScrollBarConstraintBase::autoSizePropertyKey:
case NestedArtboardBase::isPausedPropertyKey:
case AxisBase::normalizedPropertyKey:
case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey:
case LayoutComponentStyleBase::linkCornerRadiusPropertyKey:
@@ -4609,6 +4615,8 @@ public:
return object->is<ScrollConstraintBase>();
case ScrollBarConstraintBase::autoSizePropertyKey:
return object->is<ScrollBarConstraintBase>();
case NestedArtboardBase::isPausedPropertyKey:
return object->is<NestedArtboardBase>();
case AxisBase::normalizedPropertyKey:
return object->is<AxisBase>();
case LayoutComponentStyleBase::intrinsicallySizedValuePropertyKey:

View File

@@ -1,5 +1,6 @@
#ifndef _RIVE_NESTED_ARTBOARD_BASE_HPP_
#define _RIVE_NESTED_ARTBOARD_BASE_HPP_
#include "rive/core/field_types/core_bool_type.hpp"
#include "rive/core/field_types/core_bytes_type.hpp"
#include "rive/core/field_types/core_uint_type.hpp"
#include "rive/drawable.hpp"
@@ -37,9 +38,11 @@ public:
static const uint16_t artboardIdPropertyKey = 197;
static const uint16_t dataBindPathIdsPropertyKey = 582;
static const uint16_t isPausedPropertyKey = 895;
protected:
uint32_t m_ArtboardId = -1;
bool m_IsPaused = false;
public:
inline uint32_t artboardId() const { return m_ArtboardId; }
@@ -56,11 +59,23 @@ public:
virtual void decodeDataBindPathIds(Span<const uint8_t> value) = 0;
virtual void copyDataBindPathIds(const NestedArtboardBase& object) = 0;
inline bool isPaused() const { return m_IsPaused; }
void isPaused(bool value)
{
if (m_IsPaused == value)
{
return;
}
m_IsPaused = value;
isPausedChanged();
}
Core* clone() const override;
void copy(const NestedArtboardBase& object)
{
m_ArtboardId = object.m_ArtboardId;
copyDataBindPathIds(object);
m_IsPaused = object.m_IsPaused;
Drawable::copy(object);
}
@@ -74,6 +89,9 @@ public:
case dataBindPathIdsPropertyKey:
decodeDataBindPathIds(CoreBytesType::deserialize(reader));
return true;
case isPausedPropertyKey:
m_IsPaused = CoreBoolType::deserialize(reader);
return true;
}
return Drawable::deserialize(propertyKey, reader);
}
@@ -81,6 +99,7 @@ public:
protected:
virtual void artboardIdChanged() {}
virtual void dataBindPathIdsChanged() {}
virtual void isPausedChanged() {}
};
} // namespace rive

View File

@@ -1023,7 +1023,7 @@ public:
bool hitTest(Vec2D position) const override
{
auto nestedArtboard = m_component->as<NestedArtboard>();
if (nestedArtboard->isCollapsed())
if (nestedArtboard->isCollapsed() || nestedArtboard->isPaused())
{
return false;
}
@@ -1056,7 +1056,7 @@ public:
{
auto nestedArtboard = m_component->as<NestedArtboard>();
HitResult hitResult = HitResult::none;
if (nestedArtboard->isCollapsed())
if (nestedArtboard->isCollapsed() || nestedArtboard->isPaused())
{
return hitResult;
}

View File

@@ -436,7 +436,7 @@ void NestedArtboard::unbind()
void NestedArtboard::updateDataBinds()
{
if (artboardInstance() != nullptr)
if (artboardInstance() != nullptr && !isPaused())
{
artboardInstance()->updateDataBinds();
}
@@ -464,7 +464,7 @@ void NestedArtboard::bindViewModelInstance(
bool NestedArtboard::advanceComponent(float elapsedSeconds, AdvanceFlags flags)
{
if (m_Artboard == nullptr || isCollapsed())
if (m_Artboard == nullptr || isCollapsed() || isPaused())
{
return false;
}

Binary file not shown.

View File

@@ -174,4 +174,86 @@ TEST_CASE("All nested artboard modes respect hug", "[silver]")
silver.addFrame();
CHECK(silver.matches("nested_hug"));
}
TEST_CASE("Pause and resume nested artboards", "[silver]")
{
rive::SerializingFactory silver;
auto file = ReadRiveFile("assets/pause_nested_artboard.riv", &silver);
auto artboard = file->artboardDefault();
silver.frameSize(artboard->width(), artboard->height());
REQUIRE(artboard != nullptr);
auto stateMachine = artboard->stateMachineAt(0);
auto vmi = file->createViewModelInstance(artboard.get()->viewModelId(), 0);
stateMachine->bindViewModelInstance(vmi);
stateMachine->advanceAndApply(0.1f);
auto renderer = silver.makeRenderer();
artboard->draw(renderer.get());
int frames = (int)(0.25f / 0.016f);
// State machine advances normally
for (int i = 0; i < frames; i++)
{
silver.addFrame();
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
}
// Click toggles rectangle color
silver.addFrame();
stateMachine->pointerDown(rive::Vec2D(250.0f, 250.0f));
stateMachine->pointerUp(rive::Vec2D(250.0f, 250.0f));
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
// Toggle data bind pauses state machine
silver.addFrame();
stateMachine->pointerDown(rive::Vec2D(25.0f, 25.0f));
stateMachine->pointerUp(rive::Vec2D(25.0f, 25.0f));
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
// State machine does not advance
for (int i = 0; i < frames; i++)
{
silver.addFrame();
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
}
// Click does not toggle color back
silver.addFrame();
stateMachine->pointerDown(rive::Vec2D(250.0f, 250.0f));
stateMachine->pointerUp(rive::Vec2D(250.0f, 250.0f));
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
// Toggle data bind resumes state machine
silver.addFrame();
stateMachine->pointerDown(rive::Vec2D(25.0f, 25.0f));
stateMachine->pointerUp(rive::Vec2D(25.0f, 25.0f));
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
// Click toggles color back
silver.addFrame();
stateMachine->pointerDown(rive::Vec2D(250.0f, 250.0f));
stateMachine->pointerUp(rive::Vec2D(250.0f, 250.0f));
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
// State machine advances again
for (int i = 0; i < frames; i++)
{
silver.addFrame();
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
}
CHECK(silver.matches("pause_nested_artboard"));
}

Binary file not shown.