Nnnnn export bindable object with different (#12779) a680ab80e5 * chore(runtime): remove unused list methods * fix(editor): export data bind if primary is not found Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head index b7d8638..9769a18 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -76eeeed5d987e8129ae4393e57b1db097607bbc9 +a680ab80e5dce5aaf304a0e9a1c5ef6319762335
diff --git a/include/rive/artboard_component_list.hpp b/include/rive/artboard_component_list.hpp index bc90480..e676e4e 100644 --- a/include/rive/artboard_component_list.hpp +++ b/include/rive/artboard_component_list.hpp
@@ -114,8 +114,6 @@ invalidateOrderedListIndicesCache(); } void shouldResetInstances(bool value) { m_shouldResetInstances = value; } - bool useStatefulInstances() const { return m_useStatefulInstances; } - void useStatefulInstances(bool value) { m_useStatefulInstances = value; } void setVirtualizablePosition(int index, Vec2D position) override; void createArtboardAt(int index, bool forceLayoutSync = true); void addArtboardAt(std::unique_ptr<ArtboardInstance> artboard, @@ -198,21 +196,10 @@ m_artboardOverridesMap; std::unordered_map<int, int> m_artboardMapRules; - // Data binds that bridge properties between a stateful component's - // cloned ViewModelInstance and the original (user-provided) one. - // Keyed by list item so they can be cleaned up when the item is removed. - std::unordered_map<rcp<ViewModelInstanceListItem>, - std::vector<std::unique_ptr<DataBind>>> - m_bridgeDataBinds; - void createBridgeBinds(rcp<ViewModelInstanceListItem> listItem, - ViewModelInstance* original, - ViewModelInstance* clone); - void removeBridgeBinds(const rcp<ViewModelInstanceListItem>& listItem); void attachArtboardOverride(ArtboardInstance*, rcp<ViewModelInstanceListItem>); void clearArtboardOverride(ArtboardInstance*); bool m_shouldResetInstances = false; - bool m_useStatefulInstances = false; bool listsAreEqual(std::vector<rcp<ViewModelInstanceListItem>>* list, std::vector<rcp<ViewModelInstanceListItem>>* compared);
diff --git a/src/artboard_component_list.cpp b/src/artboard_component_list.cpp index 4a7bc0e..f80b773 100644 --- a/src/artboard_component_list.cpp +++ b/src/artboard_component_list.cpp
@@ -121,22 +121,6 @@ } } - // Clean up bridge binds FIRST since they reference VM instances - // that may be owned by the artboard instances below. - auto* parentAb = artboard(); - for (auto& [item, binds] : m_bridgeDataBinds) - { - for (auto& bind : binds) - { - bind->unbind(); - if (parentAb != nullptr) - { - parentAb->removeDataBind(bind.get()); - } - } - } - m_bridgeDataBinds.clear(); - // Destroy state machines BEFORE artboards. // StateMachineInstance owns FocusListenerGroup objects that hold raw // pointers to FocusData (owned by artboards). Destroying artboards first @@ -1263,56 +1247,8 @@ { auto mainArtboard = this->artboard(); auto dataContext = mainArtboard->dataContext(); - rcp<ViewModelInstance> viewModelInstance = nullptr; - - if (m_file != nullptr) - { - auto source = artboardInstance->artboardSource(); - if (m_useStatefulInstances && source != nullptr) - { - auto listItemInstance = listItem->viewModelInstance(); - if (listItemInstance != nullptr) - { - auto copy = rcp<ViewModelInstance>( - listItemInstance->clone()->as<ViewModelInstance>()); - m_file->completeViewModelProperties(copy.get()); -#ifdef WITH_RIVE_TOOLS - if (copy) - { - m_file->registerViewModelInstance(copy.get(), copy); - } -#endif - viewModelInstance = copy; - - // Create bridge data binds between the original and - // cloned VM instances for input/output properties. - createBridgeBinds(listItem, - listItemInstance.get(), - copy.get()); - } - else - { - auto viewModel = m_file->viewModel(source->viewModelId()); - if (viewModel != nullptr) - { - viewModelInstance = - m_file->createDefaultViewModelInstance(viewModel); - } - // Store the default instance on the list item so we - // don't recreate one every time. - if (viewModelInstance != nullptr) - { - listItem->viewModelInstance(viewModelInstance); - } - } - } - } - - // Fall back to the list item's VM instance if not stateful. - if (viewModelInstance == nullptr) - { - viewModelInstance = listItem->viewModelInstance(); - } + rcp<ViewModelInstance> viewModelInstance = + listItem->viewModelInstance(); // TODO: @hernan added this to make sure data binds are procesed in the // current frame instead of waiting for the next run. But might not be @@ -1357,8 +1293,6 @@ } clearArtboardOverride(itr->second.get()); } - // Remove bridge data binds before destroying the artboard. - removeBridgeBinds(item); // Destroy state machines BEFORE artboards to ensure FocusListenerGroup // can unregister from FocusData before the artboard (and its FocusData) // is destroyed. Otherwise we get use-after-free in ~FocusListenerGroup. @@ -1366,136 +1300,6 @@ m_artboardInstancesMap.erase(item); } -/// Returns the propertyValuePropertyKey for a ViewModelInstanceValue based -/// on its core type, or Core::invalidPropertyKey if unsupported. -static uint16_t propertyValueKeyForType(uint16_t coreType) -{ - switch (coreType) - { - case ViewModelInstanceNumberBase::typeKey: - return ViewModelInstanceNumberBase::propertyValuePropertyKey; - case ViewModelInstanceStringBase::typeKey: - return ViewModelInstanceStringBase::propertyValuePropertyKey; - case ViewModelInstanceColorBase::typeKey: - return ViewModelInstanceColorBase::propertyValuePropertyKey; - case ViewModelInstanceBooleanBase::typeKey: - return ViewModelInstanceBooleanBase::propertyValuePropertyKey; - case ViewModelInstanceEnumBase::typeKey: - return ViewModelInstanceEnumBase::propertyValuePropertyKey; - case ViewModelInstanceTriggerBase::typeKey: - return ViewModelInstanceTriggerBase::propertyValuePropertyKey; - case ViewModelInstanceViewModelBase::typeKey: - return ViewModelInstanceViewModelBase::propertyValuePropertyKey; - default: - return Core::invalidPropertyKey; - } -} - -void ArtboardComponentList::createBridgeBinds( - rcp<ViewModelInstanceListItem> listItem, - ViewModelInstance* original, - ViewModelInstance* clone) -{ - if (original == nullptr || clone == nullptr) - { - return; - } - auto* vm = clone->viewModel(); - if (vm == nullptr) - { - return; - } - auto* parentArtboard = artboard(); - if (parentArtboard == nullptr) - { - return; - } - - auto& binds = m_bridgeDataBinds[listItem]; - - for (auto& cloneValueRcp : clone->propertyValues()) - { - auto* cloneValue = cloneValueRcp.get(); - auto* prop = cloneValue->viewModelProperty(); - if (prop == nullptr || (!prop->isInput() && !prop->isOutput())) - { - continue; - } - - // Find the matching property on the original by ViewModelProperty - // pointer (both instances share the same ViewModel definition). - ViewModelInstanceValue* originalValue = nullptr; - for (auto& origRcp : original->propertyValues()) - { - if (origRcp->viewModelProperty() == prop) - { - originalValue = origRcp.get(); - break; - } - } - if (originalValue == nullptr) - { - continue; - } - - auto propKey = propertyValueKeyForType(cloneValue->coreType()); - if (propKey == Core::invalidPropertyKey) - { - continue; - } - - if (prop->isInput()) - { - // Input: original → clone (source to target) - auto bind = std::make_unique<DataBind>(); - bind->source(ref_rcp(originalValue)); - bind->target(cloneValue); - bind->propertyKey(propKey); - bind->flags(static_cast<uint32_t>(DataBindFlags::ToTarget)); - bind->bind(); - parentArtboard->addDataBind(bind.get()); - binds.push_back(std::move(bind)); - } - - if (prop->isOutput()) - { - // Output: clone → original. Uses ToSource direction so the - // bind is in the persisting list and continuously syncs - // changes made by the component's state machine back to - // the user-provided VM instance. - // ToSource semantics: reads from target, writes to source. - auto bind = std::make_unique<DataBind>(); - bind->source(ref_rcp(originalValue)); - bind->target(cloneValue); - bind->propertyKey(propKey); - bind->flags(static_cast<uint32_t>(DataBindFlags::ToSource)); - bind->bind(); - parentArtboard->addDataBind(bind.get()); - binds.push_back(std::move(bind)); - } - } -} - -void ArtboardComponentList::removeBridgeBinds( - const rcp<ViewModelInstanceListItem>& listItem) -{ - auto itr = m_bridgeDataBinds.find(listItem); - if (itr == m_bridgeDataBinds.end()) - { - return; - } - auto* parentArtboard = artboard(); - for (auto& bind : itr->second) - { - bind->unbind(); - if (parentArtboard != nullptr) - { - parentArtboard->removeDataBind(bind.get()); - } - } - m_bridgeDataBinds.erase(itr); -} - void ArtboardComponentList::createArtboardRecorders(const Artboard* artboard) { if (artboard == nullptr)