aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickevents.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickevents.cpp')
-rw-r--r--src/quick/items/qquickevents.cpp1636
1 files changed, 0 insertions, 1636 deletions
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index 66e850f59c..ab7b407af5 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -51,7 +51,6 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcPointerEvents, "qt.quick.pointer.events")
-Q_LOGGING_CATEGORY(lcPtrGrab, "qt.quick.pointer.grab")
/*!
\qmltype KeyEvent
@@ -470,1639 +469,4 @@ Item {
\l inverted always returns false.
*/
-/*!
- \qmltype PointerDevice
- \instantiates QPointingDevice
- \inqmlmodule QtQuick
- \ingroup qtquick-input-events
-
- \brief Provides information about a pointing device.
-
- A pointing device can be a mouse, a touchscreen, or a stylus on a graphics
- tablet.
-
- \sa PointerEvent, PointerHandler
-*/
-
-/*!
- \readonly
- \qmlproperty enumeration QtQuick::PointerDevice::type
-
- This property holds the type of the pointing device.
-
- Valid values are:
-
- \value DeviceType.Unknown
- the device cannot be identified
- \value DeviceType.Mouse
- a mouse
- \value DeviceType.TouchScreen
- a touchscreen providing absolute coordinates
- \value DeviceType.TouchPad
- a trackpad or touchpad providing relative coordinates
- \value DeviceType.Stylus
- a pen-like device
- \value DeviceType.Airbrush
- a stylus with a thumbwheel to adjust
- \l {QTabletEvent::tangentialPressure}{tangentialPressure}
- \value DeviceType.Puck
- a device that is similar to a flat mouse with a
- transparent circle with cross-hairs
- (same as \l {QTabletEvent::Puck} {Puck})
- \value DeviceType.AllDevices
- any of the above; used as a default value for construction
-
- \sa QPointingDevice::DeviceType
-*/
-
-/*!
- \readonly
- \qmlproperty enumeration QtQuick::PointerDevice::pointerType
-
- This property holds a value indicating what is interacting with
- the device. Think of the device as having a planar 2D surface, and
- the value of this property as identifying what interacts with the
- device.
-
- There is some redundancy between this property and \l {PointerDevice::type}.
- If a tocuchscreen is used, then the device is TouchScreen and
- pointerType is Finger (always).
-
- Valid values are:
-
- \value PointerDevice.Generic
- a mouse or something acting like a mouse (the core pointer on X11)
- \value PointerDevice.Finger
- the user's finger
- \value PointerDevice.Pen
- the drawing end of a stylus
- \value PointerDevice.Eraser
- the other end of the stylus (if it has a virtual eraser on the other end)
- \value PointerDevice.Cursor
- a cursor in the pre-computer sense of the word
- \value PointerDevice.AllPointerTypes
- any of the above (used as a default value in constructors)
-*/
-
-/*!
- \readonly
- \qmlproperty enumeration QtQuick::PointerDevice::capabilities
-
- This property holds a bitwise combination of the capabilities of the
- pointing device. It tells you under which conditions events are sent,
- and which properties of PointerEvent are expected to be valid.
-
- Valid values are:
-
- \value Capability.Position
- the \l {QtQuick::EventPoint::position}{position} and
- \l {QtQuick::EventPoint::scenePosition}{scenePosition} properties
- \value Capability.Area
- the \l {QtQuick::EventTouchPoint::ellipseDiameters}{ellipseDiameters} property
- \value Capability.Pressure
- the \l {QtQuick::EventTouchPoint::pressure}{pressure} property
- \value Capability.Velocity
- the \l {QtQuick::EventPoint::velocity}{velocity} property
- \value Capability.Scroll
- a \l {QtQuick::PointerDevice::type}{Mouse} has a wheel, or the
- operating system recognizes scroll gestures on a
- \l {QtQuick::PointerDevice::type}{TouchPad}
- \value Capability.Hover
- events are sent even when no button is pressed, or the finger or stylus
- is not in contact with the surface
- \value Capability.Rotation
- the \l {QtQuick::EventTouchPoint::rotation}{rotation} property
- \value Capability.XTilt
- horizontal angle between a stylus and the axis perpendicular to the surface
- \value Capability.YTilt
- vertical angle between a stylus and the axis perpendicular to the surface
-
- \sa QPointingDevice::capabilities
-*/
-
-
-// debugging helpers
-static const char *pointStateString(const QQuickEventPoint *point)
-{
- static const QMetaEnum stateMetaEnum = point->metaObject()->enumerator(point->metaObject()->indexOfEnumerator("State"));
- return stateMetaEnum.valueToKey(point->state());
-}
-
-static const QString pointDeviceName(const QQuickEventPoint *point)
-{
- auto device = static_cast<const QQuickPointerEvent *>(point->parent())->device();
- QString deviceName = (device ? device->name() : QLatin1String("null device"));
- deviceName.resize(16, u' '); // shorten, and align in case of sequential output
- return deviceName;
-}
-
-/*!
- \qmltype EventPoint
- \qmlabstract
- \instantiates QQuickEventPoint
- \inqmlmodule QtQuick
- \ingroup qtquick-input-events
- \brief Provides information about an individual point within a PointerEvent.
-
- A PointerEvent contains an EventPoint for each point of contact: one corresponding
- to the mouse cursor, or one for each finger touching a touchscreen.
-
- \sa PointerEvent, PointerHandler
-*/
-
-/*!
- \readonly
- \qmlproperty point QtQuick::EventPoint::position
-
- This property holds the coordinates of the position supplied by the event,
- relative to the upper-left corner of the Item which has the PointerHandler.
- If a contact patch is available from the pointing device, this point
- represents its centroid.
-*/
-
-/*!
- \readonly
- \qmlproperty point QtQuick::EventPoint::scenePosition
-
- This property holds the coordinates of the position supplied by the event,
- relative to the scene. If a contact patch is available from the
- \l {QtQuick::PointerEvent::device} {device}, this point represents its centroid.
-*/
-
-/*!
- \readonly
- \qmlproperty point QtQuick::EventPoint::scenePressPosition
-
- This property holds the scene-relative position at which the press event
- (on a touch device) or most recent change in QQuickPointerEvent::buttons()
- (on a mouse or tablet stylus) occurred.
-*/
-
-/*!
- \readonly
- \qmlproperty point QtQuick::EventPoint::sceneGrabPosition
-
- This property holds the scene-relative position at which the EventPoint was
- located when setGrabber() was called most recently.
-*/
-
-/*!
- \readonly
- \qmlproperty vector2d QtQuick::EventPoint::velocity
-
- This property holds average recent velocity: how fast and in which
- direction the event point has been moving recently.
-*/
-
-/*!
- \readonly
- \qmlproperty int QtQuick::EventPoint::state
-
- This property tells what the user is currently doing at this point.
-
- It can be one of:
- \value Pressed
- The user's finger is now pressing a touchscreen, button or stylus
- which was not pressed already
- \value Updated
- The touchpoint or position is being moved, with no change in pressed state
- \value Stationary
- The touchpoint or position is not being moved, and there is also
- no change in pressed state
- \value Released
- The user's finger has now released a touch point, button or stylus
- which was pressed
-*/
-
-/*!
- \readonly
- \qmlproperty int QtQuick::EventPoint::pointId
-
- This property holds the ID of the event, if any.
-
- Touchpoints have automatically-incrementing IDs: each time the user
- presses a finger against the touchscreen, it will be a larger number.
- In other cases, it will be -1.
-
- \sa {QtQuick::EventTouchPoint::uniqueId}{uniqueId}
-*/
-
-/*!
- \readonly
- \qmlproperty bool QtQuick::EventPoint::accepted
-
- Setting \a accepted to true prevents the event from being propagated to
- Items below the PointerHandler's Item.
-
- Generally, if the handler acts on the mouse event, then it should be
- accepted so that items lower in the stacking order do not also respond to
- the same event.
-*/
-
-/*!
- \readonly
- \qmlproperty real QtQuick::EventPoint::timeHeld
-
- This property holds the amount of time in seconds that the button or touchpoint has
- been held. It can be used to detect a "long press", and can drive an
- animation to show progress toward activation of the "long press" action.
-*/
-
-void QQuickEventPoint::reset(QEventPoint::State state, const QPointF &scenePos, int pointId, ulong timestamp, const QVector2D &velocity)
-{
- m_scenePos = scenePos;
- m_pointId = pointId;
- m_accept = false;
- m_state = static_cast<QQuickEventPoint::State>(state);
- m_timestamp = timestamp;
- if (state == QEventPoint::State::Pressed) {
- m_pressTimestamp = timestamp;
- m_scenePressPos = scenePos;
- }
- m_velocity = (Q_LIKELY(velocity.isNull()) ? estimatedVelocity() : velocity);
-}
-
-void QQuickEventPoint::localizePosition(QQuickItem *target)
-{
- if (target)
- m_pos = target->mapFromScene(scenePosition());
- else
- m_pos = QPointF();
-}
-
-/*!
- If this point has an exclusive grabber, returns a pointer to it; else
- returns null, if there is no grabber. The grabber could be either
- an Item or a PointerHandler.
-*/
-QObject *QQuickEventPoint::exclusiveGrabber() const
-{
- return m_exclusiveGrabber.data();
-}
-
-/*!
- Set the given Item or PointerHandler as the exclusive grabber of this point.
- If there was already an exclusive grab, it will be canceled. If there
- were passive grabbers, they will continue to lurk, but the exclusive grab
- is a behavioral override of the passive grab as long as it remains.
- If you already know whether the grabber is to be an Item or a PointerHandler,
- you should instead call setGrabberItem() or setGrabberPointerHandler(),
- because it is slightly more efficient.
-*/
-void QQuickEventPoint::setExclusiveGrabber(QObject *grabber)
-{
- if (QQuickPointerHandler *phGrabber = qmlobject_cast<QQuickPointerHandler *>(grabber))
- setGrabberPointerHandler(phGrabber, true);
- else
- setGrabberItem(static_cast<QQuickItem *>(grabber));
-}
-
-/*!
- If the exclusive grabber of this point is an Item, returns a
- pointer to that Item; else returns null, if there is no grabber or if
- the grabber is a PointerHandler.
-*/
-QQuickItem *QQuickEventPoint::grabberItem() const
-{
- return (m_grabberIsHandler ? nullptr : static_cast<QQuickItem *>(m_exclusiveGrabber.data()));
-}
-
-/*!
- Set the given Item \a grabber as the exclusive grabber of this point.
- If there was already an exclusive grab, it will be canceled. If there
- were passive grabbers, they will continue to lurk, but the exclusive grab
- is a behavioral override of the passive grab as long as it remains.
-*/
-void QQuickEventPoint::setGrabberItem(QQuickItem *grabber)
-{
- if (grabber != m_exclusiveGrabber.data()) {
- QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler();
- if (oldGrabberHandler && !oldGrabberHandler->approveGrabTransition(this, grabber))
- return;
- if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) {
- qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this) << "@" << m_scenePos
- << ": grab" << m_exclusiveGrabber << "->" << grabber;
- }
- QQuickItem *oldGrabberItem = grabberItem();
- m_exclusiveGrabber = QPointer<QObject>(grabber);
- m_grabberIsHandler = false;
- m_sceneGrabPos = m_scenePos;
- if (oldGrabberHandler) {
- oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this);
- } else if (oldGrabberItem && oldGrabberItem != grabber && grabber && grabber->window()) {
- QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(grabber->window());
- windowPriv->sendUngrabEvent(oldGrabberItem, windowPriv->isDeliveringTouchAsMouse());
- }
- if (grabber) {
- for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers)
- if (passiveGrabber)
- passiveGrabber->onGrabChanged(passiveGrabber, OverrideGrabPassive, this);
- }
- }
-}
-
-/*!
- If the exclusive grabber of this point is a PointerHandler, returns a
- pointer to that handler; else returns null, if there is no grabber or if
- the grabber is an Item.
-*/
-QQuickPointerHandler *QQuickEventPoint::grabberPointerHandler() const
-{
- return (m_grabberIsHandler ? static_cast<QQuickPointerHandler *>(m_exclusiveGrabber.data()) : nullptr);
-}
-
-/*!
- Set the given PointerHandler \a grabber as grabber of this point. If \a
- exclusive is true, it will override any other grabs; if false, \a grabber
- will be added to the list of passive grabbers of this point.
-*/
-void QQuickEventPoint::setGrabberPointerHandler(QQuickPointerHandler *grabber, bool exclusive)
-{
- if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) {
- if (exclusive) {
- if (m_exclusiveGrabber != grabber)
- qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
- << ": grab (exclusive)" << m_exclusiveGrabber << "->" << grabber;
- } else {
- qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
- << ": grab (passive)" << grabber;
- }
- }
- if (exclusive) {
- if (grabber != m_exclusiveGrabber.data()) {
- QQuickPointerHandler *oldGrabberHandler = grabberPointerHandler();
- QQuickItem *oldGrabberItem = grabberItem();
- m_exclusiveGrabber = QPointer<QObject>(grabber);
- m_grabberIsHandler = true;
- m_sceneGrabPos = m_scenePos;
- if (grabber) {
- grabber->onGrabChanged(grabber, GrabExclusive, this);
- for (QPointer<QQuickPointerHandler> passiveGrabber : m_passiveGrabbers) {
- if (!passiveGrabber.isNull() && passiveGrabber != grabber)
- passiveGrabber->onGrabChanged(grabber, OverrideGrabPassive, this);
- }
- }
- if (oldGrabberHandler) {
- oldGrabberHandler->onGrabChanged(oldGrabberHandler, (grabber ? CancelGrabExclusive : UngrabExclusive), this);
- } else if (oldGrabberItem) {
- if (pointerEvent()->asPointerTouchEvent())
- oldGrabberItem->touchUngrabEvent();
- else if (pointerEvent()->asPointerMouseEvent())
- oldGrabberItem->mouseUngrabEvent();
- }
- // touchUngrabEvent() can result in the grabber being set to null (MPTA does that, for example).
- // So set it again to ensure that final state is what we want.
- m_exclusiveGrabber = QPointer<QObject>(grabber);
- m_grabberIsHandler = true;
- m_sceneGrabPos = m_scenePos;
- }
- } else {
- if (!grabber) {
- qDebug() << "can't set passive grabber to null";
- return;
- }
- auto ptr = QPointer<QQuickPointerHandler>(grabber);
- if (!m_passiveGrabbers.contains(ptr)) {
- m_passiveGrabbers.append(ptr);
- grabber->onGrabChanged(grabber, GrabPassive, this);
- }
- }
-}
-
-/*!
- If this point has an existing exclusive grabber (Item or PointerHandler),
- inform the grabber that its grab is canceled, and remove it as grabber.
- This normally happens when the grab is stolen by another Item.
-*/
-void QQuickEventPoint::cancelExclusiveGrab()
-{
- if (m_exclusiveGrabber.isNull())
- qWarning("cancelGrab: no grabber");
- else
- cancelExclusiveGrabImpl();
-}
-
-void QQuickEventPoint::cancelExclusiveGrabImpl(QTouchEvent *cancelEvent)
-{
- if (m_exclusiveGrabber.isNull())
- return;
- if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) {
- qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
- << ": grab (exclusive)" << m_exclusiveGrabber << "-> nullptr";
- }
- if (auto handler = grabberPointerHandler()) {
- handler->onGrabChanged(handler, CancelGrabExclusive, this);
- } else if (auto item = grabberItem()) {
- if (cancelEvent)
- QCoreApplication::sendEvent(item, cancelEvent);
- else
- item->touchUngrabEvent();
- }
- m_exclusiveGrabber.clear();
-}
-
-/*!
- If this point has the given \a handler as a passive grabber,
- inform the grabber that its grab is canceled, and remove it as grabber.
- This normally happens when another Item or PointerHandler does an exclusive grab.
-*/
-void QQuickEventPoint::cancelPassiveGrab(QQuickPointerHandler *handler)
-{
- if (removePassiveGrabber(handler)) {
- if (Q_UNLIKELY(lcPtrGrab().isDebugEnabled())) {
- qCDebug(lcPtrGrab) << pointDeviceName(this) << "point" << Qt::hex << m_pointId << pointStateString(this)
- << ": grab (passive)" << handler << "removed";
- }
- handler->onGrabChanged(handler, CancelGrabPassive, this);
- }
-}
-
-/*!
- If this point has the given \a handler as a passive grabber, remove it as grabber.
- Returns true if it was removed, false if it wasn't a grabber.
-*/
-bool QQuickEventPoint::removePassiveGrabber(QQuickPointerHandler *handler)
-{
- return m_passiveGrabbers.removeOne(handler);
-}
-
-/*!
- If the given \a handler is grabbing this point passively, exclusively
- or both, cancel the grab and remove it as grabber.
- This normally happens when the handler decides that the behavior of this
- point can no longer satisfy the handler's behavioral constraints within
- the remainder of the gesture which the user is performing: for example
- the handler tries to detect a tap but a drag is occurring instead, or
- it tries to detect a drag in one direction but the drag is going in
- another direction. In such cases the handler no longer needs or wants
- to be informed of any further movements of this point.
-*/
-void QQuickEventPoint::cancelAllGrabs(QQuickPointerHandler *handler)
-{
- if (m_exclusiveGrabber == handler) {
- handler->onGrabChanged(handler, CancelGrabExclusive, this);
- m_exclusiveGrabber.clear();
- }
- cancelPassiveGrab(handler);
-}
-
-/*!
- Sets this point as \a accepted (true) or rejected (false).
-
- During delivery of the current event to the Items in the scene, each Item
- or Pointer Handler should accept the points for which it is taking
- responsibility. As soon as all points within the event are accepted, event
- propagation stops. However accepting the point does not imply any kind of
- grab, passive or exclusive.
-
- \sa setExclusiveGrabber, QQuickPointerHandler::setPassiveGrab, QQuickPointerHandler::setExclusiveGrab
-*/
-void QQuickEventPoint::setAccepted(bool accepted)
-{
- if (m_accept != accepted) {
- qCDebug(lcPointerEvents) << this << m_accept << "->" << accepted;
- m_accept = accepted;
- }
-}
-
-
-/*!
- \qmltype EventTouchPoint
- \qmlabstract
- \instantiates QQuickEventTouchPoint
- \inqmlmodule QtQuick
- \ingroup qtquick-input-events
- \brief Provides information about an individual touch point within a PointerEvent.
-
- \sa PointerEvent, PointerHandler
-*/
-
-/*!
- \readonly
- \qmlproperty QPointerUniqueId QtQuick::EventTouchPoint::uniqueId
-
- This property holds the unique ID of the fiducial or stylus in use, if any.
-
- On touchscreens that can track physical objects (such as knobs or game
- pieces) in addition to fingers, each object usually has a unique ID.
- Likewise, each stylus that can be used with a graphics tablet usually has a
- unique serial number. Qt so far only supports numeric IDs. You can get the
- actual number as uniqueId.numeric, but that is a device-specific detail.
- In the future, there may be support for non-numeric IDs, so you should
- not assume that the number is meaningful.
-
- If you need to identify specific objects, your application should provide
- UI for registering objects and mapping them to functionality: allow the
- user to select a meaning, virtual tool, or action, prompt the user to bring
- the object into proximity, and store a mapping from uniqueId to its
- purpose, for example in \l Settings.
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::EventTouchPoint::rotation
-
- This property holds the rotation angle of the stylus on a graphics tablet
- or the contact patch of a touchpoint on a touchscreen.
-
- It is valid only with certain tablet stylus devices and touchscreens that
- can measure the rotation angle. Otherwise, it will be zero.
-*/
-
-/*!
- \readonly
- \qmlproperty qreal QtQuick::EventTouchPoint::pressure
-
- This property tells how hard the user is pressing the stylus on a graphics
- tablet or the finger against a touchscreen, in the range from \c 0 (no
- measurable pressure) to \c 1.0 (maximum pressure which the device can
- measure).
-
- It is valid only with certain tablets and touchscreens that can measure
- pressure. Otherwise, it will be \c 1.0 when pressed.
-*/
-
-/*!
- \readonly
- \qmlproperty size QtQuick::EventTouchPoint::ellipseDiameters
-
- This property holds the diameters of the contact patch, if the event
- comes from a touchpoint and the \l {QtQuick::PointerEvent::device} {device}
- provides this information.
-
- A touchpoint is modeled as an elliptical area where the finger is
- pressed against the touchscreen. (In fact, it could also be
- modeled as a bitmap; but in that case we expect an elliptical
- bounding estimate to be fitted to the contact patch before the
- event is sent.) The harder the user presses, the larger the
- contact patch; so, these diameters provide an alternate way of
- detecting pressure, in case the device does not include a separate
- pressure sensor. The ellipse is centered on
- \l {QtQuick::EventPoint::scenePosition} {scenePosition}
- (\l {QtQuick::EventPoint::position} {position} in the PointerHandler's
- Item's local coordinates). The \l rotation property provides the
- rotation of the ellipse, if known. It is expected that if the
- \l rotation is zero, the verticalDiameter of the ellipse is the
- larger one (the major axis), because of the usual hand position,
- reaching upward or outward across the surface.
-
- If the contact patch is unknown, or the \l {QtQuick::PointerEvent::device} {device}
- is not a touchscreen, these values will be zero.
-*/
-
-QQuickEventTouchPoint::QQuickEventTouchPoint(QQuickPointerTouchEvent *parent)
- : QQuickEventPoint(parent), m_rotation(0), m_pressure(0)
-{}
-
-void QQuickEventTouchPoint::reset(const QEventPoint &tp, ulong timestamp)
-{
- QQuickEventPoint::reset(tp.state(), tp.scenePosition(), tp.id(), timestamp, tp.velocity());
- m_exclusiveGrabber.clear();
- m_passiveGrabbers.clear();
- m_rotation = tp.rotation();
- m_pressure = tp.pressure();
- m_ellipseDiameters = tp.ellipseDiameters();
- m_uniqueId = tp.uniqueId();
-}
-
-struct PointVelocityData {
- QVector2D velocity;
- QPointF pos;
- ulong timestamp = 0;
-};
-
-typedef QMap<quint64, PointVelocityData> PointDataForPointIdMap;
-Q_GLOBAL_STATIC(PointDataForPointIdMap, g_previousPointData)
-static const int PointVelocityAgeLimit = 500; // milliseconds
-
-/*!
- \internal
- Estimates the velocity based on a weighted average of all previous velocities.
- The older the velocity is, the less significant it becomes for the estimate.
-*/
-QVector2D QQuickEventPoint::estimatedVelocity() const
-{
- auto prevPointIt = g_previousPointData->find(m_pointId);
- auto end = g_previousPointData->end();
- if (prevPointIt == end) {
- // cleanup events older than PointVelocityAgeLimit
- for (auto it = g_previousPointData->begin(); it != end; ) {
- if (m_timestamp - it->timestamp > PointVelocityAgeLimit)
- it = g_previousPointData->erase(it);
- else
- ++it;
- }
- prevPointIt = g_previousPointData->insert(m_pointId, PointVelocityData());
- }
-
- auto &prevPoint = prevPointIt.value();
- const ulong timeElapsed = m_timestamp - prevPoint.timestamp;
- if (timeElapsed == 0) // in case we call estimatedVelocity() twice on the same QQuickEventPoint
- return m_velocity;
-
- QVector2D newVelocity;
- if (prevPoint.timestamp != 0)
- newVelocity = QVector2D(m_scenePos - prevPoint.pos) / timeElapsed;
-
- // VERY simple kalman filter: does a weighted average
- // where the older velocities get less and less significant
- static const float KalmanGain = 0.7f;
- QVector2D filteredVelocity = newVelocity * KalmanGain + m_velocity * (1.0f - KalmanGain);
-
- prevPoint.velocity = filteredVelocity;
- prevPoint.pos = m_scenePos;
- prevPoint.timestamp = m_timestamp;
- return filteredVelocity;
-}
-
-/*!
- \qmltype PointerEvent
- \instantiates QQuickPointerEvent
- \inqmlmodule QtQuick
- \ingroup qtquick-input-events
-
- \brief Provides information about an event from a pointing device.
-
- A PointerEvent is an event describing contact or movement across a surface,
- provided by a mouse, a touchpoint (single finger on a touchscreen), or a
- stylus on a graphics tablet. The \l {QtQuick::PointerEvent::device} {device}
- property provides more information about where the event came from.
-
- \sa PointerHandler
-
- \image touchpoint-metrics.png
-*/
-
-/*!
- \internal
- \class QQuickPointerEvent
-
- QQuickPointerEvent is used as a long-lived object to store data related to
- an event from a pointing device, such as a mouse, touch or tablet event,
- during event delivery. It also provides properties which may be used later
- to expose the event to QML, the same as is done with QQuickMouseEvent,
- QQuickTouchPoint, QQuickKeyEvent, etc. Since only one event can be
- delivered at a time, this class is effectively a singleton. We don't worry
- about the QObject overhead because the instances are long-lived: we don't
- dynamically create and destroy objects of this type for each event.
-*/
-
-/*!
- \readonly
- \qmlproperty enumeration QtQuick::PointerEvent::button
-
- This property holds the \l {Qt::MouseButton}{button} that caused the event,
- if any. If the \l {QtQuick::PointerEvent::device} {device} does not have
- buttons, or the event is a hover event, it will be \c Qt.NoButton.
-*/
-
-/*!
- \readonly
- \qmlproperty int QtQuick::PointerEvent::buttons
-
- This property holds the combination of mouse or stylus
- \l {Qt::MouseButton}{buttons} pressed when the event was generated. For move
- events, this is all buttons that are pressed down. For press events, this
- includes the button that caused the event, as well as any others that were
- already held. For release events, this excludes the button that caused the
- event.
-*/
-
-/*!
- \readonly
- \qmlproperty int QtQuick::PointerEvent::modifiers
-
- This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} flags
- that existed immediately before the event occurred.
-
- It contains a bitwise combination of the following flags:
- \value Qt.NoModifier
- No modifier key is pressed.
- \value Qt.ShiftModifier
- A Shift key on the keyboard is pressed.
- \value Qt.ControlModifier
- A Ctrl key on the keyboard is pressed.
- \value Qt.AltModifier
- An Alt key on the keyboard is pressed.
- \value Qt.MetaModifier
- A Meta key on the keyboard is pressed.
- \value Qt.KeypadModifier
- A keypad button is pressed.
-
- For example, to react to a Shift key + Left mouse button click:
- \qml
- Item {
- TapHandler {
- onTapped: {
- if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier))
- doSomething();
- }
- }
- }
- \endqml
-*/
-
-/*!
- \readonly
- \qmlproperty PointerDevice QtQuick::PointerEvent::device
-
- This property holds the device that generated the event.
-*/
-
-QQuickPointerEvent::~QQuickPointerEvent()
-{}
-
-QQuickPointerMouseEvent::QQuickPointerMouseEvent(QObject *parent, const QPointingDevice *device)
- : QQuickSinglePointEvent(parent, device)
-{
- m_point = new QQuickEventPoint(this);
-}
-
-QQuickPointerEvent *QQuickPointerMouseEvent::reset(QEvent *event)
-{
- auto ev = static_cast<QMouseEvent*>(event);
- m_event = ev;
- if (!event)
- return this;
-
- QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear();
- m_button = ev->button();
- m_pressedButtons = ev->buttons();
- QEventPoint::State state = QEventPoint::State::Stationary;
- switch (ev->type()) {
- case QEvent::MouseButtonPress:
- m_point->clearPassiveGrabbers();
- Q_FALLTHROUGH();
- case QEvent::MouseButtonDblClick:
- state = QEventPoint::State::Pressed;
- break;
- case QEvent::MouseButtonRelease:
- state = QEventPoint::State::Released;
- break;
- case QEvent::MouseMove:
- state = QEventPoint::State::Updated;
- break;
- default:
- break;
- }
- m_point->reset(state, ev->scenePosition(), ev->point(0).id(), ev->timestamp());
- return this;
-}
-
-void QQuickSinglePointEvent::localize(QQuickItem *target)
-{
- m_point->localizePosition(target);
-}
-
-QQuickPointerEvent *QQuickPointerTouchEvent::reset(QEvent *event)
-{
- auto ev = static_cast<QTouchEvent*>(event);
- m_event = ev;
- if (!event)
- return this;
-
- QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear();
- m_button = Qt::NoButton;
- m_pressedButtons = Qt::NoButton;
-
- const QList<QEventPoint> &tps = ev->touchPoints();
- int newPointCount = tps.count();
- m_touchPoints.reserve(newPointCount);
-
- for (int i = m_touchPoints.size(); i < newPointCount; ++i)
- m_touchPoints.insert(i, new QQuickEventTouchPoint(this));
-
- // Make sure the grabbers and on-pressed values are right from one event to the next
- struct ToPreserve {
- int pointId; // just for double-checking
- ulong pressTimestamp;
- QPointF scenePressPos;
- QPointF sceneGrabPos;
- QObject * grabber;
- QVector <QPointer <QQuickPointerHandler> > passiveGrabbers;
-
- ToPreserve() : pointId(0), pressTimestamp(0), grabber(nullptr) {}
- };
- QVector<ToPreserve> preserves(newPointCount); // jar of pickled touchpoints, in order of points in the _new_ event
-
- // Copy stuff we need to preserve, because the order of points might have changed in the event.
- // The ID is all that we can rely on (release might remove the first point etc).
- for (int i = 0; i < newPointCount; ++i) {
- int pid = tps.at(i).id();
- if (auto point = pointById(pid)) {
- preserves[i].pointId = pid;
- preserves[i].pressTimestamp = point->m_pressTimestamp;
- preserves[i].scenePressPos = point->scenePressPosition();
- preserves[i].sceneGrabPos = point->sceneGrabPosition();
- preserves[i].grabber = point->exclusiveGrabber();
- preserves[i].passiveGrabbers = point->passiveGrabbers();
- }
- }
-
- for (int i = 0; i < newPointCount; ++i) {
- auto point = m_touchPoints.at(i);
- point->reset(tps.at(i), ev->timestamp());
- const auto &preserved = preserves.at(i);
- if (point->state() == QQuickEventPoint::Pressed) {
- if (preserved.grabber)
- qWarning() << "TouchPointPressed without previous release event" << point;
- point->setGrabberItem(nullptr);
- point->clearPassiveGrabbers();
- } else {
- // Restore the grabbers without notifying (don't call onGrabChanged)
- Q_ASSERT(preserved.pointId == 0 || preserved.pointId == point->pointId());
- point->m_pressTimestamp = preserved.pressTimestamp;
- point->m_scenePressPos = preserved.scenePressPos;
- point->m_sceneGrabPos = preserved.sceneGrabPos;
- point->m_exclusiveGrabber = preserved.grabber;
- point->m_grabberIsHandler = (qmlobject_cast<QQuickPointerHandler *>(point->m_exclusiveGrabber) != nullptr);
- point->m_passiveGrabbers = preserved.passiveGrabbers;
- }
- }
- m_pointCount = newPointCount;
- return this;
-}
-
-void QQuickPointerTouchEvent::localize(QQuickItem *target)
-{
- for (auto point : qAsConst(m_touchPoints))
- point->localizePosition(target);
-}
-
-#if QT_CONFIG(gestures)
-QQuickPointerNativeGestureEvent::QQuickPointerNativeGestureEvent(QObject *parent, const QPointingDevice *device)
- : QQuickSinglePointEvent(parent, device)
-{
- m_point = new QQuickEventPoint(this);
-}
-
-QQuickPointerEvent *QQuickPointerNativeGestureEvent::reset(QEvent *event)
-{
- auto ev = static_cast<QNativeGestureEvent*>(event);
- m_event = ev;
- if (!event)
- return this;
-
- QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear();
- QEventPoint::State state = QEventPoint::State::Updated;
- switch (type()) {
- case Qt::BeginNativeGesture:
- state = QEventPoint::State::Pressed;
- break;
- case Qt::EndNativeGesture:
- state = QEventPoint::State::Released;
- break;
- default:
- break;
- }
- m_point->reset(state, ev->scenePosition(), ev->point(0).id(), ev->timestamp());
- return this;
-}
-#endif // QT_CONFIG(gestures)
-
-QQuickEventPoint *QQuickSinglePointEvent::point(int i) const
-{
- if (i == 0)
- return m_point;
- return nullptr;
-}
-
-
-/*!
- \qmltype PointerScrollEvent
- \instantiates QQuickPointerScrollEvent
- \inqmlmodule QtQuick
- \ingroup qtquick-input-events
- \brief Provides information about a scrolling event, such as from a mouse wheel.
-
- \sa WheelHandler
-*/
-
-/*!
- \internal
- \class QQuickPointerScrollEvent
-*/
-
-/*!
- \readonly
- \qmlproperty PointerDevice QtQuick::PointerScrollEvent::device
-
- This property holds the device that generated the event.
-*/
-
-/*!
- \qmlproperty int QtQuick::PointerScrollEvent::buttons
-
- This property holds the mouse buttons pressed when the wheel event was generated.
-
- It contains a bitwise combination of:
- \list
- \li \l {Qt::LeftButton} {Qt.LeftButton}
- \li \l {Qt::RightButton} {Qt.RightButton}
- \li \l {Qt::MiddleButton} {Qt.MiddleButton}
- \endlist
-*/
-
-/*!
- \readonly
- \qmlproperty int QtQuick::PointerScrollEvent::modifiers
-
- This property holds the \l {Qt::KeyboardModifier}{keyboard modifier} keys
- that were pressed immediately before the event occurred.
-
- It contains a bitwise combination of the following flags:
- \value Qt.NoModifier
- No modifier key is pressed.
- \value Qt.ShiftModifier
- A Shift key on the keyboard is pressed.
- \value Qt.ControlModifier
- A Ctrl key on the keyboard is pressed.
- \value Qt.AltModifier
- An Alt key on the keyboard is pressed.
- \value Qt.MetaModifier
- A Meta key on the keyboard is pressed.
- \value Qt.KeypadModifier
- A keypad button is pressed.
-
- For example, to react to a Shift key + Left mouse button click:
- \qml
- Item {
- TapHandler {
- onTapped: {
- if ((event.button == Qt.LeftButton) && (event.modifiers & Qt.ShiftModifier))
- doSomething();
- }
- }
- }
- \endqml
-*/
-
-/*!
- \qmlproperty point QtQuick::PointerScrollEvent::angleDelta
-
- This property holds the distance that the wheel is rotated in wheel degrees.
- The x and y cordinate of this property holds the delta in horizontal and
- vertical orientation.
-
- A positive value indicates that the wheel was rotated up/right;
- a negative value indicates that the wheel was rotated down/left.
-
- Most mouse types work in steps of 15 degrees, in which case the delta value is a
- multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
-*/
-
-/*!
- \qmlproperty point QtQuick::PointerScrollEvent::pixelDelta
-
- This property holds the delta in screen pixels and is available in platforms that
- have high-resolution trackpads, such as \macos.
- The x and y coordinates of this property hold the delta in horizontal and
- vertical orientation. The value should be used directly to scroll content on screen.
-
- For platforms without high-resolution touchpad support, pixelDelta will
- always be (0,0), and angleDelta should be used instead.
-*/
-
-/*!
- \qmlproperty bool QtQuick::PointerScrollEvent::hasAngleDelta
-
- Returns whether the \l angleDelta property has a non-null value.
-*/
-
-/*!
- \qmlproperty bool QtQuick::PointerScrollEvent::hasPixelDelta
-
- Returns whether the \l pixelDelta property has a non-null value.
-*/
-
-/*!
- \qmlproperty bool QtQuick::PointerScrollEvent::inverted
-
- Returns whether the delta values delivered with the event are inverted.
-
- Normally, a vertical wheel will produce a PointerScrollEvent with positive delta
- values if the top of the wheel is rotating away from the hand operating it.
- Similarly, a horizontal wheel movement will produce a PointerScrollEvent with
- positive delta values if the top of the wheel is moved to the left.
-
- However, on some platforms this is configurable, so that the same
- operations described above will produce negative delta values (but with the
- same magnitude). In a QML component (such as a tumbler or a slider) where
- it is appropriate to synchronize the movement or rotation of an item with
- the direction of the wheel, regardless of the system settings, the wheel
- event handler can use the inverted property to decide whether to negate the
- \l angleDelta or \l pixelDelta values.
-
- \note Many platforms provide no such information. On such platforms,
- \c inverted always returns false.
-*/
-QQuickPointerScrollEvent::QQuickPointerScrollEvent(QObject *parent, const QPointingDevice *device)
- : QQuickSinglePointEvent(parent, device)
-{
- m_point = new QQuickEventPoint(this);
-}
-
-QQuickPointerEvent *QQuickPointerScrollEvent::reset(QEvent *event)
-{
- m_event = static_cast<QPointerEvent*>(event);
- if (!event)
- return this;
-#if QT_CONFIG(wheelevent)
- if (event->type() == QEvent::Wheel) {
- auto ev = static_cast<QWheelEvent*>(event);
- QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear();
- // m_button = Qt::NoButton;
- m_pressedButtons = ev->buttons();
- m_angleDelta = QVector2D(ev->angleDelta());
- m_pixelDelta = QVector2D(ev->pixelDelta());
- m_phase = ev->phase();
- m_synthSource = ev->source();
- m_inverted = ev->inverted();
- m_point->reset(QEventPoint::State::Updated, ev->position(), ev->point(0).id(), ev->timestamp());
- }
-#endif
- // TODO else if (event->type() == QEvent::Scroll) ...
- return this;
-}
-
-void QQuickPointerScrollEvent::localize(QQuickItem *target)
-{
- m_point->localizePosition(target);
-}
-
-QQuickEventPoint *QQuickPointerTouchEvent::point(int i) const
-{
- if (i >= 0 && i < m_pointCount)
- return m_touchPoints.at(i);
- return nullptr;
-}
-
-QQuickEventPoint::QQuickEventPoint(QQuickPointerEvent *parent)
- : QObject(parent), m_pointId(0), m_exclusiveGrabber(nullptr), m_timestamp(0), m_pressTimestamp(0),
- m_state(QQuickEventPoint::Released), m_accept(false), m_grabberIsHandler(false)
-{
- Q_UNUSED(m_reserved);
-}
-
-QQuickPointerEvent *QQuickEventPoint::pointerEvent() const
-{
- return static_cast<QQuickPointerEvent *>(parent());
-}
-
-bool QQuickSinglePointEvent::allPointsAccepted() const
-{
- return m_point->isAccepted();
-}
-
-bool QQuickSinglePointEvent::allUpdatedPointsAccepted() const
-{
- return m_point->state() == QQuickEventPoint::Pressed || m_point->isAccepted();
-}
-
-bool QQuickSinglePointEvent::allPointsGrabbed() const
-{
- return m_point->exclusiveGrabber() != nullptr;
-}
-
-QMouseEvent *QQuickPointerMouseEvent::asMouseEvent(const QPointF &localPos) const
-{
- if (!m_event)
- return nullptr;
- static_cast<QMutableSinglePointEvent *>(m_event)->mutablePoint().setPosition(localPos);
- return static_cast<QMouseEvent *>(m_event);
-}
-
-/*!
- Returns the exclusive grabber of this event, if any, in a vector.
-*/
-QVector<QObject *> QQuickSinglePointEvent::exclusiveGrabbers() const
-{
- QVector<QObject *> result;
- if (QObject *grabber = m_point->exclusiveGrabber())
- result << grabber;
- return result;
-}
-
-/*!
- Remove all passive and exclusive grabbers of this event, without notifying.
-*/
-void QQuickSinglePointEvent::clearGrabbers() const
-{
- m_point->setGrabberItem(nullptr);
- m_point->clearPassiveGrabbers();
-}
-
-/*!
- Returns whether the given \a handler is the exclusive grabber of this event.
-*/
-bool QQuickSinglePointEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
-{
- return handler && (m_point->exclusiveGrabber() == handler);
-}
-
-bool QQuickPointerMouseEvent::isPressEvent() const
-{
- if (!m_event)
- return false;
- auto me = static_cast<QMouseEvent*>(m_event);
- return ((me->type() == QEvent::MouseButtonPress || me->type() == QEvent::MouseButtonDblClick) &&
- (me->buttons() & me->button()) == me->buttons());
-}
-
-bool QQuickPointerMouseEvent::isDoubleClickEvent() const
-{
- if (!m_event)
- return false;
- auto me = static_cast<QMouseEvent*>(m_event);
- return (me->type() == QEvent::MouseButtonDblClick);
-}
-
-bool QQuickPointerMouseEvent::isUpdateEvent() const
-{
- if (!m_event)
- return false;
- auto me = static_cast<QMouseEvent*>(m_event);
- return me->type() == QEvent::MouseMove;
-}
-
-bool QQuickPointerMouseEvent::isReleaseEvent() const
-{
- if (!m_event)
- return false;
- auto me = static_cast<QMouseEvent*>(m_event);
- return me && me->type() == QEvent::MouseButtonRelease;
-}
-
-bool QQuickPointerTouchEvent::allPointsAccepted() const
-{
- for (int i = 0; i < m_pointCount; ++i) {
- if (!m_touchPoints.at(i)->isAccepted())
- return false;
- }
- return true;
-}
-
-bool QQuickPointerTouchEvent::allUpdatedPointsAccepted() const
-{
- for (int i = 0; i < m_pointCount; ++i) {
- auto point = m_touchPoints.at(i);
- if (point->state() != QQuickEventPoint::Pressed && !point->isAccepted())
- return false;
- }
- return true;
-}
-
-bool QQuickPointerTouchEvent::allPointsGrabbed() const
-{
- for (int i = 0; i < m_pointCount; ++i) {
- if (!m_touchPoints.at(i)->exclusiveGrabber())
- return false;
- }
- return true;
-}
-
-/*!
- Returns the exclusive grabbers of all points in this event, if any, in a vector.
-*/
-QVector<QObject *> QQuickPointerTouchEvent::exclusiveGrabbers() const
-{
- QVector<QObject *> result;
- for (int i = 0; i < m_pointCount; ++i) {
- if (QObject *grabber = m_touchPoints.at(i)->exclusiveGrabber()) {
- if (!result.contains(grabber))
- result << grabber;
- }
- }
- return result;
-}
-
-/*!
- Remove all passive and exclusive grabbers of all touchpoints in this event,
- without notifying.
-*/
-void QQuickPointerTouchEvent::clearGrabbers() const
-{
- for (auto point: m_touchPoints) {
- point->setGrabberItem(nullptr);
- point->clearPassiveGrabbers();
- }
-}
-
-QEventPoint::States QQuickPointerTouchEvent::touchPointStates() const
-{
- return m_event
- ? static_cast<QTouchEvent*>(m_event)->touchPointStates()
- : QEventPoint::States();
-}
-
-/*!
- Returns whether the given \a handler is the exclusive grabber of any
- touchpoint within this event.
-*/
-bool QQuickPointerTouchEvent::hasExclusiveGrabber(const QQuickPointerHandler *handler) const
-{
- for (auto point: m_touchPoints)
- if (point->exclusiveGrabber() == handler)
- return true;
- return false;
-}
-
-bool QQuickPointerTouchEvent::isPressEvent() const
-{
- return touchPointStates() & QEventPoint::State::Pressed;
-}
-
-bool QQuickPointerTouchEvent::isUpdateEvent() const
-{
- return touchPointStates() & (QEventPoint::State::Updated | QEventPoint::State::Stationary);
-}
-
-bool QQuickPointerTouchEvent::isReleaseEvent() const
-{
- return touchPointStates() & QEventPoint::State::Released;
-}
-
-QVector<QPointF> QQuickPointerEvent::unacceptedPressedPointScenePositions() const
-{
- QVector<QPointF> points;
- for (int i = 0; i < pointCount(); ++i) {
- if (!point(i)->isAccepted() && point(i)->state() == QQuickEventPoint::Pressed)
- points << point(i)->scenePosition();
- }
- return points;
-}
-
-/*!
- \internal
- Populate the reusable synth-mouse event from one touchpoint.
- It's required that isTouchEvent() be true when this is called.
- If the touchpoint cannot be found, this returns nullptr.
- Ownership of the event is NOT transferred to the caller.
-*/
-QMouseEvent *QQuickPointerTouchEvent::syntheticMouseEvent(int pointID, QQuickItem *relativeTo) const
-{
- const QEventPoint *p = touchPointById(pointID);
- if (!p)
- return nullptr;
- QEvent::Type type;
- Qt::MouseButton buttons = Qt::LeftButton;
- switch (p->state()) {
- case QEventPoint::State::Pressed:
- type = QEvent::MouseButtonPress;
- break;
- case QEventPoint::State::Updated:
- case QEventPoint::State::Stationary:
- type = QEvent::MouseMove;
- break;
- case QEventPoint::State::Released:
- type = QEvent::MouseButtonRelease;
- buttons = Qt::NoButton;
- break;
- default:
- Q_ASSERT(false);
- return nullptr;
- }
- m_synthMouseEvent = QMouseEvent(type, relativeTo->mapFromScene(p->scenePosition()),
- p->scenePosition(), p->globalPosition(), Qt::LeftButton, buttons, m_event->modifiers(),
- Qt::MouseEventSynthesizedByQt, device());
- m_synthMouseEvent.setAccepted(true);
- m_synthMouseEvent.setTimestamp(m_event->timestamp());
- // ### Qt 6: try to always have valid velocity in every QEventPoint (either from the platform, or synthesized in QtGui).
- // QQuickFlickablePrivate::handleMouseMoveEvent() checks for QInputDevice::Capability::Velocity
- // and if it is set, then it does not need to do its own velocity calculations.
- // But because m_synthMouseEvent gets the same device() where the (usually) touch event came from,
- // the capability won't be set, in practice, until we have the velocity in place.
- QMutableSinglePointEvent::from(m_synthMouseEvent).mutablePoint().setVelocity(p->velocity());
- return &m_synthMouseEvent;
-}
-
-#if QT_CONFIG(tabletevent)
-QQuickPointerTabletEvent::QQuickPointerTabletEvent(QObject *parent, const QPointingDevice *device)
- : QQuickSinglePointEvent(parent, device)
-{
- m_point = new QQuickEventTabletPoint(this);
-}
-
-QQuickPointerEvent *QQuickPointerTabletEvent::reset(QEvent *event)
-{
- auto ev = static_cast<QTabletEvent*>(event);
- m_event = ev;
- if (!event)
- return this;
-
- QQuickPointerHandlerPrivate::deviceDeliveryTargets(ev->device()).clear();
- m_button = ev->button();
- m_pressedButtons = ev->buttons();
- static_cast<QQuickEventTabletPoint *>(m_point)->reset(ev);
- return this;
-}
-
-QQuickEventTabletPoint::QQuickEventTabletPoint(QQuickPointerTabletEvent *parent)
- : QQuickEventPoint(parent)
-{
-}
-
-void QQuickEventTabletPoint::reset(const QTabletEvent *ev)
-{
- QEventPoint::State state = QEventPoint::State::Stationary;
- switch (ev->type()) {
- case QEvent::TabletPress:
- state = QEventPoint::State::Pressed;
- clearPassiveGrabbers();
- break;
- case QEvent::TabletRelease:
- state = QEventPoint::State::Released;
- break;
- case QEvent::TabletMove:
- state = QEventPoint::State::Updated;
- break;
- default:
- break;
- }
- QQuickEventPoint::reset(state, ev->position(), 1, ev->timestamp());
- m_rotation = ev->rotation();
- m_pressure = ev->pressure();
- m_tangentialPressure = ev->tangentialPressure();
- m_tilt = QVector2D(ev->xTilt(), ev->yTilt());
-}
-
-bool QQuickPointerTabletEvent::isPressEvent() const
-{
- auto me = static_cast<QTabletEvent *>(m_event);
- return me->type() == QEvent::TabletPress;
-}
-
-bool QQuickPointerTabletEvent::isUpdateEvent() const
-{
- auto me = static_cast<QTabletEvent *>(m_event);
- return me->type() == QEvent::TabletMove;
-}
-
-bool QQuickPointerTabletEvent::isReleaseEvent() const
-{
- auto me = static_cast<QTabletEvent *>(m_event);
- return me->type() == QEvent::TabletRelease;
-}
-
-QTabletEvent *QQuickPointerTabletEvent::asTabletEvent() const
-{
- return static_cast<QTabletEvent *>(m_event);
-}
-#endif // QT_CONFIG(tabletevent)
-
-#if QT_CONFIG(gestures)
-bool QQuickPointerNativeGestureEvent::isPressEvent() const
-{
- return type() == Qt::BeginNativeGesture;
-}
-
-bool QQuickPointerNativeGestureEvent::isUpdateEvent() const
-{
- switch (type()) {
- case Qt::BeginNativeGesture:
- case Qt::EndNativeGesture:
- return false;
- default:
- return true;
- }
-}
-
-bool QQuickPointerNativeGestureEvent::isReleaseEvent() const
-{
- return type() == Qt::EndNativeGesture;
-}
-
-Qt::NativeGestureType QQuickPointerNativeGestureEvent::type() const
-{
- return static_cast<QNativeGestureEvent *>(m_event)->gestureType();
-}
-
-qreal QQuickPointerNativeGestureEvent::value() const
-{
- return static_cast<QNativeGestureEvent *>(m_event)->value();
-}
-#endif // QT_CONFIG(gestures)
-
-/*!
- Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
- which provide phase information, this is true when the fingers are placed
- on the touchpad and scrolling begins. On other devices where this
- information is not available, it remains false.
-*/
-bool QQuickPointerScrollEvent::isPressEvent() const
-{
- return phase() == Qt::ScrollBegin;
-}
-
-/*!
- Returns true when the scroll event has Qt::ScrollUpdate phase, or when the
- phase is unknown. Some multi-touch-capable touchpads and trackpads provide
- phase information; whereas ordinary mouse wheels and other types of
- trackpads do not, and in such cases this is always true.
-*/
-bool QQuickPointerScrollEvent::isUpdateEvent() const
-{
- return phase() == Qt::ScrollUpdate || phase() == Qt::NoScrollPhase;
-}
-
-/*!
- Returns whether the scroll event has Qt::ScrollBegin phase. On touchpads
- which provide phase information, this is true when the fingers are lifted
- from the touchpad. On other devices where this information is not
- available, it remains false.
-*/
-bool QQuickPointerScrollEvent::isReleaseEvent() const
-{
- return phase() == Qt::ScrollEnd;
-}
-
-/*!
- \internal
- Returns a pointer to the QQuickEventPoint which has the \a pointId as
- \l {QQuickEventPoint::pointId}{pointId}.
- Returns nullptr if there is no point with that ID.
-
- \fn QQuickPointerEvent::pointById(int pointId) const
-*/
-QQuickEventPoint *QQuickSinglePointEvent::pointById(int pointId) const
-{
- if (m_point && pointId == m_point->pointId())
- return m_point;
- return nullptr;
-}
-
-QQuickEventPoint *QQuickPointerTouchEvent::pointById(int pointId) const
-{
- auto it = std::find_if(m_touchPoints.constBegin(), m_touchPoints.constEnd(),
- [pointId](const QQuickEventTouchPoint *tp) { return tp->pointId() == pointId; } );
- if (it != m_touchPoints.constEnd())
- return *it;
- return nullptr;
-}
-
-/*!
- \internal
- Returns a pointer to the original TouchPoint which has the same
- \l {QEventPoint::id}{id} as \a pointId, if the original event is a
- QTouchEvent, and if that point is found. Otherwise, returns nullptr.
-*/
-const QEventPoint *QQuickPointerTouchEvent::touchPointById(int pointId) const
-{
- const QTouchEvent *ev = asTouchEvent();
- if (!ev)
- return nullptr;
- const QList<QEventPoint> &tps = ev->touchPoints();
- auto it = std::find_if(tps.constBegin(), tps.constEnd(),
- [pointId](QEventPoint const& tp) { return tp.id() == pointId; } );
- // return the pointer to the actual TP in QTouchEvent::_touchPoints
- return (it == tps.constEnd() ? nullptr : &*it);
-}
-
-/*!
- \internal
- Make a new QTouchEvent, giving it a subset of the original touch points.
-
- Returns a nullptr if all points are stationary, or there are no points inside the item,
- or none of the points were pressed inside and the item was not grabbing any of them
- and isFiltering is false. When isFiltering is true, it is assumed that the item
- cares about all points which are inside its bounds, because most filtering items
- need to monitor eventpoint movements until a drag threshold is exceeded or the
- requirements for a gesture to be recognized are met in some other way.
-*/
-QTouchEvent *QQuickPointerTouchEvent::touchEventForItem(QQuickItem *item, bool isFiltering) const
-{
- QList<QEventPoint> touchPoints;
- QEventPoint::States eventStates; // TODO maybe avoid accumulating this, since the touchevent ctor doesn't need it
- // TODO maybe add QQuickItem::mapVector2DFromScene(QVector2D) to avoid needing QQuickItemPrivate here
- // Or else just document that velocity is always scene-relative and is not scaled and rotated with the item
- // but that would require changing tst_qquickwindow::touchEvent_velocity(): it expects transformed velocity
-
- bool anyPressOrReleaseInside = false;
- bool anyStationaryWithModifiedPropertyInside = false;
- bool anyGrabber = false;
- QMatrix4x4 transformMatrix(QQuickItemPrivate::get(item)->windowToItemTransform());
- for (int i = 0; i < m_pointCount; ++i) {
- auto p = m_touchPoints.at(i);
- if (p->isAccepted())
- continue;
- // include points where item is the grabber
- bool isGrabber = p->exclusiveGrabber() == item;
- if (isGrabber)
- anyGrabber = true;
- // include points inside the bounds if no other item is the grabber or if the item is filtering
- bool isInside = item->contains(item->mapFromScene(p->scenePosition()));
- bool hasAnotherGrabber = p->exclusiveGrabber() && p->exclusiveGrabber() != item;
-
- // filtering: (childMouseEventFilter) include points that are grabbed by children of the target item
- bool grabberIsChild = false;
- auto parent = p->grabberItem();
- while (isFiltering && parent) {
- if (parent == item) {
- grabberIsChild = true;
- break;
- }
- parent = parent->parentItem();
- }
-
- bool filterRelevant = isFiltering && grabberIsChild;
- if (!(isGrabber || (isInside && (!hasAnotherGrabber || isFiltering)) || filterRelevant))
- continue;
- if ((p->state() == QQuickEventPoint::Pressed || p->state() == QQuickEventPoint::Released) && isInside)
- anyPressOrReleaseInside = true;
- // we don't use QMutableEventPoint::from() because it's fine to have const here
- const QMutableEventPoint *tp = static_cast<const QMutableEventPoint *>(touchPointById(p->pointId()));
- if (tp) {
- if (isInside && tp->stationaryWithModifiedProperty())
- anyStationaryWithModifiedPropertyInside = true;
- eventStates |= tp->state();
- QMutableEventPoint tpCopy(*tp);
- tpCopy.setPosition(item->mapFromScene(tp->scenePosition()));
- tpCopy.setVelocity(transformMatrix.mapVector(tpCopy.velocity()).toVector2D());
- touchPoints << tpCopy;
- }
- }
-
- // Now touchPoints will have only points which are inside the item.
- // But if none of them were just pressed inside, and the item has no other reason to care, ignore them anyway.
- if ((eventStates == QEventPoint::State::Stationary && !anyStationaryWithModifiedPropertyInside) ||
- touchPoints.isEmpty() || (!anyPressOrReleaseInside && !anyGrabber && !isFiltering))
- return nullptr;
-
- // if all points have the same state, set the event type accordingly
- const QTouchEvent &event = *asTouchEvent();
- QEvent::Type eventType = event.type();
- switch (eventStates) {
- case QEventPoint::State::Pressed:
- eventType = QEvent::TouchBegin;
- break;
- case QEventPoint::State::Released:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
- }
-
- QMutableTouchEvent *touchEvent = new QMutableTouchEvent(eventType, event.pointingDevice(),
- event.modifiers(), touchPoints);
- touchEvent->setTarget(item);
- touchEvent->setTimestamp(event.timestamp());
- touchEvent->accept();
- return touchEvent;
-}
-
-QTouchEvent *QQuickPointerTouchEvent::asTouchEvent() const
-{
- return static_cast<QTouchEvent *>(m_event);
-}
-
-#ifndef QT_NO_DEBUG_STREAM
-
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickPointerEvent *event)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- if (!event) {
- dbg << "QQuickPointerEvent(0)";
- return dbg;
- }
- dbg << "QQuickPointerEvent(";
- dbg << event->timestamp();
- if (event->device()) {
- dbg << " dev:";
- QtDebugUtils::formatQEnum(dbg, event->device()->type());
- dbg << " " << event->device()->name();
- } else {
- dbg << " dev: null";
- }
- if (event->buttons() != Qt::NoButton) {
- dbg << " buttons:";
- QtDebugUtils::formatQEnum(dbg, event->buttons());
- }
- dbg << " [";
- int c = event->pointCount();
- for (int i = 0; i < c; ++i)
- dbg << event->point(i) << ' ';
- dbg << "])";
- return dbg;
-}
-
-Q_QUICK_PRIVATE_EXPORT QDebug operator<<(QDebug dbg, const QQuickEventPoint *event)
-{
- QDebugStateSaver saver(dbg);
- dbg.nospace();
- if (!event) {
- dbg << "QQuickEventPoint(0)";
- return dbg;
- }
- dbg << "QQuickEventPoint(accepted:" << event->isAccepted()
- << " state:";
- QtDebugUtils::formatQEnum(dbg, event->state());
- dbg << " scenePos:" << event->scenePosition() << " id:" << Qt::hex << event->pointId() << Qt::dec
- << " timeHeld:" << event->timeHeld() << ')';
- return dbg;
-}
-
-#endif
-
QT_END_NAMESPACE