Heavy changes

This commit is contained in:
Stefano Moretti
2023-04-21 18:07:17 +02:00
parent 32a567a950
commit 11606b8f39
52 changed files with 1578 additions and 748 deletions

View File

@ -1,41 +1,23 @@
#include <BaseUI/core.h>
#include <QCoreApplication>
#include <QQmlEngine>
#include <QQuickStyle>
#include <QDebug>
#include "icons.h"
static void initialize(QQmlEngine *engine)
{
#ifdef BASEUI_EMBED_QML
Q_INIT_RESOURCE(baseui_qml);
engine->addImportPath(":/imports");
#endif
QString path = "/BaseUI/icons/";
#ifdef BASEUI_EMBED_ICONS
Q_INIT_RESOURCE(baseui_icons);
path = ":/imports" + path;
#else
path = QCoreApplication::applicationDirPath() + path;
#endif
Icons::registerIcons(engine, path);
}
namespace BaseUI
{
void init(QQmlEngine *engine)
{
QQuickStyle::setStyle("Material");
initialize(engine);
qmlRegisterSingletonType<Icons>("BaseUI", 1, 0, "Icons", Icons::singletonProvider);
Icons::instance = std::make_unique<Icons>();
#ifdef BASEUI_INCLUDE_ICONS
QString path = ":/baseui/imports/BaseUI/icons/";
BaseUI::Icons::registerIcons(engine, path + "MaterialIcons-Regular.ttf",
"Material Icons", path + "codepoints.json");
#endif
engine->addImportPath(":/baseui/imports");
}
}

View File

@ -9,21 +9,29 @@
#include <QJsonObject>
#include <QPainter>
#include <QFontMetrics>
#include <QVariantMap>
class IconProvider : public QQuickImageProvider
{
public:
explicit IconProvider(const QString &family, const QString &codesPath)
IconProvider(const QString &family, const QVariantMap &codes)
: QQuickImageProvider(QQuickImageProvider::Image)
, codepoints(codes)
, font(family)
{
}
IconProvider(const QString &family, const QString &codesPath)
: QQuickImageProvider(QQuickImageProvider::Image)
, font(family)
{
QFile file(codesPath);
if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
auto jd = QJsonDocument::fromJson(file.readAll());
if (!jd.isNull())
codepoints = jd.object();
else
QJsonDocument jd = QJsonDocument::fromJson(file.readAll());
if (jd.isNull())
qWarning() << "Invalid codepoints JSON file" << codesPath;
else
codepoints = jd.object().toVariantMap();
} else {
qWarning() << "Cannot open icon codes file" << codesPath;
qWarning() << file.errorString();
@ -44,22 +52,13 @@ public:
if (size)
*size = QSize(width, height);
#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
QStringList args = id.split(",", QString::SkipEmptyParts);
#else
QStringList args = id.split(",", Qt::SkipEmptyParts);
#endif
QString iconChar("?");
if (!args.isEmpty()) {
QString name = args.takeFirst();
if (codepoints.value(name).isUndefined())
qWarning() << "Icon name" << name << "not found in" << font.family();
else
iconChar = codepoints[name].toString();
} else {
if (id.isEmpty())
qWarning() << "Icon name empty";
}
else if (codepoints.value(id).isNull())
qWarning() << "Icon name" << id << "not found in" << font.family();
else
iconChar = codepoints[id].toString();
font.setPixelSize(width < height ? width : height);
@ -72,29 +71,6 @@ public:
image.fill(Qt::transparent);
QPainter painter(&image);
for (const QString &arg : args) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
QStringList attr = arg.split("=", QString::SkipEmptyParts);
#else
QStringList attr = arg.split("=", Qt::SkipEmptyParts);
#endif
if (attr.isEmpty() || attr.size() > 2) {
qWarning() << "Argument" << arg << "not valid.";
} else if (attr[0] == "color") {
if (attr.size() == 2)
painter.setPen(attr[1]);
else
qWarning() << "Attribute color needs a value";
} else if (attr[0] == "hflip") {
painter.setTransform(QTransform(-1, 0, 0, 0, 1, 0, width, 0, 1));
} else if (attr[0] == "vflip") {
painter.setTransform(QTransform(1, 0, 0, 0, -1, 0, 0, height, 1));
} else {
qWarning() << "Unknown attribute" << attr;
}
}
painter.setFont(font);
painter.drawText(QRect(0, 0, width, height), Qt::AlignCenter, iconChar);
@ -104,7 +80,7 @@ public:
QStringList keys() { return codepoints.keys(); }
private:
QJsonObject codepoints;
QVariantMap codepoints;
QFont font;
};

View File

