Move QEventPoint and QPointingDeviceUniqueId out of qevent

qevent.h/cpp are huge already, no need for more classes. Move QEventPoint
into new qeventpoint.h/cpp files, and QPointingDeviceUniqueId into
qpointingdevice.cpp; the class is already declared in qpointingdevice.h.

Move the documentation of QEventPoint APIs next to the implementation,
and document all APIs as properties. Add Q_PROPERTY macro where missing.

QEventPoint::device needs a workaround of qdoc due to the type being a
pointer-to-const; qdoc doesn't know how to tie a \property to it, but
documents it correctly.

While at it, move the logging category declarations to the header
matching the .cpp file where they are defined.

Change-Id: I096e609edbb760b5686d577e7fe47eea0807904e
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
bb10
Volker Hilsheimer 2020-11-05 18:11:56 +01:00
parent 1c6d6cbb62
commit bdec189ecb
13 changed files with 1140 additions and 894 deletions

View File

@ -35,6 +35,7 @@ qt_internal_add_module(Gui
image/qxpmhandler.cpp image/qxpmhandler_p.h
kernel/qclipboard.cpp kernel/qclipboard.h
kernel/qcursor.cpp kernel/qcursor.h kernel/qcursor_p.h
kernel/qeventpoint.cpp kernel/qeventpoint.h kernel/qeventpoint_p.h
kernel/qevent.cpp kernel/qevent.h kernel/qevent_p.h
kernel/qgenericplugin.cpp kernel/qgenericplugin.h
kernel/qgenericpluginfactory.cpp kernel/qgenericpluginfactory.h

View File

@ -86,6 +86,7 @@ qt_internal_add_module(Gui
image/qxpmhandler.cpp image/qxpmhandler_p.h
kernel/qclipboard.cpp kernel/qclipboard.h
kernel/qcursor.cpp kernel/qcursor.h kernel/qcursor_p.h
kernel/qeventpoint.cpp kernel/qeventpoint.h kernel/qeventpoint_p.h
kernel/qevent.cpp kernel/qevent.h kernel/qevent_p.h
kernel/qgenericplugin.cpp kernel/qgenericplugin.h
kernel/qgenericpluginfactory.cpp kernel/qgenericpluginfactory.h

View File

@ -48,6 +48,8 @@ HEADERS += \
kernel/qcursor_p.h \
kernel/qevent.h \
kernel/qevent_p.h \
kernel/qeventpoint.h \
kernel/qeventpoint_p.h \
kernel/qinputdevice.h \
kernel/qinputdevice_p.h \
kernel/qinputmethod.h \
@ -108,6 +110,7 @@ SOURCES += \
kernel/qclipboard.cpp \
kernel/qcursor.cpp \
kernel/qevent.cpp \
kernel/qeventpoint.cpp \
kernel/qinputdevice.cpp \
kernel/qinputmethod.cpp \
kernel/qinternalmimedata.cpp \

View File

@ -61,10 +61,6 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcPointerGrab, "qt.pointer.grab")
Q_LOGGING_CATEGORY(lcPointerVel, "qt.pointer.velocity")
Q_LOGGING_CATEGORY(lcEPDetach, "qt.pointer.eventpoint.detach")
/*!
\class QEnterEvent
\ingroup events
@ -225,392 +221,6 @@ QInputEvent::~QInputEvent()
Sets the timestamp for this event.
*/
/*!
\internal
Constructs an invalid event point with the given \a id and the \a device
from which it originated.
This acts as a default constructor in usages like QMap<int, QEventPoint>,
as in qgraphicsscene_p.h.
*/
QEventPoint::QEventPoint(int id, const QPointingDevice *device)
: d(new QEventPointPrivate(id, device)) {}
/*!
Constructs an event point with the given \a pointId, \a state,
\a scenePosition and \a globalPosition.
*/
QEventPoint::QEventPoint(int pointId, State state, const QPointF &scenePosition, const QPointF &globalPosition)
: d(new QEventPointPrivate(pointId, state, scenePosition, globalPosition)) {}
/*!
Constructs an event point by making a shallow copy of \a other.
*/
QEventPoint::QEventPoint(const QEventPoint &other)
: d(other.d)
{
if (d)
d->refCount++;
}
/*!
Assigns \a other to this event point and returns a reference to this
event point.
*/
QEventPoint &QEventPoint::operator=(const QEventPoint &other)
{
if (other.d)
other.d->refCount++;
if (d && !(--d->refCount))
delete d;
d = other.d;
return *this;
}
/*!
\fn QEventPoint::QEventPoint(QEventPoint &&other) noexcept
Constructs an event point by moving \a other.
*/
/*!
\fn QEventPoint &QEventPoint::operator=(QEventPoint &&other) noexcept
Move-assigns \a other to this event point instance.
*/
/*!
Returns \c true if this event point is equal to \a other, otherwise
return \c false.
*/
bool QEventPoint::operator==(const QEventPoint &other) const noexcept
{
if (d == other.d)
return true;
if (!d || !other.d)
return false;
return *d == *other.d;
}
/*!
\fn bool QEventPoint::operator!=(const QEventPoint &other) const noexcept
Returns \c true if this event point is not equal to \a other, otherwise
return \c false.
*/
/*!
Destroys the event point.
*/
QEventPoint::~QEventPoint()
{
if (d && !(--d->refCount))
delete d;
}
QPointF QEventPoint::position() const
{ return d->pos; }
QPointF QEventPoint::pressPosition() const
{ return d->globalPressPos - d->globalPos + d->pos; }
QPointF QEventPoint::grabPosition() const
{ return d->globalGrabPos - d->globalPos + d->pos; }
QPointF QEventPoint::lastPosition() const
{ return d->globalLastPos - d->globalPos + d->pos; }
QPointF QEventPoint::scenePosition() const
{ return d->scenePos; }
QPointF QEventPoint::scenePressPosition() const
{ return d->globalPressPos - d->globalPos + d->scenePos; }
QPointF QEventPoint::sceneGrabPosition() const
{ return d->globalGrabPos - d->globalPos + d->scenePos; }
QPointF QEventPoint::sceneLastPosition() const
{ return d->globalLastPos - d->globalPos + d->scenePos; }
QPointF QEventPoint::globalPosition() const
{ return d->globalPos; }
QPointF QEventPoint::globalPressPosition() const
{ return d->globalPressPos; }
QPointF QEventPoint::globalGrabPosition() const
{ return d->globalGrabPos; }
QPointF QEventPoint::globalLastPosition() const
{ return d->globalLastPos; }
QVector2D QEventPoint::velocity() const
{ return d->velocity; }
QEventPoint::State QEventPoint::state() const
{ return d->state; }
const QPointingDevice *QEventPoint::device() const
{ return d->device; }
int QEventPoint::id() const
{ return d->pointId; }
QPointingDeviceUniqueId QEventPoint::uniqueId() const
{ return d->uniqueId; }
ulong QEventPoint::timestamp() const
{ return d->timestamp; }
ulong QEventPoint::pressTimestamp() const
{ return d->pressTimestamp; }
qreal QEventPoint::timeHeld() const
{ return (d->timestamp - d->pressTimestamp) / qreal(1000); }
qreal QEventPoint::pressure() const
{ return d->pressure; }
qreal QEventPoint::rotation() const
{ return d->rotation; }
QSizeF QEventPoint::ellipseDiameters() const
{ return d->ellipseDiameters; }
bool QEventPoint::isAccepted() const
{ return d->accept; }
/*!
Returns the time from the previous QPointerEvent that contained this point.
\sa globalLastPosition()
*/
ulong QEventPoint::lastTimestamp() const
{ return d->lastTimestamp; }
/*!
Sets the accepted state of the point to \a accepted.
In widget-based applications, this function is not used so far, because
it's only meaningful for a widget to accept or reject a complete QInputEvent.
In Qt Quick however, it's normal for an Item or Event Handler to accept
only the individual points in a QTouchEvent that are actually participating
in a gesture, while other points can be delivered to other items or
handlers. For the sake of consistency, that applies to any QPointerEvent;
and delivery is done only when all points in a QPointerEvent have been
accepted.
\sa QEvent::setAccepted()
*/
void QEventPoint::setAccepted(bool accepted)
{
d->accept = accepted;
}
/*!
\obsolete
\fn QPointF QPointerEvent::normalizedPos() const
Deprecated since Qt 6.0. Use normalizedPosition() instead.
*/
/*!
Returns the normalized position of this point.
The coordinates are calculated by transforming globalPosition() into the
space of QInputDevice::availableVirtualGeometry(), i.e. \c (0, 0) is the
top-left corner and \c (1, 1) is the bottom-right corner.
\sa globalPosition()
*/
QPointF QEventPoint::normalizedPosition() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalPosition() - geom.topLeft()) / geom.width();
}
/*!
\obsolete
Deprecated since Qt 6.0. Use globalPressPosition() instead.
Returns the normalized press position of this point.
*/
QPointF QEventPoint::startNormalizedPos() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalPressPosition() - geom.topLeft()) / geom.width();
}
/*!
\obsolete
Deprecated since Qt 6.0. Use globalLastPosition() instead.
Returns the normalized position of this point from the previous press or
move event.
The coordinates are normalized to QInputDevice::availableVirtualGeometry(),
i.e. \c (0, 0) is the top-left corner and \c (1, 1) is the bottom-right corner.
\sa normalizedPos(), startNormalizedPos()
*/
QPointF QEventPoint::lastNormalizedPos() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalLastPosition() - geom.topLeft()) / geom.width();
}
/*! \internal
This class is explicitly shared, which means if you construct an event and
then the point(s) that it holds are modified before the event is delivered,
the event will be seen to hold the modified points. The workaround is that
any code which modifies an eventpoint that could already be included in an
event, or code that wants to save an eventpoint for later, has
responsibility to detach before calling any setters, so as to hold and
modify an independent copy. (The independent copy can then be used in a
subsequent event.) If detaching is unnecessary, because refCount shows that
there is only one QEventPoint referring to the QEventPointPrivate instance,
this function does nothing.
*/
void QMutableEventPoint::detach()
{
if (d->refCount == 1)
return; // no need: there is only one QEventPoint using it
qCDebug(lcEPDetach) << "detaching: refCount" << d->refCount << this;
auto old = d;
d = new QEventPointPrivate(*d);
d->refCount = 1;
--old->refCount;
}
/*! \internal
Update current state from the given \a other point, assuming that this
instance contains state from the previous event and \a other contains new
values that came in from a device.
That is: global position and other valuators will be updated, but
the following properties will not be updated:
\list
\li other properties that are not likely to be set after a fresh touchpoint
has been received from a device
\li properties that should be persistent between events (such as grabbers)
\endlist
*/
void QMutableEventPoint::updateFrom(const QEventPoint &other)
{
detach();
setPressure(other.pressure());
switch (other.state()) {
case QEventPoint::State::Pressed:
setGlobalPressPosition(other.globalPosition());
setGlobalLastPosition(other.globalPosition());
if (pressure() < 0)
setPressure(1);
break;
case QEventPoint::State::Released:
if (globalPosition() != other.globalPosition())
setGlobalLastPosition(globalPosition());
setPressure(0);
break;
default: // update or stationary
if (globalPosition() != other.globalPosition())
setGlobalLastPosition(globalPosition());
if (pressure() < 0)
setPressure(1);
break;
}
setState(other.state());
setPosition(other.position());
setScenePosition(other.scenePosition());
setGlobalPosition(other.globalPosition());
setEllipseDiameters(other.ellipseDiameters());
setRotation(other.rotation());
setVelocity(other.velocity());
}
/*! \internal
Set the timestamp from the event that updated this point's positions,
and calculate a new value for velocity().
The velocity calculation is done here because none of the QPointerEvent
subclass constructors take the timestamp directly, and because
QGuiApplication traditionally constructs an event first and then sets its
timestamp (see for example QGuiApplicationPrivate::processMouseEvent()).
This function looks up the corresponding instance in QPointingDevicePrivate::activePoints,
and assumes that its timestamp() still holds the previous time when this point
was updated, its velocity() holds this point's last-known velocity, and
its globalPosition() and globalLastPosition() hold this point's current
and previous positions, respectively. We assume timestamps are in milliseconds.
The velocity calculation is skipped if the platform has promised to
provide velocities already by setting the QInputDevice::Velocity capability.
*/
void QMutableEventPoint::setTimestamp(const ulong t)
{
// On mouse press, if the mouse has moved from its last-known location,
// QGuiApplicationPrivate::processMouseEvent() sends first a mouse move and
// then a press. Both events will get the same timestamp. So we need to set
// the press timestamp and position even when the timestamp isn't advancing,
// but skip setting lastTimestamp and velocity because those need a time delta.
if (state() == QEventPoint::State::Pressed) {
d->pressTimestamp = t;
d->globalPressPos = d->globalPos;
}
if (d->timestamp == t)
return;
detach();
if (device()) {
// get the persistent instance out of QPointingDevicePrivate::activePoints
// (which sometimes might be the same as this instance)
QEventPointPrivate *pd = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(d->device))->pointById(id())->eventPoint.d;
if (t > pd->timestamp) {
pd->lastTimestamp = pd->timestamp;
pd->timestamp = t;
if (state() == QEventPoint::State::Pressed)
pd->pressTimestamp = t;
if (pd->lastTimestamp > 0 && !device()->capabilities().testFlag(QInputDevice::Capability::Velocity)) {
// calculate instantaneous velocity according to time and distance moved since the previous point
QVector2D newVelocity = QVector2D(pd->globalPos - pd->globalLastPos) / (t - pd->lastTimestamp) * 1000;
// VERY simple kalman filter: does a weighted average
// where the older velocities get less and less significant
static const float KalmanGain = 0.7f;
pd->velocity = newVelocity * KalmanGain + pd->velocity * (1.0f - KalmanGain);
qCDebug(lcPointerVel) << "velocity" << newVelocity << "filtered" << pd->velocity <<
"based on movement" << pd->globalLastPos << "->" << pd->globalPos <<
"over time" << pd->lastTimestamp << "->" << pd->timestamp;
}
if (d != pd) {
d->lastTimestamp = pd->lastTimestamp;
d->velocity = pd->velocity;
}
}
}
d->timestamp = t;
}
/*! \internal
void QMutableEventPoint::setPosition(const QPointF &pos)
Sets the localized position.
Often events need to be localized before delivery to specific widgets or
items. This can be done directly, or in a copy (for which we have a copy
constructor), depending on whether the original point needs to be retained.
Usually it's calculated by mapping scenePosition() to the target anyway.
*/
/*!
\class QPointerEvent
\since 6.0
@ -868,7 +478,7 @@ void QPointerEvent::clearPassiveGrabbers(const QEventPoint &point)
Returns the position of the point in this event, relative to the window or
scene.
\sa QEventPoint::scenePosition()
\sa QEventPoint::scenePosition
*/
/*! \fn QPointF QSinglePointEvent::globalPosition() const
@ -4843,177 +4453,6 @@ bool QTouchEvent::isEndEvent() const
\sa QPointerEvent::point(), QPointerEvent::pointCount()
*/
/*! \class QEventPoint
\brief The QEventPoint class provides information about a point in a QPointerEvent.
\since 6.0
\inmodule QtGui
*/
/*!
\enum QEventPoint::State
Specifies the state of this event point.
\value Unknown
Unknown state.
\value Stationary
The event point did not move.
\value Pressed
The touch point or button is pressed.
\value Updated
The event point was updated.
\value Released
The touch point or button was released.
*/
/*! \fn int QEventPoint::id() const
Returns the ID number of this event point.
\note Do not assume that ID numbers start at zero or that they are
sequential. Such an assumption is often false due to the way
the underlying drivers work.
*/
/*! \fn QPointingDeviceUniqueId QEventPoint::uniqueId() const
Returns the unique ID of this point or token, if any.
It is often invalid (see \l {QPointingDeviceUniqueId::isValid()} {isValid()}),
because touchscreens cannot uniquely identify fingers.
When it comes from a QTabletEvent, it identifies the serial number of the
stylus in use.
It may identify a specific token (fiducial object) when the TUIO driver is
in use with a touchscreen that supports them.
*/
/*! \fn QEventPoint::State QEventPoint::state() const
Returns the current state of this point.
*/
/*! \fn QPointF QEventPoint::position() const
Returns the position of this point, relative to the widget
or item that received the event.
*/
/*! \fn QPointF QEventPoint::pos() const
\obsolete
Deprecated since Qt 6.0. Use position() instead.
Returns the position of this point, relative to the widget
or item that received the event.
*/
/*! \fn QPointF QEventPoint::scenePosition() const
Returns the position of this point relative to the window or scene.
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePressPosition(), position(), globalPosition()
*/
/*! \fn QPointF QEventPoint::globalPosition() const
Returns the position of this point on the screen or virtual desktop.
\sa globalPressPosition(), position(), scenePosition()
*/
/*! \fn QPointF QEventPoint::pressPosition() const
Returns the position at which this point was pressed, relative to the
widget or item that received the event.
\sa position()
*/
/*! \fn QPointF QEventPoint::scenePressPosition() const
Returns the scene position at which this point was pressed.
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePosition(), pressPosition(), globalPressPosition()
*/
/*! \fn QPointF QEventPoint::globalPressPosition() const
Returns the position at which this point was pressed on the screen or virtual desktop.
\sa globalPosition(), pressPosition(), scenePressPosition()
*/
/*! \fn QPointF QEventPoint::lastPosition() const
Returns the position of this point from the previous press or move event,
relative to the widget or QGraphicsItem that received the event.
\sa position(), pressPosition()
*/
/*! \fn QPointF QEventPoint::sceneLastPosition() const
Returns the scene position of this point from the previous press or move event.
The scene position is the position in QGraphicsScene coordinates
if the QTouchEvent is handled by a QGraphicsItem::touchEvent()
reimplementation, and identical to the screen position for
widgets.
\sa scenePosition(), scenePressPosition()
*/
/*! \fn qreal QEventPoint::pressure() const
Returns the pressure of this point. The return value is in
the range \c 0.0 to \c 1.0.
*/
/*! \fn qreal QEventPoint::rotation() const
Returns the angular orientation of this point. The return value is in degrees,
where zero (the default) indicates the finger, token or stylus is pointing upwards,
a negative angle means it's rotated to the left, and a positive angle means
it's rotated to the right. Most touchscreens do not detect rotation, so
zero is the most common value.
*/
/*! \fn QSizeF QEventPoint::ellipseDiameters() const
Returns the width and height of the bounding ellipse of the touch point.
The return value is in logical pixels. Most touchscreens do not detect the
shape of the contact point, and no mice or tablet devices can detect it,
so a null size is the most common value. On some touchscreens the diameters
may be nonzero and always equal (the ellipse is approximated as a circle).
*/
/*!
\fn QVector2D QEventPoint::velocity() const
Returns a velocity vector, in units of pixels per second, in the coordinate
system of the screen or desktop.
\note If the device's capabilities include QInputDevice::Velocity, it means
velocity comes from the operating system (perhaps the touch hardware or
driver provides it). But usually the \c Velocity capability is not set,
indicating that the velocity is calculated by Qt, using a simple Kalman
filter to provide a smoothed average velocity rather than an instantaneous
value. Effectively it tells how fast and in what direction the user has
been dragging this point over the last few events, with the most recent
event having the strongest influence.
\sa QInputDevice::capabilities(), QInputEvent::device()
*/
/*! \fn ulong QEventPoint::timestamp() const
Returns the most recent time at which this point was included in a QPointerEvent.
\sa QPointerEvent::timestamp()
*/
/*!
\class QScrollPrepareEvent
\since 4.8
@ -5256,91 +4695,6 @@ void QMutableTouchEvent::addPoint(const QEventPoint &point)
m_touchPointStates |= point.state();
}
/*!
\class QPointingDeviceUniqueId
\since 5.8
\ingroup events
\inmodule QtGui
\brief QPointingDeviceUniqueId identifies a unique object, such as a tagged token
or stylus, which is used with a pointing device.
QPointingDeviceUniqueIds can be compared for equality, and can be used as keys in a QHash.
You get access to the numerical ID via numericId(), if the device supports such IDs.
For future extensions, though, you should not use that function, but compare objects
of this type using the equality operator.
This class is a thin wrapper around an integer ID. You pass it into and out of
functions by value.
\sa QEventPoint
*/
/*!
\fn QPointingDeviceUniqueId::QPointingDeviceUniqueId()
Constructs an invalid unique pointer ID.
*/
/*!
Constructs a unique pointer ID from numeric ID \a id.
*/
QPointingDeviceUniqueId QPointingDeviceUniqueId::fromNumericId(qint64 id)
{
QPointingDeviceUniqueId result;
result.m_numericId = id;
return result;
}
/*!
\fn bool QPointingDeviceUniqueId::isValid() const
Returns whether this unique pointer ID is valid, that is, it represents an actual
pointer.
*/
/*!
\property QPointingDeviceUniqueId::numericId
\brief the numeric unique ID of the token represented by a touchpoint
If the device provides a numeric ID, isValid() returns true, and this
property provides the numeric ID;
otherwise it is -1.
You should not use the value of this property in portable code, but
instead rely on equality to identify pointers.
\sa isValid()
*/
qint64 QPointingDeviceUniqueId::numericId() const noexcept
{
return m_numericId;
}
/*!
\fn bool QPointingDeviceUniqueId::operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
\since 5.8
Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer
(\c true) or not (\c false).
*/
/*!
\fn bool QPointingDeviceUniqueId::operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
\since 5.8
Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers
(\c true) or not (\c false).
*/
/*!
\relates QPointingDeviceUniqueId
\since 5.8
Returns the hash value for \a key, using \a seed to seed the calculation.
*/
size_t qHash(QPointingDeviceUniqueId key, size_t seed) noexcept
{
return qHash(key.numericId(), seed);
}
QT_END_NAMESPACE

