add support to data bind solos by index and name (#10337) 64f828c9a2

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index ef0d699..76045c1 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-9af6af0361de2258ff05a708cacc8e58899e0d4a
+64f828c9a278586f61b7636da99d68404c906176
diff --git a/include/rive/solo.hpp b/include/rive/solo.hpp
index 8458d76..baf4b86 100644
--- a/include/rive/solo.hpp
+++ b/include/rive/solo.hpp
@@ -9,6 +9,10 @@
     void activeComponentIdChanged() override;
     StatusCode onAddedClean(CoreContext* context) override;
     bool collapse(bool value) override;
+    void updateByIndex(size_t index);
+    void updateByName(std::string& name);
+    int getActiveChildIndex();
+    std::string getActiveChildName();
 
 private:
     void propagateCollapse(bool collapse);
diff --git a/src/data_bind/context/context_value_number.cpp b/src/data_bind/context/context_value_number.cpp
index 5a4fd7e..01d501d 100644
--- a/src/data_bind/context/context_value_number.cpp
+++ b/src/data_bind/context/context_value_number.cpp
@@ -22,8 +22,16 @@
             CoreRegistry::setDouble(target, propertyKey, value);
             break;
         case CoreUintType::id:
-            int rounded = value < 0 ? 0 : std::round(value);
-            CoreRegistry::setUint(target, propertyKey, rounded);
+
+            if (target && target->is<Solo>())
+            {
+                target->as<Solo>()->updateByIndex((size_t)std::round(value));
+            }
+            else
+            {
+                int rounded = value < 0 ? 0 : std::round(value);
+                CoreRegistry::setUint(target, propertyKey, rounded);
+            }
             break;
     }
 }
@@ -41,7 +49,14 @@
         break;
         case CoreUintType::id:
         {
-            value = (float)CoreRegistry::getUint(target, propertyKey);
+            if (target && target->is<Solo>())
+            {
+                value = (float)target->as<Solo>()->getActiveChildIndex();
+            }
+            else
+            {
+                value = (float)CoreRegistry::getUint(target, propertyKey);
+            }
             break;
         }
     }
diff --git a/src/data_bind/context/context_value_string.cpp b/src/data_bind/context/context_value_string.cpp
index e4b8c6c..899676d 100644
--- a/src/data_bind/context/context_value_string.cpp
+++ b/src/data_bind/context/context_value_string.cpp
@@ -16,13 +16,40 @@
     auto value = calculateValue<DataValueString, std::string>(m_dataValue,
                                                               isMainDirection,
                                                               m_dataBind);
