// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors #include #include #include "pinwidget.h" #include "qguiappcurrentscreen.h" #include "screenshotsaver.h" #include "src/utils/confighandler.h" #include "src/utils/globalvalues.h" #include #include #include #include #include #include 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(static_cast(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(pinch)); } return true; } bool PinWidget::event(QEvent* event) { if (event->type() == QEvent::Gesture) { return gestureEvent(static_cast(event)); } else if (event->type() == QEvent::Wheel) { return scrollEvent(static_cast(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(maximumWidth())); const qreal nh = qBound(MIN_SIZE, ih * m_currentStepScaleFactor * m_scaleFactor, static_cast(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(); }