View File

@ -50,9 +50,9 @@
#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
#include <QtCore/qvariant.h>
#include <QtGui/qeventpoint.h>
#include <QtGui/qpointingdevice.h>
#include <QtGui/qregion.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qwindowdefs.h>
#if QT_CONFIG(shortcut)
@ -93,114 +93,6 @@ protected:
qint64 m_extra = 0; // reserved, unused for now
};
struct QEventPointPrivate;
class Q_GUI_EXPORT QEventPoint
{
Q_GADGET
Q_PROPERTY(const QPointingDevice *device READ device)
Q_PROPERTY(int id READ id)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId)
Q_PROPERTY(State state READ state)
Q_PROPERTY(ulong timestamp READ timestamp)
Q_PROPERTY(qreal timeHeld READ timeHeld)
Q_PROPERTY(qreal pressure READ pressure)
Q_PROPERTY(qreal rotation READ rotation)
Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters)
Q_PROPERTY(QVector2D velocity READ velocity)
Q_PROPERTY(QPointF position READ position)
Q_PROPERTY(QPointF scenePosition READ scenePosition)
Q_PROPERTY(QPointF globalPosition READ globalPosition)
public:
enum State : quint8 {
Unknown = Qt::TouchPointUnknownState,
Stationary = Qt::TouchPointStationary,
Pressed = Qt::TouchPointPressed,
Updated = Qt::TouchPointMoved,
Released = Qt::TouchPointReleased
};
Q_DECLARE_FLAGS(States, State)
Q_FLAG(States)
QEventPoint(int id = -1, const QPointingDevice *device = nullptr);
QEventPoint(int pointId, State state, const QPointF &scenePosition, const QPointF &globalPosition);
QEventPoint(const QEventPoint &other);
QEventPoint(QEventPoint && other) noexcept : d(std::move(other.d)) { other.d = nullptr; }
QEventPoint &operator=(const QEventPoint &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QEventPoint)
bool operator==(const QEventPoint &other) const noexcept;
inline bool operator!=(const QEventPoint &other) const noexcept { return !operator==(other); }
~QEventPoint();
inline void swap(QEventPoint &other) noexcept
{ qSwap(d, other.d); }
QPointF position() const;
QPointF pressPosition() const;
QPointF grabPosition() const;
QPointF lastPosition() const;
QPointF scenePosition() const;
QPointF scenePressPosition() const;
QPointF sceneGrabPosition() const;
QPointF sceneLastPosition() const;
QPointF globalPosition() const;
QPointF globalPressPosition() const;
QPointF globalGrabPosition() const;
QPointF globalLastPosition() const;
QPointF normalizedPosition() const;
#if QT_DEPRECATED_SINCE(6, 0)
// QEventPoint replaces QTouchEvent::TouchPoint, so we need all its old accessors, for now
QT_DEPRECATED_VERSION_X_6_0("Use position()")
QPointF pos() const { return position(); }
QT_DEPRECATED_VERSION_X_6_0("Use pressPosition()")
QPointF startPos() const { return pressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use scenePosition()")
QPointF scenePos() const { return scenePosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use scenePressPosition()")
QPointF startScenePos() const { return scenePressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPosition()")
QPointF screenPos() const { return globalPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPressPosition()")
QPointF startScreenPos() const { return globalPressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPressPosition()")
QPointF startNormalizedPos() const;
QT_DEPRECATED_VERSION_X_6_0("Use normalizedPosition()")
QPointF normalizedPos() const { return normalizedPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use lastPosition()")
QPointF lastPos() const { return lastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use sceneLastPosition()")
QPointF lastScenePos() const { return sceneLastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalLastPosition()")
QPointF lastScreenPos() const { return globalLastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalLastPosition()")
QPointF lastNormalizedPos() const;
#endif // QT_DEPRECATED_SINCE(6, 0)
QVector2D velocity() const;
State state() const;
const QPointingDevice *device() const;
int id() const;
QPointingDeviceUniqueId uniqueId() const;
ulong timestamp() const;
ulong lastTimestamp() const;
ulong pressTimestamp() const;
qreal timeHeld() const;
qreal pressure() const;
qreal rotation() const;
QSizeF ellipseDiameters() const;
bool isAccepted() const;
void setAccepted(bool accepted = true);
private:
QEventPointPrivate *d;
friend class QMutableEventPoint;
friend class QPointerEvent;
};
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint *);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint &);
#endif
class Q_GUI_EXPORT QPointerEvent : public QInputEvent
{
public:

View File

@ -52,6 +52,7 @@
//
#include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/private/qeventpoint_p.h>
#include <QtCore/qurl.h>
#include <QtGui/qevent.h>
#include <QtGui/qwindow.h>
@ -60,139 +61,6 @@ QT_BEGIN_NAMESPACE
class QPointingDevice;
struct QEventPointPrivate {
QEventPointPrivate(int id, const QPointingDevice *device)
: device(device), pointId(id) { }
QEventPointPrivate(int pointId, QEventPoint::State state, const QPointF &scenePosition, const QPointF &globalPosition)
: scenePos(scenePosition), globalPos(globalPosition), pointId(pointId), state(state)
{
if (state == QEventPoint::State::Released)
pressure = 0;
}
inline bool operator==(const QEventPointPrivate &other) const
{
return device == other.device
&& window == other.window
&& target == other.target
&& pos == other.pos
&& scenePos == other.scenePos
&& globalPos == other.globalPos
&& globalPressPos == other.globalPressPos
&& globalGrabPos == other.globalGrabPos
&& globalLastPos == other.globalLastPos
&& pressure == other.pressure
&& rotation == other.rotation
&& ellipseDiameters == other.ellipseDiameters
&& velocity == other.velocity
&& timestamp == other.timestamp
&& lastTimestamp == other.lastTimestamp
&& pressTimestamp == other.pressTimestamp
&& uniqueId == other.uniqueId
&& pointId == other.pointId
&& state == other.state;
}
const QPointingDevice *device = nullptr;
QPointer<QWindow> window;
QPointer<QObject> target;
QPointF pos, scenePos, globalPos,
globalPressPos, globalGrabPos, globalLastPos;
qreal pressure = 1;
qreal rotation = 0;
QSizeF ellipseDiameters = QSizeF(0, 0);
QVector2D velocity;
ulong timestamp = 0;
ulong lastTimestamp = 0;
ulong pressTimestamp = 0;
QPointingDeviceUniqueId uniqueId;
int refCount = 1;
int pointId = -1;
QEventPoint::State state = QEventPoint::State::Unknown;
bool accept = false;
};
// Private subclasses to allow accessing and modifying protected variables.
// These should NOT hold any extra state.
class Q_GUI_EXPORT QMutableEventPoint : public QEventPoint
{
public:
QMutableEventPoint(int pointId = -1, State state = QEventPoint::State::Stationary,
const QPointF &scenePosition = QPointF(), const QPointF &globalPosition = QPointF()) :
QEventPoint(pointId, state, scenePosition, globalPosition) {}
QMutableEventPoint(ulong timestamp, int pointId, State state,
const QPointF &position, const QPointF &scenePosition, const QPointF &globalPosition) :
QEventPoint(pointId, state, scenePosition, globalPosition)
{
d->timestamp = timestamp;
d->pos = position;
}
void updateFrom(const QEventPoint &other);
static QMutableEventPoint *from(QEventPoint *me) { return static_cast<QMutableEventPoint *>(me); }
static QMutableEventPoint &from(QEventPoint &me) { return static_cast<QMutableEventPoint &>(me); }
static const QMutableEventPoint &constFrom(const QEventPoint &me) { return static_cast<const QMutableEventPoint &>(me); }
void detach();
void setId(int pointId) { d->pointId = pointId; }
void setDevice(const QPointingDevice *device) { d->device = device; }
void setTimestamp(const ulong t);
void setPressTimestamp(const ulong t) { d->pressTimestamp = t; }
void setState(QEventPoint::State state) { d->state = state; }
void setUniqueId(const QPointingDeviceUniqueId &uid) { d->uniqueId = uid; }
void setPosition(const QPointF &pos) { d->pos = pos; }
void setScenePosition(const QPointF &pos) { d->scenePos = pos; }
void setGlobalPosition(const QPointF &pos) { d->globalPos = pos; }
#if QT_DEPRECATED_SINCE(6, 0)
// temporary replacements for QTouchEvent::TouchPoint setters, mainly to make porting easier
QT_DEPRECATED_VERSION_X_6_0("Use setPosition()")
void setPos(const QPointF &pos) { d->pos = pos; }
QT_DEPRECATED_VERSION_X_6_0("Use setScenePosition()")
void setScenePos(const QPointF &pos) { d->scenePos = pos; }
QT_DEPRECATED_VERSION_X_6_0("Use setGlobalPosition()")
void setScreenPos(const QPointF &pos) { d->globalPos = pos; }
#endif
void setGlobalPressPosition(const QPointF &pos) { d->globalPressPos = pos; }
void setGlobalGrabPosition(const QPointF &pos) { d->globalGrabPos = pos; }
void setGlobalLastPosition(const QPointF &pos) { d->globalLastPos = pos; }
void setEllipseDiameters(const QSizeF &diams) { d->ellipseDiameters = diams; }
void setPressure(qreal v) { d->pressure = v; }
void setRotation(qreal v) { d->rotation = v; }
void setVelocity(const QVector2D &v) { d->velocity = v; }
QWindow *window() const { return d->window.data(); }
void setWindow(const QPointer<QWindow> &w) { d->window = w; }
QObject *target() const { return d->target.data(); }
void setTarget(const QPointer<QObject> &t) { d->target = t; }
};
static_assert(sizeof(QMutableEventPoint) == sizeof(QEventPoint));
class Q_GUI_EXPORT QMutableTouchEvent : public QTouchEvent
{
public:

View File

@ -0,0 +1,664 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qeventpoint.h"
#include "private/qeventpoint_p.h"
#include "private/qpointingdevice_p.h"
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcPointerVel, "qt.pointer.velocity")
Q_LOGGING_CATEGORY(lcEPDetach, "qt.pointer.eventpoint.detach")
/*! \class QEventPoint
\brief The QEventPoint class provides information about a point in a QPointerEvent.
\since 6.0
\inmodule QtGui
*/
/*!
\enum QEventPoint::State
Specifies the state of this event point.
\value Unknown
Unknown state.
\value Stationary
The event point did not move.
\value Pressed
The touch point or button is pressed.
\value Updated
The event point was updated.
\value Released
The touch point or button was released.
*/
/*!
\internal
Constructs an invalid event point with the given \a id and the \a device
from which it originated.
This acts as a default constructor in usages like QMap<int, QEventPoint>,
as in qgraphicsscene_p.h.
*/
QEventPoint::QEventPoint(int id, const QPointingDevice *device)
: d(new QEventPointPrivate(id, device)) {}
/*!
Constructs an event point with the given \a pointId, \a state,
\a scenePosition and \a globalPosition.
*/
QEventPoint::QEventPoint(int pointId, State state, const QPointF &scenePosition, const QPointF &globalPosition)
: d(new QEventPointPrivate(pointId, state, scenePosition, globalPosition)) {}
/*!
Constructs an event point by making a shallow copy of \a other.
*/
QEventPoint::QEventPoint(const QEventPoint &other)
: d(other.d)
{
if (d)
d->refCount++;
}
/*!
Assigns \a other to this event point and returns a reference to this
event point.
*/
QEventPoint &QEventPoint::operator=(const QEventPoint &other)
{
if (other.d)
other.d->refCount++;
if (d && !(--d->refCount))
delete d;
d = other.d;
return *this;
}
/*!
\fn QEventPoint::QEventPoint(QEventPoint &&other) noexcept
Constructs an event point by moving \a other.
*/
/*!
\fn QEventPoint &QEventPoint::operator=(QEventPoint &&other) noexcept
Move-assigns \a other to this event point instance.
*/
/*!
Returns \c true if this event point is equal to \a other, otherwise
return \c false.
*/
bool QEventPoint::operator==(const QEventPoint &other) const noexcept
{
if (d == other.d)
return true;
if (!d || !other.d)
return false;
return *d == *other.d;
}
/*!
\fn bool QEventPoint::operator!=(const QEventPoint &other) const noexcept
Returns \c true if this event point is not equal to \a other, otherwise
return \c false.
*/
/*!
Destroys the event point.
*/
QEventPoint::~QEventPoint()
{
if (d && !(--d->refCount))
delete d;
}
/*! \fn QPointF QEventPoint::pos() const
\obsolete
Deprecated since Qt 6.0. Use position() instead.
Returns the position of this point, relative to the widget
or item that received the event.
*/
/*!
\property QEventPoint::position
the position of this point
The position is relative to the widget or item that received the event.
*/
QPointF QEventPoint::position() const
{ return d->pos; }
/*!
\property QEventPoint::pressPosition
the position at which this point was pressed
The position is relative to the widget or item that received the event.
\sa position
*/
QPointF QEventPoint::pressPosition() const
{ return d->globalPressPos - d->globalPos + d->pos; }
/*!
\property QEventPoint::grabPosition
the position at which this point was grabbed
The position is relative to the widget or item that received the event.
\sa position
*/
QPointF QEventPoint::grabPosition() const
{ return d->globalGrabPos - d->globalPos + d->pos; }
/*!
\property QEventPoint::lastPosition
the position of this point from the previous press or move event
The position is relative to the widget or item that received the event.
\sa position, pressPosition
*/
QPointF QEventPoint::lastPosition() const
{ return d->globalLastPos - d->globalPos + d->pos; }
/*!
\property QEventPoint::scenePosition
the scene position of this point
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePressPosition, position, globalPosition
*/
QPointF QEventPoint::scenePosition() const
{ return d->scenePos; }
/*!
\property QEventPoint::scenePressPosition
the scene position at which this point was pressed
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePosition, pressPosition, globalPressPosition
*/
QPointF QEventPoint::scenePressPosition() const
{ return d->globalPressPos - d->globalPos + d->scenePos; }
/*!
\property QEventPoint::sceneGrabPosition
the scene position at which this point was grabbed
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePosition, grabPosition, globalGrabPosition
*/
QPointF QEventPoint::sceneGrabPosition() const
{ return d->globalGrabPos - d->globalPos + d->scenePos; }
/*!
\property QEventPoint::sceneLastPosition
the scene position of this point from the previous press or move event
The scene position is the position relative to QQuickWindow if handled in QQuickItem::event(),
in QGraphicsScene coordinates if handled by an override of QGraphicsItem::touchEvent(),
or the window position in widget applications.
\sa scenePosition, scenePressPosition
*/
QPointF QEventPoint::sceneLastPosition() const
{ return d->globalLastPos - d->globalPos + d->scenePos; }
/*!
\property QEventPoint::globalPosition
the global position of this point
The global position is relative to the screen or virtual desktop.
\sa globalPressPosition, position, scenePosition
*/
QPointF QEventPoint::globalPosition() const
{ return d->globalPos; }
/*!
\property QEventPoint::globalPressPosition
the global position at which this point was pressed
The global position is relative to the screen or virtual desktop.
\sa globalPosition, pressPosition, scenePressPosition
*/
QPointF QEventPoint::globalPressPosition() const
{ return d->globalPressPos; }
/*!
\property QEventPoint::globalGrabPosition
the global position at which this point was grabbed
The global position is relative to the screen or virtual desktop.
\sa globalPosition, grabPosition, sceneGrabPosition
*/
QPointF QEventPoint::globalGrabPosition() const
{ return d->globalGrabPos; }
/*!
\property QEventPoint::globalLastPosition
the global position of this point from the previous press or move event
The global position is relative to the screen or virtual desktop.
\sa globalPosition, lastPosition, sceneLastPosition
*/
QPointF QEventPoint::globalLastPosition() const
{ return d->globalLastPos; }
/*!
\property QEventPoint::velocity
a velocity vector, in units of pixels per second, in the coordinate
system of the screen or desktop.
\note If the device's capabilities include QInputDevice::Velocity, it means
velocity comes from the operating system (perhaps the touch hardware or
driver provides it). But usually the \c Velocity capability is not set,
indicating that the velocity is calculated by Qt, using a simple Kalman
filter to provide a smoothed average velocity rather than an instantaneous
value. Effectively it tells how fast and in what direction the user has
been dragging this point over the last few events, with the most recent
event having the strongest influence.
\sa QInputDevice::capabilities(), QInputEvent::device()
*/
QVector2D QEventPoint::velocity() const
{ return d->velocity; }
/*!
\property QEventPoint::state
the current state of the event point.
*/
QEventPoint::State QEventPoint::state() const
{ return d->state; }
/*!
\property QEventPoint::device
the pointing device from which this event point originates
*/
const QPointingDevice *QEventPoint::device() const
{ return d->device; }
/*!
\property QEventPoint::id
the ID number of this event point
\note Do not assume that ID numbers start at zero or that they are
sequential. Such an assumption is often false due to the way
the underlying drivers work.
*/
int QEventPoint::id() const
{ return d->pointId; }
/*!
\property QEventPoint::uniqueId
the unique ID of this point or token, if any
It is often invalid (see \l {QPointingDeviceUniqueId::isValid()} {isValid()}),
because touchscreens cannot uniquely identify fingers.
When it comes from a QTabletEvent, it identifies the serial number of the
stylus in use.
It may identify a specific token (fiducial object) when the TUIO driver is
in use with a touchscreen that supports them.
*/
QPointingDeviceUniqueId QEventPoint::uniqueId() const
{ return d->uniqueId; }
/*!
\property QEventPoint::timestamp
the most recent time at which this point was included in a QPointerEvent
\sa QPointerEvent::timestamp()
*/
ulong QEventPoint::timestamp() const
{ return d->timestamp; }
/*!
\property QEventPoint::lastTimestamp
the time from the previous QPointerEvent that contained this point
\sa globalLastPosition
*/
ulong QEventPoint::lastTimestamp() const
{ return d->lastTimestamp; }
/*!
\property QEventPoint::pressTimestamp
the most recent time at which this point was pressed
\sa timestamp
*/
ulong QEventPoint::pressTimestamp() const
{ return d->pressTimestamp; }
/*!
\property QEventPoint::timeHeld
the duration, in milliseconds, since this point was pressed and not released
\sa pressTimestamp, timestamp
*/
qreal QEventPoint::timeHeld() const
{ return (d->timestamp - d->pressTimestamp) / qreal(1000); }
/*!
\property QEventPoint::pressure
the pressure of this point
The return value is in the range \c 0.0 to \c 1.0.
*/
qreal QEventPoint::pressure() const
{ return d->pressure; }
/*!
\property QEventPoint::rotation
the angular orientation of this point
The return value is in degrees, where zero (the default) indicates the finger,
token or stylus is pointing upwards, a negative angle means it's rotated to the
left, and a positive angle means it's rotated to the right.
Most touchscreens do not detect rotation, so zero is the most common value.
*/
qreal QEventPoint::rotation() const
{ return d->rotation; }
/*!
\property QEventPoint::ellipseDiameters
the width and height of the bounding ellipse of the touch point
The return value is in logical pixels. Most touchscreens do not detect the
shape of the contact point, and no mice or tablet devices can detect it,
so a null size is the most common value. On some touchscreens the diameters
may be nonzero and always equal (the ellipse is approximated as a circle).
*/
QSizeF QEventPoint::ellipseDiameters() const
{ return d->ellipseDiameters; }
/*!
\property QEventPoint::accepted
the accepted state of the event point
In widget-based applications, this property is not used, as it's only meaningful
for a widget to accept or reject a complete QInputEvent.
In Qt Quick however, it's normal for an Item or Event Handler to accept
only the individual points in a QTouchEvent that are actually participating
in a gesture, while other points can be delivered to other items or
handlers. For the sake of consistency, that applies to any QPointerEvent;
and delivery is done only when all points in a QPointerEvent have been
accepted.
\sa QEvent::accepted
*/
void QEventPoint::setAccepted(bool accepted)
{
d->accept = accepted;
}
bool QEventPoint::isAccepted() const
{ return d->accept; }
/*!
\obsolete
\fn QPointF QEventPoint::normalizedPos() const
Deprecated since Qt 6.0. Use normalizedPosition() instead.
*/
/*!
Returns the normalized position of this point.
The coordinates are calculated by transforming globalPosition() into the
space of QInputDevice::availableVirtualGeometry(), i.e. \c (0, 0) is the
top-left corner and \c (1, 1) is the bottom-right corner.
\sa globalPosition
*/
QPointF QEventPoint::normalizedPosition() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalPosition() - geom.topLeft()) / geom.width();
}
/*!
\obsolete
Deprecated since Qt 6.0. Use globalPressPosition() instead.
Returns the normalized press position of this point.
*/
QPointF QEventPoint::startNormalizedPos() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalPressPosition() - geom.topLeft()) / geom.width();
}
/*!
\obsolete
Deprecated since Qt 6.0. Use globalLastPosition() instead.
Returns the normalized position of this point from the previous press or
move event.
The coordinates are normalized to QInputDevice::availableVirtualGeometry(),
i.e. \c (0, 0) is the top-left corner and \c (1, 1) is the bottom-right corner.
\sa normalizedPos(), startNormalizedPos()
*/
QPointF QEventPoint::lastNormalizedPos() const
{
auto geom = d->device->availableVirtualGeometry();
if (geom.isNull())
return QPointF();
return (globalLastPosition() - geom.topLeft()) / geom.width();
}
/*! \internal
This class is explicitly shared, which means if you construct an event and
then the point(s) that it holds are modified before the event is delivered,
the event will be seen to hold the modified points. The workaround is that
any code which modifies an eventpoint that could already be included in an
event, or code that wants to save an eventpoint for later, has
responsibility to detach before calling any setters, so as to hold and
modify an independent copy. (The independent copy can then be used in a
subsequent event.) If detaching is unnecessary, because refCount shows that
there is only one QEventPoint referring to the QEventPointPrivate instance,
this function does nothing.
*/
void QMutableEventPoint::detach()
{
if (d->refCount == 1)
return; // no need: there is only one QEventPoint using it
qCDebug(lcEPDetach) << "detaching: refCount" << d->refCount << this;
auto old = d;
d = new QEventPointPrivate(*d);
d->refCount = 1;
--old->refCount;
}
/*! \internal
Update current state from the given \a other point, assuming that this
instance contains state from the previous event and \a other contains new
values that came in from a device.
That is: global position and other valuators will be updated, but
the following properties will not be updated:
\list
\li properties that are not likely to be set after a fresh touchpoint
has been received from a device
\li properties that should be persistent between events (such as grabbers)
\endlist
*/
void QMutableEventPoint::updateFrom(const QEventPoint &other)
{
detach();
setPressure(other.pressure());
switch (other.state()) {
case QEventPoint::State::Pressed:
setGlobalPressPosition(other.globalPosition());
setGlobalLastPosition(other.globalPosition());
if (pressure() < 0)
setPressure(1);
break;
case QEventPoint::State::Released:
if (globalPosition() != other.globalPosition())
setGlobalLastPosition(globalPosition());
setPressure(0);
break;
default: // update or stationary
if (globalPosition() != other.globalPosition())
setGlobalLastPosition(globalPosition());
if (pressure() < 0)
setPressure(1);
break;
}
setState(other.state());
setPosition(other.position());
setScenePosition(other.scenePosition());
setGlobalPosition(other.globalPosition());
setEllipseDiameters(other.ellipseDiameters());
setRotation(other.rotation());
setVelocity(other.velocity());
}
/*! \internal
Set the timestamp from the event that updated this point's positions,
and calculate a new value for velocity().
The velocity calculation is done here because none of the QPointerEvent
subclass constructors take the timestamp directly, and because
QGuiApplication traditionally constructs an event first and then sets its
timestamp (see for example QGuiApplicationPrivate::processMouseEvent()).
This function looks up the corresponding instance in QPointingDevicePrivate::activePoints,
and assumes that its timestamp() still holds the previous time when this point
was updated, its velocity() holds this point's last-known velocity, and
its globalPosition() and globalLastPosition() hold this point's current
and previous positions, respectively. We assume timestamps are in milliseconds.
The velocity calculation is skipped if the platform has promised to
provide velocities already by setting the QInputDevice::Velocity capability.
*/
void QMutableEventPoint::setTimestamp(const ulong t)
{
// On mouse press, if the mouse has moved from its last-known location,
// QGuiApplicationPrivate::processMouseEvent() sends first a mouse move and
// then a press. Both events will get the same timestamp. So we need to set
// the press timestamp and position even when the timestamp isn't advancing,
// but skip setting lastTimestamp and velocity because those need a time delta.
if (state() == QEventPoint::State::Pressed) {
d->pressTimestamp = t;
d->globalPressPos = d->globalPos;
}
if (d->timestamp == t)
return;
detach();
if (device()) {
// get the persistent instance out of QPointingDevicePrivate::activePoints
// (which sometimes might be the same as this instance)
QEventPointPrivate *pd = QPointingDevicePrivate::get(
const_cast<QPointingDevice *>(d->device))->pointById(id())->eventPoint.d;
if (t > pd->timestamp) {
pd->lastTimestamp = pd->timestamp;
pd->timestamp = t;
if (state() == QEventPoint::State::Pressed)
pd->pressTimestamp = t;
if (pd->lastTimestamp > 0 && !device()->capabilities().testFlag(QInputDevice::Capability::Velocity)) {
// calculate instantaneous velocity according to time and distance moved since the previous point
QVector2D newVelocity = QVector2D(pd->globalPos - pd->globalLastPos) / (t - pd->lastTimestamp) * 1000;
// VERY simple kalman filter: does a weighted average
// where the older velocities get less and less significant
static const float KalmanGain = 0.7f;
pd->velocity = newVelocity * KalmanGain + pd->velocity * (1.0f - KalmanGain);
qCDebug(lcPointerVel) << "velocity" << newVelocity << "filtered" << pd->velocity <<
"based on movement" << pd->globalLastPos << "->" << pd->globalPos <<
"over time" << pd->lastTimestamp << "->" << pd->timestamp;
}
if (d != pd) {
d->lastTimestamp = pd->lastTimestamp;
d->velocity = pd->velocity;
}
}
}
d->timestamp = t;
}
/*!
\fn void QMutableEventPoint::setPosition(const QPointF &pos)
\internal
Sets the localized position.
Often events need to be localized before delivery to specific widgets or
items. This can be done directly, or in a copy (for which we have a copy
constructor), depending on whether the original point needs to be retained.
Usually it's calculated by mapping scenePosition() to the target anyway.
*/
QT_END_NAMESPACE

View File

@ -0,0 +1,172 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QEVENTPOINT_H
#define QEVENTPOINT_H
#include <QtGui/qtguiglobal.h>
#include <QtGui/qvector2d.h>
#include <QtGui/qpointingdevice.h>
QT_BEGIN_NAMESPACE
struct QEventPointPrivate;
class Q_GUI_EXPORT QEventPoint
{
Q_GADGET
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
QDOC_PROPERTY(QPointingDevice *device READ device CONSTANT) // qdoc doesn't know const
Q_PROPERTY(const QPointingDevice *device READ device CONSTANT)
Q_PROPERTY(int id READ id CONSTANT)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId CONSTANT)
Q_PROPERTY(State state READ state CONSTANT)
Q_PROPERTY(ulong timestamp READ timestamp CONSTANT)
Q_PROPERTY(ulong pressTimestamp READ pressTimestamp CONSTANT)
Q_PROPERTY(ulong lastTimestamp READ lastTimestamp CONSTANT)
Q_PROPERTY(qreal timeHeld READ timeHeld CONSTANT)
Q_PROPERTY(qreal pressure READ pressure CONSTANT)
Q_PROPERTY(qreal rotation READ rotation CONSTANT)
Q_PROPERTY(QSizeF ellipseDiameters READ ellipseDiameters CONSTANT)
Q_PROPERTY(QVector2D velocity READ velocity CONSTANT)
Q_PROPERTY(QPointF position READ position CONSTANT)
Q_PROPERTY(QPointF pressPosition READ pressPosition CONSTANT)
Q_PROPERTY(QPointF grabPosition READ grabPosition CONSTANT)
Q_PROPERTY(QPointF lastPosition READ lastPosition CONSTANT)
Q_PROPERTY(QPointF scenePosition READ scenePosition CONSTANT)
Q_PROPERTY(QPointF scenePressPosition READ scenePressPosition CONSTANT)
Q_PROPERTY(QPointF sceneGrabPosition READ sceneGrabPosition CONSTANT)
Q_PROPERTY(QPointF sceneLastPosition READ sceneLastPosition CONSTANT)
Q_PROPERTY(QPointF globalPosition READ globalPosition CONSTANT)
Q_PROPERTY(QPointF globalPressPosition READ globalPressPosition CONSTANT)
Q_PROPERTY(QPointF globalGrabPosition READ globalGrabPosition CONSTANT)
Q_PROPERTY(QPointF globalLastPosition READ globalLastPosition CONSTANT)
public:
enum State : quint8 {
Unknown = Qt::TouchPointUnknownState,
Stationary = Qt::TouchPointStationary,
Pressed = Qt::TouchPointPressed,
Updated = Qt::TouchPointMoved,
Released = Qt::TouchPointReleased
};
Q_DECLARE_FLAGS(States, State)
Q_FLAG(States)
QEventPoint(int id = -1, const QPointingDevice *device = nullptr);
QEventPoint(int pointId, State state, const QPointF &scenePosition, const QPointF &globalPosition);
QEventPoint(const QEventPoint &other);
QEventPoint(QEventPoint && other) noexcept : d(std::move(other.d)) { other.d = nullptr; }
QEventPoint &operator=(const QEventPoint &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QEventPoint)
bool operator==(const QEventPoint &other) const noexcept;
inline bool operator!=(const QEventPoint &other) const noexcept { return !operator==(other); }
~QEventPoint();
inline void swap(QEventPoint &other) noexcept
{ qSwap(d, other.d); }
QPointF position() const;
QPointF pressPosition() const;
QPointF grabPosition() const;
QPointF lastPosition() const;
QPointF scenePosition() const;
QPointF scenePressPosition() const;
QPointF sceneGrabPosition() const;
QPointF sceneLastPosition() const;
QPointF globalPosition() const;
QPointF globalPressPosition() const;
QPointF globalGrabPosition() const;
QPointF globalLastPosition() const;
QPointF normalizedPosition() const;
#if QT_DEPRECATED_SINCE(6, 0)
// QEventPoint replaces QTouchEvent::TouchPoint, so we need all its old accessors, for now
QT_DEPRECATED_VERSION_X_6_0("Use position()")
QPointF pos() const { return position(); }
QT_DEPRECATED_VERSION_X_6_0("Use pressPosition()")
QPointF startPos() const { return pressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use scenePosition()")
QPointF scenePos() const { return scenePosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use scenePressPosition()")
QPointF startScenePos() const { return scenePressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPosition()")
QPointF screenPos() const { return globalPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPressPosition()")
QPointF startScreenPos() const { return globalPressPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalPressPosition()")
QPointF startNormalizedPos() const;
QT_DEPRECATED_VERSION_X_6_0("Use normalizedPosition()")
QPointF normalizedPos() const { return normalizedPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use lastPosition()")
QPointF lastPos() const { return lastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use sceneLastPosition()")
QPointF lastScenePos() const { return sceneLastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalLastPosition()")
QPointF lastScreenPos() const { return globalLastPosition(); }
QT_DEPRECATED_VERSION_X_6_0("Use globalLastPosition()")
QPointF lastNormalizedPos() const;
#endif // QT_DEPRECATED_SINCE(6, 0)
QVector2D velocity() const;
State state() const;
const QPointingDevice *device() const;
int id() const;
QPointingDeviceUniqueId uniqueId() const;
ulong timestamp() const;
ulong lastTimestamp() const;
ulong pressTimestamp() const;
qreal timeHeld() const;
qreal pressure() const;
qreal rotation() const;
QSizeF ellipseDiameters() const;
bool isAccepted() const;
void setAccepted(bool accepted = true);
private:
QEventPointPrivate *d;
friend class QMutableEventPoint;
friend class QPointerEvent;
};
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint *);
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEventPoint &);
#endif
QT_END_NAMESPACE
#endif // QEVENTPOINT_H

View File

@ -0,0 +1,200 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QEVENTPOINT_P_H
#define QEVENTPOINT_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/qevent.h>
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcPointerVel);
Q_DECLARE_LOGGING_CATEGORY(lcEPDetach);
class QPointingDevice;
struct QEventPointPrivate {
QEventPointPrivate(int id, const QPointingDevice *device)
: device(device), pointId(id) { }
QEventPointPrivate(int pointId, QEventPoint::State state, const QPointF &scenePosition, const QPointF &globalPosition)
: scenePos(scenePosition), globalPos(globalPosition), pointId(pointId), state(state)
{
if (state == QEventPoint::State::Released)
pressure = 0;
}
inline bool operator==(const QEventPointPrivate &other) const
{
return device == other.device
&& window == other.window
&& target == other.target
&& pos == other.pos
&& scenePos == other.scenePos
&& globalPos == other.globalPos
&& globalPressPos == other.globalPressPos
&& globalGrabPos == other.globalGrabPos
&& globalLastPos == other.globalLastPos
&& pressure == other.pressure
&& rotation == other.rotation
&& ellipseDiameters == other.ellipseDiameters
&& velocity == other.velocity
&& timestamp == other.timestamp
&& lastTimestamp == other.lastTimestamp
&& pressTimestamp == other.pressTimestamp
&& uniqueId == other.uniqueId
&& pointId == other.pointId
&& state == other.state;
}
const QPointingDevice *device = nullptr;
QPointer<QWindow> window;
QPointer<QObject> target;
QPointF pos, scenePos, globalPos,
globalPressPos, globalGrabPos, globalLastPos;
qreal pressure = 1;
qreal rotation = 0;
QSizeF ellipseDiameters = QSizeF(0, 0);
QVector2D velocity;
ulong timestamp = 0;
ulong lastTimestamp = 0;
ulong pressTimestamp = 0;
QPointingDeviceUniqueId uniqueId;
int refCount = 1;
int pointId = -1;
QEventPoint::State state = QEventPoint::State::Unknown;
bool accept = false;
};
// Private subclasses to allow accessing and modifying protected variables.
// These should NOT hold any extra state.
class Q_GUI_EXPORT QMutableEventPoint : public QEventPoint
{
public:
QMutableEventPoint(int pointId = -1, State state = QEventPoint::State::Stationary,
const QPointF &scenePosition = QPointF(), const QPointF &globalPosition = QPointF()) :
QEventPoint(pointId, state, scenePosition, globalPosition) {}
QMutableEventPoint(ulong timestamp, int pointId, State state,
const QPointF &position, const QPointF &scenePosition, const QPointF &globalPosition) :
QEventPoint(pointId, state, scenePosition, globalPosition)
{
d->timestamp = timestamp;
d->pos = position;
}
void updateFrom(const QEventPoint &other);
static QMutableEventPoint *from(QEventPoint *me) { return static_cast<QMutableEventPoint *>(me); }
static QMutableEventPoint &from(QEventPoint &me) { return static_cast<QMutableEventPoint &>(me); }
static const QMutableEventPoint &constFrom(const QEventPoint &me) { return static_cast<const QMutableEventPoint &>(me); }
void detach();
void setId(int pointId) { d->pointId = pointId; }
void setDevice(const QPointingDevice *device) { d->device = device; }
void setTimestamp(const ulong t);
void setPressTimestamp(const ulong t) { d->pressTimestamp = t; }
void setState(QEventPoint::State state) { d->state = state; }
void setUniqueId(const QPointingDeviceUniqueId &uid) { d->uniqueId = uid; }
void setPosition(const QPointF &pos) { d->pos = pos; }
void setScenePosition(const QPointF &pos) { d->scenePos = pos; }
void setGlobalPosition(const QPointF &pos) { d->globalPos = pos; }
#if QT_DEPRECATED_SINCE(6, 0)
// temporary replacements for QTouchEvent::TouchPoint setters, mainly to make porting easier
QT_DEPRECATED_VERSION_X_6_0("Use setPosition()")
void setPos(const QPointF &pos) { d->pos = pos; }
QT_DEPRECATED_VERSION_X_6_0("Use setScenePosition()")
void setScenePos(const QPointF &pos) { d->scenePos = pos; }
QT_DEPRECATED_VERSION_X_6_0("Use setGlobalPosition()")
void setScreenPos(const QPointF &pos) { d->globalPos = pos; }
#endif
void setGlobalPressPosition(const QPointF &pos) { d->globalPressPos = pos; }
void setGlobalGrabPosition(const QPointF &pos) { d->globalGrabPos = pos; }
void setGlobalLastPosition(const QPointF &pos) { d->globalLastPos = pos; }
void setEllipseDiameters(const QSizeF &diams) { d->ellipseDiameters = diams; }
void setPressure(qreal v) { d->pressure = v; }
void setRotation(qreal v) { d->rotation = v; }
void setVelocity(const QVector2D &v) { d->velocity = v; }
QWindow *window() const { return d->window.data(); }
void setWindow(const QPointer<QWindow> &w) { d->window = w; }
QObject *target() const { return d->target.data(); }
void setTarget(const QPointer<QObject> &t) { d->target = t; }
};
static_assert(sizeof(QMutableEventPoint) == sizeof(QEventPoint));
QT_END_NAMESPACE
#endif // QEVENTPOINT_P_H

View File

@ -40,16 +40,14 @@
#include "qinputdevice.h"
#include "qinputdevice_p.h"
#include "qpointingdevice.h"
#include "qwindowsysteminterface_p.h"
#include <QCoreApplication>
#include <QDebug>
#include <QLoggingCategory>
#include <QMutex>
#include <QScreen>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
/*!
\class QInputDevice
\brief The QInputDevice class describes a device from which a QInputEvent originates.

View File

@ -39,6 +39,7 @@
#include "qpointingdevice.h"
#include "qpointingdevice_p.h"
#include "qwindowsysteminterface_p.h"
#include <QList>
#include <QLoggingCategory>
#include <QMutex>
@ -48,8 +49,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices)
Q_DECLARE_LOGGING_CATEGORY(lcPointerGrab)
Q_LOGGING_CATEGORY(lcPointerGrab, "qt.pointer.grab");
/*!
\class QPointingDevice
@ -663,4 +663,91 @@ QDebug operator<<(QDebug debug, const QPointingDevice *device)
}
#endif // !QT_NO_DEBUG_STREAM
/*!
\class QPointingDeviceUniqueId
\since 5.8
\ingroup events
\inmodule QtGui
\brief QPointingDeviceUniqueId identifies a unique object, such as a tagged token
or stylus, which is used with a pointing device.
QPointingDeviceUniqueIds can be compared for equality, and can be used as keys in a QHash.
You get access to the numerical ID via numericId(), if the device supports such IDs.
For future extensions, though, you should not use that function, but compare objects
of this type using the equality operator.
This class is a thin wrapper around an integer ID. You pass it into and out of
functions by value.
\sa QEventPoint
*/
/*!
\fn QPointingDeviceUniqueId::QPointingDeviceUniqueId()
Constructs an invalid unique pointer ID.
*/
/*!
Constructs a unique pointer ID from numeric ID \a id.
*/
QPointingDeviceUniqueId QPointingDeviceUniqueId::fromNumericId(qint64 id)
{
QPointingDeviceUniqueId result;
result.m_numericId = id;
return result;
}
/*!
\fn bool QPointingDeviceUniqueId::isValid() const
Returns whether this unique pointer ID is valid, that is, it represents an actual
pointer.
*/
/*!
\property QPointingDeviceUniqueId::numericId
\brief the numeric unique ID of the token represented by a touchpoint
If the device provides a numeric ID, isValid() returns true, and this
property provides the numeric ID;
otherwise it is -1.
You should not use the value of this property in portable code, but
instead rely on equality to identify pointers.
\sa isValid()
*/
qint64 QPointingDeviceUniqueId::numericId() const noexcept
{
return m_numericId;
}
/*!
\fn bool QPointingDeviceUniqueId::operator==(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
\since 5.8
Returns whether the two unique pointer IDs \a lhs and \a rhs identify the same pointer
(\c true) or not (\c false).
*/
/*!
\fn bool QPointingDeviceUniqueId::operator!=(QPointingDeviceUniqueId lhs, QPointingDeviceUniqueId rhs)
\since 5.8
Returns whether the two unique pointer IDs \a lhs and \a rhs identify different pointers
(\c true) or not (\c false).
*/
/*!
\relates QPointingDeviceUniqueId
\since 5.8
Returns the hash value for \a key, using \a seed to seed the calculation.
*/
size_t qHash(QPointingDeviceUniqueId key, size_t seed) noexcept
{
return qHash(key.numericId(), seed);
}
QT_END_NAMESPACE

View File

@ -51,6 +51,7 @@
// We mean it.
//
#include <QtCore/qloggingcategory.h>
#include <QtGui/private/qevent_p.h>
#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qtguiglobal_p.h>
@ -59,6 +60,8 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcPointerGrab);
class Q_GUI_EXPORT QPointingDevicePrivate : public QInputDevicePrivate
{
Q_DECLARE_PUBLIC(QPointingDevice)

View File

@ -60,9 +60,12 @@
#include <QList>
#include <QWaitCondition>
#include <QAtomicInt>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputDevices);
class QWindowSystemEventHandler;
class Q_GUI_EXPORT QWindowSystemInterfacePrivate {