Skip to content

Commit

Permalink
Pinch gesture on pinned screenshot (flameshot-org#2447)
Browse files Browse the repository at this point in the history
* Minor refactoring

* Pinch gesture works fine

* Consolidated Zooming in/out

* Minor refactoring

* Minor refactoring

* clang-format

* Fixed scroll phases on Linux

* clang-format

* Re-added size constraint

* clang-format
  • Loading branch information
AndreaMarangoni authored Feb 23, 2022
1 parent aa6b5ea commit 413a3f9
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 54 deletions.
133 changes: 92 additions & 41 deletions src/tools/pin/pinwidget.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors

#include <QGraphicsDropShadowEffect>
#include <QPinchGesture>

#include "pinwidget.h"
#include "qguiappcurrentscreen.h"
#include "src/utils/confighandler.h"
#include "src/utils/globalvalues.h"
#include <QApplication>

#include <QLabel>
#include <QScreen>
#include <QShortcut>
#include <QVBoxLayout>
#include <QWheelEvent>

namespace {
static constexpr int MARGIN = 7;
static constexpr int BLUR_RADIUS = 2 * MARGIN;
static constexpr qreal STEP = 0.03;
static constexpr qreal MIN_SIZE = 100.0;
}

PinWidget::PinWidget(const QPixmap& pixmap,
const QRect& geometry,
QWidget* parent)
Expand All @@ -29,12 +39,11 @@ PinWidget::PinWidget(const QPixmap& pixmap,
m_hoverColor = conf.contrastUiColor();

m_layout = new QVBoxLayout(this);
const int margin = this->margin();
m_layout->setContentsMargins(margin, margin, margin, margin);
m_layout->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN);

m_shadowEffect = new QGraphicsDropShadowEffect(this);
m_shadowEffect->setColor(m_baseColor);
m_shadowEffect->setBlurRadius(2 * margin);
m_shadowEffect->setBlurRadius(BLUR_RADIUS);
m_shadowEffect->setOffset(0, 0);
setGraphicsEffect(m_shadowEffect);

Expand All @@ -52,7 +61,7 @@ PinWidget::PinWidget(const QPixmap& pixmap,
devicePixelRatio = currentScreen->devicePixelRatio();
}
#endif
const int m = margin * devicePixelRatio;
const int m = MARGIN * devicePixelRatio;
QRect adjusted_pos = geometry + QMargins(m, m, m, m);
setGeometry(adjusted_pos);
#if defined(Q_OS_MACOS)
Expand All @@ -69,35 +78,39 @@ PinWidget::PinWidget(const QPixmap& pixmap,
move(adjusted_pos.x(), adjusted_pos.y());
}
#endif
grabGesture(Qt::PinchGesture);
}

int PinWidget::margin() const
bool PinWidget::scrollEvent(QWheelEvent* event)
{
return 7;
}

void PinWidget::wheelEvent(QWheelEvent* event)
{
// getting the mouse wheel rotation in degree
const QPoint degrees = event->angleDelta() / 8;

// is the user zooming in or out ?
const int direction = degrees.y() > 0 ? 1 : -1;

// step taken in pixels (including direction)
const int step = degrees.manhattanLength() * direction;
const int newWidth = qBound(50, m_label->width() + step, maximumWidth());
const int newHeight = qBound(50, m_label->height() + step, maximumHeight());

// Actual scaling of the pixmap
const QSize newSize(newWidth, newHeight);
const qreal scale = qApp->devicePixelRatio();
const bool isExpanding = direction > 0;
setScaledPixmapToLabel(newSize, scale, isExpanding);

// Reflect scaling to the label
adjustSize();
event->accept();
const auto phase = event->phase();
if (phase == Qt::ScrollPhase::ScrollUpdate
#if defined(Q_OS_LINUX)
// Linux is getting only NoScrollPhase events.
or phase == Qt::ScrollPhase::NoScrollPhase
#endif
) {
const auto angle = event->angleDelta();
if (angle.y() == 0) {
return true;
}
m_currentStepScaleFactor = angle.y() > 0
? m_currentStepScaleFactor + STEP
: m_currentStepScaleFactor - STEP;
m_expanding = m_currentStepScaleFactor >= 1.0;
}
#if defined(Q_OS_MACOS)
// ScrollEnd is currently supported only on Mac OSX
if (phase == Qt::ScrollPhase::ScrollEnd) {
#else
else {
#endif
m_scaleFactor *= m_currentStepScaleFactor;
m_currentStepScaleFactor = 1.0;
m_expanding = false;
}
update();
return true;
}

void PinWidget::enterEvent(QEvent*)
Expand All @@ -112,6 +125,7 @@ void PinWidget::leaveEvent(QEvent*)

void PinWidget::mouseDoubleClickEvent(QMouseEvent*)
{
update();
close();
}

Expand All @@ -131,18 +145,55 @@ void PinWidget::mouseMoveEvent(QMouseEvent* e)
m_dragStart.y() + delta.y() - offsetH);
}

