Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquickdraghandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <private/qquickwindow_p.h>
6#include <private/qquickmultipointhandler_p_p.h>
7#include <QDebug>
8
10
12
13Q_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
14
15
62
63QPointF QQuickDragHandler::targetCentroidPosition()
64{
66 if (auto par = parentItem()) {
67 if (target() != par)
68 pos = par->mapToItem(target(), pos);
69 }
70 return pos;
71}
72
74{
75 QQuickMultiPointHandler::onGrabChanged(grabber, transition, event, point);
76 if (grabber == this && transition == QPointingDevice::GrabExclusive && target()) {
77 // In case the grab got handed over from another grabber, we might not get the Press.
78
79 auto isDescendant = [](QQuickItem *parent, QQuickItem *target) {
80 return parent && (target != parent) && !target->isAncestorOf(parent);
81 };
82 if (m_snapMode == SnapAlways
83 || (m_snapMode == SnapIfPressedOutsideTarget && !m_pressedInsideTarget)
84 || (m_snapMode == SnapAuto && !m_pressedInsideTarget && isDescendant(parentItem(), target()))
85 ) {
86 m_pressTargetPos = QPointF(target()->width(), target()->height()) / 2;
87 } else if (m_pressTargetPos.isNull()) {
88 m_pressTargetPos = targetCentroidPosition();
89 }
90 }
91}
92
108{
109 return m_snapMode;
110}
111
113{
114 if (mode == m_snapMode)
115 return;
116 m_snapMode = mode;
117 emit snapModeChanged();
118}
119
121{
123 const bool curActive = active();
124 m_xAxis.onActiveChanged(curActive, 0);
125 m_yAxis.onActiveChanged(curActive, 0);
126 if (curActive) {
127 if (auto parent = parentItem()) {
130 // tablet and mouse are treated the same by Item's legacy event handling, and
131 // touch becomes synth-mouse for Flickable, so we need to prevent stealing
132 // mouse grab too, whenever dragging occurs in an enabled direction
134 }
135 } else {
136 m_pressTargetPos = QPointF();
137 m_pressedInsideTarget = false;
138 if (auto parent = parentItem()) {
139 parent->setKeepTouchGrab(false);
140 parent->setKeepMouseGrab(false);
141 }
142 }
143}
144
146{
148 /* Do handle other events than we would normally care about
149 while we are still doing a drag; otherwise we would suddenly
150 become inactive when a wheel event arrives during dragging.
151 This extra condition needs to be kept in sync with
152 handlePointerEventImpl */
153 if (!active())
154 return false;
155
156#if QT_CONFIG(gestures)
157 if (event->type() == QEvent::NativeGesture)
158 return false;
159#endif
160
161 return true;
162}
163
165{
167 return; // see QQuickDragHandler::wantsPointerEvent; we don't want to handle those events
168
170 event->setAccepted(true);
171
172 if (active()) {
173 // Calculate drag delta, taking into account the axis enabled constraint
174 // i.e. if xAxis is not enabled, then ignore the horizontal component of the actual movement
175 QVector2D accumulatedDragDelta = QVector2D(centroid().scenePosition() - centroid().scenePressPosition());
176 if (!m_xAxis.enabled())
177 accumulatedDragDelta.setX(0);
178 if (!m_yAxis.enabled())
179 accumulatedDragDelta.setY(0);
180 setActiveTranslation(accumulatedDragDelta);
181 } else {
182 // Check that all points have been dragged past the drag threshold,
183 // to the extent that the constraints allow,
184 // and in approximately the same direction
185 qreal minAngle = 361;
186 qreal maxAngle = -361;
187 bool allOverThreshold = QQuickDeliveryAgentPrivate::isTouchEvent(event) ?
188 static_cast<QTouchEvent *>(event)->touchPointStates() != QEventPoint::Released :
189 !event->isEndEvent();
190 QVector<QEventPoint> chosenPoints;
191
192 if (event->isBeginEvent())
193 m_pressedInsideTarget = target() && currentPoints().size() > 0;
194
195 for (const QQuickHandlerPoint &p : currentPoints()) {
196 if (!allOverThreshold)
197 break;
198 auto point = event->pointById(p.id());
199 Q_ASSERT(point);
200 chosenPoints << *point;
201 setPassiveGrab(event, *point);
202 // Calculate drag delta, taking into account the axis enabled constraint
203 // i.e. if xAxis is not enabled, then ignore the horizontal component of the actual movement
204 QVector2D accumulatedDragDelta = QVector2D(point->scenePosition() - point->scenePressPosition());
205 if (!m_xAxis.enabled()) {
206 // If horizontal dragging is disallowed, but the user is dragging
207 // mostly horizontally, then don't activate.
208 if (qAbs(accumulatedDragDelta.x()) > qAbs(accumulatedDragDelta.y()))
209 accumulatedDragDelta.setY(0);
210 accumulatedDragDelta.setX(0);
211 }
212 if (!m_yAxis.enabled()) {
213 // If vertical dragging is disallowed, but the user is dragging
214 // mostly vertically, then don't activate.
215 if (qAbs(accumulatedDragDelta.y()) > qAbs(accumulatedDragDelta.x()))
216 accumulatedDragDelta.setX(0);
217 accumulatedDragDelta.setY(0);
218 }
219 qreal angle = std::atan2(accumulatedDragDelta.y(), accumulatedDragDelta.x()) * 180 / M_PI;
220 bool overThreshold = d_func()->dragOverThreshold(accumulatedDragDelta);
221 qCDebug(lcDragHandler) << "movement" << accumulatedDragDelta << "angle" << angle << "of point" << point
222 << "pressed @" << point->scenePressPosition() << "over threshold?" << overThreshold;
223 minAngle = qMin(angle, minAngle);
224 maxAngle = qMax(angle, maxAngle);
225 if (allOverThreshold && !overThreshold)
226 allOverThreshold = false;
227
228 if (event->isBeginEvent()) {
229 // m_pressedInsideTarget should stay true iff ALL points in which DragHandler is interested
230 // have been pressed inside the target() Item. (E.g. in a Slider the parent might be the
231 // whole control while the target is just the knob.)
232 if (target()) {
233 const QPointF localPressPos = target()->mapFromScene(point->scenePressPosition());
234 m_pressedInsideTarget &= target()->contains(localPressPos);
235 m_pressTargetPos = targetCentroidPosition();
236 }
237 // QQuickDeliveryAgentPrivate::deliverToPassiveGrabbers() skips subsequent delivery if the event is filtered.
238 // (That affects behavior for mouse but not for touch, because Flickable only handles mouse.)
239 // So we have to compensate by accepting the event here to avoid any parent Flickable from
240 // getting the event via direct delivery and grabbing too soon.
241 point->setAccepted(QQuickDeliveryAgentPrivate::isMouseEvent(event)); // stop propagation iff it's a mouse event
242 }
243 }
244 if (allOverThreshold) {
245 qreal angleDiff = maxAngle - minAngle;
246 if (angleDiff > 180)
247 angleDiff = 360 - angleDiff;
248 qCDebug(lcDragHandler) << "angle min" << minAngle << "max" << maxAngle << "range" << angleDiff;
249 if (angleDiff < DragAngleToleranceDegrees && grabPoints(event, chosenPoints))
250 setActive(true);
251 }
252 }
253 if (active() && target() && target()->parentItem()) {
254 const QPointF newTargetTopLeft = targetCentroidPosition() - m_pressTargetPos;
255 const QPointF xformOrigin = target()->transformOriginPoint();
256 const QPointF targetXformOrigin = newTargetTopLeft + xformOrigin;
257 QPointF pos = target()->parentItem()->mapFromItem(target(), targetXformOrigin);
258 pos -= xformOrigin;
259 QPointF targetItemPos = target()->position();
260 if (!m_xAxis.enabled())
261 pos.setX(targetItemPos.x());
262 if (!m_yAxis.enabled())
263 pos.setY(targetItemPos.y());
264 enforceAxisConstraints(&pos);
266 }
267}
268
269void QQuickDragHandler::enforceAxisConstraints(QPointF *localPos)
270{
271 if (m_xAxis.enabled())
272 localPos->setX(qBound(m_xAxis.minimum(), localPos->x(), m_xAxis.maximum()));
273 if (m_yAxis.enabled())
274 localPos->setY(qBound(m_yAxis.minimum(), localPos->y(), m_yAxis.maximum()));
275}
276
278{
279 if (trans == persistentTranslation())
280 return;
281
282 m_xAxis.updateValue(m_xAxis.activeValue(), trans.x());
283 m_yAxis.updateValue(m_yAxis.activeValue(), trans.y());
285}
286
288{
289 if (trans == activeTranslation())
290 return;
291
292 const QVector2D delta = trans - activeTranslation();
293 m_xAxis.updateValue(trans.x(), m_xAxis.persistentValue() + delta.x(), delta.x());
294 m_yAxis.updateValue(trans.y(), m_yAxis.persistentValue() + delta.y(), delta.y());
295
296 qCDebug(lcDragHandler) << "translation: delta" << delta
297 << "active" << trans << "accumulated" << persistentTranslation();
299}
300
372
373#include "moc_qquickdraghandler_p.cpp"
The QEventPoint class provides information about a point in a QPointerEvent.
Definition qeventpoint.h:20
@ NativeGesture
Definition qcoreevent.h:246
qsizetype size() const noexcept
Definition qlist.h:397
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
constexpr void setY(qreal y) noexcept
Sets the y coordinate of this point to the given finite y coordinate.
Definition qpoint.h:358
constexpr void setX(qreal x) noexcept
Sets the x coordinate of this point to the given finite x coordinate.
Definition qpoint.h:353
bool isNull() const noexcept
Returns true if both the x and y coordinates are set to 0.0 (ignoring the sign); otherwise returns fa...
Definition qpoint.h:338
A base class for pointer events.
Definition qevent.h:73
GrabTransition
This enum represents a transition of exclusive or passive grab from one object (possibly nullptr) to ...
static bool isTouchEvent(const QPointerEvent *ev)
static bool isMouseEvent(const QPointerEvent *ev)
void onActiveChanged(bool active, qreal initActiveValue)
void updateValue(qreal activeValue, qreal accumulatedValue, qreal delta=0)
qreal persistentValue() const
void setSnapMode(QQuickDragHandler::SnapMode mode)
void setPersistentTranslation(const QVector2D &trans)
void translationChanged(QVector2D delta)
void onActiveChanged() override
bool wantsPointerEvent(QPointerEvent *event) override
It is the responsibility of this function to decide whether the event could be relevant at all to thi...
void setActiveTranslation(const QVector2D &trans)
void handlePointerEventImpl(QPointerEvent *event) override
This function can be overridden to implement whatever behavior a specific subclass is intended to hav...
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) override
Notification that the grab has changed in some way which is relevant to this handler.
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setKeepTouchGrab(bool)
Sets whether the touch points grabbed by this item should remain exclusively with this item.
Q_INVOKABLE QPointF mapFromItem(const QQuickItem *item, const QPointF &point) const
Maps the given point in item's coordinate system to the equivalent point within this item's coordinat...
QPointF mapFromScene(const QPointF &point) const
Maps the given point in the scene's coordinate system to the equivalent point within this item's coor...
virtual Q_INVOKABLE bool contains(const QPointF &point) const
\qmlmethod bool QtQuick::Item::contains(point point)
QQuickItem * parentItem() const
QPointF position() const
void setKeepMouseGrab(bool)
Sets whether the mouse input should remain exclusively with this item.
bool isAncestorOf(const QQuickItem *child) const
Returns true if this item is an ancestor of child (i.e., if this item is child's parent,...
QPointF transformOriginPoint
Definition qquickitem.h:109
void onGrabChanged(QQuickPointerHandler *grabber, QPointingDevice::GrabTransition transition, QPointerEvent *event, QEventPoint &point) override
Notification that the grab has changed in some way which is relevant to this handler.
void handlePointerEventImpl(QPointerEvent *event) override
This function can be overridden to implement whatever behavior a specific subclass is intended to hav...
QList< QQuickHandlerPoint > & currentPoints()
bool wantsPointerEvent(QPointerEvent *event) override
It is the responsibility of this function to decide whether the event could be relevant at all to thi...
bool grabPoints(QPointerEvent *event, const QVector< QEventPoint > &points)
QQuickItem * parentItem() const
\qmlproperty Item QtQuick::PointerHandler::parent
void setPassiveGrab(QPointerEvent *event, const QEventPoint &point, bool grab=true)
Acquire or give up a passive grab of the given point, according to the grab state.
The QTouchEvent class contains parameters that describe a touch event.
Definition qevent.h:917
bool isEndEvent() const override
Returns true if this event includes at least one newly-released touchpoint.
Definition qevent.cpp:4543
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:502
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:501
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define M_PI
Definition qmath.h:209
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLenum mode
GLint GLsizei GLsizei height
GLint GLsizei width
GLfloat angle
GLenum target
struct _cl_event * event
GLfloat GLfloat p
[1]
static QT_BEGIN_NAMESPACE const qreal DragAngleToleranceDegrees
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define emit
double qreal
Definition qtypes.h:187