@ -1,55 +1,52 @@
#include "icons.h"
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QVariant>
#include <QQmlEngine>
#include <QFontDatabase>
#include <QColor>
#include <QVariantHash>
#include "iconprovider.h"
namespace BaseUI
{
Icons::Icons(QObject *parent)
: QQmlPropertyMap(this, parent)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
QJSEngine::setObjectOwnership(this, QJSEngine::CppOwnership);
}
Icons *Icons::instance()
{
static Icons instance_;
return &instance_;
}
QObject *Icons::singletonProvider(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
{
Q_UNUSED(qmlEngine)
Q_UNUSED(jsEngine)
return instance();
}
void Icons::registerIcons(QQmlEngine *engine, const QString &path)
void Icons::registerIcons(QQmlEngine *engine, const QString &fontPath,
const QString &fontName, const QVariantMap &codes)
{
QString iconProviderName = "baseui_icons";
if (QFontDatabase::addApplicationFont(path + "MaterialIcons-Regular.ttf") == -1)
qWarning() << "Failed to load font Material";
auto iconProvider = new IconProvider("Material Icons", path + "codepoints.json");
if (QFontDatabase::addApplicationFont(fontPath) == -1)
qWarning() << "Failed to load font:" << fontPath;
auto iconProvider = new IconProvider(fontName, codes);
engine->addImageProvider(iconProviderName, iconProvider);
#if (QT_VERSION < QT_VERSION_CHECK(6, 1, 0))
for (const QString &key : iconProvider->keys())
instance()->insert(key, QVariant("image://" + iconProviderName + "/" + key + ","));
#else
QVariantHash hash;
for (const QString &key : iconProvider->keys())
hash.insert(key, QVariant("image://" + iconProviderName + "/" + key + ","));
instance()->insert(hash);
#endif
hash.insert(key, QVariant("image://" + iconProviderName + "/" + key));
instance->insert(hash);
}
void Icons::registerIcons(QQmlEngine *engine, const QString &fontPath,
const QString &fontName, const QString &codesPath)
{
QString iconProviderName = "baseui_icons";
if (QFontDatabase::addApplicationFont(fontPath) == -1)
qWarning() << "Failed to load font:" << fontPath;
auto iconProvider = new IconProvider(fontName, codesPath);
engine->addImageProvider(iconProviderName, iconProvider);
QVariantHash hash;
for (const QString &key : iconProvider->keys())
hash.insert(key, QVariant("image://" + iconProviderName + "/" + key));
instance->insert(hash);
}
}

View File

@ -1,10 +1,13 @@
#ifndef ICONS_H
#define ICONS_H
#ifndef BASEUI_ICONS_H
#define BASEUI_ICONS_H
#include <QQmlEngine>
#include <QQmlPropertyMap>
class QQmlEngine;
class QJSEngine;
#include <memory>
namespace BaseUI
{
class Icons : public QQmlPropertyMap
{
@ -13,11 +16,13 @@ class Icons : public QQmlPropertyMap
public:
Icons(QObject *parent = nullptr);
static Icons *instance();
static QObject *singletonProvider(QQmlEngine *qmlEngine, QJSEngine *jsEngine);
inline static std::unique_ptr<Icons> instance;
static void registerIcons(QQmlEngine *engine, const QString &path);
static void registerIcons(QQmlEngine *engine, const QString &fontPath,
const QString &fontName, const QVariantMap &codes);
static void registerIcons(QQmlEngine *engine, const QString &fontPath,
const QString &fontName, const QString &codesPath);
protected:
template <typename DerivedType>
explicit Icons(DerivedType *derived, QObject *parent = nullptr)
@ -25,4 +30,35 @@ protected:
{}
};
struct IconsForeign
{
Q_GADGET
QML_FOREIGN(Icons)
QML_SINGLETON
QML_NAMED_ELEMENT(Icons)
public:
static Icons *create(QQmlEngine *, QJSEngine *engine)
{
// The instance has to exist before it is used. We cannot replace it.
Q_ASSERT(Icons::instance);
// The engine has to have the same thread affinity as the singleton.
Q_ASSERT(engine->thread() == Icons::instance->thread());
// There can only be one engine accessing the singleton.
if (s_engine)
Q_ASSERT(engine == s_engine);
else
s_engine = engine;
return Icons::instance.get();
}
private:
inline static QJSEngine *s_engine = nullptr;
};
}
#endif

12
src/plugin.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef BASEUI_PLUGIN_H
#define BASEUI_PLUGIN_H
#include <QtQml/QQmlEngineExtensionPlugin>
class BaseUIPlugin : public QQmlEngineExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
};
#endif