3#include "resources/config.h"
7#include <QGuiApplication>
11#include <QPaintDevice>
13#include <QPainterPath>
24 void setIcon(
const QIcon &icon);
25 void addIconName(
const QString &iconName);
26 const QIcon &locateIcon();
29 QStringList iconNames;
33void IconOverride::setIcon(
const QIcon &icon)
39void IconOverride::addIconName(
const QString &iconName)
41 iconNames.append(iconName);
42 if (!cachedIcon.isNull()) {
47const QIcon &IconOverride::locateIcon()
49 if (!cachedIcon.isNull()) {
52 for (
const auto &iconName : std::as_const(iconNames)) {
53 cachedIcon = QIcon::fromTheme(iconName);
54 if (!cachedIcon.isNull()) {
61struct Renderer::InternalData {
62 explicit InternalData(
const QString &fontFilePath);
63 explicit InternalData(
const QByteArray &fontData);
66 QHash<QChar, IconOverride> overrides;
67 QPaintDevice *paintDevice;
71Renderer::InternalData::InternalData(
const QString &fontFilePath)
72 : fontFilePath(fontFilePath)
73 , paintDevice(nullptr)
74 , rawFont(fontFilePath, 12)
78Renderer::InternalData::InternalData(
const QByteArray &fontData)
79 : paintDevice(nullptr)
80 , rawFont(fontData, 12)
97 : m_d(std::make_unique<InternalData>(fontFileName.isEmpty() ? QStringLiteral(
":/" META_FONT_FILE_NAME) : fontFileName))
105 : m_d(std::make_unique<InternalData>(fontData))
122 return m_d->fontFilePath;
131 const auto &path = m_d->fontFilePath;
132 if (!path.isEmpty() && !QFile::exists(path)) {
133 qWarning() <<
"ForkAwesome font file does not exist under:" << path;
135 qWarning() <<
"Unable to load ForkAwesome font from " << (path.isEmpty() ? QStringLiteral(
"buffer") : path);
142Renderer::operator bool()
const
144 return m_d->rawFont.isValid();
150static constexpr auto renderMargins = QMargins(1, 1, 1, 1);
153static void renderInternally(QChar character, QPainter *painter,
const QRawFont &rawFont,
const QRect &rect,
const QColor &color)
156 auto font = QRawFont(rawFont);
157 font.setPixelSize(rect.height());
160 const auto glyphIndexes = font.glyphIndexesForString(QString(character));
161 if (glyphIndexes.isEmpty()) {
164 const auto glyphPath = rawFont.pathForGlyph(glyphIndexes.first());
165 const auto glyphBounds = glyphPath.boundingRect();
166 if (glyphBounds.isEmpty()) {
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);
181 painter->fillPath(scaledPath, color);
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);
197 renderInternally(character, painter, m_d->rawFont, rect, color);
204QPixmap
Renderer::pixmap(QChar icon,
const QSize &size,
const QColor &color, qreal scaleFactor)
const
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);
212 if (!
static_cast<bool>(scaleFactor)) {
214#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
215 !QCoreApplication::testAttribute(Qt::AA_UseHighDpiPixmaps)
219 (m_d->paintDevice ? m_d->paintDevice->devicePixelRatioF() : qGuiApp->devicePixelRatio());
222 const auto scaledSize = QSize(size * scaleFactor);
223 auto pm = QPixmap(scaledSize);
224 pm.fill(QColor(Qt::transparent));
226 auto painter = QPainter(&pm);
227 painter.setRenderHint(QPainter::Antialiasing);
228 renderInternally(icon, &painter, m_d->rawFont, QRect(QPoint(), scaledSize), color);
230 pm.setDevicePixelRatio(scaleFactor);
252 return pixmap(icon, size, color, 0.0);
273 m_d->overrides[character].addIconName(iconNameInTheme);
281 m_d->overrides[character].setIcon(
override);
289 m_d->overrides.clear();
300 m_d->paintDevice = paintDevice;
308 static auto globalRenderer =
Renderer();
309 return globalRenderer;
Renderer(const QString &fontFileName=QString())
Constructs a new renderer with the given fontFileName.
static Renderer & global()
Returns the global instance (which is currently only used by the icon engine plugin).
const QString & fontFilePath() const
Returns the path of the font file.
void clearOverrides()
Clears all overrides added via addThemeOverride() or addOverride().
void addThemeOverride(QChar character, const QString &iconNameInTheme)
Uses the icon from the current icon theme obtained via QIcon::fromTheme() for character if it exists.
void warnIfInvalid() const
Prints a warning using qWarning() if no font could be loaded.
void addOverride(QChar character, const QIcon &override)
Uses the specified override icon for character if it is not null.
QPixmap pixmap(QChar icon, const QSize &size, const QColor &color, qreal scaleFactor) const
Renders the specified character as pixmap of the specified size.
void setAssociatedPaintDevice(QPaintDevice *paintDevice)
Sets the associated paintDevice.
~Renderer()
Destructs the renderer.
void render(QChar character, QPainter *painter, const QRect &rect, const QColor &color) const
Renders the specified icon using the specified painter.
Contains classes provided by the QtForkAwesome library.
Icon
The Icon enum specifies a ForkAwesome icon for use with QtForkAwesome::Renderer::render().
std::remove_reference_t< decltype(QChar().unicode())> IconBaseType