| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the tools applications of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "mainwindow.h" |
| |
| #include <QFontComboBox> |
| #include <QFontDatabase> |
| #include <QFileDialog> |
| #include <QMessageBox> |
| #include <QListWidget> |
| #include <QDebug> |
| #include <QShortcut> |
| #include <QCompleter> |
| #include <QDirModel> |
| #include <QRegularExpression> |
| #include <QTextCodec> |
| |
| QT_BEGIN_NAMESPACE |
| |
| MainWindow::MainWindow(const QString &customFont) |
| { |
| setupUi(this); |
| pixelSize->setValue(QFontInfo(QFont()).pixelSize()); |
| populateCharacterRanges(); |
| |
| { |
| weightCombo->addItem(QLatin1String("Light"), QVariant(int(QFont::Light))); |
| const int normalIdx = weightCombo->count(); |
| weightCombo->addItem(QLatin1String("Normal"), QVariant(int(QFont::Normal))); |
| weightCombo->addItem(QLatin1String("DemiBold"), QVariant(int(QFont::DemiBold))); |
| weightCombo->addItem(QLatin1String("Bold"), QVariant(int(QFont::Bold))); |
| weightCombo->addItem(QLatin1String("Black"), QVariant(int(QFont::Black))); |
| |
| weightCombo->setCurrentIndex(normalIdx); |
| } |
| |
| QShortcut *sc = new QShortcut(Qt::ControlModifier + Qt::Key_A, this); |
| connect(sc, SIGNAL(activated()), |
| this, SLOT(on_selectAll_clicked())); |
| sc = new QShortcut(Qt::ControlModifier + Qt::Key_D, this); |
| connect(sc, SIGNAL(activated()), |
| this, SLOT(on_deselectAll_clicked())); |
| sc = new QShortcut(Qt::ControlModifier + Qt::Key_I, this); |
| connect(sc, SIGNAL(activated()), |
| this, SLOT(on_invertSelection_clicked())); |
| |
| QCompleter *completer = new QCompleter(this); |
| completer->setModel(new QDirModel(this)); |
| path->setCompleter(completer); |
| path->setText(QDir::currentPath()); |
| |
| completer = new QCompleter(this); |
| completer->setModel(new QDirModel(this)); |
| sampleFile->setCompleter(completer); |
| charCount->setText(QString()); |
| |
| if (!customFont.isEmpty()) |
| addCustomFont(customFont); |
| |
| fontChanged(); |
| |
| connect(fontComboBox, SIGNAL(currentFontChanged(QFont)), |
| this, SLOT(fontChanged())); |
| connect(pixelSize, SIGNAL(valueChanged(int)), |
| this, SLOT(fontChanged())); |
| connect(italic, SIGNAL(stateChanged(int)), |
| this, SLOT(fontChanged())); |
| connect(weightCombo, SIGNAL(currentIndexChanged(int)), |
| this, SLOT(fontChanged())); |
| } |
| |
| void MainWindow::on_actionAdd_Custom_Font_triggered() |
| { |
| QString fontFile = QFileDialog::getOpenFileName(this, tr("Add Custom Font")); |
| if (fontFile.isEmpty()) |
| return; |
| addCustomFont(fontFile); |
| } |
| |
| void MainWindow::on_selectAll_clicked() |
| { |
| for (int i = 0; i < characterRangeView->count(); ++i) |
| characterRangeView->item(i)->setCheckState(Qt::Checked); |
| } |
| |
| void MainWindow::on_deselectAll_clicked() |
| { |
| for (int i = 0; i < characterRangeView->count(); ++i) |
| characterRangeView->item(i)->setCheckState(Qt::Unchecked); |
| } |
| |
| void MainWindow::on_invertSelection_clicked() |
| { |
| for (int i = 0; i < characterRangeView->count(); ++i) { |
| QListWidgetItem *item = characterRangeView->item(i); |
| if (item->checkState() == Qt::Checked) |
| item->setCheckState(Qt::Unchecked); |
| else |
| item->setCheckState(Qt::Checked); |
| } |
| } |
| |
| void MainWindow::fontChanged() |
| { |
| QFont f = preview->font(); |
| f.setStyleStrategy(QFont::NoFontMerging); |
| f.setPixelSize(pixelSize->value()); |
| f.setFamily(fontComboBox->currentFont().family()); |
| f.setItalic(italic->isChecked()); |
| f.setWeight(weightCombo->itemData(weightCombo->currentIndex()).toInt()); |
| |
| if (!preview->isModified()) { |
| QFontDatabase db; |
| QFontDatabase::WritingSystem ws = db.writingSystems(f.family()).value(0, QFontDatabase::Any); |
| QString sample = db.writingSystemSample(ws); |
| preview->setText(sample); |
| preview->setModified(false); |
| } |
| |
| fileName->setText(QPF::fileNameForFont(f)); |
| |
| preview->setFont(f); |
| } |
| |
| void MainWindow::on_browsePath_clicked() |
| { |
| QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory")); |
| if (!dir.isEmpty()) |
| path->setText(dir); |
| } |
| |
| void MainWindow::on_browseSampleFile_clicked() |
| { |
| QString dir = QFileDialog::getOpenFileName(this, tr("Select Sample File")); |
| if (!dir.isEmpty()) { |
| sampleFile->setText(dir); |
| on_sampleFile_editingFinished(); |
| } |
| } |
| |
| void MainWindow::on_generate_clicked() |
| { |
| QFile f(path->text() + QDir::separator() + fileName->text()); |
| if (f.exists()) { |
| if (QMessageBox::warning(this, QString(), |
| tr("%1 already exists.\nDo you want to replace it?").arg(f.fileName()), |
| QMessageBox::Yes | QMessageBox::No, QMessageBox::No) |
| != QMessageBox::Yes) { |
| statusBar()->showMessage(tr("Pre-rendering aborted...")); |
| return; |
| } |
| } |
| |
| QList<QPF::CharacterRange> ranges; |
| |
| if (chooseFromSampleFile->isChecked()) { |
| ranges = sampleFileRanges; |
| } else if (chooseFromCodePoints->isChecked()) { |
| ranges.clear(); |
| for (int i = 0; i < characterRangeView->count(); ++i) { |
| QListWidgetItem *item = characterRangeView->item(i); |
| if (item->checkState() != Qt::Checked) |
| continue; |
| |
| QPF::CharacterRange range = qvariant_cast<QPF::CharacterRange>(item->data(Qt::UserRole)); |
| ranges.append(range); |
| } |
| } |
| |
| const int generationOptions = QPF::IncludeCMap | QPF::RenderGlyphs; |
| QByteArray qpf = QPF::generate(preview->font(), generationOptions, ranges); |
| f.open(QIODevice::WriteOnly | QIODevice::Truncate); |
| f.write(qpf); |
| f.close(); |
| |
| statusBar()->showMessage(tr("Font successfully pre-rendered to %1").arg(fileName->text())); |
| } |
| |
| void MainWindow::on_sampleFile_editingFinished() |
| { |
| sampleFileRanges.clear(); |
| QFile f(sampleFile->text()); |
| if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { |
| sampleFileRanges.append(QPF::CharacterRange()); // default = all |
| return; |
| } |
| QTextStream stream(&f); |
| stream.setCodec(QTextCodec::codecForName("utf-8")); |
| stream.setAutoDetectUnicode(true); |
| QString text = stream.readAll(); |
| |
| QSet<QChar> coverage; |
| for (int i = 0; i < text.length(); ++i) |
| coverage.insert(text.at(i)); |
| |
| QList<QChar> sortedCoverage = QList<QChar>::fromSet(coverage); |
| std::sort(sortedCoverage.begin(), sortedCoverage.end()); |
| // play simple :) |
| for (QChar ch : qAsConst(sortedCoverage)) { |
| QPF::CharacterRange r; |
| r.start = ch.unicode(); |
| r.end = r.start + 1; |
| sampleFileRanges.append(r); |
| } |
| |
| charCount->setText(tr("(%1 unique characters found)").arg(sortedCoverage.count())); |
| } |
| |
| void MainWindow::populateCharacterRanges() |
| { |
| QFile f(":/Blocks.txt"); |
| if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) |
| return; |
| |
| QRegularExpression rangeExpr( |
| QRegularExpression::anchoredPattern("([0-9a-f]+)\\.\\.([0-9a-f]+); (.+)"), |
| QRegularExpression::CaseInsensitiveOption |
| ); |
| |
| QString ellipsis(QChar(0x2026)); |
| if (!characterRangeView->fontMetrics().inFont(ellipsis.at(0))) |
| ellipsis = QLatin1String("..."); |
| |
| while (!f.atEnd()) { |
| QString line = QString::fromLatin1(f.readLine()); |
| |
| if (line.endsWith(QLatin1Char('\n'))) |
| line.chop(1); |
| if (line.endsWith(QLatin1Char('\r'))) |
| line.chop(1); |
| |
| line = line.trimmed(); |
| |
| if (line.isEmpty() || line.startsWith(QLatin1Char('#'))) |
| continue; |
| |
| QRegularExpressionMatch match = rangeExpr.match(line); |
| if (!match.hasMatch()) |
| continue; |
| |
| QPF::CharacterRange range; |
| |
| bool ok = false; |
| range.start = match.captured(1).toUInt(&ok, /*base*/16); |
| if (!ok) |
| continue; |
| range.end = match.captured(2).toUInt(&ok, /*base*/16); |
| if (!ok) |
| continue; |
| |
| if (range.start >= 0xffff || range.end >= 0xffff) |
| continue; |
| |
| QString description = match.captured(3); |
| |
| QListWidgetItem *item = new QListWidgetItem(characterRangeView); |
| QString text = description; |
| text.append(QLatin1String(" (")); |
| text.append(match.captured(1)); |
| text.append(ellipsis); |
| text.append(match.captured(2)); |
| text.append(QLatin1String(")")); |
| item->setText(text); |
| item->setCheckState(Qt::Checked); |
| |
| item->setData(Qt::UserRole, QVariant::fromValue(range)); |
| } |
| } |
| |
| void MainWindow::addCustomFont(const QString &fontFile) |
| { |
| int id = QFontDatabase::addApplicationFont(fontFile); |
| if (id < 0) { |
| QMessageBox::warning(this, tr("Error Adding Custom Font"), |
| tr("The custom font %s could not be loaded.").arg(fontFile)); |
| return; |
| } |
| const QStringList families = QFontDatabase::applicationFontFamilies(id); |
| if (families.isEmpty()) { |
| QMessageBox::warning(this, tr("Error Adding Custom Font"), |
| tr("The custom font %s provides no font families.").arg(fontFile)); |
| return; |
| } |
| QFont f(families.first()); |
| fontComboBox->setCurrentFont(f); |
| } |
| |
| QT_END_NAMESPACE |