mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 13:11:19 +01:00
Nnnnn relative data bind all paths (#11346) 41d316c675
* StateMachineListener relative view model property path * StateMachineFireTrigger relative view model property path * ScriptInputViewModelProperty relative view model property path Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
@@ -1 +1 @@
|
||||
56f08da6b1998d346fa791770d7a62a50466e0f7
|
||||
41d316c675491aa5941a6342e859d6c37bf457c0
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
"string": "viewmodelpathids"
|
||||
},
|
||||
"description": "Path to the selected view model trigger property."
|
||||
},
|
||||
"isDataBindPathRelative": {
|
||||
"type": "bool",
|
||||
"initialValue": "false",
|
||||
"key": {
|
||||
"int": 923,
|
||||
"string": "isdatabindpathrelative"
|
||||
},
|
||||
"description": "Whether the data bind path is relative",
|
||||
"runtime": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,16 @@
|
||||
"string": "viewmodelpathids"
|
||||
},
|
||||
"description": "Path to the selected view model trigger property if listenerType is a viewModel trigger."
|
||||
},
|
||||
"isDataBindPathRelative": {
|
||||
"type": "bool",
|
||||
"initialValue": "false",
|
||||
"key": {
|
||||
"int": 924,
|
||||
"string": "isdatabindpathrelative"
|
||||
},
|
||||
"description": "Whether the data bind path is relative",
|
||||
"runtime": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,16 @@
|
||||
"string": "databindpathids"
|
||||
},
|
||||
"description": "Path to the selected property."
|
||||
},
|
||||
"isDataBindPathRelative": {
|
||||
"type": "bool",
|
||||
"initialValue": "false",
|
||||
"key": {
|
||||
"int": 922,
|
||||
"string": "isdatabindpathrelative"
|
||||
},
|
||||
"description": "Whether the data bind path is relative",
|
||||
"runtime": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
#ifndef _RIVE_STATE_MACHINE_FIRE_TRIGGER_HPP_
|
||||
#define _RIVE_STATE_MACHINE_FIRE_TRIGGER_HPP_
|
||||
#include "rive/generated/animation/state_machine_fire_trigger_base.hpp"
|
||||
#include "rive/data_bind_path_referencer.hpp"
|
||||
#include <stdio.h>
|
||||
namespace rive
|
||||
{
|
||||
class StateMachineFireTrigger : public StateMachineFireTriggerBase
|
||||
class StateMachineFireTrigger : public StateMachineFireTriggerBase,
|
||||
public DataBindPathReferencer
|
||||
{
|
||||
public:
|
||||
void perform(StateMachineInstance* stateMachineInstance) const override;
|
||||
void decodeViewModelPathIds(Span<const uint8_t> value) override;
|
||||
void copyViewModelPathIds(
|
||||
const StateMachineFireTriggerBase& object) override;
|
||||
|
||||
protected:
|
||||
std::vector<uint32_t> m_viewModelPathIdsBuffer;
|
||||
StatusCode import(ImportStack& importStack) override;
|
||||
};
|
||||
} // namespace rive
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "rive/generated/animation/state_machine_listener_base.hpp"
|
||||
#include "rive/listener_type.hpp"
|
||||
#include "rive/math/vec2d.hpp"
|
||||
#include "rive/data_bind_path_referencer.hpp"
|
||||
|
||||
namespace rive
|
||||
{
|
||||
@@ -10,7 +11,8 @@ class Shape;
|
||||
class StateMachineListenerImporter;
|
||||
class ListenerAction;
|
||||
class StateMachineInstance;
|
||||
class StateMachineListener : public StateMachineListenerBase
|
||||
class StateMachineListener : public StateMachineListenerBase,
|
||||
public DataBindPathReferencer
|
||||
{
|
||||
friend class StateMachineListenerImporter;
|
||||
|
||||
@@ -32,13 +34,7 @@ public:
|
||||
Vec2D previousPosition) const;
|
||||
void decodeViewModelPathIds(Span<const uint8_t> value) override;
|
||||
void copyViewModelPathIds(const StateMachineListenerBase& object) override;
|
||||
std::vector<uint32_t> viewModelPathIdsBuffer() const
|
||||
{
|
||||
return m_viewModelPathIdsBuffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<uint32_t> m_viewModelPathIdsBuffer;
|
||||
std::vector<uint32_t> viewModelPathIdsBuffer() const;
|
||||
|
||||
private:
|
||||
void addAction(std::unique_ptr<ListenerAction>);
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
ViewModelInstanceValue* getRelativeViewModelProperty(
|
||||
const std::vector<uint32_t> path,
|
||||
DataResolver* resolver) const;
|
||||
ViewModelInstanceValue* getViewModelProperty(DataBindPath* dataBindPath);
|
||||
rcp<ViewModelInstance> getViewModelInstance(
|
||||
const std::vector<uint32_t> path) const;
|
||||
rcp<ViewModelInstance> getViewModelInstance(DataBindPath*) const;
|
||||
|
||||
@@ -3,26 +3,24 @@
|
||||
#include "rive/generated/script_input_viewmodel_property_base.hpp"
|
||||
#include "rive/assets/script_asset.hpp"
|
||||
#include "rive/scripted/scripted_object.hpp"
|
||||
#include "rive/data_bind_path_referencer.hpp"
|
||||
#include <stdio.h>
|
||||
namespace rive
|
||||
{
|
||||
class ViewModelInstanceValue;
|
||||
|
||||
class ScriptInputViewModelProperty : public ScriptInputViewModelPropertyBase,
|
||||
public ScriptInput
|
||||
public ScriptInput,
|
||||
public DataBindPathReferencer
|
||||
{
|
||||
private:
|
||||
ViewModelInstanceValue* m_viewModelInstanceValue;
|
||||
|
||||
protected:
|
||||
std::vector<uint32_t> m_DataBindPathIdsBuffer;
|
||||
|
||||
public:
|
||||
~ScriptInputViewModelProperty();
|
||||
void decodeDataBindPathIds(Span<const uint8_t> value) override;
|
||||
void copyDataBindPathIds(
|
||||
const ScriptInputViewModelPropertyBase& object) override;
|
||||
std::vector<uint32_t> dataBindPathIds() { return m_DataBindPathIdsBuffer; };
|
||||
void initScriptedValue() override;
|
||||
bool validateForScriptInit() override;
|
||||
StatusCode import(ImportStack& importStack) override;
|
||||
|
||||
@@ -8,10 +8,9 @@ void StateMachineFireTrigger::perform(
|
||||
StateMachineInstance* stateMachineInstance) const
|
||||
{
|
||||
auto dataContext = stateMachineInstance->dataContext();
|
||||
if (dataContext != nullptr)
|
||||
if (dataContext != nullptr && m_dataBindPath)
|
||||
{
|
||||
auto vmProp =
|
||||
dataContext->getViewModelProperty(m_viewModelPathIdsBuffer);
|
||||
auto vmProp = dataContext->getViewModelProperty(m_dataBindPath);
|
||||
if (vmProp && vmProp->is<ViewModelInstanceTrigger>())
|
||||
{
|
||||
vmProp->as<ViewModelInstanceTrigger>()->trigger();
|
||||
@@ -19,19 +18,19 @@ void StateMachineFireTrigger::perform(
|
||||
}
|
||||
}
|
||||
|
||||
StatusCode StateMachineFireTrigger::import(ImportStack& importStack)
|
||||
{
|
||||
importDataBindPath(importStack);
|
||||
return Super::import(importStack);
|
||||
}
|
||||
|
||||
void StateMachineFireTrigger::decodeViewModelPathIds(Span<const uint8_t> value)
|
||||
{
|
||||
BinaryReader reader(value);
|
||||
while (!reader.reachedEnd())
|
||||
{
|
||||
auto val = reader.readVarUintAs<uint32_t>();
|
||||
m_viewModelPathIdsBuffer.push_back(val);
|
||||
}
|
||||
decodeDataBindPath(value);
|
||||
}
|
||||
|
||||
void StateMachineFireTrigger::copyViewModelPathIds(
|
||||
const StateMachineFireTriggerBase& object)
|
||||
{
|
||||
m_viewModelPathIdsBuffer =
|
||||
object.as<StateMachineFireTrigger>()->m_viewModelPathIdsBuffer;
|
||||
copyDataBindPath(object.as<StateMachineFireTrigger>()->dataBindPath());
|
||||
}
|
||||
@@ -1014,8 +1014,8 @@ public:
|
||||
void bindFromContext(DataContext* dataContext)
|
||||
{
|
||||
clearDataContext();
|
||||
auto path = m_listener->viewModelPathIdsBuffer();
|
||||
auto vmProp = dataContext->getViewModelProperty(path);
|
||||
auto vmProp =
|
||||
dataContext->getViewModelProperty(m_listener->dataBindPath());
|
||||
if (vmProp != nullptr)
|
||||
{
|
||||
m_viewModelInstanceValue = rive::ref_rcp(vmProp);
|
||||
@@ -1341,8 +1341,8 @@ StateMachineInstance::StateMachineInstance(const StateMachine* machine,
|
||||
// We are only storing in this unordered map data binds that are
|
||||
// targetting the source. For now, this is only the case for
|
||||
// listener actions.
|
||||
if (static_cast<DataBindFlags>(dataBindClone->flags()) ==
|
||||
DataBindFlags::ToSource)
|
||||
if ((static_cast<DataBindFlags>(dataBindClone->flags()) &
|
||||
DataBindFlags::ToSource) == DataBindFlags::ToSource)
|
||||
{
|
||||
m_bindableDataBindsToSource[bindablePropertyClone] =
|
||||
dataBindClone;
|
||||
|
||||
@@ -19,6 +19,7 @@ void StateMachineListener::addAction(std::unique_ptr<ListenerAction> action)
|
||||
|
||||
StatusCode StateMachineListener::import(ImportStack& importStack)
|
||||
{
|
||||
importDataBindPath(importStack);
|
||||
auto stateMachineImporter =
|
||||
importStack.latest<StateMachineImporter>(StateMachineBase::typeKey);
|
||||
if (stateMachineImporter == nullptr)
|
||||
@@ -53,17 +54,16 @@ void StateMachineListener::performChanges(
|
||||
|
||||
void StateMachineListener::decodeViewModelPathIds(Span<const uint8_t> value)
|
||||
{
|
||||
BinaryReader reader(value);
|
||||
while (!reader.reachedEnd())
|
||||
{
|
||||
auto val = reader.readVarUintAs<uint32_t>();
|
||||
m_viewModelPathIdsBuffer.push_back(val);
|
||||
}
|
||||
decodeDataBindPath(value);
|
||||
}
|
||||
|
||||
void StateMachineListener::copyViewModelPathIds(
|
||||
const StateMachineListenerBase& object)
|
||||
{
|
||||
m_viewModelPathIdsBuffer =
|
||||
object.as<StateMachineListener>()->m_viewModelPathIdsBuffer;
|
||||
copyDataBindPath(object.as<StateMachineListener>()->dataBindPath());
|
||||
}
|
||||
|
||||
std::vector<uint32_t> StateMachineListener::viewModelPathIdsBuffer() const
|
||||
{
|
||||
return dataBindPath()->path();
|
||||
}
|
||||
@@ -42,7 +42,7 @@ const std::vector<uint32_t>& DataBindPath::resolvedPath()
|
||||
return m_pathBuffer;
|
||||
}
|
||||
auto dataResolver = m_file->dataResolver();
|
||||
if (dataResolver)
|
||||
if (dataResolver && m_pathBuffer.size() == 1)
|
||||
{
|
||||
auto pathId = m_pathBuffer[0];
|
||||
m_pathBuffer = dataResolver->resolvePath(pathId);
|
||||
|
||||
@@ -98,6 +98,26 @@ skip_relative_path:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ViewModelInstanceValue* DataContext::getViewModelProperty(
|
||||
DataBindPath* dataBindPath)
|
||||
{
|
||||
if (dataBindPath->isRelative())
|
||||
{
|
||||
auto file = dataBindPath->file();
|
||||
if (file)
|
||||
{
|
||||
auto resolver = file->dataResolver();
|
||||
if (resolver)
|
||||
{
|
||||
return getRelativeViewModelProperty(
|
||||
dataBindPath->resolvedPath(),
|
||||
resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
return getViewModelProperty(dataBindPath->path());
|
||||
}
|
||||
|
||||
rcp<ViewModelInstance> DataContext::getViewModelInstance(
|
||||
const std::vector<uint32_t> path) const
|
||||
{
|
||||
|
||||
@@ -20,19 +20,13 @@ ScriptInputViewModelProperty::~ScriptInputViewModelProperty()
|
||||
void ScriptInputViewModelProperty::decodeDataBindPathIds(
|
||||
Span<const uint8_t> value)
|
||||
{
|
||||
BinaryReader reader(value);
|
||||
while (!reader.reachedEnd())
|
||||
{
|
||||
auto val = reader.readVarUintAs<uint32_t>();
|
||||
m_DataBindPathIdsBuffer.push_back(val);
|
||||
}
|
||||
decodeDataBindPath(value);
|
||||
}
|
||||
|
||||
void ScriptInputViewModelProperty::copyDataBindPathIds(
|
||||
const ScriptInputViewModelPropertyBase& object)
|
||||
{
|
||||
m_DataBindPathIdsBuffer =
|
||||
object.as<ScriptInputViewModelProperty>()->m_DataBindPathIdsBuffer;
|
||||
copyDataBindPath(object.as<ScriptInputViewModelProperty>()->dataBindPath());
|
||||
}
|
||||
|
||||
void ScriptInputViewModelProperty::initScriptedValue()
|
||||
@@ -62,7 +56,11 @@ bool ScriptInputViewModelProperty::validateForScriptInit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto instanceValue = dataContext->getViewModelProperty(dataBindPathIds());
|
||||
if (m_dataBindPath == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto instanceValue = dataContext->getViewModelProperty(m_dataBindPath);
|
||||
if (instanceValue == nullptr)
|
||||
{
|
||||
return false;
|
||||
@@ -78,6 +76,7 @@ bool ScriptInputViewModelProperty::validateForScriptInit()
|
||||
|
||||
StatusCode ScriptInputViewModelProperty::import(ImportStack& importStack)
|
||||
{
|
||||
importDataBindPath(importStack);
|
||||
auto importer =
|
||||
importStack.latest<ScriptedObjectImporter>(ScriptedDrawable::typeKey);
|
||||
if (importer == nullptr)
|
||||
|
||||
Binary file not shown.
@@ -2046,6 +2046,171 @@ TEST_CASE("Relative data binding view model path", "[silver]")
|
||||
|
||||
CHECK(silver.matches("relative_data_bind_path"));
|
||||
}
|
||||
TEST_CASE("Relative data binding view model state machine listener", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/relative_data_bind_path.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("listener");
|
||||
REQUIRE(artboard != nullptr);
|
||||
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto renderer = silver.makeRenderer();
|
||||
// First use the default view model instance that is attached to the
|
||||
// artboard
|
||||
{
|
||||
auto vmi =
|
||||
file->createViewModelInstance((int)artboard.get()->viewModelId(),
|
||||
0);
|
||||
auto numProp = vmi->propertyValue("num")->as<ViewModelInstanceNumber>();
|
||||
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
numProp->propertyValue(100);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
}
|
||||
// Next bind it to a different view model with the same shape
|
||||
{
|
||||
auto vm = file->viewModel("SML_VM2");
|
||||
auto vmi = file->createDefaultViewModelInstance(vm);
|
||||
auto numProp = vmi->propertyValue("num")->as<ViewModelInstanceNumber>();
|
||||
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
numProp->propertyValue(100);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
}
|
||||
|
||||
CHECK(silver.matches("relative_data_bind_path-listener"));
|
||||
}
|
||||
|
||||
TEST_CASE("Relative data binding view model state machine fire trigger",
|
||||
"[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/relative_data_bind_path.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("fire-trigger");
|
||||
REQUIRE(artboard != nullptr);
|
||||
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto renderer = silver.makeRenderer();
|
||||
// First use the default view model instance that is attached to the
|
||||
// artboard
|
||||
{
|
||||
auto vmi =
|
||||
file->createViewModelInstance((int)artboard.get()->viewModelId(),
|
||||
0);
|
||||
auto resetProp =
|
||||
vmi->propertyValue("reset")->as<ViewModelInstanceTrigger>();
|
||||
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
resetProp->trigger();
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
}
|
||||
// Next bind it to a different view model with the same shape
|
||||
{
|
||||
auto vm = file->viewModel("SMFT-VM2");
|
||||
auto vmi = file->createDefaultViewModelInstance(vm);
|
||||
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
}
|
||||
|
||||
CHECK(silver.matches("relative_data_bind_path-fire-trigger"));
|
||||
}
|
||||
TEST_CASE("Relative data binding view model scripted input", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/relative_data_bind_path.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("scripted-input");
|
||||
REQUIRE(artboard != nullptr);
|
||||
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto renderer = silver.makeRenderer();
|
||||
// First use the default view model instance that is attached to the
|
||||
// artboard
|
||||
{
|
||||
auto vmi =
|
||||
file->createViewModelInstance((int)artboard.get()->viewModelId(),
|
||||
0);
|
||||
auto child =
|
||||
vmi->propertyValue("child")->as<ViewModelInstanceViewModel>();
|
||||
auto boo = child->referenceViewModelInstance()
|
||||
->propertyValue("boo")
|
||||
->as<ViewModelInstanceBoolean>();
|
||||
auto paused = child->referenceViewModelInstance()
|
||||
->propertyValue("paused")
|
||||
->as<ViewModelInstanceBoolean>();
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
paused->propertyValue(false);
|
||||
stateMachine->advanceAndApply(1.0f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
paused->propertyValue(true);
|
||||
boo->propertyValue(false);
|
||||
stateMachine->advanceAndApply(1.0f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
}
|
||||
// Next bind it to a different view model with the same shape
|
||||
{
|
||||
auto vm = file->viewModel("SI-VM2");
|
||||
auto vmi = file->createDefaultViewModelInstance(vm);
|
||||
auto child =
|
||||
vmi->propertyValue("child")->as<ViewModelInstanceViewModel>();
|
||||
auto boo = child->referenceViewModelInstance()
|
||||
->propertyValue("boo")
|
||||
->as<ViewModelInstanceBoolean>();
|
||||
auto paused = child->referenceViewModelInstance()
|
||||
->propertyValue("paused")
|
||||
->as<ViewModelInstanceBoolean>();
|
||||
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
paused->propertyValue(false);
|
||||
stateMachine->advanceAndApply(1.0f);
|
||||
artboard->draw(renderer.get());
|
||||
silver.addFrame();
|
||||
paused->propertyValue(true);
|
||||
boo->propertyValue(false);
|
||||
stateMachine->advanceAndApply(1.0f);
|
||||
artboard->draw(renderer.get());
|
||||
}
|
||||
|
||||
CHECK(silver.matches("relative_data_bind_path-scripted-input"));
|
||||
}
|
||||
|
||||
TEST_CASE("Listen to view model value changes in state machines", "[silver]")
|
||||
{
|
||||
|
||||
Binary file not shown.
BIN
tests/unit_tests/silvers/relative_data_bind_path-listener.sriv
Normal file
BIN
tests/unit_tests/silvers/relative_data_bind_path-listener.sriv
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user