|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
#include "plFontConverter.h"
|
|
|
|
#include "plFontFreeType.h"
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
#include "HeadSpin.h"
|
|
|
|
#include "hsWindows.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "pnAllCreatables.h"
|
|
|
|
#include "plResMgr/plResManager.h"
|
|
|
|
#include "plResMgr/plResMgrCreatable.h"
|
|
|
|
#include "plResMgr/plResMgrSettings.h"
|
|
|
|
#include "plMessage/plResMgrHelperMsg.h"
|
|
|
|
REGISTER_CREATABLE(plResMgrHelperMsg);
|
|
|
|
|
|
|
|
#include "plGImage/plFont.h"
|
|
|
|
REGISTER_CREATABLE(plFont);
|
|
|
|
|
|
|
|
#include "plGImage/plBitmap.h"
|
|
|
|
#include "plGImage/plMipmap.h"
|
|
|
|
REGISTER_NONCREATABLE(plBitmap);
|
|
|
|
REGISTER_CREATABLE(plMipmap);
|
|
|
|
|
|
|
|
#include "pnKeyedObject/plUoid.h"
|
|
|
|
#include "pnKeyedObject/plKeyImp.h"
|
|
|
|
|
|
|
|
#include <QApplication>
|
|
|
|
#include <QDialog>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QFileDialog>
|
|
|
|
#include <QProgressDialog>
|
|
|
|
#include <QDragEnterEvent>
|
|
|
|
#include <QMimeData>
|
|
|
|
#include "ui_MainDialog.h"
|
|
|
|
#include "ui_FonChooser.h"
|
|
|
|
#include "ui_FreeType.h"
|
|
|
|
#include "ui_FreeTypeBatch.h"
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
static void IAboutDialog(QWidget *parent)
|
|
|
|
{
|
|
|
|
QDialog dlg(parent);
|
|
|
|
QLabel *image = new QLabel(&dlg);
|
|
|
|
image->setPixmap(QPixmap(":/icon1.ico"));
|
|
|
|
QLabel *text = new QLabel(QObject::tr(R"(plFontConverter
|
|
|
|
|
|
|
|
A simple Plasma 2.0 utility for converting public
|
|
|
|
font formats into our own bitmap font format.)"), &dlg);
|
|
|
|
QPushButton *ok = new QPushButton(QObject::tr("OK"), &dlg);
|
|
|
|
ok->setDefault(true);
|
|
|
|
|
|
|
|
QHBoxLayout *layout = new QHBoxLayout(&dlg);
|
|
|
|
layout->setMargin(8);
|
|
|
|
layout->setSpacing(10);
|
|
|
|
layout->addWidget(image);
|
|
|
|
layout->addWidget(text);
|
|
|
|
layout->addWidget(ok);
|
|
|
|
|
|
|
|
dlg.connect(ok, &QPushButton::clicked, &dlg, &QDialog::accept);
|
|
|
|
dlg.exec();
|
|
|
|
}
|
|
|
|
|
|
|
|
plFontConverter::plFontConverter()
|
|
|
|
: QMainWindow(), fFont(nullptr)
|
|
|
|
{
|
|
|
|
fUI = new Ui_MainDialog;
|
|
|
|
fUI->setupUi(this);
|
|
|
|
|
|
|
|
setAcceptDrops(true);
|
|
|
|
|
|
|
|
connect(fUI->fImportFNTAction, SIGNAL(triggered()), SLOT(OpenFNT()));
|
|
|
|
connect(fUI->fImportBDFAction, SIGNAL(triggered()), SLOT(OpenBDF()));
|
|
|
|
connect(fUI->fImportFONAction, SIGNAL(triggered()), SLOT(OpenFON()));
|
|
|
|
connect(fUI->fImportTTFAction, SIGNAL(triggered()), SLOT(OpenTTF()));
|
|
|
|
connect(fUI->fOpenAction, SIGNAL(triggered()), SLOT(OpenP2F()));
|
|
|
|
connect(fUI->fExportAction, SIGNAL(triggered()), SLOT(ExportP2F()));
|
|
|
|
connect(fUI->fExitAction, SIGNAL(triggered()), SLOT(close()));
|
|
|
|
connect(fUI->fAboutAction, &QAction::triggered, std::bind(&IAboutDialog, this));
|
|
|
|
|
|
|
|
connect(fUI->fExportButton, SIGNAL(clicked()), SLOT(ExportP2F()));
|
|
|
|
|
|
|
|
connect(fUI->fSampleText, &QLineEdit::textChanged, [this](const QString &text)
|
|
|
|
{
|
|
|
|
fUI->fPreview->Update(fFont, text);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
plFontConverter::~plFontConverter()
|
|
|
|
{
|
|
|
|
delete fUI;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::dragEnterEvent(QDragEnterEvent *event)
|
|
|
|
{
|
|
|
|
if (event->mimeData()->hasUrls())
|
|
|
|
event->acceptProposedAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::dropEvent(QDropEvent *event)
|
|
|
|
{
|
|
|
|
QList<QUrl> urls = event->mimeData()->urls();
|
|
|
|
|
|
|
|
for (const QUrl &url : urls)
|
|
|
|
{
|
|
|
|
if (!url.isLocalFile())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
plFileName fileName = url.toLocalFile().toUtf8().constData();
|
|
|
|
plString ext = fileName.GetFileExt();
|
|
|
|
if (ext.CompareI("fnt") == 0)
|
|
|
|
IImportFNT(fileName);
|
|
|
|
else if (ext.CompareI("bdf") == 0)
|
|
|
|
IImportBDF(fileName);
|
|
|
|
else if (ext.CompareI("fon") == 0 || ext.CompareI("exe") == 0)
|
|
|
|
IImportFON(fileName);
|
|
|
|
else if (ext.CompareI("ttf") == 0 || ext.CompareI("ttc") == 0)
|
|
|
|
IImportFreeType(fileName);
|
|
|
|
else if (ext.CompareI("p2f") == 0)
|
|
|
|
IOpenP2F(fileName);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Try using our freeType converter
|
|
|
|
IImportFreeType(fileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::OpenFNT()
|
|
|
|
{
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a FNT file to convert"),
|
|
|
|
QString(), "Windows FNT files (*.fnt);;All files (*.*)");
|
|
|
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
IImportFNT(fileName.toUtf8().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::OpenBDF()
|
|
|
|
{
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a BDF file to convert"),
|
|
|
|
QString(), "Adobe BDF files (*.bdf);;All files (*.*)");
|
|
|
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
IImportBDF(fileName.toUtf8().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::OpenFON()
|
|
|
|
{
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a FON file to convert"),
|
|
|
|
QString(), "Windows FON files (*.fon *.exe);;All files (*.*)");
|
|
|
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
IImportFON(fileName.toUtf8().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::OpenTTF()
|
|
|
|
{
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a TrueType font to convert"),
|
|
|
|
QString(), "TrueType files (*.ttf *.ttc);;All files (*.*)");
|
|
|
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
IImportFreeType(fileName.toUtf8().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::OpenP2F()
|
|
|
|
{
|
|
|
|
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a P2F file to open"),
|
|
|
|
QString(), "Plasma 2 font files (*.p2f);;All files (*.*)");
|
|
|
|
|
|
|
|
if (!fileName.isEmpty())
|
|
|
|
IOpenP2F(fileName.toUtf8().constData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::ExportP2F()
|
|
|
|
{
|
|
|
|
// Grab updated values for the font
|
|
|
|
plString fileName = fUI->fFaceName->text().toUtf8().constData();
|
|
|
|
fFont->SetFace(fileName);
|
|
|
|
fFont->SetSize(fUI->fFontSize->value());
|
|
|
|
fFont->SetFlag(plFont::kFlagBold, fUI->fBold->isChecked());
|
|
|
|
fFont->SetFlag(plFont::kFlagItalic, fUI->fItalic->isChecked());
|
|
|
|
|
|
|
|
// Write out
|
|
|
|
QString saveFile = QFileDialog::getSaveFileName(this, tr("Specify a file to export to"),
|
|
|
|
QString("%1-%2.p2f").arg(fFont->GetFace().c_str()).arg(fFont->GetSize()),
|
|
|
|
"Plasma 2 font files (*.p2f)");
|
|
|
|
|
|
|
|
if (!saveFile.isEmpty())
|
|
|
|
{
|
|
|
|
fileName = saveFile.toUtf8().constData();
|
|
|
|
|
|
|
|
hsUNIXStream stream;
|
|
|
|
if (!stream.Open(fileName, "wb"))
|
|
|
|
QMessageBox::critical(this, tr("Error"), tr("Can't open file for writing"));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
sprintf( fileName, "%s-%d", gFont->GetFace(), gFont->GetSize() );
|
|
|
|
|
|
|
|
if( gFont->GetKey() == nil )
|
|
|
|
hsgResMgr::ResMgr()->NewKey( fileName, gFont, plLocation::kGlobalFixedLoc );
|
|
|
|
*/
|
|
|
|
fFont->WriteRaw(&stream);
|
|
|
|
stream.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IMakeFontGoAway()
|
|
|
|
{
|
|
|
|
if (fFont != nullptr) {
|
|
|
|
plKeyImp *imp = (plKeyImp *)(fFont->GetKey());
|
|
|
|
if (imp != nullptr)
|
|
|
|
imp->SetObjectPtr(nullptr);
|
|
|
|
fFont = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IMakeNewFont()
|
|
|
|
{
|
|
|
|
IMakeFontGoAway();
|
|
|
|
fFont = new plFont();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IUpdateInfo()
|
|
|
|
{
|
|
|
|
if (fFont != nullptr && fFont->GetNumChars() == 0)
|
|
|
|
IMakeFontGoAway();
|
|
|
|
|
|
|
|
if (fFont == nullptr)
|
|
|
|
{
|
|
|
|
fUI->fExportAction->setEnabled(false);
|
|
|
|
fUI->fExportButton->setEnabled(false);
|
|
|
|
|
|
|
|
fUI->fFaceName->setText("");
|
|
|
|
fUI->fFontSize->setValue(0);
|
|
|
|
fUI->fStartingGlyph->setText("");
|
|
|
|
fUI->fGlyphCount->setText("");
|
|
|
|
|
|
|
|
fUI->fBitmapWidth->setText("");
|
|
|
|
fUI->fBitmapHeight->setText("");
|
|
|
|
fUI->fBPP->setText("");
|
|
|
|
|
|
|
|
fUI->fBold->setChecked(false);
|
|
|
|
fUI->fItalic->setChecked(false);
|
|
|
|
|
|
|
|
fUI->fPreview->Update(nullptr, QString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fUI->fExportAction->setEnabled(true);
|
|
|
|
fUI->fExportButton->setEnabled(true);
|
|
|
|
|
|
|
|
fUI->fFaceName->setText(fFont->GetFace().c_str());
|
|
|
|
fUI->fFontSize->setValue(fFont->GetSize());
|
|
|
|
fUI->fStartingGlyph->setText(QString::number(fFont->GetFirstChar()));
|
|
|
|
fUI->fGlyphCount->setText(QString::number(fFont->GetNumChars()));
|
|
|
|
|
|
|
|
fUI->fBitmapWidth->setText(QString::number(fFont->GetBitmapWidth()));
|
|
|
|
fUI->fBitmapHeight->setText(QString::number(fFont->GetBitmapHeight()));
|
|
|
|
fUI->fBPP->setText(QString::number(fFont->GetBitmapBPP()));
|
|
|
|
|
|
|
|
fUI->fBold->setChecked(fFont->IsFlagSet(plFont::kFlagBold));
|
|
|
|
fUI->fItalic->setChecked(fFont->IsFlagSet(plFont::kFlagItalic));
|
|
|
|
|
|
|
|
fUI->fPreview->Update(fFont, fUI->fSampleText->text());
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IImportFNT(const plFileName &path)
|
|
|
|
{
|
|
|
|
IMakeNewFont();
|
|
|
|
if (!fFont->LoadFromFNT(path))
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Failure converting FNT file"));
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
class ProgressRAII
|
|
|
|
{
|
|
|
|
QWidget *fParent;
|
|
|
|
QProgressDialog *fProgress;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ProgressRAII(QWidget *parent)
|
|
|
|
: fParent(parent)
|
|
|
|
{
|
|
|
|
fProgress = new QProgressDialog(parent->tr("Importing Font..."), QString(), 0, 100, parent);
|
|
|
|
fProgress->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
fParent->setEnabled(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
~ProgressRAII()
|
|
|
|
{
|
|
|
|
fProgress->close();
|
|
|
|
fParent->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetRange(int max) { fProgress->setRange(0, max); }
|
|
|
|
void SetValue(int val) { fProgress->setValue(val); }
|
|
|
|
};
|
|
|
|
|
|
|
|
class plMyBDFCallback : public plBDFConvertCallback
|
|
|
|
{
|
|
|
|
ProgressRAII fProgress;
|
|
|
|
uint16_t fPoint;
|
|
|
|
|
|
|
|
public:
|
|
|
|
plMyBDFCallback(QWidget *parent) : fProgress(parent) { }
|
|
|
|
|
|
|
|
virtual void NumChars(uint16_t chars) override
|
|
|
|
{
|
|
|
|
fProgress.SetRange(chars);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void CharDone() override
|
|
|
|
{
|
|
|
|
fPoint++;
|
|
|
|
fProgress.SetValue(fPoint);
|
|
|
|
|
|
|
|
qApp->processEvents();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void plFontConverter::IImportBDF(const plFileName &path)
|
|
|
|
{
|
|
|
|
IMakeNewFont();
|
|
|
|
|
|
|
|
plMyBDFCallback callback(this);
|
|
|
|
if (!fFont->LoadFromBDF(path, &callback))
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Failure converting BDF file"));
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
struct ResRecord
|
|
|
|
{
|
|
|
|
HRSRC fHandle;
|
|
|
|
QString fName;
|
|
|
|
|
|
|
|
ResRecord() : fHandle(nullptr) { }
|
|
|
|
ResRecord(HRSRC h, const QString &n) : fHandle(h), fName(n) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
BOOL CALLBACK ResEnumProc(HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR lParam)
|
|
|
|
{
|
|
|
|
HRSRC res = FindResource(module, name, type);
|
|
|
|
if (res != nullptr)
|
|
|
|
{
|
|
|
|
QList<ResRecord> *array = reinterpret_cast<QList<ResRecord> *>(lParam);
|
|
|
|
array->append(ResRecord(res, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ResRecord DoSelectResource(const QList<ResRecord> &resources)
|
|
|
|
{
|
|
|
|
QDialog dlg;
|
|
|
|
Ui_FonChooser ui;
|
|
|
|
ui.setupUi(&dlg);
|
|
|
|
|
|
|
|
for (const auto &rec : resources)
|
|
|
|
ui.fResourceList->addItem(rec.fName);
|
|
|
|
|
|
|
|
if (dlg.exec() == QDialog::Accepted && ui.fResourceList->currentRow() >= 0)
|
|
|
|
return resources[ui.fResourceList->currentRow()];
|
|
|
|
|
|
|
|
return ResRecord();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void plFontConverter::IImportFON(const plFileName &path)
|
|
|
|
{
|
|
|
|
// TODO: Get rid of the Windows-y stuff and parse this shit by hand
|
|
|
|
|
|
|
|
#if !defined(Q_OS_WIN) || defined(Q_OS_WIN64)
|
|
|
|
QMessageBox::critical(this, tr("ERROR"),
|
|
|
|
tr("FON import is currently only available on 32-bit Windows OSes"));
|
|
|
|
return;
|
|
|
|
#else
|
|
|
|
BOOL isWow64;
|
|
|
|
if (IsWow64Process(GetCurrentProcess(), &isWow64) && isWow64) {
|
|
|
|
// Nope, even WoW64 doesn't count... Win64 can't import a Win16
|
|
|
|
// image, regardless of whether we're running in 32- or 64-bit mode.
|
|
|
|
QMessageBox::critical(this, tr("ERROR"),
|
|
|
|
tr("FON import is currently only available on 32-bit Windows OSes"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FON files are really just resource modules
|
|
|
|
IMakeNewFont();
|
|
|
|
HMODULE file = LoadLibraryExA(path.AsString().c_str(), nil, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES);
|
|
|
|
if (file == nullptr)
|
|
|
|
{
|
|
|
|
char msg[512];
|
|
|
|
|
|
|
|
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof(msg), nil);
|
|
|
|
|
|
|
|
QMessageBox::critical(this, tr("Error"),
|
|
|
|
tr("Failure importing FON file: can't open as resource library (%1)").arg(msg));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QList<ResRecord> resList;
|
|
|
|
|
|
|
|
if (EnumResourceNames(file, "Font", ResEnumProc, (LPARAM)&resList))
|
|
|
|
{
|
|
|
|
// Put up a list of the resources so the user can choose which one
|
|
|
|
ResRecord res = DoSelectResource(resList);
|
|
|
|
if (res.fHandle != nullptr)
|
|
|
|
{
|
|
|
|
// Load the resource into a ram stream
|
|
|
|
hsRAMStream stream;
|
|
|
|
|
|
|
|
HGLOBAL glob = LoadResource(file, res.fHandle);
|
|
|
|
if (glob != nullptr)
|
|
|
|
{
|
|
|
|
void *data = LockResource(glob);
|
|
|
|
if (data != nullptr)
|
|
|
|
{
|
|
|
|
stream.Write(SizeofResource(file, res.fHandle), data);
|
|
|
|
stream.Rewind();
|
|
|
|
|
|
|
|
if (!fFont->LoadFromFNTStream(&stream))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, tr("Error"),
|
|
|
|
tr("Failure importing FON file: can't parse resource as FNT"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char msg[512];
|
|
|
|
|
|
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof(msg), nil);
|
|
|
|
|
|
|
|
QMessageBox::critical(this, tr("Error"),
|
|
|
|
tr("Failure importing FON file: can't enumerate resources (%1)").arg(msg));
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
class NumListValidator : public QValidator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NumListValidator(QObject *parent = nullptr) : QValidator(parent) { }
|
|
|
|
|
|
|
|
virtual State validate(QString &input, int &pos) const override
|
|
|
|
{
|
|
|
|
for (int ch = 0; ch < input.size(); ++ch)
|
|
|
|
{
|
|
|
|
ushort theChar = input[ch].unicode();
|
|
|
|
if ((theChar < '0' || theChar > '9') && (theChar != ' '))
|
|
|
|
return Invalid;
|
|
|
|
}
|
|
|
|
return Acceptable;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void plFontConverter::IBatchFreeType(const plFileName &path, void *init)
|
|
|
|
{
|
|
|
|
plFontFreeType::Options info;
|
|
|
|
if (init != nullptr)
|
|
|
|
info = *reinterpret_cast<plFontFreeType::Options*>(init);
|
|
|
|
|
|
|
|
QDialog dlg;
|
|
|
|
Ui_FreeTypeBatch ui;
|
|
|
|
ui.setupUi(&dlg);
|
|
|
|
dlg.layout()->setSizeConstraint(QLayout::SetFixedSize);
|
|
|
|
|
|
|
|
ui.fPointSizes->setValidator(new NumListValidator(&dlg));
|
|
|
|
|
|
|
|
ui.fPointSizes->setText(QString::number(info.fSize));
|
|
|
|
ui.fFontName->setText(path.GetFileNameNoExt().c_str());
|
|
|
|
ui.fResolution->setValue(info.fScreenRes);
|
|
|
|
ui.fMaxChar->setValue(info.fMaxCharLimit);
|
|
|
|
if (info.fBitDepth == 1)
|
|
|
|
ui.fMonochrome->setChecked(true);
|
|
|
|
else
|
|
|
|
ui.fGrayscale->setChecked(true);
|
|
|
|
|
|
|
|
if (dlg.exec() == QDialog::Rejected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QStringList sSizes = ui.fPointSizes->text().split(' ', QString::SkipEmptyParts);
|
|
|
|
QList<int> iSizes;
|
|
|
|
for (const QString &s : sSizes)
|
|
|
|
iSizes.append(s.toInt());
|
|
|
|
|
|
|
|
info.fScreenRes = ui.fResolution->value();
|
|
|
|
info.fMaxCharLimit = ui.fMaxChar->value();
|
|
|
|
info.fBitDepth = (ui.fMonochrome->isChecked() ? 1 : 8);
|
|
|
|
|
|
|
|
QString outPath = QFileDialog::getExistingDirectory(this,
|
|
|
|
tr("Select a path to write the P2F fonts to:"),
|
|
|
|
QDir::current().absolutePath(), QFileDialog::ShowDirsOnly);
|
|
|
|
if (outPath.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
plString fontName = ui.fFontName->text().toUtf8().constData();
|
|
|
|
plString destPath = outPath.toUtf8().constData();
|
|
|
|
|
|
|
|
plMyBDFCallback callback(this);
|
|
|
|
callback.NumChars(iSizes.size());
|
|
|
|
|
|
|
|
for (int size : iSizes)
|
|
|
|
{
|
|
|
|
IMakeNewFont();
|
|
|
|
plFontFreeType *ft2Convert = reinterpret_cast<plFontFreeType *>(fFont);
|
|
|
|
|
|
|
|
info.fSize = size;
|
|
|
|
if (!ft2Convert->ImportFreeType(path, &info, nil))
|
|
|
|
{
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Failure converting TrueType file"));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fFont->SetFace(fontName);
|
|
|
|
plFileName fileName = plFileName::Join(destPath,
|
|
|
|
plString::Format("%s-%d.p2f", fFont->GetFace().c_str(), fFont->GetSize()));
|
|
|
|
hsUNIXStream stream;
|
|
|
|
if (!stream.Open(fileName, "wb"))
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Can't open file for writing"));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fFont->WriteRaw(&stream);
|
|
|
|
stream.Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
callback.CharDone();
|
|
|
|
}
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IImportFreeType(const plFileName &path)
|
|
|
|
{
|
|
|
|
enum { kBatchConvertAction = 100 };
|
|
|
|
|
|
|
|
plFontFreeType::Options info;
|
|
|
|
|
|
|
|
QDialog dlg;
|
|
|
|
Ui_FreeType ui;
|
|
|
|
ui.setupUi(&dlg);
|
|
|
|
dlg.layout()->setSizeConstraint(QLayout::SetFixedSize);
|
|
|
|
|
|
|
|
// Designer can't do this...
|
|
|
|
QPushButton *batchButton = new QPushButton(tr("&Batch..."), ui.fButtons);
|
|
|
|
ui.fButtons->addButton(batchButton, QDialogButtonBox::ResetRole);
|
|
|
|
connect(batchButton, &QPushButton::clicked, &dlg,
|
|
|
|
std::bind(&QDialog::done, &dlg, kBatchConvertAction));
|
|
|
|
|
|
|
|
ui.fPointSize->setValue(info.fSize);
|
|
|
|
ui.fResolution->setValue(info.fScreenRes);
|
|
|
|
ui.fMaxChar->setValue(info.fMaxCharLimit);
|
|
|
|
if (info.fBitDepth == 1)
|
|
|
|
ui.fMonochrome->setChecked(true);
|
|
|
|
else
|
|
|
|
ui.fGrayscale->setChecked(true);
|
|
|
|
|
|
|
|
int ret = dlg.exec();
|
|
|
|
|
|
|
|
info.fSize = ui.fPointSize->value();
|
|
|
|
info.fScreenRes = ui.fResolution->value();
|
|
|
|
info.fMaxCharLimit = ui.fMaxChar->value();
|
|
|
|
info.fBitDepth = (ui.fMonochrome->isChecked() ? 1 : 8);
|
|
|
|
|
|
|
|
if (ret == QDialog::Rejected)
|
|
|
|
return;
|
|
|
|
else if (ret == kBatchConvertAction)
|
|
|
|
{
|
|
|
|
IBatchFreeType(path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMakeNewFont();
|
|
|
|
plMyBDFCallback callback(this);
|
|
|
|
|
|
|
|
plFontFreeType *ft2Convert = reinterpret_cast<plFontFreeType *>(fFont);
|
|
|
|
if (!ft2Convert->ImportFreeType(path, &info, &callback))
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Failure converting TrueType file"));
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plFontConverter::IOpenP2F(const plFileName &path)
|
|
|
|
{
|
|
|
|
IMakeNewFont();
|
|
|
|
if (!fFont->LoadFromP2FFile(path))
|
|
|
|
QMessageBox::critical(this, tr("ERROR"), tr("Failure opening P2F file"));
|
|
|
|
|
|
|
|
IUpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
QApplication app(argc, argv);
|
|
|
|
app.setApplicationName("plFontConverter");
|
|
|
|
app.setWindowIcon(QIcon(":/icon1.ico"));
|
|
|
|
|
|
|
|
plResManager *rMgr = new plResManager;
|
|
|
|
hsgResMgr::Init(rMgr);
|
|
|
|
|
|
|
|
plFontConverter mainDialog;
|
|
|
|
mainDialog.show();
|
|
|
|
int retn = app.exec();
|
|
|
|
|
|
|
|
hsgResMgr::Shutdown();
|
|
|
|
|
|
|
|
return retn;
|
|
|
|
}
|