1 #include "./syncthingicons.h"
2 
3 #include <qtutilities/misc/compat.h>
4 
5 #include <QFile>
6 #include <QGuiApplication>
7 #include <QPainter>
8 #include <QStringBuilder>
9 #include <QSvgRenderer>
10 
11 namespace Data {
12 
13 /*!
14  * \brief Generates the SVG code for the Syncthing icon with the specified \a colors and status emblem.
15  */
makeSyncthingIcon(const StatusIconColorSet & colors,StatusEmblem statusEmblem)16 QByteArray makeSyncthingIcon(const StatusIconColorSet &colors, StatusEmblem statusEmblem)
17 {
18     // serialize colors
19     auto gradientStartColor = colors.backgroundStart.name(QColor::HexRgb);
20     auto gradientEndColor = colors.backgroundEnd.name(QColor::HexRgb);
21     if (colors.backgroundStart.alphaF() < 1.0) {
22         gradientStartColor += QStringLiteral(";stop-opacity:") + QString::number(colors.backgroundStart.alphaF());
23     }
24     if (colors.backgroundEnd.alphaF() < 1.0) {
25         gradientEndColor += QStringLiteral(";stop-opacity:") + QString::number(colors.backgroundEnd.alphaF());
26     }
27     auto fillColor = colors.foreground.name(QColor::HexRgb);
28     auto strokeColor = fillColor;
29     if (colors.foreground.alphaF() < 1.0) {
30         const auto alpha = QString::number(colors.foreground.alphaF());
31         fillColor += QStringLiteral(";fill-opacity:") + alpha;
32         strokeColor += QStringLiteral(";stroke-opacity:") + alpha;
33     }
34 
35     // make SVG document
36     // clang-format off
37     static const QString emblems[] = {
38         QString(),
39         QStringLiteral(
40             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#000000\"/>"
41             "<g id=\"search\">"
42                 "<path style=\"fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.48022598\" d=\"m 10.669491,8.1035085 c -1.1972025,0 -2.2607791,1.065213 -2.2607791,2.2609745 0,1.197203 1.0650175,2.261025 2.2607791,2.261025 0.510789,0 1.007001,-0.113577 1.376093,-0.407927 l 1.936914,2.2081 0.763264,-0.763264 -2.106406,-1.919965 C 12.935006,11.372784 12.931,10.876087 12.931,10.364483 12.931,9.1672809 11.865254,8.1035085 10.669491,8.1035085 Z M 10.669712,8.884 c 0.931159,0 1.481288,0.5488435 1.481288,1.48 0,0.931159 -0.55035,1.482 -1.481509,1.482 C 9.7383328,11.846 9.189,11.295642 9.189,10.364483 9.189,9.4333265 9.7385538,8.884 10.669712,8.884 Z\"/>"
43             "</g>"
44         ),
45         QStringLiteral(
46             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#000000\"/>"
47             "<g id=\"arrows\" transform=\"rotate(0 11.5 11.5)\">"
48                 "<path id=\"arrow-left\" d=\"m 11.5,14 0,-1 c -1.5,0 -1.5,0 -1.5,-2 l 1,0 -1.5,-2 -1.5,2 1,0 c 0,3 0,3 2.5,3 z\" style=\"fill:#ffffff\"/>"
49                 "<path id=\"arrow-right\" d=\"m 11.5,9 0,1 c 1.5,0 1.5,0 1.5,2 l -1,0 1.5,2 1.5,-2 -1,0 C 14,9 14,9 11.5,9 Z\" style=\"fill:#ffffff\"/>"
50             "</g>"
51         ),
52         QStringLiteral(
53             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#000000\"/>"
54             "<g id=\"exclaim\">"
55                 "<rect id=\"exclaim-top\" x=\"11\" y=\"9\" width=\"1\" height=\"3\" style=\"fill:#ffffff\"/>"
56                 "<rect id=\"exclaim-bottom\" x=\"11\" y=\"13\" width=\"1\" height=\"1\" style=\"fill:#ffffff\"/>"
57             "</g>"
58         ),
59         QStringLiteral(
60             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#000000\"/>"
61             "<g id=\"pause\">"
62                 "<rect id=\"pause-leftbar\" x=\"10\" y=\"9\" width=\"1\" height=\"5\" style=\"fill:#ffffff\"/>"
63                 "<rect id=\"pause-rightbar\" x=\"12\" y=\"9\" width=\"1\" height=\"5\" style=\"fill:#ffffff\"/>"
64             "</g>"
65         ),
66         QStringLiteral(
67             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#27ae60\"/>"
68             "<path style=\"fill:#ffffff;fill-opacity:1;stroke:none\" d=\"m 13.661017,9.2966105 -3,2.9999995 -1,-1 -1,1 1,1 1,1 4,-4 z\"/>"
69         ),
70         QStringLiteral(
71             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#27ae60\"/>"
72             "<g id=\"tick\">"
73                 "<path style=\"opacity:1;fill:#ffffff;fill-opacity:0.98581561;fill-rule:nonzero;stroke:none;stroke-width:1.14997458;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.99954295;stroke-opacity:1;paint-order:normal;\" d=\"m 11.008051,9.1016944 h 1.25 v 5.0000006 h -1.25 z M 9.1330507,10.976695 h 5.0000003 v 1.25 H 9.1330507 Z\"/>"
74             "</g>"
75         ),
76         QStringLiteral(
77             "<circle id=\"bubble\" cx=\"11.5\" cy=\"11.5\" r=\"4.5\" style=\"fill:#000000\"/>"
78             "<g id=\"plus\">"
79                 "<path style=\"fill:#fffff6;fill-opacity:1;stroke:none;stroke-width:0.48022598\" d=\"m 10.771186,8.4407554 c -1.1972026,0 -2.1610164,0.9652542 -2.1610164,2.1610166 0,1.197203 0.9652547,2.161017 2.1610164,2.161017 0.510789,0 0.973102,-0.183061 1.342194,-0.477411 l 1.919966,1.919965 0.339535,-0.339535 -1.919965,-1.919966 c 0.29565,-0.369668 0.479287,-0.832466 0.479287,-1.34407 0,-1.197203 -0.965254,-2.1610166 -2.161017,-2.1610166 z m 0,0.480226 c 0.931159,0 1.680791,0.7496332 1.680791,1.6807906 0,0.931159 -0.749632,1.680791 -1.680791,1.680791 -0.9311583,0 -1.6807905,-0.749632 -1.6807905,-1.680791 0,-0.9311574 0.7496322,-1.6807906 1.6807905,-1.6807906 z\"/>"
80             "</g>"
81         ),
82     };
83     const auto &emblemData = emblems[static_cast<int>(statusEmblem)];
84     return (QStringLiteral(
85       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
86       "<svg xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\">"
87           "<defs>"
88               "<linearGradient id=\"grad\" gradientUnits=\"userSpaceOnUse\" x1=\"8\" y1=\"0\" x2=\"8\" y2=\"16\">"
89                   "<stop offset=\"0\" style=\"stop-color:") % gradientStartColor % QStringLiteral("\"/>"
90                   "<stop offset=\"1\" style=\"stop-color:") % gradientEndColor % QStringLiteral("\"/>"
91               "</linearGradient>"
92               "<mask id=\"bitemask\" maskUnits=\"userSpaceOnUse\">"
93                   "<g>"
94                       "<rect id=\"mask-bg\" x=\"0\" y=\"0\" width=\"16\" height=\"16\" style=\"fill:#ffffff\"/>"
95                       "<circle id=\"mask-subtract\" cx=\"11.5\" cy=\"11.5\" r=\"5.5\" style=\"fill:#000000\"/>"
96                   "</g>"
97               "</mask>"
98           "</defs>"
99           "<g id=\"syncthing-logo\" mask=\"url(#bitemask)\">"
100               "<circle id=\"outer\" cx=\"8\" cy=\"8\" r=\"8\" style=\"fill:url(#grad)\"/>"
101               "<circle id=\"inner\" cx=\"8\" cy=\"7.9727402\" r=\"5.9557071\" style=\"fill:none;stroke:") % strokeColor % QStringLiteral(";stroke-width:0.81771719\"/>"
102               "<line id=\"arm-l\" x1=\"9.1993189\" y1=\"8.776825\" x2=\"2.262351\" y2=\"9.4173737\" style=\"stroke:") % strokeColor % QStringLiteral(";stroke-width:0.81771719\"/>"
103               "<line id=\"arm-tr\" x1=\"9.1993189\" y1=\"8.776825\" x2=\"13.301533\" y2=\"5.3696747\" style=\"stroke:") % strokeColor % QStringLiteral(";stroke-width:0.81771719\"/>"
104               "<line id=\"arm-br\" x1=\"9.1993189\" y1=\"8.776825\" x2=\"11.788756\" y2=\"12.51107\" style=\"stroke:") % strokeColor % QStringLiteral(";stroke-width:0.81771719\"/>"
105               "<circle id=\"node-c\" cx=\"9.1993189\" cy=\"8.776825\" r=\"1.22\" style=\"fill:") % fillColor % QStringLiteral("\"/>"
106               "<circle id=\"node-l\" cx=\"2.262351\" cy=\"9.4173737\" r=\"1.22\" style=\"fill:") % fillColor % QStringLiteral("\"/>"
107               "<circle id=\"node-tr\" cx=\"13.301533\" cy=\"5.3696747\" r=\"1.22\" style=\"fill:") % fillColor % QStringLiteral("\"/>"
108               "<circle id=\"node-br\" cx=\"11.788756\" cy=\"12.51107\" r=\"1.22\" style=\"fill:") % fillColor % QStringLiteral("\"/>"
109           "</g>") %
110           (emblemData.isEmpty() ? QString() : emblemData) % QStringLiteral(
111       "</svg>"
112     )).toUtf8();
113     // clang-format on
114 }
115 
116 /// \cond
117 namespace Detail {
renderSvgImage(const SourceType & source,const QSize & givenSize,int margin)118 template <typename SourceType> QPixmap renderSvgImage(const SourceType &source, const QSize &givenSize, int margin)
119 {
120     const auto scaleFactor =
121 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
122         !QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps) ? 1.0 :
123 #endif
124                                                                    qGuiApp->devicePixelRatio();
125     const auto scaledSize = QSize(givenSize * scaleFactor);
126     auto renderer = QSvgRenderer(source);
127     auto renderSize = QSize(renderer.defaultSize());
128     renderSize.scale(scaledSize.width() - margin, scaledSize.height() - margin, Qt::KeepAspectRatio);
129     auto renderBounds = QRect(QPoint(), scaledSize);
130     if (renderSize.width() < renderBounds.width()) {
131         const auto diff = (renderBounds.width() - renderSize.width()) / 2;
132         renderBounds.setX(diff);
133         renderBounds.setWidth(renderSize.width());
134     }
135     if (renderSize.height() < renderBounds.height()) {
136         const auto diff = (renderBounds.height() - renderSize.height()) / 2;
137         renderBounds.setY(diff);
138         renderBounds.setHeight(renderSize.height());
139     }
140     auto pm = QPixmap(scaledSize);
141     pm.fill(QColor(Qt::transparent));
142     auto painter = QPainter(&pm);
143     renderer.render(&painter, renderBounds);
144     pm.setDevicePixelRatio(scaleFactor);
145     return pm;
146 }
147 } // namespace Detail
148 /// \endcond
149 
150 /*!
151  * \brief Renders an SVG image to a QPixmap.
152  * \remarks If instantiating QIcon directly from SVG image the icon is not displayed in the tray under Plasma 5. It works
153  *          with Tint2, however.
154  */
renderSvgImage(const QString & path,const QSize & size,int margin)155 QPixmap renderSvgImage(const QString &path, const QSize &size, int margin)
156 {
157     return Detail::renderSvgImage(path, size, margin);
158 }
159 
160 /*!
161  * \brief Renders an SVG image to a QPixmap.
162  */
renderSvgImage(const QByteArray & contents,const QSize & size,int margin)163 QPixmap renderSvgImage(const QByteArray &contents, const QSize &size, int margin)
164 {
165     return Detail::renderSvgImage(contents, size, margin);
166 }
167 
168 /*!
169  * \brief Returns the font awesome icon with the specified \a iconName and \a color.
170  */
loadFontAwesomeIcon(const QString & iconName,const QColor & color,bool solid)171 QByteArray loadFontAwesomeIcon(const QString &iconName, const QColor &color, bool solid)
172 {
173     auto result = QByteArray();
174     auto icon = QFile(QString((solid ? QStringLiteral(":/icons/hicolor/scalable/fa/") : QStringLiteral(":/icons/hicolor/scalable/fa-non-solid/"))
175         % iconName % QStringLiteral(".svg")));
176     if (!icon.open(QFile::ReadOnly)) {
177         return result;
178     }
179     result = icon.readAll();
180     const auto pathBegin = result.indexOf("<path ");
181     if (pathBegin > 0) {
182         result.insert(pathBegin + 6, (QStringLiteral("fill=\"") % color.name(QColor::HexRgb) % QStringLiteral("\" ")).toUtf8());
183     }
184     return result;
185 }
186 
StatusIconSettings()187 StatusIconSettings::StatusIconSettings()
188     : defaultColor({ QStringLiteral("#26B6DB"), QStringLiteral("#0882C8"), QStringLiteral("#FFFFFF") })
189     , errorColor({ QStringLiteral("#DB3C26"), QStringLiteral("#C80828"), QStringLiteral("#FFFFFF") })
190     , warningColor({ QStringLiteral("#c9ce3b"), QStringLiteral("#ebb83b"), QStringLiteral("#FFFFFF") })
191     , idleColor({ QStringLiteral("#2D9D69"), QStringLiteral("#2D9D69"), QStringLiteral("#FFFFFF") })
192     , scanningColor({ QStringLiteral("#26B6DB"), QStringLiteral("#0882C8"), QStringLiteral("#FFFFFF") })
193     , synchronizingColor({ QStringLiteral("#26B6DB"), QStringLiteral("#0882C8"), QStringLiteral("#FFFFFF") })
194     , pausedColor({ QStringLiteral("#A9A9A9"), QStringLiteral("#58656C"), QStringLiteral("#FFFFFF") })
195     , disconnectedColor({ QStringLiteral("#A9A9A9"), QStringLiteral("#58656C"), QStringLiteral("#FFFFFF") })
196 {
197 }
198 
StatusIconSettings(StatusIconSettings::DarkTheme)199 StatusIconSettings::StatusIconSettings(StatusIconSettings::DarkTheme)
200     : defaultColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FFFFFFFF") })
201     , errorColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FFFFAEA5") })
202     , warningColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFFFF6A5") })
203     , idleColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFFFFFFF") })
204     , scanningColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFA5EFFF") })
205     , synchronizingColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFA5EFFF") })
206     , pausedColor({ QStringLiteral("#00000000"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFA7A7A7") })
207     , disconnectedColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FFA7A7A7") })
208 {
209 }
210 
StatusIconSettings(StatusIconSettings::BrightTheme)211 StatusIconSettings::StatusIconSettings(StatusIconSettings::BrightTheme)
212     : defaultColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FF000000") })
213     , errorColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFDB3C26") })
214     , warningColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FFC9CE3B") })
215     , idleColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FF000000") })
216     , scanningColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FF26B6DB") })
217     , synchronizingColor({ QStringLiteral("#00000000"), QStringLiteral("#00000000"), QStringLiteral("#FF26B6DB") })
218     , pausedColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFA7A7A7") })
219     , disconnectedColor({ QStringLiteral("#00FFFFFF"), QStringLiteral("#00FFFFFF"), QStringLiteral("#FFA7A7A7") })
220 {
221 }
222 
colorMapping()223 std::vector<StatusIconSettings::ColorMapping> StatusIconSettings::colorMapping()
224 {
225     return std::vector<ColorMapping>({
226         { QCoreApplication::translate("Data::StatusIconSettings", "Misc. notifications"), StatusEmblem::Complete, defaultColor },
227         { QCoreApplication::translate("Data::StatusIconSettings", "Error"), StatusEmblem::Alert, errorColor },
228         { QCoreApplication::translate("Data::StatusIconSettings", "Warning"), StatusEmblem::Alert, warningColor },
229         { QCoreApplication::translate("Data::StatusIconSettings", "Idle"), StatusEmblem::None, idleColor },
230         { QCoreApplication::translate("Data::StatusIconSettings", "Scanning"), StatusEmblem::Scanning, scanningColor },
231         { QCoreApplication::translate("Data::StatusIconSettings", "Synchronizing"), StatusEmblem::Synchronizing, synchronizingColor },
232         { QCoreApplication::translate("Data::StatusIconSettings", "Paused"), StatusEmblem::Paused, pausedColor },
233         { QCoreApplication::translate("Data::StatusIconSettings", "Disconnected"), StatusEmblem::None, disconnectedColor },
234     });
235 }
236 
StatusIconSettings(const QString & str)237 StatusIconSettings::StatusIconSettings(const QString &str)
238     : StatusIconSettings()
239 {
240     const auto parts = QtUtilities::splitRef(str, QChar(';'));
241     int index = 0;
242     for (auto *field :
243         { &defaultColor, &errorColor, &warningColor, &idleColor, &scanningColor, &synchronizingColor, &pausedColor, &disconnectedColor }) {
244         if (index >= parts.size()) {
245             break;
246         }
247         const auto colors = parts[index].split(QChar(','));
248         if (colors.size() >= 2) {
249             field->backgroundStart = colors[0].toString();
250             field->backgroundEnd = colors[1].toString();
251         }
252         if (colors.size() >= 3) {
253             field->foreground = colors[2].toString();
254         }
255         ++index;
256     }
257 }
258 
toString() const259 QString StatusIconSettings::toString() const
260 {
261     QString res;
262     res.reserve(128);
263     for (auto *field :
264         { &defaultColor, &errorColor, &warningColor, &idleColor, &scanningColor, &synchronizingColor, &pausedColor, &disconnectedColor }) {
265         if (!res.isEmpty()) {
266             res += QChar(';');
267         }
268         res += field->backgroundStart.name(QColor::HexArgb) % QChar(',') % field->backgroundEnd.name(QColor::HexArgb) % QChar(',')
269             % field->foreground.name(QColor::HexArgb);
270     }
271     return res;
272 }
273 
StatusIcons(const StatusIconSettings & settings)274 StatusIcons::StatusIcons(const StatusIconSettings &settings)
275     : disconnected(QIcon(renderSvgImage(makeSyncthingIcon(settings.disconnectedColor, StatusEmblem::None), settings.renderSize)))
276     , idling(QIcon(renderSvgImage(makeSyncthingIcon(settings.idleColor, StatusEmblem::None), settings.renderSize)))
277     , scanninig(QIcon(renderSvgImage(makeSyncthingIcon(settings.scanningColor, StatusEmblem::Scanning), settings.renderSize)))
278     , notify(QIcon(renderSvgImage(makeSyncthingIcon(settings.warningColor, StatusEmblem::Alert), settings.renderSize)))
279     , pause(QIcon(renderSvgImage(makeSyncthingIcon(settings.pausedColor, StatusEmblem::Paused), settings.renderSize)))
280     , sync(QIcon(renderSvgImage(makeSyncthingIcon(settings.synchronizingColor, StatusEmblem::Synchronizing), settings.renderSize)))
281     , syncComplete(QIcon(renderSvgImage(makeSyncthingIcon(settings.defaultColor, StatusEmblem::Complete), settings.renderSize)))
282     , error(QIcon(renderSvgImage(makeSyncthingIcon(settings.errorColor, StatusEmblem::Alert), settings.renderSize)))
283     , errorSync(QIcon(renderSvgImage(makeSyncthingIcon(settings.errorColor, StatusEmblem::Synchronizing), settings.renderSize)))
284     , newItem(QIcon(renderSvgImage(makeSyncthingIcon(settings.defaultColor, StatusEmblem::Add), settings.renderSize)))
285     , isValid(true)
286 {
287 }
288 
FontAwesomeIcons(const QColor & color,const QSize & size,int margin)289 FontAwesomeIcons::FontAwesomeIcons(const QColor &color, const QSize &size, int margin)
290     : hashtag(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("hashtag"), color), size, margin))
291     , folderOpen(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("folder-open"), color), size, margin))
292     , globe(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("globe"), color), size, margin))
293     , home(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("home"), color), size, margin))
294     , shareAlt(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("share-alt"), color), size, margin))
295     , refresh(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("redo"), color), size, margin))
296     , clock(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("clock"), color), size, margin))
297     , exchangeAlt(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("exchange-alt"), color), size, margin))
298     , exclamationTriangle(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("exclamation-triangle"), color), size, margin))
299     , cogs(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("cogs"), color), size, margin))
300     , link(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("link"), color), size, margin))
301     , eye(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("eye"), color), size, margin))
302     , fileArchive(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("file-archive"), color), size, margin))
303     , folder(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("folder"), color), size, margin))
304     , certificate(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("certificate"), color), size, margin))
305     , networkWired(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("network-wired"), color), size, margin))
306     , cloudDownloadAlt(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("cloud-download-alt"), color), size, margin))
307     , cloudUploadAlt(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("cloud-upload-alt"), color), size, margin))
308     , tag(renderSvgImage(loadFontAwesomeIcon(QStringLiteral("tag"), color), size, margin))
309 {
310 }
311 
IconManager()312 IconManager::IconManager()
313     : m_statusIcons()
314     , m_trayIcons(m_statusIcons)
315     , m_fontAwesomeIconsForLightTheme(QColor(10, 10, 10), QSize(64, 64), 8)
316     , m_fontAwesomeIconsForDarkTheme(Qt::white, QSize(64, 64), 8)
317 {
318 }
319 
instance()320 IconManager &IconManager::instance()
321 {
322     static IconManager iconManager;
323     return iconManager;
324 }
325 
326 } // namespace Data
327