feature: add support for removing all elements from a view model list (#11872) 354acb8533
feature: add support for removing al elements from a view model list

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index fb8495d..3d16540 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-501b7f488c5af1947ae46f5998dba79d829ca7ef
+354acb85334c9378780c977880cd10e164aa5dec
diff --git a/include/rive/lua/rive_lua_libs.hpp b/include/rive/lua/rive_lua_libs.hpp
index 658dffe..cdd0287 100644
--- a/include/rive/lua/rive_lua_libs.hpp
+++ b/include/rive/lua/rive_lua_libs.hpp
@@ -174,6 +174,7 @@
     shift,
     pop,
     swap,
+    clear,
 
     // Artboards
     draw,
diff --git a/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp b/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp
index 7fb82ea..8f93859 100644
--- a/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp
+++ b/include/rive/viewmodel/runtime/viewmodel_instance_list_runtime.hpp
@@ -25,6 +25,7 @@
     void removeInstance(ViewModelInstanceRuntime*);
     void removeInstanceAt(int);
     void swap(uint32_t, uint32_t);
+    void removeAllInstances();
     size_t size() const;
     const DataType dataType() override { return DataType::list; }
 
diff --git a/include/rive/viewmodel/viewmodel_instance_list.hpp b/include/rive/viewmodel/viewmodel_instance_list.hpp
index 2337866..e73ff7c 100644
--- a/include/rive/viewmodel/viewmodel_instance_list.hpp
+++ b/include/rive/viewmodel/viewmodel_instance_list.hpp
@@ -23,6 +23,7 @@
     void swap(uint32_t index1, uint32_t index2);
     rcp<ViewModelInstanceListItem> pop();
     rcp<ViewModelInstanceListItem> shift();
+    void removeAllItems();
     Core* clone() const override;
     void advanced() override;
     void parentViewModelInstance(ViewModelInstance* parent)
diff --git a/src/lua/lua_properties.cpp b/src/lua/lua_properties.cpp
index 01bf95b..e913067 100644
--- a/src/lua/lua_properties.cpp
+++ b/src/lua/lua_properties.cpp
@@ -552,6 +552,12 @@
             }
             return 0;
         }
+        case (int)LuaAtoms::clear:
+        {
+            auto list = property->instanceValue()->as<ViewModelInstanceList>();
+            list->removeAllItems();
+            return 0;
+        }
 
         case (int)LuaAtoms::insert:
         {
diff --git a/src/lua/rive_lua_libs.cpp b/src/lua/rive_lua_libs.cpp
index 9011913..c873c09 100644
--- a/src/lua/rive_lua_libs.cpp
+++ b/src/lua/rive_lua_libs.cpp
@@ -109,6 +109,7 @@
     {"pop", (int16_t)LuaAtoms::pop},
     {"swap", (int16_t)LuaAtoms::swap},
     {"shift", (int16_t)LuaAtoms::shift},
+    {"clear", (int16_t)LuaAtoms::clear},
     {"draw", (int16_t)LuaAtoms::draw},
     {"advance", (int16_t)LuaAtoms::advance},
     {"frameOrigin", (int16_t)LuaAtoms::frameOrigin},
diff --git a/src/viewmodel/runtime/viewmodel_instance_list_runtime.cpp b/src/viewmodel/runtime/viewmodel_instance_list_runtime.cpp
index aa63f0c..dd55140 100644
--- a/src/viewmodel/runtime/viewmodel_instance_list_runtime.cpp
+++ b/src/viewmodel/runtime/viewmodel_instance_list_runtime.cpp
@@ -105,6 +105,12 @@
     instanceList->swap(a, b);
 }
 
+void ViewModelInstanceListRuntime::removeAllInstances()
+{
+    m_viewModelInstanceValue->as<ViewModelInstanceList>()->removeAllItems();
+    m_itemsMap.clear();
+}
+
 size_t ViewModelInstanceListRuntime::size() const
 {
     auto listItems =
diff --git a/src/viewmodel/viewmodel_instance_list.cpp b/src/viewmodel/viewmodel_instance_list.cpp
index 1edd99d..b9bc8bc 100644
--- a/src/viewmodel/viewmodel_instance_list.cpp
+++ b/src/viewmodel/viewmodel_instance_list.cpp
@@ -126,6 +126,23 @@
     propertyValueChanged();
 }
 
+void ViewModelInstanceList::removeAllItems()
+{
+    if (m_ListItems.size() > 0)
+    {
+        for (auto& listItem : m_ListItems)
+        {
+            if (listItem->viewModelInstance())
+            {
+                listItem->viewModelInstance()->removeParent(
+                    parentViewModelInstance());
+            }
+        }
+        m_ListItems.clear();
+        propertyValueChanged();
+    }
+}
+
 rcp<ViewModelInstanceListItem> ViewModelInstanceList::item(uint32_t index)
 {
     if (index < m_ListItems.size())
diff --git a/tests/unit_tests/assets/clear_viewmodel_list.riv b/tests/unit_tests/assets/clear_viewmodel_list.riv
new file mode 100644
index 0000000..ac1d0fb
--- /dev/null
+++ b/tests/unit_tests/assets/clear_viewmodel_list.riv
Binary files differ
diff --git a/tests/unit_tests/runtime/data_bind_lists.cpp b/tests/unit_tests/runtime/data_bind_lists_test.cpp
similarity index 85%
rename from tests/unit_tests/runtime/data_bind_lists.cpp
rename to tests/unit_tests/runtime/data_bind_lists_test.cpp
index b3cf9c5..0781729 100644
--- a/tests/unit_tests/runtime/data_bind_lists.cpp
+++ b/tests/unit_tests/runtime/data_bind_lists_test.cpp
@@ -138,3 +138,29 @@
 
     CHECK(silver.matches("list_items"));
 }
+
+TEST_CASE("Clear view model list", "[silver]")
+{
+    SerializingFactory silver;
+    auto file = ReadRiveFile("assets/clear_viewmodel_list.riv", &silver);
+
+    auto artboard = file->artboardDefault();
+    REQUIRE(artboard != nullptr);
+
+    silver.frameSize(artboard->width(), artboard->height());
+
+    auto stateMachine = artboard->stateMachineAt(0);
+    stateMachine->advanceAndApply(0.016f);
+
+    auto vmi = file->createViewModelInstance(artboard.get());
+
+    stateMachine->bindViewModelInstance(vmi);
+    auto renderer = silver.makeRenderer();
+    stateMachine->advanceAndApply(1.2f);
+    artboard->draw(renderer.get());
+    silver.addFrame();
+    stateMachine->advanceAndApply(1.2f);
+    artboard->draw(renderer.get());
+
+    CHECK(silver.matches("clear_viewmodel_list"));
+}
diff --git a/tests/unit_tests/silvers/clear_viewmodel_list.sriv b/tests/unit_tests/silvers/clear_viewmodel_list.sriv
new file mode 100644
index 0000000..c3b6b37
--- /dev/null
+++ b/tests/unit_tests/silvers/clear_viewmodel_list.sriv
Binary files differ