blob: 5404981b963e8cd906d5175c62c342faec300ffd [file]
#include "rive/nested_artboard_layout.hpp"
#include "rive/artboard.hpp"
#include "rive/animation/keyframe_interpolator.hpp"
#include "rive/layout/layout_data.hpp"
#include "rive/math/aabb.hpp"
#include "rive/world_transform_component.hpp"
using namespace rive;
Core* NestedArtboardLayout::clone() const
{
NestedArtboardLayout* nestedArtboard =
static_cast<NestedArtboardLayout*>(NestedArtboardLayoutBase::clone());
nestedArtboard->file(file());
if (m_referencedArtboard == nullptr)
{
return nestedArtboard;
}
auto ni = m_referencedArtboard->instance();
nestedArtboard->referencedArtboard(ni.release());
return nestedArtboard;
}
AABB NestedArtboardLayout::layoutBounds()
{
#ifdef WITH_RIVE_LAYOUT
if (artboardInstance() != nullptr)
{
return artboardInstance()->layoutBounds();
}
#endif
return AABB();
}
#ifdef WITH_RIVE_LAYOUT
void* NestedArtboardLayout::layoutNode(int index)
{
if (artboardInstance() == nullptr)
{
return nullptr;
}
return static_cast<void*>(&artboardInstance()->takeLayoutData()->node);
}
#endif
void NestedArtboardLayout::markHostingLayoutDirty(
ArtboardInstance* artboardInstance)
{
if (artboard() != nullptr)
{
artboard()->markLayoutDirty(this->artboardInstance());
artboard()->markLayoutStyleDirty();
}
}
void NestedArtboardLayout::markLayoutNodeDirty(
bool shouldForceUpdateLayoutBounds)
{
updateWidthOverride();
updateHeightOverride();
}
// Where the layout put us, less the mounted artboard's own origin, applied in
// the parent's frame:
//
// parentWorld * translate(slot - origin) * m_Transform
//
// Applied after constraints rather than composed before them. A constraint that
// copies a position (follow path, translation) composes the world transform
// from its target and replaces our translation outright, so a placement folded
// into composeWorldTransform is discarded and the artboard renders off by its
// origin. With no constraint the two orders are the same matrix, so files that
// do not constrain a nested artboard are unaffected.
void NestedArtboardLayout::applyLayoutPlacement()
{
auto artboard = artboardInstance();
if (artboard == nullptr)
{
return;
}
auto base =
Vec2D(artboard->layoutX(), artboard->layoutY()) - artboard->origin();
auto* parentComponent = parent();
if (parentComponent != nullptr && parentComponent->is<Artboard>())
{
base += parentComponent->as<Artboard>()->origin();
}
if (m_ParentTransformComponent != nullptr)
{
// Rotate/scale into the parent's frame; its translation cancels.
const Mat2D& p = m_ParentTransformComponent->worldTransform();
m_WorldTransform[4] += p[0] * base.x + p[2] * base.y;
m_WorldTransform[5] += p[1] * base.x + p[3] * base.y;
}
else
{
m_WorldTransform[4] += base.x;
m_WorldTransform[5] += base.y;
}
}
void NestedArtboardLayout::updateConstraints()
{
if (layoutConstraints().size() > 0)
{
for (auto parentConstraint : layoutConstraints())
{
parentConstraint->constrainChild(this);
}
}
Super::updateConstraints();
applyLayoutPlacement();
}
StatusCode NestedArtboardLayout::onAddedClean(CoreContext* context)
{
StatusCode code = Super::onAddedClean(context);
if (code != StatusCode::Ok)
{
return code;
}
updateWidthOverride();
updateHeightOverride();
return StatusCode::Ok;
}
void NestedArtboardLayout::updateLayoutBounds(bool animate)
{
#ifdef WITH_RIVE_LAYOUT
if (artboardInstance() == nullptr)
{
return;
}
artboardInstance()->updateLayoutBounds(animate);
#endif
}
#ifdef WITH_RIVE_LAYOUT
bool NestedArtboardLayout::cascadeLayoutStyle(
LayoutStyleInterpolation inheritedInterpolation,
KeyFrameInterpolator* inheritedInterpolator,
float inheritedInterpolationTime,
LayoutDirection direction)
{
if (artboardInstance() != nullptr)
{
artboardInstance()->cascadeLayoutStyle(inheritedInterpolation,
inheritedInterpolator,
inheritedInterpolationTime,
direction);
}
return false;
}
#endif
void NestedArtboardLayout::updateWidthOverride()
{
if (artboardInstance() == nullptr)
{
return;
}
m_styleOverrider.updateWidthOverride(artboardInstance());
}
void NestedArtboardLayout::updateHeightOverride()
{
if (artboardInstance() == nullptr)
{
return;
}
m_styleOverrider.updateHeightOverride(artboardInstance());
}
// The layout that collected us, which may sit above a container. Asking
// parent() reported row/not-stack for a Solo and sized the wrong axis.
bool NestedArtboardLayout::isRow()
{
auto* layout = owningLayout(parent());
return layout != nullptr ? layout->mainAxisIsRow() : true;
}
bool NestedArtboardLayout::isStack()
{
auto* layout = owningLayout(parent());
return layout != nullptr && layout->isStackContainer();
}
void NestedArtboardLayout::instanceWidthChanged() { updateWidthOverride(); }
void NestedArtboardLayout::instanceHeightChanged() { updateHeightOverride(); }
void NestedArtboardLayout::instanceWidthUnitsValueChanged()
{
updateWidthOverride();
}
void NestedArtboardLayout::instanceHeightUnitsValueChanged()
{
updateHeightOverride();
}
void NestedArtboardLayout::instanceWidthScaleTypeChanged()
{
updateWidthOverride();
}
void NestedArtboardLayout::instanceHeightScaleTypeChanged()
{
updateHeightOverride();
}
bool NestedArtboardLayout::syncStyleChanges()
{
if (m_referencedArtboard == nullptr)
{
return false;
}
return m_referencedArtboard->syncStyleChanges();
}
void NestedArtboardLayout::updateArtboard(
ViewModelInstanceArtboard* viewModelInstanceArtboard)
{
#ifdef WITH_RIVE_LAYOUT
// Re-collect on the layout that owns our node, not on parent(), or a
// container between the two leaves the swap unsynced.
auto* layout = owningLayout(parent());
if (layout != nullptr)
{
layout->clearLayoutChildren();
}
#endif
NestedArtboard::updateArtboard(viewModelInstanceArtboard);
updateWidthOverride();
updateHeightOverride();
#ifdef WITH_RIVE_LAYOUT
if (layout != nullptr)
{
layout->syncLayoutChildren();
}
#endif
}