From 60784c47d9f2acb6bbe38c9b871e73278b2108bc Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Sun, 11 Jan 2026 19:28:31 +0100 Subject: [PATCH] Tentative implementation of font handling on cpp side. --- app/app.pro | 6 +- app/fontlistmodel.cpp | 94 ++++++ app/fontlistmodel.h | 59 ++++ app/fontmanager.cpp | 524 +++++++++++++++++++++++++++++++ app/fontmanager.h | 110 +++++++ app/main.cpp | 11 +- app/monospacefontmanager.cpp | 50 --- app/monospacefontmanager.h | 20 -- app/qml/ApplicationSettings.qml | 124 +------- app/qml/BurnInEffect.qml | 12 +- app/qml/PreprocessedTerminal.qml | 23 +- app/qml/SettingsTerminalTab.qml | 2 +- app/qml/resources.qrc | 1 - 13 files changed, 827 insertions(+), 209 deletions(-) create mode 100644 app/fontlistmodel.cpp create mode 100644 app/fontlistmodel.h create mode 100644 app/fontmanager.cpp create mode 100644 app/fontmanager.h delete mode 100644 app/monospacefontmanager.cpp delete mode 100644 app/monospacefontmanager.h diff --git a/app/app.pro b/app/app.pro index 18a6d6e..0ba5954 100644 --- a/app/app.pro +++ b/app/app.pro @@ -16,11 +16,13 @@ DESTDIR = $$OUT_PWD/../ HEADERS += \ fileio.h \ - monospacefontmanager.h + fontmanager.h \ + fontlistmodel.h SOURCES += main.cpp \ fileio.cpp \ - monospacefontmanager.cpp + fontmanager.cpp \ + fontlistmodel.cpp macx:ICON = icons/crt.icns diff --git a/app/fontlistmodel.cpp b/app/fontlistmodel.cpp new file mode 100644 index 0000000..4d176c8 --- /dev/null +++ b/app/fontlistmodel.cpp @@ -0,0 +1,94 @@ +#include "fontlistmodel.h" + +FontListModel::FontListModel(QObject *parent) + : QAbstractListModel(parent) +{ +} + +int FontListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) { + return 0; + } + return m_fonts.size(); +} + +QVariant FontListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_fonts.size()) { + return QVariant(); + } + + const FontEntry &font = m_fonts.at(index.row()); + + switch (role) { + case NameRole: + return font.name; + case TextRole: + return font.text; + case SourceRole: + return font.source; + case BaseWidthRole: + return font.baseWidth; + case PixelSizeRole: + return font.pixelSize; + case LowResolutionRole: + return font.lowResolutionFont; + case IsSystemRole: + return font.isSystemFont; + case FamilyRole: + return font.family; + case FallbackNameRole: + return font.fallbackName; + default: + return QVariant(); + } +} + +QHash FontListModel::roleNames() const +{ + QHash roles; + roles[NameRole] = "name"; + roles[TextRole] = "text"; + roles[SourceRole] = "source"; + roles[BaseWidthRole] = "baseWidth"; + roles[PixelSizeRole] = "pixelSize"; + roles[LowResolutionRole] = "lowResolutionFont"; + roles[IsSystemRole] = "isSystemFont"; + roles[FamilyRole] = "family"; + roles[FallbackNameRole] = "fallbackName"; + return roles; +} + +void FontListModel::setFonts(const QVector &fonts) +{ + beginResetModel(); + m_fonts = fonts; + endResetModel(); + emit countChanged(); +} + +const QVector &FontListModel::fonts() const +{ + return m_fonts; +} + +QVariantMap FontListModel::get(int index) const +{ + QVariantMap map; + if (index < 0 || index >= m_fonts.size()) { + return map; + } + + const FontEntry &font = m_fonts.at(index); + map.insert("name", font.name); + map.insert("text", font.text); + map.insert("source", font.source); + map.insert("baseWidth", font.baseWidth); + map.insert("pixelSize", font.pixelSize); + map.insert("lowResolutionFont", font.lowResolutionFont); + map.insert("isSystemFont", font.isSystemFont); + map.insert("family", font.family); + map.insert("fallbackName", font.fallbackName); + return map; +} diff --git a/app/fontlistmodel.h b/app/fontlistmodel.h new file mode 100644 index 0000000..00fda4c --- /dev/null +++ b/app/fontlistmodel.h @@ -0,0 +1,59 @@ +#ifndef FONTLISTMODEL_H +#define FONTLISTMODEL_H + +#include +#include +#include +#include +#include + +struct FontEntry +{ + QString name; + QString text; + QString source; + qreal baseWidth = 1.0; + int pixelSize = 0; + bool lowResolutionFont = false; + bool isSystemFont = false; + QString family; + QString fallbackName; +}; + +class FontListModel : public QAbstractListModel +{ + Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + +public: + explicit FontListModel(QObject *parent = nullptr); + + enum Roles { + NameRole = Qt::UserRole + 1, + TextRole, + SourceRole, + BaseWidthRole, + PixelSizeRole, + LowResolutionRole, + IsSystemRole, + FamilyRole, + FallbackNameRole + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash roleNames() const override; + + void setFonts(const QVector &fonts); + const QVector &fonts() const; + + Q_INVOKABLE QVariantMap get(int index) const; + +signals: + void countChanged(); + +private: + QVector m_fonts; +}; + +#endif // FONTLISTMODEL_H diff --git a/app/fontmanager.cpp b/app/fontmanager.cpp new file mode 100644 index 0000000..759ed84 --- /dev/null +++ b/app/fontmanager.cpp @@ -0,0 +1,524 @@ +#include "fontmanager.h" + +#include +#include +#include + +namespace { +constexpr int kModernRasterization = 4; +constexpr int kBaseFontPixelHeight = 32; +constexpr int kSystemFontPixelSize = 30; +} + +FontManager::FontManager(QObject *parent) + : QObject(parent) + , m_fontListModel(this) + , m_filteredFontListModel(this) +{ + populateBundledFonts(); + populateSystemFonts(); + m_fontListModel.setFonts(m_allFonts); + updateFilteredFonts(); + updateComputedFont(); +} + +QStringList FontManager::retrieveMonospaceFonts() +{ + QStringList result; + + QFontDatabase fontDatabase; + const QStringList fontFamilies = fontDatabase.families(); + + for (const QString &fontFamily : fontFamilies) { + QFont font(fontFamily); + if (fontDatabase.isFixedPitch(font.family())) { + result.append(fontFamily); + } + } + + return result; +} + +void FontManager::refresh() +{ + updateFilteredFonts(); + updateComputedFont(); +} + +FontListModel *FontManager::fontList() +{ + return &m_fontListModel; +} + +FontListModel *FontManager::filteredFontList() +{ + return &m_filteredFontListModel; +} + +int FontManager::fontSource() const +{ + return m_fontSource; +} + +void FontManager::setFontSource(int fontSource) +{ + if (m_fontSource == fontSource) { + return; + } + m_fontSource = fontSource; + emit fontSourceChanged(); + updateFilteredFonts(); + updateComputedFont(); +} + +int FontManager::rasterization() const +{ + return m_rasterization; +} + +void FontManager::setRasterization(int rasterization) +{ + if (m_rasterization == rasterization) { + return; + } + m_rasterization = rasterization; + emit rasterizationChanged(); + updateFilteredFonts(); + updateComputedFont(); +} + +QString FontManager::fontName() const +{ + return m_fontName; +} + +void FontManager::setFontName(const QString &fontName) +{ + if (m_fontName == fontName) { + return; + } + m_fontName = fontName; + emit fontNameChanged(); + updateFilteredFonts(); + updateComputedFont(); +} + +qreal FontManager::fontScaling() const +{ + return m_fontScaling; +} + +void FontManager::setFontScaling(qreal fontScaling) +{ + if (qFuzzyCompare(m_fontScaling, fontScaling)) { + return; + } + m_fontScaling = fontScaling; + emit fontScalingChanged(); + updateComputedFont(); +} + +qreal FontManager::fontWidth() const +{ + return m_fontWidth; +} + +void FontManager::setFontWidth(qreal fontWidth) +{ + if (qFuzzyCompare(m_fontWidth, fontWidth)) { + return; + } + m_fontWidth = fontWidth; + emit fontWidthChanged(); + updateComputedFont(); +} + +qreal FontManager::lineSpacing() const +{ + return m_lineSpacing; +} + +void FontManager::setLineSpacing(qreal lineSpacing) +{ + if (qFuzzyCompare(m_lineSpacing, lineSpacing)) { + return; + } + m_lineSpacing = lineSpacing; + emit lineSpacingChanged(); + updateComputedFont(); +} + +qreal FontManager::baseFontScaling() const +{ + return m_baseFontScaling; +} + +void FontManager::setBaseFontScaling(qreal baseFontScaling) +{ + if (qFuzzyCompare(m_baseFontScaling, baseFontScaling)) { + return; + } + m_baseFontScaling = baseFontScaling; + emit baseFontScalingChanged(); + updateComputedFont(); +} + +bool FontManager::lowResolutionFont() const +{ + return m_lowResolutionFont; +} + +void FontManager::setFontSubstitutions(const QString &family, const QStringList &substitutes) +{ + if (family.isEmpty()) { + return; + } + + QFont::removeSubstitutions(family); + + if (substitutes.isEmpty()) { + return; + } + + QFont::insertSubstitutions(family, substitutes); +} + +void FontManager::removeFontSubstitution(const QString &family) +{ + if (family.isEmpty()) { + return; + } + + QFont::removeSubstitutions(family); +} + +void FontManager::populateBundledFonts() +{ + m_allFonts.clear(); + + addBundledFont( + "TERMINUS_SCALED", + "Terminus", + ":/fonts/terminus/TerminusTTF-4.49.3.ttf", + 1.0, + 12, + true); + addBundledFont( + "EXCELSIOR_SCALED", + "Fixedsys Excelsior", + ":/fonts/fixedsys-excelsior/FSEX301-L2.ttf", + 1.0, + 16, + true, + "UNSCII_16_SCALED"); + addBundledFont( + "GREYBEARD_SCALED", + "Greybeard", + ":/fonts/greybeard/Greybeard-16px.ttf", + 1.0, + 16, + true, + "UNSCII_16_SCALED"); + addBundledFont( + "COMMODORE_PET_SCALED", + "Commodore PET", + ":/fonts/pet-me/PetMe.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "COZETTE_SCALED", + "Cozette", + ":/fonts/cozette/CozetteVector.ttf", + 1.0, + 13, + true); + addBundledFont( + "UNSCII_8_SCALED", + "Unscii 8", + ":/fonts/unscii/unscii-8.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "UNSCII_8_THIN_SCALED", + "Unscii 8 Thin", + ":/fonts/unscii/unscii-8-thin.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "UNSCII_16_SCALED", + "Unscii 16", + ":/fonts/unscii/unscii-16-full.ttf", + 1.0, + 16, + true, + "UNSCII_16_SCALED"); + addBundledFont( + "APPLE_II_SCALED", + "Apple ][", + ":/fonts/apple2/PrintChar21.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "ATARI_400_SCALED", + "Atari 400-800", + ":/fonts/atari-400-800/AtariClassic-Regular.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "COMMODORE_64_SCALED", + "Commodore 64", + ":/fonts/pet-me/PetMe64.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "IBM_EGA_8x8", + "IBM EGA 8x8", + ":/fonts/oldschool-pc-fonts/PxPlus_IBM_EGA_8x8.ttf", + 0.5, + 8, + true, + "UNSCII_8_SCALED"); + addBundledFont( + "IBM_VGA_8x16", + "IBM VGA 8x16", + ":/fonts/oldschool-pc-fonts/PxPlus_IBM_VGA_8x16.ttf", + 1.0, + 16, + true, + "UNSCII_16_SCALED"); + + addBundledFont( + "TERMINUS", + "Terminus", + ":/fonts/terminus/TerminusTTF-4.49.3.ttf", + 1.0, + 32, + false); + addBundledFont( + "HACK", + "Hack", + ":/fonts/hack/Hack-Regular.ttf", + 1.0, + 32, + false); + addBundledFont( + "FIRA_CODE", + "Fira Code", + ":/fonts/fira-code/FiraCode-Medium.ttf", + 1.0, + 32, + false); + addBundledFont( + "IOSEVKA", + "Iosevka", + ":/fonts/iosevka/IosevkaTerm-ExtendedMedium.ttf", + 1.0, + 32, + false); + addBundledFont( + "JETBRAINS_MONO", + "JetBrains Mono", + ":/fonts/jetbrains-mono/JetBrainsMono-Medium.ttf", + 1.0, + 32, + false); + addBundledFont( + "IBM_3278", + "IBM 3278", + ":/fonts/ibm-3278/3270-Regular.ttf", + 1.0, + 32, + false); +} + +void FontManager::addBundledFont(const QString &name, + const QString &text, + const QString &source, + qreal baseWidth, + int pixelSize, + bool lowResolutionFont, + const QString &fallbackName) +{ + FontEntry entry; + entry.name = name; + entry.text = text; + entry.source = source; + entry.baseWidth = baseWidth; + entry.pixelSize = pixelSize; + entry.lowResolutionFont = lowResolutionFont; + entry.isSystemFont = false; + entry.fallbackName = fallbackName; + entry.family = resolveFontFamily(source); + m_allFonts.append(entry); +} + +void FontManager::populateSystemFonts() +{ + const QStringList families = retrieveMonospaceFonts(); + for (const QString &family : families) { + if (m_bundledFamilies.contains(family)) { + continue; + } + FontEntry entry; + entry.name = family; + entry.text = family; + entry.source = QString(); + entry.baseWidth = 1.0; + entry.pixelSize = kSystemFontPixelSize; + entry.lowResolutionFont = false; + entry.isSystemFont = true; + entry.family = family; + m_allFonts.append(entry); + } +} + +void FontManager::updateFilteredFonts() +{ + QVector filtered; + bool fontNameFound = false; + const bool modernMode = (m_rasterization == kModernRasterization); + + for (const FontEntry &font : m_allFonts) { + const bool isBundled = !font.isSystemFont; + const bool matchesSource = (m_fontSource == 0 && isBundled) + || (m_fontSource == 1 && font.isSystemFont); + + if (!matchesSource) { + continue; + } + + const bool matchesRasterization = font.isSystemFont + || (modernMode == !font.lowResolutionFont); + + if (!matchesRasterization) { + continue; + } + + filtered.append(font); + if (font.name == m_fontName) { + fontNameFound = true; + } + } + + if (!fontNameFound && !filtered.isEmpty()) { + if (m_fontName != filtered.first().name) { + m_fontName = filtered.first().name; + emit fontNameChanged(); + } + } + + m_filteredFontListModel.setFonts(filtered); + emit filteredFontListChanged(); +} + +void FontManager::updateComputedFont() +{ + const FontEntry *font = findFontByName(m_fontName); + if (!font) { + const QVector &filteredFonts = m_filteredFontListModel.fonts(); + if (!filteredFonts.isEmpty()) { + font = &filteredFonts.first(); + } + } + + if (!font) { + return; + } + + const qreal totalFontScaling = m_baseFontScaling * m_fontScaling; + const qreal targetPixelHeight = kBaseFontPixelHeight * totalFontScaling; + const qreal lineSpacingFactor = m_lineSpacing; + + const int lineSpacing = qRound(targetPixelHeight * lineSpacingFactor); + const int pixelSize = font->lowResolutionFont + ? font->pixelSize + : static_cast(targetPixelHeight); + + const qreal nativeLineHeight = font->pixelSize + qRound(font->pixelSize * lineSpacingFactor); + const qreal targetLineHeight = targetPixelHeight + lineSpacing; + const qreal screenScaling = font->lowResolutionFont + ? (nativeLineHeight > 0 ? targetLineHeight / nativeLineHeight : 1.0) + : 1.0; + + const qreal fontWidth = font->baseWidth * m_fontWidth; + + QString fontFamily = font->family.isEmpty() ? font->name : font->family; + QString fallbackFontFamily; + + if (!font->fallbackName.isEmpty() && font->fallbackName != font->name) { + const FontEntry *fallback = findFontByName(font->fallbackName); + if (fallback) { + fallbackFontFamily = fallback->family.isEmpty() ? fallback->name : fallback->family; + } + } + + QStringList fallbackChain; + if (!fallbackFontFamily.isEmpty()) { + fallbackChain.append(fallbackFontFamily); + } +#if defined(Q_OS_MAC) + fallbackChain.append(QStringLiteral("Menlo")); +#else + fallbackChain.append(QStringLiteral("Monospace")); +#endif + setFontSubstitutions(fontFamily, fallbackChain); + + if (m_lowResolutionFont != font->lowResolutionFont) { + m_lowResolutionFont = font->lowResolutionFont; + emit lowResolutionFontChanged(); + } + + emit terminalFontChanged(fontFamily, + pixelSize, + lineSpacing, + screenScaling, + fontWidth, + fallbackFontFamily, + font->lowResolutionFont); +} + +const FontEntry *FontManager::findFontByName(const QString &name) const +{ + for (const FontEntry &font : m_allFonts) { + if (font.name == name) { + return &font; + } + } + return nullptr; +} + +QString FontManager::resolveFontFamily(const QString &sourcePath) +{ + const auto cached = m_loadedFamilies.constFind(sourcePath); + if (cached != m_loadedFamilies.constEnd()) { + return cached.value(); + } + + const int fontId = QFontDatabase::addApplicationFont(sourcePath); + QString family; + if (fontId != -1) { + const QStringList families = QFontDatabase::applicationFontFamilies(fontId); + if (!families.isEmpty()) { + family = families.first(); + } + } + + if (!family.isEmpty()) { + m_bundledFamilies.insert(family); + } + + m_loadedFamilies.insert(sourcePath, family); + return family; +} diff --git a/app/fontmanager.h b/app/fontmanager.h new file mode 100644 index 0000000..eca8354 --- /dev/null +++ b/app/fontmanager.h @@ -0,0 +1,110 @@ +#ifndef FONTMANAGER_H +#define FONTMANAGER_H + +#include +#include +#include +#include + +#include "fontlistmodel.h" + +class FontManager : public QObject +{ + Q_OBJECT + Q_PROPERTY(FontListModel *fontList READ fontList CONSTANT) + Q_PROPERTY(FontListModel *filteredFontList READ filteredFontList NOTIFY filteredFontListChanged) + Q_PROPERTY(int fontSource READ fontSource WRITE setFontSource NOTIFY fontSourceChanged) + Q_PROPERTY(int rasterization READ rasterization WRITE setRasterization NOTIFY rasterizationChanged) + Q_PROPERTY(QString fontName READ fontName WRITE setFontName NOTIFY fontNameChanged) + Q_PROPERTY(qreal fontScaling READ fontScaling WRITE setFontScaling NOTIFY fontScalingChanged) + Q_PROPERTY(qreal fontWidth READ fontWidth WRITE setFontWidth NOTIFY fontWidthChanged) + Q_PROPERTY(qreal lineSpacing READ lineSpacing WRITE setLineSpacing NOTIFY lineSpacingChanged) + Q_PROPERTY(qreal baseFontScaling READ baseFontScaling WRITE setBaseFontScaling NOTIFY baseFontScalingChanged) + Q_PROPERTY(bool lowResolutionFont READ lowResolutionFont NOTIFY lowResolutionFontChanged) + +public: + explicit FontManager(QObject *parent = nullptr); + + Q_INVOKABLE void refresh(); + + FontListModel *fontList(); + FontListModel *filteredFontList(); + + int fontSource() const; + void setFontSource(int fontSource); + + int rasterization() const; + void setRasterization(int rasterization); + + QString fontName() const; + void setFontName(const QString &fontName); + + qreal fontScaling() const; + void setFontScaling(qreal fontScaling); + + qreal fontWidth() const; + void setFontWidth(qreal fontWidth); + + qreal lineSpacing() const; + void setLineSpacing(qreal lineSpacing); + + qreal baseFontScaling() const; + void setBaseFontScaling(qreal baseFontScaling); + + bool lowResolutionFont() const; + +signals: + void fontSourceChanged(); + void rasterizationChanged(); + void fontNameChanged(); + void fontScalingChanged(); + void fontWidthChanged(); + void lineSpacingChanged(); + void baseFontScalingChanged(); + void lowResolutionFontChanged(); + void filteredFontListChanged(); + + void terminalFontChanged(QString fontFamily, + int pixelSize, + int lineSpacing, + qreal screenScaling, + qreal fontWidth, + QString fallbackFontFamily, + bool lowResolutionFont); + +private: + QStringList retrieveMonospaceFonts(); + void populateBundledFonts(); + void populateSystemFonts(); + void addBundledFont(const QString &name, + const QString &text, + const QString &source, + qreal baseWidth, + int pixelSize, + bool lowResolutionFont, + const QString &fallbackName = QString()); + void setFontSubstitutions(const QString &family, const QStringList &substitutes); + void removeFontSubstitution(const QString &family); + void updateFilteredFonts(); + void updateComputedFont(); + const FontEntry *findFontByName(const QString &name) const; + QString resolveFontFamily(const QString &sourcePath); + + FontListModel m_fontListModel; + FontListModel m_filteredFontListModel; + QVector m_allFonts; + + int m_fontSource = 0; + int m_rasterization = 0; + QString m_fontName = QStringLiteral("TERMINUS_SCALED"); + qreal m_fontScaling = 1.0; + qreal m_fontWidth = 1.0; + qreal m_lineSpacing = 0.1; + qreal m_baseFontScaling = 0.75; + bool m_lowResolutionFont = false; + + QHash m_loadedFamilies; + QSet m_bundledFamilies; +}; + +#endif // FONTMANAGER_H diff --git a/app/main.cpp b/app/main.cpp index a9a8eac..2c580b3 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -7,17 +7,18 @@ #include #include #include +#include #include #include #include -#include #include #include -#include +#include +#include #if defined(Q_OS_MAC) #include @@ -97,7 +98,9 @@ int main(int argc, char *argv[]) QQmlApplicationEngine engine; FileIO fileIO; - MonospaceFontManager monospaceFontManager; + + qmlRegisterType("CoolRetroTerm", 1, 0, "FontManager"); + qmlRegisterUncreatableType("CoolRetroTerm", 1, 0, "FontListModel", "FontListModel is created by FontManager"); #if !defined(Q_OS_MAC) app.setWindowIcon(QIcon::fromTheme("cool-retro-term", QIcon(":../icons/32x32/cool-retro-term.png"))); @@ -124,8 +127,6 @@ int main(int argc, char *argv[]) engine.rootContext()->setContextProperty("workdir", getNamedArgument(args, "--workdir", "$HOME")); engine.rootContext()->setContextProperty("fileIO", &fileIO); - engine.rootContext()->setContextProperty("monospaceFontManager", &monospaceFontManager); - engine.rootContext()->setContextProperty("monospaceSystemFonts", monospaceFontManager.retrieveMonospaceFonts()); // Manage import paths for Linux and OSX. QStringList importPathList = engine.importPathList(); diff --git a/app/monospacefontmanager.cpp b/app/monospacefontmanager.cpp deleted file mode 100644 index 9ca9eef..0000000 --- a/app/monospacefontmanager.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "monospacefontmanager.h" - -#include -#include - -MonospaceFontManager::MonospaceFontManager(QObject *parent) : QObject(parent) -{ - -} - -QStringList MonospaceFontManager::retrieveMonospaceFonts() { - QStringList result; - - QFontDatabase fontDatabase; - QStringList fontFamilies = fontDatabase.families(); - - for (int i = 0; i < fontFamilies.size(); i++) { - QString fontFamily = fontFamilies[i]; - QFont font(fontFamily); - if (fontDatabase.isFixedPitch(font.family())) { - result.append(fontFamily); - } - } - - return result; -} - -void MonospaceFontManager::setFontSubstitutions(const QString &family, const QStringList &substitutes) -{ - if (family.isEmpty()) { - return; - } - - QFont::removeSubstitutions(family); - - if (substitutes.isEmpty()) { - return; - } - - QFont::insertSubstitutions(family, substitutes); -} - -void MonospaceFontManager::removeFontSubstitution(const QString &family) -{ - if (family.isEmpty()) { - return; - } - - QFont::removeSubstitutions(family); -} diff --git a/app/monospacefontmanager.h b/app/monospacefontmanager.h deleted file mode 100644 index 2e25782..0000000 --- a/app/monospacefontmanager.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef MONOSPACEFONTMANAGER_H -#define MONOSPACEFONTMANAGER_H - -#include -#include -#include - -class MonospaceFontManager : public QObject -{ - Q_OBJECT -public: - explicit MonospaceFontManager(QObject *parent = nullptr); - Q_INVOKABLE QStringList retrieveMonospaceFonts(); - -public slots: - Q_INVOKABLE void setFontSubstitutions(const QString &family, const QStringList &substitutes); - void removeFontSubstitution(const QString &family); -}; - -#endif // MONOSPACEFONTMANAGER_H diff --git a/app/qml/ApplicationSettings.qml b/app/qml/ApplicationSettings.qml index adc1c05..ff14171 100644 --- a/app/qml/ApplicationSettings.qml +++ b/app/qml/ApplicationSettings.qml @@ -19,6 +19,7 @@ *******************************************************************************/ import QtQuick 2.2 import QtQuick.Controls 2.0 +import CoolRetroTerm 1.0 import "utils.js" as Utils @@ -60,7 +61,6 @@ QtObject { property bool blinkingCursor: false - onWindowScalingChanged: updateFont() // PROFILE SETTINGS /////////////////////////////////////////////////////// property real windowOpacity: 1.0 @@ -113,133 +113,33 @@ QtObject { readonly property int subpixel_rasterization: 3 readonly property int modern_rasterization: 4 - property int rasterization: no_rasterization + property alias rasterization: fontManager.rasterization readonly property int bundled_fonts: 0 readonly property int system_fonts: 1 - property int fontSource: bundled_fonts + property alias fontSource: fontManager.fontSource // FONTS ////////////////////////////////////////////////////////////////// readonly property real baseFontScaling: 0.75 - property real fontScaling: 1.0 + property alias fontScaling: fontManager.fontScaling property real totalFontScaling: baseFontScaling * fontScaling - property real fontWidth: 1.0 - property real lineSpacing: 0.1 + property alias fontWidth: fontManager.fontWidth + property alias lineSpacing: fontManager.lineSpacing - property bool lowResolutionFont: false + property alias lowResolutionFont: fontManager.lowResolutionFont - property string fontName: "TERMINUS_SCALED" - property var fontlist: fontManager.item ? fontManager.item.fontlist : null + property alias fontName: fontManager.fontName + property alias filteredFontList: fontManager.filteredFontList - property var filteredFontList: ListModel {} - - function updateFont() { - if (!fontManager.item || !fontlist) return - - filteredFontList.clear() - var currentFontInList = false - - for (var i = 0; i < fontlist.count; i++) { - var font = fontlist.get(i) - var isBundled = !font.isSystemFont - var isSystem = font.isSystemFont - - var matchesSource = (fontSource === bundled_fonts && isBundled) || (fontSource === system_fonts && isSystem) - - if (!matchesSource) continue - - var modernMode = rasterization === modern_rasterization - var matchesRasterization = font.isSystemFont || (modernMode == !font.lowResolutionFont) - - if (matchesRasterization) { - filteredFontList.append(font) - if (font.name === fontName) { - currentFontInList = true - } - } - } - - if (!currentFontInList && filteredFontList.count > 0) { - fontName = filteredFontList.get(0).name - } - - var index = getIndexByName(fontName) - if (index === undefined) return - - fontManager.item.selectedFontIndex = index - fontManager.item.scaling = totalFontScaling - - var fontSourcePath = fontManager.item.source - var pixelSize = fontManager.item.pixelSize - var lineSpacing = fontManager.item.lineSpacing - var screenScaling = fontManager.item.screenScaling - var fontWidth = (fontManager.item.baseWidth ?? 1.0) * appSettings.fontWidth - var fontFamily = fontManager.item.family - var isSystemFont = fontManager.item.isSystemFont - var lowResolutionFont = fontManager.item.lowResolutionFont; - var fallbackFontFamily = "" - - appSettings.lowResolutionFont = fontManager.item.lowResolutionFont - - if (!isSystemFont) { - fontLoader.source = fontSourcePath - fontFamily = fontLoader.name - } - - fallbackFontLoader.source = "" - var fallbackName = fontManager.item.fallbackName - if (fallbackName && fallbackName !== fontName) { - var fallbackFont = getFontByName(fallbackName) - if (fallbackFont) { - fallbackFontLoader.source = fallbackFont.source - fallbackFontFamily = fallbackFontLoader.name - } - } - - terminalFontChanged(fontFamily, pixelSize, lineSpacing, screenScaling, fontWidth, fallbackFontFamily, lowResolutionFont) + property FontManager fontManager: FontManager { + id: fontManager + baseFontScaling: baseFontScaling } - onFontSourceChanged: updateFont() - onRasterizationChanged: updateFont() - onFontNameChanged: updateFont() - - signal terminalFontChanged(string fontFamily, int pixelSize, int lineSpacing, real screenScaling, real fontWidth, string fallbackFontFamily, bool lowResolutionFont) - signal initializedSettings - property Loader fontManager: Loader { - source: "Fonts.qml" - onLoaded: updateFont() - } - - property FontLoader fontLoader: FontLoader {} - property FontLoader fallbackFontLoader: FontLoader {} - - onTotalFontScalingChanged: updateFont() - onFontWidthChanged: updateFont() - onLineSpacingChanged: updateFont() - - function getIndexByName(name) { - for (var i = 0; i < fontlist.count; i++) { - var requestedName = fontlist.get(i).name - if (name === requestedName) - return i - } - return 0 // If the font is not available default to 0. - } - - function getFontByName(name) { - for (var i = 0; i < fontlist.count; i++) { - var font = fontlist.get(i) - if (name === font.name) { - return font - } - } - return null - } - function incrementScaling() { fontScaling = Math.min(fontScaling + 0.05, maximumFontScaling) } diff --git a/app/qml/BurnInEffect.qml b/app/qml/BurnInEffect.qml index 88a6966..ea73568 100644 --- a/app/qml/BurnInEffect.qml +++ b/app/qml/BurnInEffect.qml @@ -81,6 +81,14 @@ Loader { } } // Restart blurred source settings change. + Connections { + target: appSettings.fontManager + + onTerminalFontChanged: { + burnInEffect.restartBlurSource() + } + } + Connections { target: appSettings @@ -88,10 +96,6 @@ Loader { burnInEffect.restartBlurSource() } - onTerminalFontChanged: { - burnInEffect.restartBlurSource() - } - onRasterizationChanged: { burnInEffect.restartBlurSource() } diff --git a/app/qml/PreprocessedTerminal.qml b/app/qml/PreprocessedTerminal.qml index 814f103..02cb722 100644 --- a/app/qml/PreprocessedTerminal.qml +++ b/app/qml/PreprocessedTerminal.qml @@ -148,29 +148,24 @@ Item{ } function handleFontChanged(fontFamily, pixelSize, lineSpacing, screenScaling, fontWidth, fallbackFontFamily, lowResolutionFont) { - var updatedFont = Qt.font({ + kterminal.font = Qt.font({ family: fontFamily, pixelSize: pixelSize }); - if (!updatedFont) { - return; - } - - kterminal.font = updatedFont; - terminalContainer.fontWidth = fontWidth; terminalContainer.screenScaling = screenScaling; scaleTexture = Math.max(1.0, Math.floor(screenScaling * appSettings.windowScaling)); kterminal.lineSpacing = lineSpacing; + } - var fallbackChain = []; - if (fallbackFontFamily && fallbackFontFamily.length > 0) { - fallbackChain.push(fallbackFontFamily); + Connections { + target: appSettings + + onWindowScalingChanged: { + scaleTexture = Math.max(1.0, Math.floor(terminalContainer.screenScaling * appSettings.windowScaling)); } - fallbackChain.push(appSettings.isMacOS ? "Menlo" : "Monospace"); - monospaceFontManager.setFontSubstitutions(fontFamily, fallbackChain); } function startSession() { @@ -194,8 +189,8 @@ Item{ forceActiveFocus(); } Component.onCompleted: { - appSettings.terminalFontChanged.connect(handleFontChanged); - appSettings.updateFont() + appSettings.fontManager.terminalFontChanged.connect(handleFontChanged); + appSettings.fontManager.refresh() startSession(); } } diff --git a/app/qml/SettingsTerminalTab.qml b/app/qml/SettingsTerminalTab.qml index e7cc746..c76831d 100644 --- a/app/qml/SettingsTerminalTab.qml +++ b/app/qml/SettingsTerminalTab.qml @@ -104,7 +104,7 @@ ColumnLayout { currentIndex = 0 } Connections { - target: appSettings + target: appSettings.fontManager onTerminalFontChanged: { fontChanger.updateIndex() diff --git a/app/qml/resources.qrc b/app/qml/resources.qrc index d442895..089bf54 100644 --- a/app/qml/resources.qrc +++ b/app/qml/resources.qrc @@ -6,7 +6,6 @@ ApplicationSettings.qml SettingsWindow.qml TerminalWindow.qml - Fonts.qml SettingsGeneralTab.qml PreprocessedTerminal.qml TimeManager.qml