File indexing completed on 2025-02-02 04:11:27

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "font_delegate.hpp"
0008 
0009 #include <QPainter>
0010 
0011 using namespace glaxnimate::gui;
0012 using namespace glaxnimate;
0013 
0014 static QFontDatabase::WritingSystem writingSystemFromScript(QLocale::Script script)
0015 {
0016     switch (script) {
0017     case QLocale::ArabicScript:
0018         return QFontDatabase::Arabic;
0019     case QLocale::CyrillicScript:
0020         return QFontDatabase::Cyrillic;
0021     case QLocale::GurmukhiScript:
0022         return QFontDatabase::Gurmukhi;
0023     case QLocale::SimplifiedHanScript:
0024         return QFontDatabase::SimplifiedChinese;
0025     case QLocale::TraditionalHanScript:
0026         return QFontDatabase::TraditionalChinese;
0027     case QLocale::LatinScript:
0028         return QFontDatabase::Latin;
0029     case QLocale::ArmenianScript:
0030         return QFontDatabase::Armenian;
0031     case QLocale::BengaliScript:
0032         return QFontDatabase::Bengali;
0033     case QLocale::DevanagariScript:
0034         return QFontDatabase::Devanagari;
0035     case QLocale::GeorgianScript:
0036         return QFontDatabase::Georgian;
0037     case QLocale::GreekScript:
0038         return QFontDatabase::Greek;
0039     case QLocale::GujaratiScript:
0040         return QFontDatabase::Gujarati;
0041     case QLocale::HebrewScript:
0042         return QFontDatabase::Hebrew;
0043     case QLocale::JapaneseScript:
0044         return QFontDatabase::Japanese;
0045     case QLocale::KhmerScript:
0046         return QFontDatabase::Khmer;
0047     case QLocale::KannadaScript:
0048         return QFontDatabase::Kannada;
0049     case QLocale::KoreanScript:
0050         return QFontDatabase::Korean;
0051     case QLocale::LaoScript:
0052         return QFontDatabase::Lao;
0053     case QLocale::MalayalamScript:
0054         return QFontDatabase::Malayalam;
0055     case QLocale::MyanmarScript:
0056         return QFontDatabase::Myanmar;
0057     case QLocale::TamilScript:
0058         return QFontDatabase::Tamil;
0059     case QLocale::TeluguScript:
0060         return QFontDatabase::Telugu;
0061     case QLocale::ThaanaScript:
0062         return QFontDatabase::Thaana;
0063     case QLocale::ThaiScript:
0064         return QFontDatabase::Thai;
0065     case QLocale::TibetanScript:
0066         return QFontDatabase::Tibetan;
0067     case QLocale::SinhalaScript:
0068         return QFontDatabase::Sinhala;
0069     case QLocale::SyriacScript:
0070         return QFontDatabase::Syriac;
0071     case QLocale::OriyaScript:
0072         return QFontDatabase::Oriya;
0073     case QLocale::OghamScript:
0074         return QFontDatabase::Ogham;
0075     case QLocale::RunicScript:
0076         return QFontDatabase::Runic;
0077     case QLocale::NkoScript:
0078         return QFontDatabase::Nko;
0079     default:
0080         return QFontDatabase::Any;
0081     }
0082 }
0083 static QFontDatabase::WritingSystem writingSystemFromLocale()
0084 {
0085     QStringList uiLanguages = QLocale::system().uiLanguages();
0086     QLocale::Script script;
0087     if (!uiLanguages.isEmpty())
0088         script = QLocale(uiLanguages.at(0)).script();
0089     else
0090         script = QLocale::system().script();
0091 
0092     return writingSystemFromScript(script);
0093 }
0094 
0095 static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin)
0096 {
0097 #if QT_VERSION_MAJOR < 6
0098     QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase().writingSystems(font.family());
0099 #else
0100     QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase::writingSystems(font.family());
0101 #endif
0102 
0103     // this just confuses the algorithm below. Vietnamese is Latin with lots of special chars
0104     writingSystems.removeOne(QFontDatabase::Vietnamese);
0105     *hasLatin = writingSystems.removeOne(QFontDatabase::Latin);
0106 
0107     if (writingSystems.isEmpty())
0108         return QFontDatabase::Any;
0109 
0110     QFontDatabase::WritingSystem system = writingSystemFromLocale();
0111 
0112     if (writingSystems.contains(system))
0113         return system;
0114 
0115     if (system == QFontDatabase::TraditionalChinese
0116             && writingSystems.contains(QFontDatabase::SimplifiedChinese)) {
0117         return QFontDatabase::SimplifiedChinese;
0118     }
0119 
0120     if (system == QFontDatabase::SimplifiedChinese
0121             && writingSystems.contains(QFontDatabase::TraditionalChinese)) {
0122         return QFontDatabase::TraditionalChinese;
0123     }
0124 
0125     system = writingSystems.constLast();
0126 
0127     if (!*hasLatin) {
0128         // we need to show something
0129         return system;
0130     }
0131 
0132     if (writingSystems.count() == 1 && system > QFontDatabase::Cyrillic)
0133         return system;
0134 
0135     if (writingSystems.count() <= 2 && system > QFontDatabase::Armenian && system < QFontDatabase::Vietnamese)
0136         return system;
0137 
0138     if (writingSystems.count() <= 5 && system >= QFontDatabase::SimplifiedChinese && system <= QFontDatabase::Korean)
0139         return system;
0140 
0141     return QFontDatabase::Any;
0142 }
0143 
0144 
0145 
0146 font::FontDelegate::FontDelegate(QObject *parent)
0147     : QAbstractItemDelegate(parent),
0148 //       truetype(QStringLiteral(":/qt-project.org/styles/commonstyle/images/fonttruetype-16.png")),
0149 //       bitmap(QStringLiteral(":/qt-project.org/styles/commonstyle/images/fontbitmap-16.png")),
0150       writingSystem(QFontDatabase::Any)
0151 {
0152 }
0153 
0154 
0155 void font::FontDelegate::paint(QPainter *painter,
0156                                 const QStyleOptionViewItem &option,
0157                                 const QModelIndex &index) const
0158 {
0159     QString text = index.data(Qt::DisplayRole).toString();
0160     QFont font(option.font);
0161     font.setPointSize(QFontInfo(font).pointSize() * 3 / 2);
0162     QFont font2 = font;
0163     font2.setFamily(text);
0164 
0165     bool hasLatin;
0166     QFontDatabase::WritingSystem system = writingSystemForFont(font2, &hasLatin);
0167     if (hasLatin)
0168         font = font2;
0169 
0170     QRect r = option.rect;
0171 
0172     if (option.state & QStyle::State_Selected) {
0173         painter->save();
0174         painter->setBrush(option.palette.highlight());
0175         painter->setPen(Qt::NoPen);
0176         painter->drawRect(option.rect);
0177         painter->setPen(QPen(option.palette.highlightedText(), 0));
0178     }
0179 
0180     /*
0181     const QIcon *icon = &bitmap;
0182     if (QFontDatabase().isSmoothlyScalable(text)) {
0183         icon = &truetype;
0184     }
0185     const QSize actualSize = icon->actualSize(r.size());
0186     const QRect iconRect = QStyle::alignedRect(option.direction, option.displayAlignment,
0187                                                actualSize, r);
0188     icon->paint(painter, iconRect, Qt::AlignLeft|Qt::AlignVCenter);
0189     if (option.direction == Qt::RightToLeft)
0190         r.setRight(r.right() - actualSize.width() - 4);
0191     else
0192         r.setLeft(r.left() + actualSize.width() + 4);
0193 */
0194     QFont old = painter->font();
0195     painter->setFont(font);
0196 
0197     const Qt::Alignment textAlign = QStyle::visualAlignment(option.direction, option.displayAlignment);
0198     // If the ascent of the font is larger than the height of the rect,
0199     // we will clip the text, so it's better to align the tight bounding rect in this case
0200     // This is specifically for fonts where the ascent is very large compared to
0201     // the descent, like certain of the Stix family.
0202     QFontMetricsF fontMetrics(font);
0203     if (fontMetrics.ascent() > r.height()) {
0204         QRectF tbr = fontMetrics.tightBoundingRect(text);
0205         QRect textRect(r);
0206         textRect.setHeight(textRect.height() + (r.height() - tbr.height()));
0207         painter->drawText(textRect, Qt::AlignBottom|Qt::TextSingleLine|textAlign, text);
0208     } else {
0209         painter->drawText(r, Qt::AlignVCenter|Qt::TextSingleLine|textAlign, text);
0210     }
0211 
0212     if (writingSystem != QFontDatabase::Any)
0213         system = writingSystem;
0214 
0215     if (system != QFontDatabase::Any) {
0216         int w = painter->fontMetrics().horizontalAdvance(text + QLatin1String("  "));
0217         painter->setFont(font2);
0218 
0219 #if QT_VERSION_MAJOR < 6
0220         QString sample = QFontDatabase().writingSystemSample(system);
0221 #else
0222         QString sample = QFontDatabase::writingSystemSample(system);
0223 #endif
0224         if (option.direction == Qt::RightToLeft)
0225             r.setRight(r.right() - w);
0226         else
0227             r.setLeft(r.left() + w);
0228         painter->drawText(r, Qt::AlignVCenter|Qt::TextSingleLine|textAlign, sample);
0229     }
0230     painter->setFont(old);
0231 
0232     if (option.state & QStyle::State_Selected)
0233         painter->restore();
0234 
0235 }
0236 
0237 QSize font::FontDelegate::sizeHint(const QStyleOptionViewItem &option,
0238                                     const QModelIndex &index) const
0239 {
0240     QString text = index.data(Qt::DisplayRole).toString();
0241     QFont font(option.font);
0242 //     font.setFamily(text);
0243     font.setPointSize(QFontInfo(font).pointSize() * 3/2);
0244     QFontMetrics fontMetrics(font);
0245     return QSize(fontMetrics.horizontalAdvance(text), fontMetrics.height());
0246 }