mirror of
https://github.com/fergalmoran/flameshot.git
synced 2026-01-05 00:24:23 +00:00
252 lines
7.4 KiB
C++
252 lines
7.4 KiB
C++
// 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 "screenshotsaver.h"
|
|
#include "src/utils/confighandler.h"
|
|
#include "src/utils/globalvalues.h"
|
|
|
|
#include <QLabel>
|
|
#include <QMenu>
|
|
#include <QScreen>
|
|
#include <QShortcut>
|
|
#include <QVBoxLayout>
|
|
#include <QWheelEvent>
|
|
|
|
namespace {
|
|
constexpr int MARGIN = 7;
|
|
constexpr int BLUR_RADIUS = 2 * MARGIN;
|
|
constexpr qreal STEP = 0.03;
|
|
constexpr qreal MIN_SIZE = 100.0;
|
|
}
|
|
|
|
PinWidget::PinWidget(const QPixmap& pixmap,
|
|
const QRect& geometry,
|
|
QWidget* parent)
|
|
: QWidget(parent)
|
|
, m_pixmap(pixmap)
|
|
, m_layout(new QVBoxLayout(this))
|
|
, m_label(new QLabel())
|
|
, m_shadowEffect(new QGraphicsDropShadowEffect(this))
|
|
{
|
|
setWindowIcon(QIcon(GlobalValues::iconPath()));
|
|
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
|
|
// set the bottom widget background transparent
|
|
setAttribute(Qt::WA_TranslucentBackground);
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
ConfigHandler conf;
|
|
m_baseColor = conf.uiColor();
|
|
m_hoverColor = conf.contrastUiColor();
|
|
|
|
m_layout->setContentsMargins(MARGIN, MARGIN, MARGIN, MARGIN);
|
|
|
|
m_shadowEffect->setColor(m_baseColor);
|
|
m_shadowEffect->setBlurRadius(BLUR_RADIUS);
|
|
m_shadowEffect->setOffset(0, 0);
|
|
setGraphicsEffect(m_shadowEffect);
|
|
|
|
m_label->setPixmap(m_pixmap);
|
|
m_layout->addWidget(m_label);
|
|
|
|
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
|
|
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
|
|
|
|
qreal devicePixelRatio = 1;
|
|
#if defined(Q_OS_MACOS)
|
|
QScreen* currentScreen = QGuiAppCurrentScreen().currentScreen();
|
|
if (currentScreen != nullptr) {
|
|
devicePixelRatio = currentScreen->devicePixelRatio();
|
|
}
|
|
#endif
|
|
const int margin =
|
|
static_cast<int>(static_cast<double>(MARGIN) * devicePixelRatio);
|
|
QRect adjusted_pos = geometry + QMargins(margin, margin, margin, margin);
|
|
setGeometry(adjusted_pos);
|
|
#if defined(Q_OS_LINUX)
|
|
setWindowFlags(Qt::X11BypassWindowManagerHint);
|
|
#endif
|
|
|
|
#if defined(Q_OS_MACOS)
|
|
if (currentScreen != nullptr) {
|
|
QPoint topLeft = currentScreen->geometry().topLeft();
|
|
adjusted_pos.setX((adjusted_pos.x() - topLeft.x()) / devicePixelRatio +
|
|
topLeft.x());
|
|
|
|
adjusted_pos.setY((adjusted_pos.y() - topLeft.y()) / devicePixelRatio +
|
|
topLeft.y());
|
|
adjusted_pos.setWidth(adjusted_pos.size().width() / devicePixelRatio);
|
|
adjusted_pos.setHeight(adjusted_pos.size().height() / devicePixelRatio);
|
|
resize(0, 0);
|
|
move(adjusted_pos.x(), adjusted_pos.y());
|
|
}
|
|
#endif
|
|
grabGesture(Qt::PinchGesture);
|
|
|
|
this->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(this,
|
|
&QWidget::customContextMenuRequested,
|
|
this,
|
|
&PinWidget::showContextMenu);
|
|
}
|
|
|
|
bool PinWidget::scrollEvent(QWheelEvent* event)
|
|
{
|
|
const auto phase = event->phase();
|
|
if (phase == Qt::ScrollPhase::ScrollUpdate
|
|
#if defined(Q_OS_LINUX) || defined(Q_OS_WINDOWS)
|
|
// Linux is getting only NoScrollPhase events.
|
|
|| 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;
|
|
}
|
|
|
|
m_sizeChanged = true;
|
|
update();
|
|
return true;
|
|
}
|
|
|
|
void PinWidget::enterEvent(QEvent*)
|
|
{
|
|
m_shadowEffect->setColor(m_hoverColor);
|
|
}
|
|
|
|
void PinWidget::leaveEvent(QEvent*)
|
|
{
|
|
m_shadowEffect->setColor(m_baseColor);
|
|
}
|
|
|
|
void PinWidget::mouseDoubleClickEvent(QMouseEvent*)
|
|
{
|
|
update();
|
|
close();
|
|
}
|
|
|
|
void PinWidget::mousePressEvent(QMouseEvent* e)
|
|
{
|
|
m_dragStart = e->globalPos();
|
|
m_offsetX = e->localPos().x() / width();
|
|
m_offsetY = e->localPos().y() / height();
|
|
}
|
|
|
|
void PinWidget::mouseMoveEvent(QMouseEvent* e)
|
|
{
|
|
const QPoint delta = e->globalPos() - m_dragStart;
|
|
const int offsetW = width() * m_offsetX;
|
|
const int offsetH = height() * m_offsetY;
|
|
move(m_dragStart.x() + delta.x() - offsetW,
|
|
m_dragStart.y() + delta.y() - offsetH);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (m_sizeChanged) {
|
|
const auto aspectRatio =
|
|
m_expanding ? Qt::KeepAspectRatioByExpanding : Qt::KeepAspectRatio;
|
|
const auto transformType = ConfigHandler().antialiasingPinZoom()
|
|
? Qt::SmoothTransformation
|
|
: Qt::FastTransformation;
|
|
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();
|
|
m_sizeChanged = false;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
m_sizeChanged = true;
|
|
update();
|
|
}
|
|
|
|
void PinWidget::showContextMenu(const QPoint& pos)
|
|
{
|
|
QMenu contextMenu(tr("Context menu"), this);
|
|
|
|
QAction copyToClipboardAction(tr("Copy to clipboard"), this);
|
|
connect(©ToClipboardAction,
|
|
&QAction::triggered,
|
|
this,
|
|
&PinWidget::copyToClipboard);
|
|
contextMenu.addAction(©ToClipboardAction);
|
|
|
|
QAction saveToFileAction(tr("Save to file"), this);
|
|
connect(
|
|
&saveToFileAction, &QAction::triggered, this, &PinWidget::saveToFile);
|
|
contextMenu.addAction(&saveToFileAction);
|
|
|
|
contextMenu.exec(mapToGlobal(pos));
|
|
}
|
|
|
|
void PinWidget::copyToClipboard()
|
|
{
|
|
saveToClipboard(m_pixmap);
|
|
}
|
|
void PinWidget::saveToFile()
|
|
{
|
|
hide();
|
|
saveToFilesystemGUI(m_pixmap);
|
|
show();
|
|
}
|