KQuickImageEditor

resizerectangle.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "resizerectangle.h"
8
9#include <QDebug>
10#include <QSGFlatColorMaterial>
11#include <QSGGeometry>
12#include <QSGGeometryNode>
13
14ResizeRectangle::ResizeRectangle(QQuickItem *parent)
15 : QQuickItem(parent)
16{
17 setAcceptedMouseButtons(Qt::LeftButton);
18 setFlag(ItemHasContents);
19}
20
21void ResizeRectangle::componentComplete()
22{
24 QQmlEngine *engine = qmlEngine(this);
25 m_handleComponent = new QQmlComponent(engine, QUrl(QStringLiteral("qrc:/BasicResizeHandle.qml")));
26
27 auto handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create());
28 qDebug() << handleItem;
29 m_handleBottomLeft = qobject_cast<ResizeHandle *>(handleItem);
30 m_handleBottomLeft->setParent(this);
31 m_handleBottomLeft->setParentItem(this);
32 m_handleBottomLeft->setResizeCorner(ResizeHandle::BottomLeft);
33 m_handleBottomLeft->setX(m_insideX - 5);
34 m_handleBottomLeft->setY(m_insideY + m_insideHeight - 5);
35 m_handleBottomLeft->setRectangle(this);
36
37 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create());
38 m_handleBottomRight = qobject_cast<ResizeHandle *>(handleItem);
39 m_handleBottomRight->setParent(this);
40 m_handleBottomRight->setParentItem(this);
41 m_handleBottomRight->setResizeCorner(ResizeHandle::BottomRight);
42 m_handleBottomRight->setX(m_insideX + m_insideWidth - 5);
43 m_handleBottomRight->setY(m_insideY + m_insideHeight - 5);
44 m_handleBottomRight->setRectangle(this);
45
46 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create());
47 m_handleTopLeft = qobject_cast<ResizeHandle *>(handleItem);
48 m_handleTopLeft->setParent(this);
49 m_handleTopLeft->setParentItem(this);
50 m_handleTopLeft->setResizeCorner(ResizeHandle::TopLeft);
51 m_handleTopLeft->setX(m_insideX - 5);
52 m_handleTopLeft->setY(m_insideY - 5);
53 m_handleTopLeft->setRectangle(this);
54
55 handleItem = qobject_cast<QQuickItem *>(m_handleComponent->create());
56 m_handleTopRight = qobject_cast<ResizeHandle *>(handleItem);
57 m_handleTopRight->setParent(this);
58 m_handleTopRight->setParentItem(this);
59 m_handleTopRight->setResizeCorner(ResizeHandle::TopRight);
60 m_handleTopRight->setX(m_insideX + m_insideWidth - 5);
61 m_handleTopRight->setY(m_insideY - 5);
62 m_handleTopRight->setRectangle(this);
63}
64
65void ResizeRectangle::updateHandles()
66{
67 if (isComponentComplete()) {
68 m_handleTopRight->setX(m_insideX + m_insideWidth - 5);
69 m_handleTopRight->setY(m_insideY - 5);
70 m_handleTopLeft->setX(m_insideX - 5);
71 m_handleTopLeft->setY(m_insideY - 5);
72 m_handleBottomRight->setX(m_insideX + m_insideWidth - 5);
73 m_handleBottomRight->setY(m_insideY + m_insideHeight - 5);
74 m_handleBottomLeft->setX(m_insideX - 5);
75 m_handleBottomLeft->setY(m_insideY + m_insideHeight - 5);
76 }
77}
78
79qreal ResizeRectangle::insideX() const
80{
81 return m_insideX;
82}
83
84void ResizeRectangle::setInsideX(qreal x)
85{
86 x = qBound(0.0, x, this->width() - m_insideWidth);
87 if (m_insideX == x) {
88 return;
89 }
90 m_insideX = x;
91 updateHandles();
92 Q_EMIT insideXChanged();
93 update();
94}
95
96qreal ResizeRectangle::insideY() const
97{
98 return m_insideY;
99}
100
101void ResizeRectangle::setInsideY(qreal y)
102{
103 y = qBound(0.0, y, this->height() - m_insideHeight);
104 if (m_insideY == y) {
105 return;
106 }
107 m_insideY = y;
108 updateHandles();
109 Q_EMIT insideYChanged();
110 update();
111}
112
113qreal ResizeRectangle::insideWidth() const
114{
115 return m_insideWidth;
116}
117
118void ResizeRectangle::setInsideWidth(qreal width)
119{
120 width = qMin(width, this->width());
121 if (m_insideWidth == width) {
122 return;
123 }
124 m_insideWidth = width;
125 updateHandles();
126 Q_EMIT insideWidthChanged();
127 update();
128}
129
130qreal ResizeRectangle::insideHeight() const
131{
132 return m_insideHeight;
133}
134
135void ResizeRectangle::setInsideHeight(qreal height)
136{
137 height = qMin(height, this->height());
138 if (m_insideHeight == height) {
139 return;
140 }
141 m_insideHeight = height;
142 updateHandles();
143 Q_EMIT insideHeightChanged();
144 update();
145}
146
147QSGNode *ResizeRectangle::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
148{
149 QSGGeometryNode *node = nullptr;
150 QSGGeometry *geometry = nullptr;
151
152 const int vertexCount = 12;
153 const int indexCount = 8 * 3;
154 if (!oldNode) {
155 node = new QSGGeometryNode;
156 geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), vertexCount, indexCount);
159 node->setGeometry(geometry);
161
163 material->setColor(QColor(0, 0, 0, 70));
164 node->setMaterial(material);
166 } else {
167 node = static_cast<QSGGeometryNode *>(oldNode);
168 geometry = node->geometry();
169 geometry->allocate(vertexCount, indexCount);
170 }
171
172 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D();
173 points[0].set(0, 0);
174 points[1].set(0, height());
175 points[2].set(m_insideX, 0);
176 points[3].set(m_insideX, height());
177
178 points[4].set(m_insideX + m_insideWidth, 0);
179 points[5].set(m_insideX + m_insideWidth, height());
180 points[6].set(width(), 0);
181 points[7].set(width(), height());
182
183 points[8].set(m_insideX, m_insideY);
184 points[9].set(m_insideX + m_insideWidth, m_insideY);
185 points[10].set(m_insideX + m_insideWidth, m_insideY + m_insideHeight);
186 points[11].set(m_insideX, m_insideY + m_insideHeight);
187
188 quint16 *indices = geometry->indexDataAsUShort();
189 // left
190 indices[0 + 0] = 0;
191 indices[0 + 1] = 1;
192 indices[0 + 2] = 2;
193
194 indices[3 + 0] = 3;
195 indices[3 + 1] = 1;
196 indices[3 + 2] = 2;
197
198 // right
199 indices[6 + 0] = 4;
200 indices[6 + 1] = 5;
201 indices[6 + 2] = 6;
202
203 indices[9 + 0] = 7;
204 indices[9 + 1] = 5;
205 indices[9 + 2] = 6;
206
207 // top
208 indices[12 + 0] = 2;
209 indices[12 + 1] = 8;
210 indices[12 + 2] = 4;
211
212 indices[15 + 0] = 9;
213 indices[15 + 1] = 8;
214 indices[15 + 2] = 4;
215
216 // bottom
217 indices[18 + 0] = 3;
218 indices[18 + 1] = 11;
219 indices[18 + 2] = 10;
220
221 indices[21 + 0] = 3;
222 indices[21 + 1] = 5;
223 indices[21 + 2] = 10;
224
225 geometry->markIndexDataDirty();
226 geometry->markVertexDataDirty();
228 return node;
229}
230
231void ResizeRectangle::mouseReleaseEvent(QMouseEvent *event)
232{
233 m_mouseClickedOnRectangle = false;
234 event->accept();
235}
236
237void ResizeRectangle::mousePressEvent(QMouseEvent *event)
238{
239 m_mouseDownPosition = event->pos();
240 m_mouseDownGeometry = QPointF(m_insideX, m_insideY);
241 if (m_mouseDownPosition.x() >= m_insideX && m_mouseDownPosition.x() <= m_insideX + m_insideWidth && m_mouseDownPosition.y() >= m_insideY
242 && m_mouseDownPosition.y() <= m_insideY + m_insideHeight) {
243 m_mouseClickedOnRectangle = true;
244 }
245 event->accept();
246}
247
248void ResizeRectangle::mouseMoveEvent(QMouseEvent *event)
249{
250 if (m_mouseClickedOnRectangle) {
251 const QPointF difference = m_mouseDownPosition - event->pos();
252 const qreal x = m_mouseDownGeometry.x() - difference.x();
253 const qreal y = m_mouseDownGeometry.y() - difference.y();
254 setInsideX(x);
255 setInsideY(y);
256 }
257}
258
259void ResizeRectangle::mouseDoubleClickEvent(QMouseEvent *event)
260{
262 event->accept();
263}
264
265#include "moc_resizerectangle.cpp"
void acceptSize()
Double click event signal.
Q_EMITQ_EMIT
void setParent(QObject *parent)
qreal x() const const
qreal y() const const
virtual QObject * create(QQmlContext *context)
virtual void componentComplete() override
bool isComponentComplete() const const
void setParentItem(QQuickItem *parent)
void update()
void setX(qreal)
void setY(qreal)
QSGGeometry * geometry()
void setGeometry(QSGGeometry *geometry)
void setColor(const QColor &color)
void set(float x, float y)
void allocate(int vertexCount, int indexCount)
const AttributeSet & defaultAttributes_Point2D()
quint16 * indexDataAsUShort()
void markIndexDataDirty()
void markVertexDataDirty()
void setDrawingMode(unsigned int mode)
void setIndexDataPattern(DataPattern p)
Point2D * vertexDataAsPoint2D()
void setMaterial(QSGMaterial *material)
void markDirty(DirtyState bits)
void setFlag(Flag f, bool enabled)
LeftButton
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:40 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.