File indexing completed on 2024-05-12 16:02:27

0001 /* This file is part of the KDE project
0002  *
0003  * SPDX-FileCopyrightText: 2017 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 #include "kis_font_family_combo_box.h"
0008 #include <QFontDatabase>
0009 #include <QFontComboBox>
0010 #include <QHBoxLayout>
0011 #include <QComboBox>
0012 #include <QAbstractItemView>
0013 #include <QScrollBar>
0014 #include <QCompleter>
0015 #include <klocalizedstring.h>
0016 #include <kis_debug.h>
0017 #include <QPainter>
0018 #include <kconfiggroup.h>
0019 #include <ksharedconfig.h>
0020 
0021 PinnedFontsSeparator::PinnedFontsSeparator(QAbstractItemDelegate *_default, QWidget *parent)
0022     : QStyledItemDelegate(parent)
0023     , m_separatorIndex(0)
0024     , m_separatorAdded(false)
0025     , m_defaultDelegate(_default)
0026 {
0027 }
0028 
0029 void PinnedFontsSeparator::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0030 {
0031     if (index.row() == m_separatorIndex && m_separatorAdded) {
0032         QRect viewRect = option.rect;
0033         painter->setPen(Qt::gray);
0034         painter->drawLine((viewRect.topLeft() + viewRect.bottomLeft()) / 2 + QPoint(5, 0),
0035                           (viewRect.topRight() + viewRect.bottomRight()) / 2 - QPoint(5, 0));
0036     } else {
0037         m_defaultDelegate->paint(painter, option, index);
0038     }
0039 }
0040 
0041 QSize PinnedFontsSeparator::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
0042 {
0043     return QStyledItemDelegate::sizeHint(option, index) * 1.25;
0044 }
0045 
0046 void PinnedFontsSeparator::setSeparatorIndex(int index)
0047 {
0048     m_separatorIndex = index;
0049 }
0050 
0051 void PinnedFontsSeparator::setSeparatorAdded()
0052 {
0053     m_separatorAdded = true;
0054 }
0055 
0056 KisFontFamilyComboBox::KisFontFamilyComboBox(QWidget *parent)
0057     : QComboBox(parent)
0058     , m_initilized(false)
0059     , m_initializeFromConfig(false)
0060 {
0061     setEditable(true);
0062     completer()->setCompletionMode(QCompleter::InlineCompletion);
0063     completer()->setCaseSensitivity(Qt::CaseInsensitive);
0064     // The following are all helper fonts for LaTeX that no one but LaTeX would use
0065     // but because many people use LaTeX, they do show up on quite a few systems.
0066     m_blacklistedFonts << "bbold10" << "cmbsy10" << "cmmib10"
0067                        << "cmss10" << "cmex10" << "cmmi10"
0068                        << "cmr10" << "cmsy10" << "eufb10"
0069                        << "eufm10" << "eurb10" << "eurm10"
0070                        << "esint10" << "eufm10" << "eusb10"
0071                        << "eusm10" << "lasy10" << "lasyb10"
0072                        << "msam10" << "msbm10" << "rsfs10"
0073                        << "stmary10" << "wasy10" << "wasyb10";
0074     refillComboBox();
0075     QFontComboBox *temp = new QFontComboBox(this);
0076     m_fontSeparator = new PinnedFontsSeparator(temp->itemDelegate(), this);
0077     temp->setEnabled(true);
0078     temp->hide();
0079     m_separatorIndex = 0;
0080 
0081     KConfigGroup cfg(KSharedConfig::openConfig(), "");
0082     m_pinnedFonts = cfg.readEntry<QStringList>("PinnedFonts", QStringList());
0083 
0084 }
0085 
0086 void KisFontFamilyComboBox::refillComboBox(QVector<QFontDatabase::WritingSystem> writingSystems)
0087 {
0088     QFontDatabase fonts = QFontDatabase();
0089     int maxWidth        = 0;
0090     this->clear();
0091 
0092     QStringList duplicateFonts;
0093     QStringList filteredFonts;
0094 
0095     if (writingSystems.isEmpty()) {
0096         writingSystems.append(QFontDatabase::Any);
0097     }
0098 
0099     for (int i = 0; i < writingSystems.size(); i++) {
0100         Q_FOREACH (QString family, fonts.families(writingSystems.at(i))) {
0101             // if it's a private family it shouldn't be added.
0102             bool addFont = !fonts.isPrivateFamily(family);
0103 
0104             if (addFont && filteredFonts.contains(family)) {
0105                 addFont = false;
0106             }
0107             if (addFont && duplicateFonts.contains(family)) {
0108                 addFont = false;
0109             }
0110             if (addFont && m_blacklistedFonts.contains(family)) {
0111                 addFont = false;
0112             }
0113             if (addFont && !fonts.isSmoothlyScalable(family)) {
0114                 addFont = false;
0115             }
0116 
0117             if (addFont) {
0118                 // now, check for all possible familyname+style name combinations, so we can avoid those.
0119                 Q_FOREACH (const QString style, fonts.styles(family)) {
0120                     duplicateFonts.append(family + " " + style);
0121                     duplicateFonts.append(family + "_" + style);
0122                 }
0123                 filteredFonts.append(family);
0124 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
0125                 int width = 1.5 * view()->fontMetrics()
0126                         .horizontalAdvance(family + " " + fonts.writingSystemSample(QFontDatabase::Any));
0127 #else
0128                 int width = 1.5 * view()->fontMetrics()
0129                         .width(family + " " + fonts.writingSystemSample(QFontDatabase::Any));
0130 
0131 #endif
0132                 if (width > maxWidth) {
0133                     maxWidth = width;
0134                 }
0135             }
0136         }
0137     }
0138     this->addItems(filteredFonts);
0139     if (this->count() > this->maxVisibleItems()) {
0140         maxWidth += view()->style()->pixelMetric(QStyle::PixelMetric::PM_ScrollBarExtent);
0141     }
0142     view()->setMinimumWidth(maxWidth);
0143 } // KisFontFamilyComboBox::refillComboBox
0144 
0145 void KisFontFamilyComboBox::setTopFont(const QString &family)
0146 {
0147     if (family.isEmpty() || !m_initilized || m_pinnedFonts.contains(family)) {
0148         return;
0149     }
0150 
0151     if (m_pinnedFonts.count() > 4) {
0152         this->removeItem(4);
0153         m_pinnedFonts.pop_back();
0154         m_separatorIndex--;
0155     }
0156 
0157     if (m_pinnedFonts.isEmpty()) {
0158         this->insertSeparator(0);
0159         m_fontSeparator->setSeparatorAdded();
0160     }
0161 
0162     m_pinnedFonts.push_front(family);
0163     this->insertItem(0, family);
0164     m_separatorIndex++;
0165     m_fontSeparator->setSeparatorIndex(m_separatorIndex);
0166     KConfigGroup cfg(KSharedConfig::openConfig(), "");
0167 
0168     cfg.writeEntry("PinnedFonts", m_pinnedFonts);
0169 }
0170 
0171 void KisFontFamilyComboBox::setInitialized()
0172 {
0173     if(m_initilized)
0174         return;
0175 
0176     m_initilized = true;
0177 
0178     for(int i=m_pinnedFonts.count()-1; i>=0; i--){
0179         this->insertItem(0, m_pinnedFonts[i]);
0180         m_separatorIndex++;
0181     }
0182 
0183     if(m_pinnedFonts.count() > 0){
0184         this->insertSeparator(m_separatorIndex);
0185         m_fontSeparator->setSeparatorIndex(m_separatorIndex);
0186         m_fontSeparator->setSeparatorAdded();
0187     }
0188 
0189     this->setItemDelegate(m_fontSeparator);
0190 }
0191 
0192 KisFontComboBoxes::KisFontComboBoxes(QWidget *parent)
0193     : QWidget(parent)
0194 {
0195     QHBoxLayout *layout = new QHBoxLayout(this);
0196     layout->setContentsMargins(0, 0, 0, 0);
0197 
0198     m_family = new KisFontFamilyComboBox();
0199     m_family->setMinimumWidth(100);
0200     m_family->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
0201     layout->addWidget(m_family);
0202 
0203     m_styles = new QComboBox();
0204     m_styles->setObjectName("stylesComboBox");
0205     layout->addWidget(m_styles);
0206     fontFamilyChanged();
0207     m_family->setToolTip(i18n("Font Family"));
0208     m_styles->setToolTip(i18n("Font Style"));
0209     connect(m_family, SIGNAL(activated(int)), this, SLOT(fontFamilyChanged()));
0210     connect(m_family, SIGNAL(activated(int)), this, SLOT(fontChange()));
0211     connect(m_styles, SIGNAL(activated(int)), this, SLOT(fontChange()));
0212 }
0213 
0214 void KisFontComboBoxes::setCurrentFont(QFont font)
0215 {
0216     setCurrentFamily(font.family());
0217     setCurrentStyle(QFontDatabase().styleString(font));
0218 }
0219 
0220 void KisFontComboBoxes::setCurrentFamily(const QString family)
0221 {
0222     m_family->setCurrentText(family);
0223     fontFamilyChanged();
0224 }
0225 
0226 void KisFontComboBoxes::setCurrentStyle(QString style)
0227 {
0228     int index = m_styles->findText(style, Qt::MatchFixedString);
0229 
0230     if (index < 0) {
0231         index = m_styles->findText(style, Qt::MatchContains);
0232     }
0233 
0234     if (index < 0) {
0235         index = m_styles->findText("regular", Qt::MatchContains);
0236     }
0237 
0238     if (index >= 0) {
0239         m_styles->setCurrentIndex(index);
0240     }
0241 }
0242 
0243 QString KisFontComboBoxes::currentFamily() const
0244 {
0245     return m_family->currentText();
0246 }
0247 
0248 QString KisFontComboBoxes::currentStyle() const
0249 {
0250     return m_styles->currentText();
0251 }
0252 
0253 QFont KisFontComboBoxes::currentFont(int pointSize) const
0254 {
0255     return QFontDatabase().font(m_family->currentText(), m_styles->currentText(), pointSize);
0256 }
0257 
0258 void KisFontComboBoxes::refillComboBox(QVector<QFontDatabase::WritingSystem> writingSystems)
0259 {
0260     KisFontFamilyComboBox *cmb = qobject_cast<KisFontFamilyComboBox *>(m_family);
0261     cmb->refillComboBox(writingSystems);
0262 }
0263 
0264 void KisFontComboBoxes::fontFamilyChanged()
0265 {
0266     QString currentText = m_styles->currentText();
0267     QFontDatabase fonts;
0268     const QString family = m_family->currentText();
0269     int maxWidth         = 0;
0270     m_styles->clear();
0271     QStringList styles;
0272 
0273     KisFontFamilyComboBox *cmb = qobject_cast<KisFontFamilyComboBox *>(m_family);
0274     cmb->setTopFont(family);
0275 
0276     if (fonts.styles(family).isEmpty()) {
0277         styles.append("Normal");
0278     }
0279 
0280     Q_FOREACH (const QString style, fonts.styles(family)) {
0281         int b      = fonts.weight(family, style);
0282         int bindex = 0;
0283         for (int i = 0; i < styles.size(); i++) {
0284             if (b > fonts.weight(family, styles.at(i))) {
0285                 bindex = i;
0286             }
0287         }
0288         if (!styles.contains(style)) {
0289             styles.insert(bindex, style);
0290 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
0291             maxWidth = qMax(m_styles->view()->fontMetrics().horizontalAdvance(style + "  "), maxWidth);
0292 #else
0293             maxWidth = qMax(m_styles->view()->fontMetrics().width(style + "  "), maxWidth);
0294 #endif
0295         }
0296     }
0297     m_styles->addItems(styles);
0298     if (m_styles->count() > m_styles->maxVisibleItems()) {
0299         maxWidth += m_styles->view()->style()->pixelMetric(QStyle::PixelMetric::PM_ScrollBarExtent);
0300     }
0301     m_styles->view()->setMinimumWidth(maxWidth);
0302     if (styles.contains(currentText)) {
0303         m_styles->setCurrentText(currentText);
0304     }
0305 } // KisFontComboBoxes::fontFamilyChanged
0306 
0307 void KisFontComboBoxes::fontChange()
0308 {
0309     emit fontChanged(currentFont(10).toString());
0310 }
0311 
0312 void KisFontComboBoxes::setInitialized()
0313 {
0314     KisFontFamilyComboBox *cmb = qobject_cast<KisFontFamilyComboBox *>(m_family);
0315     cmb->setInitialized();
0316 }