1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "fontpanel.h"
41
42#include <QtWidgets/QLabel>
43#include <QtWidgets/QComboBox>
44#include <QtWidgets/QFormLayout>
45#include <QtWidgets/QSpacerItem>
46#include <QtWidgets/QFontComboBox>
47#include <QtCore/QTimer>
48#include <QtWidgets/QLineEdit>
49
50QT_BEGIN_NAMESPACE
51
52FontPanel::FontPanel(QWidget *parentWidget) :
53 QGroupBox(parentWidget),
54 m_previewLineEdit(new QLineEdit),
55 m_writingSystemComboBox(new QComboBox),
56 m_familyComboBox(new QFontComboBox),
57 m_styleComboBox(new QComboBox),
58 m_pointSizeComboBox(new QComboBox),
59 m_previewFontUpdateTimer(0)
60{
61 setTitle(tr(s: "Font"));
62
63 QFormLayout *formLayout = new QFormLayout(this);
64 // writing systems
65 m_writingSystemComboBox->setEditable(false);
66
67 auto writingSystems = m_fontDatabase.writingSystems();
68 writingSystems.push_front(t: QFontDatabase::Any);
69 for (QFontDatabase::WritingSystem ws : qAsConst(t&: writingSystems))
70 m_writingSystemComboBox->addItem(atext: QFontDatabase::writingSystemName(writingSystem: ws), auserData: QVariant(ws));
71 connect(sender: m_writingSystemComboBox, signal: QOverload<int>::of(ptr: &QComboBox::currentIndexChanged),
72 receiver: this, slot: &FontPanel::slotWritingSystemChanged);
73 formLayout->addRow(labelText: tr(s: "&Writing system"), field: m_writingSystemComboBox);
74
75 connect(sender: m_familyComboBox, signal: &QFontComboBox::currentFontChanged,
76 receiver: this, slot: &FontPanel::slotFamilyChanged);
77 formLayout->addRow(labelText: tr(s: "&Family"), field: m_familyComboBox);
78
79 m_styleComboBox->setEditable(false);
80 connect(sender: m_styleComboBox, signal: QOverload<int>::of(ptr: &QComboBox::currentIndexChanged),
81 receiver: this, slot: &FontPanel::slotStyleChanged);
82 formLayout->addRow(labelText: tr(s: "&Style"), field: m_styleComboBox);
83
84 m_pointSizeComboBox->setEditable(false);
85 connect(sender: m_pointSizeComboBox, signal: QOverload<int>::of(ptr: &QComboBox::currentIndexChanged),
86 receiver: this, slot: &FontPanel::slotPointSizeChanged);
87 formLayout->addRow(labelText: tr(s: "&Point size"), field: m_pointSizeComboBox);
88
89 m_previewLineEdit->setReadOnly(true);
90 formLayout->addRow(widget: m_previewLineEdit);
91
92 setWritingSystem(QFontDatabase::Any);
93}
94
95QFont FontPanel::selectedFont() const
96{
97 QFont rc = m_familyComboBox->currentFont();
98 const QString family = rc.family();
99 rc.setPointSize(pointSize());
100 const QString styleDescription = styleString();
101 if (styleDescription.contains(s: QLatin1String("Italic")))
102 rc.setStyle(QFont::StyleItalic);
103 else if (styleDescription.contains(s: QLatin1String("Oblique")))
104 rc.setStyle(QFont::StyleOblique);
105 else
106 rc.setStyle(QFont::StyleNormal);
107 rc.setBold(m_fontDatabase.bold(family, style: styleDescription));
108
109 // Weight < 0 asserts...
110 const int weight = m_fontDatabase.weight(family, style: styleDescription);
111 if (weight >= 0)
112 rc.setWeight(weight);
113 return rc;
114}
115
116void FontPanel::setSelectedFont(const QFont &f)
117{
118 m_familyComboBox->setCurrentFont(f);
119 if (m_familyComboBox->currentIndex() < 0) {
120 // family not in writing system - find the corresponding one?
121 QList<QFontDatabase::WritingSystem> familyWritingSystems = m_fontDatabase.writingSystems(family: f.family());
122 if (familyWritingSystems.isEmpty())
123 return;
124
125 setWritingSystem(familyWritingSystems.constFirst());
126 m_familyComboBox->setCurrentFont(f);
127 }
128
129 updateFamily(family: family());
130
131 const int pointSizeIndex = closestPointSizeIndex(ps: f.pointSize());
132 m_pointSizeComboBox->setCurrentIndex( pointSizeIndex);
133
134 const QString styleString = m_fontDatabase.styleString(font: f);
135 const int styleIndex = m_styleComboBox->findText(text: styleString);
136 m_styleComboBox->setCurrentIndex(styleIndex);
137 slotUpdatePreviewFont();
138}
139
140
141QFontDatabase::WritingSystem FontPanel::writingSystem() const
142{
143 const int currentIndex = m_writingSystemComboBox->currentIndex();
144 if ( currentIndex == -1)
145 return QFontDatabase::Latin;
146 return static_cast<QFontDatabase::WritingSystem>(m_writingSystemComboBox->itemData(index: currentIndex).toInt());
147}
148
149QString FontPanel::family() const
150{
151 const int currentIndex = m_familyComboBox->currentIndex();
152 return currentIndex != -1 ? m_familyComboBox->currentFont().family() : QString();
153}
154
155int FontPanel::pointSize() const
156{
157 const int currentIndex = m_pointSizeComboBox->currentIndex();
158 return currentIndex != -1 ? m_pointSizeComboBox->itemData(index: currentIndex).toInt() : 9;
159}
160
161QString FontPanel::styleString() const
162{
163 const int currentIndex = m_styleComboBox->currentIndex();
164 return currentIndex != -1 ? m_styleComboBox->itemText(index: currentIndex) : QString();
165}
166
167void FontPanel::setWritingSystem(QFontDatabase::WritingSystem ws)
168{
169 m_writingSystemComboBox->setCurrentIndex(m_writingSystemComboBox->findData(data: QVariant(ws)));
170 updateWritingSystem(ws);
171}
172
173
174void FontPanel::slotWritingSystemChanged(int)
175{
176 updateWritingSystem(ws: writingSystem());
177 delayedPreviewFontUpdate();
178}
179
180void FontPanel::slotFamilyChanged(const QFont &)
181{
182 updateFamily(family: family());
183 delayedPreviewFontUpdate();
184}
185
186void FontPanel::slotStyleChanged(int)
187{
188 updatePointSizes(family: family(), style: styleString());
189 delayedPreviewFontUpdate();
190}
191
192void FontPanel::slotPointSizeChanged(int)
193{
194 delayedPreviewFontUpdate();
195}
196
197void FontPanel::updateWritingSystem(QFontDatabase::WritingSystem ws)
198{
199
200 m_previewLineEdit->setText(QFontDatabase::writingSystemSample(writingSystem: ws));
201 m_familyComboBox->setWritingSystem (ws);
202 // Current font not in WS ... set index 0.
203 if (m_familyComboBox->currentIndex() < 0) {
204 m_familyComboBox->setCurrentIndex(0);
205 updateFamily(family: family());
206 }
207}
208
209void FontPanel::updateFamily(const QString &family)
210{
211 // Update styles and trigger update of point sizes.
212 // Try to maintain selection or select normal
213 const QString &oldStyleString = styleString();
214
215 const QStringList &styles = m_fontDatabase.styles(family);
216 const bool hasStyles = !styles.isEmpty();
217
218 m_styleComboBox->setCurrentIndex(-1);
219 m_styleComboBox->clear();
220 m_styleComboBox->setEnabled(hasStyles);
221
222 int normalIndex = -1;
223 const QString normalStyle = QLatin1String("Normal");
224
225 if (hasStyles) {
226 for (const QString &style : styles) {
227 // try to maintain selection or select 'normal' preferably
228 const int newIndex = m_styleComboBox->count();
229 m_styleComboBox->addItem(atext: style);
230 if (oldStyleString == style) {
231 m_styleComboBox->setCurrentIndex(newIndex);
232 } else {
233 if (oldStyleString == normalStyle)
234 normalIndex = newIndex;
235 }
236 }
237 if (m_styleComboBox->currentIndex() == -1 && normalIndex != -1)
238 m_styleComboBox->setCurrentIndex(normalIndex);
239 }
240 updatePointSizes(family, style: styleString());
241}
242
243int FontPanel::closestPointSizeIndex(int desiredPointSize) const
244{
245 // try to maintain selection or select closest.
246 int closestIndex = -1;
247 int closestAbsError = 0xFFFF;
248
249 const int pointSizeCount = m_pointSizeComboBox->count();
250 for (int i = 0; i < pointSizeCount; i++) {
251 const int itemPointSize = m_pointSizeComboBox->itemData(index: i).toInt();
252 const int absError = qAbs(t: desiredPointSize - itemPointSize);
253 if (absError < closestAbsError) {
254 closestIndex = i;
255 closestAbsError = absError;
256 if (closestAbsError == 0)
257 break;
258 } else { // past optimum
259 if (absError > closestAbsError) {
260 break;
261 }
262 }
263 }
264 return closestIndex;
265}
266
267
268void FontPanel::updatePointSizes(const QString &family, const QString &styleString)
269{
270 const int oldPointSize = pointSize();
271
272 auto pointSizes = m_fontDatabase.pointSizes(family, style: styleString);
273 if (pointSizes.isEmpty())
274 pointSizes = QFontDatabase::standardSizes();
275
276 const bool hasSizes = !pointSizes.isEmpty();
277 m_pointSizeComboBox->clear();
278 m_pointSizeComboBox->setEnabled(hasSizes);
279 m_pointSizeComboBox->setCurrentIndex(-1);
280
281 // try to maintain selection or select closest.
282 if (hasSizes) {
283 QString n;
284 for (int pointSize : qAsConst(t&: pointSizes))
285 m_pointSizeComboBox->addItem(atext: n.setNum(n: pointSize), auserData: QVariant(pointSize));
286 const int closestIndex = closestPointSizeIndex(desiredPointSize: oldPointSize);
287 if (closestIndex != -1)
288 m_pointSizeComboBox->setCurrentIndex(closestIndex);
289 }
290}
291
292void FontPanel::slotUpdatePreviewFont()
293{
294 m_previewLineEdit->setFont(selectedFont());
295}
296
297void FontPanel::delayedPreviewFontUpdate()
298{
299 if (!m_previewFontUpdateTimer) {
300 m_previewFontUpdateTimer = new QTimer(this);
301 connect(sender: m_previewFontUpdateTimer, signal: &QTimer::timeout,
302 receiver: this, slot: &FontPanel::slotUpdatePreviewFont);
303 m_previewFontUpdateTimer->setInterval(0);
304 m_previewFontUpdateTimer->setSingleShot(true);
305 }
306 if (m_previewFontUpdateTimer->isActive())
307 return;
308 m_previewFontUpdateTimer->start();
309}
310
311QT_END_NAMESPACE
312

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