Qt ForkAwesome: renderer.cpp Source File

Qt ForkAwesome 0.3.4 Library that bundles ForkAwesome for use within Qt applications

Loading...
Searching...
No Matches
renderer.cpp
Go to the documentation of this file.
1#include "./renderer.h"
2
3#include "resources/config.h"
4
5#include <QDebug>
6#include <QFile>
7#include <QGuiApplication>
8#include <QHash>
9#include <QIcon>
10#include <QMargins>
11#include <QPaintDevice>
12#include <QPainter>
13#include <QPainterPath>
14#include <QRawFont>
15
16#include <utility>
17
19namespace QtForkAwesome {
20
22
23struct IconOverride {
24 void setIcon(const QIcon &icon);
25 void addIconName(const QString &iconName);
26 const QIcon &locateIcon();
27
28private:
29 QStringList iconNames;
30 QIcon cachedIcon;
31};
32
33void IconOverride::setIcon(const QIcon &icon)
34{
35 iconNames.clear();
36 cachedIcon = icon;
37}
38
39void IconOverride::addIconName(const QString &iconName)
40{
41 iconNames.append(iconName);
42 if (!cachedIcon.isNull()) {
43 cachedIcon = QIcon();
44 }
45}
46
47const QIcon &IconOverride::locateIcon()
48{
49 if (!cachedIcon.isNull()) {
50 return cachedIcon;
51 }
52 for (const auto &iconName : std::as_const(iconNames)) {
53 cachedIcon = QIcon::fromTheme(iconName);
54 if (!cachedIcon.isNull()) {
55 return cachedIcon;
56 }
57 }
58 return cachedIcon;
59}
60
61struct Renderer::InternalData {
62 explicit InternalData(const QString &fontFilePath);
63 explicit InternalData(const QByteArray &fontData);
64
65 QString fontFilePath;
66 QHash<QChar, IconOverride> overrides;
67 QPaintDevice *paintDevice;
68 QRawFont rawFont;
69};
70
71Renderer::InternalData::InternalData(const QString &fontFilePath)
72 : fontFilePath(fontFilePath)
73 , paintDevice(nullptr)
74 , rawFont(fontFilePath, 12)
75{
76}
77
78Renderer::InternalData::InternalData(const QByteArray &fontData)
79 : paintDevice(nullptr)
80 , rawFont(fontData, 12)
81{
82}
83
85
91
96Renderer::Renderer(const QString &fontFileName)
97 : m_d(std::make_unique<InternalData>(fontFileName.isEmpty() ? QStringLiteral(":/" META_FONT_FILE_NAME) : fontFileName))
98{
99}
100
104 Renderer::Renderer(const QByteArray &fontData)
105 : m_d(std::make_unique<InternalData>(fontData))
106{
107}
108
112Renderer::~Renderer()
113{
114}
115
120 const QString &Renderer::fontFilePath() const
121{
122 return m_d->fontFilePath;
123}
124
128 void Renderer::warnIfInvalid() const
129{
130 if (!*this) {
131 const auto &path = m_d->fontFilePath;
132 if (!path.isEmpty() && !QFile::exists(path)) {
133 qWarning() << "ForkAwesome font file does not exist under:" << path;
134 }
135 qWarning() << "Unable to load ForkAwesome font from " << (path.isEmpty() ? QStringLiteral("buffer") : path);
136 }
137}
138
142Renderer::operator bool() const
143{
144 return m_d->rawFont.isValid();
145}
146
150static constexpr auto renderMargins = QMargins(1, 1, 1, 1);
151
153static void renderInternally(QChar character, QPainter *painter, const QRawFont &rawFont, const QRect &rect, const QColor &color)
154{
155 // create a new font to set the size according to the height of rect
156 auto font = QRawFont(rawFont);
157 font.setPixelSize(rect.height());
158
159 // compute the glyph index and the path and bounds of the glyph
160 const auto glyphIndexes = font.glyphIndexesForString(QString(character));
161 if (glyphIndexes.isEmpty()) {
162 return;
163 }
164 const auto glyphPath = rawFont.pathForGlyph(glyphIndexes.first());
165 const auto glyphBounds = glyphPath.boundingRect();
166 if (glyphBounds.isEmpty()) {
167 return;
168 }
169
170 // scale the path to render it centered within rect keeping the aspect ratio
171 const auto rectWithMargins = rect - renderMargins;
172 const auto scaleX = rectWithMargins.width() / glyphBounds.width();
173 const auto scaleY = rectWithMargins.height() / glyphBounds.height();
174 const auto scale = qMin(scaleX, scaleY);
175 const auto rectCenter = rectWithMargins.center();
176 const auto glyphBoundsCenter = glyphBounds.center();
177 const auto dx = rectCenter.x() - (glyphBoundsCenter.x() * scale);
178 const auto dy = rectCenter.y() - (glyphBoundsCenter.y() * scale);
179 const auto scaledPath = QTransform().translate(dx, dy).scale(scale, scale).map(glyphPath);
180
181 painter->fillPath(scaledPath, color);
182}
184
188 void QtForkAwesome::Renderer::render(QChar character, QPainter *painter, const QRect &rect, const QColor &color) const
189{
190 if (auto override = m_d->overrides.find(character); override != m_d->overrides.end()) {
191 if (const auto &overrideIcon = override->locateIcon(); !overrideIcon.isNull()) {
192 overrideIcon.paint(painter, rect, Qt::AlignCenter, QIcon::Normal, QIcon::On);
193 return;
194 }
195 }
196 if (*this) {
197 renderInternally(character, painter, m_d->rawFont, rect, color);
198 }
199}
200
204QPixmap Renderer::pixmap(QChar icon, const QSize &size, const QColor &color, qreal scaleFactor) const
205{
206 if (auto override = m_d->overrides.find(icon); override != m_d->overrides.end()) {
207 if (const auto &overrideIcon = override->locateIcon(); !overrideIcon.isNull()) {
208 return overrideIcon.pixmap(size, QIcon::Normal, QIcon::On);
209 }
210 }
211
212 if (!static_cast<bool>(scaleFactor)) {
213 scaleFactor =
214#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
215 !QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps)
216 ? 1.0
217 :
218#endif
219 (m_d->paintDevice ? m_d->paintDevice->devicePixelRatioF() : qGuiApp->devicePixelRatio());
220 }
221
222 const auto scaledSize = QSize(size * scaleFactor);
223 auto pm = QPixmap(scaledSize);
224 pm.fill(QColor(Qt::transparent));
225 if (*this) {
226 auto painter = QPainter(&pm);
227 painter.setRenderHint(QPainter::Antialiasing);
228 renderInternally(icon, &painter, m_d->rawFont, QRect(QPoint(), scaledSize), color);
229 }
230 pm.setDevicePixelRatio(scaleFactor);
231 return pm;
232}
233
237QPixmap Renderer::pixmap(Icon icon, const QSize &size, const QColor &color, qreal scaleFactor) const
238{
239 return pixmap(QChar(static_cast<IconBaseType>(icon)), size, color, scaleFactor);
240}
241
250QPixmap QtForkAwesome::Renderer::pixmap(QChar icon, const QSize &size, const QColor &color) const
251{
252 return pixmap(icon, size, color, 0.0);
253}
254
263QPixmap Renderer::pixmap(Icon icon, const QSize &size, const QColor &color) const
264{
265 return pixmap(QChar(static_cast<IconBaseType>(icon)), size, color, 0.0);
266}
267
271 void Renderer::addThemeOverride(QChar character, const QString &iconNameInTheme)
272{
273 m_d->overrides[character].addIconName(iconNameInTheme);
274}
275
279 void Renderer::addOverride(QChar character, const QIcon &override)
280{
281 m_d->overrides[character].setIcon(override);
282}
283
287 void Renderer::clearOverrides()
288{
289 m_d->overrides.clear();
290}
291
298 void Renderer::setAssociatedPaintDevice(QPaintDevice *paintDevice)
299{
300 m_d->paintDevice = paintDevice;
301}
302
306 Renderer &Renderer::global()
307{
308 static auto globalRenderer = Renderer();
309 return globalRenderer;
310}
311
312} // namespace QtForkAwesome
QtForkAwesome::Renderer::Renderer
Renderer(const QString &fontFileName=QString())
Constructs a new renderer with the given fontFileName.
Definition renderer.cpp:96
QtForkAwesome::Renderer::global
static Renderer & global()
Returns the global instance (which is currently only used by the icon engine plugin).
Definition renderer.cpp:306
QtForkAwesome::Renderer::fontFilePath
const QString & fontFilePath() const
Returns the path of the font file.
Definition renderer.cpp:120
QtForkAwesome::Renderer::clearOverrides
void clearOverrides()
Clears all overrides added via addThemeOverride() or addOverride().
Definition renderer.cpp:287
QtForkAwesome::Renderer::addThemeOverride
void addThemeOverride(QChar character, const QString &iconNameInTheme)
Uses the icon from the current icon theme obtained via QIcon::fromTheme() for character if it exists.
Definition renderer.cpp:271
QtForkAwesome::Renderer::warnIfInvalid
void warnIfInvalid() const
Prints a warning using qWarning() if no font could be loaded.
Definition renderer.cpp:128
QtForkAwesome::Renderer::addOverride
void addOverride(QChar character, const QIcon &override)
Uses the specified override icon for character if it is not null.
Definition renderer.cpp:279
QtForkAwesome::Renderer::pixmap
QPixmap pixmap(QChar icon, const QSize &size, const QColor &color, qreal scaleFactor) const
Renders the specified character as pixmap of the specified size.
Definition renderer.cpp:204
QtForkAwesome::Renderer::setAssociatedPaintDevice
void setAssociatedPaintDevice(QPaintDevice *paintDevice)
Sets the associated paintDevice.
Definition renderer.cpp:298
QtForkAwesome::Renderer::~Renderer
~Renderer()
Destructs the renderer.
Definition renderer.cpp:112
QtForkAwesome::Renderer::render
void render(QChar character, QPainter *painter, const QRect &rect, const QColor &color) const
Renders the specified icon using the specified painter.
Definition renderer.cpp:188
QtForkAwesome
Contains classes provided by the QtForkAwesome library.
Definition renderer.h:20
QtForkAwesome::Icon
Icon
The Icon enum specifies a ForkAwesome icon for use with QtForkAwesome::Renderer::render().
Definition icon.h:11
QtForkAwesome::IconBaseType
std::remove_reference_t< decltype(QChar().unicode())> IconBaseType
Definition iconfwd.h:10
renderer.h