mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
feature: add scroll threshold (#10824) 284c801953
Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
@@ -1 +1 @@
|
||||
53bc4a7cbb42ca8e5746bc21940d50d530b763ea
|
||||
284c8019536d32d8767c64897279c2b9ff9ee443
|
||||
|
||||
@@ -121,6 +121,16 @@
|
||||
},
|
||||
"description": "Whether pointer events trigger the scrolling",
|
||||
"bindable": true
|
||||
},
|
||||
"threshold": {
|
||||
"type": "double",
|
||||
"animates": true,
|
||||
"key": {
|
||||
"int": 894,
|
||||
"string": "threshold"
|
||||
},
|
||||
"description": "Minimum threshold in pixels to trigger the scrolling behavior",
|
||||
"bindable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ class ViewportDraggableProxy : public DraggableProxy
|
||||
private:
|
||||
ScrollConstraint* m_constraint;
|
||||
Vec2D m_lastPosition;
|
||||
bool m_isDragging = false;
|
||||
|
||||
public:
|
||||
ViewportDraggableProxy(ScrollConstraint* constraint, Drawable* hittable) :
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
static const uint16_t virtualizePropertyKey = 850;
|
||||
static const uint16_t infinitePropertyKey = 851;
|
||||
static const uint16_t interactivePropertyKey = 891;
|
||||
static const uint16_t thresholdPropertyKey = 894;
|
||||
|
||||
protected:
|
||||
float m_ScrollOffsetX = 0.0f;
|
||||
@@ -53,6 +54,7 @@ protected:
|
||||
bool m_Virtualize = false;
|
||||
bool m_Infinite = false;
|
||||
bool m_Interactive = true;
|
||||
float m_Threshold = 0.0f;
|
||||
|
||||
public:
|
||||
inline float scrollOffsetX() const { return m_ScrollOffsetX; }
|
||||
@@ -179,6 +181,17 @@ public:
|
||||
interactiveChanged();
|
||||
}
|
||||
|
||||
inline float threshold() const { return m_Threshold; }
|
||||
void threshold(float value)
|
||||
{
|
||||
if (m_Threshold == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Threshold = value;
|
||||
thresholdChanged();
|
||||
}
|
||||
|
||||
Core* clone() const override;
|
||||
void copy(const ScrollConstraintBase& object)
|
||||
{
|
||||
@@ -190,6 +203,7 @@ public:
|
||||
m_Virtualize = object.m_Virtualize;
|
||||
m_Infinite = object.m_Infinite;
|
||||
m_Interactive = object.m_Interactive;
|
||||
m_Threshold = object.m_Threshold;
|
||||
DraggableConstraint::copy(object);
|
||||
}
|
||||
|
||||
@@ -221,6 +235,9 @@ public:
|
||||
case interactivePropertyKey:
|
||||
m_Interactive = CoreBoolType::deserialize(reader);
|
||||
return true;
|
||||
case thresholdPropertyKey:
|
||||
m_Threshold = CoreDoubleType::deserialize(reader);
|
||||
return true;
|
||||
}
|
||||
return DraggableConstraint::deserialize(propertyKey, reader);
|
||||
}
|
||||
@@ -237,6 +254,7 @@ protected:
|
||||
virtual void virtualizeChanged() {}
|
||||
virtual void infiniteChanged() {}
|
||||
virtual void interactiveChanged() {}
|
||||
virtual void thresholdChanged() {}
|
||||
};
|
||||
} // namespace rive
|
||||
|
||||
|
||||
@@ -1801,6 +1801,9 @@ public:
|
||||
case ScrollConstraintBase::scrollIndexPropertyKey:
|
||||
object->as<ScrollConstraintBase>()->scrollIndex(value);
|
||||
break;
|
||||
case ScrollConstraintBase::thresholdPropertyKey:
|
||||
object->as<ScrollConstraintBase>()->threshold(value);
|
||||
break;
|
||||
case ElasticScrollPhysicsBase::frictionPropertyKey:
|
||||
object->as<ElasticScrollPhysicsBase>()->friction(value);
|
||||
break;
|
||||
@@ -3142,6 +3145,8 @@ public:
|
||||
return object->as<ScrollConstraintBase>()->scrollPercentY();
|
||||
case ScrollConstraintBase::scrollIndexPropertyKey:
|
||||
return object->as<ScrollConstraintBase>()->scrollIndex();
|
||||
case ScrollConstraintBase::thresholdPropertyKey:
|
||||
return object->as<ScrollConstraintBase>()->threshold();
|
||||
case ElasticScrollPhysicsBase::frictionPropertyKey:
|
||||
return object->as<ElasticScrollPhysicsBase>()->friction();
|
||||
case ElasticScrollPhysicsBase::speedMultiplierPropertyKey:
|
||||
@@ -3860,6 +3865,7 @@ public:
|
||||
case ScrollConstraintBase::scrollPercentXPropertyKey:
|
||||
case ScrollConstraintBase::scrollPercentYPropertyKey:
|
||||
case ScrollConstraintBase::scrollIndexPropertyKey:
|
||||
case ScrollConstraintBase::thresholdPropertyKey:
|
||||
case ElasticScrollPhysicsBase::frictionPropertyKey:
|
||||
case ElasticScrollPhysicsBase::speedMultiplierPropertyKey:
|
||||
case ElasticScrollPhysicsBase::elasticFactorPropertyKey:
|
||||
@@ -4693,6 +4699,8 @@ public:
|
||||
return object->is<ScrollConstraintBase>();
|
||||
case ScrollConstraintBase::scrollIndexPropertyKey:
|
||||
return object->is<ScrollConstraintBase>();
|
||||
case ScrollConstraintBase::thresholdPropertyKey:
|
||||
return object->is<ScrollConstraintBase>();
|
||||
case ElasticScrollPhysicsBase::frictionPropertyKey:
|
||||
return object->is<ElasticScrollPhysicsBase>();
|
||||
case ElasticScrollPhysicsBase::speedMultiplierPropertyKey:
|
||||
|
||||
@@ -11,7 +11,50 @@ bool ViewportDraggableProxy::drag(Vec2D mousePosition, float timeStamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_constraint->dragView(mousePosition - m_lastPosition, timeStamp);
|
||||
auto deltaPosition = mousePosition - m_lastPosition;
|
||||
if (!m_isDragging)
|
||||
{
|
||||
switch (m_constraint->direction())
|
||||
{
|
||||
case DraggableConstraintDirection::vertical:
|
||||
{
|
||||
if (std::abs(deltaPosition.y) > m_constraint->threshold())
|
||||
{
|
||||
m_isDragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DraggableConstraintDirection::horizontal:
|
||||
{
|
||||
if (std::abs(deltaPosition.x) > m_constraint->threshold())
|
||||
{
|
||||
m_isDragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DraggableConstraintDirection::all:
|
||||
{
|
||||
if (deltaPosition.length() > m_constraint->threshold())
|
||||
{
|
||||
m_isDragging = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_constraint->dragView(deltaPosition, timeStamp);
|
||||
m_lastPosition = mousePosition;
|
||||
return true;
|
||||
}
|
||||
@@ -22,6 +65,7 @@ bool ViewportDraggableProxy::startDrag(Vec2D mousePosition, float timeStamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_isDragging = false;
|
||||
m_constraint->initPhysics();
|
||||
m_lastPosition = mousePosition;
|
||||
return true;
|
||||
|
||||
BIN
tests/unit_tests/assets/scroll_threshold.riv
Normal file
BIN
tests/unit_tests/assets/scroll_threshold.riv
Normal file
Binary file not shown.
@@ -13,7 +13,7 @@
|
||||
|
||||
using namespace rive;
|
||||
|
||||
TEST_CASE("multiple scrolliing artboards", "[silver]")
|
||||
TEST_CASE("multiple scrolling artboards", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/scroll_test.riv", &silver);
|
||||
@@ -99,3 +99,198 @@ TEST_CASE("multiple scrolliing artboards", "[silver]")
|
||||
|
||||
CHECK(silver.matches("scroll_test"));
|
||||
}
|
||||
|
||||
TEST_CASE("Vertical scroll with threshold", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/scroll_threshold.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("vertical-scroll");
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto vmi = file->createViewModelInstance(artboard.get()->viewModelId(), 0);
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
|
||||
auto renderer = silver.makeRenderer();
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
silver.addFrame();
|
||||
|
||||
// Threshold value is 40
|
||||
|
||||
float pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 40)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Since it didn't go over the threshold, element shouldn't have scrolled
|
||||
// and nested item should trigger its click action
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
// Scroll beyond threshold
|
||||
pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 10)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Scrolled beyond threshold and click action is not fired
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(artboard->width() / 2.0f, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
CHECK(silver.matches("scroll_threshold-vertical-scroll"));
|
||||
}
|
||||
|
||||
TEST_CASE("Horizontal scroll with threshold", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/scroll_threshold.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("horizontal-scroll");
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto vmi = file->createViewModelInstance(artboard.get()->viewModelId(), 0);
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
|
||||
auto renderer = silver.makeRenderer();
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
silver.addFrame();
|
||||
|
||||
// Threshold value is 40
|
||||
|
||||
float pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 40)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Since it didn't go over the threshold, element shouldn't have scrolled
|
||||
// and nested item should trigger its click action
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
// Scroll beyond threshold
|
||||
pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 10)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Scrolled beyond threshold and click action is not fired
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(pos, artboard->height() / 2.0f));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
CHECK(silver.matches("scroll_threshold-horizontal-scroll"));
|
||||
}
|
||||
|
||||
TEST_CASE("Multidirectional scroll with threshold", "[silver]")
|
||||
{
|
||||
SerializingFactory silver;
|
||||
auto file = ReadRiveFile("assets/scroll_threshold.riv", &silver);
|
||||
|
||||
auto artboard = file->artboardNamed("all-scroll");
|
||||
silver.frameSize(artboard->width(), artboard->height());
|
||||
|
||||
auto stateMachine = artboard->stateMachineAt(0);
|
||||
auto vmi = file->createViewModelInstance(artboard.get()->viewModelId(), 0);
|
||||
stateMachine->bindViewModelInstance(vmi);
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
|
||||
auto renderer = silver.makeRenderer();
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
silver.addFrame();
|
||||
|
||||
// Threshold value is 40
|
||||
|
||||
float pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 50)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Since it didn't go over the threshold, element shouldn't have scrolled
|
||||
// and nested item should trigger its click action
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
// Scroll beyond threshold
|
||||
pos = 70.0f;
|
||||
stateMachine->pointerDown(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
while (pos > 32)
|
||||
{
|
||||
|
||||
silver.addFrame();
|
||||
stateMachine->pointerMove(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
pos -= 8;
|
||||
}
|
||||
// Scrolled diagonnally beyond threshold and click action is not fired
|
||||
silver.addFrame();
|
||||
stateMachine->pointerUp(rive::Vec2D(pos, pos));
|
||||
stateMachine->advanceAndApply(0.1f);
|
||||
artboard->draw(renderer.get());
|
||||
|
||||
CHECK(silver.matches("scroll_threshold-all-scroll"));
|
||||
}
|
||||
|
||||
BIN
tests/unit_tests/silvers/scroll_threshold-all-scroll.sriv
Normal file
BIN
tests/unit_tests/silvers/scroll_threshold-all-scroll.sriv
Normal file
Binary file not shown.
BIN
tests/unit_tests/silvers/scroll_threshold-horizontal-scroll.sriv
Normal file
BIN
tests/unit_tests/silvers/scroll_threshold-horizontal-scroll.sriv
Normal file
Binary file not shown.
BIN
tests/unit_tests/silvers/scroll_threshold-vertical-scroll.sriv
Normal file
BIN
tests/unit_tests/silvers/scroll_threshold-vertical-scroll.sriv
Normal file
Binary file not shown.
Reference in New Issue
Block a user