1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "fontpanel.h"
5
6#include <QtWidgets/QLabel>
7#include <QtWidgets/QComboBox>
8#include <QtWidgets/QFormLayout>
9#include <QtWidgets/QSpacerItem>
10#include <QtWidgets/QFontComboBox>
11#include <QtCore/QTimer>
12#include <QtWidgets/QLineEdit>
13
14QT_BEGIN_NAMESPACE
15
16using namespace Qt::StringLiterals;
17
18FontPanel::FontPanel(QWidget *parentWidget) :
19 QGroupBox(parentWidget),
20 m_previewLineEdit(new QLineEdit),
21 m_writingSystemComboBox(new QComboBox),
22 m_familyComboBox(new QFontComboBox),
23 m_styleComboBox(new QComboBox),
24 m_pointSizeComboBox(new QComboBox),
25 m_previewFontUpdateTimer(0)
26{
27 setTitle(tr(s: "Font"));
28
29 QFormLayout *formLayout = new QFormLayout(this);
30 // writing systems
31 m_writingSystemComboBox->setEditable(false);
32
33 auto writingSystems = QFontDatabase::writingSystems();
34 writingSystems.push_front(t: QFontDatabase::Any);
35 for (QFontDatabase::WritingSystem ws : std::as_const(t&: writingSystems))
36 m_writingSystemComboBox->addItem(atext: QFontDatabase::writingSystemName(writingSystem: ws), auserData: QVariant(ws));
37 connect(sender: m_writingSystemComboBox, signal: &QComboBox::currentIndexChanged,
38 context: this, slot: &FontPanel::slotWritingSystemChanged);
39 formLayout->addRow(labelText: tr(s: "&Writing system"), field: m_writingSystemComboBox);
40
41 connect(sender: m_familyComboBox, signal: &QFontComboBox::currentFontChanged,
42 context: this, slot: &FontPanel::slotFamilyChanged);
43 formLayout->addRow(labelText: tr(s: "&Family"), field: m_familyComboBox);
44
45 m_styleComboBox->setEditable(false);
46 connect(sender: m_styleComboBox, signal: &QComboBox::currentIndexChanged,
47 context: this, slot: &FontPanel::slotStyleChanged);
48 formLayout->addRow(labelText: tr(s: "&Style"), field: m_styleComboBox);
49
50 m_pointSizeComboBox->setEditable(false);
51 connect(sender: m_pointSizeComboBox, signal: &QComboBox::currentIndexChanged,
52 context: this, slot: &FontPanel::slotPointSizeChanged);
53 formLayout->addRow(labelText: tr(s: "&Point size"), field: m_pointSizeComboBox);
54
55 m_previewLineEdit->setReadOnly(true);
56 formLayout->addRow(widget: m_previewLineEdit);
57
58 setWritingSystem(QFontDatabase::Any);
59}
60
61QFont FontPanel::selectedFont() const
62{
63 QFont rc = m_familyComboBox->currentFont();
64 const QString family = rc.family();
65 rc.setPointSize(pointSize());
66 const QString styleDescription = styleString();
67 if (styleDescription.contains(s: "Italic"_L1))
68 rc.setStyle(QFont::StyleItalic);
69 else if (styleDescription.contains(s: "Oblique"_L1))
70 rc.setStyle(QFont::StyleOblique);
71 else
72 rc.setStyle(QFont::StyleNormal);
73 rc.setBold(QFontDatabase::bold(family, style: styleDescription));
74 rc.setWeight(QFont::Weight(QFontDatabase::weight(family, style: styleDescription)));
75 return rc;
76}
77
78void FontPanel::setSelectedFont(const QFont &f)
79{
80 m_familyComboBox->setCurrentFont(f);
81 if (m_familyComboBox->currentIndex() < 0) {
82 // family not in writing system - find the corresponding one?
83 QList<QFontDatabase::WritingSystem> familyWritingSystems = QFontDatabase::writingSystems(family: f.family());
84 if (familyWritingSystems.isEmpty())
85 return;
86
87 setWritingSystem(familyWritingSystems.constFirst());
88 m_familyComboBox->setCurrentFont(f);
89 }
90
91 updateFamily(family: family());
92
93 const int pointSizeIndex = closestPointSizeIndex(ps: f.pointSize());
94 m_pointSizeComboBox->setCurrentIndex( pointSizeIndex);
95
96 const QString styleString = QFontDatabase::styleString(font: f);
97 const int styleIndex = m_styleComboBox->findText(text: styleString);
98 m_styleComboBox->setCurrentIndex(styleIndex);
99 slotUpdatePreviewFont();
100}
101
102
103QFontDatabase::WritingSystem FontPanel::writingSystem() const
104{
105 const int currentIndex = m_writingSystemComboBox->currentIndex();
106 if ( currentIndex == -1)
107 return QFontDatabase::Latin;
108 return static_cast<QFontDatabase::WritingSystem>(m_writingSystemComboBox->itemData(index: currentIndex).toInt());
109}
110
111QString FontPanel::family() const
112{
113 const int currentIndex = m_familyComboBox->currentIndex();
114 return currentIndex != -1 ? m_familyComboBox->currentFont().family() : QString();
115}
116
117int FontPanel::pointSize() const
118{
119 const int currentIndex = m_pointSizeComboBox->currentIndex();
120 return currentIndex != -1 ? m_pointSizeComboBox->itemData(index: currentIndex).toInt() : 9;
121}
122
123QString FontPanel::styleString() const
124{
125 const int currentIndex = m_styleComboBox->currentIndex();
126 return currentIndex != -1 ? m_styleComboBox->itemText(index: currentIndex) : QString();
127}
128
129void FontPanel::setWritingSystem(QFontDatabase::WritingSystem ws)
130{
131 m_writingSystemComboBox->setCurrentIndex(m_writingSystemComboBox->findData(data: QVariant(ws)));
132 updateWritingSystem(ws);
133}
134
135
136void FontPanel::slotWritingSystemChanged(int)
137{
138 updateWritingSystem(ws: writingSystem());
139 delayedPreviewFontUpdate();
140}
141
142void FontPanel::slotFamilyChanged(const QFont &)
143{
144 updateFamily(family: family());
145 delayedPreviewFontUpdate();
146}
147
148void FontPanel::slotStyleChanged(int)
149{
150 updatePointSizes(family: family(), style: styleString());
151 delayedPreviewFontUpdate();
152}
153
154void FontPanel::slotPointSizeChanged(int)
155{
156 delayedPreviewFontUpdate();
157}
158
159void FontPanel::updateWritingSystem(QFontDatabase::WritingSystem ws)
160{
161
162 m_previewLineEdit->setText(QFontDatabase::writingSystemSample(writingSystem: ws));
163 m_familyComboBox->setWritingSystem (ws);
164 // Current font not in WS ... set index 0.
165 if (m_familyComboBox->currentIndex() < 0) {
166 m_familyComboBox->setCurrentIndex(0);
167 updateFamily(family: family());
168 }
169}
170
171void FontPanel::updateFamily(const QString &family)
172{
173 // Update styles and trigger update of point sizes.
174 // Try to maintain selection or select normal
175 const QString &oldStyleString = styleString();
176
177 const QStringList &styles = QFontDatabase::styles(family);
178 const bool hasStyles = !styles.isEmpty();
179
180 m_styleComboBox->setCurrentIndex(-1);
181 m_styleComboBox->clear();
182 m_styleComboBox->setEnabled(hasStyles);
183
184 int normalIndex = -1;
185 const QString normalStyle = "Normal"_L1;
186
187 if (hasStyles) {
188 for (const QString &style : styles) {
189 // try to maintain selection or select 'normal' preferably
190 const int newIndex = m_styleComboBox->count();
191 m_styleComboBox->addItem(atext: style);
192 if (oldStyleString == style) {
193 m_styleComboBox->setCurrentIndex(newIndex);
194 } else {
195 if (oldStyleString == normalStyle)
196 normalIndex = newIndex;
197 }
198 }
199 if (m_styleComboBox->currentIndex() == -1 && normalIndex != -1)
200 m_styleComboBox->setCurrentIndex(normalIndex);
201 }
202 updatePointSizes(family, style: styleString());
203}
204
205int FontPanel::closestPointSizeIndex(int desiredPointSize) const
206{
207 // try to maintain selection or select closest.
208 int closestIndex = -1;
209 int closestAbsError = 0xFFFF;
210
211 const int pointSizeCount = m_pointSizeComboBox->count();
212 for (int i = 0; i < pointSizeCount; i++) {
213 const int itemPointSize = m_pointSizeComboBox->itemData(index: i).toInt();
214 const int absError = qAbs(t: desiredPointSize - itemPointSize);
215 if (absError < closestAbsError) {
216 closestIndex = i;
217 closestAbsError = absError;
218 if (closestAbsError == 0)
219 break;
220 } else { // past optimum
221 if (absError > closestAbsError) {
222 break;
223 }
224 }
225 }
226 return closestIndex;
227}
228
229
230void FontPanel::updatePointSizes(const QString &family, const QString &styleString)
231{
232 const int oldPointSize = pointSize();
233
234 auto pointSizes = QFontDatabase::pointSizes(family, style: styleString);
235 if (pointSizes.isEmpty())
236 pointSizes = QFontDatabase::standardSizes();
237
238 const bool hasSizes = !pointSizes.isEmpty();
239 m_pointSizeComboBox->clear();
240 m_pointSizeComboBox->setEnabled(hasSizes);
241 m_pointSizeComboBox->setCurrentIndex(-1);
242
243 // try to maintain selection or select closest.
244 if (hasSizes) {
245 QString n;
246 for (int pointSize : std::as_const(t&: pointSizes))
247 m_pointSizeComboBox->addItem(atext: n.setNum(n: pointSize), auserData: QVariant(pointSize));
248 const int closestIndex = closestPointSizeIndex(desiredPointSize: oldPointSize);
249 if (closestIndex != -1)
250 m_pointSizeComboBox->setCurrentIndex(closestIndex);
251 }
252}
253
254void FontPanel::slotUpdatePreviewFont()
255{
256 m_previewLineEdit->setFont(selectedFont());
257}
258
259void FontPanel::delayedPreviewFontUpdate()
260{
261 if (!m_previewFontUpdateTimer) {
262 m_previewFontUpdateTimer = new QTimer(this);
263 connect(sender: m_previewFontUpdateTimer, signal: &QTimer::timeout,
264 context: this, slot: &FontPanel::slotUpdatePreviewFont);
265 m_previewFontUpdateTimer->setInterval(0);
266 m_previewFontUpdateTimer->setSingleShot(true);
267 }
268 if (m_previewFontUpdateTimer->isActive())
269 return;
270 m_previewFontUpdateTimer->start();
271}
272
273QT_END_NAMESPACE
274

source code of qttools/src/shared/fontpanel/fontpanel.cpp