mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
Prevent pointer events when interacting with scroll view (#10251) 40592c7963
Currently, when items are inside a scroll view, when the scroll view is dragged and released, the item's click event will still trigger its listener if the same item is hovered. This adds a way to disable pointer events. In this implementation, when a scroll drag begins, we set the GestureClickPhase to disabled which prevents clicks from being captured. Co-authored-by: Philip Chung <philterdesign@gmail.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
210c1fd1762397310aae3d64b569e99d9ba0e9ea
|
||||
40592c79637cab7fd3b0e466ee417080bd0671ab
|
||||
|
||||
@@ -28,6 +28,8 @@ public:
|
||||
HitResult pointerDown(Vec2D position);
|
||||
HitResult pointerUp(Vec2D position);
|
||||
HitResult pointerExit(Vec2D position);
|
||||
HitResult dragStart(Vec2D position, float timeStamp = 0);
|
||||
HitResult dragEnd(Vec2D position, float timeStamp = 0);
|
||||
bool tryChangeState();
|
||||
bool hitTest(Vec2D position) const;
|
||||
|
||||
|
||||
@@ -130,6 +130,10 @@ public:
|
||||
HitResult pointerDown(Vec2D position) override;
|
||||
HitResult pointerUp(Vec2D position) override;
|
||||
HitResult pointerExit(Vec2D position) override;
|
||||
HitResult dragStart(Vec2D position,
|
||||
float timeStamp = 0,
|
||||
bool disablePointer = true);
|
||||
HitResult dragEnd(Vec2D position, float timeStamp = 0);
|
||||
bool tryChangeState();
|
||||
bool hitTest(Vec2D position) const;
|
||||
|
||||
@@ -190,6 +194,8 @@ public:
|
||||
const LayerState* layerState(size_t index);
|
||||
#endif
|
||||
void updateDataBinds();
|
||||
void enablePointerEvents();
|
||||
void disablePointerEvents();
|
||||
|
||||
private:
|
||||
std::vector<EventReport> m_reportedEvents;
|
||||
@@ -239,6 +245,8 @@ public:
|
||||
float timeStamp = 0) = 0;
|
||||
virtual void prepareEvent(Vec2D position, ListenerType hitType) = 0;
|
||||
virtual bool hitTest(Vec2D position) const = 0;
|
||||
virtual void enablePointerEvents() {}
|
||||
virtual void disablePointerEvents() {}
|
||||
#ifdef TESTING
|
||||
int earlyOutCount = 0;
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@ enum class GestureClickPhase : int
|
||||
out = 0,
|
||||
down = 1,
|
||||
clicked = 2,
|
||||
disabled = 3,
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -12,6 +12,8 @@ enum class ListenerType : int
|
||||
event = 5,
|
||||
click = 6,
|
||||
draggableConstraint = 7,
|
||||
dragStart = 8,
|
||||
dragEnd = 9,
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -21,7 +21,6 @@ struct PointerEvent
|
||||
|
||||
// add more fields as needed
|
||||
};
|
||||
|
||||
} // namespace rive
|
||||
|
||||
#endif
|
||||
|
||||
@@ -84,6 +84,24 @@ HitResult NestedStateMachine::pointerExit(Vec2D position)
|
||||
return HitResult::none;
|
||||
}
|
||||
|
||||
HitResult NestedStateMachine::dragStart(Vec2D position, float timeStamp)
|
||||
{
|
||||
if (m_StateMachineInstance != nullptr)
|
||||
{
|
||||
return m_StateMachineInstance->dragStart(position, timeStamp);
|
||||
}
|
||||
return HitResult::none;
|
||||
}
|
||||
|
||||
HitResult NestedStateMachine::dragEnd(Vec2D position, float timeStamp)
|
||||
{
|
||||
if (m_StateMachineInstance != nullptr)
|
||||
{
|
||||
return m_StateMachineInstance->dragEnd(position, timeStamp);
|
||||
}
|
||||
return HitResult::none;
|
||||
}
|
||||
|
||||
NestedInput* NestedStateMachine::input(size_t index)
|
||||
{
|
||||
if (index < m_nestedInputs.size())
|
||||
|
||||
@@ -530,14 +530,23 @@ public:
|
||||
void unhover() { m_isHovered = false; }
|
||||
void reset()
|
||||
{
|
||||
m_isConsumed = false;
|
||||
m_prevIsHovered = m_isHovered;
|
||||
m_isHovered = false;
|
||||
if (m_clickPhase != GestureClickPhase::disabled)
|
||||
{
|
||||
m_isConsumed = false;
|
||||
m_prevIsHovered = m_isHovered;
|
||||
m_isHovered = false;
|
||||
}
|
||||
if (m_clickPhase == GestureClickPhase::clicked)
|
||||
{
|
||||
m_clickPhase = GestureClickPhase::out;
|
||||
}
|
||||
}
|
||||
virtual void enable() { m_clickPhase = GestureClickPhase::out; }
|
||||
virtual void disable()
|
||||
{
|
||||
m_clickPhase = GestureClickPhase::disabled;
|
||||
consume();
|
||||
}
|
||||
bool isConsumed() { return m_isConsumed; }
|
||||
bool isHovered() { return m_isHovered; }
|
||||
bool prevHovered() { return m_prevIsHovered; }
|
||||
@@ -688,6 +697,9 @@ public:
|
||||
delete m_draggable;
|
||||
}
|
||||
|
||||
void enable() override {}
|
||||
void disable() override {}
|
||||
|
||||
DraggableConstraint* constraint() { return m_constraint; }
|
||||
|
||||
bool canEarlyOut(Component* drawable) override { return false; }
|
||||
@@ -718,8 +730,9 @@ public:
|
||||
m_draggable->endDrag(position, timeStamp);
|
||||
if (hasScrolled)
|
||||
{
|
||||
return ProcessEventResult::scroll;
|
||||
stateMachineInstance->dragEnd(position, timeStamp);
|
||||
hasScrolled = false;
|
||||
return ProcessEventResult::scroll;
|
||||
}
|
||||
}
|
||||
else if (prevPhase != GestureClickPhase::down &&
|
||||
@@ -732,6 +745,10 @@ public:
|
||||
clickPhase() == GestureClickPhase::down)
|
||||
{
|
||||
m_draggable->drag(position, timeStamp);
|
||||
if (!hasScrolled)
|
||||
{
|
||||
stateMachineInstance->dragStart(position, timeStamp, false);
|
||||
}
|
||||
hasScrolled = true;
|
||||
return ProcessEventResult::scroll;
|
||||
}
|
||||
@@ -859,6 +876,22 @@ public:
|
||||
}
|
||||
listeners.push_back(listenerGroup);
|
||||
}
|
||||
|
||||
void enablePointerEvents() override
|
||||
{
|
||||
for (auto listenerGroup : listeners)
|
||||
{
|
||||
listenerGroup->enable();
|
||||
}
|
||||
}
|
||||
|
||||
void disablePointerEvents() override
|
||||
{
|
||||
for (auto listenerGroup : listeners)
|
||||
{
|
||||
listenerGroup->disable();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Representation of a HitDrawable with a Hittable component
|
||||
@@ -987,6 +1020,14 @@ public:
|
||||
nestedStateMachine->pointerMove(nestedPosition,
|
||||
timeStamp);
|
||||
break;
|
||||
case ListenerType::dragStart:
|
||||
nestedStateMachine->dragStart(nestedPosition,
|
||||
timeStamp);
|
||||
break;
|
||||
case ListenerType::dragEnd:
|
||||
nestedStateMachine->dragEnd(nestedPosition,
|
||||
timeStamp);
|
||||
break;
|
||||
case ListenerType::enter:
|
||||
case ListenerType::exit:
|
||||
case ListenerType::event:
|
||||
@@ -1004,6 +1045,8 @@ public:
|
||||
case ListenerType::move:
|
||||
nestedStateMachine->pointerExit(nestedPosition);
|
||||
break;
|
||||
case ListenerType::dragStart:
|
||||
case ListenerType::dragEnd:
|
||||
case ListenerType::enter:
|
||||
case ListenerType::exit:
|
||||
case ListenerType::event:
|
||||
@@ -1091,6 +1134,12 @@ public:
|
||||
itemHitResult =
|
||||
stateMachine->pointerMove(listPosition);
|
||||
break;
|
||||
case ListenerType::dragStart:
|
||||
stateMachine->dragStart(listPosition);
|
||||
break;
|
||||
case ListenerType::dragEnd:
|
||||
stateMachine->dragEnd(listPosition);
|
||||
break;
|
||||
case ListenerType::enter:
|
||||
case ListenerType::exit:
|
||||
case ListenerType::event:
|
||||
@@ -1108,6 +1157,8 @@ public:
|
||||
case ListenerType::move:
|
||||
stateMachine->pointerExit(listPosition);
|
||||
break;
|
||||
case ListenerType::dragStart:
|
||||
case ListenerType::dragEnd:
|
||||
case ListenerType::enter:
|
||||
case ListenerType::exit:
|
||||
case ListenerType::event:
|
||||
@@ -1216,6 +1267,24 @@ HitResult StateMachineInstance::pointerExit(Vec2D position)
|
||||
{
|
||||
return updateListeners(position, ListenerType::exit);
|
||||
}
|
||||
HitResult StateMachineInstance::dragStart(Vec2D position,
|
||||
float timeStamp,
|
||||
bool disablePointer)
|
||||
{
|
||||
if (disablePointer)
|
||||
{
|
||||
disablePointerEvents();
|
||||
}
|
||||
auto hit = updateListeners(position, ListenerType::dragStart);
|
||||
return hit;
|
||||
}
|
||||
HitResult StateMachineInstance::dragEnd(Vec2D position, float timeStamp)
|
||||
{
|
||||
enablePointerEvents();
|
||||
auto hit = updateListeners(position, ListenerType::dragEnd);
|
||||
pointerMove(position, timeStamp);
|
||||
return hit;
|
||||
}
|
||||
|
||||
#ifdef TESTING
|
||||
const LayerState* StateMachineInstance::layerState(size_t index)
|
||||
@@ -2027,6 +2096,22 @@ void StateMachineInstance::notifyEventListeners(
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachineInstance::enablePointerEvents()
|
||||
{
|
||||
for (const auto& hitShape : m_hitComponents)
|
||||
{
|
||||
hitShape->enablePointerEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachineInstance::disablePointerEvents()
|
||||
{
|
||||
for (const auto& hitShape : m_hitComponents)
|
||||
{
|
||||
hitShape->disablePointerEvents();
|
||||
}
|
||||
}
|
||||
|
||||
BindableProperty* StateMachineInstance::bindablePropertyInstance(
|
||||
BindableProperty* bindableProperty) const
|
||||
{
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user