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 }