blob: 561bc6efe6ec05b840bb408b6ca8178d5149c3aa [file]
#include "rive/animation/state_machine_instance.hpp"
#include "rive/animation/state_machine_listener_single.hpp"
#include "rive/component.hpp"
#include "rive/constraints/draggable_constraint.hpp"
using namespace rive;
std::vector<ListenerGroupWithTargets*> DraggableConstraint::listenerGroups()
{
std::vector<ListenerGroupWithTargets*> result;
for (auto dragProxy : draggables())
{
auto listener = new StateMachineListenerSingle();
listener->listenerTypeValue(
static_cast<uint32_t>(ListenerType::componentProvided));
auto* listenerGroup = new DraggableConstraintListenerGroup(
listener,
this,
dragProxy);
auto hittable = dragProxy->hittable();
if (hittable != nullptr && hittable->is<Component>())
{
auto* target = new HitTarget(
hittable->as<Component>(),
dragProxy->isOpaque());
auto* groupWithTargets = new ListenerGroupWithTargets(
listenerGroup,
std::vector<HitTarget*>{target});
result.push_back(groupWithTargets);
}
}
return result;
}
// Mirrors the down -> clicked/out teardown in processEvent, which cancellation
// bypasses by clearing the phase before processEvent can observe the change.
bool DraggableConstraintListenerGroup::cancelPointer(
int pointerId,
Vec2D position,
float timeStamp)
{
auto pointer = findPointerData(pointerId);
bool wasDown = pointer != nullptr &&
pointer->phase == GestureClickPhase::down;
bool wasDragging = ListenerGroup::cancelPointer(
pointerId,
position,
timeStamp);
if (wasDown)
{
m_draggable->endDrag(position, timeStamp);
if (m_scrollingPointerId == pointerId)
{
m_scrollingPointerId = -1;
wasDragging = true;
}
}
return wasDragging;
}
ProcessEventResult DraggableConstraintListenerGroup::processEvent(
Component* component,
Vec2D position,
int pointerId,
ListenerType hitEvent,
PointerButton button,
bool canHit,
float timeStamp,
StateMachineInstance* stateMachineInstance)
{
if ((hitEvent == ListenerType::down || hitEvent == ListenerType::up) &&
button != PointerButton::primary)
{
return ProcessEventResult::none;
}
auto pointer = pointerData(pointerId);
auto prevPhase = pointer->phase;
ListenerGroup::processEvent(
component,
position,
pointerId,
hitEvent,
button,
canHit,
timeStamp,
stateMachineInstance);
if (prevPhase == GestureClickPhase::down &&
(pointer->phase == GestureClickPhase::clicked ||
pointer->phase == GestureClickPhase::out))
{
m_draggable->endDrag(position, timeStamp);
if (m_scrollingPointerId == pointerId)
{
stateMachineInstance->dragEnd(position, timeStamp, pointerId);
m_scrollingPointerId = -1;
return ProcessEventResult::scroll;
}
}
else if (
prevPhase != GestureClickPhase::down &&
pointer->phase == GestureClickPhase::down)
{
m_draggable->startDrag(position, timeStamp);
m_scrollingPointerId = -1;
}
else if (
hitEvent == ListenerType::move &&
pointer->phase == GestureClickPhase::down)
{
auto hasDragged = m_draggable->drag(position, timeStamp);
if (hasDragged)
{
if (m_scrollingPointerId != pointerId)
{
stateMachineInstance->dragStart(position, timeStamp, false, pointerId);
}
m_scrollingPointerId = pointerId;
return ProcessEventResult::scroll;
}
}
return ProcessEventResult::none;
}