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 "qwindowdefs.h" |
5 | #include "qfontdialog.h" |
6 | |
7 | #include "qfontdialog_p.h" |
8 | |
9 | #include <qapplication.h> |
10 | #include <qcheckbox.h> |
11 | #include <qcombobox.h> |
12 | #include <qevent.h> |
13 | #include <qgroupbox.h> |
14 | #include <qlabel.h> |
15 | #include <qlayout.h> |
16 | #include <qlineedit.h> |
17 | #include <qpushbutton.h> |
18 | #include <qstyle.h> |
19 | #include <qdialogbuttonbox.h> |
20 | #include <qheaderview.h> |
21 | #include <qlistview.h> |
22 | #include <qstringlistmodel.h> |
23 | #include <qvalidator.h> |
24 | #include <private/qfontdatabase_p.h> |
25 | #include <private/qdialog_p.h> |
26 | #include <private/qfont_p.h> |
27 | |
28 | QT_BEGIN_NAMESPACE |
29 | |
30 | using namespace Qt::StringLiterals; |
31 | |
32 | class QFontListView : public QListView |
33 | { |
34 | Q_OBJECT |
35 | public: |
36 | QFontListView(QWidget *parent); |
37 | inline QStringListModel *model() const { |
38 | return static_cast<QStringListModel *>(QListView::model()); |
39 | } |
40 | inline void setCurrentItem(int item) { |
41 | QListView::setCurrentIndex(static_cast<QAbstractListModel*>(model())->index(row: item)); |
42 | } |
43 | inline int currentItem() const { |
44 | return QListView::currentIndex().row(); |
45 | } |
46 | inline int count() const { |
47 | return model()->rowCount(); |
48 | } |
49 | inline QString currentText() const { |
50 | int row = QListView::currentIndex().row(); |
51 | return row < 0 ? QString() : model()->stringList().at(i: row); |
52 | } |
53 | void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override { |
54 | QListView::currentChanged(current, previous); |
55 | if (current.isValid()) |
56 | emit highlighted(current.row()); |
57 | } |
58 | QString text(int i) const { |
59 | return model()->stringList().at(i); |
60 | } |
61 | signals: |
62 | void highlighted(int); |
63 | }; |
64 | |
65 | QFontListView::QFontListView(QWidget *parent) |
66 | : QListView(parent) |
67 | { |
68 | setModel(new QStringListModel(parent)); |
69 | setEditTriggers(NoEditTriggers); |
70 | } |
71 | |
72 | static const Qt::WindowFlags qfd_DefaultWindowFlags = |
73 | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; |
74 | |
75 | QFontDialogPrivate::QFontDialogPrivate() |
76 | : writingSystem(QFontDatabase::Any), |
77 | options(QFontDialogOptions::create()) |
78 | { |
79 | } |
80 | |
81 | QFontDialogPrivate::~QFontDialogPrivate() |
82 | { |
83 | } |
84 | |
85 | /*! |
86 | \class QFontDialog |
87 | \ingroup standard-dialogs |
88 | \inmodule QtWidgets |
89 | |
90 | \brief The QFontDialog class provides a dialog widget for selecting a font. |
91 | |
92 | A font dialog is created through one of the static getFont() |
93 | functions. |
94 | |
95 | Examples: |
96 | |
97 | \snippet code/src_gui_dialogs_qfontdialog.cpp 0 |
98 | |
99 | The dialog can also be used to set a widget's font directly: |
100 | \snippet code/src_gui_dialogs_qfontdialog.cpp 1 |
101 | If the user clicks OK the font they chose will be used for myWidget, |
102 | and if they click Cancel the original font is used. |
103 | |
104 | \image fusion-fontdialog.png A font dialog in the Fusion widget style. |
105 | |
106 | \sa QFont, QFontInfo, QFontMetrics, QColorDialog, QFileDialog, |
107 | {Standard Dialogs Example} |
108 | */ |
109 | |
110 | /*! |
111 | Constructs a standard font dialog. |
112 | |
113 | Use setCurrentFont() to set the initial font attributes. |
114 | |
115 | The \a parent parameter is passed to the QDialog constructor. |
116 | |
117 | \sa getFont() |
118 | */ |
119 | QFontDialog::QFontDialog(QWidget *parent) |
120 | : QDialog(*new QFontDialogPrivate, parent, qfd_DefaultWindowFlags) |
121 | { |
122 | Q_D(QFontDialog); |
123 | d->init(); |
124 | } |
125 | |
126 | /*! |
127 | Constructs a standard font dialog with the given \a parent and specified |
128 | \a initial font. |
129 | */ |
130 | QFontDialog::QFontDialog(const QFont &initial, QWidget *parent) |
131 | : QFontDialog(parent) |
132 | { |
133 | setCurrentFont(initial); |
134 | } |
135 | |
136 | void QFontDialogPrivate::init() |
137 | { |
138 | Q_Q(QFontDialog); |
139 | |
140 | q->setSizeGripEnabled(true); |
141 | q->setWindowTitle(QFontDialog::tr(s: "Select Font")); |
142 | |
143 | // grid |
144 | familyEdit = new QLineEdit(q); |
145 | familyEdit->setReadOnly(true); |
146 | familyList = new QFontListView(q); |
147 | familyEdit->setFocusProxy(familyList); |
148 | |
149 | familyAccel = new QLabel(q); |
150 | #ifndef QT_NO_SHORTCUT |
151 | familyAccel->setBuddy(familyList); |
152 | #endif |
153 | familyAccel->setIndent(2); |
154 | |
155 | styleEdit = new QLineEdit(q); |
156 | styleEdit->setReadOnly(true); |
157 | styleList = new QFontListView(q); |
158 | styleEdit->setFocusProxy(styleList); |
159 | |
160 | styleAccel = new QLabel(q); |
161 | #ifndef QT_NO_SHORTCUT |
162 | styleAccel->setBuddy(styleList); |
163 | #endif |
164 | styleAccel->setIndent(2); |
165 | |
166 | sizeEdit = new QLineEdit(q); |
167 | sizeEdit->setFocusPolicy(Qt::ClickFocus); |
168 | QIntValidator *validator = new QIntValidator(1, 512, q); |
169 | sizeEdit->setValidator(validator); |
170 | sizeList = new QFontListView(q); |
171 | |
172 | sizeAccel = new QLabel(q); |
173 | #ifndef QT_NO_SHORTCUT |
174 | sizeAccel->setBuddy(sizeEdit); |
175 | #endif |
176 | sizeAccel->setIndent(2); |
177 | |
178 | // effects box |
179 | effects = new QGroupBox(q); |
180 | QVBoxLayout *vbox = new QVBoxLayout(effects); |
181 | strikeout = new QCheckBox(effects); |
182 | vbox->addWidget(strikeout); |
183 | underline = new QCheckBox(effects); |
184 | vbox->addWidget(underline); |
185 | |
186 | sample = new QGroupBox(q); |
187 | QHBoxLayout *hbox = new QHBoxLayout(sample); |
188 | sampleEdit = new QLineEdit(sample); |
189 | sampleEdit->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)); |
190 | sampleEdit->setAlignment(Qt::AlignCenter); |
191 | // Note that the sample text is *not* translated with tr(), as the |
192 | // characters used depend on the charset encoding. |
193 | sampleEdit->setText("AaBbYyZz"_L1); |
194 | hbox->addWidget(sampleEdit); |
195 | |
196 | writingSystemCombo = new QComboBox(q); |
197 | |
198 | writingSystemAccel = new QLabel(q); |
199 | #ifndef QT_NO_SHORTCUT |
200 | writingSystemAccel->setBuddy(writingSystemCombo); |
201 | #endif |
202 | writingSystemAccel->setIndent(2); |
203 | |
204 | size = 0; |
205 | smoothScalable = false; |
206 | |
207 | QObjectPrivate::connect(sender: writingSystemCombo, signal: &QComboBox::activated, |
208 | receiverPrivate: this, slot: &QFontDialogPrivate::writingSystemHighlighted); |
209 | QObjectPrivate::connect(sender: familyList, signal: &QFontListView::highlighted, |
210 | receiverPrivate: this, slot: &QFontDialogPrivate::familyHighlighted); |
211 | QObjectPrivate::connect(sender: styleList, signal: &QFontListView::highlighted, |
212 | receiverPrivate: this, slot: &QFontDialogPrivate::styleHighlighted); |
213 | QObjectPrivate::connect(sender: sizeList, signal: &QFontListView::highlighted, |
214 | receiverPrivate: this, slot: &QFontDialogPrivate::sizeHighlighted); |
215 | QObjectPrivate::connect(sender: sizeEdit, signal: &QLineEdit::textChanged, |
216 | receiverPrivate: this, slot: &QFontDialogPrivate::sizeChanged); |
217 | |
218 | QObjectPrivate::connect(sender: strikeout, signal: &QCheckBox::clicked, |
219 | receiverPrivate: this, slot: &QFontDialogPrivate::updateSample); |
220 | QObjectPrivate::connect(sender: underline, signal: &QCheckBox::clicked, receiverPrivate: this, |
221 | slot: &QFontDialogPrivate::updateSample); |
222 | |
223 | for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) { |
224 | QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i); |
225 | QString writingSystemName = QFontDatabase::writingSystemName(writingSystem: ws); |
226 | if (writingSystemName.isEmpty()) |
227 | break; |
228 | writingSystemCombo->addItem(atext: writingSystemName); |
229 | } |
230 | |
231 | updateFamilies(); |
232 | if (familyList->count() != 0) { |
233 | familyList->setCurrentItem(0); |
234 | sizeList->setCurrentItem(0); |
235 | } |
236 | |
237 | // grid layout |
238 | QGridLayout *mainGrid = new QGridLayout(q); |
239 | |
240 | int spacing = mainGrid->spacing(); |
241 | if (spacing >= 0) { // uniform spacing |
242 | mainGrid->setSpacing(0); |
243 | |
244 | mainGrid->setColumnMinimumWidth(column: 1, minSize: spacing); |
245 | mainGrid->setColumnMinimumWidth(column: 3, minSize: spacing); |
246 | |
247 | int margin = 0; |
248 | mainGrid->getContentsMargins(left: nullptr, top: nullptr, right: nullptr, bottom: &margin); |
249 | |
250 | mainGrid->setRowMinimumHeight(row: 3, minSize: margin); |
251 | mainGrid->setRowMinimumHeight(row: 6, minSize: 2); |
252 | mainGrid->setRowMinimumHeight(row: 8, minSize: margin); |
253 | } |
254 | |
255 | mainGrid->addWidget(familyAccel, row: 0, column: 0); |
256 | mainGrid->addWidget(familyEdit, row: 1, column: 0); |
257 | mainGrid->addWidget(familyList, row: 2, column: 0); |
258 | |
259 | mainGrid->addWidget(styleAccel, row: 0, column: 2); |
260 | mainGrid->addWidget(styleEdit, row: 1, column: 2); |
261 | mainGrid->addWidget(styleList, row: 2, column: 2); |
262 | |
263 | mainGrid->addWidget(sizeAccel, row: 0, column: 4); |
264 | mainGrid->addWidget(sizeEdit, row: 1, column: 4); |
265 | mainGrid->addWidget(sizeList, row: 2, column: 4); |
266 | |
267 | mainGrid->setColumnStretch(column: 0, stretch: 38); |
268 | mainGrid->setColumnStretch(column: 2, stretch: 24); |
269 | mainGrid->setColumnStretch(column: 4, stretch: 10); |
270 | |
271 | mainGrid->addWidget(effects, row: 4, column: 0); |
272 | |
273 | mainGrid->addWidget(sample, row: 4, column: 2, rowSpan: 4, columnSpan: 3); |
274 | |
275 | mainGrid->addWidget(writingSystemAccel, row: 5, column: 0); |
276 | mainGrid->addWidget(writingSystemCombo, row: 7, column: 0); |
277 | |
278 | buttonBox = new QDialogButtonBox(q); |
279 | mainGrid->addWidget(buttonBox, row: 9, column: 0, rowSpan: 1, columnSpan: 5); |
280 | |
281 | QPushButton *button |
282 | = static_cast<QPushButton *>(buttonBox->addButton(button: QDialogButtonBox::Ok)); |
283 | QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, context: q, slot: &QDialog::accept); |
284 | button->setDefault(true); |
285 | |
286 | buttonBox->addButton(button: QDialogButtonBox::Cancel); |
287 | QObject::connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: q, slot: &QDialog::reject); |
288 | |
289 | q->resize(w: 500, h: 360); |
290 | |
291 | sizeEdit->installEventFilter(filterObj: q); |
292 | familyList->installEventFilter(filterObj: q); |
293 | styleList->installEventFilter(filterObj: q); |
294 | sizeList->installEventFilter(filterObj: q); |
295 | |
296 | familyList->setFocus(); |
297 | retranslateStrings(); |
298 | sampleEdit->setObjectName("qt_fontDialog_sampleEdit"_L1); |
299 | } |
300 | |
301 | /*! |
302 | \internal |
303 | Destroys the font dialog and frees up its storage. |
304 | */ |
305 | |
306 | QFontDialog::~QFontDialog() |
307 | { |
308 | } |
309 | |
310 | /*! |
311 | Executes a modal font dialog and returns a font. |
312 | |
313 | If the user clicks \uicontrol OK, the selected font is returned. If the user |
314 | clicks \uicontrol Cancel, the \a initial font is returned. |
315 | |
316 | The dialog is constructed with the given \a parent and the options specified |
317 | in \a options. \a title is shown as the window title of the dialog and \a |
318 | initial is the initially selected font. If the \a ok parameter is not-null, |
319 | the value it refers to is set to true if the user clicks \uicontrol OK, and set to |
320 | false if the user clicks \uicontrol Cancel. |
321 | |
322 | Examples: |
323 | \snippet code/src_gui_dialogs_qfontdialog.cpp 2 |
324 | |
325 | The dialog can also be used to set a widget's font directly: |
326 | \snippet code/src_gui_dialogs_qfontdialog.cpp 3 |
327 | In this example, if the user clicks OK the font they chose will be |
328 | used, and if they click Cancel the original font is used. |
329 | */ |
330 | QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title, |
331 | FontDialogOptions options) |
332 | { |
333 | return QFontDialogPrivate::getFont(ok, initial, parent, title, options); |
334 | } |
335 | |
336 | /*! |
337 | \overload |
338 | |
339 | Executes a modal font dialog and returns a font. |
340 | |
341 | If the user clicks \uicontrol OK, the selected font is returned. If the user |
342 | clicks \uicontrol Cancel, the Qt default font is returned. |
343 | |
344 | The dialog is constructed with the given \a parent. |
345 | If the \a ok parameter is not-null, the value it refers to is set |
346 | to true if the user clicks \uicontrol OK, and false if the user clicks |
347 | \uicontrol Cancel. |
348 | |
349 | Example: |
350 | \snippet code/src_gui_dialogs_qfontdialog.cpp 4 |
351 | */ |
352 | QFont QFontDialog::getFont(bool *ok, QWidget *parent) |
353 | { |
354 | QFont initial; |
355 | return QFontDialogPrivate::getFont(ok, initial, parent, title: QString(), options: { }); |
356 | } |
357 | |
358 | QFont QFontDialogPrivate::getFont(bool *ok, const QFont &initial, QWidget *parent, |
359 | const QString &title, QFontDialog::FontDialogOptions options) |
360 | { |
361 | QAutoPointer<QFontDialog> dlg(new QFontDialog(parent)); |
362 | dlg->setOptions(options); |
363 | dlg->setCurrentFont(initial); |
364 | if (!title.isEmpty()) |
365 | dlg->setWindowTitle(title); |
366 | |
367 | int ret = (dlg->exec() || (options & QFontDialog::NoButtons)); |
368 | if (ok) |
369 | *ok = !!ret; |
370 | if (ret && bool(dlg)) { |
371 | return dlg->selectedFont(); |
372 | } else { |
373 | return initial; |
374 | } |
375 | } |
376 | |
377 | /*! |
378 | \internal |
379 | An event filter to make the Up, Down, PageUp and PageDown keys work |
380 | correctly in the line edits. The source of the event is the object |
381 | \a o and the event is \a e. |
382 | */ |
383 | |
384 | bool QFontDialog::eventFilter(QObject *o , QEvent *e) |
385 | { |
386 | Q_D(QFontDialog); |
387 | if (e->type() == QEvent::KeyPress) { |
388 | QKeyEvent *k = static_cast<QKeyEvent *>(e); |
389 | if (o == d->sizeEdit && |
390 | (k->key() == Qt::Key_Up || |
391 | k->key() == Qt::Key_Down || |
392 | k->key() == Qt::Key_PageUp || |
393 | k->key() == Qt::Key_PageDown)) { |
394 | |
395 | int ci = d->sizeList->currentItem(); |
396 | QCoreApplication::sendEvent(receiver: d->sizeList, event: k); |
397 | |
398 | if (ci != d->sizeList->currentItem() |
399 | && style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: this)) |
400 | d->sizeEdit->selectAll(); |
401 | return true; |
402 | } else if ((o == d->familyList || o == d->styleList) && |
403 | (k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter)) { |
404 | k->accept(); |
405 | accept(); |
406 | return true; |
407 | } |
408 | } else if (e->type() == QEvent::FocusIn |
409 | && style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: this)) { |
410 | if (o == d->familyList) |
411 | d->familyEdit->selectAll(); |
412 | else if (o == d->styleList) |
413 | d->styleEdit->selectAll(); |
414 | else if (o == d->sizeList) |
415 | d->sizeEdit->selectAll(); |
416 | } else if (e->type() == QEvent::MouseButtonPress && o == d->sizeList) { |
417 | d->sizeEdit->setFocus(); |
418 | } |
419 | return QDialog::eventFilter(o, e); |
420 | } |
421 | |
422 | void QFontDialogPrivate::initHelper(QPlatformDialogHelper *h) |
423 | { |
424 | Q_Q(QFontDialog); |
425 | auto *fontDialogHelper = static_cast<QPlatformFontDialogHelper *>(h); |
426 | fontDialogHelper->setOptions(options); |
427 | fontDialogHelper->setCurrentFont(q->currentFont()); |
428 | QObject::connect(sender: fontDialogHelper, signal: &QPlatformFontDialogHelper::currentFontChanged, |
429 | context: q, slot: &QFontDialog::currentFontChanged); |
430 | QObject::connect(sender: fontDialogHelper, signal: &QPlatformFontDialogHelper::fontSelected, |
431 | context: q, slot: &QFontDialog::fontSelected); |
432 | } |
433 | |
434 | void QFontDialogPrivate::helperPrepareShow(QPlatformDialogHelper *) |
435 | { |
436 | options->setWindowTitle(q_func()->windowTitle()); |
437 | } |
438 | |
439 | /* |
440 | Updates the contents of the "font family" list box. This |
441 | function can be reimplemented if you have special requirements. |
442 | */ |
443 | |
444 | void QFontDialogPrivate::updateFamilies() |
445 | { |
446 | Q_Q(QFontDialog); |
447 | |
448 | enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 }; |
449 | |
450 | const QFontDialog::FontDialogOptions scalableMask = (QFontDialog::ScalableFonts | QFontDialog::NonScalableFonts); |
451 | const QFontDialog::FontDialogOptions spacingMask = (QFontDialog::ProportionalFonts | QFontDialog::MonospacedFonts); |
452 | const QFontDialog::FontDialogOptions options = q->options(); |
453 | |
454 | QStringList familyNames; |
455 | const auto families = QFontDatabase::families(writingSystem); |
456 | for (const QString &family : families) { |
457 | if (QFontDatabase::isPrivateFamily(family)) |
458 | continue; |
459 | |
460 | if ((options & scalableMask) && (options & scalableMask) != scalableMask) { |
461 | if (bool(options & QFontDialog::ScalableFonts) != QFontDatabase::isSmoothlyScalable(family)) |
462 | continue; |
463 | } |
464 | if ((options & spacingMask) && (options & spacingMask) != spacingMask) { |
465 | if (bool(options & QFontDialog::MonospacedFonts) != QFontDatabase::isFixedPitch(family)) |
466 | continue; |
467 | } |
468 | familyNames << family; |
469 | } |
470 | |
471 | familyList->model()->setStringList(familyNames); |
472 | |
473 | QString foundryName1, familyName1, foundryName2, familyName2; |
474 | int bestFamilyMatch = -1; |
475 | match_t bestFamilyType = MATCH_NONE; |
476 | |
477 | QFont f; |
478 | |
479 | // ##### do the right thing for a list of family names in the font. |
480 | QFontDatabasePrivate::parseFontName(name: family, foundry&: foundryName1, family&: familyName1); |
481 | |
482 | QStringList::const_iterator it = familyNames.constBegin(); |
483 | int i = 0; |
484 | for(; it != familyNames.constEnd(); ++it, ++i) { |
485 | QFontDatabasePrivate::parseFontName(name: *it, foundry&: foundryName2, family&: familyName2); |
486 | |
487 | //try to match... |
488 | if (familyName1 == familyName2) { |
489 | bestFamilyType = MATCH_FAMILY; |
490 | if (foundryName1 == foundryName2) { |
491 | bestFamilyMatch = i; |
492 | break; |
493 | } |
494 | if (bestFamilyMatch < MATCH_FAMILY) |
495 | bestFamilyMatch = i; |
496 | } |
497 | |
498 | //and try some fall backs |
499 | match_t type = MATCH_NONE; |
500 | if (bestFamilyType <= MATCH_NONE && familyName2 == "helvetica"_L1) |
501 | type = MATCH_LAST_RESORT; |
502 | if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().constFirst()) |
503 | type = MATCH_APP; |
504 | // ### add fallback for writingSystem |
505 | if (type != MATCH_NONE) { |
506 | bestFamilyType = type; |
507 | bestFamilyMatch = i; |
508 | } |
509 | } |
510 | |
511 | if (i != -1 && bestFamilyType != MATCH_NONE) |
512 | familyList->setCurrentItem(bestFamilyMatch); |
513 | else |
514 | familyList->setCurrentItem(0); |
515 | familyEdit->setText(familyList->currentText()); |
516 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
517 | && familyList->hasFocus()) |
518 | familyEdit->selectAll(); |
519 | |
520 | updateStyles(); |
521 | } |
522 | |
523 | /* |
524 | Updates the contents of the "font style" list box. This |
525 | function can be reimplemented if you have special requirements. |
526 | */ |
527 | void QFontDialogPrivate::updateStyles() |
528 | { |
529 | Q_Q(QFontDialog); |
530 | QStringList styles = QFontDatabase::styles(family: familyList->currentText()); |
531 | styleList->model()->setStringList(styles); |
532 | |
533 | if (styles.isEmpty()) { |
534 | styleEdit->clear(); |
535 | smoothScalable = false; |
536 | } else { |
537 | if (!style.isEmpty()) { |
538 | bool found = false; |
539 | bool first = true; |
540 | QString cstyle = style; |
541 | |
542 | redo: |
543 | for (int i = 0; i < static_cast<int>(styleList->count()); i++) { |
544 | if (cstyle == styleList->text(i)) { |
545 | styleList->setCurrentItem(i); |
546 | found = true; |
547 | break; |
548 | } |
549 | } |
550 | if (!found && first) { |
551 | if (cstyle.contains(s: "Italic"_L1)) { |
552 | cstyle.replace(before: "Italic"_L1, after: "Oblique"_L1); |
553 | first = false; |
554 | goto redo; |
555 | } else if (cstyle.contains(s: "Oblique"_L1)) { |
556 | cstyle.replace(before: "Oblique"_L1, after: "Italic"_L1); |
557 | first = false; |
558 | goto redo; |
559 | } else if (cstyle.contains(s: "Regular"_L1)) { |
560 | cstyle.replace(before: "Regular"_L1, after: "Normal"_L1); |
561 | first = false; |
562 | goto redo; |
563 | } else if (cstyle.contains(s: "Normal"_L1)) { |
564 | cstyle.replace(before: "Normal"_L1, after: "Regular"_L1); |
565 | first = false; |
566 | goto redo; |
567 | } |
568 | } |
569 | if (!found) |
570 | styleList->setCurrentItem(0); |
571 | } else { |
572 | styleList->setCurrentItem(0); |
573 | } |
574 | |
575 | styleEdit->setText(styleList->currentText()); |
576 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
577 | && styleList->hasFocus()) |
578 | styleEdit->selectAll(); |
579 | |
580 | smoothScalable = QFontDatabase::isSmoothlyScalable(family: familyList->currentText(), style: styleList->currentText()); |
581 | } |
582 | |
583 | updateSizes(); |
584 | } |
585 | |
586 | /*! |
587 | \internal |
588 | Updates the contents of the "font size" list box. This |
589 | function can be reimplemented if you have special requirements. |
590 | */ |
591 | |
592 | void QFontDialogPrivate::updateSizes() |
593 | { |
594 | Q_Q(QFontDialog); |
595 | |
596 | if (!familyList->currentText().isEmpty()) { |
597 | QList<int> sizes = QFontDatabase::pointSizes(family: familyList->currentText(), style: styleList->currentText()); |
598 | |
599 | int i = 0; |
600 | int current = -1; |
601 | QStringList str_sizes; |
602 | str_sizes.reserve(asize: sizes.size()); |
603 | for(QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); ++it) { |
604 | str_sizes.append(t: QString::number(*it)); |
605 | if (current == -1 && *it == size) |
606 | current = i; |
607 | ++i; |
608 | } |
609 | sizeList->model()->setStringList(str_sizes); |
610 | if (current != -1) |
611 | sizeList->setCurrentItem(current); |
612 | |
613 | const QSignalBlocker blocker(sizeEdit); |
614 | sizeEdit->setText((smoothScalable ? QString::number(size) : sizeList->currentText())); |
615 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
616 | && sizeList->hasFocus()) |
617 | sizeEdit->selectAll(); |
618 | } else { |
619 | sizeEdit->clear(); |
620 | } |
621 | |
622 | updateSample(); |
623 | } |
624 | |
625 | void QFontDialogPrivate::updateSample() |
626 | { |
627 | // compute new font |
628 | int pSize = sizeEdit->text().toInt(); |
629 | QFont newFont(QFontDatabase::font(family: familyList->currentText(), style, pointSize: pSize)); |
630 | newFont.setStrikeOut(strikeout->isChecked()); |
631 | newFont.setUnderline(underline->isChecked()); |
632 | |
633 | if (familyList->currentText().isEmpty()) |
634 | sampleEdit->clear(); |
635 | |
636 | updateSampleFont(newFont); |
637 | } |
638 | |
639 | void QFontDialogPrivate::updateSampleFont(const QFont &newFont) |
640 | { |
641 | Q_Q(QFontDialog); |
642 | if (newFont != sampleEdit->font()) { |
643 | sampleEdit->setFont(newFont); |
644 | emit q->currentFontChanged(font: newFont); |
645 | } |
646 | } |
647 | |
648 | /*! |
649 | \internal |
650 | */ |
651 | void QFontDialogPrivate::writingSystemHighlighted(int index) |
652 | { |
653 | writingSystem = QFontDatabase::WritingSystem(index); |
654 | sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem)); |
655 | updateFamilies(); |
656 | } |
657 | |
658 | /*! |
659 | \internal |
660 | */ |
661 | void QFontDialogPrivate::familyHighlighted(int i) |
662 | { |
663 | Q_Q(QFontDialog); |
664 | family = familyList->text(i); |
665 | familyEdit->setText(family); |
666 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
667 | && familyList->hasFocus()) |
668 | familyEdit->selectAll(); |
669 | |
670 | updateStyles(); |
671 | } |
672 | |
673 | |
674 | /*! |
675 | \internal |
676 | */ |
677 | |
678 | void QFontDialogPrivate::styleHighlighted(int index) |
679 | { |
680 | Q_Q(QFontDialog); |
681 | QString s = styleList->text(i: index); |
682 | styleEdit->setText(s); |
683 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
684 | && styleList->hasFocus()) |
685 | styleEdit->selectAll(); |
686 | |
687 | style = s; |
688 | |
689 | updateSizes(); |
690 | } |
691 | |
692 | |
693 | /*! |
694 | \internal |
695 | */ |
696 | |
697 | void QFontDialogPrivate::sizeHighlighted(int index) |
698 | { |
699 | Q_Q(QFontDialog); |
700 | QString s = sizeList->text(i: index); |
701 | sizeEdit->setText(s); |
702 | if (q->style()->styleHint(stylehint: QStyle::SH_FontDialog_SelectAssociatedText, opt: nullptr, widget: q) |
703 | && sizeEdit->hasFocus()) |
704 | sizeEdit->selectAll(); |
705 | |
706 | size = s.toInt(); |
707 | updateSample(); |
708 | } |
709 | |
710 | /*! |
711 | \internal |
712 | This slot is called if the user changes the font size. |
713 | The size is passed in the \a s argument as a \e string. |
714 | */ |
715 | |
716 | void QFontDialogPrivate::sizeChanged(const QString &s) |
717 | { |
718 | // no need to check if the conversion is valid, since we have an QIntValidator in the size edit |
719 | int size = s.toInt(); |
720 | if (this->size == size) |
721 | return; |
722 | |
723 | this->size = size; |
724 | if (sizeList->count() != 0) { |
725 | int i; |
726 | for (i = 0; i < sizeList->count() - 1; i++) { |
727 | if (sizeList->text(i).toInt() >= this->size) |
728 | break; |
729 | } |
730 | const QSignalBlocker blocker(sizeList); |
731 | if (sizeList->text(i).toInt() == this->size) |
732 | sizeList->setCurrentItem(i); |
733 | else |
734 | sizeList->clearSelection(); |
735 | } |
736 | updateSample(); |
737 | } |
738 | |
739 | void QFontDialogPrivate::retranslateStrings() |
740 | { |
741 | familyAccel->setText(QFontDialog::tr(s: "&Font")); |
742 | styleAccel->setText(QFontDialog::tr(s: "Font st&yle")); |
743 | sizeAccel->setText(QFontDialog::tr(s: "&Size")); |
744 | effects->setTitle(QFontDialog::tr(s: "Effects")); |
745 | strikeout->setText(QFontDialog::tr(s: "Stri&keout")); |
746 | underline->setText(QFontDialog::tr(s: "&Underline")); |
747 | sample->setTitle(QFontDialog::tr(s: "Sample")); |
748 | writingSystemAccel->setText(QFontDialog::tr(s: "Wr&iting System")); |
749 | } |
750 | |
751 | /*! |
752 | \reimp |
753 | */ |
754 | void QFontDialog::changeEvent(QEvent *e) |
755 | { |
756 | Q_D(QFontDialog); |
757 | if (e->type() == QEvent::LanguageChange) { |
758 | d->retranslateStrings(); |
759 | } |
760 | QDialog::changeEvent(e); |
761 | } |
762 | |
763 | /*! |
764 | \property QFontDialog::currentFont |
765 | \brief the current font of the dialog. |
766 | */ |
767 | |
768 | /*! |
769 | Sets the font highlighted in the QFontDialog to the given \a font. |
770 | |
771 | \sa selectedFont() |
772 | */ |
773 | void QFontDialog::setCurrentFont(const QFont &font) |
774 | { |
775 | Q_D(QFontDialog); |
776 | d->family = font.families().value(i: 0); |
777 | d->style = QFontDatabase::styleString(font); |
778 | d->size = font.pointSize(); |
779 | if (d->size == -1) { |
780 | QFontInfo fi(font); |
781 | d->size = fi.pointSize(); |
782 | } |
783 | d->strikeout->setChecked(font.strikeOut()); |
784 | d->underline->setChecked(font.underline()); |
785 | d->updateFamilies(); |
786 | |
787 | if (d->nativeDialogInUse) { |
788 | if (QPlatformFontDialogHelper *helper = d->platformFontDialogHelper()) |
789 | helper->setCurrentFont(font); |
790 | } |
791 | } |
792 | |
793 | /*! |
794 | Returns the current font. |
795 | |
796 | \sa selectedFont() |
797 | */ |
798 | QFont QFontDialog::currentFont() const |
799 | { |
800 | Q_D(const QFontDialog); |
801 | |
802 | if (d->nativeDialogInUse) { |
803 | if (const QPlatformFontDialogHelper *helper = d->platformFontDialogHelper()) |
804 | return helper->currentFont(); |
805 | } |
806 | return d->sampleEdit->font(); |
807 | } |
808 | |
809 | /*! |
810 | Returns the font that the user selected by clicking the \uicontrol{OK} |
811 | or equivalent button. |
812 | |
813 | \note This font is not always the same as the font held by the |
814 | \l currentFont property since the user can choose different fonts |
815 | before finally selecting the one to use. |
816 | */ |
817 | QFont QFontDialog::selectedFont() const |
818 | { |
819 | Q_D(const QFontDialog); |
820 | return d->selectedFont; |
821 | } |
822 | |
823 | /*! |
824 | \enum QFontDialog::FontDialogOption |
825 | |
826 | This enum specifies various options that affect the look and feel |
827 | of a font dialog. |
828 | |
829 | For instance, it allows to specify which type of font should be |
830 | displayed. If none are specified all fonts available will be listed. |
831 | |
832 | Note that the font filtering options might not be supported on some |
833 | platforms (e.g. Mac). They are always supported by the non native |
834 | dialog (used on Windows or Linux). |
835 | |
836 | \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".) |
837 | \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's |
838 | native font panel. |
839 | \value ScalableFonts Show scalable fonts |
840 | \value NonScalableFonts Show non scalable fonts |
841 | \value MonospacedFonts Show monospaced fonts |
842 | \value ProportionalFonts Show proportional fonts |
843 | |
844 | \sa options, setOption(), testOption() |
845 | */ |
846 | |
847 | /*! |
848 | Sets the given \a option to be enabled if \a on is true; |
849 | otherwise, clears the given \a option. |
850 | |
851 | \sa options, testOption() |
852 | */ |
853 | void QFontDialog::setOption(FontDialogOption option, bool on) |
854 | { |
855 | const QFontDialog::FontDialogOptions previousOptions = options(); |
856 | if (!(previousOptions & option) != !on) |
857 | setOptions(previousOptions ^ option); |
858 | } |
859 | |
860 | /*! |
861 | Returns \c true if the given \a option is enabled; otherwise, returns |
862 | false. |
863 | |
864 | \sa options, setOption() |
865 | */ |
866 | bool QFontDialog::testOption(FontDialogOption option) const |
867 | { |
868 | Q_D(const QFontDialog); |
869 | return d->options->testOption(option: static_cast<QFontDialogOptions::FontDialogOption>(option)); |
870 | } |
871 | |
872 | /*! |
873 | \property QFontDialog::options |
874 | \brief the various options that affect the look and feel of the dialog |
875 | |
876 | By default, all options are disabled. |
877 | |
878 | Options should be set before showing the dialog. Setting them while the |
879 | dialog is visible is not guaranteed to have an immediate effect on the |
880 | dialog (depending on the option and on the platform). |
881 | |
882 | \sa setOption(), testOption() |
883 | */ |
884 | void QFontDialog::setOptions(FontDialogOptions options) |
885 | { |
886 | Q_D(QFontDialog); |
887 | |
888 | if (QFontDialog::options() == options) |
889 | return; |
890 | |
891 | d->options->setOptions(QFontDialogOptions::FontDialogOptions(int(options))); |
892 | d->buttonBox->setVisible(!(options & NoButtons)); |
893 | } |
894 | |
895 | QFontDialog::FontDialogOptions QFontDialog::options() const |
896 | { |
897 | Q_D(const QFontDialog); |
898 | return QFontDialog::FontDialogOptions(int(d->options->options())); |
899 | } |
900 | |
901 | /*! |
902 | Opens the dialog and connects its fontSelected() signal to the slot specified |
903 | by \a receiver and \a member. |
904 | |
905 | The signal will be disconnected from the slot when the dialog is closed. |
906 | */ |
907 | void QFontDialog::open(QObject *receiver, const char *member) |
908 | { |
909 | Q_D(QFontDialog); |
910 | connect(sender: this, SIGNAL(fontSelected(QFont)), receiver, member); |
911 | d->receiverToDisconnectOnClose = receiver; |
912 | d->memberToDisconnectOnClose = member; |
913 | QDialog::open(); |
914 | } |
915 | |
916 | /*! |
917 | \fn void QFontDialog::currentFontChanged(const QFont &font) |
918 | |
919 | This signal is emitted when the current font is changed. The new font is |
920 | specified in \a font. |
921 | |
922 | The signal is emitted while a user is selecting a font. Ultimately, the |
923 | chosen font may differ from the font currently selected. |
924 | |
925 | \sa currentFont, fontSelected(), selectedFont() |
926 | */ |
927 | |
928 | /*! |
929 | \fn void QFontDialog::fontSelected(const QFont &font) |
930 | |
931 | This signal is emitted when a font has been selected. The selected font is |
932 | specified in \a font. |
933 | |
934 | The signal is only emitted when a user has chosen the final font to be |
935 | used. It is not emitted while the user is changing the current font in the |
936 | font dialog. |
937 | |
938 | \sa selectedFont(), currentFontChanged(), currentFont |
939 | */ |
940 | |
941 | /*! |
942 | \reimp |
943 | */ |
944 | void QFontDialog::setVisible(bool visible) |
945 | { |
946 | // will call QFontDialogPrivate::setVisible |
947 | QDialog::setVisible(visible); |
948 | } |
949 | |
950 | /*! |
951 | \internal |
952 | |
953 | The implementation of QFontDialog::setVisible() has to live here so that the call |
954 | to hide() in ~QDialog calls this function; it wouldn't call the override of |
955 | QDialog::setVisible(). |
956 | */ |
957 | void QFontDialogPrivate::setVisible(bool visible) |
958 | { |
959 | Q_Q(QFontDialog); |
960 | |
961 | if (canBeNativeDialog()) |
962 | setNativeDialogVisible(visible); |
963 | if (nativeDialogInUse) { |
964 | // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below |
965 | // updates the state correctly, but skips showing the non-native version: |
966 | q->setAttribute(Qt::WA_DontShowOnScreen, on: true); |
967 | } else { |
968 | q->setAttribute(Qt::WA_DontShowOnScreen, on: false); |
969 | } |
970 | QDialogPrivate::setVisible(visible); |
971 | } |
972 | |
973 | /*! |
974 | Closes the dialog and sets its result code to \a result. If this dialog |
975 | is shown with exec(), done() causes the local event loop to finish, |
976 | and exec() to return \a result. |
977 | |
978 | \sa QDialog::done() |
979 | */ |
980 | void QFontDialog::done(int result) |
981 | { |
982 | Q_D(QFontDialog); |
983 | if (result == Accepted) { |
984 | // We check if this is the same font we had before, if so we emit currentFontChanged |
985 | QFont selectedFont = currentFont(); |
986 | if (selectedFont != d->selectedFont) |
987 | emit(currentFontChanged(font: selectedFont)); |
988 | d->selectedFont = selectedFont; |
989 | emit fontSelected(font: d->selectedFont); |
990 | } else |
991 | d->selectedFont = QFont(); |
992 | if (d->receiverToDisconnectOnClose) { |
993 | disconnect(sender: this, SIGNAL(fontSelected(QFont)), |
994 | receiver: d->receiverToDisconnectOnClose, member: d->memberToDisconnectOnClose); |
995 | d->receiverToDisconnectOnClose = nullptr; |
996 | } |
997 | d->memberToDisconnectOnClose.clear(); |
998 | QDialog::done(result); |
999 | } |
1000 | |
1001 | bool QFontDialogPrivate::canBeNativeDialog() const |
1002 | { |
1003 | // Don't use Q_Q here! This function is called from ~QDialog, |
1004 | // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()). |
1005 | const QDialog * const q = static_cast<const QDialog*>(q_ptr); |
1006 | if (nativeDialogInUse) |
1007 | return true; |
1008 | if (QCoreApplication::testAttribute(attribute: Qt::AA_DontUseNativeDialogs) |
1009 | || q->testAttribute(attribute: Qt::WA_DontShowOnScreen) |
1010 | || (options->options() & QFontDialog::DontUseNativeDialog)) { |
1011 | return false; |
1012 | } |
1013 | |
1014 | return strcmp(s1: QFontDialog::staticMetaObject.className(), s2: q->metaObject()->className()) == 0; |
1015 | } |
1016 | |
1017 | QT_END_NAMESPACE |
1018 | |
1019 | #include "qfontdialog.moc" |
1020 | #include "moc_qfontdialog.cpp" |
1021 |
Definitions
- QFontListView
- model
- setCurrentItem
- currentItem
- count
- currentText
- currentChanged
- text
- QFontListView
- qfd_DefaultWindowFlags
- QFontDialogPrivate
- ~QFontDialogPrivate
- QFontDialog
- QFontDialog
- init
- ~QFontDialog
- getFont
- getFont
- getFont
- eventFilter
- initHelper
- helperPrepareShow
- updateFamilies
- updateStyles
- updateSizes
- updateSample
- updateSampleFont
- writingSystemHighlighted
- familyHighlighted
- styleHighlighted
- sizeHighlighted
- sizeChanged
- retranslateStrings
- changeEvent
- setCurrentFont
- currentFont
- selectedFont
- setOption
- testOption
- setOptions
- options
- open
- setVisible
- setVisible
- done
Learn Advanced QML with KDAB
Find out more