implemented feature request #69: Show data tooltip on MouseMove by adding general actions that can be executed on a mouse move operation, when no mouse button is pressed, modification by keyboard modifiers is possible though

This commit is contained in:
jkriege2 2022-05-15 14:15:15 +02:00
parent 5c665ff8af
commit ae5713ea68
9 changed files with 325 additions and 116 deletions

View File

@ -17,6 +17,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
<li>fixed issue described in <a href="https://github.com/jkriege2/JKQtPlotter/pull/62">#62: Fix custom labels draw, because giving exactly two label-strings did not display all of them</a>, thanks to <a href="https://github.com/FalsinSoft">user:FalsinSoft</a></li>
<li>fixed issue <a href="https://github.com/jkriege2/JKQtPlotter/pull/70">#70: Typo in jkqtplotter/CMakeLists.txt</a>, thanks to <a href="https://github.com/tedlinlab">user:tedlinlab</a></li>
<li>NEW: JKQTPFilledCurveXGraph and JKQTPFilledCurveYGraph can now plot wiggle plots with different fill styles above and below the baseline (feature request <a href="https://github.com/jkriege2/JKQtPlotter/issues/68">#68 Wiggle Plots</a> from <a href="https://github.com/xichaoqiang">user:xichaoqiang</a> </li>
<li>NEW/BREAKING CHANGE: data tooltip can now also be shown when "just" moving the mouse (so far this was only possible when dragging the mouse with a button pressed). This also removes JKQtPlotter::getActMouseLeftAsToolTip() and adds JKQtPlotter::getActMouseMoveToolTip() instead! Also the default toolbars and context menus changed!</li>
</ul>
\subsection page_whatsnew_TRUNK_DOWNLOAD trunk: Download

View File

@ -95,6 +95,14 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
connect(cmbMagnification, SIGNAL(currentIndexChanged(int)), this, SLOT(setPlotMagnification(int)));
cmbMagnification->setCurrentIndex(3);
// add a QComboBox that allows to set the left mouse button action for the JKQTPlotter
cmbMouseMoveAction=new QComboBox(this);
layForm->addRow("mouse action: move, no modifiers", cmbMouseMoveAction);
cmbMouseMoveAction->addItem("none");
cmbMouseMoveAction->addItem("jkqtpmmaToolTipForClosestDataPoint");
connect(cmbMouseMoveAction, SIGNAL(currentIndexChanged(int)), this, SLOT(setMouseMoveAction(int)));
setMouseMoveAction(cmbMouseMoveAction->currentIndex());
// add a QComboBox that allows to set the left mouse button action for the JKQTPlotter
cmbLeftNoModMouseAction=new QComboBox(this);
layForm->addRow("mouse action: left-click, no modifiers", cmbLeftNoModMouseAction);
@ -335,6 +343,12 @@ void TestUserInteraction::setRightMouseAction(int index)
else plot->registerMouseDragAction(Qt::RightButton, Qt::NoModifier, static_cast<JKQTPMouseDragActions>(index));
}
void TestUserInteraction::setMouseMoveAction(int index)
{
if (index==0) plot->deregisterMouseMoveAction(Qt::NoModifier);
else plot->registerMouseMoveAction(Qt::NoModifier, static_cast<JKQTPMouseMoveActions>(index-1));
}
void TestUserInteraction::setPlotMagnification(int index)
{
plot->setMagnification(cmbMagnification->itemData(index).toDouble());

View File

@ -21,6 +21,7 @@ class TestUserInteraction : public QMainWindow
signals:
public slots:
void setMouseMoveAction(int index);
void setLeftMouseAction(int index);
void setLeftCtrlMouseAction(int index);
void setRightMouseAction(int index);
@ -63,6 +64,7 @@ class TestUserInteraction : public QMainWindow
QCheckBox* chkShowToolbar;
QCheckBox* chkToolbarAlwaysOn;
QCheckBox* chkGrid;
QComboBox* cmbMouseMoveAction;
QComboBox* cmbLeftNoModMouseAction;
QComboBox* cmbLeftCtrlModMouseAction;
QComboBox* cmbRightNoModMouseAction;

View File

@ -29,6 +29,7 @@
#endif
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/graphs/jkqtpscatter.h"
#include "jkqtplotter.h"
#define jkqtp_RESIZE_DELAY 100
@ -62,7 +63,7 @@ JKQTPlotter::JKQTPlotter(bool datastore_internal, QWidget* parent, JKQTPDatastor
contextSubMenus(),
plotterStyle(JKQTPGetSystemDefaultStyle()),
resizeTimer(), registeredOverrideMouseDragActionModes(),
actgrpMouseLeft(nullptr), actMouseLeftAsDefault(nullptr), actMouseLeftAsRuler(nullptr), actMouseLeftAsToolTip(nullptr), actMouseLeftAsZoomRect(nullptr), actMouseLeftAsPanView(nullptr)
actgrpMouseLeft(nullptr), actMouseLeftAsDefault(nullptr), actMouseLeftAsRuler(nullptr), actMouseMoveToolTip(nullptr), actMouseLeftAsZoomRect(nullptr), actMouseLeftAsPanView(nullptr)
{
initJKQTPlotterResources();
@ -99,17 +100,22 @@ JKQTPlotter::JKQTPlotter(bool datastore_internal, QWidget* parent, JKQTPDatastor
actMouseLeftAsRuler=actgrpMouseLeft->addAction(QIcon(":/JKQTPlotter/jkqtp_mouseact_ruler.png"), tr("Ruler Tool"));
actMouseLeftAsRuler->setToolTip(tr("switch on the ruler tool (left button, no modifiers)"));
actMouseLeftAsRuler->setCheckable(true);
actMouseLeftAsToolTip=actgrpMouseLeft->addAction(QIcon(":/JKQTPlotter/jkqtp_mouseact_tooltip.png"), tr("Data Tooltip Tool"));
actMouseLeftAsToolTip->setToolTip(tr("switch on the data tooltip tool (left button, no modifiers)"));
actMouseLeftAsToolTip->setCheckable(true);
//actMouseLeftAsToolTip=actgrpMouseLeft->addAction(QIcon(":/JKQTPlotter/jkqtp_mouseact_tooltip.png"), tr("Data Tooltip Tool"));
//actMouseLeftAsToolTip->setToolTip(tr("switch on the data tooltip tool when moving the mouse (no modifiers)"));
//actMouseLeftAsToolTip->setCheckable(true);
actgrpMouseLeft->setExclusive(true);
actMouseLeftAsDefault->setChecked(true);
actMouseMoveToolTip=new QAction(QIcon(":/JKQTPlotter/jkqtp_mouseact_tooltip.png"), tr("Data Tooltip Tool"));
actMouseMoveToolTip->setToolTip(tr("switch on the data tooltip tool when moving the mouse (no modifiers)"));
actMouseMoveToolTip->setCheckable(true);
actMouseMoveToolTip->setChecked(false);
connect(actMouseLeftAsDefault, SIGNAL(triggered()), this, SLOT(resetMouseLeftAction()));
connect(actMouseLeftAsRuler, SIGNAL(triggered()), this, SLOT(setMouseLeftActionAsRuler()));
connect(actMouseLeftAsToolTip, SIGNAL(triggered()), this, SLOT(setMouseLeftActionAsToolTip()));
connect(actMouseLeftAsPanView, SIGNAL(triggered()), this, SLOT(setMouseLeftActionAsPanView()));
connect(actMouseLeftAsZoomRect, SIGNAL(triggered()), this, SLOT(setMouseLeftActionAsZoomRect()));
connect(actMouseMoveToolTip, SIGNAL(toggled(bool)), this, SLOT(setMouseMoveActionAsToolTip(bool)));
toolbar=new JKVanishQToolBar(this);
@ -358,6 +364,27 @@ void JKQTPlotter::clearAllMouseWheelActions()
//qDebug()<<"clearAllMouseWheelActions(): "<<plotterStyle.registeredMouseWheelActions;
}
void JKQTPlotter::registerMouseMoveAction(Qt::KeyboardModifiers modifier, JKQTPMouseMoveActions action)
{
//qDebug()<<"registerMouseMoveAction("<<modifier<<","<<action<<"): "<<plotterStyle.registeredMouseMoveActions;
plotterStyle.registeredMouseMoveActions[modifier]=action;
//qDebug()<<"registerMouseMoveAction("<<modifier<<","<<action<<"): "<<plotterStyle.registeredMouseMoveActions;
}
void JKQTPlotter::deregisterMouseMoveAction(Qt::KeyboardModifiers modifier)
{
//qDebug()<<"deregisterMouseMoveAction("<<modifier<<"): "<<plotterStyle.registeredMouseMoveActions;
plotterStyle.registeredMouseMoveActions.remove(modifier);
//qDebug()<<"deregisterMouseMoveAction("<<modifier<<"): "<<plotterStyle.registeredMouseMoveActions;
}
void JKQTPlotter::clearAllMouseMoveActions()
{
//qDebug()<<"clearAllMouseMoveActions(): "<<plotterStyle.registeredMouseMoveActions;
plotterStyle.registeredMouseMoveActions.clear();
//qDebug()<<"clearAllMouseMoveActions(): "<<plotterStyle.registeredMouseMoveActions;
}
@ -453,8 +480,8 @@ void JKQTPlotter::fillInternalStructForToolTipOfClosestDataPoint(double x0, doub
foundAll=true;
}
}
mouseDragMarkers.clear();
if (foundAll && dbest<getCurrentPlotterStyle().maxTooltipDistance) {
mouseDragMarkers.clear();
QStringList entries;
for (int i=0; i<posSyss.size(); i++) {
const QPoint posPix=QPointF(getXAxis()->x2p(posSyss[i].x())*magnification, getYAxis()->x2p(posSyss[i].y())*magnification).toPoint();
@ -475,7 +502,7 @@ void JKQTPlotter::fillInternalStructForToolTipOfClosestDataPoint(double x0, doub
}
void JKQTPlotter::paintUserAction() {
if (currentMouseDragAction.isValid() && mouseDragingRectangle) {
if ((currentMouseDragAction.isValid() && mouseDragingRectangle) || (!currentMouseMoveAction.isEmpty())) {
image=oldImage;
if (image.width()>0 && image.height()>0 && !image.isNull()) {
JKQTPEnhancedPainter painter(&image);
@ -492,97 +519,100 @@ void JKQTPlotter::paintUserAction() {
const double y2=plotter->y2p(mouseDragRectYEnd)*magnification;
const double dx=x2-x1;
const double dy=y2-y1;
if (currentMouseDragAction.mode==jkqtpmdaDrawRectangleForEvent) {
painter.fillRect(QRectF(x1, y1, x2-x1, y2-y1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(x1, y1, x2-x1, y2-y1));
} else if (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) {
double xmin=mouseDragRectXStart;
double xmax=mouseDragRectXEnd;
double ymin=mouseDragRectYStart;
double ymax=mouseDragRectYEnd;
plotter->correctXYRangeForAspectRatio(xmin,xmax,ymin,ymax);
if (currentMouseDragAction.isValid() && mouseDragingRectangle) {
if (currentMouseDragAction.mode==jkqtpmdaDrawRectangleForEvent) {
painter.fillRect(QRectF(x1, y1, x2-x1, y2-y1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(x1, y1, x2-x1, y2-y1));
} else if (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) {
double xmin=mouseDragRectXStart;
double xmax=mouseDragRectXEnd;
double ymin=mouseDragRectYStart;
double ymax=mouseDragRectYEnd;
plotter->correctXYRangeForAspectRatio(xmin,xmax,ymin,ymax);
const double xz1=plotter->x2p(xmin)*magnification;
const double yz1=plotter->y2p(ymin)*magnification;
const double xz2=plotter->x2p(xmax)*magnification;
const double yz2=plotter->y2p(ymax)*magnification;
const double xz1=plotter->x2p(xmin)*magnification;
const double yz1=plotter->y2p(ymin)*magnification;
const double xz2=plotter->x2p(xmax)*magnification;
const double yz2=plotter->y2p(ymax)*magnification;
painter.fillRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawCircleForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawEllipse(QPointF(x1, y1), qMin(fabs(dx), fabs(dy)), qMin(fabs(dx), fabs(dy)));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawEllipseForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawEllipse(QPointF(x1, y1), fabs(dx), fabs(dy));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawLineForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawLine(QPointF(x1,y1), QPointF(x2,y2));
} else if (currentMouseDragAction.mode==jkqtpmdaRuler) {
painter.setPen(plotterStyle.userActionOpaquePen);
painter.setBrush(plotterStyle.userActionOpaqueBrush);
painter.drawLine(QPointF(x1,y1), QPointF(x2,y1));
painter.drawLine(QPointF(x2,y1), QPointF(x2,y2));
painter.drawLine(QPointF(x1,y1), QPointF(x2,y2));
const double dxy=sqrt(jkqtp_sqr(mouseDragRectXEnd-mouseDragRectXStart)+jkqtp_sqr(mouseDragRectYEnd-mouseDragRectYStart));
const double alpha=atan2((mouseDragRectYEnd-mouseDragRectYStart), (mouseDragRectXEnd-mouseDragRectXStart))/JKQTPSTATISTICS_PI*180.0;
const double dx=fabs(mouseDragRectXEnd-mouseDragRectXStart);
const double dy=fabs(mouseDragRectYEnd-mouseDragRectYStart);
painter.fillRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1), plotterStyle.userActionOverlayBrush);
painter.setPen(plotterStyle.userActionOverlayPen);
painter.drawRect(QRectF(xz1, yz1, xz2-xz1, yz2-yz1));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawCircleForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawEllipse(QPointF(x1, y1), qMin(fabs(dx), fabs(dy)), qMin(fabs(dx), fabs(dy)));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawEllipseForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawEllipse(QPointF(x1, y1), fabs(dx), fabs(dy));
} else if (currentMouseDragAction.mode==jkqtpmdaDrawLineForEvent) {
painter.setPen(plotterStyle.userActionOverlayPen);
painter.setBrush(plotterStyle.userActionOverlayBrush);
painter.drawLine(QPointF(x1,y1), QPointF(x2,y2));
} else if (currentMouseDragAction.mode==jkqtpmdaRuler) {
painter.setPen(plotterStyle.userActionOpaquePen);
painter.setBrush(plotterStyle.userActionOpaqueBrush);
painter.drawLine(QPointF(x1,y1), QPointF(x2,y1));
painter.drawLine(QPointF(x2,y1), QPointF(x2,y2));
painter.drawLine(QPointF(x1,y1), QPointF(x2,y2));
const double dxy=sqrt(jkqtp_sqr(mouseDragRectXEnd-mouseDragRectXStart)+jkqtp_sqr(mouseDragRectYEnd-mouseDragRectYStart));
const double alpha=atan2((mouseDragRectYEnd-mouseDragRectYStart), (mouseDragRectXEnd-mouseDragRectXStart))/JKQTPSTATISTICS_PI*180.0;
const double dx=fabs(mouseDragRectXEnd-mouseDragRectXStart);
const double dy=fabs(mouseDragRectYEnd-mouseDragRectYStart);
painter.setBrush(plotterStyle.userActionOpaqueBrush);
QString txt;
double a=0,d=0,so=0,w=0;
getPlotter()->getMathText()->setFontSize(plotterStyle.userActionFontSize);
getPlotter()->getMathText()->setFontRomanOrSpecial(plotterStyle.userActionFontName);
txt=QString::fromStdString("\\delta_{x}="+jkqtp_floattolatexstr(dx, 3));
getPlotter()->getMathText()->parse(txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
if (y1>y2) {
QRectF rec((x1+x2)/2.0-w/2.0, y1+2, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignTop, rec);
} else {
QRectF rec((x1+x2)/2.0-w/2.0, y1-2-a-d, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignBottom, rec);
}
txt=jkqtp_floattolatexqstr(dy, 3);
getPlotter()->getMathText()->parse("\\delta_{y}="+txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
//double dyh=a+d;
if (x2>x1) {
QRectF rec(x2+2, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignVCenter|Qt::AlignLeft, rec);
} else {
QRectF rec(x2-2-w, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignVCenter|Qt::AlignRight, rec);
}
txt=QString::fromStdString("\\delta_{x,y}="+jkqtp_floattolatexstr(dxy)+", \\alpha="+jkqtp_floattolatexstr(alpha, 1)+"\\degree, \\stfrac{\\mathrm{d}y}{\\mathrm{d}x}="+jkqtp_floattolatexstr(dy/dx, 1));
getPlotter()->getMathText()->parse(txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
if (x2<x1) {
QRectF rec((x1+x2)/2.0, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter,Qt::AlignTop|Qt::AlignLeft, rec);
} else {
QRectF rec((x1+x2)/2.0-w, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter,Qt::AlignTop|Qt::AlignRight, rec);
}
painter.setBrush(plotterStyle.userActionOpaqueBrush);
QString txt;
double a=0,d=0,so=0,w=0;
getPlotter()->getMathText()->setFontSize(plotterStyle.userActionFontSize);
getPlotter()->getMathText()->setFontRomanOrSpecial(plotterStyle.userActionFontName);
txt=QString::fromStdString("\\delta_{x}="+jkqtp_floattolatexstr(dx, 3));
getPlotter()->getMathText()->parse(txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
if (y1>y2) {
QRectF rec((x1+x2)/2.0-w/2.0, y1+2, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignTop, rec);
} else {
QRectF rec((x1+x2)/2.0-w/2.0, y1-2-a-d, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignBottom, rec);
}
txt=jkqtp_floattolatexqstr(dy, 3);
getPlotter()->getMathText()->parse("\\delta_{y}="+txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
//double dyh=a+d;
if (x2>x1) {
QRectF rec(x2+2, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignVCenter|Qt::AlignLeft, rec);
} else {
QRectF rec(x2-2-w, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter, Qt::AlignVCenter|Qt::AlignRight, rec);
}
txt=QString::fromStdString("\\delta_{x,y}="+jkqtp_floattolatexstr(dxy)+", \\alpha="+jkqtp_floattolatexstr(alpha, 1)+"\\degree, \\stfrac{\\mathrm{d}y}{\\mathrm{d}x}="+jkqtp_floattolatexstr(dy/dx, 1));
getPlotter()->getMathText()->parse(txt);
getPlotter()->getMathText()->getSizeDetail(painter, w, a, d, so);
if (x2<x1) {
QRectF rec((x1+x2)/2.0, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter,Qt::AlignTop|Qt::AlignLeft, rec);
} else {
QRectF rec((x1+x2)/2.0-w, (y1+y2)/2.0-(a+d)/2.0, w, a+d);
painter.fillRect(rec, plotterStyle.userActionOpaqueBrush);
getPlotter()->getMathText()->draw(painter,Qt::AlignTop|Qt::AlignRight, rec);
}
} else if (currentMouseDragAction.mode==jkqtpmdaToolTipForClosestDataPoint) {
}
if ((currentMouseDragAction.isValid() && currentMouseDragAction.mode==jkqtpmdaToolTipForClosestDataPoint) || currentMouseMoveAction.contains(jkqtpmmaToolTipForClosestDataPoint)) {
if (mouseDragMarkers.size()>0) {
const int markerD=getCurrentPlotterStyle().userActionMarkerDiameter;
if (getCurrentPlotterStyle().userActionMarkerType==jkqtpuamtCircle) {
@ -695,6 +725,7 @@ void JKQTPlotter::mouseMoveEvent ( QMouseEvent * event ) {
if (!plotterStyle.toolbarEnabled) {
toolbar->hide();
}
currentMouseMoveAction.clear();
if (currentMouseDragAction.isValid()) {
if (( (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) ||
(currentMouseDragAction.mode==jkqtpmdaDrawRectangleForEvent) ||
@ -761,6 +792,21 @@ void JKQTPlotter::mouseMoveEvent ( QMouseEvent * event ) {
event->accept();
/*if (emitSignals)*/ //emit plotMouseMove(x, y);
}
} else if (event->buttons()==Qt::NoButton) {
bool foundIT=false;
auto actionIT=findMatchingMouseMoveAction(event->modifiers(), &foundIT);
if (foundIT) {
// we found a matching action
currentMouseMoveAction.insert(actionIT.value());
if(actionIT.value()==jkqtpmmaToolTipForClosestDataPoint){
mouseDragRectXStart=plotter->p2x(event->x()/magnification);
mouseDragRectYStart=plotter->p2y((event->y()-getPlotYOffset())/magnification);
mouseDragRectXStartPixel=event->x();
mouseDragRectYStartPixel=event->y();
fillInternalStructForToolTipOfClosestDataPoint(plotter->p2x(event->x()/magnification), plotter->p2y((event->y()-getPlotYOffset())/magnification));
}
paintUserAction();
}
}
// emit move signal, if event occured inside plot only
@ -806,7 +852,7 @@ void JKQTPlotter::mousePressEvent ( QMouseEvent * event ){
event->accept();
}
updateCursor();
if ((actionIT!=plotterStyle.registeredMouseDragActionModes.end() || actionIT!=registeredOverrideMouseDragActionModes.end()) && actionIT.value()==jkqtpmdaToolTipForClosestDataPoint) {
if (foundIT && actionIT.value()==jkqtpmdaToolTipForClosestDataPoint) {
fillInternalStructForToolTipOfClosestDataPoint(mouseDragRectXStart, mouseDragRectYStart);
paintUserAction();
}
@ -1043,12 +1089,13 @@ void JKQTPlotter::initContextMenu()
contextMenu->addAction(plotter->getActionZoomAll());
contextMenu->addAction(plotter->getActionZoomIn());
contextMenu->addAction(plotter->getActionZoomOut());
contextMenu->addSeparator();
contextMenu->addAction(actMouseMoveToolTip);
contextMenu->addSection(tr("left mouse button tool"));
contextMenu->addAction(actMouseLeftAsDefault);
contextMenu->addAction(actMouseLeftAsPanView);
contextMenu->addAction(actMouseLeftAsZoomRect);
contextMenu->addAction(actMouseLeftAsRuler);
contextMenu->addAction(actMouseLeftAsToolTip);
contextMenu->addSeparator();
QMenu* menVisibleGroup=new QMenu(tr("Graph Visibility"), contextMenu);
for (size_t i=0; i<getPlotter()->getGraphCount(); i++) {
@ -1102,7 +1149,11 @@ void JKQTPlotter::initContextMenu()
void JKQTPlotter::updateCursor() {
if (!currentMouseDragAction.isValid()) {
setCursor(QCursor(Qt::ArrowCursor));
if (currentMouseMoveAction.contains(jkqtpmmaToolTipForClosestDataPoint)) {
setCursor(QCursor(Qt::CrossCursor));
} else {
setCursor(QCursor(Qt::ArrowCursor));
}
} else {
if (currentMouseDragAction.mode==jkqtpmdaZoomByRectangle) {
static QBitmap cursor(":/JKQTPlotter/jkqtp_cursor_zoom.png");
@ -1400,7 +1451,7 @@ void JKQTPlotter::setMouseLeftActionAsRuler()
setOverrideMouseDragAction(Qt::LeftButton, Qt::NoModifier, JKQTPMouseDragActions::jkqtpmdaRuler);
}
void JKQTPlotter::setMouseLeftActionAsToolTip()
void JKQTPlotter::setMouseLeftDragActionAsToolTip()
{
setOverrideMouseDragAction(Qt::LeftButton, Qt::NoModifier, JKQTPMouseDragActions::jkqtpmdaToolTipForClosestDataPoint);
}
@ -1410,31 +1461,63 @@ void JKQTPlotter::resetMouseLeftAction()
resetOverrideMouseDragAction(Qt::LeftButton, Qt::NoModifier);
}
void JKQTPlotter::setMouseMoveActionAsToolTip(bool enabled)
{
if (enabled) {
registerMouseMoveAction(Qt::NoModifier, JKQTPMouseMoveActions::jkqtpmmaToolTipForClosestDataPoint);
} else {
deregisterMouseMoveAction(Qt::NoModifier);
}
}
void JKQTPlotter::setMouseActionToolbarActionsActive(bool __value)
{
actgrpMouseLeft->setVisible(__value);
actMouseMoveToolTip->setVisible(__value);
}
QAction* JKQTPlotter::getActMouseLeftAsDefault() const {
QAction* JKQTPlotter::getActMouseLeftAsDefault() {
return actMouseLeftAsDefault;
}
QAction *JKQTPlotter::getActMouseLeftAsZoomRect() const
QAction *JKQTPlotter::getActMouseLeftAsZoomRect()
{
return actMouseLeftAsZoomRect;
}
QAction *JKQTPlotter::getActMouseLeftAsPanView() const
QAction *JKQTPlotter::getActMouseLeftAsPanView()
{
return actMouseLeftAsPanView;
}
QAction* JKQTPlotter::getActMouseLeftAsRuler() const {
QAction* JKQTPlotter::getActMouseLeftAsRuler() {
return actMouseLeftAsRuler;
}
QAction* JKQTPlotter::getActMouseLeftAsToolTip() const {
return actMouseLeftAsToolTip;
const QAction* JKQTPlotter::getActMouseLeftAsDefault() const {
return actMouseLeftAsDefault;
}
const QAction *JKQTPlotter::getActMouseLeftAsZoomRect() const
{
return actMouseLeftAsZoomRect;
}
const QAction *JKQTPlotter::getActMouseLeftAsPanView() const
{
return actMouseLeftAsPanView;
}
const QAction* JKQTPlotter::getActMouseLeftAsRuler() const {
return actMouseLeftAsRuler;
}
const QAction* JKQTPlotter::getActMouseMoveToolTip() const {
return actMouseMoveToolTip;
}
QAction* JKQTPlotter::getActMouseMoveToolTip() {
return actMouseMoveToolTip;
}
void JKQTPlotter::setOverrideMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifier, JKQTPMouseDragActions action)
@ -1545,11 +1628,12 @@ void JKQTPlotter::populateToolbar(QToolBar *toolbar) const
toolbar->addAction(plotter->getActionZoomIn());
toolbar->addAction(plotter->getActionZoomOut());
toolbar->addSeparator();
toolbar->addAction(actMouseMoveToolTip);
toolbar->addSeparator();
toolbar->addAction(actMouseLeftAsDefault);
toolbar->addAction(actMouseLeftAsPanView);
toolbar->addAction(actMouseLeftAsZoomRect);
toolbar->addAction(actMouseLeftAsRuler);
toolbar->addAction(actMouseLeftAsToolTip);
if (actions().size()>0) {
toolbar->addSeparator();
toolbar->addActions(actions());
@ -1731,6 +1815,20 @@ JKQTPMouseWheelActionsHashMapIterator JKQTPlotter::findMatchingMouseWheelAction(
//return plotterStyle.registeredMouseWheelActions.find(modifiers);
}
JKQTPMouseMoveActionsHashMapIterator JKQTPlotter::findMatchingMouseMoveAction(Qt::KeyboardModifiers modifiers, bool *found) const
{
if (found) *found=false;
for (JKQTPMouseMoveActionsHashMapIterator it=plotterStyle.registeredMouseMoveActions.begin(); it!=plotterStyle.registeredMouseMoveActions.end(); ++it) {
if (it.key()==modifiers) {
if (found) *found=true;
return it;
}
}
return plotterStyle.registeredMouseMoveActions.end();
//return plotterStyle.registeredMouseMoveActions.find(modifiers);
}
void JKQTPlotter::setPlotUpdateEnabled(bool enable)
{
doDrawing=enable;

View File

@ -370,7 +370,7 @@ JKQTPLOTTER_LIB_EXPORT void initJKQTPlotterResources();
* \image html contextmenu_graphvisibility.gif
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEWHEEL Actions When a Mouse Wheel Event Occurs
* The actions to be performed when the mouse hweel is operated are specified in JKQTPMouseWheelActions.
* The actions to be performed when the mouse wheel is operated are specified in JKQTPMouseWheelActions.
* You can bind one of these actions to the mouse-wheel (under the condition that a specified Qt::KeyboardModifiers
* is pressed) by using these functions:
* - registerMouseWheelAction() tells JKQTPlotter to perform a certain action (selected from JKQTPMouseWheelActions)
@ -386,7 +386,7 @@ JKQTPLOTTER_LIB_EXPORT void initJKQTPlotterResources();
* In addition the signal void plotMouseWheelOperated() is emitted whenever a mouse-wheel event occurs.
*
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE Signaling When Mouse Moves
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE Mouse Move Signaling and Actions
* In addition the signal plotMouseMove() is called whenever the mouse moves over the plot.
* Additional signals may be emitted, depending on the currently active JKQTPlotter::MouseActionMode.
*
@ -395,6 +395,14 @@ JKQTPLOTTER_LIB_EXPORT void initJKQTPlotterResources();
*
* \image html mousepositiondisplay.gif
*
* The actions to be performed when the mouse moves without a mouse-button pressed are specified in JKQTPMouseMoveActions.
* You can bind one of these actions to the mouse (under the condition that a specified Qt::KeyboardModifiers
* is pressed) by using these functions:
* - registerMouseMoveAction() tells JKQTPlotter to perform a certain action (selected from JKQTPMouseMoveActions)
* when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed.
* - deregisterMouseMoveAction() deletes a previously defined user-interaction
* - clearAllMouseMoveActions() deletes all previously specified user-actions
* .
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_FASTRESIZING Fast Resizing of a Plot Widget
* When the user resized the widget, the graph would in principle have to be readrawn for every intermediate step.
@ -712,6 +720,13 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief deletes all mouse-wheel actions \see registerMouseWheelAction(), deregisterMouseWheelAction(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */
void clearAllMouseWheelActions();
/** \brief specifies the action to perform on a mouse move event when a given modifier is pressed \see deregisterMouseMoveAction(), clearAllMouseMoveActions(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */
void registerMouseMoveAction(Qt::KeyboardModifiers modifier, JKQTPMouseMoveActions action);
/** \brief deletes all mouse-move actions registered for a given \a modifier \see registerMouseMoveAction(), clearAllMouseMoveActions(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */
void deregisterMouseMoveAction(Qt::KeyboardModifiers modifier);
/** \brief deletes all mouse-move actions \see registerMouseMoveAction(), deregisterMouseMoveAction(), \ref JKQTPLOTTER_USERMOUSEINTERACTION */
void clearAllMouseMoveActions();
/*! \brief returns the currently set special context menu object
*
* \see \ref JKQTPLOTTER_SPECIALCONTEXTMENU, setSpecialContextMenu(), menuSpecialContextMenu, contextMenuOpened(), \ref JKQTPlotterUserInteraction
@ -901,16 +916,26 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
*/
void saveCurrentPlotterStyle(QSettings& settings, const QString& group="plots/", bool alsoSaveBaseStyle=true) const;
/** \brief \copydoc actMouseLeftAsToolTip */
QAction *getActMouseLeftAsToolTip() const;
/** \brief \copydoc actMouseMoveToolTip */
QAction *getActMouseMoveToolTip();
/** \brief \copydoc actMouseLeftAsRuler */
QAction *getActMouseLeftAsRuler() const;
QAction *getActMouseLeftAsRuler();
/** \brief \copydoc actMouseLeftAsDefault */
QAction *getActMouseLeftAsDefault() const;
QAction *getActMouseLeftAsDefault();
/** \brief \copydoc actMouseLeftAsZoomRect */
QAction *getActMouseLeftAsZoomRect() const;
QAction *getActMouseLeftAsZoomRect();
/** \brief \copydoc actMouseLeftAsPanView */
QAction *getActMouseLeftAsPanView() const;
QAction *getActMouseLeftAsPanView();
/** \brief \copydoc actMouseMoveToolTip */
const QAction *getActMouseMoveToolTip() const;
/** \brief \copydoc actMouseLeftAsRuler */
const QAction *getActMouseLeftAsRuler() const;
/** \brief \copydoc actMouseLeftAsDefault */
const QAction *getActMouseLeftAsDefault() const;
/** \brief \copydoc actMouseLeftAsZoomRect */
const QAction *getActMouseLeftAsZoomRect() const;
/** \brief \copydoc actMouseLeftAsPanView */
const QAction *getActMouseLeftAsPanView() const;
public slots:
@ -1224,7 +1249,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
* \see setX(), setX(), zoomToFit(), setAbsoluteXY(), JKQTBasePlotter::setXY()
*/
inline void setXY(double xminn, double xmaxx, double yminn, double ymaxx) { plotter->setXY(xminn, xmaxx, yminn, ymaxx); }
signals:
/** \brief emitted whenever the mouse moves
*
@ -1416,9 +1440,16 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief the currently executed MouseDragAction */
MouseDragAction currentMouseDragAction;
/** \brief the currently executed MouseMoveActions */
QSet<JKQTPMouseMoveActions> currentMouseMoveAction;
/** \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;
/** \brief searches JKQTPlotterStyle::registeredMouseMoveActions for a matching action */
JKQTPMouseMoveActionsHashMapIterator findMatchingMouseMoveAction(Qt::KeyboardModifiers modifiers, bool *found=nullptr) const;
/** \brief searches JKQTPlotterStyle::registeredMouseWheelActions for a matching action */
JKQTPMouseWheelActionsHashMapIterator findMatchingMouseWheelAction(Qt::KeyboardModifiers modifiers, bool *found=nullptr) const;
@ -1545,9 +1576,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
* - if displayMousePosition is \c true , stores the current mouse position in mousePosX, mousePosY
* - if necessary, contributes to user-actions started by mousePressEvent()
* - emits plotMouseMove() if the mouse is inside the plot rectangle .
* - execute mouseMoveActions
* .
*
* \see mousePosX, mousePosY
* \see registerMouseWheelAction(), deregisterMouseWheelAction(), registeredMouseWheelActions
*/
void mouseMoveEvent ( QMouseEvent * event );
@ -1683,7 +1716,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief action that activates the ruler tool (override!) */
QAction* actMouseLeftAsRuler;
/** \brief action that activates the tooltip tool (override!) */
QAction* actMouseLeftAsToolTip;
QAction* actMouseMoveToolTip;
/** \brief action that activates the zoom rectangle tool (override!) */
QAction* actMouseLeftAsZoomRect;
/** \brief action that activates the pan view tool (override!) */
@ -1715,10 +1748,12 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPlotter: public QWidget {
void setMouseLeftActionAsZoomRect();
/** \brief action that activates the ruler tool \see resetMouseLeftAction(), setMouseLeftActionAsToolTip() */
void setMouseLeftActionAsRuler();
/** \brief action that activates the tooltip tool \see setMouseLeftActionAsRuler(), resetMouseLeftAction() */
void setMouseLeftActionAsToolTip();
/** \brief action that activates the tooltip tool, when dragging the mouse with the left button pressed \see resetMouseLeftAction() */
void setMouseLeftDragActionAsToolTip();
/** \brief resets any previously set override action for the left mouse-button, un-modified \see setMouseLeftActionAsRuler(), setMouseLeftActionAsToolTip() */
void resetMouseLeftAction();
/** \brief action that (de)activates the tooltip tool, when moving the mouse without any button pressed \see setMouseLeftActionAsRuler(), resetMouseLeftAction() */
void setMouseMoveActionAsToolTip(bool enabled);
};

View File

@ -25,6 +25,7 @@ JKQTPlotterStyle::JKQTPlotterStyle():
usePaletteColors(true),
registeredMouseDragActionModes(),
registeredMouseWheelActions(),
registeredMouseMoveActions(),
registeredMouseDoubleClickActions()
{
// default user-actions:
@ -97,6 +98,7 @@ void JKQTPlotterStyle::loadSettings(const QSettings &settings, const QString &gr
return -1;
};
registeredMouseMoveActions.clear();
registeredMouseWheelActions.clear();
registeredMouseDragActionModes.clear();
registeredMouseDoubleClickActions.clear();
@ -125,6 +127,12 @@ void JKQTPlotterStyle::loadSettings(const QSettings &settings, const QString &gr
auto action=String2JKQTPMouseWheelActions(settings.value(group+"actions/mouse_wheel"+QString::number(id)+"/action", jkqtpmwaZoomByWheel).toString());
registeredMouseWheelActions[modifiers]=action;
}
id=readID(k, group+"actions/mouse_move");
if (id>=0) {
auto modifiers=jkqtp_String2KeyboardModifiers(settings.value(group+"actions/mouse_move"+QString::number(id)+"/modifiers", Qt::NoModifier).toString());
auto action=String2JKQTPMouseMoveActions(settings.value(group+"actions/mouse_move"+QString::number(id)+"/action", jkqtpmwaZoomByWheel).toString());
registeredMouseMoveActions[modifiers]=action;
}
}
}
}
@ -190,6 +198,13 @@ void JKQTPlotterStyle::saveSettings(QSettings &settings, const QString &group) c
settings.setValue(group+"actions/mouse_wheel"+QString::number(cnt)+"/action", JKQTPMouseWheelActions2String(it.value()));
cnt++;
}
cnt=0;
for (auto it=registeredMouseMoveActions.begin(); it!=registeredMouseMoveActions.end(); ++it) {
settings.setValue(group+"actions/mouse_move"+QString::number(cnt)+"/modifiers", jkqtp_KeyboardModifiers2String(it.key()));
settings.setValue(group+"actions/mouse_move"+QString::number(cnt)+"/action", JKQTPMouseMoveActions2String(it.value()));
cnt++;
}
}

View File

@ -151,6 +151,9 @@ public:
JKQTPMouseDoubleClickActionsHashMap registeredMouseDoubleClickActions;
/** \brief the currently executed MouseMoveAction */
JKQTPMouseMoveActionsHashMap registeredMouseMoveActions;
};

View File

@ -543,3 +543,15 @@ JKQTPUserActionMarkerType String2JKQTPUserActionMarkerType(const QString &act)
if (m=="circle+crosshair" || m=="circle+cross") return jkqtpuamtCircleAndCrossHair;
return jkqtpuamtCircle;
}
QString JKQTPMouseMoveActions2String(JKQTPMouseMoveActions act)
{
if (act==jkqtpmmaToolTipForClosestDataPoint) return "ToolTipForClosestDataPoint";
return "ToolTipForClosestDataPoint";
}
JKQTPMouseMoveActions String2JKQTPMouseMoveActions(const QString &s)
{
if (s=="jkqtpmmatooltipforclosestdatapoint"||s=="closestdatapointtooltip"||s=="tooltipforclosestdatapoint"||s=="tooltip") return jkqtpmmaToolTipForClosestDataPoint;
return jkqtpmmaToolTipForClosestDataPoint;
}

View File

@ -172,6 +172,29 @@ JKQTPLOTTER_LIB_EXPORT QString JKQTPMouseWheelActions2String(JKQTPMouseWheelActi
*/
JKQTPLOTTER_LIB_EXPORT JKQTPMouseWheelActions String2JKQTPMouseWheelActions(const QString &act);
/** \brief Availble action this JKQtPlotter can perform when mouse events occur.
* This allows you to e.g. draw rectangles or lines over the plot and receive a signal, when the drawing finishes
* \ingroup jkqtpplottersupprt
*/
enum JKQTPMouseMoveActions {
jkqtpmmaToolTipForClosestDataPoint /*!< \brief shows a tooltip with data of the closest data-point in the plot \image html tooltiptool.gif */
};
/** \brief convert a JKQTPMouseDragActions to a <a href="http://doc.qt.io/qt-5/qstring.html">QString</a>
* \ingroup jkqtpplottersupprt
*
* \see String2JKQTPMouseDragActions(), JKQTPMouseDragActions
*/
JKQTPLOTTER_LIB_EXPORT QString JKQTPMouseMoveActions2String(JKQTPMouseMoveActions act);
/** \brief convert a <a href="http://doc.qt.io/qt-5/qstring.html">QString</a> (created by JKQTPMouseDragActions2String() ) to JKQTPMouseDragActions
* \ingroup jkqtpplottersupprt
*
* \see JKQTPMouseDragActions2String(), JKQTPMouseDragActions
*/
JKQTPLOTTER_LIB_EXPORT JKQTPMouseMoveActions String2JKQTPMouseMoveActions(const QString &button);
/** \brief modes for the context menu
* \ingroup jkqtpplottersupprt
*/
@ -217,6 +240,12 @@ typedef QHash<QPair<Qt::MouseButton,Qt::KeyboardModifiers>, JKQTPMouseDoubleClic
typedef JKQTPMouseDoubleClickActionsHashMap::const_iterator JKQTPMouseDoubleClickActionsHashMapIterator;
/** \brief data structure for storage of assigned JKQTPMouseMoveActions \see JKQTPMouseMoveActionsHashMapIterator
* \ingroup jkqtpplottersupprt */
typedef QHash<Qt::KeyboardModifiers, JKQTPMouseMoveActions> JKQTPMouseMoveActionsHashMap;
/** \brief iterator for JKQTPMouseMoveActionsHashMap \see JKQTPMouseMoveActionsHashMap
* \ingroup jkqtpplottersupprt */
typedef JKQTPMouseMoveActionsHashMap::const_iterator JKQTPMouseMoveActionsHashMapIterator;
/** \brief Specifies how a fill-color is derived from a given color
* \ingroup jkqtpplotter_styling