File pinwidget.cpp#
File List > pin > pinwidget.cpp
Go to the documentation of this file.
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
#include <QGraphicsDropShadowEffect>
#include <QGraphicsOpacityEffect>
#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);
setFocusPolicy(Qt::StrongFocus);
// 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);
setWindowOpacity(m_opacity);
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) || defined(Q_OS_LINUX)
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) || defined(Q_OS_LINUX)
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);
}
void PinWidget::closePin()
{
update();
close();
}
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*)
{
closePin();
}
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);
}
void PinWidget::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_0) {
m_opacity = 1.0;
} else if (event->key() == Qt::Key_9) {
m_opacity = 0.9;
} else if (event->key() == Qt::Key_8) {
m_opacity = 0.8;
} else if (event->key() == Qt::Key_7) {
m_opacity = 0.7;
} else if (event->key() == Qt::Key_6) {
m_opacity = 0.6;
} else if (event->key() == Qt::Key_5) {
m_opacity = 0.5;
} else if (event->key() == Qt::Key_4) {
m_opacity = 0.4;
} else if (event->key() == Qt::Key_3) {
m_opacity = 0.3;
} else if (event->key() == Qt::Key_2) {
m_opacity = 0.2;
} else if (event->key() == Qt::Key_1) {
m_opacity = 0.1;
}
setWindowOpacity(m_opacity);
}
bool PinWidget::gestureEvent(QGestureEvent* event)
{
if (QGesture* pinch = event->gesture(Qt::PinchGesture)) {
pinchTriggered(static_cast<QPinchGesture*>(pinch));
}
return true;
}
void PinWidget::rotateLeft()
{
m_sizeChanged = true;
auto rotateTransform = QTransform().rotate(270);
m_pixmap = m_pixmap.transformed(rotateTransform);
}
void PinWidget::rotateRight()
{
m_sizeChanged = true;
auto rotateTransform = QTransform().rotate(90);
m_pixmap = m_pixmap.transformed(rotateTransform);
}
void PinWidget::increaseOpacity()
{
m_opacity += 0.1;
if (m_opacity > 1.0) {
m_opacity = 1.0;
}
setWindowOpacity(m_opacity);
}
void PinWidget::decreaseOpacity()
{
m_opacity -= 0.1;
if (m_opacity < 0.0) {
m_opacity = 0.0;
}
setWindowOpacity(m_opacity);
}
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.addSeparator();
QAction rotateRightAction(tr("Rotate Right"), this);
connect(
&rotateRightAction, &QAction::triggered, this, &PinWidget::rotateRight);
contextMenu.addAction(&rotateRightAction);
QAction rotateLeftAction(tr("Rotate Left"), this);
connect(
&rotateLeftAction, &QAction::triggered, this, &PinWidget::rotateLeft);
contextMenu.addAction(&rotateLeftAction);
QAction increaseOpacityAction(tr("Increase Opacity"), this);
connect(&increaseOpacityAction,
&QAction::triggered,
this,
&PinWidget::increaseOpacity);
contextMenu.addAction(&increaseOpacityAction);
QAction decreaseOpacityAction(tr("Decrease Opacity"), this);
connect(&decreaseOpacityAction,
&QAction::triggered,
this,
&PinWidget::decreaseOpacity);
contextMenu.addAction(&decreaseOpacityAction);
QAction closePinAction(tr("Close"), this);
connect(&closePinAction, &QAction::triggered, this, &PinWidget::closePin);
contextMenu.addSeparator();
contextMenu.addAction(&closePinAction);
contextMenu.exec(mapToGlobal(pos));
}
void PinWidget::copyToClipboard()
{
saveToClipboard(m_pixmap);
}
void PinWidget::saveToFile()
{
hide();
saveToFilesystemGUI(m_pixmap);
show();
}