finished rework of user-interaction API for the mouse

This commit is contained in:
Jan W. Krieger 2019-01-28 17:05:03 +01:00
parent 17a4473e4f
commit c5b9504189
4 changed files with 342 additions and 163 deletions

View File

@ -90,12 +90,6 @@ 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
chkZoomByMouseWheel=new QCheckBox(this);
chkZoomByMouseWheel->setChecked(plot->getZoomByMouseWheel());
layForm->addRow("zoom by mouse wheel:", chkZoomByMouseWheel);
connect(chkZoomByMouseWheel, SIGNAL(toggled(bool)), plot, SLOT(setZoomByMouseWheel(bool)));
// 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);
@ -161,6 +155,46 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
special->addMenu("Special submenu")->addAction("Special subentry 1 (no action!)");
plot->setSpecialContextMenu(special);
// add a QComboBox that allows to set the left mouse button double-click action for the JKQTPlotter
cmbLeftDoubleClickMouseAction=new QComboBox(this);
layForm->addRow("mouse action: left double-click, no modifiers", cmbLeftDoubleClickMouseAction);
cmbLeftDoubleClickMouseAction->addItem("ClickZoomsIn");
cmbLeftDoubleClickMouseAction->addItem("ClickZoomsOut");
cmbLeftDoubleClickMouseAction->addItem("ClickOpensContextMenu");
cmbLeftDoubleClickMouseAction->addItem("ClickOpensSpecialContextMenu");
cmbLeftDoubleClickMouseAction->addItem("ClickMovesViewport");
cmbLeftDoubleClickMouseAction->addItem("NoAction");
cmbLeftDoubleClickMouseAction->setCurrentIndex(4);
connect(cmbLeftDoubleClickMouseAction, SIGNAL(currentIndexChanged(int)), this, SLOT(setLeftDoubleClickMouseAction(int)));
setLeftDoubleClickMouseAction(cmbLeftDoubleClickMouseAction->currentIndex());
// add a QComboBox that allows to set the left mouse button double-click action for the JKQTPlotter
cmbRightDoubleClickMouseAction=new QComboBox(this);
layForm->addRow("mouse action: right double-click, no modifiers", cmbRightDoubleClickMouseAction);
cmbRightDoubleClickMouseAction->addItem("ClickZoomsIn");
cmbRightDoubleClickMouseAction->addItem("ClickZoomsOut");
cmbRightDoubleClickMouseAction->addItem("ClickOpensContextMenu");
cmbRightDoubleClickMouseAction->addItem("ClickOpensSpecialContextMenu");
cmbRightDoubleClickMouseAction->addItem("ClickMovesViewport");
cmbRightDoubleClickMouseAction->addItem("NoAction");
cmbRightDoubleClickMouseAction->setCurrentIndex(1);
connect(cmbRightDoubleClickMouseAction, SIGNAL(currentIndexChanged(int)), this, SLOT(setRightDoubleClickMouseAction(int)));
setRightDoubleClickMouseAction(cmbRightDoubleClickMouseAction->currentIndex());
// add a QComboBox that allows to set the mouse wheel action without modifiers
cmbMouseWheelAction=new QComboBox(this);
layForm->addRow("mouse action: mouse wheel, no modifiers", cmbMouseWheelAction);
cmbMouseWheelAction->addItem("ZoomByWheel");
cmbMouseWheelAction->addItem("PanByWheel");
cmbMouseWheelAction->addItem("NoAction");
cmbMouseWheelAction->setCurrentIndex(0);
connect(cmbMouseWheelAction, SIGNAL(currentIndexChanged(int)), this, SLOT(setMouseWheelNoModAction(int)));
setMouseWheelNoModAction(cmbMouseWheelAction->currentIndex());
// and add a QLabel to show the different events of the JKQTPlotter:
labMouseMoved=new QLabel(this);
layForm->addRow("last mouse moved:", labMouseMoved);
@ -171,6 +205,7 @@ TestUserInteraction::TestUserInteraction(QWidget *parent) :
connect(plot, SIGNAL(plotMouseMove(double, double)), this, SLOT(plotMouseMove(double, double)));
connect(plot, SIGNAL(plotMouseClicked(double, double, Qt::KeyboardModifiers , Qt::MouseButton)), this, SLOT(plotMouseClicked(double, double, Qt::KeyboardModifiers, Qt::MouseButton)));
connect(plot, SIGNAL(plotMouseDoubleClicked(double, double, Qt::KeyboardModifiers, Qt::MouseButton)), this, SLOT(plotMouseDoubleClicked(double, double, Qt::KeyboardModifiers, Qt::MouseButton)));
connect(plot, SIGNAL(plotMouseWheelOperated(double, double, Qt::KeyboardModifiers, int, int)), this, SLOT(plotMouseWheelOperated(double, double, Qt::KeyboardModifiers, int, int)));
connect(plot, SIGNAL(plotNewZoomRectangle(double, double, double, double, Qt::KeyboardModifiers)), this, SLOT(plotNewZoomRectangle(double, double, double, double, Qt::KeyboardModifiers)));
connect(plot, SIGNAL(contextMenuOpened(double, double, QMenu*)), this, SLOT(contextMenuOpened(double, double, QMenu*)));
connect(plot, SIGNAL(zoomChangedLocally(double, double, double, double, JKQTPlotter*)), this, SLOT(zoomChangedLocally(double, double, double, double, JKQTPlotter*)));
@ -213,6 +248,24 @@ void TestUserInteraction::setRightClickContextMenu(int index)
plot->setContextMenuMode(static_cast<JKQTPlotter::ContextMenuModes>(index));
}
void TestUserInteraction::setLeftDoubleClickMouseAction(int index)
{
if (index>=cmbLeftDoubleClickMouseAction->count()-1) plot->deregisterMouseDoubleClickAction(Qt::LeftButton, Qt::NoModifier);
else plot->registerMouseDoubleClickAction(Qt::LeftButton, Qt::NoModifier, static_cast<JKQTPlotter::MouseDoubleClickActions>(index));
}
void TestUserInteraction::setRightDoubleClickMouseAction(int index)
{
if (index>=cmbLeftDoubleClickMouseAction->count()-1) plot->deregisterMouseDoubleClickAction(Qt::RightButton, Qt::NoModifier);
else plot->registerMouseDoubleClickAction(Qt::RightButton, Qt::NoModifier, static_cast<JKQTPlotter::MouseDoubleClickActions>(index));
}
void TestUserInteraction::setMouseWheelNoModAction(int index)
{
if (index>=cmbMouseWheelAction->count()-1) plot->deregisterMouseWheelAction(Qt::NoModifier);
else plot->registerMouseWheelAction(Qt::NoModifier, static_cast<JKQTPlotter::MouseWheelActions>(index));
}
void TestUserInteraction::plotMouseMove(double x, double y)
{
labMouseMoved->setText(QString("plotMouseMove(%1, %2)").arg(x).arg(y));
@ -233,6 +286,11 @@ void TestUserInteraction::plotNewZoomRectangle(double mouseDragRectXStart, doubl
labMouseAction->setText(QString("plotNewZoomRectangle(x=%1..%2, y=%3..%4, modifiers=%5)").arg(mouseDragRectXStart).arg(mouseDragRectXEnd).arg(mouseDragRectYStart).arg(mouseDragRectYEnd).arg(KeyboradMod2String(modifiers)));
}
void TestUserInteraction::plotMouseWheelOperated(double x, double y, Qt::KeyboardModifiers modifiers, int deltaAngleX, int deltaAngleY)
{
labMouseAction->setText(QString("plotMouseWheelOperated(x=%1, y%2, modifiers=%3, deltaAngleX=%4, deltaAngleY=%5)").arg(x).arg(y).arg(KeyboradMod2String(modifiers)).arg(deltaAngleX).arg(deltaAngleY));
}
void TestUserInteraction::contextMenuOpened(double x, double y, QMenu *contextMenu)
{
contextMenu->addSeparator();

View File

@ -26,11 +26,15 @@ class TestUserInteraction : public QMainWindow
void setRightMouseAction(int index);
void setPlotMagnification(int index);
void setRightClickContextMenu(int index);
void setLeftDoubleClickMouseAction(int index);
void setRightDoubleClickMouseAction(int index);
void setMouseWheelNoModAction(int index);
void plotMouseMove(double x, double y);
void plotMouseClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
void plotMouseDoubleClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
void plotNewZoomRectangle(double mouseDragRectXStart, double mouseDragRectXEnd, double mouseDragRectYStart, double mouseDragRectYEnd, Qt::KeyboardModifiers modifiers);
void plotMouseWheelOperated(double x, double y, Qt::KeyboardModifiers modifiers, int deltaAngleX, int deltaAngleY);
void contextMenuOpened(double x, double y, QMenu* contextMenu);
void zoomChangedLocally(double newxmin, double newxmax, double newymin, double newymax, JKQTPlotter* sender);
void userScribbleClick(double x, double y, Qt::KeyboardModifiers modifiers, bool first, bool last);
@ -53,9 +57,11 @@ class TestUserInteraction : public QMainWindow
QComboBox* cmbLeftCtrlModMouseAction;
QComboBox* cmbRightNoModMouseAction;
QComboBox* cmbRightClickContextMenu;
QComboBox* cmbRightDoubleClickMouseAction;
QComboBox* cmbLeftDoubleClickMouseAction;
QComboBox* cmbMouseWheelAction;
QCheckBox* chkLogX;
QCheckBox* chkLogY;
QCheckBox* chkZoomByMouseWheel;
QLabel* labMouseAction;
QLabel* labMouseMoved;
QLabel* labMouseClicked;

View File

@ -69,7 +69,6 @@ JKQTPlotter::JKQTPlotter(QWidget *parent):
void JKQTPlotter::init(bool datastore_internal, QWidget* parent, JKQTPDatastore* datast)
{
leftDoubleClickAction=LeftDoubleClickDefault;
menuSpecialContextMenu=nullptr;
mouseContextX=0;
mouseContextY=0;
@ -86,7 +85,6 @@ void JKQTPlotter::init(bool datastore_internal, QWidget* parent, JKQTPDatastore*
mousePosX=0;
mousePosY=0;
rightMouseButtonAction=JKQTPlotter::RightMouseButtonContextMenu;
connect(plotter, SIGNAL(plotUpdated()), this, SLOT(redrawPlot()));
connect(plotter, SIGNAL(overlaysUpdated()), this, SLOT(redrawOverlays()));
@ -106,13 +104,17 @@ void JKQTPlotter::init(bool datastore_internal, QWidget* parent, JKQTPDatastore*
displayMousePosition=true;
displayToolbar=true;
toolbarAlwaysOn=false;
// set default user-interactions:
contextMenuMode=ContextMenuModes::StandardContextMenu;
registerMouseDragAction(Qt::LeftButton, Qt::NoModifier, MouseDragActions::ZoomRectangle);
registerMouseDragAction(Qt::LeftButton, Qt::ControlModifier, MouseDragActions::PanPlotOnMove);
registerMouseDoubleClickAction(Qt::LeftButton, Qt::NoModifier, MouseDoubleClickActions::ClickMovesViewport);
registerMouseWheelAction(Qt::NoModifier, MouseWheelActions::ZoomByWheel);
zoomByMouseWheel=true;
// enable mouse-tracking, so mouseMoved-Events can be caught
setMouseTracking(true);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
toolbar=new JKVanishQToolBar(this);
@ -228,6 +230,24 @@ void JKQTPlotter::setUserActionCompositionMode(const QPainter::CompositionMode &
}
}
void JKQTPlotter::registerMouseWheelAction(Qt::KeyboardModifier modifier, JKQTPlotter::MouseWheelActions action)
{
registeredMouseWheelActions[modifier]=action;
}
void JKQTPlotter::deregisterMouseWheelAction(Qt::KeyboardModifier modifier)
{
registeredMouseWheelActions.remove(modifier);
}
void JKQTPlotter::clearAllMouseWheelActions()
{
registeredMouseWheelActions.clear();
}
QPainter::CompositionMode JKQTPlotter::getUserActionCompositionMode() const
{
return this->userActionCompositionMode;
@ -382,7 +402,7 @@ void JKQTPlotter::mousePressEvent ( QMouseEvent * event ){
currentMouseDragAction.clear();
auto actionIT=findMatchingMouseDragAction(event->button(), event->modifiers());
if (actionIT!=registeredMouseActionModes.end()) {
if (actionIT!=registeredMouseDragActionModes.end()) {
// we found a matching action
currentMouseDragAction=MouseDragAction(actionIT.key().first, actionIT.key().second, actionIT.value());
mouseLastClickX=event->x();
@ -470,41 +490,55 @@ void JKQTPlotter::mouseReleaseEvent ( QMouseEvent * event ){
}
void JKQTPlotter::mouseDoubleClickEvent ( QMouseEvent * event ){
auto itAction=findMatchingMouseDoubleClickAction(event->button(), event->modifiers());
if (itAction!=registeredMouseDoubleClickActions.end()) {
// we found an action to perform on this double-click
if (itAction.value()==MouseDoubleClickActions::ClickOpensContextMenu) {
openStandardContextMenu(event->x(), event->y());
} else if (itAction.value()==MouseDoubleClickActions::ClickOpensSpecialContextMenu) {
openSpecialContextMenu(event->x(), event->y());
} else if (itAction.value()==MouseDoubleClickActions::ClickZoomsIn || itAction.value()==MouseDoubleClickActions::ClickZoomsOut) {
double factor=4.0;
if (itAction.value()==MouseDoubleClickActions::ClickZoomsOut) factor=1;
double xmin=plotter->p2x(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor);
double xmax=plotter->p2x(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor);
double ymin=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor);
double ymax=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor);
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
xmin=getXMin();
xmax=getXMax();
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
ymin=getYMin();
ymax=getYMax();
}
plotter->setXY(xmin, xmax, ymin, ymax);
update();
} else if (itAction.value()==MouseDoubleClickActions::ClickMovesViewport) {
QRectF zoomRect= QRectF(QPointF(plotter->x2p(getXAxis()->getMin()),plotter->y2p(getYAxis()->getMax())), QPointF(plotter->x2p(getXAxis()->getMax()),plotter->y2p(getYAxis()->getMin())));
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.moveCenter(QPointF(zoomRect.center().x(), event->y()));
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
zoomRect.moveCenter(QPointF(event->x(), zoomRect.center().y()));
} else {
zoomRect.moveCenter(QPointF(event->x(), event->y()));
}
setXY(plotter->p2x(zoomRect.left()), plotter->p2x(zoomRect.right()), plotter->p2y(zoomRect.bottom()), plotter->p2y(zoomRect.top()));
}
}
// only react on double clicks inside the widget
if ( (event->x()/magnification>=plotter->getInternalPlotBorderLeft()) && (event->x()/magnification<=plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) &&
((event->y()-getPlotYOffset())/magnification>=plotter->getInternalPlotBorderTop()) && ((event->y()-getPlotYOffset())/magnification<=plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
mouseLastClickX=event->x();
mouseLastClickY=event->y();
if (event->button()==Qt::LeftButton) {
if (leftDoubleClickAction==LeftDoubleClickContextMenu) {
openStandardContextMenu(event->x(), event->y());
event->accept();
} else if (leftDoubleClickAction==LeftDoubleClickSpecialContextMenu) {
openSpecialContextMenu(event->x(), event->y());
event->accept();
}
}
if (rightMouseButtonAction==JKQTPlotter::RightMouseButtonZoom && event->button()==Qt::RightButton) {
double factor=4.0;
if (event->button()==Qt::RightButton) factor=1;
double xmin=plotter->p2x((long)round(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor));
double xmax=plotter->p2x((long)round(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor));
double ymin=plotter->p2y((long)round(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor));
double ymax=plotter->p2y((long)round(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor));
event->accept();
//xAxis->setRange(xmin, xmax);
//yAxis->setRange(ymin, ymax);
//redrawPlot();
/*if (plotter->isEmittingSignalsEnabled())*/ emit zoomChangedLocally(xmin, xmax, ymin, ymax, this);
plotter->setXY(xmin, xmax, ymin, ymax);
update();
}
emit plotMouseDoubleClicked(plotter->p2x(event->x()/magnification), plotter->p2y((event->y()-getPlotYOffset())/magnification), event->modifiers(), event->button());
} else { event->ignore(); }
}
event->accept();
updateCursor();
currentMouseDragAction.clear();
}
@ -524,20 +558,42 @@ void JKQTPlotter::keyReleaseEvent(QKeyEvent *event) {
}
void JKQTPlotter::wheelEvent ( QWheelEvent * event ) {
// only react on wheel turns inside the widget, turning forward will zoom out and turning backwards will zoom in by a factor of 2
if ( zoomByMouseWheel && ((event->x()/magnification>=plotter->getInternalPlotBorderLeft()) && (event->x()/magnification<=plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) &&
((event->y()-getPlotYOffset())/magnification>=plotter->getInternalPlotBorderTop()) && ((event->y()-getPlotYOffset())/magnification<=plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) ) {
auto itAction=findMatchingMouseWheelAction(event->modifiers());
if (itAction!=registeredMouseWheelActions.end()) {
if (itAction.value()==MouseWheelActions::ZoomByWheel) {
double factor=pow(2.0, 1.0*static_cast<double>(event->delta())/120.0)*2.0;
double xmin=plotter->p2x((long)round(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor));
double xmax=plotter->p2x((long)round(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor));
double ymin=plotter->p2y((long)round(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor));
double ymax=plotter->p2y((long)round(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor));
double xmin=plotter->p2x(static_cast<double>(event->x())/magnification-static_cast<double>(plotter->getPlotWidth())/factor);
double xmax=plotter->p2x(static_cast<double>(event->x())/magnification+static_cast<double>(plotter->getPlotWidth())/factor);
double ymin=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())+static_cast<double>(plotter->getPlotHeight())/factor);
double ymax=plotter->p2y(static_cast<double>(event->y())/magnification-static_cast<double>(getPlotYOffset())-static_cast<double>(plotter->getPlotHeight())/factor);
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
xmin=getXMin();
xmax=getXMax();
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
ymin=getYMin();
ymax=getYMax();
}
plotter->setXY(xmin, xmax, ymin, ymax);
} else if (itAction.value()==MouseWheelActions::PanByWheel) {
QPoint d=event->pixelDelta();
QRectF zoomRect= QRectF(QPointF(plotter->x2p(getXAxis()->getMin()),plotter->y2p(getYAxis()->getMax())), QPointF(plotter->x2p(getXAxis()->getMax()),plotter->y2p(getYAxis()->getMin())));
if ( (event->x()/magnification<plotter->getInternalPlotBorderLeft()) || (event->x()/magnification>plotter->getPlotWidth()+plotter->getInternalPlotBorderLeft()) ) {
zoomRect.translate(0, d.y());
} else if (((event->y()-getPlotYOffset())/magnification<plotter->getInternalPlotBorderTop()) || ((event->y()-getPlotYOffset())/magnification>plotter->getPlotHeight()+plotter->getInternalPlotBorderTop()) ) {
zoomRect.translate(d.x(), 0);
} else {
zoomRect.translate(d.x(), d.y());
}
setXY(plotter->p2x(zoomRect.left()), plotter->p2x(zoomRect.right()), plotter->p2y(zoomRect.bottom()), plotter->p2y(zoomRect.top()));
}
}
event->accept();
plotter->setXY(xmin, xmax, ymin, ymax);
} else {
event->ignore();
}
emit plotMouseWheelOperated(plotter->p2x(event->x()), plotter->p2x(event->y()), event->modifiers(), event->angleDelta().x(), event->angleDelta().y());
updateCursor();
currentMouseDragAction.clear();
}
@ -873,31 +929,10 @@ void JKQTPlotter::reactGraphVisible(bool visible)
}
}
void JKQTPlotter::setRightMouseButtonAction(const JKQTPlotter::RightMouseButtonAction &__value)
{
this->rightMouseButtonAction = __value;
}
void JKQTPlotter::setContextMenuMode(JKQTPlotter::ContextMenuModes mode) {
contextMenuMode=mode;
}
JKQTPlotter::RightMouseButtonAction JKQTPlotter::getActionRightMouseButton() const
{
return this->rightMouseButtonAction;
}
void JKQTPlotter::setLeftDoubleClickAction(const JKQTPlotter::LeftDoubleClickAction &__value)
{
this->leftDoubleClickAction = __value;
}
JKQTPlotter::LeftDoubleClickAction JKQTPlotter::getActionLeftDoubleClick() const
{
return this->leftDoubleClickAction;
}
QMenu *JKQTPlotter::getSpecialContextMenu() const {
return this->menuSpecialContextMenu;
}
@ -911,16 +946,6 @@ void JKQTPlotter::setSpecialContextMenu(QMenu *menu)
}
}
void JKQTPlotter::setZoomByMouseWheel(bool __value)
{
this->zoomByMouseWheel = __value;
}
bool JKQTPlotter::getZoomByMouseWheel() const
{
return this->zoomByMouseWheel;
}
double JKQTPlotter::getMouseContextX() const {
return this->mouseContextX;
}
@ -1063,24 +1088,59 @@ void JKQTPlotter::openStandardAndSpecialContextMenu(int x, int y)
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, JKQTPlotter::MouseDragActions>::const_iterator JKQTPlotter::findMatchingMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const
{
if (modifiers.testFlag(Qt::ShiftModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ShiftModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ShiftModifier));
} else if (modifiers.testFlag(Qt::ControlModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ControlModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ControlModifier));
} else if (modifiers.testFlag(Qt::AltModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::AltModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::AltModifier));
} else if (modifiers.testFlag(Qt::MetaModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::MetaModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::MetaModifier));
} else if (modifiers.testFlag(Qt::KeypadModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::KeypadModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::KeypadModifier));
} else if (modifiers.testFlag(Qt::GroupSwitchModifier)) {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::GroupSwitchModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::GroupSwitchModifier));
} else {
return registeredMouseActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::NoModifier));
return registeredMouseDragActionModes.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::NoModifier));
}
return registeredMouseActionModes.end();
}
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, JKQTPlotter::MouseDoubleClickActions>::const_iterator JKQTPlotter::findMatchingMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const
{
if (modifiers.testFlag(Qt::ShiftModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ShiftModifier));
} else if (modifiers.testFlag(Qt::ControlModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::ControlModifier));
} else if (modifiers.testFlag(Qt::AltModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::AltModifier));
} else if (modifiers.testFlag(Qt::MetaModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::MetaModifier));
} else if (modifiers.testFlag(Qt::KeypadModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::KeypadModifier));
} else if (modifiers.testFlag(Qt::GroupSwitchModifier)) {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::GroupSwitchModifier));
} else {
return registeredMouseDoubleClickActions.find(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, Qt::NoModifier));
}
}
QHash<Qt::KeyboardModifier, JKQTPlotter::MouseWheelActions>::const_iterator JKQTPlotter::findMatchingMouseWheelAction(Qt::KeyboardModifiers modifiers) const
{
if (modifiers.testFlag(Qt::ShiftModifier)) {
return registeredMouseWheelActions.find(Qt::ShiftModifier);
} else if (modifiers.testFlag(Qt::ControlModifier)) {
return registeredMouseWheelActions.find(Qt::ControlModifier);
} else if (modifiers.testFlag(Qt::AltModifier)) {
return registeredMouseWheelActions.find(Qt::AltModifier);
} else if (modifiers.testFlag(Qt::MetaModifier)) {
return registeredMouseWheelActions.find(Qt::MetaModifier);
} else if (modifiers.testFlag(Qt::KeypadModifier)) {
return registeredMouseWheelActions.find(Qt::KeypadModifier);
} else if (modifiers.testFlag(Qt::GroupSwitchModifier)) {
return registeredMouseWheelActions.find(Qt::GroupSwitchModifier);
} else {
return registeredMouseWheelActions.find(Qt::NoModifier);
}
}
void JKQTPlotter::setPlotUpdateEnabled(bool enable)
{
@ -1091,17 +1151,32 @@ void JKQTPlotter::setPlotUpdateEnabled(bool enable)
void JKQTPlotter::registerMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifier modifier, JKQTPlotter::MouseDragActions action)
{
registeredMouseActionModes[qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier)]=action;
registeredMouseDragActionModes[qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier)]=action;
}
void JKQTPlotter::deregisterMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifier modifier)
{
registeredMouseActionModes.remove(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier));
registeredMouseDragActionModes.remove(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier));
}
void JKQTPlotter::clearAllRegisteredMouseDragActions()
{
registeredMouseActionModes.clear();
registeredMouseDragActionModes.clear();
}
void JKQTPlotter::registerMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifier modifier, JKQTPlotter::MouseDoubleClickActions action)
{
registeredMouseDoubleClickActions[qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier)]=action;
}
void JKQTPlotter::deregisterMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifier modifier)
{
registeredMouseDoubleClickActions.remove(qMakePair<Qt::MouseButton, Qt::KeyboardModifier>(button, modifier));
}
void JKQTPlotter::clearAllRegisteredMouseDoubleClickActions()
{
registeredMouseDoubleClickActions.clear();
}

