data bind artboards rcp file (#10214) c542b9b7ac

* make file ref counted

* migrate File to refcnt

* add bindable artboard class to keep file reference

* feat(unity): support rcp file and BindableArtboard class (#10228)

* refactor(apple): use updated file bindable artboard apis (#10229)

* update command queue to support bindable artboards

* use bindable artboards on command queue

* self manage view model instances in js runtime

* change remaining viewModelInstanceRuntimes to rcp

* refactor(apple): update view model instances to use rcp (#10298)

* refactor(unity): support rcp ViewModelInstanceRuntime (#10309)

* rebase fix

* deprecate getArtboard in favor of getBindableArtboard

* fix merge

* remove unused lambda capture

* fix rive binding

* feat(Android): RCP File, VMI, and add bindable artboards (#10456)

* refactor: C++ refactors

- Import from long (incorrect) -> jlong
- Header clang-tidy fix
- Use reinterpret_cast instead of C-style cast
- Break out some variables instead of long one liners
- Use auto
- Remove unused env and thisObj

# Conflicts:
#	packages/runtime_android/kotlin/src/main/cpp/src/helpers/general.cpp

* docs: Improve documentation on the File class

* feat: Support bindable artboard type and RCP VMIs

# Conflicts:
#	packages/runtime_android/kotlin/src/androidTest/java/app/rive/runtime/kotlin/core/RiveDataBindingTest.kt

* feat: Support RCP files

* refactor: Change from +1/-1 ref to just release

* fix: Moved to the more appropriate null pointer for GetStringUTFChars

* replace unref with release

Co-authored-by: Adam <67035612+damzobridge@users.noreply.github.com>
Co-authored-by: David Skuza <david@rive.app>
Co-authored-by: Erik <erik@rive.app>
Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
bodymovin
2025-09-30 00:01:40 +00:00
parent 080ae94b7c
commit 6362192a61
41 changed files with 236 additions and 97 deletions

View File

@@ -1 +1 @@
f7613dbf3542cf1d666612856728d70ba1715521
c542b9b7ac7ac5cd96f798f3fbe7dd5411beecd3

View File

@@ -38,6 +38,7 @@ class DataBind;
class BindableProperty;
class HitDrawable;
class ListenerViewModel;
typedef void (*DataBindChanged)();
#ifdef WITH_RIVE_TOOLS
class StateMachineInstance;

View File

@@ -6,9 +6,7 @@
#include "rive/animation/linear_animation.hpp"
#include "rive/animation/state_machine.hpp"
#include "rive/core_context.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind/data_context.hpp"
#include "rive/data_bind/data_bind_context.hpp"
#include "rive/viewmodel/viewmodel_instance_value.hpp"
#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
#include "rive/generated/artboard_base.hpp"
@@ -48,6 +46,7 @@ class SMIBool;
class SMIInput;
class SMINumber;
class SMITrigger;
class DataBind;
#ifdef WITH_RIVE_TOOLS
typedef void (*ArtboardCallback)(void*);

View File

@@ -8,6 +8,7 @@
#include "rive/artboard.hpp"
#include "rive/constraints/constrainable_list.hpp"
#include "rive/property_recorder.hpp"
#include "rive/file.hpp"
#include "rive/artboard_host.hpp"
#include "rive/data_bind/data_bind_list_item_consumer.hpp"
#include "rive/layout/layout_node_provider.hpp"
@@ -17,7 +18,6 @@
#include <unordered_map>
namespace rive
{
class File;
class LayoutComponent;
class ScrollConstraint;

View File

@@ -1,6 +1,7 @@
#ifndef _RIVE_ARTBOARD_HOST_HPP_
#define _RIVE_ARTBOARD_HOST_HPP_
#include "rive/refcnt.hpp"
#include "rive/file.hpp"
#include <stdio.h>
namespace rive
{
@@ -8,7 +9,6 @@ class ArtboardInstance;
class DataBind;
class DataContext;
class ViewModelInstance;
class File;
class ArtboardHost
{

View File

@@ -0,0 +1,23 @@
#ifndef _RIVE_BINDABLE_ARTBOARD_HPP_
#define _RIVE_BINDABLE_ARTBOARD_HPP_
#include "rive/refcnt.hpp"
#include "rive/file.hpp"
#include "rive/artboard.hpp"
namespace rive
{
class BindableArtboard : public RefCnt<BindableArtboard>
{
public:
BindableArtboard(rcp<const File> file,
std::unique_ptr<ArtboardInstance> artboard);
ArtboardInstance* artboard() { return m_artboard.get(); }
private:
rcp<const File> m_file;
std::unique_ptr<ArtboardInstance> m_artboard;
};
} // namespace rive
#endif

View File

@@ -29,6 +29,7 @@ public:
AudioSource* getAudioSource(AudioSourceHandle) const;
Font* getFont(FontHandle) const;
ArtboardInstance* getArtboardInstance(ArtboardHandle) const;
rcp<BindableArtboard> getBindableArtboard(ArtboardHandle) const;
StateMachineInstance* getStateMachineInstance(StateMachineHandle) const;
ViewModelInstanceRuntime* getViewModelInstance(
ViewModelInstanceHandle) const;
@@ -187,8 +188,7 @@ private:
std::unordered_map<FontHandle, rcp<Font>> m_fonts;
std::unordered_map<RenderImageHandle, rcp<RenderImage>> m_images;
std::unordered_map<AudioSourceHandle, rcp<AudioSource>> m_audioSources;
std::unordered_map<ArtboardHandle, std::unique_ptr<ArtboardInstance>>
m_artboards;
std::unordered_map<ArtboardHandle, rcp<BindableArtboard>> m_artboards;
std::unordered_map<ViewModelInstanceHandle, rcp<ViewModelInstanceRuntime>>
m_viewModels;
std::unordered_map<StateMachineHandle,

View File

@@ -6,10 +6,10 @@
#include "rive/refcnt.hpp"
#include "rive/viewmodel/viewmodel.hpp"
#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
#include "rive/file.hpp"
#include <stdio.h>
namespace rive
{
class File;
class DataConverterNumberToList : public DataConverterNumberToListBase
{

View File

@@ -7,10 +7,10 @@
#include "rive/data_bind/converters/data_converter.hpp"
#include "rive/data_bind/data_values/data_type.hpp"
#include "rive/dirtyable.hpp"
#include "rive/file.hpp"
#include <stdio.h>
namespace rive
{
class File;
class DataBindContextValue;
#ifdef WITH_RIVE_TOOLS
class DataBind;
@@ -43,8 +43,8 @@ public:
bool sourceToTargetRunsFirst();
bool advance(float elapsedTime);
void suppressDirt(bool value) { m_suppressDirt = value; };
void file(File* value) { m_file = value; };
File* file() const { return m_file; };
void file(File* value);
File* file() const;
DataType outputType();
DataType sourceOutputType();

View File

@@ -12,6 +12,7 @@
#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
#include "rive/animation/keyframe_interpolator.hpp"
#include "rive/data_bind/converters/data_converter.hpp"
#include "rive/refcnt.hpp"
#include <vector>
#include <set>
@@ -23,10 +24,12 @@
namespace rive
{
class BinaryReader;
class DataBind;
class RuntimeHeader;
class Factory;
class ScrollPhysics;
class ViewModelRuntime;
class BindableArtboard;
///
/// Tracks the success/failure result when importing a Rive file.
@@ -92,6 +95,9 @@ public:
std::unique_ptr<ArtboardInstance> artboardDefault() const;
std::unique_ptr<ArtboardInstance> artboardAt(size_t index) const;
std::unique_ptr<ArtboardInstance> artboardNamed(std::string name) const;
rcp<BindableArtboard> bindableArtboardNamed(std::string name) const;
rcp<BindableArtboard> bindableArtboardDefault() const;
rcp<BindableArtboard> internalBindableArtboardFromArtboard(Artboard*) const;
Artboard* artboard() const;

View File

@@ -12,6 +12,7 @@
#include "rive/viewmodel/viewmodel_instance_artboard.hpp"
#include "rive/refcnt.hpp"
#include "rive/file.hpp"
#include <stdio.h>
namespace rive
{

View File

@@ -5,6 +5,7 @@
#include <stdint.h>
#include "rive/viewmodel/runtime/viewmodel_instance_value_runtime.hpp"
#include "rive/viewmodel/viewmodel_instance_artboard.hpp"
#include "rive/bindable_artboard.hpp"
namespace rive
{
@@ -17,11 +18,11 @@ public:
ViewModelInstanceArtboard* viewModelInstance) :
ViewModelInstanceValueRuntime(viewModelInstance)
{}
void value(Artboard* artboard);
void value(rcp<BindableArtboard> bindableArtboard);
const DataType dataType() override { return DataType::artboard; }
#ifdef TESTING
Artboard* testing_value();
rcp<BindableArtboard> testing_value();
#endif
};
} // namespace rive

View File

@@ -19,7 +19,7 @@ public:
ViewModelInstanceListRuntime(ViewModelInstanceList* viewModelInstance) :
ViewModelInstanceValueRuntime(viewModelInstance)
{}
ViewModelInstanceRuntime* instanceAt(int index);
rcp<ViewModelInstanceRuntime> instanceAt(int index);
void addInstance(ViewModelInstanceRuntime*);
bool addInstanceAt(ViewModelInstanceRuntime*, int);
void removeInstance(ViewModelInstanceRuntime*);

View File

@@ -43,7 +43,8 @@ public:
ViewModelInstanceTriggerRuntime* propertyTrigger(
const std::string& path) const;
ViewModelInstanceListRuntime* propertyList(const std::string& path) const;
ViewModelInstanceRuntime* propertyViewModel(const std::string& path) const;
rcp<ViewModelInstanceRuntime> propertyViewModel(
const std::string& path) const;
ViewModelInstanceAssetImageRuntime* propertyImage(
const std::string& path) const;
ViewModelInstanceArtboardRuntime* propertyArtboard(

View File

@@ -27,11 +27,11 @@ public:
const std::string& name() const;
size_t instanceCount() const;
size_t propertyCount() const;
ViewModelInstanceRuntime* createInstanceFromIndex(size_t index) const;
ViewModelInstanceRuntime* createInstanceFromName(
rcp<ViewModelInstanceRuntime> createInstanceFromIndex(size_t index) const;
rcp<ViewModelInstanceRuntime> createInstanceFromName(
const std::string& name) const;
ViewModelInstanceRuntime* createDefaultInstance() const;
ViewModelInstanceRuntime* createInstance() const;
rcp<ViewModelInstanceRuntime> createDefaultInstance() const;
rcp<ViewModelInstanceRuntime> createInstance() const;
std::vector<PropertyData> properties();
static std::vector<PropertyData> buildPropertiesData(
std::vector<rive::ViewModelProperty*>& properties);
@@ -40,9 +40,7 @@ public:
private:
ViewModel* m_viewModel;
const File* m_file;
mutable std::vector<rcp<ViewModelInstanceRuntime>>
m_viewModelInstanceRuntimes;
ViewModelInstanceRuntime* createRuntimeInstance(
rcp<ViewModelInstanceRuntime> createRuntimeInstance(
rcp<ViewModelInstance> instance) const;
};
} // namespace rive

View File

@@ -1,6 +1,7 @@
#ifndef _RIVE_VIEW_MODEL_INSTANCE_ARTBOARD_HPP_
#define _RIVE_VIEW_MODEL_INSTANCE_ARTBOARD_HPP_
#include "rive/generated/viewmodel/viewmodel_instance_artboard_base.hpp"
#include "rive/bindable_artboard.hpp"
#include <stdio.h>
namespace rive
{
@@ -15,11 +16,11 @@ protected:
void propertyValueChanged() override;
public:
void asset(Artboard* value);
Artboard* asset() { return m_artboard; }
void asset(rcp<BindableArtboard> value);
rcp<BindableArtboard> asset() { return m_bindableArtboard; }
private:
Artboard* m_artboard = nullptr;
rcp<BindableArtboard> m_bindableArtboard = nullptr;
#ifdef WITH_RIVE_TOOLS
public:
void onChanged(ViewModelArtboardChanged callback)

View File

@@ -3,6 +3,7 @@
#include "rive/math/simd.hpp"
#include "rive/artboard.hpp"
#include "rive/file.hpp"
#include "rive/refcnt.hpp"
#include "rive/layout.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/static_scene.hpp"

View File

@@ -4,6 +4,7 @@
#include "rive/artboard.hpp"
#include "rive/file.hpp"
#include "rive/refcnt.hpp"
#include "rive/animation/linear_animation_instance.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/animation/state_machine_input_instance.hpp"

View File

@@ -4,6 +4,7 @@
#include "rive/animation/state_machine_layer.hpp"
#include "rive/animation/state_machine_input.hpp"
#include "rive/animation/state_machine_listener.hpp"
#include "rive/data_bind/data_bind.hpp"
using namespace rive;

View File

@@ -27,6 +27,8 @@
#include "rive/viewmodel/viewmodel_instance_trigger.hpp"
#include "rive/artboard_component_list.hpp"
#include "rive/constraints/draggable_constraint.hpp"
#include "rive/data_bind/data_bind_context.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind_flags.hpp"
#include "rive/event_report.hpp"
#include "rive/gesture_click_phase.hpp"

View File

@@ -23,6 +23,7 @@
#include "rive/nested_artboard_leaf.hpp"
#include "rive/nested_artboard_layout.hpp"
#include "rive/joystick.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind_flags.hpp"
#include "rive/animation/nested_bool.hpp"
#include "rive/animation/nested_number.hpp"
@@ -1666,7 +1667,7 @@ void Artboard::bindViewModelInstance(rcp<ViewModelInstance> viewModelInstance,
bool Artboard::isAncestor(const Artboard* artboard)
{
if (m_artboardSource == artboard)
if (artboard != nullptr && m_artboardSource == artboard->artboardSource())
{
return true;
}

View File

@@ -0,0 +1,8 @@
#include "rive/bindable_artboard.hpp"
using namespace rive;
BindableArtboard::BindableArtboard(rcp<const File> file,
std::unique_ptr<ArtboardInstance> artboard) :
m_file(file), m_artboard(std::move(artboard))
{}

View File

@@ -293,7 +293,15 @@ ArtboardInstance* CommandServer::getArtboardInstance(
{
assert(std::this_thread::get_id() == m_threadID);
auto it = m_artboards.find(handle);
return it != m_artboards.end() ? it->second.get() : nullptr;
return it != m_artboards.end() ? it->second.get()->artboard() : nullptr;
}
rcp<BindableArtboard> CommandServer::getBindableArtboard(
ArtboardHandle handle) const
{
assert(std::this_thread::get_id() == m_threadID);
auto it = m_artboards.find(handle);
return it != m_artboards.end() ? it->second : nullptr;
}
StateMachineInstance* CommandServer::getStateMachineInstance(
@@ -519,7 +527,7 @@ bool CommandServer::processCommands()
if (file != nullptr)
{
m_fileDependencies[handle] = {};
m_files[handle] = std::move(file);
m_files[handle] = file;
std::unique_lock<std::mutex> messageLock(
m_commandQueue->m_messageMutex);
@@ -823,12 +831,9 @@ bool CommandServer::processCommands()
if (rive::File* file = getFile(fileHandle))
{
if (auto artboard = name.empty()
? file->artboardDefault()
: file->artboardNamed(name))
? file->bindableArtboardDefault()
: file->bindableArtboardNamed(name))
{
assert(m_fileDependencies.find(fileHandle) !=
m_fileDependencies.end());
m_fileDependencies[fileHandle].push_back(handle);
m_artboardDependencies[handle] = {};
m_artboards[handle] = std::move(artboard);
}
@@ -984,8 +989,7 @@ bool CommandServer::processCommands()
{
if (viewModelInstanceName.empty())
{
instance =
ref_rcp(viewModel->createDefaultInstance());
instance = viewModel->createDefaultInstance();
if (instance == nullptr)
{
ErrorReporter<FileHandle>(
@@ -1000,9 +1004,8 @@ bool CommandServer::processCommands()
}
else
{
instance =
ref_rcp(viewModel->createInstanceFromName(
viewModelInstanceName));
instance = viewModel->createInstanceFromName(
viewModelInstanceName);
if (instance == nullptr)
{
ErrorReporter<FileHandle>(
@@ -1019,7 +1022,7 @@ bool CommandServer::processCommands()
}
else
{
instance = ref_rcp(viewModel->createInstance());
instance = viewModel->createInstance();
if (instance == nullptr)
{
ErrorReporter<FileHandle>(
@@ -1313,8 +1316,7 @@ bool CommandServer::processCommands()
if (auto nestedViewModel =
rootViewInstance->propertyViewModel(path))
{
m_viewModels[nestedViewHandle] =
ref_rcp(nestedViewModel);
m_viewModels[nestedViewHandle] = nestedViewModel;
}
else
{
@@ -1365,8 +1367,7 @@ bool CommandServer::processCommands()
auto viewModelInstance = list->instanceAt(index);
if (viewModelInstance)
{
m_viewModels[listViewHandle] =
ref_rcp(viewModelInstance);
m_viewModels[listViewHandle] = viewModelInstance;
}
else
{
@@ -2244,14 +2245,14 @@ bool CommandServer::processCommands()
}
case DataType::artboard:
{
if (auto artboard =
getArtboardInstance(artboadHandle))
if (auto bindableArtboard =
getBindableArtboard(artboadHandle))
{
if (auto artboardProperty =
viewModelInstance->propertyArtboard(
value.metaData.name))
{
artboardProperty->value(artboard);
artboardProperty->value(bindableArtboard);
}
else
{

View File

@@ -391,4 +391,8 @@ bool DataBind::advance(float elapsedTime)
return converter()->advance(elapsedTime);
}
return false;
}
}
void DataBind::file(File* value) { m_file = value; };
File* DataBind::file() const { return m_file; };

View File

@@ -1,4 +1,5 @@
#include "rive/file.hpp"
#include "rive/bindable_artboard.hpp"
#include "rive/runtime_header.hpp"
#include "rive/animation/animation.hpp"
#include "rive/artboard_component_list.hpp"
@@ -38,6 +39,7 @@
#include "rive/animation/blend_state_direct.hpp"
#include "rive/animation/transition_property_viewmodel_comparator.hpp"
#include "rive/constraints/scrolling/scroll_physics.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind/bindable_property.hpp"
#include "rive/data_bind/bindable_property_artboard.hpp"
#include "rive/data_bind/bindable_property_asset.hpp"
@@ -589,6 +591,27 @@ std::unique_ptr<ArtboardInstance> File::artboardNamed(std::string name) const
return ab ? ab->instance() : nullptr;
}
rcp<BindableArtboard> File::bindableArtboardNamed(std::string name) const
{
auto ab = this->artboardNamed(name);
return ab ? make_rcp<BindableArtboard>(ref_rcp(this), std::move(ab))
: nullptr;
}
rcp<BindableArtboard> File::bindableArtboardDefault() const
{
auto ab = this->artboardDefault();
return ab ? make_rcp<BindableArtboard>(ref_rcp(this), std::move(ab))
: nullptr;
}
rcp<BindableArtboard> File::internalBindableArtboardFromArtboard(
Artboard* artboard) const
{
auto ab = artboard ? artboard->instance() : nullptr;
return ab ? make_rcp<BindableArtboard>(nullptr, std::move(ab)) : nullptr;
}
void File::completeViewModelInstance(
rcp<ViewModelInstance> viewModelInstance) const
{

View File

@@ -9,6 +9,7 @@
#include "rive/constraints/scrolling/scroll_physics.hpp"
#include "rive/viewmodel/viewmodel.hpp"
#include "rive/viewmodel/viewmodel_instance.hpp"
#include "rive/file.hpp"
#include "rive/data_bind/converters/data_converter.hpp"
#include "rive/data_bind/converters/data_converter_group_item.hpp"
#include "rive/data_bind/converters/data_converter_range_mapper.hpp"

View File

@@ -64,9 +64,10 @@ Artboard* NestedArtboard::findArtboard(
}
if (viewModelInstanceArtboard->asset() != nullptr)
{
if (!parentArtboard()->isAncestor(viewModelInstanceArtboard->asset()))
if (!parentArtboard()->isAncestor(
viewModelInstanceArtboard->asset()->artboard()))
{
return viewModelInstanceArtboard->asset();
return viewModelInstanceArtboard->asset()->artboard();
}
return nullptr;
}

View File

@@ -4,13 +4,15 @@
// Default namespace for Rive Cpp code
using namespace rive;
void ViewModelInstanceArtboardRuntime::value(Artboard* artboard)
void ViewModelInstanceArtboardRuntime::value(
rcp<BindableArtboard> bindableArtboard)
{
m_viewModelInstanceValue->as<ViewModelInstanceArtboard>()->asset(artboard);
m_viewModelInstanceValue->as<ViewModelInstanceArtboard>()->asset(
bindableArtboard);
}
#ifdef TESTING
Artboard* ViewModelInstanceArtboardRuntime::testing_value()
rcp<BindableArtboard> ViewModelInstanceArtboardRuntime::testing_value()
{
return m_viewModelInstanceValue->as<ViewModelInstanceArtboard>()->asset();
}

View File

@@ -6,7 +6,8 @@
// Default namespace for Rive Cpp code
using namespace rive;
ViewModelInstanceRuntime* ViewModelInstanceListRuntime::instanceAt(int index)
rcp<ViewModelInstanceRuntime> ViewModelInstanceListRuntime::instanceAt(
int index)
{
auto listItems =
m_viewModelInstanceValue->as<ViewModelInstanceList>()->listItems();
@@ -22,12 +23,12 @@ ViewModelInstanceRuntime* ViewModelInstanceListRuntime::instanceAt(int index)
auto it = m_itemsMap.find(listItem);
if (it != m_itemsMap.end())
{
return it->second.get();
return rcp<ViewModelInstanceRuntime>(it->second);
}
auto instanceRuntime =
make_rcp<ViewModelInstanceRuntime>(listItem->viewModelInstance());
m_itemsMap[listItem] = instanceRuntime;
return instanceRuntime.get();
return rcp<ViewModelInstanceRuntime>(instanceRuntime);
}
void ViewModelInstanceListRuntime::addInstance(

View File

@@ -296,14 +296,14 @@ rcp<ViewModelInstanceRuntime> ViewModelInstanceRuntime::instanceRuntime(
return nullptr;
}
ViewModelInstanceRuntime* ViewModelInstanceRuntime::propertyViewModel(
rcp<ViewModelInstanceRuntime> ViewModelInstanceRuntime::propertyViewModel(
const std::string& path) const
{
const auto propertyName = getPropertyNameFromPath(path);
auto viewModelInstance = viewModelInstanceFromFullPath(path);
if (viewModelInstance != nullptr)
{
return viewModelInstance->instanceRuntime(propertyName).get();
return viewModelInstance->instanceRuntime(propertyName);
}
return nullptr;
}

View File

@@ -108,7 +108,7 @@ std::vector<std::string> ViewModelRuntime::instanceNames() const
return names;
}
ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromIndex(
rcp<ViewModelInstanceRuntime> ViewModelRuntime::createInstanceFromIndex(
const size_t index) const
{
auto viewModelInstance = m_viewModel->instance(index);
@@ -129,7 +129,7 @@ ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromIndex(
return nullptr;
}
ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromName(
rcp<ViewModelInstanceRuntime> ViewModelRuntime::createInstanceFromName(
const std::string& name) const
{
auto viewModelInstance = m_viewModel->instance(name);
@@ -151,7 +151,7 @@ ViewModelInstanceRuntime* ViewModelRuntime::createInstanceFromName(
return nullptr;
}
ViewModelInstanceRuntime* ViewModelRuntime::createDefaultInstance() const
rcp<ViewModelInstanceRuntime> ViewModelRuntime::createDefaultInstance() const
{
auto viewModelInstance =
m_file->createDefaultViewModelInstance(m_viewModel);
@@ -164,21 +164,20 @@ ViewModelInstanceRuntime* ViewModelRuntime::createDefaultInstance() const
return createInstance();
}
ViewModelInstanceRuntime* ViewModelRuntime::createInstance() const
rcp<ViewModelInstanceRuntime> ViewModelRuntime::createInstance() const
{
auto instance = m_file->createViewModelInstance(m_viewModel);
return createRuntimeInstance(instance);
}
ViewModelInstanceRuntime* ViewModelRuntime::createRuntimeInstance(
rcp<ViewModelInstanceRuntime> ViewModelRuntime::createRuntimeInstance(
rcp<ViewModelInstance> instance) const
{
if (instance != nullptr)
{
auto viewModelInstanceRuntime = rcp<ViewModelInstanceRuntime>(
new ViewModelInstanceRuntime(instance));
m_viewModelInstanceRuntimes.push_back(viewModelInstanceRuntime);
return viewModelInstanceRuntime.get();
return viewModelInstanceRuntime;
}
return nullptr;
}

View File

@@ -10,7 +10,7 @@ using namespace rive;
void ViewModelInstanceArtboard::propertyValueChanged()
{
m_artboard = nullptr;
m_bindableArtboard = nullptr;
addDirt(ComponentDirt::Bindings);
#ifdef WITH_RIVE_TOOLS
if (m_changedCallback != nullptr)
@@ -21,9 +21,9 @@ void ViewModelInstanceArtboard::propertyValueChanged()
onValueChanged();
}
void ViewModelInstanceArtboard::asset(Artboard* value)
void ViewModelInstanceArtboard::asset(rcp<BindableArtboard> value)
{
propertyValue(-1);
m_artboard = value;
m_bindableArtboard = value;
addDirt(ComponentDirt::Bindings);
}

View File

@@ -4,6 +4,7 @@
#include "rive/artboard.hpp"
#include "rive/factory.hpp"
#include "rive/file.hpp"
#include "rive/refcnt.hpp"
struct AutoClose
{

View File

@@ -14,6 +14,7 @@
#include "rive/artboard.hpp"
#include "rive/renderer.hpp"
#include "rive/file.hpp"
#include "rive/refcnt.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/static_scene.hpp"
#include <filesystem>

View File

@@ -8,6 +8,7 @@
#include "common/test_harness.hpp"
#include "common/testing_window.hpp"
#include "rive/artboard.hpp"
#include "rive/refcnt.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/file.hpp"
#include "rive/text/font_hb.hpp"

View File

@@ -175,9 +175,8 @@ TEST_CASE("artboard management", "[CommandQueue]")
// Deleting the file first should now delete the artboard as well.
commandQueue->deleteFile(fileHandle);
commandQueue->runOnce([fileHandle, artboardHandle1](CommandServer* server) {
commandQueue->runOnce([fileHandle](CommandServer* server) {
CHECK(server->getFile(fileHandle) == nullptr);
CHECK(server->getArtboardInstance(artboardHandle1) == nullptr);
});
commandQueue->deleteArtboard(artboardHandle1);
@@ -792,7 +791,7 @@ TEST_CASE("View Models", "[CommandQueue]")
auto list =
server->getViewModelInstance(bviewModel)->propertyList("Test List");
CHECK(list != nullptr);
CHECK(list->instanceAt(0) ==
CHECK(list->instanceAt(0).get() ==
server->getViewModelInstance(listViewModel));
});
@@ -1628,7 +1627,7 @@ public:
CHECK(nested != nullptr);
auto property = instance->propertyViewModel(name);
CHECK(property != nullptr);
CHECK(property == nested);
CHECK(property.get() == nested);
});
// There is no requesting for nested view models
@@ -1807,20 +1806,24 @@ TEST_CASE("View Model Property Set/Get", "[CommandQueue]")
});
// Same for artboards.
auto bindableArtboardHandle =
commandQueue->instantiateDefaultArtboard(fileHandle);
commandQueue->setViewModelInstanceArtboard(tester.m_handle,
"Test Artboard",
artboardHandle);
bindableArtboardHandle);
commandQueue->runOnce([artboardHandle,
commandQueue->runOnce([bindableArtboardHandle,
handle = tester.m_handle](CommandServer* server) {
auto artboard = server->getArtboardInstance(artboardHandle);
CHECK(artboard != nullptr);
auto bindableArtboard =
server->getBindableArtboard(bindableArtboardHandle);
CHECK(bindableArtboard != nullptr);
auto viewModel = server->getViewModelInstance(handle);
CHECK(viewModel != nullptr);
auto artboardProperty = viewModel->propertyArtboard("Test Artboard");
CHECK(artboardProperty != nullptr);
CHECK(artboardProperty->testing_value() == artboard);
CHECK(artboardProperty->testing_value() == bindableArtboard);
});
commandQueue->deleteArtboard(bindableArtboardHandle);
auto badImageHandle =
commandQueue->decodeImage(std::vector<uint8_t>(1024 * 1024, {}));
@@ -2512,8 +2515,8 @@ public:
CHECK(value2Instance != nullptr);
auto property = instance->propertyList(name);
CHECK(property != nullptr);
CHECK(property->instanceAt(index) == value1Instance);
CHECK(property->instanceAt(index2) == value2Instance);
CHECK(property->instanceAt(index).get() == value1Instance);
CHECK(property->instanceAt(index2).get() == value2Instance);
});
}
@@ -2532,23 +2535,23 @@ public:
auto property = instance->propertyList(name);
CHECK(property != nullptr);
auto valueModel = server->getViewModelInstance(value);
CHECK(property->instanceAt(index) == valueModel);
CHECK(property->instanceAt(index).get() == valueModel);
});
}
void pushExpectation(std::string name, ViewModelInstanceHandle value)
{
m_queue->appendViewModelInstanceListViewModel(m_handle, name, value);
m_queue->runOnce(
[handle = m_handle, name, value](CommandServer* server) {
auto instance = server->getViewModelInstance(handle);
CHECK(instance != nullptr);
auto property = instance->propertyList(name);
CHECK(property != nullptr);
auto valueModel = server->getViewModelInstance(value);
CHECK(property->instanceAt(static_cast<int>(property->size()) -
1) == valueModel);
});
m_queue->runOnce([handle = m_handle, name, value](
CommandServer* server) {
auto instance = server->getViewModelInstance(handle);
CHECK(instance != nullptr);
auto property = instance->propertyList(name);
CHECK(property != nullptr);
auto valueModel = server->getViewModelInstance(value);
CHECK(property->instanceAt(static_cast<int>(property->size()) - 1)
.get() == valueModel);
});
}
void pushBadExpectation(std::string name,

View File

@@ -68,7 +68,7 @@ TEST_CASE("Test data binding artboards from same and different sources",
// Change source to local artboard at index 1
auto ch1Source = file->artboard("ch1");
auto ch1Source = file->bindableArtboardNamed("ch1");
vmiArtboard->asset(ch1Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
@@ -76,14 +76,14 @@ TEST_CASE("Test data binding artboards from same and different sources",
// Change source to local artboard at index 2
auto ch2Source = file->artboard("ch2");
auto ch2Source = file->bindableArtboardNamed("ch2");
vmiArtboard->asset(ch2Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Change source to external artboard "source_1"
auto source1 = sourceFile->artboard("source_1");
auto source1 = sourceFile->bindableArtboardNamed("source_1");
vmiArtboard->asset(source1);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
@@ -102,7 +102,7 @@ TEST_CASE("Test data binding artboards from same and different sources",
artboard->draw(renderer.get());
// Change source to external artboard "source_2"
auto source2 = sourceFile->artboard("source_2");
auto source2 = sourceFile->bindableArtboardNamed("source_2");
vmiArtboard->asset(source2);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
@@ -166,7 +166,7 @@ TEST_CASE("Test recursive data binding artboards is skipped", "[data binding]")
artboard->draw(renderer.get());
// Change source to artboard "recursive-grand-child-1"
auto child1Source = file->artboard("recursive-grand-child-1");
auto child1Source = file->bindableArtboardNamed("recursive-grand-child-1");
vmiArtboard->asset(child1Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
@@ -174,7 +174,7 @@ TEST_CASE("Test recursive data binding artboards is skipped", "[data binding]")
// Changing source to artboard "recursive-parent" does not change the
// content because it's an ancestor of itself
auto parentSource = file->artboard("recursive-parent");
auto parentSource = file->bindableArtboardNamed("recursive-parent");
vmiArtboard->asset(parentSource);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
@@ -182,18 +182,74 @@ TEST_CASE("Test recursive data binding artboards is skipped", "[data binding]")
// Changing source to artboard "recursive-grand-parent" does not change the
// content because it's an ancestor of itself
auto grandParentSource = file->artboard("recursive-grand-parent");
auto grandParentSource =
file->bindableArtboardNamed("recursive-grand-parent");
vmiArtboard->asset(grandParentSource);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Change source to artboard "recursive-grand-child-2"
auto child2Source = file->artboard("recursive-grand-child-2");
auto child2Source = file->bindableArtboardNamed("recursive-grand-child-2");
vmiArtboard->asset(child2Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
CHECK(silver.matches("data_binding_artboards_test_recursive"));
}
TEST_CASE("Test default data binding artboard from different source",
"[data binding]")
{
// Note: the data_binding_artboards_source_test has a view model created
// that matches the view model the original artboards have. This is a
// temporary "hack" to validate that the artboard gets correctly bound
SerializingFactory silver;
auto file = ReadRiveFile("assets/data_binding_artboards_test.riv", &silver);
auto sourceFile =
ReadRiveFile("assets/data_binding_artboards_source_test.riv", &silver);
auto artboard = file->artboardDefault();
silver.frameSize(artboard->width(), artboard->height());
REQUIRE(artboard != nullptr);
auto stateMachine = artboard->stateMachineAt(0);
int viewModelId = artboard.get()->viewModelId();
auto vmi = viewModelId == -1
? file->createViewModelInstance(artboard.get())
: file->createViewModelInstance(viewModelId, 0);
stateMachine->bindViewModelInstance(vmi);
stateMachine->advanceAndApply(0.1f);
auto renderer = silver.makeRenderer();
artboard->draw(renderer.get());
auto vmiArtboard =
vmi->propertyValue("ab")->as<ViewModelInstanceArtboard>();
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Change source to local artboard at index 1
auto ch1Source = file->bindableArtboardNamed("ch1");
vmiArtboard->asset(ch1Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Change source to local artboard at index 2
auto ch2Source = file->bindableArtboardNamed("ch2");
vmiArtboard->asset(ch2Source);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Change source to default bindable artboard
auto source1 = sourceFile->bindableArtboardDefault();
vmiArtboard->asset(source1);
silver.addFrame();
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
CHECK(silver.matches("data_binding_artboards_default_test"));
}