/* SPDX-FileCopyrightText: 2023 David Edmundson SPDX-FileCopyrightText: 2022 Luca Carlon SPDX-License-Identifier: LGPL-2.0-or-later */ #include "windowresizehandler.h" #include #include #include using namespace PlasmaQuick; class WindowResizeHandlerPrivate { public: QWindow *window; QMargins margins; Qt::Edges activeEdges; bool updateMouseCursor(const QPointF &globalMousePos); void unsetMouseCursor(); Qt::Edges hitTest(const QPointF &pos); private: bool overridingCursor = false; bool hitTestLeft(const QPointF &pos); bool hitTestRight(const QPointF &pos); bool hitTestTop(const QPointF &pos); bool hitTestBottom(const QPointF &pos); }; PlasmaQuick::WindowResizeHandler::WindowResizeHandler(QWindow *parent) : QObject(parent) , d(new WindowResizeHandlerPrivate) { d->window = parent; d->window->installEventFilter(this); } WindowResizeHandler::~WindowResizeHandler() { d->window->removeEventFilter(this); } void WindowResizeHandler::setMargins(const QMargins &margins) { d->margins = margins; } QMargins WindowResizeHandler::margins() const { return d->margins; } void WindowResizeHandler::setActiveEdges(Qt::Edges edges) { d->activeEdges = edges; } Qt::Edges WindowResizeHandler::activeEdges() const { return d->activeEdges; } bool WindowResizeHandler::eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched) switch (event->type()) { case QEvent::Enter: { QEnterEvent *ee = static_cast(event); d->updateMouseCursor(ee->globalPosition()); return false; } case QEvent::Leave: d->unsetMouseCursor(); return false; case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: { QMouseEvent *me = static_cast(event); if (event->type() == QEvent::MouseMove && d->updateMouseCursor(me->globalPosition())) { return false; } if (event->type() == QEvent::MouseButtonPress) { const QPointF globalMousePos = me->globalPosition(); const Qt::Edges sides = d->hitTest(globalMousePos) & d->activeEdges; if (sides) { d->window->startSystemResize(sides); return true; } } } break; default: break; } return false; } bool WindowResizeHandlerPrivate::updateMouseCursor(const QPointF &globalMousePos) { Qt::Edges sides = hitTest(globalMousePos) & activeEdges; if (!sides) { unsetMouseCursor(); return false; } if (sides == Qt::Edges(Qt::LeftEdge | Qt::TopEdge)) { window->setCursor(Qt::SizeFDiagCursor); } else if (sides == Qt::Edges(Qt::RightEdge | Qt::TopEdge)) { window->setCursor(Qt::SizeBDiagCursor); } else if (sides == Qt::Edges(Qt::LeftEdge | Qt::BottomEdge)) { window->setCursor(Qt::SizeBDiagCursor); } else if (sides == Qt::Edges(Qt::RightEdge | Qt::BottomEdge)) { window->setCursor(Qt::SizeFDiagCursor); } else if (sides.testFlag(Qt::TopEdge)) { window->setCursor(Qt::SizeVerCursor); } else if (sides.testFlag(Qt::LeftEdge)) { window->setCursor(Qt::SizeHorCursor); } else if (sides.testFlag(Qt::RightEdge)) { window->setCursor(Qt::SizeHorCursor); } else { window->setCursor(Qt::SizeVerCursor); } overridingCursor = true; return true; } void WindowResizeHandlerPrivate::unsetMouseCursor() { if (overridingCursor) { window->unsetCursor(); overridingCursor = false; } } Qt::Edges WindowResizeHandlerPrivate::hitTest(const QPointF &pos) { bool left = hitTestLeft(pos); bool right = hitTestRight(pos); bool top = hitTestTop(pos); bool bottom = hitTestBottom(pos); Qt::Edges edges; if (left) { edges.setFlag(Qt::LeftEdge); } if (right) { edges.setFlag(Qt::RightEdge); } if (bottom) { edges.setFlag(Qt::BottomEdge); } if (top) { edges.setFlag(Qt::TopEdge); } return edges; } bool WindowResizeHandlerPrivate::hitTestLeft(const QPointF &pos) { const QRect geometry = window->geometry(); const QRectF rect(geometry.x(), geometry.y(), margins.left(), geometry.height()); return rect.contains(pos); } bool WindowResizeHandlerPrivate::hitTestRight(const QPointF &pos) { const QRect geometry = window->geometry(); const QRectF rect(geometry.x() + geometry.width() - margins.right(), geometry.y(), margins.right(), geometry.height()); return rect.contains(pos); } bool WindowResizeHandlerPrivate::hitTestTop(const QPointF &pos) { const QRect geometry = window->geometry(); const QRectF rect(geometry.x(), geometry.y(), geometry.width(), margins.top()); return rect.contains(pos); } bool WindowResizeHandlerPrivate::hitTestBottom(const QPointF &pos) { const QRect geometry = window->geometry(); const QRectF rect(geometry.x(), geometry.y() + geometry.height() - margins.bottom(), geometry.width(), margins.bottom()); return rect.contains(pos); }