blob: 283274e1e0fa2843d66c31b8f959853813168fc3 [file]
/*
* Copyright 2026 Rive
*/
// A scroll registers itself on each child provider and each child runs it from
// its own updateConstraints. A participant provides through its
// LayoutParticipant child, so the host is not a provider and neither half
// happened for it — participants sat still while layout children scrolled.
// Mirrors rive_core/test/scroll_participant_test.dart.
#include "rive/artboard.hpp"
#include "rive/constraints/scrolling/scroll_constraint.hpp"
#include "rive/layout/layout_participant.hpp"
#include "rive/layout_component.hpp"
#include "rive/shapes/shape.hpp"
#include "rive_file_reader.hpp"
#include "rive_testing.hpp"
#include <catch.hpp>
using namespace rive;
// Asset generated by rive_core/test/layout_participant_export_test.dart: a
// 100-tall viewport over 300-tall content whose only child is a participating
// shape, so nothing else can carry the scroll for it.
TEST_CASE("a scroll constraint moves a participating child", "[layoutscroll]")
{
auto file = ReadRiveFile("assets/layout/scroll_participant.riv");
auto artboard = file->artboard();
REQUIRE(artboard != nullptr);
artboard->advance(0.0f);
// By type, not by name: the exporter keeps only the artboard's name, so
// this asset carries none for its children.
auto shapes = artboard->find<Shape>();
REQUIRE(shapes.size() == 1);
auto* shape = shapes[0];
REQUIRE(shape->isParticipatingInLayout());
REQUIRE(artboard->find<ScrollConstraint>().size() == 1);
auto* scroll = artboard->find<ScrollConstraint>()[0];
// There is room to scroll, so the offset below is not clamped away.
REQUIRE(scroll->maxOffsetY() <= -50.0f);
const float before = shape->worldTransform()[5];
scroll->scrollOffsetY(-50.0f);
artboard->advance(0.0f);
REQUIRE(shape->worldTransform()[5] - before == Approx(-50.0f));
}