Files
rive-cpp/src/constraints/scrolling/scroll_constraint.cpp
luigi-rosso a1441bba0a chore: fix clang-17 compiler (#9666) 8a1f3286b9
* chore: fix clang-17 compiler

* chore: adding missing file

* fix: rive_native builds

* chore: remove no runtime linking on linux

* chore: more fixes

* chore: removing rive_common

* chore: use build_rive.sh for ios

* chore: use rive_build.sh for recorder

* chore: fix fill missing version

* chore: add rive_build.sh to path

* chore: add rive_build.sh to pr_ios_tests.yaml

* chore: add rive_build to the recorder tests

* chore: drop rive_flutter tests

* chore: fixing ios tests

* fix misspelled

* chore: cleanup

* chore: use latest zlib

* chore: premake5.lua redirects to premake5_v2

* fix: tvos and ios builds

* fix: unreal build path for miniaudio

Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
2025-05-15 18:21:04 +00:00

302 lines
7.6 KiB
C++

#include "rive/constraints/scrolling/scroll_constraint.hpp"
#include "rive/constraints/scrolling/scroll_constraint_proxy.hpp"
#include "rive/constraints/transform_constraint.hpp"
#include "rive/core_context.hpp"
#include "rive/layout/layout_node_provider.hpp"
#include "rive/transform_component.hpp"
#include "rive/math/mat2d.hpp"
using namespace rive;
ScrollConstraint::~ScrollConstraint() { delete m_physics; }
void ScrollConstraint::constrain(TransformComponent* component)
{
m_scrollTransform =
Mat2D::fromTranslate(constrainsHorizontal() ? clampedOffsetX() : 0,
constrainsVertical() ? clampedOffsetY() : 0);
}
void ScrollConstraint::constrainChild(LayoutNodeProvider* child)
{
auto component = child->transformComponent();
if (component == nullptr)
{
return;
}
auto targetTransform =
Mat2D::multiply(component->worldTransform(), m_scrollTransform);
TransformConstraint::constrainWorld(component,
component->worldTransform(),
m_componentsA,
targetTransform,
m_componentsB,
strength());
}
void ScrollConstraint::dragView(Vec2D delta)
{
if (m_physics != nullptr)
{
m_physics->accumulate(delta);
}
scrollOffsetX(offsetX() + delta.x);
scrollOffsetY(offsetY() + delta.y);
}
void ScrollConstraint::runPhysics()
{
m_isDragging = false;
std::vector<Vec2D> snappingPoints;
if (snap())
{
for (auto child : content()->children())
{
auto c = LayoutNodeProvider::from(child);
if (c != nullptr)
{
auto bounds = c->layoutBounds();
snappingPoints.push_back(Vec2D(bounds.left(), bounds.top()));
}
}
}
if (m_physics != nullptr)
{
m_physics->run(Vec2D(maxOffsetX(), maxOffsetY()),
Vec2D(offsetX(), offsetY()),
snap() ? snappingPoints : std::vector<Vec2D>());
}
}
bool ScrollConstraint::advanceComponent(float elapsedSeconds,
AdvanceFlags flags)
{
if ((flags & AdvanceFlags::AdvanceNested) != AdvanceFlags::AdvanceNested)
{
// offsetX(0);
// offsetY(0);
return false;
}
if (m_physics == nullptr)
{
return false;
}
if (m_physics->isRunning())
{
auto offset = m_physics->advance(elapsedSeconds);
scrollOffsetX(offset.x);
scrollOffsetY(offset.y);
}
return m_physics->enabled();
}
std::vector<DraggableProxy*> ScrollConstraint::draggables()
{
std::vector<DraggableProxy*> items;
items.push_back(new ViewportDraggableProxy(this, viewport()->proxy()));
return items;
}
void ScrollConstraint::buildDependencies()
{
Super::buildDependencies();
for (auto child : content()->children())
{
auto layout = LayoutNodeProvider::from(child);
if (layout != nullptr)
{
addDependent(child);
layout->addLayoutConstraint(static_cast<LayoutConstraint*>(this));
}
}
}
Core* ScrollConstraint::clone() const
{
auto cloned = ScrollConstraintBase::clone();
if (physics() != nullptr)
{
auto constraint = cloned->as<ScrollConstraint>();
auto clonedPhysics = physics()->clone()->as<ScrollPhysics>();
constraint->physics(clonedPhysics);
}
return cloned;
}
StatusCode ScrollConstraint::import(ImportStack& importStack)
{
auto backboardImporter =
importStack.latest<BackboardImporter>(BackboardBase::typeKey);
if (backboardImporter != nullptr)
{
std::vector<ScrollPhysics*> physicsObjects =
backboardImporter->physics();
if (physicsId() != -1 && physicsId() < physicsObjects.size())
{
auto phys = physicsObjects[physicsId()];
if (phys != nullptr)
{
auto cloned = phys->clone()->as<ScrollPhysics>();
physics(cloned);
}
}
}
else
{
return StatusCode::MissingObject;
}
return Super::import(importStack);
}
StatusCode ScrollConstraint::onAddedDirty(CoreContext* context)
{
StatusCode result = Super::onAddedDirty(context);
offsetX(scrollOffsetX());
offsetY(scrollOffsetY());
return result;
}
void ScrollConstraint::initPhysics()
{
m_isDragging = true;
if (m_physics != nullptr)
{
m_physics->prepare(direction());
}
}
void ScrollConstraint::stopPhysics()
{
if (m_physics != nullptr)
{
m_physics->reset();
}
}
float ScrollConstraint::scrollPercentX()
{
return maxOffsetX() != 0 ? scrollOffsetX() / maxOffsetX() : 0;
}
float ScrollConstraint::scrollPercentY()
{
return maxOffsetY() != 0 ? scrollOffsetY() / maxOffsetY() : 0;
}
float ScrollConstraint::scrollIndex()
{
return indexAtPosition(Vec2D(scrollOffsetX(), scrollOffsetY()));
}
void ScrollConstraint::setScrollPercentX(float value)
{
if (m_isDragging)
{
return;
}
stopPhysics();
float to = value * maxOffsetX();
scrollOffsetX(to);
}
void ScrollConstraint::setScrollPercentY(float value)
{
if (m_isDragging)
{
return;
}
stopPhysics();
float to = value * maxOffsetY();
scrollOffsetY(to);
}
void ScrollConstraint::setScrollIndex(float value)
{
if (m_isDragging)
{
return;
}
stopPhysics();
Vec2D to = positionAtIndex(value);
if (constrainsHorizontal())
{
scrollOffsetX(to.x);
}
else if (constrainsVertical())
{
scrollOffsetY(to.y);
}
}
Vec2D ScrollConstraint::positionAtIndex(float index)
{
if (content() == nullptr || content()->children().size() == 0)
{
return Vec2D();
}
uint32_t i = 0;
LayoutNodeProvider* lastChild;
for (auto child : content()->children())
{
auto c = LayoutNodeProvider::from(child);
if (c != nullptr)
{
float floorIndex = std::floor(index);
if (i == (uint32_t)floorIndex)
{
float mod = index - floorIndex;
auto bounds = c->layoutBounds();
return Vec2D(-bounds.left() - bounds.width() * mod,
-bounds.top() - bounds.height() * mod);
}
lastChild = c;
i++;
}
}
auto bounds = lastChild->layoutBounds();
return Vec2D(-bounds.left(), -bounds.top());
}
float ScrollConstraint::indexAtPosition(Vec2D pos)
{
if (content() == nullptr || content()->children().size() == 0)
{
return 0;
}
float i = 0.0f;
if (constrainsHorizontal())
{
for (auto child : content()->children())
{
auto c = LayoutNodeProvider::from(child);
if (c != nullptr)
{
auto bounds = c->layoutBounds();
if (pos.x > -bounds.left() - bounds.width())
{
return i + (-pos.x - bounds.left()) / bounds.width();
}
i++;
}
}
return i;
}
else if (constrainsVertical())
{
for (auto child : content()->children())
{
auto c = LayoutNodeProvider::from(child);
if (c != nullptr)
{
auto bounds = c->layoutBounds();
if (pos.y > -bounds.top() - bounds.height())
{
return i + (-pos.y - bounds.top()) / bounds.height();
}
i++;
}
}
return i;
}
return 0;
}