View File

@ -156,6 +156,9 @@ LIB_EXPORT void initJKQTPlotterResources();
*
* \subsection JKQTPLOTTER_USERMOUSEINTERACTION Mouse-Interaction in JKQTPlotter
*
* \see \ref JKQTPlotterUserInteraction
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEDRAG Actions When Dragging the Mouse
* JKQTPlotter offers several methods that allow to customize, how it reacts to mouse actions:
* - registerMouseDragAction() tells JKQTPlotter to perform a certain action (selected from JKQTPlotter::MouseActionMode)
* when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed.
@ -166,10 +169,13 @@ LIB_EXPORT void initJKQTPlotterResources();
* \endcode
* Therefore by default you can draw a zoom rectangle with the left mouse button without modifiers
* and you can pan/drag the plot with the left mouse-button while keeping CTRL pressed.
* - deregisterMouseDragAction() deletes a previously defined unser-interaction
* - deregisterMouseDragAction() deletes a previously defined user-interaction
* - clearAllRegisteredMouseDragActions() deletes all previously specified user-actions
* .
*
* Pressing the \c ESC key will stop the current JKQTPlotter::MouseActionMode.
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSECLICK Actions After Clicks on the Mouse Buttons
* The right mouse button has a special role: If it is single-clicked and no JKQTPlotter::MouseActionMode is specified
* for the vent, it opens the context menu, unless you call \c setContextMenuMoode(JKQTPlotter::NoContextMenu) .
* You can also use setContextMenuMoode() to specify which type of context menu is shown. See JKQTPlotter::ContextMenuModes
@ -179,13 +185,43 @@ LIB_EXPORT void initJKQTPlotterResources();
* - plotMouseClicked() for any single-click (during the pressDown-Event!)
* - plotMouseDoubleClicked() for any double-click
* .
*
* The reaction to double-clicks of the mouse buttons can be specified separately. The possible
* actions are listed in JKQTPlotter::MouseDoubleClickActions. You can bind one of these actions
* to a specific click with these functions:
* - registerMouseDoubleClickAction() tells JKQTPlotter to perform a certain action (selected from JKQTPlotter::MouseDoubleClickActions)
* when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed.
* By default JKQTPlotter calls this in its constructors:
* \code
* registerMouseDoubleClickAction(Qt::LeftButton, Qt::NoModifier, JKQTPlotter::MouseDoubleClickActions::ClickMovesViewport);
* \endcode
* Therefore by default you can pan the plot/move the viewport by double clicking a location
* - deregisterMouseDoubleClickAction() deletes a previously defined user-interaction
* - clearAllRegisteredMouseDoubleClickAction() deletes all previously specified user-actions
* .
* The button to react to is specified as a parameter.
*
* \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 JKQTPlotter::MouseWheelActions.
* You can bind one of these actions to the mouse-wheel (under the condition that a specified Qt::KeyboardModifier
* is pressed) by using these functions:
* - registerMouseWheelAction() tells JKQTPlotter to perform a certain action (selected from JKQTPlotter::MouseWheelActions)
* when a specified mouse button is pushed while a specified (or no) keyborad modifiers (e.g. CTRL,ALT,SHIFT...) is pressed.
* By default JKQTPlotter calls this in its constructors:
* \code
* registerMouseWheelAction(Qt::NoModifier, JKQTPlotter::MouseWheelActions::ZoomByWheel);
* \endcode
* Therefore by default you can zoom into and out of the plot, using the mouse wheel.
* - deregisterMouseWheelAction() deletes a previously defined user-interaction
* - clearAllMouseWheelActions() deletes all previously specified user-actions
* .
* In addition the signal void plotMouseWheelOperated() is emitted whenever a mouse-wheel event occurs.
*
*
* \subsubsection JKQTPLOTTER_USERMOUSEINTERACTION_MOUSEMOVE Signaling When Mouse Moves
* 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.
*
* Pressing the ESC key will stop the current JKQTPlotter::MouseActionMode.
*
* \see \ref JKQTPlotterUserInteraction
*
*
*
* \section JKQTPLOTTER_USEQTCREATOR How to use JKQTPlotter in the Qt Form Designer
@ -228,18 +264,17 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief actions that can be bound to a double-click of the mouse */
enum MouseDoubleClickActions {
ClickZoomsIn=0, /*!< \brief a (double-)click zooms into the plot at the current mouse location */
ClickZoomsOut, /*!< \brief a (double-)click zooms out of the plot at the current mouse location */
ClickOpensContextMenu, /*!< \brief a (double-)click opens the context menu */
ClickOpensSpecialContextMenu, /*!< \brief a (double-)click opens the special context menu \see setSpecialContextMenu() */
NoClickAction, /*!< \brief no action is performed */
ClickZoomsIn=0, /*!< \brief a double-click zooms into the plot at the current mouse location */
ClickZoomsOut, /*!< \brief a double-click zooms out of the plot at the current mouse location */
ClickOpensContextMenu, /*!< \brief a double-click opens the context menu */
ClickOpensSpecialContextMenu, /*!< \brief a double-click opens the special context menu \see setSpecialContextMenu() */
ClickMovesViewport, /*!< \brief a double-click centers the x/y-range around the clicked position */
};
/** \brief actions that can be bound to a mouse wheel event */
enum MouseWheelActions {
ZoomByWheel=0, /*!< \brief use the mouse-wheel for zooming */
PanByWheel, /*!< \brief use the mouse-wheel for panning the plot */
NoWheelAction, /*!< \brief no mouse-wheel action */
};
/** \brief modes for the context menu */
@ -254,22 +289,6 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief options of how to react to a right mouse button click */
enum RightMouseButtonAction {
RightMouseButtonNone=0, /*!< \brief do not perform any action on a right mouse button click */
RightMouseButtonZoom=1, /*!< \brief use right mouse button for zoomin out */
RightMouseButtonContextMenu=2 /*!< \brief show the context menu when clicking the right mouse button */
};
/** \brief options of how to react to a left mouse button double-click (single-click events are described by MouseActionMode) */
enum LeftDoubleClickAction {
LeftDoubleClickDefault, /*!< \brief */
LeftDoubleClickContextMenu, /*!< \brief open the context menu when the left mouse button is double-clicked */
LeftDoubleClickSpecialContextMenu, /*!< \brief open the special context menu when the left mouse button is double-clicked */
};
/** \brief class constructor
*
@ -397,31 +416,37 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
*/
void setPlotUpdateEnabled(bool enable);
/** \brief registeres a certain mouse action \a action to be executed when a mouse drag operation is
/** \brief registeres a certain mouse drag action \a action to be executed when a mouse drag operation is
* initialized with the given \a button and \a modifier */
void registerMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifier modifier, MouseDragActions action);
/** \brief deregisteres the mouse action to be executed when a mouse drag operation is
/** \brief deregisteres the mouse drag action to be executed when a mouse drag operation is
* initialized with the given \a button and \a modifier */
void deregisterMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifier modifier);
/** \brief clear all registeres mouse actions */
/** \brief clear all registeres mouse drag actions */
void clearAllRegisteredMouseDragActions();
/*! \brief returns the property rightMouseButtonAction ( \copybrief rightMouseButtonAction ).
\details Description of the parameter rightMouseButtonAction is: <BLOCKQUOTE>\copydoc rightMouseButtonAction </BLOCKQUOTE>
\see rightMouseButtonAction for more information */
RightMouseButtonAction getActionRightMouseButton() const;
/*! \brief returns the property leftDoubleClickAction ( \copybrief leftDoubleClickAction ).
\details Description of the parameter leftDoubleClickAction is: <BLOCKQUOTE>\copydoc leftDoubleClickAction </BLOCKQUOTE>
\see leftDoubleClickAction for more information */
LeftDoubleClickAction getActionLeftDoubleClick() const;
/** \brief registeres a certain mouse action \a action to be executed when a mouse double-click occurs
* with the given \a button and \a modifier */
void registerMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifier modifier, MouseDoubleClickActions action);
/** \brief deregisteres the mouse action \a action to be executed when a mouse double-click occurs
* with the given \a button and \a modifier */
void deregisterMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifier modifier);
/** \brief clear all registered mouse double-click actions */
void clearAllRegisteredMouseDoubleClickActions();
/** \brief specifies the action to perform on a mouse wheel event when a given modifier is pressed \see deregisterMouseWheelAction(), clearAllMouseWheelActions(), JKQTPLOTTER_USERMOUSEINTERACTION */
void registerMouseWheelAction(Qt::KeyboardModifier modifier, MouseWheelActions action);
/** \brief deletes all mouse-wheel actions registered for a given \a modifier \see registerMouseWheelAction(), clearAllMouseWheelActions(), JKQTPLOTTER_USERMOUSEINTERACTION */
void deregisterMouseWheelAction(Qt::KeyboardModifier modifier);
/** \brief deletes all mouse-wheel actions \see registerMouseWheelAction(), deregisterMouseWheelAction(), JKQTPLOTTER_USERMOUSEINTERACTION */
void clearAllMouseWheelActions();
/*! \brief returns the currently set special context menu object */
QMenu *getSpecialContextMenu() const;
/*! \brief sets a QMenu object to be used as special context menu */
void setSpecialContextMenu(QMenu* menu);
/*! \brief returns the property zoomByMouseWheel ( \copybrief zoomByMouseWheel ).
\details Description of the parameter zoomByMouseWheel is: <BLOCKQUOTE>\copydoc zoomByMouseWheel </BLOCKQUOTE>
\see zoomByMouseWheel for more information */
bool getZoomByMouseWheel() const;
/** \brief returns the property mouseContextX ( \copybrief mouseContextX ).
\details Description of the parameter mouseContextX is: <BLOCKQUOTE>\copydoc mouseContextX </BLOCKQUOTE>.
@ -638,23 +663,6 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
\see userActionCompositionMode for more information */
void setUserActionCompositionMode(const QPainter::CompositionMode & __value);
/*! \brief sets the property zoomByMouseWheel ( \copybrief zoomByMouseWheel ) to the specified \a __value.
\details Description of the parameter zoomByMouseWheel is: <BLOCKQUOTE>\copydoc zoomByMouseWheel </BLOCKQUOTE>
\see zoomByMouseWheel for more information */
void setZoomByMouseWheel(bool __value);
/*! \brief sets the property leftDoubleClickAction ( \copybrief leftDoubleClickAction ) to the specified \a __value.
\details Description of the parameter leftDoubleClickAction is: <BLOCKQUOTE>\copydoc leftDoubleClickAction </BLOCKQUOTE>
\see leftDoubleClickAction for more information */
void setLeftDoubleClickAction(const LeftDoubleClickAction & __value);
/*! \brief sets the property rightMouseButtonAction ( \copybrief rightMouseButtonAction ) to the specified \a __value.
\details Description of the parameter rightMouseButtonAction is: <BLOCKQUOTE>\copydoc rightMouseButtonAction </BLOCKQUOTE>
\see rightMouseButtonAction for more information */
void setRightMouseButtonAction(const RightMouseButtonAction & __value);
/** \brief sets the mode if the standard context menu \see ContextMenuModes, JKQTPLOTTER_USERMOUSEINTERACTION */
void setContextMenuMode(ContextMenuModes mode);
@ -729,6 +737,15 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
* \param button mouse-button that was used for the click
*/
void plotMouseDoubleClicked(double x, double y, Qt::KeyboardModifiers modifiers, Qt::MouseButton button);
/** \brief emitted when a single-click event from the mouse occurs inside the plot
*
* \param x x-position of the mouse (in plot coordinates)
* \param y y-position of the mouse (in plot coordinates)
* \param modifiers key-modifiers when the click occured
* \param deltaAngleX amount of rotation (in eighths of a degree) of the wheel in x-direction
* \param deltaAngleY amount of rotation (in eighths of a degree) of the wheel in y-direction
*/
void plotMouseWheelOperated(double x, double y, Qt::KeyboardModifiers modifiers, int deltaAngleX, int deltaAngleY);
/** \brief emitted when the mouse action JKQTPlotter::ZoomRectangle and the drawing of the new zoom rectangle is finished (=mouse key released)
*
* \param mouseDragRectXStart start of the selected x-range (in plot coordinates)
@ -839,12 +856,25 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
/** \brief the currently executed MouseDragAction */
MouseDragAction currentMouseDragAction;
/** \brief lists all availble mouse action modes */
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, MouseDragActions> registeredMouseActionModes;
/** \brief lists all availble mouse drag action modes */
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, MouseDragActions> registeredMouseDragActionModes;
/** \brief searches registeredMouseActionModes for a matching action */
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, MouseDragActions>::const_iterator findMatchingMouseDragAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const;
/** \brief lists all availble mouse wheel action modes */
QHash<Qt::KeyboardModifier, MouseWheelActions> registeredMouseWheelActions;
/** \brief searches registeredMouseWheelActions for a matching action */
QHash<Qt::KeyboardModifier, MouseWheelActions>::const_iterator findMatchingMouseWheelAction(Qt::KeyboardModifiers modifiers) const;
/** \brief action to perform on a double-click of the mouse buttons (depending on the button and the modifiers) */
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, MouseDoubleClickActions> registeredMouseDoubleClickActions;
/** \brief searches registeredMouseDoubleClickActions for a matching action */
QHash<QPair<Qt::MouseButton,Qt::KeyboardModifier>, MouseDoubleClickActions>::const_iterator findMatchingMouseDoubleClickAction(Qt::MouseButton button, Qt::KeyboardModifiers modifiers) const;
/** \brief you may overwrite this method to modify the given context emnu before it is displayed.
*
* The plotter will fill the menu with the default items and then call this method. The default implementation does NOTHING.
@ -918,14 +948,6 @@ class LIB_EXPORT JKQTPlotter: public QWidget {
*/
QImage oldImage;
/** \brief indicates whether zooming in by double clicking and zooming out by right-clicking is activated */
RightMouseButtonAction rightMouseButtonAction;
/** \brief indicates whether zooming using the mouse-wheel is activated */
bool zoomByMouseWheel;
/** \brief indicates the action to perform on a left mouse-button double-click */
LeftDoubleClickAction leftDoubleClickAction;
/** \brief use this QMenu instance instead of the standard context emnu of this widget */
QMenu* menuSpecialContextMenu;
@ -1093,4 +1115,22 @@ inline uint qHash(const QPair<Qt::MouseButton,Qt::KeyboardModifier> &key, uint s
return static_cast<uint>(key.first)+static_cast<uint>(key.second);
}
/** \brief qHash-variant used by JKQTPlotter
* \internal
* \ingroup jkqtpplotterclasses
*/
template<>
inline uint qHash(const Qt::MouseButton &key, uint /*seed*/ ) noexcept(noexcept(qHash(key))) {
return static_cast<uint>(key);
}
/** \brief qHash-variant used by JKQTPlotter
* \internal
* \ingroup jkqtpplotterclasses
*/
template<>
inline uint qHash(const Qt::KeyboardModifier &key, uint /*seed*/ ) noexcept(noexcept(qHash(key))) {
return static_cast<uint>(key);
}
#endif // JKQTPLOTTER_H