blob: 8ed3060277bdecd11943c7764a54db1a46762d2c [file] [log] [blame]
#include "rive/component.hpp"
#include "rive/file.hpp"
#include "rive/artboard_component_list.hpp"
#include "rive/constraints/layout_constraint.hpp"
#include "rive/constraints/list_constraint.hpp"
#include "rive/constraints/scrolling/scroll_constraint.hpp"
#include "rive/layout_component.hpp"
#include "rive/viewmodel/viewmodel_instance_symbol_list_index.hpp"
#include "rive/world_transform_component.hpp"
#include "rive/layout/layout_data.hpp"
using namespace rive;
ArtboardComponentList::ArtboardComponentList() {}
ArtboardComponentList::~ArtboardComponentList() { clear(); }
void ArtboardComponentList::clear()
{
for (auto& artboard : m_artboardInstancesMap)
{
artboard.second.reset();
}
for (auto& sm : m_stateMachinesMap)
{
sm.second.reset();
}
m_artboardInstancesMap.clear();
m_stateMachinesMap.clear();
m_listItems.clear();
m_artboardsMap.clear();
m_resourcePool.clear();
m_stateMachinesPool.clear();
m_artboardOverridesMap.clear();
}
rcp<ViewModelInstanceListItem> ArtboardComponentList::listItem(int index)
{
if (index < m_listItems.size())
{
return m_listItems[index];
}
return nullptr;
}
ArtboardInstance* ArtboardComponentList::artboardInstance(int index)
{
if (index < m_listItems.size())
{
auto item = listItem(index);
auto itr = m_artboardInstancesMap.find(item);
if (itr != m_artboardInstancesMap.end())
{
return m_artboardInstancesMap[item].get();
}
}
return nullptr;
}
StateMachineInstance* ArtboardComponentList::stateMachineInstance(int index)
{
if (index < m_listItems.size())
{
auto item = listItem(index);
auto itr = m_stateMachinesMap.find(item);
if (itr != m_stateMachinesMap.end())
{
return m_stateMachinesMap[item].get();
}
}
return nullptr;
}
#ifdef WITH_RIVE_LAYOUT
void* ArtboardComponentList::layoutNode(int index)
{
auto artboard = artboardInstance(index);
if (artboard != nullptr)
{
return static_cast<void*>(&artboard->takeLayoutData()->node);
}
return nullptr;
}
#endif
void ArtboardComponentList::markLayoutNodeDirty(
bool shouldForceUpdateLayoutBounds)
{
bool parentIsRow = mainAxisIsRow();
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
artboard->parentIsRow(parentIsRow);
}
}
}
void ArtboardComponentList::updateLayoutBounds(bool animate)
{
#ifdef WITH_RIVE_LAYOUT
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
artboard->updateLayoutBounds(animate);
auto bounds = artboard->layoutBounds();
setItemSize(Vec2D(bounds.width(), bounds.height()), i);
}
}
#endif
computeLayoutBounds();
}
bool ArtboardComponentList::syncStyleChanges()
{
bool changed = false;
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
bool artboardChanged = artboard->syncStyleChanges();
if (artboardChanged)
{
changed = true;
}
}
}
return changed;
}
Artboard* ArtboardComponentList::findArtboard(
const rcp<ViewModelInstanceListItem>& listItem) const
{
auto viewModelInstance = listItem->viewModelInstance();
if (viewModelInstance == nullptr)
{
return nullptr;
}
auto artboard = m_artboardsMap.find(viewModelInstance->viewModelId());
if (artboard != m_artboardsMap.end())
{
return artboard->second;
}
auto artboards = m_file->artboards();
for (auto& artboard : artboards)
{
if (artboard->viewModelId() == viewModelInstance->viewModelId())
{
m_artboardsMap[viewModelInstance->viewModelId()] = artboard;
return artboard;
}
}
return nullptr;
}
void ArtboardComponentList::disposeListItem(
const rcp<ViewModelInstanceListItem>& listItem)
{
removeArtboard(listItem);
}
std::unique_ptr<ArtboardInstance> ArtboardComponentList::createArtboard(
Component* target,
rcp<ViewModelInstanceListItem> listItem) const
{
auto artboard = findArtboard(listItem);
if (artboard != nullptr)
{
auto inst = artboard->instance();
return inst;
}
return nullptr;
}
std::unique_ptr<StateMachineInstance> ArtboardComponentList::
createStateMachineInstance(Component* target, ArtboardInstance* artboard)
{
if (artboard != nullptr)
{
auto stateMachineInstance = artboard->stateMachineAt(0);
linkStateMachineToArtboard(stateMachineInstance.get(), artboard);
return stateMachineInstance;
}
return nullptr;
}
void ArtboardComponentList::linkStateMachineToArtboard(
StateMachineInstance* stateMachineInstance,
ArtboardInstance* artboard)
{
if (artboard != nullptr && stateMachineInstance != nullptr)
{
auto dataContext = artboard->dataContext();
stateMachineInstance->dataContext(dataContext);
// 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
// necessary. Needs more testing.
stateMachineInstance->updateDataBinds(false);
}
}
bool ArtboardComponentList ::listsAreEqual(
std::vector<rcp<ViewModelInstanceListItem>>* list,
std::vector<rcp<ViewModelInstanceListItem>>* compared)
{
if (!list || !compared)
{
return false;
}
if (list->size() != compared->size())
{
return false;
}
size_t index = 0;
for (auto& item : *list)
{
if (item != (*compared)[index])
{
return false;
}
++index;
}
return true;
}
void ArtboardComponentList::updateList(
std::vector<rcp<ViewModelInstanceListItem>>* list)
{
if (listsAreEqual(&m_listItems, list))
{
return;
}
m_oldItems.clear();
m_oldItems.assign(m_listItems.begin(), m_listItems.end());
m_listItems.clear();
m_listItems.assign(list->begin(), list->end());
m_artboardSizes.clear();
auto p = layoutParent();
if (p != nullptr)
{
#ifdef WITH_RIVE_LAYOUT
p->clearLayoutChildren();
#endif
}
// We need to dispose old items after the layout children of the parent have
// updated to ensure no bad YGNodes are being hosted from the old data
// during clearLayoutChildren.
for (auto item : m_oldItems)
{
auto it = std::find(m_listItems.begin(), m_listItems.end(), item);
if (it == m_listItems.end())
{
disposeListItem(item);
}
}
uint32_t index = 0;
for (auto& item : m_listItems)
{
auto viewModelInstance = item->viewModelInstance();
if (viewModelInstance != nullptr)
{
auto symbol = viewModelInstance->symbol(
ViewModelInstanceSymbolListIndexBase::typeKey);
if (symbol != nullptr)
{
symbol->as<ViewModelInstanceSymbolListIndex>()->propertyValue(
index);
}
}
auto artboard = findArtboard(item);
if (artboard != nullptr)
{
m_artboardSizes.push_back(
Vec2D(artboard->width(), artboard->height()));
}
auto itr = m_artboardInstancesMap.find(item);
if (!virtualizationEnabled() && itr == m_artboardInstancesMap.end())
{
createArtboardAt(index);
}
index++;
}
computeLayoutBounds();
syncLayoutChildren();
markLayoutNodeDirty();
markWorldTransformDirty();
addDirt(ComponentDirt::Components);
}
void ArtboardComponentList::syncLayoutChildren()
{
auto p = layoutParent();
if (p != nullptr)
{
#ifdef WITH_RIVE_LAYOUT
p->syncLayoutChildren();
#endif
}
}
bool ArtboardComponentList::advanceComponent(float elapsedSeconds,
AdvanceFlags flags)
{
if (artboardCount() == 0 || isCollapsed())
{
return false;
}
bool keepGoing = false;
bool advanceNested =
(flags & AdvanceFlags::AdvanceNested) == AdvanceFlags::AdvanceNested;
bool newFrame = (flags & AdvanceFlags::NewFrame) == AdvanceFlags::NewFrame;
auto advancingFlags = flags & ~AdvanceFlags::IsRoot;
for (int i = 0; i < artboardCount(); i++)
{
if (advanceNested)
{
auto stateMachine = stateMachineInstance(i);
if (stateMachine != nullptr)
{
// If it is not a new frame, we
// first validate whether their state has changed. Then and only
// then we advance the state machine. This avoids triggering
// dirt from advances that make intermediate value changes but
// finally settle in the same value
if (!newFrame)
{
if (stateMachine->tryChangeState())
{
if (stateMachine->advance(elapsedSeconds, newFrame))
{
keepGoing = true;
}
}
}
else
{
if (stateMachine->advance(elapsedSeconds, newFrame))
{
keepGoing = true;
}
}
}
}
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
if (artboard->advanceInternal(elapsedSeconds, advancingFlags))
{
keepGoing = true;
}
if (artboard->hasDirt(ComponentDirt::Components))
{
// The animation(s) caused the artboard to need an update.
addDirt(ComponentDirt::Components);
}
}
}
return keepGoing;
}
void ArtboardComponentList::reset()
{
for (auto& item : m_listItems)
{
if (m_shouldResetInstances)
{
auto viewModelInstance = item->viewModelInstance();
if (viewModelInstance != nullptr)
{
viewModelInstance->advanced();
}
}
auto itr = m_artboardInstancesMap.find(item);
if (itr != m_artboardInstancesMap.end())
{
m_artboardInstancesMap[item]->reset();
}
}
}
AABB ArtboardComponentList::layoutBounds()
{
return AABB(0, 0, m_layoutSize.x, m_layoutSize.y);
}
AABB ArtboardComponentList::layoutBoundsForNode(int index)
{
if (virtualizationEnabled())
{
auto realIndex = std::fmod(index, m_listItems.size());
auto gap = this->gap();
float runningSize = 0;
bool isHorizontal = mainAxisIsRow();
for (int i = 0; i < realIndex; i++)
{
auto size = m_artboardSizes[i];
if (isHorizontal)
{
runningSize += size.x + gap;
}
else
{
runningSize += size.y + gap;
}
}
auto itemSize = m_artboardSizes[realIndex];
double left = isHorizontal ? runningSize : 0;
double top = isHorizontal ? 0 : runningSize;
return AABB(left, top, left + itemSize.x, top + itemSize.y);
}
else
{
if (index >= 0 && index < numLayoutNodes())
{
return artboardInstance(index)->layoutBounds();
}
}
return AABB();
}
void ArtboardComponentList::markHostingLayoutDirty(
ArtboardInstance* artboardInstance)
{
// TODO: Should optimize this
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = this->artboardInstance(i);
if (artboard != nullptr && artboard == artboardInstance)
{
this->artboard()->markLayoutDirty(artboardInstance);
break;
}
}
markWorldTransformDirty();
}
bool ArtboardComponentList::willDraw()
{
return Super::willDraw() && m_listItems.size() > 0;
}
void ArtboardComponentList::draw(Renderer* renderer)
{
if (m_needsSaveOperation)
{
renderer->save();
}
if (virtualizationEnabled())
{
renderer->transform(
parent()->as<WorldTransformComponent>()->worldTransform());
if (m_visibleStartIndex != -1 && m_visibleEndIndex != -1)
{
// We need to render in the correct order so we get the correct
// z-index for items in cases where there is overlap
auto startIndex = m_visibleStartIndex % (int)m_listItems.size();
auto endIndex = m_visibleEndIndex % (int)m_listItems.size();
int i = startIndex;
while (true)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
renderer->save();
auto transform = m_artboardTransforms[artboard];
renderer->transform(transform);
artboard->draw(renderer);
renderer->restore();
}
if (i == endIndex)
{
break;
}
i = (i + 1) % m_listItems.size();
}
}
}
else
{
renderer->transform(worldTransform());
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
renderer->save();
auto transform = m_artboardTransforms[artboard];
renderer->transform(transform);
artboard->draw(renderer);
renderer->restore();
}
}
}
if (m_needsSaveOperation)
{
renderer->restore();
}
}
Core* ArtboardComponentList::hitTest(HitInfo*, const Mat2D&) { return nullptr; }
bool ArtboardComponentList::hitTestHost(const Vec2D& position,
bool skipOnUnclipped,
ArtboardInstance* artboard)
{
if (artboard == nullptr)
{
return false;
}
auto bounds = artboardPosition(artboard);
Vec2D offset(bounds.x + position.x, bounds.y + position.y);
auto transform = virtualizationEnabled()
? parent()->as<LayoutComponent>()->worldTransform()
: worldTransform();
return parent()->hitTestPoint(transform * offset, skipOnUnclipped, false);
}
Vec2D ArtboardComponentList::hostTransformPoint(
const Vec2D& vec,
ArtboardInstance* artboardInstance)
{
auto bounds = artboardPosition(artboardInstance);
Vec2D offset(bounds.x + vec.x, bounds.y + vec.y);
auto transform = virtualizationEnabled()
? parent()->as<LayoutComponent>()->worldTransform()
: worldTransform();
auto localVec = transform * offset;
auto ab = artboard();
return ab ? ab->rootTransform(localVec) : localVec;
}
void ArtboardComponentList::update(ComponentDirt value)
{
Super::update(value);
if (artboardCount() == 0)
{
return;
}
if (hasDirt(value, ComponentDirt::RenderOpacity))
{
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
artboard->opacity(renderOpacity());
}
}
}
if (hasDirt(value, ComponentDirt::Components))
{
for (int i = 0; i < artboardCount(); i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
artboard->updatePass(false);
}
}
}
}
void ArtboardComponentList::updateWorldTransform()
{
updateArtboardsWorldTransform();
Super::updateWorldTransform();
}
void ArtboardComponentList::updateArtboardsWorldTransform()
{
auto count = m_listItems.size();
if (count == 0)
{
return;
}
// We only update non layout transforms here
if (!virtualizationEnabled())
{
auto useLayout = layoutParent() != nullptr;
for (int i = 0; i < count; i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
auto bounds = useLayout ? artboard->layoutBounds()
: artboard->worldBounds();
m_artboardTransforms[artboard] =
Mat2D::fromTranslate(bounds.left(), bounds.top());
}
}
}
}
void ArtboardComponentList::updateConstraints()
{
if (m_layoutConstraints.size() > 0)
{
for (auto parentConstraint : m_layoutConstraints)
{
parentConstraint->constrainChild(this);
}
}
if (m_listConstraints.size() > 0 && !virtualizationEnabled())
{
for (auto listConstraint : m_listConstraints)
{
listConstraint->constrainList(this);
}
}
for (auto constraint : constraints())
{
auto listConstraint = ListConstraint::from(constraint);
if (listConstraint != nullptr)
{
continue;
}
constraint->constrain(this);
}
}
void ArtboardComponentList::internalDataContext(DataContext* value)
{
// Reconcile the existing data contexts with the new parent
for (auto& artboard : m_artboardInstancesMap)
{
auto dataContext = artboard.second->dataContext();
if (dataContext != nullptr)
{
dataContext->parent(value);
artboard.second->internalDataContext(dataContext);
}
}
for (auto& sm : m_stateMachinesMap)
{
auto dataContext = sm.second->dataContext();
if (dataContext != nullptr)
{
dataContext->parent(value);
sm.second->internalDataContext(dataContext);
}
}
}
void ArtboardComponentList::bindViewModelInstance(
rcp<ViewModelInstance> viewModelInstance,
DataContext* parent)
{
// At the time this is called, artboards will not yet have been instanced
// so its essentially a no-op and the call to bindViewModelInstance on
// each artboard is made at the time of artboard instancing
}
void ArtboardComponentList::clearDataContext() {}
void ArtboardComponentList::unbind() { clear(); }
void ArtboardComponentList::updateDataBinds()
{
for (int i = 0; i < artboardCount(); i++)
{
auto stateMachine = stateMachineInstance(i);
if (stateMachine != nullptr)
{
stateMachine->updateDataBinds(false);
}
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
artboard->updateDataBinds();
}
}
}
Vec2D ArtboardComponentList::artboardPosition(ArtboardInstance* artboard)
{
auto mat = m_artboardTransforms[artboard];
return Vec2D(mat[4], mat[5]);
}
bool ArtboardComponentList::worldToLocal(Vec2D world, Vec2D* local, int index)
{
assert(local != nullptr);
auto artboard = artboardInstance(index);
if (artboard == nullptr)
{
return false;
}
Vec2D offset = artboardPosition(artboard);
auto transform = virtualizationEnabled()
? parent()->as<LayoutComponent>()->worldTransform()
: worldTransform();
auto artboardTransform =
transform * Mat2D::fromTranslate(offset.x, offset.y);
Mat2D toMountedArtboard;
if (!artboardTransform.invert(&toMountedArtboard))
{
return false;
}
*local = toMountedArtboard * world;
return true;
}
void ArtboardComponentList::file(File* value) { m_file = value; }
File* ArtboardComponentList::file() const { return m_file; }
Core* ArtboardComponentList::clone() const
{
auto clone =
static_cast<ArtboardComponentList*>(ArtboardComponentListBase::clone());
clone->file(file());
return clone;
}
void ArtboardComponentList::createArtboardAt(int index)
{
auto item = listItem(index);
if (item != nullptr)
{
auto artboardCopy = createArtboard(this, item);
if (artboardCopy != nullptr)
{
attachArtboardOverride(artboardCopy.get(), item);
addArtboardAt(std::move(artboardCopy), index);
}
}
}
void ArtboardComponentList::addArtboardAt(
std::unique_ptr<ArtboardInstance> artboard,
int index)
{
auto item = listItem(index);
if (item != nullptr)
{
auto artboardInstance = artboard.get();
m_artboardInstancesMap[item] = std::move(artboard);
bindArtboard(artboardInstance, item);
if (artboardInstance != nullptr)
{
artboardInstance->host(this);
artboardInstance->frameOrigin(false);
artboardInstance->parentIsRow(mainAxisIsRow());
}
syncLayoutChildren();
auto artboard = findArtboard(item);
if (artboard != nullptr)
{
auto& smPool = m_stateMachinesPool[artboard];
if (!smPool.empty())
{
auto sm = smPool.back().get();
sm->resetState();
applyRecorders(sm, artboard);
m_stateMachinesMap[item] = std::move(smPool.back());
linkStateMachineToArtboard(sm, artboardInstance);
smPool.pop_back();
return;
}
}
auto stateMachineCopy =
createStateMachineInstance(this, artboardInstance);
m_stateMachinesMap[item] = std::move(stateMachineCopy);
}
}
void ArtboardComponentList::bindArtboard(
ArtboardInstance* artboardInstance,
rcp<ViewModelInstanceListItem> listItem)
{
if (artboardInstance != nullptr)
{
auto mainArtboard = this->artboard();
auto dataContext = mainArtboard->dataContext();
// 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
// necessary. Needs more testing.
artboardInstance->bindViewModelInstance(listItem->viewModelInstance(),
dataContext);
artboardInstance->updateDataBinds();
}
}
void ArtboardComponentList::removeArtboardAt(int index)
{
auto item = listItem(index);
removeArtboard(item);
}
void ArtboardComponentList::removeArtboard(rcp<ViewModelInstanceListItem> item)
{
auto itr = m_artboardInstancesMap.find(item);
if (itr != m_artboardInstancesMap.end())
{
clearArtboardOverride(itr->second.get());
}
m_artboardInstancesMap.erase(item);
m_stateMachinesMap.erase(item);
}
void ArtboardComponentList::createArtboardRecorders(const Artboard* artboard)
{
if (artboard == nullptr)
{
return;
}
auto recorderIt = m_propertyRecordersMap.find(artboard);
if (recorderIt == m_propertyRecordersMap.end())
{
auto propertyRecorder = rivestd::make_unique<PropertyRecorder>();
propertyRecorder->recordArtboard(artboard);
m_propertyRecordersMap[artboard] = std::move(propertyRecorder);
for (auto& nestedArtboard : artboard->nestedArtboards())
{
auto sourceArtboard = nestedArtboard->sourceArtboard();
createArtboardRecorders(sourceArtboard);
}
}
}
void ArtboardComponentList::applyRecorders(Artboard* artboard,
const Artboard* sourceArtboard)
{
auto sourcedArtboardIt = m_propertyRecordersMap.find(sourceArtboard);
if (sourcedArtboardIt != m_propertyRecordersMap.end())
{
auto propertyRecorder = sourcedArtboardIt->second.get();
propertyRecorder->apply(artboard);
}
for (auto& nestedArtboard : artboard->nestedArtboards())
{
applyRecorders(nestedArtboard->sourceArtboard(),
nestedArtboard->sourceArtboard()->artboardSource());
}
}
void ArtboardComponentList::applyRecorders(
StateMachineInstance* stateMachineInstance,
const Artboard* sourceArtboard)
{
auto propertyRecorder = m_propertyRecordersMap[sourceArtboard].get();
propertyRecorder->apply(stateMachineInstance);
}
void ArtboardComponentList::addVirtualizable(int index)
{
auto listItem = this->listItem(index);
if (listItem != nullptr)
{
auto artboard = findArtboard(listItem);
if (artboard != nullptr)
{
createArtboardRecorders(artboard);
auto& pool = m_resourcePool[artboard];
if (pool.empty())
{
createArtboardAt(index);
}
else
{
auto pooledArtboard = pool.back().get();
applyRecorders(pooledArtboard, artboard);
addArtboardAt(std::move(pool.back()), index);
pool.pop_back();
}
// Add components dirt so we process layout updates in the same
// frame that a mounted artboard is added
addDirt(ComponentDirt::Components);
auto p = layoutParent();
if (p != nullptr)
{
p->markLayoutStyleDirty();
}
}
}
}
void ArtboardComponentList::removeVirtualizable(int index)
{
auto listItem = this->listItem(index);
if (listItem != nullptr)
{
auto artboard = findArtboard(listItem);
auto artboardInstance = std::move(m_artboardInstancesMap[listItem]);
if (artboard != nullptr && artboardInstance != nullptr)
{
auto& pool = m_resourcePool[artboard];
pool.push_back(std::move(artboardInstance));
}
auto smInstanceIterator = m_stateMachinesMap.find(listItem);
if (smInstanceIterator != m_stateMachinesMap.end())
{
auto& smPool = m_stateMachinesPool[artboard];
smPool.push_back(std::move(smInstanceIterator->second));
}
}
removeArtboardAt(index);
}
void ArtboardComponentList::setVirtualizablePosition(int index, Vec2D position)
{
auto artboard = this->artboardInstance(index);
if (artboard != nullptr)
{
m_artboardTransforms[artboard] =
Mat2D::fromTranslate(position.x, position.y);
}
}
bool ArtboardComponentList::virtualizationEnabled()
{
auto virtualizer = scrollConstraint();
return virtualizer != nullptr && virtualizer->virtualize();
}
ScrollConstraint* ArtboardComponentList::scrollConstraint()
{
for (auto parentConstraint : m_layoutConstraints)
{
if (parentConstraint->constraint()->is<ScrollConstraint>())
{
return parentConstraint->constraint()->as<ScrollConstraint>();
}
}
return nullptr;
}
void ArtboardComponentList::computeLayoutBounds()
{
if (virtualizationEnabled())
{
auto gap = this->gap();
auto runningWidth = 0.0f;
auto runningHeight = 0.0f;
bool isHorz = mainAxisIsRow();
for (int i = 0; i < m_artboardSizes.size(); i++)
{
auto size = m_artboardSizes[i];
auto realGap = i == m_artboardSizes.size() - 1 ? 0 : gap;
if (isHorz)
{
runningWidth += size.x + realGap;
runningHeight = std::max(runningHeight, size.y);
}
else
{
runningWidth = std::max(runningWidth, size.x);
runningHeight += size.y + realGap;
}
}
m_layoutSize = Vec2D(runningWidth, runningHeight);
auto scroll = scrollConstraint();
if (scroll != nullptr)
{
scroll->constrainVirtualized(true);
}
}
}
Vec2D ArtboardComponentList::size() { return m_layoutSize; }
Vec2D ArtboardComponentList::itemSize(int index)
{
return index < m_artboardSizes.size() ? m_artboardSizes[index] : Vec2D();
}
void ArtboardComponentList::setItemSize(Vec2D size, int index)
{
if (index < m_artboardSizes.size())
{
m_artboardSizes[index] = size;
}
}
float ArtboardComponentList::gap()
{
auto p = layoutParent();
if (p != nullptr)
{
return mainAxisIsRow() ? p->gapHorizontal() : p->gapVertical();
}
return 0.0f;
}
void ArtboardComponentList::attachArtboardOverride(
ArtboardInstance* instance,
rcp<ViewModelInstanceListItem> listItem)
{
auto viewModelInstance = listItem->viewModelInstance();
if (viewModelInstance == nullptr)
{
return;
}
auto artboards = m_file->artboards();
int artboardIndex = -1;
for (auto& artboard : artboards)
{
artboardIndex++;
if (artboard->viewModelId() == viewModelInstance->viewModelId())
{
break;
}
}
if (artboardIndex < 0 && artboardIndex >= artboards.size())
{
return;
}
ArtboardComponentListOverride* artboardOverride = nullptr;
for (auto& child : children())
{
if (child->is<ArtboardComponentListOverride>())
{
if (child->as<ArtboardComponentListOverride>()->artboardId() == -1)
{
artboardOverride = child->as<ArtboardComponentListOverride>();
}
else if (child->as<ArtboardComponentListOverride>()->artboardId() ==
artboardIndex)
{
artboardOverride = child->as<ArtboardComponentListOverride>();
break;
}
}
}
if (artboardOverride != nullptr)
{
artboardOverride->addArtboard(instance);
}
}
void ArtboardComponentList::clearArtboardOverride(
ArtboardInstance* artboardInstance)
{
for (auto& child : children())
{
if (child->is<ArtboardComponentListOverride>())
{
// Passing the artboard to all overrides in case in the future we
// support stacking overrides on top of each other.
// Currently all except one will be a no-op.
child->as<ArtboardComponentListOverride>()->removeArtboard(
artboardInstance);
}
}
}
bool ArtboardComponentList::mainAxisIsRow()
{
auto p = layoutParent();
return p != nullptr ? p->mainAxisIsRow() : true;
}
LayoutComponent* ArtboardComponentList::layoutParent()
{
if (parent() != nullptr && parent()->is<LayoutComponent>())
{
return parent()->as<LayoutComponent>();
}
return nullptr;
}
const Mat2D& ArtboardComponentList::listTransform() { return worldTransform(); }
void ArtboardComponentList::listItemTransforms(std::vector<Mat2D*>& transforms)
{
auto count = m_listItems.size();
for (int i = 0; i < count; i++)
{
auto artboard = artboardInstance(i);
if (artboard != nullptr)
{
transforms.push_back(&m_artboardTransforms[artboard]);
}
}
}