1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtcolorline.h"
5#include "qdrawutil.h"
6
7#include <QtGui/QPainter>
8#include <QtGui/QPaintEvent>
9#include <QtWidgets/QStyleOption>
10#include <QtGui/QRegion>
11
12QT_BEGIN_NAMESPACE
13
14class QtColorLinePrivate
15{
16 QtColorLine *q_ptr;
17 Q_DECLARE_PUBLIC(QtColorLine)
18public:
19 QtColorLinePrivate();
20
21 QColor color() const;
22 void setColor(const QColor &color);
23
24 QtColorLine::ColorComponent colorComponent() const;
25 void setColorComponent(QtColorLine::ColorComponent component);
26
27 void setIndicatorSize(int size);
28 int indicatorSize() const;
29
30 void setIndicatorSpace(int space);
31 int indicatorSpace() const;
32
33 void setFlip(bool flip);
34 bool flip() const;
35
36 void setBackgroundCheckered(bool checkered);
37 bool isBackgroundCheckered() const;
38
39 void setOrientation(Qt::Orientation orientation);
40 Qt::Orientation orientation() const;
41
42 void resizeEvent(QResizeEvent *event);
43 void paintEvent(QPaintEvent *event);
44 void mousePressEvent(QMouseEvent *event);
45 void mouseMoveEvent(QMouseEvent *event);
46 void mouseReleaseEvent(QMouseEvent *event);
47 void mouseDoubleClickEvent(QMouseEvent *event);
48private:
49 void checkColor();
50 bool isMainPixmapValid() const;
51 void validate();
52 void recreateMainPixmap();
53 QSize pixmapSizeFromGeometrySize(const QSize &geometrySize) const;
54 QPixmap gradientPixmap(int size, Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped = false) const;
55 QPixmap gradientPixmap(Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped = false) const;
56 QPixmap hueGradientPixmap(int size, Qt::Orientation orientation, bool flipped = false,
57 int saturation = 0xFF, int value = 0xFF, int alpha = 0xFF) const;
58 QPixmap hueGradientPixmap(Qt::Orientation orientation, bool flipped = false,
59 int saturation = 0xFF, int value = 0xFF, int alpha = 0xFF) const;
60
61 QList<QRect> rects(const QPointF &point) const;
62
63 QColor colorFromPoint(const QPointF &point) const;
64 QPointF pointFromColor(const QColor &color) const;
65
66 QColor m_color;
67 QtColorLine::ColorComponent m_component;
68 bool m_flipped;
69 bool m_backgroundCheckered;
70 Qt::Orientation m_orientation;
71 bool m_dragging;
72 bool m_combiningAlpha;
73 int m_indicatorSize;
74 int m_indicatorSpace;
75 QPointF m_point;
76 QPoint m_clickOffset;
77
78 QPixmap m_mainPixmap;
79 QPixmap m_alphalessPixmap;
80 QPixmap m_semiAlphaPixmap;
81 QSize m_pixmapSize;
82
83 struct PixData {
84 QSize size;
85 QColor color;
86 QtColorLine::ColorComponent component;
87 bool flipped;
88 Qt::Orientation orientation;
89 };
90
91 PixData m_lastValidMainPixmapData;
92};
93
94QtColorLinePrivate::QtColorLinePrivate()
95 : m_color(Qt::black), m_component(QtColorLine::Value),
96 m_flipped(false), m_backgroundCheckered(true), m_orientation(Qt::Horizontal), m_dragging(false), m_combiningAlpha(false)
97{
98 m_indicatorSize = 22;
99 m_indicatorSpace = 0;
100 m_pixmapSize = QSize(0, 0);
101 m_point = pointFromColor(color: m_color);
102}
103
104void QtColorLinePrivate::setColor(const QColor &color)
105{
106 if (m_color == color)
107 return;
108 if (!color.isValid())
109 return;
110 if (m_dragging) // Warning perhaps here, recursive call
111 return;
112 m_color = color;
113 checkColor();
114 m_point = pointFromColor(color: m_color);
115 q_ptr->update();
116}
117
118QColor QtColorLinePrivate::color() const
119{
120 return m_color;
121}
122
123void QtColorLinePrivate::setColorComponent(QtColorLine::ColorComponent component)
124{
125 if (m_component == component)
126 return;
127 if (m_dragging) // Warning perhaps here, recursive call
128 return;
129 m_component = component;
130 checkColor();
131 m_point = pointFromColor(color: m_color);
132 q_ptr->update();
133}
134
135QtColorLine::ColorComponent QtColorLinePrivate::colorComponent() const
136{
137 return m_component;
138}
139
140void QtColorLinePrivate::setIndicatorSize(int size)
141{
142 if (size <= 0)
143 return;
144 if (m_dragging) // Warning perhaps here, recursive call
145 return;
146 if (m_indicatorSize == size)
147 return;
148 m_indicatorSize = size;
149 m_pixmapSize = pixmapSizeFromGeometrySize(geometrySize: q_ptr->contentsRect().size());
150 q_ptr->update();
151 q_ptr->updateGeometry();
152}
153
154int QtColorLinePrivate::indicatorSize() const
155{
156 return m_indicatorSize;
157}
158
159void QtColorLinePrivate::setIndicatorSpace(int space)
160{
161 if (space < 0)
162 return;
163 if (m_dragging) // Warning perhaps here, recursive call
164 return;
165 if (m_indicatorSpace == space)
166 return;
167 m_indicatorSpace = space;
168 m_pixmapSize = pixmapSizeFromGeometrySize(geometrySize: q_ptr->contentsRect().size());
169 q_ptr->update();
170}
171
172int QtColorLinePrivate::indicatorSpace() const
173{
174 return m_indicatorSpace;
175}
176
177void QtColorLinePrivate::setFlip(bool flip)
178{
179 if (m_dragging) // Warning perhaps here, recursive call
180 return;
181 if (m_flipped == flip)
182 return;
183 m_flipped = flip;
184 m_point = pointFromColor(color: m_color);
185 q_ptr->update();
186}
187
188bool QtColorLinePrivate::flip() const
189{
190 return m_flipped;
191}
192
193void QtColorLinePrivate::setBackgroundCheckered(bool checkered)
194{
195 if (m_backgroundCheckered == checkered)
196 return;
197 m_backgroundCheckered = checkered;
198 q_ptr->update();
199}
200
201bool QtColorLinePrivate::isBackgroundCheckered() const
202{
203 return m_backgroundCheckered;
204}
205
206void QtColorLinePrivate::setOrientation(Qt::Orientation orientation)
207{
208 if (m_dragging) // Warning perhaps here, recursive call
209 return;
210 if (m_orientation == orientation)
211 return;
212
213 m_orientation = orientation;
214 if (!q_ptr->testAttribute(attribute: Qt::WA_WState_OwnSizePolicy)) {
215 QSizePolicy sp = q_ptr->sizePolicy();
216 sp.transpose();
217 q_ptr->setSizePolicy(sp);
218 q_ptr->setAttribute(Qt::WA_WState_OwnSizePolicy, on: false);
219 }
220 m_point = pointFromColor(color: m_color);
221 q_ptr->update();
222 q_ptr->updateGeometry();
223}
224
225Qt::Orientation QtColorLinePrivate::orientation() const
226{
227 return m_orientation;
228}
229
230void QtColorLinePrivate::checkColor()
231{
232 switch (m_component) {
233 case QtColorLine::Red:
234 case QtColorLine::Green:
235 case QtColorLine::Blue:
236 if (m_color.spec() != QColor::Rgb)
237 m_color = m_color.toRgb();
238 break;
239 case QtColorLine::Hue:
240 case QtColorLine::Saturation:
241 case QtColorLine::Value:
242 if (m_color.spec() != QColor::Hsv)
243 m_color = m_color.toHsv();
244 break;
245 default:
246 break;
247 }
248 if (m_color.spec() == QColor::Hsv) {
249 if (m_color.hue() == 360 || m_color.hue() == -1) {
250 m_color.setHsvF(h: 0.0, s: m_color.saturationF(), v: m_color.valueF(), a: m_color.alphaF());
251 }
252 }
253}
254
255bool QtColorLinePrivate::isMainPixmapValid() const
256{
257 if (m_mainPixmap.isNull()) {
258 if (m_pixmapSize.isEmpty())
259 return true;
260 else
261 return false;
262 }
263 if (m_lastValidMainPixmapData.component != m_component)
264 return false;
265 if (m_lastValidMainPixmapData.size != m_pixmapSize)
266 return false;
267 if (m_lastValidMainPixmapData.flipped != m_flipped)
268 return false;
269 if (m_lastValidMainPixmapData.orientation != m_orientation)
270 return false;
271 if (m_lastValidMainPixmapData.color == m_color)
272 return true;
273 switch (m_component) {
274 case QtColorLine::Red:
275 if (m_color.green() == m_lastValidMainPixmapData.color.green() &&
276 m_color.blue() == m_lastValidMainPixmapData.color.blue() &&
277 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
278 return true;
279 break;
280 case QtColorLine::Green:
281 if (m_color.red() == m_lastValidMainPixmapData.color.red() &&
282 m_color.blue() == m_lastValidMainPixmapData.color.blue() &&
283 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
284 return true;
285 break;
286 case QtColorLine::Blue:
287 if (m_color.red() == m_lastValidMainPixmapData.color.red() &&
288 m_color.green() == m_lastValidMainPixmapData.color.green() &&
289 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
290 return true;
291 break;
292 case QtColorLine::Hue:
293 if (m_color.saturation() == m_lastValidMainPixmapData.color.saturation() &&
294 m_color.value() == m_lastValidMainPixmapData.color.value() &&
295 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
296 return true;
297 break;
298 case QtColorLine::Saturation:
299 if (m_color.hue() == m_lastValidMainPixmapData.color.hue() &&
300 m_color.value() == m_lastValidMainPixmapData.color.value() &&
301 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
302 return true;
303 break;
304 case QtColorLine::Value:
305 if (m_color.hue() == m_lastValidMainPixmapData.color.hue() &&
306 m_color.saturation() == m_lastValidMainPixmapData.color.saturation() &&
307 (!m_combiningAlpha || m_color.alpha() == m_lastValidMainPixmapData.color.alpha()))
308 return true;
309 break;
310 case QtColorLine::Alpha:
311 if (m_color.hue() == m_lastValidMainPixmapData.color.hue() &&
312 m_color.saturation() == m_lastValidMainPixmapData.color.saturation() &&
313 m_color.value() == m_lastValidMainPixmapData.color.value())
314 return true;
315 }
316 return false;
317}
318
319void QtColorLinePrivate::validate()
320{
321 if (isMainPixmapValid())
322 return;
323
324 recreateMainPixmap();
325}
326
327QPixmap QtColorLinePrivate::gradientPixmap(Qt::Orientation orientation, const QColor &begin, const QColor &end, bool flipped) const
328{
329 int size = m_pixmapSize.width();
330 if (orientation == Qt::Vertical)
331 size = m_pixmapSize.height();
332 return gradientPixmap(size, orientation, begin, end, flipped);
333}
334
335QPixmap QtColorLinePrivate::gradientPixmap(int size, Qt::Orientation orientation,
336 const QColor &begin, const QColor &end, bool flipped) const
337{
338 int gradW = size;
339 int gradH = size;
340 int w = size;
341 int h = size;
342 if (orientation == Qt::Horizontal) {
343 gradH = 0;
344 h = 1;
345 } else {
346 gradW = 0;
347 w = 1;
348 }
349 QColor c1 = begin;
350 QColor c2 = end;
351 if (flipped) {
352 c1 = end;
353 c2 = begin;
354 }
355 QLinearGradient lg(0, 0, gradW, gradH);
356 lg.setColorAt(pos: 0, color: c1);
357 lg.setColorAt(pos: 1, color: c2);
358 QImage img(w, h, QImage::Format_ARGB32);
359 QPainter p(&img);
360 p.setCompositionMode(QPainter::CompositionMode_Source);
361 p.fillRect(QRect(0, 0, w, h), lg);
362 return QPixmap::fromImage(image: img);
363}
364
365QPixmap QtColorLinePrivate::hueGradientPixmap(Qt::Orientation orientation, bool flipped,
366 int saturation, int value, int alpha) const
367{
368 int size = m_pixmapSize.width();
369 if (orientation == Qt::Vertical)
370 size = m_pixmapSize.height();
371 return hueGradientPixmap(size, orientation, flipped, saturation, value, alpha);
372}
373
374QPixmap QtColorLinePrivate::hueGradientPixmap(int size, Qt::Orientation orientation, bool flipped,
375 int saturation, int value, int alpha) const
376{
377 int gradW = size + 1;
378 int gradH = size + 1;
379 int w = size;
380 int h = size;
381 if (orientation == Qt::Horizontal) {
382 gradH = 0;
383 h = 1;
384 } else {
385 gradW = 0;
386 w = 1;
387 }
388 QList<QColor> colorList;
389 colorList << QColor::fromHsv(h: 0, s: saturation, v: value, a: alpha);
390 colorList << QColor::fromHsv(h: 60, s: saturation, v: value, a: alpha);
391 colorList << QColor::fromHsv(h: 120, s: saturation, v: value, a: alpha);
392 colorList << QColor::fromHsv(h: 180, s: saturation, v: value, a: alpha);
393 colorList << QColor::fromHsv(h: 240, s: saturation, v: value, a: alpha);
394 colorList << QColor::fromHsv(h: 300, s: saturation, v: value, a: alpha);
395 colorList << QColor::fromHsv(h: 0, s: saturation, v: value, a: alpha);
396 QLinearGradient lg(0, 0, gradW, gradH);
397 for (int i = 0; i <= 6; i++)
398 lg.setColorAt(pos: double(i) / 6.0, color: flipped ? colorList.at(i: 6 - i) : colorList.at(i));
399 QImage img(w, h, QImage::Format_ARGB32);
400 QPainter p(&img);
401 p.setCompositionMode(QPainter::CompositionMode_Source);
402 p.fillRect(QRect(0, 0, w, h), lg);
403 return QPixmap::fromImage(image: img);
404}
405
406void QtColorLinePrivate::recreateMainPixmap()
407{
408 m_lastValidMainPixmapData.size = m_pixmapSize;
409 m_lastValidMainPixmapData.component = m_component;
410 m_lastValidMainPixmapData.color = m_color;
411 m_lastValidMainPixmapData.flipped = m_flipped;
412 m_lastValidMainPixmapData.orientation = m_orientation;
413
414 if (m_pixmapSize.isEmpty()) {
415 m_mainPixmap = QPixmap();
416 m_alphalessPixmap = QPixmap();
417 m_semiAlphaPixmap = QPixmap();
418 return;
419 }
420
421 if (m_mainPixmap.size() != m_pixmapSize) {
422 m_mainPixmap = QPixmap(m_pixmapSize);
423 m_alphalessPixmap = QPixmap(m_pixmapSize);
424 m_semiAlphaPixmap = QPixmap(m_pixmapSize);
425 }
426
427 Qt::Orientation orient = m_orientation;
428 const bool flip = m_flipped;
429
430 const int r = m_color.red();
431 const int g = m_color.green();
432 const int b = m_color.blue();
433 const int h = m_color.hue();
434 const int s = m_color.saturation();
435 const int v = m_color.value();
436 const int a = m_color.alpha();
437 const double coef = 0.5;
438 const int semi = qRound(d: a * coef + 0xFF * (1.0 - coef));
439
440 if (m_component == QtColorLine::Hue) {
441 m_alphalessPixmap = hueGradientPixmap(orientation: orient, flipped: flip, saturation: s, value: v, alpha: 0xFF);
442 if (m_combiningAlpha) {
443 m_mainPixmap = hueGradientPixmap(orientation: orient, flipped: flip, saturation: s, value: v, alpha: a);
444 m_semiAlphaPixmap = hueGradientPixmap(orientation: orient, flipped: flip, saturation: s, value: v, alpha: semi);
445 }
446 } else if (m_component == QtColorLine::Saturation) {
447 m_alphalessPixmap = gradientPixmap(orientation: orient, begin: QColor::fromHsv(h, s: 0, v, a: 0xFF), end: QColor::fromHsv(h, s: 0xFF, v, a: 0xFF), flipped: flip);
448 if (m_combiningAlpha) {
449 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromHsv(h, s: 0, v, a), end: QColor::fromHsv(h, s: 0xFF, v, a), flipped: flip);
450 m_semiAlphaPixmap = gradientPixmap(orientation: orient, begin: QColor::fromHsv(h, s: 0, v, a: semi), end: QColor::fromHsv(h, s: 0xFF, v, a: semi), flipped: flip);
451 }
452 } else if (m_component == QtColorLine::Value) {
453 m_alphalessPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g: 0, b: 0, a: 0xFF), end: QColor::fromHsv(h, s, v: 0xFF, a: 0xFF), flipped: flip);
454 if (m_combiningAlpha) {
455 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g: 0, b: 0, a), end: QColor::fromHsv(h, s, v: 0xFF, a), flipped: flip);
456 m_semiAlphaPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g: 0, b: 0, a: semi), end: QColor::fromHsv(h, s, v: 0xFF, a: semi), flipped: flip);
457 }
458 } else if (m_component == QtColorLine::Red) {
459 m_alphalessPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g, b, a: 0xFF), end: QColor::fromRgb(r: 0xFF, g, b, a: 0xFF), flipped: flip);
460 if (m_combiningAlpha) {
461 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g, b, a), end: QColor::fromRgb(r: 0xFF, g, b, a), flipped: flip);
462 m_semiAlphaPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r: 0, g, b, a: semi), end: QColor::fromRgb(r: 0xFF, g, b, a: semi), flipped: flip);
463 }
464 } else if (m_component == QtColorLine::Green) {
465 m_alphalessPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g: 0, b, a: 0xFF), end: QColor::fromRgb(r, g: 0xFF, b, a: 0xFF), flipped: flip);
466 if (m_combiningAlpha) {
467 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g: 0, b, a), end: QColor::fromRgb(r, g: 0xFF, b, a), flipped: flip);
468 m_semiAlphaPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g: 0, b, a: semi), end: QColor::fromRgb(r, g: 0xFF, b, a: semi), flipped: flip);
469 }
470 } else if (m_component == QtColorLine::Blue) {
471 m_alphalessPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g, b: 0, a: 0xFF), end: QColor::fromRgb(r, g, b: 0xFF, a: 0xFF), flipped: flip);
472 if (m_combiningAlpha) {
473 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g, b: 0, a), end: QColor::fromRgb(r, g, b: 0xFF, a), flipped: flip);
474 m_semiAlphaPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g, b: 0, a: semi), end: QColor::fromRgb(r, g, b: 0xFF, a: semi), flipped: flip);
475 }
476 } else if (m_component == QtColorLine::Alpha) {
477 m_mainPixmap = gradientPixmap(orientation: orient, begin: QColor::fromRgb(r, g, b, a: 0), end: QColor::fromRgb(r, g, b, a: 0xFF), flipped: flip);
478
479// m_alphalessPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, b, 0xFF), QColor::fromRgb(r, g, b, 0xFF), flip);
480// m_semiAlphaPixmap = gradientPixmap(orient, QColor::fromRgb(r, g, b, semi), QColor::fromRgb(r, g, b, semi), flip);
481 }
482 if (!m_combiningAlpha && m_component != QtColorLine::Alpha)
483 m_mainPixmap = m_alphalessPixmap;
484}
485
486QSize QtColorLinePrivate::pixmapSizeFromGeometrySize(
487 const QSize &geometrySize) const
488{
489 QSize size(m_indicatorSize + 2 * m_indicatorSpace - 1,
490 m_indicatorSize + 2 * m_indicatorSpace - 1);
491 if (m_orientation == Qt::Horizontal)
492 size.setHeight(0);
493 else
494 size.setWidth(0);
495 return geometrySize - size;
496}
497
498QColor QtColorLinePrivate::colorFromPoint(const QPointF &point) const
499{
500 QPointF p = point;
501 if (p.x() < 0)
502 p.setX(0.0);
503 else if (p.x() > 1)
504 p.setX(1.0);
505 if (p.y() < 0)
506 p.setY(0.0);
507 else if (p.y() > 1)
508 p.setY(1.0);
509
510 double pos = p.x();
511 if (m_orientation == Qt::Vertical)
512 pos = p.y();
513 if (m_flipped)
514 pos = 1.0 - pos;
515 QColor c;
516 qreal hue;
517 switch (m_component) {
518 case QtColorLine::Red:
519 c.setRgbF(r: pos, g: m_color.greenF(), b: m_color.blueF(), a: m_color.alphaF());
520 break;
521 case QtColorLine::Green:
522 c.setRgbF(r: m_color.redF(), g: pos, b: m_color.blueF(), a: m_color.alphaF());
523 break;
524 case QtColorLine::Blue:
525 c.setRgbF(r: m_color.redF(), g: m_color.greenF(), b: pos, a: m_color.alphaF());
526 break;
527 case QtColorLine::Hue:
528 hue = pos;
529 hue *= 35999.0 / 36000.0;
530 c.setHsvF(h: hue, s: m_color.saturationF(), v: m_color.valueF(), a: m_color.alphaF());
531 break;
532 case QtColorLine::Saturation:
533 c.setHsvF(h: m_color.hueF(), s: pos, v: m_color.valueF(), a: m_color.alphaF());
534 break;
535 case QtColorLine::Value:
536 c.setHsvF(h: m_color.hueF(), s: m_color.saturationF(), v: pos, a: m_color.alphaF());
537 break;
538 case QtColorLine::Alpha:
539 c.setHsvF(h: m_color.hueF(), s: m_color.saturationF(), v: m_color.valueF(), a: pos);
540 break;
541 }
542 return c;
543}
544
545QPointF QtColorLinePrivate::pointFromColor(const QColor &color) const
546{
547 qreal hue = color.hueF();
548 if (color.hue() == 360)
549 hue = 0.0;
550 else
551 hue *= 36000.0 / 35999.0;
552
553 double pos = 0.0;
554 switch (m_component) {
555 case QtColorLine::Red:
556 pos = color.redF();
557 break;
558 case QtColorLine::Green:
559 pos = color.greenF();
560 break;
561 case QtColorLine::Blue:
562 pos = color.blueF();
563 break;
564 case QtColorLine::Hue:
565 pos = hue;
566 break;
567 case QtColorLine::Saturation:
568 pos = color.saturationF();
569 break;
570 case QtColorLine::Value:
571 pos = color.valueF();
572 break;
573 case QtColorLine::Alpha:
574 pos = color.alphaF();
575 break;
576 }
577 if (m_flipped)
578 pos = 1.0 - pos;
579 QPointF p(pos, pos);
580 if (m_orientation == Qt::Horizontal)
581 p.setY(0);
582 else
583 p.setX(0);
584 return p;
585}
586
587QList<QRect> QtColorLinePrivate::rects(const QPointF &point) const
588{
589 QRect r = q_ptr->geometry();
590 r.moveTo(ax: 0, ay: 0);
591
592 int x1 = (int)((r.width() - m_indicatorSize - 2 * m_indicatorSpace) * point.x() + 0.5);
593 int x2 = x1 + m_indicatorSize + 2 * m_indicatorSpace;
594 int y1 = (int)((r.height() - m_indicatorSize - 2 * m_indicatorSpace) * point.y() + 0.5);
595 int y2 = y1 + m_indicatorSize + 2 * m_indicatorSpace;
596
597 QList<QRect> rects;
598 if (m_orientation == Qt::Horizontal) {
599 // r0 r1 r2
600 QRect r0(0, 0, x1, r.height());
601 QRect r1(x1 + m_indicatorSpace, 0, m_indicatorSize, r.height());
602 QRect r2(x2, 0, r.width() - x2, r.height());
603
604 rects << r0 << r1 << r2;
605 } else {
606 // r0
607 // r1
608 // r2
609 QRect r0(0, 0, r.width(), y1);
610 QRect r1(0, y1 + m_indicatorSpace, r.width(), m_indicatorSize);
611 QRect r2(0, y2, r.width(), r.height() - y2);
612
613 rects << r0 << r1 << r2;
614 }
615 return rects;
616}
617
618void QtColorLinePrivate::resizeEvent(QResizeEvent *event)
619{
620 m_pixmapSize = pixmapSizeFromGeometrySize(geometrySize: event->size());
621}
622
623void QtColorLinePrivate::paintEvent(QPaintEvent *)
624{
625 QRect rect = q_ptr->rect();
626
627 QList<QRect> r = rects(point: m_point);
628
629 QColor c = colorFromPoint(point: m_point);
630 if (!m_combiningAlpha && m_component != QtColorLine::Alpha)
631 c.setAlpha(0xFF);
632
633 QPainter p(q_ptr);
634 if (q_ptr->isEnabled()) {
635 if (m_backgroundCheckered) {
636 int pixSize = 20;
637 QPixmap pm(2 * pixSize, 2 * pixSize);
638 QPainter pmp(&pm);
639 pmp.fillRect(x: 0, y: 0, w: pixSize, h: pixSize, c: Qt::white);
640 pmp.fillRect(x: pixSize, y: pixSize, w: pixSize, h: pixSize, c: Qt::white);
641 pmp.fillRect(x: 0, y: pixSize, w: pixSize, h: pixSize, c: Qt::black);
642 pmp.fillRect(x: pixSize, y: 0, w: pixSize, h: pixSize, c: Qt::black);
643 pmp.end();
644
645 p.setBrushOrigin(x: (rect.width() % pixSize + pixSize) / 2, y: (rect.height() % pixSize + pixSize) / 2);
646
647 QRegion region(r[1].adjusted(xp1: 4, yp1: 4, xp2: -4, yp2: -4));
648 region += QRect(rect.topLeft(), QPoint(r[1].left() + 0, rect.bottom()));
649 region += QRect(QPoint(r[1].right() - 0, rect.top()), rect.bottomRight());
650 region += QRect(rect.topLeft(), QPoint(rect.right(), r[1].top() + 0));
651 region += QRect(QPoint(rect.left(), r[1].bottom() - 0), rect.bottomRight());
652 p.setClipRegion(region);
653 p.fillRect(rect, pm);
654 p.setBrushOrigin(x: 0, y: 0);
655 p.setClipping(false);
656 }
657
658 validate();
659
660 QSize fieldSize = pixmapSizeFromGeometrySize(geometrySize: q_ptr->geometry().size());
661
662 QPoint posOnField = r[1].topLeft() - QPoint(m_indicatorSpace, m_indicatorSpace);
663 int x = posOnField.x();
664 int y = posOnField.y();
665 int w = fieldSize.width();
666 int h = fieldSize.height();
667
668 QRect r0, r2;
669 if (m_orientation == Qt::Horizontal) {
670 r0 = QRect(0, 0, x, m_pixmapSize.height());
671 r2 = QRect(x + 1, 0, w - x - 1, m_pixmapSize.height());
672 } else {
673 r0 = QRect(0, 0, m_pixmapSize.width(), y);
674 r2 = QRect(0, y + 1, m_pixmapSize.width(), h - y - 1);
675 }
676
677 p.setBrush(m_mainPixmap);
678 p.setPen(Qt::NoPen);
679 if (r[0].isValid()) {
680 p.drawRect(r: r[0]);
681 }
682 if (r[2].isValid()) {
683 p.setBrushOrigin(r[2].topLeft() - r2.topLeft());
684 p.drawRect(r: r[2]);
685 }
686 if (m_indicatorSpace) {
687 p.setBrush(c);
688 if (m_orientation == Qt::Horizontal) {
689 p.drawRect(r: r[1].adjusted(xp1: -m_indicatorSpace, yp1: 0, xp2: -r[1].width(), yp2: 0));
690 p.drawRect(r: r[1].adjusted(xp1: r[1].width(), yp1: 0, xp2: m_indicatorSpace, yp2: 0));
691 } else {
692 p.drawRect(r: r[1].adjusted(xp1: 0, yp1: -m_indicatorSpace, xp2: 0, yp2: -r[1].height()));
693 p.drawRect(r: r[1].adjusted(xp1: 0, yp1: r[1].height(), xp2: 0, yp2: m_indicatorSpace));
694 }
695 }
696
697 QPen pen(c);
698 p.setPen(pen);
699 p.setBrush(Qt::NoBrush);
700 if (r[1].isValid()) {
701 p.drawRect(r: r[1].adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
702 // p.drawRect(r[1].adjusted(1, 1, -2, -2));
703 }
704 double coef = 9.0 / 10;
705 p.setPen(Qt::NoPen);
706 if (m_component != QtColorLine::Alpha && m_combiningAlpha) {
707 p.setBrush(m_alphalessPixmap);
708 if (r[0].isValid()) {
709 p.setBrushOrigin(QPoint(0, 0));
710 QRect thinRect1 = r[0];
711 QRect thinRect2 = r[0];
712 QRect thinRect = r[0];
713 if (m_orientation == Qt::Horizontal) {
714 thinRect1.adjust(dx1: 0, dy1: qRound(d: thinRect1.height() * coef), dx2: 0, dy2: 0);
715 thinRect2.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -qRound(d: thinRect2.height() * coef));
716 thinRect.adjust(dx1: 0, dy1: qRound(d: thinRect.height() * coef), dx2: 0, dy2: -qRound(d: thinRect.height() * coef));
717 } else {
718 thinRect1.adjust(dx1: qRound(d: thinRect1.width() * coef), dy1: 0, dx2: 0, dy2: 0);
719 thinRect2.adjust(dx1: 0, dy1: 0, dx2: -qRound(d: thinRect2.width() * coef), dy2: 0);
720 thinRect.adjust(dx1: qRound(d: thinRect.width() * coef), dy1: 0, dx2: -qRound(d: thinRect.width() * coef), dy2: 0);
721 }
722 p.drawRect(r: thinRect1);
723 p.drawRect(r: thinRect2);
724 //p.drawRect(thinRect);
725 }
726 if (r[2].isValid()) {
727 p.setBrushOrigin(r[2].topLeft() - r2.topLeft());
728 QRect thinRect1 = r[2];
729 QRect thinRect2 = r[2];
730 QRect thinRect = r[2];
731 if (m_orientation == Qt::Horizontal) {
732 thinRect1.adjust(dx1: 0, dy1: qRound(d: thinRect1.height() * coef), dx2: 0, dy2: 0);
733 thinRect2.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -qRound(d: thinRect2.height() * coef));
734 thinRect.adjust(dx1: 0, dy1: qRound(d: thinRect.height() * coef), dx2: 0, dy2: -qRound(d: thinRect.height() * coef));
735 } else {
736 thinRect1.adjust(dx1: qRound(d: thinRect1.width() * coef), dy1: 0, dx2: 0, dy2: 0);
737 thinRect2.adjust(dx1: 0, dy1: 0, dx2: -qRound(d: thinRect2.width() * coef), dy2: 0);
738 thinRect.adjust(dx1: qRound(d: thinRect.width() * coef), dy1: 0, dx2: -qRound(d: thinRect.width() * coef), dy2: 0);
739 }
740 p.drawRect(r: thinRect1);
741 p.drawRect(r: thinRect2);
742 //p.drawRect(thinRect);
743 }
744 /*
745
746*/
747
748
749
750
751
752 p.setPen(Qt::NoPen);
753
754 p.setBrush(m_semiAlphaPixmap);
755 if (r[0].isValid()) {
756 p.setBrushOrigin(QPoint(0, 0));
757 QRect thinRect1 = r[0];
758 QRect thinRect2 = r[0];
759 QRect thinRect = r[0];
760 if (m_orientation == Qt::Horizontal) {
761 thinRect1.adjust(dx1: 0, dy1: qRound(d: thinRect1.height() * coef) - 1, dx2: 0, dy2: 0);
762 thinRect1.setBottom(thinRect1.top());
763 thinRect2.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -qRound(d: thinRect2.height() * coef) + 1);
764 thinRect2.setTop(thinRect2.bottom());
765 thinRect.adjust(dx1: 0, dy1: qRound(d: thinRect.height() * coef), dx2: 0, dy2: -qRound(d: thinRect.height() * coef));
766 } else {
767 thinRect1.adjust(dx1: qRound(d: thinRect1.width() * coef) - 1, dy1: 0, dx2: 0, dy2: 0);
768 thinRect1.setRight(thinRect1.left());
769 thinRect2.adjust(dx1: 0, dy1: 0, dx2: -qRound(d: thinRect2.width() * coef) + 1, dy2: 0);
770 thinRect2.setLeft(thinRect2.right());
771 thinRect.adjust(dx1: qRound(d: thinRect.width() * coef), dy1: 0, dx2: -qRound(d: thinRect.width() * coef), dy2: 0);
772 }
773 p.drawRect(r: thinRect1);
774 p.drawRect(r: thinRect2);
775 //p.drawRect(thinRect);
776 }
777 if (r[2].isValid()) {
778 p.setBrushOrigin(r[2].topLeft() - r2.topLeft());
779 QRect thinRect1 = r[2];
780 QRect thinRect2 = r[2];
781 QRect thinRect = r[2];
782 if (m_orientation == Qt::Horizontal) {
783 thinRect1.adjust(dx1: 0, dy1: qRound(d: thinRect1.height() * coef) - 1, dx2: 0, dy2: 0);
784 thinRect1.setBottom(thinRect1.top());
785 thinRect2.adjust(dx1: 0, dy1: 0, dx2: 0, dy2: -qRound(d: thinRect2.height() * coef) + 1);
786 thinRect2.setTop(thinRect2.bottom());
787 thinRect.adjust(dx1: 0, dy1: qRound(d: thinRect.height() * coef), dx2: 0, dy2: -qRound(d: thinRect.height() * coef));
788 } else {
789 thinRect1.adjust(dx1: qRound(d: thinRect1.width() * coef) - 1, dy1: 0, dx2: 0, dy2: 0);
790 thinRect1.setRight(thinRect1.left());
791 thinRect2.adjust(dx1: 0, dy1: 0, dx2: -qRound(d: thinRect2.width() * coef) + 1, dy2: 0);
792 thinRect2.setLeft(thinRect2.right());
793 thinRect.adjust(dx1: qRound(d: thinRect.width() * coef), dy1: 0, dx2: -qRound(d: thinRect.width() * coef), dy2: 0);
794 }
795 p.drawRect(r: thinRect1);
796 p.drawRect(r: thinRect2);
797 //p.drawRect(thinRect);
798 }
799 p.setBrush(m_alphalessPixmap);
800 QRegion region;
801 if (m_orientation == Qt::Horizontal) {
802 region += r[1].adjusted(xp1: 0, yp1: qRound(d: r[1].height() * coef), xp2: 0, yp2: 0);
803 region += r[1].adjusted(xp1: 0, yp1: 0, xp2: 0, yp2: -qRound(d: r[1].height() * coef));
804 p.setClipRegion(region);
805 } else {
806 region += r[1].adjusted(xp1: qRound(d: r[1].width() * coef), yp1: 0, xp2: 0, yp2: 0);
807 region += r[1].adjusted(xp1: 0, yp1: 0, xp2: -qRound(d: r[1].width() * coef), yp2: 0);
808 p.setClipRegion(region);
809 }
810 p.setClipRegion(region);
811 p.setBrush(Qt::NoBrush);
812 p.setPen(QPen(QColor(c.rgb())));
813
814 p.drawRect(r: r[1].adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
815 // p.drawRect(r[1].adjusted(1, 1, -2, -2));
816/*
817 p.setBrush(m_semiAlphaPixmap);
818 if (m_orientation == Qt::Horizontal) {
819 QRect top = r[1].adjusted(0, 0, 0, -qRound(r[1].height() * coef) + 1);
820 top.setTop(top.bottom());
821 QRect bottom = r[1].adjusted(0, qRound(r[1].height() * coef) - 1, 0, 0);
822 top.setBottom(bottom.top());
823 p.setClipRect(top);
824 p.setClipRect(bottom, Qt::UniteClip);
825 } else {
826
827 }
828 QColor semiColor(c.rgb());
829 semiColor.setAlpha((c.alpha() + 0xFF) / 2);
830 p.setPen(QPen(semiColor));
831 p.drawRect(r[1].adjusted(0, 0, -1, -1));
832 // p.drawRect(r[1].adjusted(1, 1, -2, -2));
833*/
834 p.setClipping(false);
835 }
836 }
837
838 p.setBrush(Qt::NoBrush);
839 int lw = 4;
840 //int br = 1;
841 int br = 0;
842 r[1].adjust(dx1: br, dy1: br, dx2: -br, dy2: -br);
843 if (r[1].adjusted(xp1: lw, yp1: lw, xp2: -lw, yp2: -lw).isValid()) {
844 QStyleOptionFrame opt;
845 opt.initFrom(w: q_ptr);
846 opt.rect = r[1];
847 opt.lineWidth = 2;
848 opt.midLineWidth = 1;
849 if (m_dragging)
850 opt.state |= QStyle::State_Sunken;
851 else
852 opt.state |= QStyle::State_Raised;
853 q_ptr->style()->drawPrimitive(pe: QStyle::PE_Frame, opt: &opt, p: &p, w: q_ptr);
854 QRect colorRect = r[1].adjusted(xp1: lw, yp1: lw, xp2: -lw, yp2: -lw);
855 if (q_ptr->isEnabled()) {
856 p.fillRect(colorRect, color: c);
857 const QColor frameColor(0, 0, 0, 38);
858 p.setPen(frameColor);
859 p.drawRect(r: colorRect.adjusted(xp1: 0, yp1: 0, xp2: -1, yp2: -1));
860 /*
861 p.fillRect(colorRect.width() / 4 + colorRect.left(),
862 colorRect.height() / 4 + colorRect.top(),
863 colorRect.width() / 2,
864 colorRect.height() / 2,
865 QColor(c.rgb()));
866 */
867 /*
868 if (m_component != QtColorLine::Alpha) {
869 p.fillRect(colorRect.adjusted(0, colorRect.height() * 4 / 5, 0, 0), QColor(c.rgb()));
870 p.fillRect(colorRect.adjusted(0, 0, 0, -colorRect.height() * 4 / 5), QColor(c.rgb()));
871 }
872 */
873 }
874 }
875}
876
877void QtColorLinePrivate::mousePressEvent(QMouseEvent *event)
878{
879 if (event->button() != Qt::LeftButton)
880 return;
881
882 QList<QRect> r = rects(point: m_point);
883 QPoint clickPos = event->position().toPoint();
884
885 QPoint posOnField = r[1].topLeft() - QPoint(m_indicatorSpace, m_indicatorSpace);
886 m_clickOffset = posOnField - clickPos;
887
888 if (!r[1].contains(p: clickPos))
889 return;
890 m_dragging = true;
891 q_ptr->update();
892}
893
894void QtColorLinePrivate::mouseMoveEvent(QMouseEvent *event)
895{
896 if (!m_dragging)
897 return;
898 QPoint newPos = event->position().toPoint();
899
900 QSize fieldSize = q_ptr->geometry().size() -
901 QSize(m_indicatorSize + 2 * m_indicatorSpace - 1, m_indicatorSize + 2 * m_indicatorSpace - 1);
902 QPoint newPosOnField = newPos + m_clickOffset;
903 if (newPosOnField.x() < 0)
904 newPosOnField.setX(0);
905 else if (newPosOnField.x() > fieldSize.width())
906 newPosOnField.setX(fieldSize.width());
907 if (newPosOnField.y() < 0)
908 newPosOnField.setY(0);
909 else if (newPosOnField.y() > fieldSize.height())
910 newPosOnField.setY(fieldSize.height());
911
912 const double x = double(newPosOnField.x()) / fieldSize.width();
913 const double y = double(newPosOnField.y()) / fieldSize.height();
914 m_point = QPointF(x, y);
915 QColor color = colorFromPoint(point: m_point);
916 if (m_color == color)
917 return;
918 m_color = color;
919 emit q_ptr->colorChanged(color); // maybe before internal set, 1 line above
920 q_ptr->update();
921}
922
923void QtColorLinePrivate::mouseReleaseEvent(QMouseEvent *event)
924{
925 if (event->button() != Qt::LeftButton)
926 return;
927 m_dragging = false;
928 q_ptr->update();
929}
930
931void QtColorLinePrivate::mouseDoubleClickEvent(QMouseEvent *event)
932{
933 if (event->button() != Qt::LeftButton)
934 return;
935
936 QList<QRect> r = rects(point: m_point);
937 QPoint clickPos = event->position().toPoint();
938 if (!r[0].contains(p: clickPos) && !r[2].contains(p: clickPos))
939 return;
940 QPoint newPosOnField = clickPos;
941 if (r[2].contains(p: clickPos))
942 newPosOnField -= QPoint(m_indicatorSize + 2 * m_indicatorSpace - 2, m_indicatorSize + 2 * m_indicatorSpace - 2);
943 QSize fieldSize = q_ptr->geometry().size() -
944 QSize(m_indicatorSize + 2 * m_indicatorSpace - 1, m_indicatorSize + 2 * m_indicatorSpace - 1);
945
946 const double x = double(newPosOnField.x()) / fieldSize.width();
947 const double y = double(newPosOnField.y()) / fieldSize.height();
948 m_point = QPointF(x, y);
949 QColor color = colorFromPoint(point: m_point);
950 if (m_color == color)
951 return;
952 m_color = color;
953 emit q_ptr->colorChanged(color); // maybe before internal set, 1 line above
954 q_ptr->update();
955}
956
957////////////////////////////////////////////////////
958
959QtColorLine::QtColorLine(QWidget *parent)
960 : QWidget(parent), d_ptr(new QtColorLinePrivate)
961{
962 d_ptr->q_ptr = this;
963
964 setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
965}
966
967QtColorLine::~QtColorLine()
968{
969}
970
971QSize QtColorLine::minimumSizeHint() const
972{
973 return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize);
974}
975
976QSize QtColorLine::sizeHint() const
977{
978 return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize);
979}
980
981void QtColorLine::setColor(const QColor &color)
982{
983 d_ptr->setColor(color);
984}
985
986QColor QtColorLine::color() const
987{
988 return d_ptr->color();
989}
990
991void QtColorLine::setColorComponent(QtColorLine::ColorComponent component)
992{
993 d_ptr->setColorComponent(component);
994}
995
996QtColorLine::ColorComponent QtColorLine::colorComponent() const
997{
998 return d_ptr->colorComponent();
999}
1000
1001void QtColorLine::setIndicatorSize(int size)
1002{
1003 d_ptr->setIndicatorSize(size);
1004}
1005
1006int QtColorLine::indicatorSize() const
1007{
1008 return d_ptr->indicatorSize();
1009}
1010
1011void QtColorLine::setIndicatorSpace(int space)
1012{
1013 d_ptr->setIndicatorSpace(space);
1014}
1015
1016int QtColorLine::indicatorSpace() const
1017{
1018 return d_ptr->indicatorSpace();
1019}
1020
1021void QtColorLine::setFlip(bool flip)
1022{
1023 d_ptr->setFlip(flip);
1024}
1025
1026bool QtColorLine::flip() const
1027{
1028 return d_ptr->flip();
1029}
1030
1031void QtColorLine::setBackgroundCheckered(bool checkered)
1032{
1033 d_ptr->setBackgroundCheckered(checkered);
1034}
1035
1036bool QtColorLine::isBackgroundCheckered() const
1037{
1038 return d_ptr->isBackgroundCheckered();
1039}
1040
1041void QtColorLine::setOrientation(Qt::Orientation orientation)
1042{
1043 d_ptr->setOrientation(orientation);
1044}
1045
1046Qt::Orientation QtColorLine::orientation() const
1047{
1048 return d_ptr->orientation();
1049}
1050void QtColorLine::resizeEvent(QResizeEvent *event)
1051{
1052 d_ptr->resizeEvent(event);
1053}
1054
1055void QtColorLine::paintEvent(QPaintEvent *event)
1056{
1057 d_ptr->paintEvent(event);
1058}
1059
1060void QtColorLine::mousePressEvent(QMouseEvent *event)
1061{
1062 d_ptr->mousePressEvent(event);
1063}
1064
1065void QtColorLine::mouseMoveEvent(QMouseEvent *event)
1066{
1067 d_ptr->mouseMoveEvent(event);
1068}
1069
1070void QtColorLine::mouseReleaseEvent(QMouseEvent *event)
1071{
1072 d_ptr->mouseReleaseEvent(event);
1073}
1074
1075void QtColorLine::mouseDoubleClickEvent(QMouseEvent *event)
1076{
1077 d_ptr->mouseDoubleClickEvent(event);
1078}
1079
1080QT_END_NAMESPACE
1081

source code of qttools/src/shared/qtgradienteditor/qtcolorline.cpp