1 /** -*- mode: c++ ; c-basic-offset: 2 -*-
2  *
3  *  @file Tags.cpp
4  *
5  *  Copyright 2017 Sebastien Fourey
6  *
7  *  This file is part of G'MIC-Qt, a generic plug-in for raster graphics
8  *  editors, offering hundreds of filters thanks to the underlying G'MIC
9  *  image processing framework.
10  *
11  *  gmic_qt is free software: you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation, either version 3 of the License, or
14  *  (at your option) any later version.
15  *
16  *  gmic_qt is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with gmic_qt.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25 #include "Tags.h"
26 #include <QAction>
27 #include <QBuffer>
28 #include <QByteArray>
29 #include <QDebug>
30 #include <QIcon>
31 #include <QImage>
32 #include <QObject>
33 #include <QPainter>
34 #include <QPixmap>
35 #include <QStringList>
36 #include "Common.h"
37 #include "DialogSettings.h"
38 
39 namespace GmicQt
40 {
41 
42 const TagColorSet TagColorSet::Full(TagColorSet::_fullMask);
43 const TagColorSet TagColorSet::ActualColors(TagColorSet::_fullMask &(~1u));
44 const TagColorSet TagColorSet::Empty(0);
45 
46 QString TagAssets::_markerHtml[static_cast<unsigned int>(TagColor::Count)];
47 QIcon TagAssets::_menuIcons[static_cast<unsigned int>(TagColor::Count)];
48 QIcon TagAssets::_menuIconsWithCheck[static_cast<unsigned int>(TagColor::Count)];
49 QIcon TagAssets::_menuIconsWithDisk[static_cast<unsigned int>(TagColor::Count)];
50 unsigned int TagAssets::_markerSideSize[static_cast<unsigned int>(TagColor::Count)];
51 QColor TagAssets::colors[static_cast<unsigned int>(TagColor::Count)] = {QColor(0, 0, 0, 0),    QColor(250, 68, 113),  QColor(179, 228, 59), QColor(121, 171, 255),
52                                                                         QColor(117, 225, 242), QColor(188, 154, 234), QColor(236, 224, 105)};
53 
markerHtml(const TagColor color,unsigned int height)54 const QString & TagAssets::markerHtml(const TagColor color, unsigned int height)
55 {
56   if (!(height % 2)) {
57     ++height;
58   }
59   const int iColor = (int)color;
60   if (!_markerHtml[iColor].isEmpty() && _markerSideSize[iColor] == height) {
61     return _markerHtml[iColor];
62   }
63   QImage image(height, height, QImage::Format_RGBA8888);
64   image.fill(QColor(0, 0, 0, 0));
65   if (color != TagColor::None) {
66     QPainter painter(&image);
67     painter.setRenderHint(QPainter::Antialiasing, true);
68     QPen pen = painter.pen();
69     pen.setWidth(1);
70     pen.setColor(QColor(0, 0, 0, 128));
71     painter.setPen(pen);
72     painter.setBrush(colors[iColor]);
73     painter.drawEllipse(1, 1, height - 2, height - 2);
74   }
75   QByteArray ba;
76   QBuffer buffer(&ba);
77   image.save(&buffer, "png");
78   _markerSideSize[iColor] = height;
79   _markerHtml[iColor] = QString("<img style=\"vertical-align: baseline\" src=\"data:image/png;base64,%1\"/>").arg(QString(ba.toBase64()));
80   return _markerHtml[iColor];
81 }
82 
menuIcon(TagColor color,IconMark mark)83 const QIcon & TagAssets::menuIcon(TagColor color, IconMark mark)
84 {
85   const int iColor = (int)color;
86   if (_menuIcons[iColor].isNull()) {
87     QPixmap bg(64, 64);
88     QFont font;
89     font.setPixelSize(60);
90     {
91       bg.fill(QColor(0, 0, 0, 0));
92       QPainter p(&bg);
93       p.setRenderHint(QPainter::Antialiasing, true);
94       if (color == TagColor::None) {
95         QPen pen;
96         pen.setWidth(3);
97         if (DialogSettings::darkThemeEnabled()) {
98           pen.setColor(QColor(40, 40, 40));
99           p.setBrush(DialogSettings::CheckBoxBaseColor);
100         } else {
101           QPalette palette;
102           pen.setColor(palette.text().color());
103           p.setBrush(palette.window().color());
104         }
105         p.setPen(pen);
106         p.drawEllipse(bg.rect().adjusted(2, 2, -2, -2));
107       } else {
108         p.setBrush(colors[iColor]);
109         p.drawRoundedRect(bg.rect(), 15, 15);
110       }
111       _menuIcons[iColor] = QIcon(bg);
112     }
113     QColor markColor = Qt::black;
114     if (color == TagColor::None) {
115       markColor = DialogSettings::darkThemeEnabled() ? QColor(170, 170, 170) : QPalette().text().color();
116     }
117     QPixmap pixmap(bg);
118     {
119       QPainter p(&pixmap);
120       p.setFont(font);
121       p.setPen(markColor);
122       p.setRenderHint(QPainter::Antialiasing, true);
123       p.drawText(pixmap.rect(), Qt::AlignCenter | Qt::AlignVCenter, "\xE2\x9C\x93"); // CHECK MARK
124       _menuIconsWithCheck[iColor] = QIcon(pixmap);
125     }
126     pixmap = bg;
127     {
128       QPainter p(&pixmap);
129       p.setFont(font);
130       p.setPen(markColor);
131       p.setRenderHint(QPainter::Antialiasing, true);
132       p.drawText(pixmap.rect(), Qt::AlignCenter | Qt::AlignVCenter, "\xE2\x9A\xAB"); // MEDIUM BLACK CIRCLE
133       _menuIconsWithDisk[iColor] = QIcon(pixmap);
134     }
135   }
136   switch (mark) {
137   case IconMark::Check:
138     return _menuIconsWithCheck[iColor];
139   case IconMark::Disk:
140     return _menuIconsWithDisk[iColor];
141   default:
142     return _menuIcons[iColor];
143   }
144 }
145 
action(QObject * parent,TagColor color,IconMark mark)146 QAction * TagAssets::action(QObject * parent, TagColor color, IconMark mark)
147 {
148   if ((color == TagColor::None) || (color == TagColor::Count)) {
149     return nullptr;
150   }
151   return new QAction(menuIcon(color, mark), QObject::tr("%1 Tag").arg(colorName(color)), parent);
152 }
153 
colorName(TagColor color)154 QString TagAssets::colorName(TagColor color)
155 {
156   Q_ASSERT_X(((unsigned int)color < (unsigned int)TagColor::Count), __PRETTY_FUNCTION__, "Invalid color");
157   static QStringList names = {QObject::tr("None"),    //
158                               QObject::tr("Red"),     //
159                               QObject::tr("Green"),   //
160                               QObject::tr("Blue"),    //
161                               QObject::tr("Cyan"),    //
162                               QObject::tr("Magenta"), //
163                               QObject::tr("Yellow")};
164   return names.at(int(color));
165 }
166 
operator <<(std::ostream & out,const TagColorSet & colors)167 std::ostream & operator<<(std::ostream & out, const TagColorSet & colors)
168 {
169   out << "{";
170   bool first = true;
171   for (TagColor color : colors) {
172     if (first) {
173       first = false;
174     } else {
175       out << ",";
176     }
177     out << TagAssets::colorName(color).toStdString();
178   }
179   out << "}";
180   return out;
181 }
182 
183 } // namespace GmicQt
184