diff --git a/lib/crop/croptool.h b/lib/crop/croptool.h --- a/lib/crop/croptool.h +++ b/lib/crop/croptool.h @@ -58,6 +58,8 @@ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override; void hoverMoveEvent(QGraphicsSceneHoverEvent*) override; void keyPressEvent(QKeyEvent*) override; + void keyReleaseEvent(QKeyEvent* event) override; + void focusInEvent(QFocusEvent* event) override; void toolActivated() override; void toolDeactivated() override; diff --git a/lib/crop/croptool.cpp b/lib/crop/croptool.cpp --- a/lib/crop/croptool.cpp +++ b/lib/crop/croptool.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -87,10 +88,12 @@ QRect mRect; QList mCropHandleList; CropHandle mMovingHandle; + CropHandle mMouseOverHandle; QPoint mLastMouseMovePos; double mCropRatio; double mLockedCropRatio; CropWidget* mCropWidget; + bool mControlKeyIsDown; QRect viewportCropRect() const { @@ -165,14 +168,20 @@ break; case CH_Content: - shape = buttonDown ? Qt::ClosedHandCursor : Qt::OpenHandCursor; + shape = buttonDown + ? Qt::ClosedHandCursor + : mControlKeyIsDown ? Qt::BitmapCursor : Qt::OpenHandCursor; break; default: - shape = Qt::ArrowCursor; + shape = mControlKeyIsDown ? Qt::BitmapCursor : Qt::ArrowCursor; break; } - q->imageView()->setCursor(shape); + if (shape == Qt::BitmapCursor) { + q->imageView()->setCursor(q->zoomCursor()); + } else { + q->imageView()->setCursor(shape); + } } void keepRectInsideImage() @@ -226,8 +235,10 @@ d->q = this; d->mCropHandleList << CH_Left << CH_Right << CH_Top << CH_Bottom << CH_TopLeft << CH_TopRight << CH_BottomLeft << CH_BottomRight; d->mMovingHandle = CH_None; + d->mMouseOverHandle = CH_None; d->mCropRatio = 0.; d->mLockedCropRatio = 0.; + d->mControlKeyIsDown = false; d->mRect = d->computeVisibleImageRect(); d->setupWidget(); } @@ -293,16 +304,27 @@ void CropTool::mousePressEvent(QGraphicsSceneMouseEvent* event) { - if (event->buttons() != Qt::LeftButton) { + if (event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton) { event->ignore(); return; } + const CropHandle newMovingHandle = d->handleAt(event->pos()); - if (event->modifiers() & Qt::ControlModifier - && !(newMovingHandle & (CH_Top | CH_Left | CH_Right | CH_Bottom))) { + const bool mouseOverResizeHandle = newMovingHandle & (CH_Top | CH_Left | CH_Right | CH_Bottom); + const bool controlPressed = event->modifiers() & Qt::ControlModifier; + if (controlPressed && !mouseOverResizeHandle) { event->ignore(); return; } + if (event->buttons() == Qt::RightButton) { + if (controlPressed && mouseOverResizeHandle) { + // Prevent zooming + event->accept(); + } else { + event->ignore(); + } + return; + } event->accept(); d->mMovingHandle = newMovingHandle; @@ -405,7 +427,23 @@ void CropTool::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { - if (event->buttons() != Qt::LeftButton || d->handleAt(event->pos()) == CH_None) { + if (event->buttons() != Qt::LeftButton && event->buttons() != Qt::RightButton) { + event->ignore(); + return; + } + + const CropHandle handle = d->handleAt(event->pos()); + const bool mouseOverResizeHandle = handle & (CH_Top | CH_Left | CH_Right | CH_Bottom); + if (event->modifiers() & Qt::ControlModifier) { + if (mouseOverResizeHandle) { + // Prevent zooming + event->accept(); + } else { + event->ignore(); + } + return; + } + if (event->buttons() != Qt::LeftButton || handle == CH_None) { event->ignore(); return; } @@ -417,8 +455,8 @@ { event->accept(); // Make sure cursor is updated when moving over handles - CropHandle handle = d->handleAt(event->lastPos()); - d->updateCursor(handle, false /* buttonDown */); + d->mMouseOverHandle = d->handleAt(event->lastPos()); + d->updateCursor(d->mMouseOverHandle, false /* buttonDown */); } void CropTool::keyPressEvent(QKeyEvent* event) @@ -445,11 +483,36 @@ } break; } + case Qt::Key_Control: + event->accept(); + d->mControlKeyIsDown = true; + d->updateCursor(d->mMouseOverHandle, d->mMovingHandle != CH_None); + break; + case Qt::Key_Space: + event->accept(); + break; default: + event->ignore(); break; } } +void CropTool::keyReleaseEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Control) { + d->mControlKeyIsDown = false; + d->updateCursor(d->mMouseOverHandle, false); + event->accept(); + } else { + event->ignore(); + } +} + +void CropTool::focusInEvent(QFocusEvent* event) +{ + d->mControlKeyIsDown = QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier; + event->accept(); +} + void CropTool::toolActivated() { d->mCropWidget->setAdvancedSettingsEnabled(GwenviewConfig::cropAdvancedSettingsEnabled()); diff --git a/lib/documentview/abstractimageview.h b/lib/documentview/abstractimageview.h --- a/lib/documentview/abstractimageview.h +++ b/lib/documentview/abstractimageview.h @@ -150,6 +150,8 @@ void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override; void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override; + void setToolActive(bool active); + private: friend struct AbstractImageViewPrivate; AbstractImageViewPrivate* const d; diff --git a/lib/documentview/abstractimageview.cpp b/lib/documentview/abstractimageview.cpp --- a/lib/documentview/abstractimageview.cpp +++ b/lib/documentview/abstractimageview.cpp @@ -50,6 +50,7 @@ bool mControlKeyIsDown; bool mEnlargeSmallerImages; + bool mToolActive; qreal mZoom; bool mZoomToFit; @@ -126,15 +127,17 @@ return pix; } - void checkAndRequestZoomAction(const QGraphicsSceneMouseEvent* event) + bool checkAndRequestZoomAction(const QGraphicsSceneMouseEvent* event) { if (event->modifiers() & Qt::ControlModifier) { if (event->button() == Qt::LeftButton) { q->zoomInRequested(event->pos()); } else if (event->button() == Qt::RightButton) { q->zoomOutRequested(event->pos()); } + return true; } + return false; } }; @@ -145,6 +148,7 @@ d->q = this; d->mControlKeyIsDown = false; d->mEnlargeSmallerImages = false; + d->mToolActive = false; d->mZoom = 1; d->mZoomToFit = true; d->mZoomToFill = false; @@ -369,7 +373,9 @@ { QGraphicsItem::mousePressEvent(event); - d->checkAndRequestZoomAction(event); + if (d->checkAndRequestZoomAction(event)) { + event->accept(); + } // Prepare for panning or dragging if (event->button() == Qt::LeftButton) { @@ -505,7 +511,9 @@ toggleFullScreenRequested(); } - d->checkAndRequestZoomAction(event); + if (d->checkAndRequestZoomAction(event)) { + event->accept(); + } } QPointF AbstractImageView::imageOffset() const @@ -585,6 +593,10 @@ void AbstractImageView::updateCursor() { + if (d->mToolActive) { + return; + } + if (d->mControlKeyIsDown) { setCursor(d->mZoomCursor); } else { @@ -617,4 +629,9 @@ updateCursor(); } +void AbstractImageView::setToolActive(bool active) +{ + d->mToolActive = active; +} + } // namespace diff --git a/lib/documentview/abstractrasterimageviewtool.h b/lib/documentview/abstractrasterimageviewtool.h --- a/lib/documentview/abstractrasterimageviewtool.h +++ b/lib/documentview/abstractrasterimageviewtool.h @@ -30,6 +30,7 @@ // Local +class QFocusEvent; class QKeyEvent; class QGraphicsSceneHoverEvent; class QGraphicsSceneMouseEvent; @@ -68,6 +69,8 @@ {} virtual void keyReleaseEvent(QKeyEvent*) {} + virtual void focusInEvent(QFocusEvent*) + {} virtual void toolActivated() {} @@ -79,6 +82,8 @@ return nullptr; } + QCursor zoomCursor() const; + public Q_SLOTS: virtual void onWidgetSlidedIn() {} diff --git a/lib/documentview/abstractrasterimageviewtool.cpp b/lib/documentview/abstractrasterimageviewtool.cpp --- a/lib/documentview/abstractrasterimageviewtool.cpp +++ b/lib/documentview/abstractrasterimageviewtool.cpp @@ -22,7 +22,9 @@ #include "abstractrasterimageviewtool.h" // Qt +#include #include +#include // KDE @@ -35,13 +37,25 @@ struct AbstractRasterImageViewToolPrivate { RasterImageView* mRasterImageView; + QCursor mZoomCursor; + + void setupZoomCursor() + { + // We do not use "appdata" here because that does not work when this + // code is called from a KPart. + const QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("gwenview/cursors/zoom.png")); + const QPixmap cursorPixmap = QPixmap(path); + mZoomCursor = QCursor(cursorPixmap, 11, 11); + } + }; AbstractRasterImageViewTool::AbstractRasterImageViewTool(RasterImageView* view) : QObject(view) , d(new AbstractRasterImageViewToolPrivate) { d->mRasterImageView = view; + d->setupZoomCursor(); } AbstractRasterImageViewTool::~AbstractRasterImageViewTool() @@ -64,4 +78,9 @@ event->ignore(); } +QCursor AbstractRasterImageViewTool::zoomCursor() const +{ + return d->mZoomCursor; +} + } // namespace diff --git a/lib/documentview/rasterimageview.h b/lib/documentview/rasterimageview.h --- a/lib/documentview/rasterimageview.h +++ b/lib/documentview/rasterimageview.h @@ -71,6 +71,7 @@ void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; void hoverMoveEvent(QGraphicsSceneHoverEvent*) override; + void focusInEvent(QFocusEvent* event) override; private Q_SLOTS: void slotDocumentMetaInfoLoaded(); diff --git a/lib/documentview/rasterimageview.cpp b/lib/documentview/rasterimageview.cpp --- a/lib/documentview/rasterimageview.cpp +++ b/lib/documentview/rasterimageview.cpp @@ -466,6 +466,7 @@ // Go back to default cursor when tool is deactivated. We need to call this here and // not further below in case toolActivated wants to set its own new cursor afterwards. + setToolActive(tool != nullptr); updateCursor(); d->mTool = tool; @@ -569,4 +570,15 @@ AbstractImageView::hoverMoveEvent(event); } +void RasterImageView::focusInEvent(QFocusEvent* event) +{ + if (d->mTool) { + d->mTool.data()->focusInEvent(event); + if (event->isAccepted()) { + return; + } + } + AbstractImageView::focusInEvent(event); +} + } // namespace diff --git a/lib/redeyereduction/redeyereductiontool.h b/lib/redeyereduction/redeyereductiontool.h --- a/lib/redeyereduction/redeyereductiontool.h +++ b/lib/redeyereduction/redeyereductiontool.h @@ -56,6 +56,8 @@ void mouseReleaseEvent(QGraphicsSceneMouseEvent*) override; void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) override; void keyPressEvent(QKeyEvent*) override; + void keyReleaseEvent(QKeyEvent* event) override; + void focusInEvent(QFocusEvent* event) override; void toolActivated() override; diff --git a/lib/redeyereduction/redeyereductiontool.cpp b/lib/redeyereduction/redeyereductiontool.cpp --- a/lib/redeyereduction/redeyereductiontool.cpp +++ b/lib/redeyereduction/redeyereductiontool.cpp @@ -24,6 +24,7 @@ // Qt #include #include +#include #include #include #include @@ -72,6 +73,7 @@ QPointF mCenter; int mDiameter; RedEyeReductionWidget* mToolWidget; + bool mControlKeyIsDown; void setupToolWidget() { @@ -94,6 +96,15 @@ } return QRectF(mCenter.x() - mDiameter / 2, mCenter.y() - mDiameter / 2, mDiameter, mDiameter); } + + void updateCursor() + { + if (mControlKeyIsDown) { + q->imageView()->setCursor(q->zoomCursor()); + } else { + q->imageView()->setCursor(Qt::CrossCursor); + } + } }; RedEyeReductionTool::RedEyeReductionTool(RasterImageView* view) @@ -103,6 +114,7 @@ d->q = this; d->mDiameter = GwenviewConfig::redEyeReductionDiameter(); d->mStatus = NotSet; + d->mControlKeyIsDown = false; d->setupToolWidget(); view->document()->startLoadingFullImage(); @@ -166,13 +178,12 @@ void RedEyeReductionTool::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { - // Just prevent the event from reaching the image view - event->accept(); + event->ignore(); } void RedEyeReductionTool::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event) { - if (event->buttons() != Qt::LeftButton) { + if (event->buttons() != Qt::LeftButton || event->modifiers() & Qt::ControlModifier) { event->ignore(); return; } @@ -199,14 +210,43 @@ } break; } + case Qt::Key_Control: + event->accept(); + d->mControlKeyIsDown = true; + d->updateCursor(); + break; + case Qt::Key_Space: + event->accept(); + break; default: + event->ignore(); break; } } +void RedEyeReductionTool::keyReleaseEvent(QKeyEvent* event) { + if (event->key() == Qt::Key_Control) { + d->mControlKeyIsDown = false; + d->updateCursor(); + event->accept(); + } else { + event->ignore(); + } +} + +void RedEyeReductionTool::focusInEvent(QFocusEvent* event) +{ + const bool controlKeyIsCurrentlyDown = QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier; + if (d->mControlKeyIsDown != controlKeyIsCurrentlyDown) { + d->mControlKeyIsDown = controlKeyIsCurrentlyDown; + d->updateCursor(); + } + event->accept(); +} + void RedEyeReductionTool::toolActivated() { - imageView()->setCursor(Qt::CrossCursor); + d->updateCursor(); } void RedEyeReductionTool::slotApplyClicked()