File indexing completed on 2024-09-01 04:28:43
0001 /* 0002 * SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "resizerectangle.h" 0008 0009 #include <QDebug> 0010 #include <QSGFlatColorMaterial> 0011 #include <QSGGeometry> 0012 #include <QSGGeometryNode> 0013 0014 ResizeRectangle::ResizeRectangle(QQuickItem *parent) 0015 : QQuickItem(parent) 0016 { 0017 setAcceptedMouseButtons(Qt::LeftButton); 0018 setFlag(ItemHasContents); 0019 } 0020 0021 void ResizeRectangle::componentComplete() 0022 { 0023 QQuickItem::componentComplete(); 0024 QQmlEngine *engine = qmlEngine(this); 0025 m_handleComponent = new QQmlComponent(engine, QUrl(QStringLiteral("qrc:/BasicResizeHandle.qml"))); 0026 0027 auto handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create()); 0028 qDebug() << handleItem; 0029 m_handleBottomLeft = qobject_cast<ResizeHandle *>(handleItem); 0030 m_handleBottomLeft->setParent(this); 0031 m_handleBottomLeft->setParentItem(this); 0032 m_handleBottomLeft->setResizeCorner(ResizeHandle::BottomLeft); 0033 m_handleBottomLeft->setX(m_insideX - 5); 0034 m_handleBottomLeft->setY(m_insideY + m_insideHeight - 5); 0035 m_handleBottomLeft->setRectangle(this); 0036 0037 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create()); 0038 m_handleBottomRight = qobject_cast<ResizeHandle *>(handleItem); 0039 m_handleBottomRight->setParent(this); 0040 m_handleBottomRight->setParentItem(this); 0041 m_handleBottomRight->setResizeCorner(ResizeHandle::BottomRight); 0042 m_handleBottomRight->setX(m_insideX + m_insideWidth - 5); 0043 m_handleBottomRight->setY(m_insideY + m_insideHeight - 5); 0044 m_handleBottomRight->setRectangle(this); 0045 0046 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create()); 0047 m_handleTopLeft = qobject_cast<ResizeHandle *>(handleItem); 0048 m_handleTopLeft->setParent(this); 0049 m_handleTopLeft->setParentItem(this); 0050 m_handleTopLeft->setResizeCorner(ResizeHandle::TopLeft); 0051 m_handleTopLeft->setX(m_insideX - 5); 0052 m_handleTopLeft->setY(m_insideY - 5); 0053 m_handleTopLeft->setRectangle(this); 0054 0055 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create()); 0056 m_handleTopRight = qobject_cast<ResizeHandle *>(handleItem); 0057 m_handleTopRight->setParent(this); 0058 m_handleTopRight->setParentItem(this); 0059 m_handleTopRight->setResizeCorner(ResizeHandle::TopRight); 0060 m_handleTopRight->setX(m_insideX + m_insideWidth - 5); 0061 m_handleTopRight->setY(m_insideY - 5); 0062 m_handleTopRight->setRectangle(this); 0063 } 0064 0065 void ResizeRectangle::updateHandles() 0066 { 0067 if (isComponentComplete()) { 0068 m_handleTopRight->setX(m_insideX + m_insideWidth - 5); 0069 m_handleTopRight->setY(m_insideY - 5); 0070 m_handleTopLeft->setX(m_insideX - 5); 0071 m_handleTopLeft->setY(m_insideY - 5); 0072 m_handleBottomRight->setX(m_insideX + m_insideWidth - 5); 0073 m_handleBottomRight->setY(m_insideY + m_insideHeight - 5); 0074 m_handleBottomLeft->setX(m_insideX - 5); 0075 m_handleBottomLeft->setY(m_insideY + m_insideHeight - 5); 0076 } 0077 } 0078 0079 qreal ResizeRectangle::insideX() const 0080 { 0081 return m_insideX; 0082 } 0083 0084 void ResizeRectangle::setInsideX(qreal x) 0085 { 0086 x = qBound(0.0, x, this->width() - m_insideWidth); 0087 if (m_insideX == x) { 0088 return; 0089 } 0090 m_insideX = x; 0091 updateHandles(); 0092 Q_EMIT insideXChanged(); 0093 update(); 0094 } 0095 0096 qreal ResizeRectangle::insideY() const 0097 { 0098 return m_insideY; 0099 } 0100 0101 void ResizeRectangle::setInsideY(qreal y) 0102 { 0103 y = qBound(0.0, y, this->height() - m_insideHeight); 0104 if (m_insideY == y) { 0105 return; 0106 } 0107 m_insideY = y; 0108 updateHandles(); 0109 Q_EMIT insideYChanged(); 0110 update(); 0111 } 0112 0113 qreal ResizeRectangle::insideWidth() const 0114 { 0115 return m_insideWidth; 0116 } 0117 0118 void ResizeRectangle::setInsideWidth(qreal width) 0119 { 0120 width = qMin(width, this->width()); 0121 if (m_insideWidth == width) { 0122 return; 0123 } 0124 m_insideWidth = width; 0125 updateHandles(); 0126 Q_EMIT insideWidthChanged(); 0127 update(); 0128 } 0129 0130 qreal ResizeRectangle::insideHeight() const 0131 { 0132 return m_insideHeight; 0133 } 0134 0135 void ResizeRectangle::setInsideHeight(qreal height) 0136 { 0137 height = qMin(height, this->height()); 0138 if (m_insideHeight == height) { 0139 return; 0140 } 0141 m_insideHeight = height; 0142 updateHandles(); 0143 Q_EMIT insideHeightChanged(); 0144 update(); 0145 } 0146 0147 QSGNode *ResizeRectangle::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) 0148 { 0149 QSGGeometryNode *node = nullptr; 0150 QSGGeometry *geometry = nullptr; 0151 0152 const int vertexCount = 12; 0153 const int indexCount = 8 * 3; 0154 if (!oldNode) { 0155 node = new QSGGeometryNode; 0156 geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount, indexCount); 0157 geometry->setIndexDataPattern(QSGGeometry::StaticPattern); 0158 geometry->setDrawingMode(QSGGeometry::DrawTriangles); 0159 node->setGeometry(geometry); 0160 node->setFlag(QSGNode::OwnsGeometry); 0161 0162 QSGFlatColorMaterial *material = new QSGFlatColorMaterial; 0163 material->setColor(QColor(0, 0, 0, 70)); 0164 node->setMaterial(material); 0165 node->setFlag(QSGNode::OwnsMaterial); 0166 } else { 0167 node = static_cast<QSGGeometryNode *>(oldNode); 0168 geometry = node->geometry(); 0169 geometry->allocate(vertexCount, indexCount); 0170 } 0171 0172 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D(); 0173 points[0].set(0, 0); 0174 points[1].set(0, height()); 0175 points[2].set(m_insideX, 0); 0176 points[3].set(m_insideX, height()); 0177 0178 points[4].set(m_insideX + m_insideWidth, 0); 0179 points[5].set(m_insideX + m_insideWidth, height()); 0180 points[6].set(width(), 0); 0181 points[7].set(width(), height()); 0182 0183 points[8].set(m_insideX, m_insideY); 0184 points[9].set(m_insideX + m_insideWidth, m_insideY); 0185 points[10].set(m_insideX + m_insideWidth, m_insideY + m_insideHeight); 0186 points[11].set(m_insideX, m_insideY + m_insideHeight); 0187 0188 quint16 *indices = geometry->indexDataAsUShort(); 0189 // left 0190 indices[0 + 0] = 0; 0191 indices[0 + 1] = 1; 0192 indices[0 + 2] = 2; 0193 0194 indices[3 + 0] = 3; 0195 indices[3 + 1] = 1; 0196 indices[3 + 2] = 2; 0197 0198 // right 0199 indices[6 + 0] = 4; 0200 indices[6 + 1] = 5; 0201 indices[6 + 2] = 6; 0202 0203 indices[9 + 0] = 7; 0204 indices[9 + 1] = 5; 0205 indices[9 + 2] = 6; 0206 0207 // top 0208 indices[12 + 0] = 2; 0209 indices[12 + 1] = 8; 0210 indices[12 + 2] = 4; 0211 0212 indices[15 + 0] = 9; 0213 indices[15 + 1] = 8; 0214 indices[15 + 2] = 4; 0215 0216 // bottom 0217 indices[18 + 0] = 3; 0218 indices[18 + 1] = 11; 0219 indices[18 + 2] = 10; 0220 0221 indices[21 + 0] = 3; 0222 indices[21 + 1] = 5; 0223 indices[21 + 2] = 10; 0224 0225 geometry->markIndexDataDirty(); 0226 geometry->markVertexDataDirty(); 0227 node->markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial); 0228 return node; 0229 } 0230 0231 void ResizeRectangle::mouseReleaseEvent(QMouseEvent *event) 0232 { 0233 m_mouseClickedOnRectangle = false; 0234 event->accept(); 0235 } 0236 0237 void ResizeRectangle::mousePressEvent(QMouseEvent *event) 0238 { 0239 m_mouseDownPosition = event->pos(); 0240 m_mouseDownGeometry = QPointF(m_insideX, m_insideY); 0241 if (m_mouseDownPosition.x() >= m_insideX && m_mouseDownPosition.x() <= m_insideX + m_insideWidth && m_mouseDownPosition.y() >= m_insideY 0242 && m_mouseDownPosition.y() <= m_insideY + m_insideHeight) { 0243 m_mouseClickedOnRectangle = true; 0244 } 0245 event->accept(); 0246 } 0247 0248 void ResizeRectangle::mouseMoveEvent(QMouseEvent *event) 0249 { 0250 if (m_mouseClickedOnRectangle) { 0251 const QPointF difference = m_mouseDownPosition - event->pos(); 0252 const qreal x = m_mouseDownGeometry.x() - difference.x(); 0253 const qreal y = m_mouseDownGeometry.y() - difference.y(); 0254 setInsideX(x); 0255 setInsideY(y); 0256 } 0257 } 0258 0259 void ResizeRectangle::mouseDoubleClickEvent(QMouseEvent *event) 0260 { 0261 Q_EMIT acceptSize(); 0262 event->accept(); 0263 } 0264 0265 #include "moc_resizerectangle.cpp"