void PinWidget::setScaledPixmapToLabel(const QSize& newSize,
const qreal scale,
const bool expanding)
bool PinWidget::gestureEvent(QGestureEvent* event)
{
if (QGesture* pinch = event->gesture(Qt::PinchGesture)) {
pinchTriggered(static_cast<QPinchGesture*>(pinch));
}
return true;
}

bool PinWidget::event(QEvent* event)
{
if (event->type() == QEvent::Gesture) {
return gestureEvent(static_cast<QGestureEvent*>(event));
} else if (event->type() == QEvent::Wheel) {
return scrollEvent(static_cast<QWheelEvent*>(event));
}
return QWidget::event(event);
}

void PinWidget::paintEvent(QPaintEvent* event)
{
ConfigHandler config;
QPixmap scaledPixmap;
const auto aspectRatio =
expanding ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio;
const auto transformType = config.antialiasingPinZoom()
m_expanding ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio;
const auto transformType = ConfigHandler().antialiasingPinZoom()
? Qt::SmoothTransformation
: Qt::FastTransformation;
scaledPixmap = m_pixmap.scaled(newSize * scale, aspectRatio, transformType);
scaledPixmap.setDevicePixelRatio(scale);
m_label->setPixmap(scaledPixmap);
const qreal iw = m_pixmap.width();
const qreal ih = m_pixmap.height();
const qreal nw = qBound(MIN_SIZE,
iw * m_currentStepScaleFactor * m_scaleFactor,
static_cast<qreal>(maximumWidth()));
const qreal nh = qBound(MIN_SIZE,
ih * m_currentStepScaleFactor * m_scaleFactor,
static_cast<qreal>(maximumHeight()));
const QPixmap pix = m_pixmap.scaled(nw, nh, aspectRatio, transformType);
m_label->setPixmap(pix);
adjustSize();
}

void PinWidget::pinchTriggered(QPinchGesture* gesture)
{
const QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
m_currentStepScaleFactor = gesture->totalScaleFactor();
m_expanding = m_currentStepScaleFactor > gesture->lastScaleFactor();
}
if (gesture->state() == Qt::GestureFinished) {
m_scaleFactor *= m_currentStepScaleFactor;
m_currentStepScaleFactor = 1;
m_expanding = false;
}
update();
}
32 changes: 19 additions & 13 deletions src/tools/pin/pinwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@

#pragma once

#include <QGraphicsDropShadowEffect>
#include <QWidget>

class QVBoxLayout;
class QLabel;
class QVBoxLayout;
class QGestureEvent;
class QPinchGesture;
class QGraphicsDropShadowEffect;

class PinWidget : public QWidget
{
Expand All @@ -17,20 +19,20 @@ class PinWidget : public QWidget
const QRect& geometry,
QWidget* parent = nullptr);

int margin() const;

protected:
void wheelEvent(QWheelEvent* e);
void mouseDoubleClickEvent(QMouseEvent*);
void mousePressEvent(QMouseEvent*);
void mouseMoveEvent(QMouseEvent*);
void enterEvent(QEvent*);
void leaveEvent(QEvent*);
void mouseDoubleClickEvent(QMouseEvent*) override;
void mousePressEvent(QMouseEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
void enterEvent(QEvent*) override;
void leaveEvent(QEvent*) override;

bool event(QEvent* event) override;
void paintEvent(QPaintEvent* event) override;

private:
void setScaledPixmapToLabel(const QSize& newSize,
const qreal scale,
const bool expanding);
bool gestureEvent(QGestureEvent* event);
bool scrollEvent(QWheelEvent* e);
void pinchTriggered(QPinchGesture*);

QPixmap m_pixmap;
QVBoxLayout* m_layout;
Expand All @@ -39,4 +41,8 @@ class PinWidget : public QWidget
qreal m_offsetX, m_offsetY;
QGraphicsDropShadowEffect* m_shadowEffect;
QColor m_baseColor, m_hoverColor;

bool m_expanding{ false };
qreal m_scaleFactor{ 1 };
qreal m_currentStepScaleFactor{ 1 };
};

0 comments on commit 413a3f9

Please sign in to comment.