1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2011-01-28
7 * Description : color label widget
8 *
9 * Copyright (C) 2011-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10 *
11 * This program is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation;
14 * either version 2, or (at your option)
15 * any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * ============================================================ */
23
24 #include "colorlabelwidget.h"
25
26 // Qt includes
27
28 #include <QApplication>
29 #include <QPainter>
30 #include <QPixmap>
31 #include <QIcon>
32 #include <QLayout>
33 #include <QLabel>
34 #include <QButtonGroup>
35 #include <QWidgetAction>
36 #include <QFontMetrics>
37 #include <QFont>
38 #include <QToolButton>
39 #include <QMenu>
40
41 // KDE includes
42
43 #include <klocalizedstring.h>
44 #include <kactioncollection.h>
45
46 // Local includes
47
48 #include "dlayoutbox.h"
49 #include "dxmlguiwindow.h"
50 #include "dexpanderbox.h"
51
52 namespace Digikam
53 {
54
55 class Q_DECL_HIDDEN ColorLabelWidget::Private
56 {
57 public:
58
Private()59 explicit Private()
60 : colorBtns (nullptr),
61 desc (nullptr),
62 btnNone (nullptr),
63 btnRed (nullptr),
64 btnOrange (nullptr),
65 btnYellow (nullptr),
66 btnGreen (nullptr),
67 btnBlue (nullptr),
68 btnMagenta (nullptr),
69 btnGray (nullptr),
70 btnBlack (nullptr),
71 btnWhite (nullptr),
72 descBox (nullptr),
73 shortcut (nullptr)
74 {
75 }
76
77 QButtonGroup* colorBtns;
78
79 QLabel* desc;
80
81 QToolButton* btnNone;
82 QToolButton* btnRed;
83 QToolButton* btnOrange;
84 QToolButton* btnYellow;
85 QToolButton* btnGreen;
86 QToolButton* btnBlue;
87 QToolButton* btnMagenta;
88 QToolButton* btnGray;
89 QToolButton* btnBlack;
90 QToolButton* btnWhite;
91
92 DHBox* descBox;
93
94 DAdjustableLabel* shortcut;
95 };
96
ColorLabelWidget(QWidget * const parent)97 ColorLabelWidget::ColorLabelWidget(QWidget* const parent)
98 : DVBox(parent),
99 d (new Private)
100 {
101 setAttribute(Qt::WA_DeleteOnClose);
102 setFocusPolicy(Qt::NoFocus);
103
104 DHBox* const hbox = new DHBox(this);
105 hbox->setContentsMargins(QMargins());
106 hbox->setSpacing(0);
107
108 d->btnNone = new QToolButton(hbox);
109 d->btnNone->setCheckable(true);
110 d->btnNone->setFocusPolicy(Qt::NoFocus);
111 d->btnNone->setIcon(buildIcon(NoColorLabel));
112 d->btnNone->installEventFilter(this);
113
114 d->btnRed = new QToolButton(hbox);
115 d->btnRed->setCheckable(true);
116 d->btnRed->setFocusPolicy(Qt::NoFocus);
117 d->btnRed->setIcon(buildIcon(RedLabel));
118 d->btnRed->installEventFilter(this);
119
120 d->btnOrange = new QToolButton(hbox);
121 d->btnOrange->setCheckable(true);
122 d->btnOrange->setFocusPolicy(Qt::NoFocus);
123 d->btnOrange->setIcon(buildIcon(OrangeLabel));
124 d->btnOrange->installEventFilter(this);
125
126 d->btnYellow = new QToolButton(hbox);
127 d->btnYellow->setCheckable(true);
128 d->btnYellow->setFocusPolicy(Qt::NoFocus);
129 d->btnYellow->setIcon(buildIcon(YellowLabel));
130 d->btnYellow->installEventFilter(this);
131
132 d->btnGreen = new QToolButton(hbox);
133 d->btnGreen->setCheckable(true);
134 d->btnGreen->setFocusPolicy(Qt::NoFocus);
135 d->btnGreen->setIcon(buildIcon(GreenLabel));
136 d->btnGreen->installEventFilter(this);
137
138 d->btnBlue = new QToolButton(hbox);
139 d->btnBlue->setCheckable(true);
140 d->btnBlue->setFocusPolicy(Qt::NoFocus);
141 d->btnBlue->setIcon(buildIcon(BlueLabel));
142 d->btnBlue->installEventFilter(this);
143
144 d->btnMagenta = new QToolButton(hbox);
145 d->btnMagenta->setCheckable(true);
146 d->btnMagenta->setFocusPolicy(Qt::NoFocus);
147 d->btnMagenta->setIcon(buildIcon(MagentaLabel));
148 d->btnMagenta->installEventFilter(this);
149
150 d->btnGray = new QToolButton(hbox);
151 d->btnGray->setCheckable(true);
152 d->btnGray->setFocusPolicy(Qt::NoFocus);
153 d->btnGray->setIcon(buildIcon(GrayLabel));
154 d->btnGray->installEventFilter(this);
155
156 d->btnBlack = new QToolButton(hbox);
157 d->btnBlack->setCheckable(true);
158 d->btnBlack->setFocusPolicy(Qt::NoFocus);
159 d->btnBlack->setIcon(buildIcon(BlackLabel));
160 d->btnBlack->installEventFilter(this);
161
162 d->btnWhite = new QToolButton(hbox);
163 d->btnWhite->setCheckable(true);
164 d->btnWhite->setFocusPolicy(Qt::NoFocus);
165 d->btnWhite->setIcon(buildIcon(WhiteLabel));
166 d->btnWhite->installEventFilter(this);
167
168 d->colorBtns = new QButtonGroup(hbox);
169 d->colorBtns->addButton(d->btnNone, NoColorLabel);
170 d->colorBtns->addButton(d->btnRed, RedLabel);
171 d->colorBtns->addButton(d->btnOrange, OrangeLabel);
172 d->colorBtns->addButton(d->btnYellow, YellowLabel);
173 d->colorBtns->addButton(d->btnGreen, GreenLabel);
174 d->colorBtns->addButton(d->btnBlue, BlueLabel);
175 d->colorBtns->addButton(d->btnMagenta, MagentaLabel);
176 d->colorBtns->addButton(d->btnGray, GrayLabel);
177 d->colorBtns->addButton(d->btnBlack, BlackLabel);
178 d->colorBtns->addButton(d->btnWhite, WhiteLabel);
179
180 d->descBox = new DHBox(this);
181 d->descBox->setContentsMargins(QMargins());
182 d->descBox->setSpacing(0);
183 d->desc = new QLabel(d->descBox);
184 d->shortcut = new DAdjustableLabel(d->descBox);
185 QFont fnt = d->shortcut->font();
186 fnt.setItalic(true);
187 d->shortcut->setFont(fnt);
188 d->shortcut->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
189 d->shortcut->setWordWrap(false);
190
191 setSpacing(0);
192 setContentsMargins(QMargins());
193 setColorLabels(QList<ColorLabel>() << NoColorLabel);
194 setDescriptionBoxVisible(true);
195 setButtonsExclusive(true);
196
197 // -------------------------------------------------------------
198
199 connect(d->colorBtns, SIGNAL(buttonReleased(int)),
200 this, SIGNAL(signalColorLabelChanged(int)));
201 }
202
~ColorLabelWidget()203 ColorLabelWidget::~ColorLabelWidget()
204 {
205 delete d;
206 }
207
setDescriptionBoxVisible(bool b)208 void ColorLabelWidget::setDescriptionBoxVisible(bool b)
209 {
210 d->descBox->setVisible(b);
211
212 if (!b)
213 {
214 foreach (QAbstractButton* const btn, d->colorBtns->buttons())
215 {
216 ColorLabel id = (ColorLabel)(d->colorBtns->id(btn));
217 btn->setToolTip(labelColorName(id));
218 }
219 }
220 }
221
setButtonsExclusive(bool b)222 void ColorLabelWidget::setButtonsExclusive(bool b)
223 {
224 d->colorBtns->setExclusive(b);
225 }
226
updateDescription(ColorLabel label)227 void ColorLabelWidget::updateDescription(ColorLabel label)
228 {
229 d->desc->setText(labelColorName(label));
230
231 DXmlGuiWindow* const app = dynamic_cast<DXmlGuiWindow*>(qApp->activeWindow());
232
233 if (app)
234 {
235 QAction* const ac = app->actionCollection()->action(QString::fromLatin1("colorshortcut-%1").arg(label));
236
237 if (ac)
238 {
239 d->shortcut->setAdjustedText(ac->shortcut().toString());
240 }
241 }
242 }
243
eventFilter(QObject * obj,QEvent * ev)244 bool ColorLabelWidget::eventFilter(QObject* obj, QEvent* ev)
245 {
246 if (obj == d->btnNone)
247 {
248 if (ev->type() == QEvent::Enter)
249 {
250 updateDescription(NoColorLabel);
251 return false;
252 }
253 }
254
255 if (obj == d->btnRed)
256 {
257 if (ev->type() == QEvent::Enter)
258 {
259 updateDescription(RedLabel);
260 return false;
261 }
262 }
263
264 if (obj == d->btnOrange)
265 {
266 if (ev->type() == QEvent::Enter)
267 {
268 updateDescription(OrangeLabel);
269 return false;
270 }
271 }
272
273 if (obj == d->btnYellow)
274 {
275 if (ev->type() == QEvent::Enter)
276 {
277 updateDescription(YellowLabel);
278 return false;
279 }
280 }
281
282 if (obj == d->btnGreen)
283 {
284 if (ev->type() == QEvent::Enter)
285 {
286 updateDescription(GreenLabel);
287 return false;
288 }
289 }
290
291 if (obj == d->btnBlue)
292 {
293 if (ev->type() == QEvent::Enter)
294 {
295 updateDescription(BlueLabel);
296 return false;
297 }
298 }
299
300 if (obj == d->btnMagenta)
301 {
302 if (ev->type() == QEvent::Enter)
303 {
304 updateDescription(MagentaLabel);
305 return false;
306 }
307 }
308
309 if (obj == d->btnGray)
310 {
311 if (ev->type() == QEvent::Enter)
312 {
313 updateDescription(GrayLabel);
314 return false;
315 }
316 }
317
318 if (obj == d->btnBlack)
319 {
320 if (ev->type() == QEvent::Enter)
321 {
322 updateDescription(BlackLabel);
323 return false;
324 }
325 }
326
327 if (obj == d->btnWhite)
328 {
329 if (ev->type() == QEvent::Enter)
330 {
331 updateDescription(WhiteLabel);
332 return false;
333 }
334 }
335
336 // pass the event on to the parent class
337
338 return DVBox::eventFilter(obj, ev);
339 }
340
setColorLabels(const QList<ColorLabel> & list)341 void ColorLabelWidget::setColorLabels(const QList<ColorLabel>& list)
342 {
343 foreach (QAbstractButton* const btn, d->colorBtns->buttons())
344 {
345 ColorLabel id = (ColorLabel)(d->colorBtns->id(btn));
346 btn->setChecked(list.contains(id));
347 updateDescription(id);
348 }
349 }
350
colorLabels() const351 QList<ColorLabel> ColorLabelWidget::colorLabels() const
352 {
353 QList<ColorLabel> list;
354
355 foreach (QAbstractButton* const btn, d->colorBtns->buttons())
356 {
357 if (btn && btn->isChecked())
358 {
359 list.append((ColorLabel)(d->colorBtns->id(btn)));
360 }
361 }
362
363 return list;
364 }
365
buildIcon(ColorLabel label,int size)366 QIcon ColorLabelWidget::buildIcon(ColorLabel label, int size)
367 {
368 if (label != NoColorLabel)
369 {
370 QPixmap pix(size, size);
371 QPainter p(&pix);
372 p.setPen(qApp->palette().color(QPalette::Active, QPalette::ButtonText));
373 p.fillRect(0, 0, pix.width()-1, pix.height()-1, labelColor(label));
374 p.drawRect(0, 0, pix.width()-1, pix.height()-1);
375
376 return QIcon(pix);
377 }
378
379 return QIcon::fromTheme(QLatin1String("emblem-unmounted"));
380 }
381
labelColor(ColorLabel label)382 QColor ColorLabelWidget::labelColor(ColorLabel label)
383 {
384 QColor color;
385
386 switch (label)
387 {
388 case RedLabel:
389 color = qRgb(0xDF, 0x6E, 0x5F);
390 break;
391
392 case OrangeLabel:
393 color = qRgb(0xEE, 0xAF, 0x6B);
394 break;
395
396 case YellowLabel:
397 color = qRgb(0xE4, 0xD3, 0x78);
398 break;
399
400 case GreenLabel:
401 color = qRgb(0xAF, 0xD8, 0x78);
402 break;
403
404 case BlueLabel:
405 color = qRgb(0x77, 0xBA, 0xE8);
406 break;
407
408 case MagentaLabel:
409 color = qRgb(0xCB, 0x98, 0xE1);
410 break;
411
412 case GrayLabel:
413 color = qRgb(0xB7, 0xB7, 0xB7);
414 break;
415
416 case BlackLabel:
417 color = qRgb(0x28, 0x28, 0x28);
418 break;
419
420 case WhiteLabel:
421 color = qRgb(0xF7, 0xFE, 0xFA);
422 break;
423
424 default: // NoColorLabel
425 break;
426 }
427
428 return color;
429 }
430
labelColorName(ColorLabel label)431 QString ColorLabelWidget::labelColorName(ColorLabel label)
432 {
433 QString name;
434
435 switch (label)
436 {
437 case RedLabel:
438 name = i18nc("@info: color label name", "Red");
439 break;
440
441 case OrangeLabel:
442 name = i18nc("@info: color label name", "Orange");
443 break;
444
445 case YellowLabel:
446 name = i18nc("@info: color label name", "Yellow");
447 break;
448
449 case GreenLabel:
450 name = i18nc("@info: color label name", "Green");
451 break;
452
453 case BlueLabel:
454 name = i18nc("@info: color label name", "Blue");
455 break;
456
457 case MagentaLabel:
458 name = i18nc("@info: color label name", "Magenta");
459 break;
460
461 case GrayLabel:
462 name = i18nc("@info: color label name", "Gray");
463 break;
464
465 case BlackLabel:
466 name = i18nc("@info: color label name", "Black");
467 break;
468
469 case WhiteLabel:
470 name = i18nc("@info: color label name", "White");
471 break;
472
473 default: // NoColorLabel
474 name = i18nc("@info: color label name", "None");
475 break;
476 }
477
478 return name;
479 }
480
481 // -----------------------------------------------------------------------------
482
483 class Q_DECL_HIDDEN ColorLabelSelector::Private
484 {
485
486 public:
487
Private()488 explicit Private()
489 : clw(nullptr)
490 {
491 }
492
493 ColorLabelWidget* clw;
494 };
495
ColorLabelSelector(QWidget * parent)496 ColorLabelSelector::ColorLabelSelector(QWidget* parent)
497 : QPushButton(parent),
498 d (new Private)
499 {
500 QMenu* const popup = new QMenu(this);
501 setMenu(popup);
502
503 QWidgetAction* const action = new QWidgetAction(this);
504 d->clw = new ColorLabelWidget(this);
505 action->setDefaultWidget(d->clw);
506 popup->addAction(action);
507 slotColorLabelChanged(NoColorLabel);
508
509 connect(d->clw, SIGNAL(signalColorLabelChanged(int)),
510 this, SLOT(slotColorLabelChanged(int)));
511 }
512
~ColorLabelSelector()513 ColorLabelSelector::~ColorLabelSelector()
514 {
515 delete d;
516 }
517
colorLabelWidget() const518 ColorLabelWidget* ColorLabelSelector::colorLabelWidget() const
519 {
520 return d->clw;
521 }
522
setColorLabel(ColorLabel label)523 void ColorLabelSelector::setColorLabel(ColorLabel label)
524 {
525 d->clw->setColorLabels(QList<ColorLabel>() << label);
526 slotColorLabelChanged(label);
527 }
528
colorLabel()529 ColorLabel ColorLabelSelector::colorLabel()
530 {
531 QList<ColorLabel> list = d->clw->colorLabels();
532
533 if (!list.isEmpty())
534 {
535 return list.first();
536 }
537
538 return NoColorLabel;
539 }
540
slotColorLabelChanged(int id)541 void ColorLabelSelector::slotColorLabelChanged(int id)
542 {
543 setText(QString());
544 setIcon(d->clw->buildIcon((ColorLabel)id));
545 setToolTip(i18nc("@info: color label selector", "Color Label: %1", d->clw->labelColorName((ColorLabel)id)));
546 menu()->close();
547
548 emit signalColorLabelChanged(id);
549 }
550
551 // -----------------------------------------------------------------------------
552
ColorLabelMenuAction(QMenu * const parent)553 ColorLabelMenuAction::ColorLabelMenuAction(QMenu* const parent)
554 : QMenu(parent)
555 {
556 setTitle(i18nc("@title: color label menu", "Color"));
557 QWidgetAction* const wa = new QWidgetAction(this);
558 ColorLabelWidget* const clw = new ColorLabelWidget(parent);
559 wa->setDefaultWidget(clw);
560 addAction(wa);
561
562 connect(clw, SIGNAL(signalColorLabelChanged(int)),
563 this, SIGNAL(signalColorLabelChanged(int)));
564
565 connect(clw, SIGNAL(signalColorLabelChanged(int)),
566 parent, SLOT(close()));
567 }
568
~ColorLabelMenuAction()569 ColorLabelMenuAction::~ColorLabelMenuAction()
570 {
571 }
572
573 } // namespace Digikam
574