add drag event type support (#10807) 2f4ec0a570

* add drag event type support

Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
bodymovin
2025-10-21 22:21:50 +00:00
parent c18e964c42
commit 42d61b6c86
6 changed files with 104 additions and 4 deletions

View File

@@ -1 +1 @@
c7a0379ab3bd3ec3fb9b2ed26d5b238b93a26976
2f4ec0a57046df283b229974330b4f38bdcaaf70

View File

@@ -16,6 +16,7 @@ enum class ListenerType : int
dragStart = 9,
dragEnd = 10,
viewModel = 11,
drag = 12,
};
}
#endif

View File

@@ -617,21 +617,24 @@ public:
auto listenerType = m_listener->listenerType();
return !(listenerType == ListenerType::enter ||
listenerType == ListenerType::exit ||
listenerType == ListenerType::move);
listenerType == ListenerType::move ||
listenerType == ListenerType::drag);
}
virtual bool needsDownListener(Component* drawable)
{
auto listenerType = m_listener->listenerType();
return listenerType == ListenerType::down ||
listenerType == ListenerType::click;
listenerType == ListenerType::click ||
listenerType == ListenerType::drag;
}
virtual bool needsUpListener(Component* drawable)
{
auto listenerType = m_listener->listenerType();
return listenerType == ListenerType::up ||
listenerType == ListenerType::click;
listenerType == ListenerType::click ||
listenerType == ListenerType::drag;
}
virtual ProcessEventResult processEvent(
@@ -651,6 +654,7 @@ public:
// context. In this case, we unhover the group so it is not marked as
// previously hovered.
auto pointer = pointerData(pointerId);
auto prevPhase = pointer->phase;
if (!canHit && pointer->isHovered)
{
pointer->isHovered = false;
@@ -690,6 +694,14 @@ public:
pointer->phase = GestureClickPhase::out;
}
}
if (prevPhase == GestureClickPhase::down &&
(pointer->phase == GestureClickPhase::clicked ||
pointer->phase == GestureClickPhase::out) &&
m_hasDragged)
{
stateMachineInstance->dragEnd(position, timeStamp, pointerId);
m_hasDragged = false;
}
auto _listener = listener();
// Always update hover states regardless of which specific listener type
// we're trying to trigger.
@@ -723,6 +735,29 @@ public:
stateMachineInstance->markNeedsAdvance();
consume();
}
// Perform changes if:
// - the listener type is drag
// - the clickPhase is down
// - the pointer type is move
if (pointer->phase == GestureClickPhase::down &&
_listener->listenerType() == ListenerType::drag &&
hitEvent == ListenerType::move)
{
_listener->performChanges(
stateMachineInstance,
position,
Vec2D(previousPosition->x, previousPosition->y));
stateMachineInstance->markNeedsAdvance();
if (!m_hasDragged)
{
stateMachineInstance->dragStart(position,
timeStamp,
false,
pointerId);
m_hasDragged = true;
}
consume();
}
previousPosition->x = position.x;
previousPosition->y = position.y;
return ProcessEventResult::pointer;
@@ -733,6 +768,7 @@ public:
private:
// Consumed listeners aren't processed again in the current frame
bool m_isConsumed = false;
bool m_hasDragged = false;
const StateMachineListener* m_listener;
std::unordered_map<int, _PointerData*> m_pointers;
std::vector<_PointerData*> m_pointersPool;
@@ -1114,6 +1150,7 @@ public:
case ListenerType::draggableConstraint:
case ListenerType::textInput:
case ListenerType::viewModel:
case ListenerType::drag:
break;
}
}
@@ -1136,6 +1173,7 @@ public:
case ListenerType::draggableConstraint:
case ListenerType::textInput:
case ListenerType::viewModel:
case ListenerType::drag:
break;
}
}
@@ -1246,6 +1284,7 @@ public:
case ListenerType::draggableConstraint:
case ListenerType::textInput:
case ListenerType::viewModel:
case ListenerType::drag:
break;
}
}
@@ -1267,6 +1306,7 @@ public:
case ListenerType::draggableConstraint:
case ListenerType::textInput:
case ListenerType::viewModel:
case ListenerType::drag:
break;
}
}

Binary file not shown.

View File

@@ -1388,4 +1388,63 @@ TEST_CASE("Replace view model instance in nested list", "[silver]")
}
CHECK(silver.matches("replace_vm_instance-double-nest"));
}
TEST_CASE("Pointer drag event", "[silver]")
{
SerializingFactory silver;
auto file = ReadRiveFile("assets/drag_event.riv", &silver);
auto artboard = file->artboardDefault();
REQUIRE(artboard != nullptr);
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();
// Clicking on a square without moving will trigger the click on the nested
// artboard
stateMachine->pointerDown(rive::Vec2D(250, 250));
stateMachine->pointerUp(rive::Vec2D(250, 250));
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
silver.addFrame();
auto coord = 250.0f;
stateMachine->pointerDown(rive::Vec2D(coord, coord));
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
// Drag gesture works and click is cancelled
while (coord > 50)
{
silver.addFrame();
stateMachine->pointerMove(rive::Vec2D(coord, coord));
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
coord -= 10;
}
stateMachine->pointerUp(rive::Vec2D(coord, coord));
silver.addFrame();
// Clicking again on a square without moving will trigger the click on the
// nested artboard
stateMachine->pointerDown(rive::Vec2D(coord, coord));
stateMachine->advanceAndApply(0.1f);
stateMachine->pointerUp(rive::Vec2D(coord, coord));
stateMachine->advanceAndApply(0.1f);
artboard->draw(renderer.get());
CHECK(silver.matches("drag_event"));
}

Binary file not shown.