Krita Source Code Documentation
Loading...
Searching...
No Matches
FontStyleModel.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2024 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include "FontStyleModel.h"
7#include <QDebug>
9#include <KisResourceModel.h>
10#include <KoFontRegistry.h>
12
13const QString WEIGHT_TAG = "wght";
14const QString WIDTH_TAG = "wdth";
15const QString SLANT_TAG = "slnt";
16const QString ITALIC_TAG = "ital";
17const QString OPTICAL_TAG = "opsz";
18
24
26 : QAbstractItemModel(parent)
27 , d(new Private)
28{
30 QList<QLocale> locales;
31 Q_FOREACH (const QString langCode, KLocalizedString::languages()) {
32 locales.append(QLocale(langCode));
33 }
34 d->locales = locales;
35}
36
40// sort the font styles in any given manner.
42
43 for (auto it = a.instanceCoords.begin(); it != a.instanceCoords.end(); it++) {
44 if (it.key() == ITALIC_TAG || it.key() == SLANT_TAG) continue;
45 qreal other = b.instanceCoords.value(it.key());
46 if (it.value() < other) return true;
47 }
48 // todo: support slant and ital variation axes.
49 QFont::Style aStyle = a.isItalic? a.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
50 QFont::Style bStyle = b.isItalic? a.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
51 return aStyle < bStyle;
52}
53
55{
56 beginResetModel();
57 std::sort(styles.begin(), styles.end(), styleLowerThan);
58 d->styles = styles;
59 endResetModel();
60}
61
63{
64 return d->styles.value(row).instanceCoords.value(WEIGHT_TAG, 400.0);
65}
66
68{
69 return d->styles.value(row).instanceCoords.value(WIDTH_TAG, 100.0);
70}
71
73{
74 KoSvgText::FontFamilyStyleInfo style = d->styles.value(row);
75 QFont::Style styleType = style.isItalic? style.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
76 if (style.instanceCoords.value(ITALIC_TAG, 0) != 0) {
77 styleType = QFont::StyleItalic;
78 } else if (style.instanceCoords.value(SLANT_TAG, 0) != 0) {
79 styleType = QFont::StyleOblique;
80 }
81 return styleType;
82}
83
85{
86 return -(d->styles.value(row).instanceCoords.value(SLANT_TAG, 0));
87}
88
89QVariantHash FontStyleModel::axesValues(int row)
90{
91 return data(index(row, 0), AxisValues).toHash();
92}
93
94#include <KoCssTextUtils.h>
95QHash<int, KoSvgText::FontFamilyStyleInfo> searchAxisTag(const QString &tag,
96 const qreal &value,
97 const QVector<qreal> &values,
98 const qreal &defaultVal,
99 const qreal &defaultValUpper,
100 const QHash<int, KoSvgText::FontFamilyStyleInfo> &styles) {
101 QHash<int, KoSvgText::FontFamilyStyleInfo> filteredStyles;
102 bool shouldNotReturnDefault = ((tag == ITALIC_TAG || tag == SLANT_TAG) && value != defaultVal);
103 qreal selectedValue = KoCssTextUtils::cssSelectFontStyleValue(values, value, defaultVal, defaultValUpper, shouldNotReturnDefault);
104 for (auto it = styles.begin(); it!= styles.end(); it++) {
105 qreal val = it.value().instanceCoords.value(tag, defaultVal);
106 if (val == selectedValue) {
107 if (shouldNotReturnDefault && val == defaultVal) continue;
108 filteredStyles.insert(it.key(), it.value());
109 }
110 }
111 return filteredStyles;
112}
113
114int FontStyleModel::rowForStyle(const qreal &weight, const qreal &width, const int &styleMode, const qreal &styleValue)
115{
116 QHash<int, KoSvgText::FontFamilyStyleInfo> styles;
117 QVector<qreal> weights;
118 QVector<qreal> widths;
119 QVector<qreal> slants;
120 QVector<qreal> italics;
121 for (int i = 0; i< d->styles.size(); i++) {
122 styles.insert(i, d->styles.at(i));
123 weights.append(d->styles.value(i).instanceCoords.value(WEIGHT_TAG, 400.0));
124 widths.append(d->styles.value(i).instanceCoords.value(WIDTH_TAG, 100.0));
125 int fontStyle = d->styles.value(i).isItalic? d->styles.value(i).isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
126 if (d->styles.value(i).instanceCoords.contains(SLANT_TAG) || fontStyle == QFont::StyleOblique) {
127 slants.append(d->styles.value(i).instanceCoords.value(SLANT_TAG, -11.0));
128 }
129 if (d->styles.value(i).instanceCoords.contains(ITALIC_TAG) || fontStyle == QFont::StyleItalic) {
130 italics.append(d->styles.value(i).instanceCoords.value(ITALIC_TAG, 1.0));
131 }
132 }
133
134 if (styles.size() > 1) {
135 styles = searchAxisTag(WIDTH_TAG, width, widths, 100.0, 100.0, styles);
136 }
137 if (styles.size() > 1) {
138 styles = searchAxisTag(WEIGHT_TAG, weight, weights, 400.0, 500.0, styles);
139 }
140 // Test all the italics and slant stuff, complete with fallbacks...
141 if (styles.size() > 1) {
142 QHash<int, KoSvgText::FontFamilyStyleInfo> italicStyles;
143 QHash<int, KoSvgText::FontFamilyStyleInfo> obliqueStyles;
144 if (!slants.isEmpty()) {
145 obliqueStyles = searchAxisTag(SLANT_TAG,
146 styleMode == QFont::StyleItalic? -11.0: -styleValue, slants,
147 0.0,
148 0.0,
149 styles);
150 }
151 if (!italics.isEmpty()) {
152 italicStyles = searchAxisTag(ITALIC_TAG,
153 1.0,
154 italics,
155 0.0,
156 0.0,
157 styles);
158 }
159 if (styleMode == QFont::StyleItalic) {
160 if (!italicStyles.isEmpty()) {
161 styles = italicStyles;
162 } else if (!obliqueStyles.isEmpty()) {
163 styles = obliqueStyles;
164 }
165 } else if (styleMode == QFont::StyleOblique) {
166 if (!obliqueStyles.isEmpty()) {
167 styles = obliqueStyles;
168 } else if (!italicStyles.isEmpty()) {
169 styles = italicStyles;
170 }
171 } else {
172 QHash<int, KoSvgText::FontFamilyStyleInfo> regularStyles;
173 for (auto it = styles.begin(); it!= styles.end(); it++) {
174 if (!obliqueStyles.contains(it.key()) && !italicStyles.contains(it.key())) {
175 regularStyles.insert(it.key(), it.value());
176 }
177 }
178 if (!regularStyles.isEmpty()) styles = regularStyles;
179 }
180 }
181 return styles.isEmpty()? 0: styles.keys().first();
182}
183
185{
186 QStringList families = textPropertiesModel->fontFamilies();
188
189 if (!families.isEmpty() && d->fontModel) {
190
191 std::optional<QString> name = KoFontRegistry::instance()->wwsNameByFamilyName(families.first());
192 QString familyName = !name? families.first(): name.value();
193
194 QVector<KoResourceSP> res = d->fontModel->resourcesForFilename(familyName);
195 if (!res.isEmpty()) {
196 KoFontFamilySP family = res.first().staticCast<KoFontFamily>();
197 if (family) {
198 styles = family->styles();
199 }
200 }
201 }
202 setStylesInfo(styles);
203}
204
205QModelIndex FontStyleModel::index(int row, int column, const QModelIndex &parent) const
206{
207 Q_UNUSED(parent)
208 if (column != 0) return QModelIndex();
209 if (row >= 0 && row < d->styles.size()) return createIndex(row, column, &row);
210 return QModelIndex();
211}
212
213QModelIndex FontStyleModel::parent(const QModelIndex &child) const
214{
215 Q_UNUSED(child)
216 return QModelIndex();
217}
218
219int FontStyleModel::rowCount(const QModelIndex &parent) const
220{
221 Q_UNUSED(parent)
222 return d->styles.size();
223}
224
225int FontStyleModel::columnCount(const QModelIndex &parent) const
226{
227 Q_UNUSED(parent)
228 return 1;
229}
230
231QVariant FontStyleModel::data(const QModelIndex &index, int role) const
232{
233 if (!index.isValid()) return QVariant();
234
235 KoSvgText::FontFamilyStyleInfo style = d->styles.at(index.row());
236 if (role == Qt::DisplayRole) {
237 if (style.localizedLabels.isEmpty()) return QString();
238 QString label = style.localizedLabels.value(QLocale(QLocale::English), style.localizedLabels.values().first());
239 Q_FOREACH(const QLocale &locale, d->locales) {
240 if (style.localizedLabels.keys().contains(locale)) {
241 label = style.localizedLabels.value(locale, label);
242 break;
243 }
244 }
245 return label;
246 } else if (role == Weight){
247 return style.instanceCoords.value(WEIGHT_TAG, 400.0);
248 } else if (role == Width){
249 return style.instanceCoords.value(WIDTH_TAG, 100.0);
250 } else if (role == StyleMode){
251 QFont::Style styleType = style.isItalic? style.isOblique? QFont::StyleOblique: QFont::StyleItalic: QFont::StyleNormal;
252 if (style.instanceCoords.value(ITALIC_TAG, 0) != 0) {
253 styleType = QFont::StyleItalic;
254 } else if (style.instanceCoords.value(SLANT_TAG, 0) != 0) {
255 styleType = QFont::StyleOblique;
256 }
257 return styleType;
258 } else if (role == Slant){
259 return -(style.instanceCoords.value(SLANT_TAG, 0));
260 } else if (role == AxisValues) {
261 QVariantHash vals;
262 for (auto it = style.instanceCoords.begin(); it != style.instanceCoords.end(); it++) {
263 if (!(it.key() == WEIGHT_TAG
264 || it.key() == WIDTH_TAG
265 || it.key() == SLANT_TAG
266 || it.key() == ITALIC_TAG)) {
267 vals.insert(it.key(), QVariant::fromValue(it.value()));
268 }
269 }
270 return vals;
271 }
272 return QVariant();
273}
274
275QHash<int, QByteArray> FontStyleModel::roleNames() const
276{
277 QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
278 roles[Weight] = "weight";
279 roles[Width] = "width";
280 roles[StyleMode] = "stylemode";
281 roles[Slant] = "slant";
282 roles[AxisValues] = "axisvalues";
283 return roles;
284}
const QString SLANT_TAG
QHash< int, KoSvgText::FontFamilyStyleInfo > searchAxisTag(const QString &tag, const qreal &value, const QVector< qreal > &values, const qreal &defaultVal, const qreal &defaultValUpper, const QHash< int, KoSvgText::FontFamilyStyleInfo > &styles)
const QString WEIGHT_TAG
const QString ITALIC_TAG
const QString WIDTH_TAG
static bool styleLowerThan(const KoSvgText::FontFamilyStyleInfo &a, const KoSvgText::FontFamilyStyleInfo &b)
const QString OPTICAL_TAG
float value(const T *src, size_t ch)
const QString SLANT_TAG
const QString WEIGHT_TAG
const QString ITALIC_TAG
const QString WIDTH_TAG
Q_INVOKABLE void setFromTextPropertiesModel(KoSvgTextPropertiesModel *textPropertiesModel)
Update styles model from current text properties.
Q_INVOKABLE QVariantHash axesValues(int row)
Q_INVOKABLE int styleModeValue(int row)
int rowCount(const QModelIndex &parent) const override
Q_INVOKABLE qreal weightValue(int row)
QModelIndex parent(const QModelIndex &child) const
int columnCount(const QModelIndex &parent) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Q_INVOKABLE qreal widthValue(int row)
QVariant data(const QModelIndex &index, int role) const override
QHash< int, QByteArray > roleNames() const override
@ AxisValues
other axis values
@ StyleMode
QFont::Style.
@ Width
qreal, represents 'wdth'
@ Weight
qreal, represents 'wgth'
@ Slant
qreal, represents 'slnt'
Q_INVOKABLE qreal slantValue(int row)
Q_INVOKABLE int rowForStyle(const qreal &weight, const qreal &width, const int &styleMode, const qreal &styleValue)
Find the closest style that represents the current width, weight and stylemode.
const QScopedPointer< Private > d
void setStylesInfo(QList< KoSvgText::FontFamilyStyleInfo > styles)
Set the base style info;.
FontStyleModel(QObject *parent=nullptr)
The KisResourceModel class provides the main access to resources. It is possible to filter the resour...
static qreal cssSelectFontStyleValue(const QVector< qreal > &values, const qreal targetValue, const qreal defaultValue, const qreal defaultValueUpper, const bool shouldNotReturnDefault)
cssSelectFontStyleValue Select the closest font style value from the list, following the CSS Fonts se...
The KoFontFamily class Abstract representation of a Weight/Width/Slant font family,...
std::optional< QString > wwsNameByFamilyName(const QString familyName) const
static KoFontRegistry * instance()
The KoSvgTextPropertiesModel class.
const QString FontFamilies
QList< KoSvgText::FontFamilyStyleInfo > styles
KisResourceModel * fontModel
QHash< QString, float > instanceCoords
Definition KoSvgText.h:816
QHash< QLocale, QString > localizedLabels
Definition KoSvgText.h:815