Krita Source Code Documentation
Loading...
Searching...
No Matches
KisVisualRectangleSelectorShape.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
7
8#include <QColor>
9#include <QPainter>
10#include <QRect>
11#include <QList>
12#include <QLineF>
13#include <QtMath>
14
15#include "kis_debug.h"
16
18 Dimensions dimension,
19 int channel1, int channel2,
20 int width,
22 : KisVisualColorSelectorShape(parent, dimension, channel1, channel2)
23{
24 //qDebug() << "creating KisVisualRectangleSelectorShape" << this;
25 m_type = d;
26 m_barWidth = width;
27}
28
30{
31 //qDebug() << "deleting KisVisualRectangleSelectorShape" << this;
32}
33
38
47
49{
50 return getAvailableSpace(geom, true);
51}
52
54{
55 return getAvailableSpace(geom, false);
56}
57
62
64{
65 QPoint tl;
66 QPoint br;
67
69 br = geom.bottomRight();
70 tl = QPoint(geom.topLeft().x() + m_barWidth, geom.topLeft().y());
72 br = geom.bottomRight();
73 tl = QPoint(geom.topLeft().x(), geom.topLeft().y() + m_barWidth);
74 } else {
75 tl = QPoint(geom.topLeft().x() + m_barWidth, geom.topLeft().y() + m_barWidth);
76 br = QPoint(geom.bottomRight().x() - m_barWidth, geom.bottomRight().y() - m_barWidth);
77 }
78 QRect available(tl, br);
79 if (!stretch) {
80 int size = qMin(available.height(), available.width());
82 available.moveTop(available.y() + (available.height() - size)/2);
84 available.moveLeft(available.x() + (available.width() - size)/2);
85 }
86 available.setSize(QSize(size, size));
87 }
88
89 return available;
90}
91
93{
94 // Reminder: in Qt widget space, origin is top-left, but we want zero y to be at the bottom
95 qreal x = 0.5 * width();
96 qreal y = 0.5 * height();
97 qreal offset = 5.0;
101 y = qMin((1.0 - coordinate.x())*(height()-offset*2)+offset, (qreal)height());
103 x = qMin(coordinate.x()*(width()-offset*2)+offset, (qreal)width());
105
106 QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth);
107 QPointF left (innerRect.left(),innerRect.center().y());
108 QList <QLineF> polygonLines;
109 polygonLines.append(QLineF(left, innerRect.topLeft()));
110 polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight()));
111 polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight()));
112 polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft()));
113 polygonLines.append(QLineF(innerRect.bottomLeft(), left));
114
115 qreal totalLength =0.0;
116 Q_FOREACH(QLineF line, polygonLines) {
117 totalLength += line.length();
118 }
119
120 qreal length = coordinate.x()*totalLength;
121 QPointF intersect(x,y);
122 Q_FOREACH(QLineF line, polygonLines) {
123 if (line.length()>length && length>0){
124 intersect = line.pointAt(length/line.length());
125
126 }
127 length-=line.length();
128 }
129 x = qRound(intersect.x());
130 y = qRound(intersect.y());
131
132 }
133 else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ {
134
135 QRectF innerRect(m_barWidth/2, m_barWidth/2, width()-m_barWidth, height()-m_barWidth);
136 QPointF bottom (innerRect.center().x(), innerRect.bottom());
137 QList <QLineF> polygonLines;
138 polygonLines.append(QLineF(bottom, innerRect.bottomLeft()));
139 polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft()));
140 polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight()));
141 polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight()));
142 polygonLines.append(QLineF(innerRect.bottomRight(), bottom));
143
144 qreal totalLength =0.0;
145 Q_FOREACH(QLineF line, polygonLines) {
146 totalLength += line.length();
147 }
148
149 qreal length = coordinate.x()*(totalLength/2);
150 QPointF intersect(x,y);
151 if (coordinate.y()==1) {
152 for (int i = polygonLines.size()-1; i==0; i--) {
153 QLineF line = polygonLines.at(i);
154 if (line.length()>length && length>0){
155 intersect = line.pointAt(length/line.length());
156
157 }
158 length-=line.length();
159 }
160 } else {
161 Q_FOREACH(QLineF line, polygonLines) {
162 if (line.length()>length && length>0){
163 intersect = line.pointAt(length/line.length());
164
165 }
166 length-=line.length();
167 }
168 }
169 x = qRound(intersect.x());
170 y = qRound(intersect.y());
171
172 }
173 } else {
174 x = qMin(coordinate.x()*(width()-offset*2)+offset, (qreal)width());
175 y = qMin((1.0 - coordinate.y())*(height()-offset*2)+offset, (qreal)height());
176 }
177 return QPointF(x,y);
178}
179
181{
182 // Reminder: in Qt widget space, origin is top-left, but we want zero y to be at the bottom
183 //default values:
184 qreal x = 0.5;
185 qreal y = 0.5;
186 qreal offset = 5.0;
190 x = 1.0 - (coordinate.y()-offset)/(height()-offset*2);
192 x = (coordinate.x()-offset)/(width()-offset*2);
194 //border
195
196 QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2));
197 QPointF left (innerRect.left(),innerRect.center().y());
198 QList <QLineF> polygonLines;
199 polygonLines.append(QLineF(left, innerRect.topLeft()));
200 polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight()));
201 polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight()));
202 polygonLines.append(QLineF(innerRect.bottomRight(), innerRect.bottomLeft()));
203 polygonLines.append(QLineF(innerRect.bottomLeft(), left));
204
205 QLineF radius(coordinate, this->geometry().center());
206 QPointF intersect(0.5,0.5);
207 qreal length = 0.0;
208 qreal totalLength = 0.0;
209 bool foundIntersect = false;
210 Q_FOREACH(QLineF line, polygonLines) {
211 if (line.intersects(radius, &intersect) == QLineF::BoundedIntersection && foundIntersect == false)
212 {
213 foundIntersect = true;
214 length+=QLineF(line.p1(), intersect).length();
215
216 }
217 if (foundIntersect==false) {
218 length+=line.length();
219 }
220 totalLength+=line.length();
221 }
222
223 x = length/totalLength;
224
225 } else /*if (m_type == KisVisualRectangleSelectorShape::borderMirrored)*/ {
226 //border
227
228 QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2));
229 QPointF bottom (innerRect.center().x(), innerRect.bottom());
230 QList <QLineF> polygonLines;
231 polygonLines.append(QLineF(bottom, innerRect.bottomLeft()));
232 polygonLines.append(QLineF(innerRect.bottomLeft(), innerRect.topLeft()));
233 polygonLines.append(QLineF(innerRect.topLeft(), innerRect.topRight()));
234 polygonLines.append(QLineF(innerRect.topRight(), innerRect.bottomRight()));
235 polygonLines.append(QLineF(innerRect.bottomRight(), bottom));
236
237 QLineF radius(coordinate, this->geometry().center());
238 QPointF intersect(0.5,0.5);
239 qreal length = 0.0;
240 qreal totalLength = 0.0;
241 bool foundIntersect = false;
242 Q_FOREACH(QLineF line, polygonLines) {
243 if (line.intersects(radius, &intersect) == QLineF::BoundedIntersection && foundIntersect == false)
244 {
245 foundIntersect = true;
246 length+=QLineF(line.p1(), intersect).length();
247
248 }
249 if (foundIntersect==false) {
250 length+=line.length();
251 }
252 totalLength+=line.length();
253 }
254 int halflength = totalLength/2;
255
256 if (length>halflength) {
257 x = (halflength - (length-halflength))/halflength;
258 y = 1.0;
259 } else {
260 x = length/halflength;
261 y = 0.0;
262 }
263 }
264 }
265 else {
266 x = (coordinate.x()-offset)/(width()-offset*2);
267 y = 1.0 - (coordinate.y()-offset)/(height()-offset*2);
268 }
269 x = qBound((qreal)0.0, x, (qreal)1.0);
270 y = qBound((qreal)0.0, y, (qreal)1.0);
271 return QPointF(x, y);
272}
273
275{
276 QRegion mask = QRegion(0,0,width(),height());
278 mask = mask.subtracted(QRegion(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2)));
279 }
280 return mask;
281}
282
284{
285 // Hi-DPI aware rendering requires that we determine the device pixel dimension;
286 // actual widget size in device pixels is not accessible unfortunately, it might be 1px smaller...
287 const int deviceWidth = qCeil(width() * devicePixelRatioF());
288 const int deviceHeight = qCeil(height() * devicePixelRatioF());
289
290 QImage alphaMask(deviceWidth, deviceHeight, QImage::Format_Alpha8);
291 alphaMask.fill(0);
292 alphaMask.setDevicePixelRatio(devicePixelRatioF());
293 QPainter painter(&alphaMask);
294 painter.setRenderHint(QPainter::Antialiasing);
295 painter.setBrush(Qt::white);
296 painter.setPen(Qt::NoPen);
297
298 if (getDimensions() == onedimensional) {
300 painter.drawRect(2, 3, width() - 4, height() - 6);
302 painter.drawRect(3, 2, width() - 6, height() - 4);
303 } else /*if (m_type == border || m_type == borderMirrored)*/ {
304 painter.drawRect(2, 2, width() - 4, height() - 4);
305 painter.setBrush(Qt::black);
306 painter.drawRect(m_barWidth, m_barWidth, width() - 2 * m_barWidth, height() - 2 * m_barWidth);
307 }
308 } else {
309 painter.drawRect(3, 3, width() - 6, height() - 6);
310 }
311
312 return alphaMask;
313}
314
316{
317 //qDebug() << this << "KisVisualRectangleSelectorShape::drawCursor: image needs update" << imagesNeedUpdate();
320 QBrush fill(Qt::SolidPattern);
321
322 int cursorwidth = 5;
323
327 QRectF rect;
329 qreal y = qRound(cursorPoint.y());
330 rect.setCoords(1.5, y - cursorwidth + 0.5, width() - 1.5, y + cursorwidth - 0.5);
331 } else {
332 qreal x = qRound(cursorPoint.x());
333 rect.setCoords(x - cursorwidth + 0.5, 1.5, x + cursorwidth - 0.5, height() - 1.5);
334 }
335 painter.setPen(Qt::white);
336 fill.setColor(Qt::white);
337 painter.setBrush(fill);
338 painter.drawRect(rect);
339 fill.setColor(col);
340 painter.setPen(Qt::black);
341 painter.setBrush(fill);
342 painter.drawRect(rect.adjusted(1, 1, -1, -1));
343
345 QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2));
346 painter.setPen(Qt::white);
347 fill.setColor(Qt::white);
348 painter.setBrush(fill);
349 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth);
350 QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y());
351 painter.drawEllipse(mirror, cursorwidth, cursorwidth);
352 fill.setColor(col);
353 painter.setPen(Qt::black);
354 painter.setBrush(fill);
355 painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1);
356 painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1);
357
358 } else {
359 painter.setPen(Qt::white);
360 fill.setColor(Qt::white);
361 painter.setBrush(fill);
362 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth);
363 fill.setColor(col);
364 painter.setPen(Qt::black);
365 painter.setBrush(fill);
366 painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0);
367 }
368}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
The KisVisualColorSelectorShape class A 2d widget can represent at maximum 2 coordinates....
void forceImageUpdate()
forceImageUpdate force the image to recache.
QPointF getCursorPosition() const
getCursorPosition
QColor getColorFromConverter(KoColor c)
getColorFromConverter
Dimensions getDimensions() const
getDimensions
Dimensions
The Dimensions enum Whether or not the shape is single or two dimensional.
The KisVisualColorSelector class.
void setBorderWidth(int width) override
setBorderWidth set the border of the single dimensional selector.
QRect getSpaceForSquare(QRect geom) override
getSpaceForSquare
QRect getAvailableSpace(QRect geom, bool stretch)
QImage renderAlphaMask() const override
render the alpha mask for the widget background the returned image is expected to be QImage::Format_A...
QPointF convertWidgetCoordinateToShapeCoordinate(QPointF coordinate) const override
convertWidgetCoordinateToShapeCoordinate Convert a coordinate in the widget's height/width to a shape...
KisVisualRectangleSelectorShape(KisVisualColorSelector *parent, Dimensions dimension, int channel1, int channel2, int width=20, KisVisualRectangleSelectorShape::singelDTypes d=KisVisualRectangleSelectorShape::vertical)
QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const override
convertShapeCoordinateToWidgetCoordinate