IMPROVED handling of JKQTPMouseWheelActions::jkqtpmwaZoomByWheelAndTrackpadPan: now consecutive pan-actions are recognizes as such, even if the pan-delta is larger than the predefined limit ... as long as the events were generated close in time to each other!

This commit is contained in:
jkriege2 2023-06-18 15:13:24 +02:00
parent 9762b44b7d
commit cd77d38a5b
3 changed files with 45 additions and 21 deletions

View File

@ -213,7 +213,7 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
cmbMouseWheelAction->addItem("jkqtpmwaPanByWheel");
cmbMouseWheelAction->addItem("jkqtpmwaZoomByWheelAndTrackpadPan");
cmbMouseWheelAction->addItem("NoAction");
cmbMouseWheelAction->setCurrentIndex(0);
cmbMouseWheelAction->setCurrentIndex(2);
connect(cmbMouseWheelAction, SIGNAL(currentIndexChanged(int)), this, SLOT(setMouseWheelNoModAction(int)));
setMouseWheelNoModAction(cmbMouseWheelAction->currentIndex());

View File

@ -54,6 +54,9 @@ int JKQTPlotter::getGlobalResizeDelay()
JKQTPlotter::JKQTPlotter(bool datastore_internal, QWidget* parent, JKQTPDatastore* datast):
QWidget(parent, Qt::Widget),
currentMouseDragAction(),
lastWheelActionType(WheelActionType::None),
lastWheelActionTimestamp(0),
maxWheelEventSeriesTimestampDifference(300),
doDrawing(false),
plotter(nullptr),
mouseDragingRectangle(false),
@ -1015,39 +1018,45 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
#endif
const QPoint angleDelta=event->angleDelta();
QRectF zoomRect= QRectF(QPointF(plotter->x2p(getXAxis()->getMin()),plotter->y2p(getYAxis()->getMax())), QPointF(plotter->x2p(getXAxis()->getMax()),plotter->y2p(getYAxis()->getMin())));
//qDebug()<<"wheelEvent: "<<event->type()<<", "<<event->modifiers()<<", "<<angleDelta<<", "<<event->pixelDelta()<<", "<<event->inverted()<<", "<<event->source()<<", "<<event->buttons();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
//qDebug()<<"wheelEvent: "<<event->type()<<"["<<event->deviceType()<<", "<<event->device()->name()<<", "<<event->device()->seatName()<<", "<<event->device()->capabilities()<<", "<<event->pointingDevice()->pointerType()<<", "<<event->timestamp()<<"], "<<event->phase()<<", "<<event->modifiers()<<", "<<angleDelta<<", "<<event->pixelDelta()<<", "<<event->inverted()<<", "<<event->source()<<", "<<event->buttons();
#else
//qDebug()<<"wheelEvent: "<<event->type()<<", "<<event->timestamp()<<", "<<event->phase()<<", "<<event->modifiers()<<", "<<angleDelta<<", "<<event->pixelDelta()<<", "<<event->inverted()<<", "<<event->source()<<", "<<event->buttons();
#endif
bool foundIT=false;
auto itAction=findMatchingMouseWheelAction(event->modifiers(), &foundIT);
enum {
acZoom,
acPan,
acNone
} acTodo=acNone;
WheelActionType acTodo=WheelActionType::None;
QPointF d(0,0); // for acPan, the shift of the ROI
double factor=1; // for zooming, the zoom-factor
if (foundIT) {
if (itAction.value()==JKQTPMouseWheelActions::jkqtpmwaZoomByWheel) {
acTodo=acZoom;
acTodo=WheelActionType::Zoom;
if (abs(angleDelta.y())>30 && angleDelta.x()==0) {
factor=pow(2.0, 1.0*static_cast<double>(angleDelta.y())/120.0);
} else if (abs(angleDelta.x())>30 && angleDelta.y()==0) {
factor=pow(2.0, 1.0*static_cast<double>(angleDelta.x())/120.0);
}
} else if (itAction.value()==JKQTPMouseWheelActions::jkqtpmwaZoomByWheelAndTrackpadPan) {
if (abs(angleDelta.x())<30 && abs(angleDelta.y())<30) {
// this heuristics recognizes pan-gestures on a track-pad.
// These are converted by Qt to wheelEvents with small angleDelta()-Values
// typical angleDelta values are 120 (1/10 degree) or above, here we use 30
// to accomodate for finer resolved mouse-wheels
//
// unfortunately there is no other way to distinguish these cases, as Qt does not transport
// the source of the QWheelEvent!
acTodo=acPan;
// this heuristics recognizes pan-gestures on a track-pad.
// These are converted by Qt to wheelEvents with small angleDelta()-Values
// typical angleDelta values are 120 (1/10 degree) or above, here we use 30
// to accomodate for finer resolved mouse-wheels
//
// unfortunately there is no other way to distinguish these cases, as Qt does not transport
// the source of the QWheelEvent!
const bool doPan=(abs(angleDelta.x())<30 && abs(angleDelta.y())<30);
// in addition when the last wheelEvent was a pan-Event and the current is close in time (less than maxWheelEventSeriesTimestampDifference Milliseconds),
// but now we classify a zoom-event we assume there was an acceleration in panning, that leads to angleDelta() larger than the
// limit of 30 above ... in this we still force another PANNING!
const bool forcePan=(!doPan && lastWheelActionType==WheelActionType::Pan
&& (event->timestamp()-lastWheelActionTimestamp)<maxWheelEventSeriesTimestampDifference);
if (forcePan || doPan) {
acTodo=WheelActionType::Pan;
d=angleDelta;
} else {
acTodo=acZoom;
acTodo=WheelActionType::Zoom;
if (abs(angleDelta.y())>30 && angleDelta.x()==0) {
factor=pow(2.0, 1.0*static_cast<double>(angleDelta.y())/120.0);
} else if (abs(angleDelta.x())>30 && angleDelta.y()==0) {
@ -1055,7 +1064,7 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
}
}
} else if (itAction.value()==JKQTPMouseWheelActions::jkqtpmwaPanByWheel) {
acTodo=acPan;
acTodo=WheelActionType::Pan;
d=QPointF(angleDelta.x()/120.0*zoomRect.width()/10.0,
angleDelta.y()/120.0*zoomRect.height()/10.0);
// maximum shoft is 100 Pixels in either direction
@ -1071,7 +1080,7 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
//qDebug()<<" action: "<<acTodo<<" factor="<<factor<<" d="<<d;
if (acTodo==acZoom && factor!=1.0) {
if (acTodo==WheelActionType::Zoom && factor!=1.0) {
double xmin=plotter->p2x(static_cast<double>(wheel_x)/magnification-static_cast<double>(plotter->getPlotWidth()*0.5)/factor);
double xmax=plotter->p2x(static_cast<double>(wheel_x)/magnification+static_cast<double>(plotter->getPlotWidth()*0.5)/factor);
double ymin=plotter->p2y(static_cast<double>(wheel_y)/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight()*0.5)/factor);
@ -1085,7 +1094,7 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
}
//qDebug()<<" zoom: factor="<<factor;
plotter->setXY(xmin, xmax, ymin, ymax, true);
} else if (acTodo==acPan && (d.x()!=0 || d.y()!=0)) {
} else if (acTodo==WheelActionType::Pan && (d.x()!=0 || d.y()!=0)) {
//qDebug()<<" pan: d="<<d;
if ( (wheel_x/magnification<plotter->getInternalPlotBorderLeft()) || (wheel_x/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.translate(0, d.y());
@ -1103,6 +1112,8 @@ void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
updateCursor();
currentMouseDragAction.clear();
lastWheelActionType=acTodo;
lastWheelActionTimestamp=event->timestamp();
}
bool JKQTPlotter::event(QEvent* event) {

View File

@ -1418,6 +1418,19 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief the currently executed MouseMoveActions */
QSet<JKQTPMouseMoveActions> currentMouseMoveAction;
enum class WheelActionType {
Zoom,
Pan,
None
};
/** \brief storage for last WheelActionType (used in wheelAction() to distinguish trackpad-pan ations in mode jkqtpmwaZoomByWheelAndTrackpadPan) */
WheelActionType lastWheelActionType;
/** \brief storage for timestammp of the last QWheelEvent (used in wheelAction() to distinguish trackpad-pan ations in mode jkqtpmwaZoomByWheelAndTrackpadPan) */
quint64 lastWheelActionTimestamp;
/** \brief max. time between two QWheelEvents that are recognized as one series */
const quint64 maxWheelEventSeriesTimestampDifference;
/** \brief searches JKQTPlotterStyle::registeredMouseActionModes for a matching action, returns in \a found whether an action was found */
JKQTPMouseDragActionsHashMapIterator findMatchingMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers, bool *found=nullptr) const;