-    CoreRegistry::setString(target, propertyKey, value);
+    switch (CoreRegistry::propertyFieldId(propertyKey))
+    {
+        case CoreUintType::id:
+        {
+            if (target && target->is<Solo>())
+            {
+                target->as<Solo>()->updateByName(value);
+            }
+            break;
+        }
+        default:
+            CoreRegistry::setString(target, propertyKey, value);
+            break;
+    }
 }
 
 bool DataBindContextValueString::syncTargetValue(Core* target,
                                                  uint32_t propertyKey)
 {
-    auto value = CoreRegistry::getString(target, propertyKey);
+    std::string value = "";
+    switch (CoreRegistry::propertyFieldId(propertyKey))
+    {
+        case CoreUintType::id:
+        {
+            if (target && target->is<Solo>())
+            {
+                value = target->as<Solo>()->getActiveChildName();
+            }
+            break;
+        }
+        default:
+            value = CoreRegistry::getString(target, propertyKey);
+            break;
+    }
 
     if (m_previousValue != value)
     {
diff --git a/src/solo.cpp b/src/solo.cpp
index 4eb0859..82632a8 100644
--- a/src/solo.cpp
+++ b/src/solo.cpp
@@ -51,4 +51,56 @@
 
     propagateCollapse(isCollapsed());
     return StatusCode::Ok;
-}
\ No newline at end of file
+}
+
+void Solo::updateByIndex(size_t index)
+{
+    if (index >= 0 && index < children().size() && artboard())
+    {
+        auto child = children()[index];
+        int globalIndex = artboard()->idOf(child);
+        activeComponentId(globalIndex);
+    }
+}
+
+void Solo::updateByName(std::string& name)
+{
+    for (auto& child : children())
+    {
+        if (child->name() == name)
+        {
+
+            int globalIndex = artboard()->idOf(child);
+            activeComponentId(globalIndex);
+            break;
+        }
+    }
+}
+
+int Solo::getActiveChildIndex()
+{
+    Core* active = artboard()->resolve(activeComponentId());
+    if (active)
+    {
+        int index = 0;
+        for (auto& child : children())
+        {
+            if (child == active)
+            {
+                return index;
+            }
+            index++;
+        }
+    }
+    return -1;
+}
+
+std::string Solo::getActiveChildName()
+{
+    Core* active = artboard()->resolve(activeComponentId());
+    if (active && active->is<Component>())
+    {
+        return active->as<Component>()->name();
+    }
+    return "";
+}
diff --git a/tests/unit_tests/assets/data_bind_solo.riv b/tests/unit_tests/assets/data_bind_solo.riv
new file mode 100644
index 0000000..1367c84
--- /dev/null
+++ b/tests/unit_tests/assets/data_bind_solo.riv
Binary files differ
diff --git a/tests/unit_tests/runtime/data_binding_test.cpp b/tests/unit_tests/runtime/data_binding_test.cpp
index 2109229..11a5935 100644
--- a/tests/unit_tests/runtime/data_binding_test.cpp
+++ b/tests/unit_tests/runtime/data_binding_test.cpp
@@ -1222,4 +1222,76 @@
     }
 
     CHECK(silver.matches("custom_property_trigger_bind"));
-}
\ No newline at end of file
+}
+
+TEST_CASE("Data binding solos", "[data binding]")
+{
+
+    rive::SerializingFactory silver;
+    auto file = ReadRiveFile("assets/data_bind_solo.riv", &silver);
+
+    auto artboard = file->artboardNamed("values-to-solos");
+
+    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.0f);
+    stateMachine->advanceAndApply(0.016f);
+
+    auto renderer = silver.makeRenderer();
+    artboard->draw(renderer.get());
+
+    int frames = (int)(1.0f / 0.016f);
+    for (int i = 0; i < frames; i++)
+    {
+        silver.addFrame();
+        stateMachine->advanceAndApply(0.016f);
+        artboard->draw(renderer.get());
+    }
+
+    CHECK(silver.matches("data_bind_solo-values-to-solos"));
+}
+
+TEST_CASE("Data binding solos - target to source", "[data binding]")
+{
+
+    rive::SerializingFactory silver;
+    auto file = ReadRiveFile("assets/data_bind_solo.riv", &silver);
+
+    auto artboard = file->artboardNamed("solos-to-values");
+
+    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.0f);
+    stateMachine->advanceAndApply(0.016f);
+
+    auto renderer = silver.makeRenderer();
+    artboard->draw(renderer.get());
+
+    int frames = (int)(1.0f / 0.016f);
+    for (int i = 0; i < frames; i++)
+    {
+        silver.addFrame();
+        stateMachine->advanceAndApply(0.016f);
+        artboard->draw(renderer.get());
+    }
+
+    CHECK(silver.matches("data_bind_solo-solos-to-values"));
+}
diff --git a/tests/unit_tests/silvers/data_bind_solo-solos-to-values.sriv b/tests/unit_tests/silvers/data_bind_solo-solos-to-values.sriv
new file mode 100644
index 0000000..af621a6
--- /dev/null
+++ b/tests/unit_tests/silvers/data_bind_solo-solos-to-values.sriv
Binary files differ
diff --git a/tests/unit_tests/silvers/data_bind_solo-values-to-solos.sriv b/tests/unit_tests/silvers/data_bind_solo-values-to-solos.sriv
new file mode 100644
index 0000000..3880c22
--- /dev/null
+++ b/tests/unit_tests/silvers/data_bind_solo-values-to-solos.sriv
Binary files differ