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...
289 return QImage();
290 }
291 qreal startRatio = 0.0;
292 qreal endRatio = 1.0;
293
295 startRatio = 0.25;
296 }
297
298 return renderAlphaMaskImpl(startRatio, endRatio);
299}
300
302{
303 // Hi-DPI aware rendering requires that we determine the device pixel dimension;
304 // actual widget size in device pixels is not accessible unfortunately, it might be 1px smaller...
307 return QImage();
308 }
309 qreal startRatio = 0.0;
310 qreal endRatio = 1.0;
311
313 endRatio = 0.25;
314 }
315
316 return renderAlphaMaskImpl(startRatio, endRatio);
317}
318
319QImage KisVisualRectangleSelectorShape::renderAlphaMaskImpl(qreal ratioStart, qreal ratioEnd) const
320{
321 // Hi-DPI aware rendering requires that we determine the device pixel dimension;
322 // actual widget size in device pixels is not accessible unfortunately, it might be 1px smaller...
323 const int deviceWidth = qCeil(width() * devicePixelRatioF());
324 const int deviceHeight = qCeil(height() * devicePixelRatioF());
325
326 QImage alphaMask(deviceWidth, deviceHeight, QImage::Format_Alpha8);
327 alphaMask.fill(0);
328 alphaMask.setDevicePixelRatio(devicePixelRatioF());
329 QPainter painter(&alphaMask);
330 painter.setRenderHint(QPainter::Antialiasing);
331 painter.setBrush(Qt::white);
332 painter.setPen(Qt::NoPen);
333
334 const int marginMajor = 3;
335 const int marginMinor = 2;
336
337 if (getDimensions() == onedimensional) {
339 const int barWidth = width() - (marginMinor*2);
340 const int start = (barWidth*ratioStart);
341 const int end = (barWidth*ratioEnd) - start;
342 painter.drawRect(start + marginMinor, marginMajor, end, height() - (2*marginMajor));
343
345 const int barWidth = height() - (marginMinor*2);
346 const int start = (barWidth*ratioStart);
347 const int end = (barWidth*ratioEnd) - start;
348 painter.drawRect(marginMajor, start + marginMinor, width() - (2*marginMajor), end);
349
350 } else /*if (m_type == border || m_type == borderMirrored)*/ {
351 painter.drawRect(2, 2, width() - 4, height() - 4);
352 painter.setBrush(Qt::black);
353 painter.drawRect(m_barWidth, m_barWidth, width() - 2 * m_barWidth, height() - 2 * m_barWidth);
354 }
355 } else {
356 painter.drawRect(marginMajor, marginMajor, width() - marginMajor*2, height() - marginMajor*2);
357 }
358
359 return alphaMask;
360}
361
363{
364 //qDebug() << this << "KisVisualRectangleSelectorShape::drawCursor: image needs update" << imagesNeedUpdate();
367 QBrush fill(Qt::SolidPattern);
368
369 int cursorwidth = 5;
370
374 QRectF rect;
376 qreal y = qRound(cursorPoint.y());
377 rect.setCoords(1.5, y - cursorwidth + 0.5, width() - 1.5, y + cursorwidth - 0.5);
378 } else {
379 qreal x = qRound(cursorPoint.x());
380 rect.setCoords(x - cursorwidth + 0.5, 1.5, x + cursorwidth - 0.5, height() - 1.5);
381 }
382 painter.setPen(Qt::white);
383 fill.setColor(Qt::white);
384 painter.setBrush(fill);
385 painter.drawRect(rect);
386 fill.setColor(col);
387 painter.setPen(Qt::black);
388 painter.setBrush(fill);
389 painter.drawRect(rect.adjusted(1, 1, -1, -1));
390
392 QRectF innerRect(m_barWidth, m_barWidth, width()-(m_barWidth*2), height()-(m_barWidth*2));
393 painter.setPen(Qt::white);
394 fill.setColor(Qt::white);
395 painter.setBrush(fill);
396 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth);
397 QPoint mirror(innerRect.center().x()+(innerRect.center().x()-cursorPoint.x()),cursorPoint.y());
398 painter.drawEllipse(mirror, cursorwidth, cursorwidth);
399 fill.setColor(col);
400 painter.setPen(Qt::black);
401 painter.setBrush(fill);
402 painter.drawEllipse(cursorPoint, cursorwidth-1, cursorwidth-1);
403 painter.drawEllipse(mirror, cursorwidth-1, cursorwidth-1);
404
405 } else {
406 painter.setPen(Qt::white);
407 fill.setColor(Qt::white);
408 painter.setBrush(fill);
409 painter.drawEllipse(cursorPoint, cursorwidth, cursorwidth);
410 fill.setColor(col);
411 painter.setPen(Qt::black);
412 painter.setBrush(fill);
413 painter.drawEllipse(cursorPoint, cursorwidth-1.0, cursorwidth-1.0);
414 }
415}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
The KisVisualColorSelectorShape class A 2d widget can represent at maximum 2 coordinates....
KisVisualColorSelector * colorSelector() const
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...
QImage renderAlphaMaskImpl(qreal ratioStart, qreal ratioEnd) const
KisVisualRectangleSelectorShape(KisVisualColorSelector *parent, Dimensions dimension, int channel1, int channel2, int width=20, KisVisualRectangleSelectorShape::singelDTypes d=KisVisualRectangleSelectorShape::vertical)
QPointF convertShapeCoordinateToWidgetCoordinate(QPointF coordinate) const override
convertShapeCoordinateToWidgetCoordinate