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 
48 QT_BEGIN_NAMESPACE
49 
50 class QtColorLinePrivate
51 {
52     QtColorLine *q_ptr;
53     Q_DECLARE_PUBLIC(QtColorLine)
54 public:
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);
84 private:
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 
QtColorLinePrivate()130 QtColorLinePrivate::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 
setColor(const QColor & color)140 void 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 
color() const154 QColor QtColorLinePrivate::color() const
155 {
156     return m_color;
157 }
158 
setColorComponent(QtColorLine::ColorComponent component)159 void 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 
colorComponent() const171 QtColorLine::ColorComponent QtColorLinePrivate::colorComponent() const
172 {
173     return m_component;
174 }
175 
setIndicatorSize(int size)176 void 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 
indicatorSize() const190 int QtColorLinePrivate::indicatorSize() const
191 {
192     return m_indicatorSize;
193 }
194 
setIndicatorSpace(int space)195 void 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 
indicatorSpace() const208 int QtColorLinePrivate::indicatorSpace() const
209 {
210     return m_indicatorSpace;
211 }
212 
setFlip(bool flip)213 void 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 
flip() const224 bool QtColorLinePrivate::flip() const
225 {
226     return m_flipped;
227 }
228 
setBackgroundCheckered(bool checkered)229 void QtColorLinePrivate::setBackgroundCheckered(bool checkered)
230 {
231     if (m_backgroundCheckered == checkered)
232         return;
233     m_backgroundCheckered = checkered;
234     q_ptr->update();
235 }
236 
isBackgroundCheckered() const237 bool QtColorLinePrivate::isBackgroundCheckered() const
238 {
239     return m_backgroundCheckered;
240 }
241 
setOrientation(Qt::Orientation orientation)242 void 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 
orientation() const261 Qt::Orientation QtColorLinePrivate::orientation() const
262 {
263     return m_orientation;
264 }
265 
checkColor()266 void 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 
isMainPixmapValid() const291 bool 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 
validate()355 void QtColorLinePrivate::validate()
356 {
357     if (isMainPixmapValid())
358         return;
359 
360     recreateMainPixmap();
361 }
362 
gradientPixmap(Qt::Orientation orientation,const QColor & begin,const QColor & end,bool flipped) const363 QPixmap 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 
gradientPixmap(int size,Qt::Orientation orientation,const QColor & begin,const QColor & end,bool flipped) const371 QPixmap 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 
hueGradientPixmap(Qt::Orientation orientation,bool flipped,int saturation,int value,int alpha) const401 QPixmap 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 
hueGradientPixmap(int size,Qt::Orientation orientation,bool flipped,int saturation,int value,int alpha) const410 QPixmap 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 
recreateMainPixmap()442 void 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 
pixmapSizeFromGeometrySize(const QSize & geometrySize) const522 QSize 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 
colorFromPoint(const QPointF & point) const534 QColor 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 
pointFromColor(const QColor & color) const581 QPointF 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 
rects(const QPointF & point) const623 QVector<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 
resizeEvent(QResizeEvent * event)654 void QtColorLinePrivate::resizeEvent(QResizeEvent *event)
655 {
656     m_pixmapSize = pixmapSizeFromGeometrySize(event->size());
657 }
658 
paintEvent(QPaintEvent *)659 void 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 
mousePressEvent(QMouseEvent * event)913 void 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 
mouseMoveEvent(QMouseEvent * event)930 void 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 
mouseReleaseEvent(QMouseEvent * event)959 void QtColorLinePrivate::mouseReleaseEvent(QMouseEvent *event)
960 {
961     if (event->button() != Qt::LeftButton)
962         return;
963     m_dragging = false;
964     q_ptr->update();
965 }
966 
mouseDoubleClickEvent(QMouseEvent * event)967 void 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 
QtColorLine(QWidget * parent)995 QtColorLine::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 
~QtColorLine()1003 QtColorLine::~QtColorLine()
1004 {
1005 }
1006 
minimumSizeHint() const1007 QSize QtColorLine::minimumSizeHint() const
1008 {
1009     return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize);
1010 }
1011 
sizeHint() const1012 QSize QtColorLine::sizeHint() const
1013 {
1014     return QSize(d_ptr->m_indicatorSize, d_ptr->m_indicatorSize);
1015 }
1016 
setColor(const QColor & color)1017 void QtColorLine::setColor(const QColor &color)
1018 {
1019     d_ptr->setColor(color);
1020 }
1021 
color() const1022 QColor QtColorLine::color() const
1023 {
1024     return d_ptr->color();
1025 }
1026 
setColorComponent(QtColorLine::ColorComponent component)1027 void QtColorLine::setColorComponent(QtColorLine::ColorComponent component)
1028 {
1029     d_ptr->setColorComponent(component);
1030 }
1031 
colorComponent() const1032 QtColorLine::ColorComponent QtColorLine::colorComponent() const
1033 {
1034     return d_ptr->colorComponent();
1035 }
1036 
setIndicatorSize(int size)1037 void QtColorLine::setIndicatorSize(int size)
1038 {
1039     d_ptr->setIndicatorSize(size);
1040 }
1041 
indicatorSize() const1042 int QtColorLine::indicatorSize() const
1043 {
1044     return d_ptr->indicatorSize();
1045 }
1046 
setIndicatorSpace(int space)1047 void QtColorLine::setIndicatorSpace(int space)
1048 {
1049     d_ptr->setIndicatorSpace(space);
1050 }
1051 
indicatorSpace() const1052 int QtColorLine::indicatorSpace() const
1053 {
1054     return d_ptr->indicatorSpace();
1055 }
1056 
setFlip(bool flip)1057 void QtColorLine::setFlip(bool flip)
1058 {
1059     d_ptr->setFlip(flip);
1060 }
1061 
flip() const1062 bool QtColorLine::flip() const
1063 {
1064     return d_ptr->flip();
1065 }
1066 
setBackgroundCheckered(bool checkered)1067 void QtColorLine::setBackgroundCheckered(bool checkered)
1068 {
1069     d_ptr->setBackgroundCheckered(checkered);
1070 }
1071 
isBackgroundCheckered() const1072 bool QtColorLine::isBackgroundCheckered() const
1073 {
1074     return d_ptr->isBackgroundCheckered();
1075 }
1076 
setOrientation(Qt::Orientation orientation)1077 void QtColorLine::setOrientation(Qt::Orientation orientation)
1078 {
1079     d_ptr->setOrientation(orientation);
1080 }
1081 
orientation() const1082 Qt::Orientation QtColorLine::orientation() const
1083 {
1084     return d_ptr->orientation();
1085 }
resizeEvent(QResizeEvent * event)1086 void QtColorLine::resizeEvent(QResizeEvent *event)
1087 {
1088     d_ptr->resizeEvent(event);
1089 }
1090 
paintEvent(QPaintEvent * event)1091 void QtColorLine::paintEvent(QPaintEvent *event)
1092 {
1093     d_ptr->paintEvent(event);
1094 }
1095 
mousePressEvent(QMouseEvent * event)1096 void QtColorLine::mousePressEvent(QMouseEvent *event)
1097 {
1098     d_ptr->mousePressEvent(event);
1099 }
1100 
mouseMoveEvent(QMouseEvent * event)1101 void QtColorLine::mouseMoveEvent(QMouseEvent *event)
1102 {
1103     d_ptr->mouseMoveEvent(event);
1104 }
1105 
mouseReleaseEvent(QMouseEvent * event)1106 void QtColorLine::mouseReleaseEvent(QMouseEvent *event)
1107 {
1108     d_ptr->mouseReleaseEvent(event);
1109 }
1110 
mouseDoubleClickEvent(QMouseEvent * event)1111 void QtColorLine::mouseDoubleClickEvent(QMouseEvent *event)
1112 {
1113     d_ptr->mouseDoubleClickEvent(event);
1114 }
1115 
1116 QT_END_NAMESPACE
1117