Freeciv21
Develop your civilization from humble roots to a global empire
icons.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2020 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 #include "icons.h"
12 // Qt
13 #include <QApplication>
14 #include <QIcon>
15 #include <QIconEngine>
16 #include <QPainter>
17 #include <QPalette>
18 #include <QSvgRenderer>
19 #include <QWidget>
20 
21 // utility
22 #include "shared.h"
23 
24 QString current_theme;
25 fcIcons *fcIcons::m_instance = nullptr;
26 hIcon *hIcon::m_instance = nullptr;
27 
31 fcIcons::fcIcons() = default;
32 
37 {
38  if (!m_instance) {
39  m_instance = new fcIcons;
40  }
41  return m_instance;
42 }
43 
48 {
49  delete m_instance;
50  m_instance = nullptr;
51 }
52 
53 namespace {
54 
60 class icon_engine : public QIconEngine {
61 public:
62  explicit icon_engine(const QString &path) : path(path) {}
63 
64  icon_engine *clone() const override { return new icon_engine(path); }
65 
66  void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode,
67  QIcon::State state) override
68  {
69  // For now, only use one color variant for icons.
70  Q_UNUSED(mode)
71  Q_UNUSED(state)
72 
73  if (rect.width() <= 0 || rect.height() <= 0) {
74  return;
75  }
76 
77  auto col = QApplication::palette().color(QPalette::ButtonText);
78  if (auto widget = dynamic_cast<QWidget *>(painter->device()); widget) {
79  col = widget->palette().color(QPalette::ButtonText);
80  }
81  QString key = path + "-" + QString::number(rect.width()) + "-"
82  + QString::number(rect.height()) + "-" + col.name();
83  QPixmap pix;
84  if (!QPixmapCache::find(key, &pix)) {
85  pix = QPixmap(rect.width(), rect.height());
86  pix.fill(Qt::transparent);
87  if (!path.isEmpty()) {
88  QSvgRenderer renderer;
89  QFile f(path);
90  QByteArray bytes;
91  if (f.open(QIODevice::ReadOnly)) {
92  bytes = f.readAll();
93  }
94  if (!bytes.isEmpty()) {
95  bytes.replace("\"#000\"",
96  QStringLiteral("\"%1\"").arg(col.name()).toLatin1());
97  }
98  renderer.load(bytes);
99  QPainter p(&pix);
100  renderer.render(&p, QRect(0, 0, rect.width(), rect.height()));
101  }
102  QPixmapCache::insert(key, pix);
103  }
104  painter->drawPixmap(rect, pix);
105  }
106 
107  QPixmap pixmap(const QSize &size, QIcon::Mode mode,
108  QIcon::State state) override
109  {
110  QPixmap pix(size);
111  pix.fill(Qt::transparent);
112  QPainter painter(&pix);
113  paint(&painter, QRect(QPoint(0, 0), size), mode, state);
114  return pix;
115  }
116 
117 private:
118  QString path;
119 };
120 } // namespace
121 
125 QIcon fcIcons::getIcon(const QString &id)
126 {
127  QIcon icon;
128 
129  // Try custom icon from theme.
130  icon.addFile(fileinfoname(
131  get_data_dirs(),
132  qUtf8Printable(
133  QStringLiteral("themes/%1/%2.svg").arg(current_theme, id))));
134  if (!icon.isNull()) {
135  return icon;
136  }
137 
138  // Try SVG from icons dir.
139  QString path = fileinfoname(
140  get_data_dirs(),
141  qUtf8Printable(QStringLiteral("themes/icons/%1.svg").arg(id)));
142  if (!path.isEmpty()) {
143  // Special icon engine for theme colorization.
144  return QIcon(new icon_engine(path));
145  }
146 
147  // Fall back to PNG.
148  icon.addFile(fileinfoname(
149  get_data_dirs(),
150  qUtf8Printable(
151  QStringLiteral("themes/%1/%2.png").arg(current_theme, id))));
152  if (!icon.isNull()) {
153  return icon;
154  }
155 
156  icon.addFile(fileinfoname(
157  get_data_dirs(),
158  qUtf8Printable(QStringLiteral("themes/icons/%1.png").arg(id))));
159 
160  return icon;
161 }
162 
166 QPixmap *fcIcons::getPixmap(const QString &id)
167 {
168  QPixmap *pm;
169  bool status;
170  QString str;
171  QByteArray png_bytes;
172 
173  pm = new QPixmap;
174  if (QPixmapCache::find(id, pm)) {
175  return pm;
176  }
177  str = QStringLiteral("themes/");
178  png_bytes = QString(str + current_theme + "/" + id + ".png").toLocal8Bit();
179  status = pm->load(fileinfoname(get_data_dirs(), png_bytes.data()));
180 
181  if (!status) {
182  str = str + "icons/";
183  png_bytes = QString(str + id + ".png").toLocal8Bit();
184  pm->load(fileinfoname(get_data_dirs(), png_bytes.data()));
185  }
186  QPixmapCache::insert(id, *pm);
187 
188  return pm;
189 }
190 
194 QString fcIcons::getPath(const QString &id)
195 {
196  QString str;
197  QByteArray png_bytes;
198 
199  str = QStringLiteral("themes/icons/");
200  png_bytes = QString(str + id + ".png").toLocal8Bit();
201 
202  return fileinfoname(get_data_dirs(), png_bytes.data());
203 }
204 
206 {
207  if (!m_instance) {
208  m_instance = new hIcon;
210  }
211  return m_instance;
212 }
213 
215 {
216  delete m_instance;
217  m_instance = nullptr;
218 }
219 
221 {
222  hash.insert(QStringLiteral("prodplus"),
223  fcIcons::instance()->getIcon(QStringLiteral("hprod")));
224  hash.insert(QStringLiteral("foodplus"),
225  fcIcons::instance()->getIcon(QStringLiteral("hfood")));
226  hash.insert(QStringLiteral("tradeplus"),
227  fcIcons::instance()->getIcon(QStringLiteral("htrade")));
228  hash.insert(QStringLiteral("gold"),
229  fcIcons::instance()->getIcon(QStringLiteral("hgold")));
230  hash.insert(QStringLiteral("science"),
231  fcIcons::instance()->getIcon(QStringLiteral("hsci")));
232  hash.insert(QStringLiteral("resize"),
233  fcIcons::instance()->getIcon(QStringLiteral("resize")));
234 }
235 
236 QIcon hIcon::get(const QString &id) { return hash.value(id, QIcon()); }
Definition: icons.h:17
QIcon getIcon(const QString &id)
Returns icon by given name.
Definition: icons.cpp:125
QPixmap * getPixmap(const QString &id)
Returns pixmap by given name, pixmap needs to be deleted by someone else.
Definition: icons.cpp:166
static fcIcons * m_instance
Definition: icons.h:22
QString getPath(const QString &id)
Returns path for icon.
Definition: icons.cpp:194
static fcIcons * instance()
Returns instance of fc_icons.
Definition: icons.cpp:36
fcIcons()
Icon provider constructor.
static void drop()
Deletes fc_icons instance.
Definition: icons.cpp:47
Definition: icons.h:33
static void drop()
Definition: icons.cpp:214
hIcon()=default
void createIcons()
Definition: icons.cpp:220
QHash< QString, QIcon > hash
Definition: icons.h:40
static hIcon * m_instance
Definition: icons.h:38
static hIcon * i()
Definition: icons.cpp:205
QIcon get(const QString &id)
Definition: icons.cpp:236
QString current_theme
Definition: icons.cpp:24
const QStringList & get_data_dirs()
Returns a list of data directory paths, in the order in which they should be searched.
Definition: shared.cpp:533
QString fileinfoname(const QStringList &dirs, const QString &filename)
Returns a filename to access the specified file from a directory by searching all specified directori...
Definition: shared.cpp:661
size_t size
Definition: specvec.h:64