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