File indexing completed on 2024-04-14 04:36:49

0001 /*
0002  * SPDX-FileCopyrightText: (C) 2019 Marco Martin <mart@kde.org>
0003  * SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.1-or-later
0006  */
0007 
0008 #include "resizehandle.h"
0009 #include "resizerectangle.h"
0010 
0011 #include <QCursor>
0012 #include <cmath>
0013 
0014 ResizeHandle::ResizeHandle(QQuickItem *parent)
0015     : QQuickItem(parent)
0016 {
0017     setAcceptedMouseButtons(Qt::LeftButton);
0018 
0019     auto syncCursor = [this]() {
0020         switch (m_resizeCorner) {
0021         case Left:
0022         case Right:
0023             setCursor(QCursor(Qt::SizeHorCursor));
0024             break;
0025         case Top:
0026         case Bottom:
0027             setCursor(QCursor(Qt::SizeVerCursor));
0028             break;
0029         case TopLeft:
0030         case BottomRight:
0031             setCursor(QCursor(Qt::SizeFDiagCursor));
0032             break;
0033         case TopRight:
0034         case BottomLeft:
0035         default:
0036             setCursor(Qt::SizeBDiagCursor);
0037         }
0038     };
0039 
0040     syncCursor();
0041     connect(this, &ResizeHandle::resizeCornerChanged, this, syncCursor);
0042 }
0043 
0044 QQuickItem *ResizeHandle::rectangle() const
0045 {
0046     return m_rectangle;
0047 }
0048 
0049 void ResizeHandle::setResizeCorner(ResizeHandle::Corner corner)
0050 {
0051     if (m_resizeCorner == corner) {
0052         return;
0053     }
0054     m_resizeCorner = corner;
0055     Q_EMIT resizeCornerChanged();
0056 }
0057 
0058 void ResizeHandle::setRectangle(QQuickItem *rectangle)
0059 {
0060     if (m_rectangle == rectangle) {
0061         return;
0062     }
0063     m_rectangle = qobject_cast<ResizeRectangle *>(rectangle);
0064     Q_EMIT rectangleChanged();
0065 }
0066 
0067 bool ResizeHandle::resizeBlocked() const
0068 {
0069     return false; // m_resizeWidthBlocked || m_resizeHeightBlocked;
0070 }
0071 
0072 bool ResizeHandle::resizeLeft() const
0073 {
0074     return m_resizeCorner == Left || m_resizeCorner == TopLeft || m_resizeCorner == BottomLeft;
0075 }
0076 
0077 bool ResizeHandle::resizeTop() const
0078 {
0079     return m_resizeCorner == Top || m_resizeCorner == TopLeft || m_resizeCorner == TopRight;
0080 }
0081 
0082 bool ResizeHandle::resizeRight() const
0083 {
0084     return m_resizeCorner == Right || m_resizeCorner == TopRight || m_resizeCorner == BottomRight;
0085 }
0086 
0087 bool ResizeHandle::resizeBottom() const
0088 {
0089     return m_resizeCorner == Bottom || m_resizeCorner == BottomLeft || m_resizeCorner == BottomRight;
0090 }
0091 
0092 void ResizeHandle::setResizeBlocked(bool width, bool height)
0093 {
0094     if (m_resizeWidthBlocked == width && m_resizeHeightBlocked == height) {
0095         return;
0096     }
0097 
0098     m_resizeWidthBlocked = width;
0099     m_resizeHeightBlocked = height;
0100 
0101     Q_EMIT resizeBlockedChanged();
0102 }
0103 
0104 void ResizeHandle::mousePressEvent(QMouseEvent *event)
0105 {
0106     m_mouseDownPosition = event->windowPos();
0107     m_mouseDownGeometry = QRectF(m_rectangle->insideX(), m_rectangle->insideY(), m_rectangle->insideWidth(), m_rectangle->insideHeight());
0108     setResizeBlocked(false, false);
0109     event->accept();
0110 }
0111 
0112 void ResizeHandle::mouseMoveEvent(QMouseEvent *event)
0113 {
0114     const QPointF difference = m_mouseDownPosition - event->windowPos();
0115 
0116     const QSizeF minimumSize = QSize(20, 20);
0117 
0118     // Horizontal resize
0119     if (resizeLeft()) {
0120         const qreal width = qMax(minimumSize.width(), m_mouseDownGeometry.width() + difference.x());
0121         const qreal x = m_mouseDownGeometry.x() + (m_mouseDownGeometry.width() - width);
0122 
0123         m_rectangle->setInsideX(x);
0124         m_rectangle->setInsideWidth(width);
0125         setResizeBlocked(m_mouseDownGeometry.width() + difference.x() < minimumSize.width(), m_resizeHeightBlocked);
0126     } else if (resizeRight()) {
0127         const qreal width = qMax(minimumSize.width(), m_mouseDownGeometry.width() - difference.x());
0128 
0129         m_rectangle->setInsideWidth(width);
0130         setResizeBlocked(m_mouseDownGeometry.width() - difference.x() < minimumSize.width(), m_resizeHeightBlocked);
0131     }
0132 
0133     // Vertical Resize
0134     if (resizeTop()) {
0135         const qreal height = qMax(minimumSize.height(), m_mouseDownGeometry.height() + difference.y());
0136         const qreal y = m_mouseDownGeometry.y() + (m_mouseDownGeometry.height() - height);
0137 
0138         m_rectangle->setInsideY(y);
0139         m_rectangle->setInsideHeight(height);
0140         setResizeBlocked(m_resizeWidthBlocked, m_mouseDownGeometry.height() + difference.y() < minimumSize.height());
0141     } else if (resizeBottom()) {
0142         const qreal height = qMax(minimumSize.height(), m_mouseDownGeometry.height() - difference.y());
0143 
0144         m_rectangle->setInsideHeight(qMax(height, minimumSize.height()));
0145         setResizeBlocked(m_resizeWidthBlocked, m_mouseDownGeometry.height() - difference.y() < minimumSize.height());
0146     }
0147 
0148     event->accept();
0149 }
0150 
0151 void ResizeHandle::mouseReleaseEvent(QMouseEvent *event)
0152 {
0153     event->accept();
0154 
0155     setResizeBlocked(false, false);
0156     Q_EMIT resizeBlockedChanged();
0157 }