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