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