1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 1997-02-20
7  * Description : color chooser widgets
8  *
9  * Copyright (C)      1997 by Martin Jones <mjones at kde dot org>
10  * Copyright (C) 2015-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11  *
12  * This program is free software; you can redistribute it
13  * and/or modify it under the terms of the GNU General
14  * Public License as published by the Free Software Foundation;
15  * either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * ============================================================ */
24 
25 #include "dcolorvalueselector.h"
26 
27 // Qt includes
28 
29 #include <QPainter>
30 #include <QImage>
31 #include <QPaintEvent>
32 #include <QPixmap>
33 #include <QStyle>
34 #include <QStyleOption>
35 
36 // Local includes
37 
38 #include "dcolorchoosermode_p.h"
39 
40 namespace Digikam
41 {
42 
43 class Q_DECL_HIDDEN DSelector::Private
44 {
45 public:
46 
Private()47     explicit Private()
48       : arrowsize(5),
49         m_indent(true),
50         arrowPE(QStyle::PE_IndicatorArrowLeft)
51     {
52     }
53 
54     const int                arrowsize;
55     bool                     m_indent;
56     QStyle::PrimitiveElement arrowPE;
57 };
58 
DSelector(QWidget * const parent)59 DSelector::DSelector(QWidget* const parent)
60     : QAbstractSlider(parent),
61       d(new Private)
62 {
63     setOrientation(Qt::Horizontal);
64 }
65 
DSelector(Qt::Orientation o,QWidget * const parent)66 DSelector::DSelector(Qt::Orientation o, QWidget* const parent)
67     : QAbstractSlider(parent),
68       d(new Private)
69 {
70     setOrientation(o);
71 
72     if (o == Qt::Horizontal)
73     {
74         setArrowDirection(Qt::UpArrow);
75     }
76 }
77 
~DSelector()78 DSelector::~DSelector()
79 {
80     delete d;
81 }
82 
setIndent(bool i)83 void DSelector::setIndent(bool i)
84 {
85     d->m_indent = i;
86 }
87 
indent() const88 bool DSelector::indent() const
89 {
90     return d->m_indent;
91 }
92 
contentsRect() const93 QRect DSelector::contentsRect() const
94 {
95     int w  = indent() ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0;
96     int iw = (w < d->arrowsize) ? d->arrowsize : w;
97 
98     if (orientation() == Qt::Vertical)
99     {
100         if (arrowDirection() == Qt::RightArrow)
101         {
102             return QRect(w + d->arrowsize, iw,
103                          width() - w*2 - d->arrowsize,
104                          height() - iw*2);
105         }
106         else
107         {
108             return QRect(w, iw,
109                          width() - w*2 - d->arrowsize,
110                          height() - iw*2);
111         }
112     }
113     else
114     {
115         // Qt::Horizontal
116 
117         if (arrowDirection() == Qt::UpArrow)
118         {
119             return QRect(iw, w,
120                          width() - 2*iw,
121                          height() - w*2 - d->arrowsize);
122         }
123         else
124         {
125             return QRect(iw, w + d->arrowsize,
126                          width() - 2*iw,
127                          height() - w*2 - d->arrowsize);
128         }
129     }
130 }
131 
paintEvent(QPaintEvent *)132 void DSelector::paintEvent(QPaintEvent*)
133 {
134     QPainter painter;
135     int w  = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
136     int iw = (w < d->arrowsize) ? d->arrowsize : w;
137 
138     painter.begin(this);
139 
140     drawContents(&painter);
141 
142     QBrush brush;
143 
144     QPoint pos = calcArrowPos(value());
145     drawArrow(&painter, pos);
146 
147     if (indent())
148     {
149         QStyleOptionFrame opt;
150         opt.initFrom(this);
151         opt.state = QStyle::State_Sunken;
152 
153         if (orientation() == Qt::Vertical)
154         {
155             opt.rect.adjust(0, iw - w, -5, w - iw);
156         }
157         else
158         {
159             opt.rect.adjust(iw - w, 0, w - iw, -5);
160         }
161 
162         QBrush oldBrush = painter.brush();
163         painter.setBrush(Qt::NoBrush);
164         style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this);
165         painter.setBrush(oldBrush);
166     }
167 
168     painter.end();
169 }
170 
mousePressEvent(QMouseEvent * e)171 void DSelector::mousePressEvent(QMouseEvent* e)
172 {
173     setSliderDown(true);
174     moveArrow(e->pos());
175 }
176 
mouseMoveEvent(QMouseEvent * e)177 void DSelector::mouseMoveEvent(QMouseEvent* e)
178 {
179     moveArrow(e->pos());
180 }
181 
mouseReleaseEvent(QMouseEvent * e)182 void DSelector::mouseReleaseEvent(QMouseEvent* e)
183 {
184     moveArrow(e->pos());
185     setSliderDown(false);
186 }
187 
wheelEvent(QWheelEvent * e)188 void DSelector::wheelEvent(QWheelEvent* e)
189 {
190     int val = value() + e->angleDelta().y() / 120;
191     setSliderDown(true);
192     setValue(val);
193     setSliderDown(false);
194 }
195 
moveArrow(const QPoint & pos)196 void DSelector::moveArrow(const QPoint& pos)
197 {
198     int val;
199     int w  = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
200     int iw = (w < d->arrowsize) ? d->arrowsize : w;
201 
202     if (orientation() == Qt::Vertical)
203     {
204         val = (maximum() - minimum()) * (height() - pos.y() - iw) /
205               (height() - iw * 2) + minimum();
206     }
207     else
208     {
209         val = (maximum() - minimum()) * ( pos.x() - iw) /
210               (width() - iw * 2) + minimum();
211     }
212 
213     setValue(val);
214     update();
215 }
216 
calcArrowPos(int val)217 QPoint DSelector::calcArrowPos(int val)
218 {
219     QPoint p;
220     int w  = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
221     int iw = (w < d->arrowsize) ? d->arrowsize : w;
222 
223     if (orientation() == Qt::Vertical)
224     {
225         p.setY(height() - iw - 1 - (height() - 2 * iw - 1) * val  / (maximum() - minimum()));
226 
227         if (d->arrowPE == QStyle::PE_IndicatorArrowRight)
228         {
229             p.setX(0);
230         }
231         else
232         {
233             p.setX(width() - 5);
234         }
235     }
236     else
237     {
238         p.setX(iw + (width() - 2 * iw - 1) * val  / (maximum() - minimum()));
239 
240         if (d->arrowPE == QStyle::PE_IndicatorArrowDown)
241         {
242             p.setY(0);
243         }
244         else
245         {
246             p.setY(height() - 5);
247         }
248     }
249 
250     return p;
251 }
252 
setArrowDirection(Qt::ArrowType direction)253 void DSelector::setArrowDirection(Qt::ArrowType direction)
254 {
255     switch (direction)
256     {
257         case Qt::UpArrow:
258             if (orientation() == Qt::Horizontal)
259             {
260                 d->arrowPE = QStyle::PE_IndicatorArrowUp;
261             }
262             else
263             {
264                 d->arrowPE = QStyle::PE_IndicatorArrowLeft;
265             }
266             break;
267 
268         case Qt::DownArrow:
269             if (orientation() == Qt::Horizontal)
270             {
271                 d->arrowPE = QStyle::PE_IndicatorArrowDown;
272             }
273             else
274             {
275                 d->arrowPE = QStyle::PE_IndicatorArrowRight;
276             }
277             break;
278 
279         case Qt::LeftArrow:
280             if (orientation() == Qt::Vertical)
281             {
282                 d->arrowPE = QStyle::PE_IndicatorArrowLeft;
283             }
284             else
285             {
286                 d->arrowPE = QStyle::PE_IndicatorArrowDown;
287             }
288             break;
289 
290         case Qt::RightArrow:
291             if (orientation() == Qt::Vertical)
292             {
293                 d->arrowPE = QStyle::PE_IndicatorArrowRight;
294             }
295             else
296             {
297                 d->arrowPE = QStyle::PE_IndicatorArrowUp;
298             }
299             break;
300 
301         case Qt::NoArrow:
302             break;
303     }
304 }
305 
arrowDirection() const306 Qt::ArrowType DSelector::arrowDirection() const
307 {
308     switch (d->arrowPE)
309     {
310         case QStyle::PE_IndicatorArrowUp:
311             return Qt::UpArrow;
312             break;
313 
314         case QStyle::PE_IndicatorArrowDown:
315             return Qt::DownArrow;
316             break;
317 
318         case QStyle::PE_IndicatorArrowRight:
319             return Qt::RightArrow;
320             break;
321 
322         case QStyle::PE_IndicatorArrowLeft:
323         default:
324             return Qt::LeftArrow;
325             break;
326     }
327 }
328 
drawArrow(QPainter * painter,const QPoint & pos)329 void DSelector::drawArrow(QPainter* painter, const QPoint& pos)
330 {
331     painter->setPen(QPen());
332     painter->setBrush(QBrush(palette().color(QPalette::ButtonText)));
333 
334     QStyleOption o;
335 
336     if (orientation() == Qt::Vertical)
337     {
338         o.rect = QRect(pos.x(), pos.y() - d->arrowsize / 2,
339                        d->arrowsize, d->arrowsize);
340     }
341     else
342     {
343         o.rect = QRect(pos.x() - d->arrowsize / 2, pos.y(),
344                        d->arrowsize, d->arrowsize);
345 
346     }
347 
348     style()->drawPrimitive(d->arrowPE, &o, painter, this);
349 }
350 
351 // -------------------------------------------------------------------------------------
352 
353 class Q_DECL_HIDDEN DColorValueSelector::Private
354 {
355 public:
356 
Private(DColorValueSelector * const q)357     explicit Private(DColorValueSelector* const q)
358         : q(q),
359           hue(0),
360           saturation(0),
361           color(0),
362           mode(ChooserClassic)
363     {
364     }
365 
366     DColorValueSelector* q;
367     int                  hue;
368     int                  saturation;
369     int                  color;
370     DColorChooserMode    mode;
371     QPixmap              pixmap;
372 };
373 
DColorValueSelector(QWidget * const parent)374 DColorValueSelector::DColorValueSelector(QWidget* const parent)
375     : DSelector(Qt::Vertical, parent),
376       d(new Private(this))
377 {
378     setRange(0, 255);
379 }
380 
DColorValueSelector(Qt::Orientation o,QWidget * const parent)381 DColorValueSelector::DColorValueSelector(Qt::Orientation o, QWidget* const parent)
382     : DSelector(o, parent),
383       d(new Private(this))
384 {
385     setRange(0, 255);
386 }
387 
~DColorValueSelector()388 DColorValueSelector::~DColorValueSelector()
389 {
390     delete d;
391 }
392 
hue() const393 int DColorValueSelector::hue() const
394 {
395     return d->hue;
396 }
397 
setHue(int hue)398 void DColorValueSelector::setHue(int hue)
399 {
400     d->hue = hue;
401 }
402 
saturation() const403 int DColorValueSelector::saturation() const
404 {
405     return d->saturation;
406 }
407 
setSaturation(int saturation)408 void DColorValueSelector::setSaturation(int saturation)
409 {
410     d->saturation = saturation;
411 }
412 
colorValue() const413 int DColorValueSelector::colorValue() const
414 {
415     return d->color;
416 }
417 
setColorValue(int colorValue)418 void DColorValueSelector::setColorValue(int colorValue)
419 {
420     d->color = colorValue;
421 }
422 
updateContents()423 void DColorValueSelector::updateContents()
424 {
425     drawPalette(&d->pixmap);
426 }
427 
resizeEvent(QResizeEvent *)428 void DColorValueSelector::resizeEvent(QResizeEvent*)
429 {
430     updateContents();
431 }
432 
drawContents(QPainter * painter)433 void DColorValueSelector::drawContents(QPainter* painter)
434 {
435     painter->drawPixmap(contentsRect().x(), contentsRect().y(), d->pixmap);
436 }
437 
setChooserMode(DColorChooserMode c)438 void DColorValueSelector::setChooserMode(DColorChooserMode c)
439 {
440     if (c == ChooserHue)
441     {
442         setRange(0, 360);
443     }
444     else
445     {
446         setRange(0, 255);
447     }
448 
449     d->mode = c;
450 }
451 
chooserMode() const452 DColorChooserMode DColorValueSelector::chooserMode() const
453 {
454     return d->mode;
455 }
456 
drawPalette(QPixmap * pixmap)457 void DColorValueSelector::drawPalette(QPixmap* pixmap)
458 {
459     QColor color;
460 
461     if (chooserMode() == ChooserHue)
462     {
463         color.setHsv(hue(), 255, 255);
464     }
465     else
466     {
467         color.setHsv(hue(), saturation(), colorValue());
468     }
469 
470     QLinearGradient gradient;
471 
472     if (orientation() == Qt::Vertical)
473     {
474         gradient.setStart(0, contentsRect().height());
475         gradient.setFinalStop(0, 0);
476     }
477     else
478     {
479         gradient.setStart(0, 0);
480         gradient.setFinalStop(contentsRect().width(), 0);
481     }
482 
483     const int steps = componentValueSteps(chooserMode());
484 
485     for (int v = 0 ; v <= steps ; ++v)
486     {
487         setComponentValue(color, chooserMode(), v * (1.0 / steps));
488         gradient.setColorAt(v * (1.0 / steps), color);
489     }
490 
491     *pixmap = QPixmap(contentsRect().size());
492     QPainter painter(pixmap);
493     painter.fillRect(pixmap->rect(), gradient);
494 }
495 
496 } // namespace Digikam
497