| #include <sstream> | |
| #include <iomanip> | |
| #include <array> | |
| #include "rive/viewmodel/viewmodel_instance_list.hpp" | |
| #include "rive/viewmodel/viewmodel_instance_list_item.hpp" | |
| #include "rive/component_dirt.hpp" | |
| using namespace rive; | |
| ViewModelInstanceList::~ViewModelInstanceList() { detachParent(); } | |
| void ViewModelInstanceList::detachParent() | |
| { | |
| if (m_parentViewModelInstance == nullptr) | |
| { | |
| return; | |
| } | |
| for (auto& item : m_ListItems) | |
| { | |
| if (item->viewModelInstance() != nullptr) | |
| { | |
| item->viewModelInstance()->removeParent(m_parentViewModelInstance); | |
| } | |
| } | |
| m_parentViewModelInstance = nullptr; | |
| } | |
| void ViewModelInstanceList::propertyValueChanged() | |
| { | |
| addDirt(ComponentDirt::Bindings); | |
| #ifdef WITH_RIVE_TOOLS | |
| if (m_changedCallback != nullptr) | |
| { | |
| m_changedCallback(this); | |
| } | |
| #endif | |
| onValueChanged(); | |
| } | |
| void ViewModelInstanceList::addItem(rcp<ViewModelInstanceListItem> item) | |
| { | |
| m_ListItems.push_back(item); | |
| if (item->viewModelInstance()) | |
| { | |
| item->viewModelInstance()->addParent(parentViewModelInstance()); | |
| } | |
| propertyValueChanged(); | |
| } | |
| bool ViewModelInstanceList::addItemAt( | |
| rcp<ViewModelInstanceListItem> item, | |
| int index) | |
| { | |
| if (index >= 0 && index <= m_ListItems.size()) | |
| { | |
| m_ListItems.insert(m_ListItems.begin() + index, item); | |
| if (item->viewModelInstance()) | |
| { | |
| item->viewModelInstance()->addParent(parentViewModelInstance()); | |
| } | |
| propertyValueChanged(); | |
| return true; | |
| } | |
| return false; | |
| } | |
| void ViewModelInstanceList::internalAddItem(rcp<ViewModelInstanceListItem> item) | |
| { | |
| // Copy the supplied owning reference, just as addItem does. | |
| m_ListItems.push_back(item); | |
| if (item->viewModelInstance()) | |
| { | |
| item->viewModelInstance()->addParent(parentViewModelInstance()); | |
| } | |
| } | |
| void ViewModelInstanceList::removeItem(int index) | |
| { | |
| // TODO: @hernan decide if we want to return a boolean | |
| if (index >= 0 && index < m_ListItems.size()) | |
| { | |
| auto listItem = m_ListItems[index]; | |
| if (listItem->viewModelInstance()) | |
| { | |
| listItem->viewModelInstance()->removeParent(parentViewModelInstance()); | |
| } | |
| m_ListItems.erase(m_ListItems.begin() + index); | |
| propertyValueChanged(); | |
| } | |
| } | |
| rcp<ViewModelInstanceListItem> ViewModelInstanceList::pop() | |
| { | |
| if (m_ListItems.size() > 0) | |
| { | |
| auto listItem = m_ListItems.back(); | |
| removeItem((int)m_ListItems.size() - 1); | |
| return listItem; | |
| } | |
| return nullptr; | |
| } | |
| rcp<ViewModelInstanceListItem> ViewModelInstanceList::shift() | |
| { | |
| if (m_ListItems.size() > 0) | |
| { | |
| auto listItem = m_ListItems.front(); | |
| removeItem(0); | |
| return listItem; | |
| } | |
| return nullptr; | |
| } | |
| void ViewModelInstanceList::removeItem(rcp<ViewModelInstanceListItem> listItem) | |
| { | |
| auto noSpaceEnd = std::remove( | |
| m_ListItems.begin(), | |
| m_ListItems.end(), | |
| listItem); | |
| m_ListItems.erase(noSpaceEnd, m_ListItems.end()); | |
| if (listItem->viewModelInstance()) | |
| { | |
| listItem->viewModelInstance()->removeParent(parentViewModelInstance()); | |
| } | |
| 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(); | |
| } | |
| } | |
| void ViewModelInstanceList::removeAllItemsWithViewModelInstance( | |
| ViewModelInstance* viewModelInstance, | |
| std::vector<rcp<ViewModelInstanceListItem>>* removed) | |
| { | |
| if (viewModelInstance == nullptr || m_ListItems.empty()) | |
| { | |
| return; | |
| } | |
| // The items kept slide down over the ones taken out, so the pass erases | |
| // once at the end instead of shifting the tail for every match. | |
| auto kept = m_ListItems.begin(); | |
| for (auto it = m_ListItems.begin(); it != m_ListItems.end(); ++it) | |
| { | |
| if ((*it)->viewModelInstance().get() == viewModelInstance) | |
| { | |
| viewModelInstance->removeParent(parentViewModelInstance()); | |
| if (removed != nullptr) | |
| { | |
| removed->push_back(std::move(*it)); | |
| } | |
| continue; | |
| } | |
| if (kept != it) | |
| { | |
| *kept = std::move(*it); | |
| } | |
| ++kept; | |
| } | |
| if (kept != m_ListItems.end()) | |
| { | |
| m_ListItems.erase(kept, m_ListItems.end()); | |
| propertyValueChanged(); | |
| } | |
| } | |
| rcp<ViewModelInstanceListItem> ViewModelInstanceList::item(uint32_t index) | |
| { | |
| if (index < m_ListItems.size()) | |
| { | |
| return m_ListItems[index]; | |
| } | |
| return nullptr; | |
| } | |
| void ViewModelInstanceList::swap(uint32_t index1, uint32_t index2) | |
| { | |
| if (index1 < m_ListItems.size() && index2 < m_ListItems.size()) | |
| { | |
| std::iter_swap(m_ListItems.begin() + index1, m_ListItems.begin() + index2); | |
| propertyValueChanged(); | |
| } | |
| } | |
| void ViewModelInstanceList::updateList( | |
| std::vector<rcp<ViewModelInstanceListItem>>* list) | |
| { | |
| if (list == nullptr) | |
| { | |
| return; | |
| } | |
| // Detach old children from this host instance before replacing the list. | |
| if (parentViewModelInstance()) | |
| { | |
| for (auto& item : m_ListItems) | |
| { | |
| if (item->viewModelInstance() != nullptr) | |
| { | |
| item->viewModelInstance()->removeParent(parentViewModelInstance()); | |
| } | |
| } | |
| } | |
| m_ListItems.clear(); | |
| m_ListItems.reserve(list->size()); | |
| for (auto& item : *list) | |
| { | |
| m_ListItems.push_back(item); | |
| if (parentViewModelInstance() && item->viewModelInstance() != nullptr) | |
| { | |
| item->viewModelInstance()->addParent(parentViewModelInstance()); | |
| } | |
| } | |
| propertyValueChanged(); | |
| } | |
| Core* ViewModelInstanceList::clone() const | |
| { | |
| auto cloned = new ViewModelInstanceList(); | |
| cloned->copy(*this); | |
| for (auto property : m_ListItems) | |
| { | |
| auto clonedValue = property->clone()->as<ViewModelInstanceListItem>(); | |
| cloned->internalAddItem(rcp<ViewModelInstanceListItem>(clonedValue)); | |
| } | |
| return cloned; | |
| } | |
| #ifdef WITH_RIVE_EDITOR | |
| void ViewModelInstanceList::editorPrepareForDestruction() | |
| { | |
| detachParent(); | |
| m_ListItems.clear(); | |
| ViewModelInstanceValue::editorPrepareForDestruction(); | |
| } | |
| #endif |