diff --git a/src/QuickEditor/QuickEditor.h b/src/QuickEditor/QuickEditor.h --- a/src/QuickEditor/QuickEditor.h +++ b/src/QuickEditor/QuickEditor.h @@ -55,13 +55,15 @@ inline void acceptSelection(); void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; void mouseDoubleClickEvent(QMouseEvent* event) override; void paintEvent(QPaintEvent*) override; inline void drawBottomHelpText(QPainter& painter); inline void drawDragHandles(QPainter& painter); + inline void drawMagnifier(QPainter& painter); inline void drawMidHelpText(QPainter& painter); inline void drawSelectionSizeTooltip(QPainter& painter); inline void layoutBottomHelpText(); @@ -82,8 +84,12 @@ static const int bottomHelpBoxPairSpacing; static const int bottomHelpBoxLineHeight; + static const int magZoom; + static const int magPixels; + QColor mMaskColour; QColor mStrokeColour; + QColor mCrossColour; QColor mLabelBackgroundColour; QColor mLabelForegroundColour; QRectF mSelection; @@ -99,6 +105,10 @@ int mBottomHelpGridLeftWidth; MouseState mMouseDragState; QPixmap mPixmap; + QPointF mMousePos; + bool mMagnifierAllowed; + bool mShowMagnifier; + bool mToggleMagnifier; signals: void grabDone(const QPixmap &pixmap); diff --git a/src/QuickEditor/QuickEditor.cpp b/src/QuickEditor/QuickEditor.cpp --- a/src/QuickEditor/QuickEditor.cpp +++ b/src/QuickEditor/QuickEditor.cpp @@ -35,9 +35,13 @@ const int QuickEditor::bottomHelpBoxPairSpacing = 6; const int QuickEditor::bottomHelpBoxLineHeight = 24; +const int QuickEditor::magZoom = 5; +const int QuickEditor::magPixels = 16; + QuickEditor::QuickEditor(const QPixmap& pixmap, QObject* parent) : mMaskColour(QColor::fromRgbF(0, 0, 0, 0.15)), mStrokeColour(palette().highlight().color()), + mCrossColour(QColor::fromRgbF(mStrokeColour.redF(), mStrokeColour.greenF(), mStrokeColour.blueF(), 0.7)), mLabelBackgroundColour(QColor::fromRgbF( palette().light().color().redF(), palette().light().color().greenF(), @@ -56,7 +60,10 @@ mBottomHelpTextFont(font()), mBottomHelpGridLeftWidth(0), mMouseDragState(MouseState::None), - mPixmap(pixmap) + mPixmap(pixmap), + mMagnifierAllowed(false), + mShowMagnifier(SpectacleConfig::instance()->showMagnifierChecked()), + mToggleMagnifier(false) { Q_UNUSED(parent); @@ -131,19 +138,36 @@ default: break; } + if (event->modifiers() & Qt::ShiftModifier) { + mToggleMagnifier = true; + update(); + } + event->accept(); +} + +void QuickEditor::keyReleaseEvent(QKeyEvent* event) +{ + if (mToggleMagnifier && !(event->modifiers() & Qt::ShiftModifier)) { + mToggleMagnifier = false; + update(); + } + event->accept(); } void QuickEditor::mousePressEvent(QMouseEvent* event) { if (event->button() & Qt::LeftButton) { const QPointF& pos = event->screenPos(); + mMousePos = pos; + mMagnifierAllowed = true; mMouseDragState = whereIsTheMouse(pos); switch(mMouseDragState) { case MouseState::Outside: mStartPos = pos; break; case MouseState::Inside: mStartPos = pos; + mMagnifierAllowed = false; mInitialTopLeft = mSelection.topLeft(); setCursor(Qt::ClosedHandCursor); break; @@ -166,15 +190,21 @@ break; } } + if (mMagnifierAllowed) { + update(); + } event->accept(); } void QuickEditor::mouseMoveEvent(QMouseEvent* event) { const QPointF& pos = event->screenPos(); + mMousePos = pos; + mMagnifierAllowed = true; switch (mMouseDragState) { case MouseState::None: { setMouseCursor(pos); + mMagnifierAllowed = false; break; } case MouseState::TopLeft: @@ -217,6 +247,7 @@ break; } case MouseState::Inside: { + mMagnifierAllowed = false; // We use some math here to figure out if the diff with which we // move the rectangle with moves it out of bounds, // in which case we adjust the diff to not let that happen @@ -311,6 +342,8 @@ } drawBottomHelpText(painter); + } else if (mMagnifierAllowed && (mShowMagnifier ^ mToggleMagnifier)) { + drawMagnifier(painter); } } else { drawMidHelpText(painter); @@ -419,6 +452,57 @@ painter.fillPath(path, mStrokeColour); } +inline void QuickEditor::drawMagnifier(QPainter &painter) +{ + const int pixels = 2 * magPixels + 1; + int magX = mMousePos.x() * devicePixelRatioF() - magPixels; + int offsetX = 0; + if (magX < 0) { + offsetX = magX; + magX = 0; + } else { + const int maxX = mPixmap.width() - pixels; + if (magX > maxX) { + offsetX = magX - maxX; + magX = maxX; + } + } + int magY = mMousePos.y() * devicePixelRatioF() - magPixels; + int offsetY = 0; + if (magY < 0) { + offsetY = magY; + magY = 0; + } else { + const int maxY = mPixmap.height() - pixels; + if (magY > maxY) { + offsetY = magY - maxY; + magY = maxY; + } + } + QRectF magniRect(magX, magY, pixels, pixels); + + const qreal gg = 32; + qreal drawPosX = mMousePos.x() + gg + pixels * magZoom / 2; + if (drawPosX > width() - pixels * magZoom / 2) { + drawPosX = mMousePos.x() - gg - pixels * magZoom / 2; + } + qreal drawPosY = mMousePos.y() + gg + pixels * magZoom / 2; + if (drawPosY > height() - pixels * magZoom / 2) { + drawPosY = mMousePos.y() - gg - pixels * magZoom / 2; + } + QPointF drawPos(drawPosX, drawPosY); + QRectF crossHairTop(drawPos.x() + magZoom * (offsetX - 0.5), drawPos.y() - magZoom * (magPixels + 0.5), magZoom, magZoom * (magPixels + offsetY)); + QRectF crossHairRight(drawPos.x() + magZoom * (0.5 + offsetX), drawPos.y() + magZoom * (offsetY - 0.5), magZoom * (magPixels - offsetX), magZoom); + QRectF crossHairBottom(drawPos.x() + magZoom * (offsetX - 0.5), drawPos.y() + magZoom * (0.5 + offsetY), magZoom, magZoom * (magPixels - offsetY)); + QRectF crossHairLeft(drawPos.x() - magZoom * (magPixels + 0.5), drawPos.y() + magZoom * (offsetY - 0.5), magZoom * (magPixels + offsetX), magZoom); + const auto frag = QPainter::PixmapFragment::create(drawPos, magniRect, magZoom, magZoom); + painter.drawPixmapFragments(&frag, 1, mPixmap, QPainter::OpaqueHint); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + for (auto& rect : { crossHairTop, crossHairRight, crossHairBottom, crossHairLeft }) { + painter.fillRect(rect, mCrossColour); + } +} + inline void QuickEditor::drawMidHelpText(QPainter &painter) { const QRect& fullRect = geometry();