Browse Source

Merge pull request #413 from zrax/qt_tools

Port GUI Tools to Qt5
Adam Johnson 10 years ago
parent
commit
69f1e2c511
  1. 2
      CMakeLists.txt
  2. 1
      README.md
  3. 2
      Sources/Plasma/CoreLib/hsThread_Unix.cpp
  4. 2
      Sources/Plasma/CoreLib/plFileSystem.cpp
  5. 47
      Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp
  6. 3
      Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp
  7. 6
      Sources/Plasma/PubUtilLib/plGImage/plFont.cpp
  8. 4
      Sources/Plasma/PubUtilLib/plGImage/plFont.h
  9. 3
      Sources/Tools/CMakeLists.txt
  10. 57
      Sources/Tools/plFontConverter/CMakeLists.txt
  11. 609
      Sources/Tools/plFontConverter/plFontConverter.cpp
  12. 86
      Sources/Tools/plFontConverter/plFontConverter.h
  13. 756
      Sources/Tools/plFontConverter/plFontConverterProc.cpp
  14. 8
      Sources/Tools/plFontConverter/plFontFreeType.cpp
  15. 8
      Sources/Tools/plFontConverter/plFontFreeType.h
  16. 115
      Sources/Tools/plFontConverter/plFontPreview.cpp
  17. 54
      Sources/Tools/plFontConverter/plFontPreview.h
  18. 81
      Sources/Tools/plFontConverter/res/FonChooser.ui
  19. 137
      Sources/Tools/plFontConverter/res/FreeType.ui
  20. 159
      Sources/Tools/plFontConverter/res/FreeTypeBatch.ui
  21. 355
      Sources/Tools/plFontConverter/res/MainDialog.ui
  22. 5
      Sources/Tools/plFontConverter/res/plFontConverter.qrc
  23. 269
      Sources/Tools/plFontConverter/res/plFontConverter.rc
  24. 52
      Sources/Tools/plFontConverter/res/resource.h
  25. 48
      Sources/Tools/plLocalizationEditor/CMakeLists.txt
  26. 375
      Sources/Tools/plLocalizationEditor/plAddDlgs.cpp
  27. 53
      Sources/Tools/plLocalizationEditor/plAddDlgs.h
  28. 444
      Sources/Tools/plLocalizationEditor/plEditDlg.cpp
  29. 61
      Sources/Tools/plLocalizationEditor/plEditDlg.h
  30. 131
      Sources/Tools/plLocalizationEditor/plLocTreeView.cpp
  31. 19
      Sources/Tools/plLocalizationEditor/plLocTreeView.h
  32. 339
      Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp
  33. 133
      Sources/Tools/plLocalizationEditor/res/AddElement.ui
  34. 94
      Sources/Tools/plLocalizationEditor/res/AddLocalization.ui
  35. 181
      Sources/Tools/plLocalizationEditor/res/EditDialog.ui
  36. 5
      Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc
  37. 269
      Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc
  38. 51
      Sources/Tools/plLocalizationEditor/res/resource.h
  39. 85
      Sources/Tools/plResBrowser/CMakeLists.txt
  40. 425
      Sources/Tools/plResBrowser/plResBrowser.cpp
  41. 76
      Sources/Tools/plResBrowser/plResBrowser.h
  42. 432
      Sources/Tools/plResBrowser/plResBrowserWndProc.cpp
  43. 497
      Sources/Tools/plResBrowser/plResTreeView.cpp
  44. 51
      Sources/Tools/plResBrowser/plResTreeView.h
  45. 73
      Sources/Tools/plResBrowser/plWinRegistryTools.cpp
  46. 21
      Sources/Tools/plResBrowser/plWinRegistryTools.h
  47. 76
      Sources/Tools/plResBrowser/res/FindDialog.ui
  48. 575
      Sources/Tools/plResBrowser/res/ResBrowser.ui
  49. 5
      Sources/Tools/plResBrowser/res/plResBrowser.qrc
  50. 203
      Sources/Tools/plResBrowser/res/plResBrowser.rc
  51. 68
      Sources/Tools/plResBrowser/res/resource.h

2
CMakeLists.txt

@ -46,11 +46,11 @@ find_package(Ogg REQUIRED) #TODO: Not required if we aren't building the clie
find_package(Vorbis REQUIRED) #TODO: Not required if we aren't building the client
find_package(Speex REQUIRED) #TODO: Not required if we aren't building the client
find_package(CURL REQUIRED)
find_package(Freetype)
if(WIN32)
find_package(PhysX REQUIRED) #TODO: Not required if we aren't building the client
find_package(DirectX REQUIRED)
find_package(Freetype)
endif(WIN32)
find_package(Bink) #TODO: Find Bink, but don't require it if plPipeline isn't built...

1
README.md

@ -38,6 +38,7 @@ The following libraries are optional:
- (for building resource.dat) PyGTK - http://www.pygtk.org/downloads.html
- (for building resource.dat) PIL - http://www.pythonware.com/products/pil/
- (for plFontConverter) Freetype - http://freetype.org/
- (for the GUI tools) Qt5 - http://qt-project.org/
Reducing the use of proprietary libraries is a focus of development and should be expected to change.

2
Sources/Plasma/CoreLib/hsThread_Unix.cpp

@ -307,8 +307,8 @@ hsSemaphore::~hsSemaphore()
status = sem_close(fPSema);
} else {
status = sem_destroy(fPSema);
delete fPSema;
}
delete fPSema;
hsThrowIfOSErr(status);
#else
int status = ::pthread_cond_destroy(&fPCond);

2
Sources/Plasma/CoreLib/plFileSystem.cpp

@ -394,7 +394,7 @@ std::vector<plFileName> plFileSystem::ListDir(const plFileName &path, const char
continue;
}
if (pattern && pattern[0] && fnmatch(pattern, de->d_name, 0))
if (pattern && pattern[0] && fnmatch(pattern, de->d_name, 0) == 0)
contents.push_back(dir_name);
else if (!pattern || !pattern[0])
contents.push_back(dir_name);

47
Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp

@ -691,11 +691,14 @@ bool pfLocalizationDataMgr::pf3PartMap<mapT>::exists(const plString & key)
return false;
// now check individually
if (fData.find(age) == fData.end()) // age doesn't exist
auto curAge = fData.find(age);
if (curAge == fData.end()) // age doesn't exist
return false;
if (fData[age].find(set) == fData[age].end()) // set doesn't exist
auto curSet = curAge->second.find(set);
if (curSet == curAge->second.end()) // set doesn't exist
return false;
if (fData[age][set].find(name) == fData[age][set].end()) // name doesn't exist
auto curElement = curSet->second.find(name);
if (curElement == curSet->second.end()) // name doesn't exist
return false;
// we passed all the tests, return true!
@ -713,9 +716,11 @@ bool pfLocalizationDataMgr::pf3PartMap<mapT>::setExists(const plString & key)
return false;
// now check individually
if (fData.find(age) == fData.end()) // age doesn't exist
auto curAge = fData.find(age);
if (curAge == fData.end()) // age doesn't exist
return false;
if (fData[age].find(set) == fData[age].end()) // set doesn't exist
auto curSet = curAge->second.find(set);
if (curSet == curAge->second.end()) // set doesn't exist
return false;
// we passed all the tests, return true!
@ -733,19 +738,22 @@ void pfLocalizationDataMgr::pf3PartMap<mapT>::erase(const plString & key)
return;
// now check individually
if (fData.find(age) == fData.end()) // age doesn't exist
auto curAge = fData.find(age);
if (curAge == fData.end()) // age doesn't exist
return;
if (fData[age].find(set) == fData[age].end()) // set doesn't exist
auto curSet = curAge->second.find(set);
if (curSet == curAge->second.end()) // set doesn't exist
return;
if (fData[age][set].find(name) == fData[age][set].end()) // name doesn't exist
auto curElement = curSet->second.find(name);
if (curElement == curSet->second.end()) // name doesn't exist
return;
// ok, so now we want to nuke it!
fData[age][set].erase(name);
if (fData[age][set].size() == 0) // is the set now empty?
fData[age].erase(set); // nuke it!
if (fData[age].size() == 0) // is the age now empty?
fData.erase(age); // nuke it!
curSet->second.erase(name);
if (curSet->second.size() == 0) // is the set now empty?
curAge->second.erase(curSet); // nuke it!
if (curAge->second.size() == 0) // is the age now empty?
fData.erase(curAge); // nuke it!
}
//// operator[]() ////////////////////////////////////////////////////
@ -780,10 +788,11 @@ std::vector<plString> pfLocalizationDataMgr::pf3PartMap<mapT>::getSetList(const
std::vector<plString> retVal;
typename std::map<plString, std::map<plString, mapT> >::iterator curSet;
if (fData.find(age) == fData.end())
auto curAge = fData.find(age);
if (curAge == fData.end())
return retVal; // return an empty list, the age doesn't exist
for (curSet = fData[age].begin(); curSet != fData[age].end(); curSet++)
for (curSet = curAge->second.begin(); curSet != curAge->second.end(); curSet++)
retVal.push_back(curSet->first);
return retVal;
@ -797,13 +806,15 @@ std::vector<plString> pfLocalizationDataMgr::pf3PartMap<mapT>::getNameList(const
std::vector<plString> retVal;
typename std::map<plString, mapT>::iterator curName;
if (fData.find(age) == fData.end())
auto curAge = fData.find(age);
if (curAge == fData.end())
return retVal; // return an empty list, the age doesn't exist
if (fData[age].find(set) == fData[age].end())
auto curSet = curAge->second.find(set);
if (curSet == curAge->second.end())
return retVal; // return an empty list, the set doesn't exist
for (curName = fData[age][set].begin(); curName != fData[age][set].end(); curName++)
for (curName = curSet->second.begin(); curName != curSet->second.end(); curName++)
retVal.push_back(curName->first);
return retVal;

3
Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp

@ -157,7 +157,8 @@ void pfLocalizedString::IParameterize(const plString & inString)
void pfLocalizedString::IConvertFromPlainText(const plString & plainText)
{
IParameterize(plainText);
fPlainTextRep = plainText;
IParameterize(fPlainTextRep);
IUpdateXML();
}

6
Sources/Plasma/PubUtilLib/plGImage/plFont.cpp

@ -1253,7 +1253,7 @@ bool plFont::LoadFromP2FFile( const plFileName &path )
// Load this font from the data found in the given Windows FNT file,
// using the format specified in the Windows 3 Developers Notes.
bool plFont::LoadFromFNT( const char *path )
bool plFont::LoadFromFNT( const plFileName &path )
{
hsUNIXStream stream; // Ahh, irony
if( !stream.Open( path, "rb" ) )
@ -2023,9 +2023,9 @@ bool plFont::LoadFromBDFStream( hsStream *stream, plBDFConvertCallback *callb
return false;
}
bool plFont::LoadFromBDF( const char *path, plBDFConvertCallback *callback )
bool plFont::LoadFromBDF( const plFileName &path, plBDFConvertCallback *callback )
{
FILE *fp = fopen( path, "rt" );
FILE *fp = fopen( path.AsString().c_str(), "rt" );
if( fp == nil )
return false;
try

4
Sources/Plasma/PubUtilLib/plGImage/plFont.h

@ -293,10 +293,10 @@ class plFont : public hsKeyedObject
void CalcStringExtents( const plString &string, uint16_t &width, uint16_t &height, uint16_t &ascent, uint32_t &firstClippedChar, uint16_t &lastX, uint16_t &lastY );
void CalcStringExtents( const wchar_t *string, uint16_t &width, uint16_t &height, uint16_t &ascent, uint32_t &firstClippedChar, uint16_t &lastX, uint16_t &lastY );
bool LoadFromFNT( const char *path );
bool LoadFromFNT( const plFileName &path );
bool LoadFromFNTStream( hsStream *stream );
bool LoadFromBDF( const char *path, plBDFConvertCallback *callback );
bool LoadFromBDF( const plFileName &path, plBDFConvertCallback *callback );
bool LoadFromBDFStream( hsStream *stream, plBDFConvertCallback *callback );
bool LoadFromP2FFile( const plFileName &path );

3
Sources/Tools/CMakeLists.txt

@ -1,4 +1,7 @@
if(PLASMA_BUILD_TOOLS)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
add_subdirectory(plLocalizationEditor)
add_subdirectory(plResBrowser)
add_subdirectory(plShaderAssembler)

57
Sources/Tools/plFontConverter/CMakeLists.txt

@ -5,49 +5,60 @@ include_directories("../../Plasma/PubUtilLib")
include_directories(${FREETYPE_INCLUDE_DIRS})
set(plFontConverter_HEADERS
plFontConverter.h
plFontFreeType.h
plFontPreview.h
)
qt5_wrap_cpp(plFontConverter_MOC ${plFontConverter_HEADERS})
set(plFontConverter_SOURCES
plFontConverter.cpp
plFontConverterProc.cpp
plFontFreeType.cpp
plFontPreview.cpp
)
set(plFontConverter_RESOURCES
res/plFontConverter.rc
res/resource.h
res/icon1.ico
if(WIN32)
set(plFontConverter_SOURCES ${plFontConverter_SOURCES}
res/plFontConverter.rc
)
endif()
set(plFontConverter_RCC_SOURCES
res/plFontConverter.qrc
)
qt5_add_resources(plFontConverter_RCC ${plFontConverter_RCC_SOURCES})
set(plFontConverter_UIC_SOURCES
res/MainDialog.ui
res/FonChooser.ui
res/FreeType.ui
res/FreeTypeBatch.ui
)
add_executable(plFontConverter WIN32 ${plFontConverter_SOURCES} ${plFontConverter_HEADERS} ${plFontConverter_RESOURCES})
qt5_wrap_ui(plFontConverter_UIC ${plFontConverter_UIC_SOURCES})
# For generated ui_*.h files
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(plFontConverter WIN32 ${plFontConverter_HEADERS}
${plFontConverter_SOURCES} ${plFontConverter_RCC}
${plFontConverter_UIC} ${plFontConverter_MOC})
target_link_libraries(plFontConverter CoreLib)
target_link_libraries(plFontConverter pnKeyedObject)
target_link_libraries(plFontConverter pnSceneObject)
target_link_libraries(plFontConverter pnUUID)
target_link_libraries(plFontConverter plGImage)
target_link_libraries(plFontConverter plMessage)
target_link_libraries(plFontConverter plPipeline)
target_link_libraries(plFontConverter plResMgr)
target_link_libraries(plFontConverter ${JPEG_LIBRARY})
target_link_libraries(plFontConverter ${DirectX_LIBRARIES})
target_link_libraries(plFontConverter ${FREETYPE_LIBRARIES})
if (WIN32)
target_link_libraries(plFontConverter rpcrt4)
target_link_libraries(plFontConverter vfw32)
target_link_libraries(plFontConverter ws2_32)
target_link_libraries(plFontConverter winmm)
target_link_libraries(plFontConverter strmiids)
target_link_libraries(plFontConverter comctl32)
target_link_libraries(plFontConverter shlwapi)
endif(WIN32)
target_link_libraries(plFontConverter Qt5::Widgets)
if(USE_VLD)
target_link_libraries(plFontConverter ${VLD_LIBRARY})
endif()
source_group("Source Files" FILES ${plFontConverter_SOURCES})
source_group("Source Files" FILES ${plFontConverter_SOURCES} ${plFontConverter_MOC})
source_group("Header Files" FILES ${plFontConverter_HEADERS})
source_group("Resource Files" FILES ${plFontConverter_RESOURCES})
source_group("Resource Files" FILES ${plFontConverter_RCC_SOURCES} ${plFontConverter_RCC}
${plFontConverter_UIC_SOURCES} ${plFontConverter_UIC})

609
Sources/Tools/plFontConverter/plFontConverter.cpp

@ -39,12 +39,13 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
#define CLASSNAME "plFontConverter" // Used in WinInit()
#define WINDOWNAME "plFontConverter"
#include "plFontConverter.h"
#include "plFontFreeType.h"
#ifdef Q_OS_WIN
#include "HeadSpin.h"
#include "hsWindows.h"
#include "res/resource.h"
#endif
#include "pnAllCreatables.h"
#include "plResMgr/plResManager.h"
@ -61,34 +62,604 @@ REGISTER_CREATABLE(plFont);
REGISTER_NONCREATABLE(plBitmap);
REGISTER_CREATABLE(plMipmap);
#include "pnKeyedObject/plUoid.h"
#include "pnKeyedObject/plKeyImp.h"
HINSTANCE gInstance;
char *gCommandLine = nil;
HWND gMainWindow = nil;
#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"
BOOL CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
#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()));
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
connect(fUI->fSampleText, &QLineEdit::textChanged, [this](const QString &text)
{
fUI->fPreview->Update(fFont, text);
});
}
plFontConverter::~plFontConverter()
{
delete fUI;
}
void plFontConverter::dragEnterEvent(QDragEnterEvent *event)
{
HACCEL accelTable = LoadAccelerators( hInstance, MAKEINTRESOURCE( IDR_ACCELERATOR1 ) );
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 (*.*)");
gCommandLine = (char *)lpCmdLine;
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;
gInstance = hInstance;
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 );
hsgResMgr::Init(rMgr);
DialogBox( gInstance, MAKEINTRESOURCE( IDD_MAINDIALOG ), nil, WndProc );
plFontConverter mainDialog;
mainDialog.show();
int retn = app.exec();
hsgResMgr::Shutdown();
return 0;
return retn;
}
/* Enable themes in Windows XP and later */
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

86
Sources/Tools/plFontConverter/plFontConverter.h

@ -0,0 +1,86 @@
/*==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==*/
#ifndef _plFontConverter_h
#define _plFontConverter_h
#include <QMainWindow>
class plFont;
class plFileName;
class plFontConverter : public QMainWindow
{
Q_OBJECT
public:
plFontConverter();
virtual ~plFontConverter();
private slots:
void OpenFNT();
void OpenBDF();
void OpenFON();
void OpenTTF();
void OpenP2F();
void ExportP2F();
protected:
virtual void dragEnterEvent(QDragEnterEvent *event);
virtual void dropEvent(QDropEvent *event);
private:
class Ui_MainDialog *fUI;
plFont *fFont;
void IMakeFontGoAway();
void IMakeNewFont();
void IUpdateInfo();
void IImportFNT(const plFileName &path);
void IImportBDF(const plFileName &path);
void IImportFON(const plFileName &path);
void IBatchFreeType(const plFileName &path, void *init = nullptr);
void IImportFreeType(const plFileName &path);
void IOpenP2F(const plFileName &path);
};
#endif

756
Sources/Tools/plFontConverter/plFontConverterProc.cpp

@ -1,756 +0,0 @@
/*==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 "HeadSpin.h"
#include "hsWindows.h"
#include "res/resource.h"
#include <shlwapi.h>
#include <shellapi.h>
#include <shlobj.h>
#include <commdlg.h>
#include <commctrl.h>
#include <ctime>
#include "hsStream.h"
#include "hsResMgr.h"
#include "plFontFreeType.h"
#include "plGImage/plFont.h"
#include "plGImage/plMipmap.h"
#include "pnKeyedObject/plUoid.h"
#include "pnKeyedObject/plKeyImp.h"
extern HINSTANCE gInstance;
// My global font that i'm working on
plFont *gFont = nil;
// Preview bitmap
HDC gPreviewHDC = nil;
HBITMAP gPreviewBitmap = nil;
void IMakeFontGoAway( void )
{
if( gFont != nil )
{
plKeyImp *imp = (plKeyImp *)(gFont->GetKey());
if( imp != nil )
imp->SetObjectPtr( nil );
gFont = nil;
}
}
void IMakeNewFont( void )
{
IMakeFontGoAway();
gFont = new plFont();
}
BOOL CALLBACK AboutDialogProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
if( msg == WM_COMMAND )
EndDialog( hWnd, 0 );
return 0;
}
bool PromptForFile( HWND parent, const char *prompt, const char *filter, char *fileName, int fileNameMax, bool save )
{
OPENFILENAME openInfo;
memset( &openInfo, 0, sizeof( OPENFILENAME ) );
openInfo.hInstance = gInstance;
openInfo.hwndOwner = parent;
openInfo.lStructSize = sizeof( OPENFILENAME );
openInfo.lpstrFile = fileName;
openInfo.nMaxFile = fileNameMax;
openInfo.lpstrFilter = filter;
openInfo.lpstrTitle = prompt;
openInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
if( !save )
openInfo.Flags |= OFN_READONLY;
if( save )
return GetSaveFileName( &openInfo ) ? true : false;
return GetOpenFileName( &openInfo ) ? true : false;
}
void IUpdateInfo( HWND hDlg )
{
const int TEST_STRING_SIZE = 512;
static wchar_t testString[ TEST_STRING_SIZE ] = L"The quick brown fox jumped over the lazy dog! ABCabc012345;,.";
if( gFont == nil )
{
SetDlgItemText( hDlg, IDC_FACE, "" );
SetDlgItemText( hDlg, IDC_FSIZE, "" );
SetDlgItemText( hDlg, IDC_STARTG, "" );
SetDlgItemText( hDlg, IDC_GCOUNT, "" );
SetDlgItemText( hDlg, IDC_WIDTH, "" );
SetDlgItemText( hDlg, IDC_HEIGHT, "" );
SetDlgItemText( hDlg, IDC_BPP, "" );
CheckDlgButton( hDlg, IDC_BOLD, false );
CheckDlgButton( hDlg, IDC_ITALIC, false );
return;
}
SetDlgItemText( hDlg, IDC_FACE, gFont->GetFace().c_str() );
SetDlgItemInt( hDlg, IDC_FSIZE, gFont->GetSize(), false );
SetDlgItemInt( hDlg, IDC_STARTG, gFont->GetFirstChar(), false );
SetDlgItemInt( hDlg, IDC_GCOUNT, gFont->GetNumChars(), false );
SetDlgItemInt( hDlg, IDC_WIDTH, gFont->GetBitmapWidth(), false );
SetDlgItemInt( hDlg, IDC_HEIGHT, gFont->GetBitmapHeight(), false );
SetDlgItemInt( hDlg, IDC_BPP, gFont->GetBitmapBPP(), false );
CheckDlgButton( hDlg, IDC_BOLD, gFont->IsFlagSet( plFont::kFlagBold ) );
CheckDlgButton( hDlg, IDC_ITALIC, gFont->IsFlagSet( plFont::kFlagItalic ) );
if( gPreviewHDC != nil )
{
DeleteObject( gPreviewHDC );
DeleteObject( gPreviewBitmap );
gPreviewHDC = nil;
gPreviewBitmap = nil;
}
// Get the size of our preview
RECT r;
GetClientRect( GetDlgItem( hDlg, IDC_PREVIEW ), &r );
MapWindowPoints( GetDlgItem( hDlg, IDC_PREVIEW ), hDlg, (POINT *)&r, 2 );
InvalidateRect( hDlg, &r, false );
if( gFont->GetNumChars() == 0 )
return;
// Our preview bitmap
HDC deskDC = GetDC( nil );
gPreviewHDC = CreateCompatibleDC( deskDC );
gPreviewBitmap = CreateCompatibleBitmap( deskDC, r.right - r.left, r.bottom - r.top );
SelectObject( gPreviewHDC, gPreviewBitmap );
ReleaseDC( nil, deskDC );
::GetDlgItemTextW( hDlg, IDC_PREVTEXT, testString, TEST_STRING_SIZE );
// Create us a mipmap to render onto, render onto it, then copy that to our DC
plMipmap *mip = new plMipmap( r.right - r.left, r.bottom - r.top, plMipmap::kARGB32Config, 1 );
memset( mip->GetImage(), 0xff, mip->GetWidth() * mip->GetHeight() * 4 );
gFont->SetRenderColor( 0xff000000 );
gFont->SetRenderFlag( plFont::kRenderClip, true );
gFont->SetRenderClipRect( 0, 0, (int16_t)(r.right - r.left), (int16_t)(r.bottom - r.top) );
uint16_t w, h, a, lastX, lastY;
uint32_t firstCC;
gFont->CalcStringExtents( testString, w, h, a, firstCC, lastX, lastY );
int cY = ( ( ( r.bottom - r.top ) - h ) >> 1 ) + a;
if( cY < 0 )
cY = 0;
else if( cY > r.bottom - r.top - 1 )
cY = r.bottom - r.top - 1;
memset( mip->GetAddr32( 8, cY ), 0xc0, ( r.right - r.left - 8 ) * 4 );
gFont->RenderString( mip, 8, cY, testString );
int x, y;
for( y = 0; y < r.bottom - r.top; y++ )
{
for( x = 0; x < r.right - r.left; x++ )
{
uint32_t color = *mip->GetAddr32( x, y );
hsColorRGBA rgba;
rgba.FromARGB32( color );
if( color != 0xffffffff && color != 0xff000000 )
{
int q = 0;
}
SetPixel( gPreviewHDC, x, y, RGB( rgba.r * 255.f, rgba.g * 255.f, rgba.b * 255.f) );
}
}
delete mip;
}
class plSetKeyObj : public hsKeyedObject
{
public:
void SetMyKey( const plKey &key )
{
SetKey( key );
}
};
class plMyBDFCallback : public plBDFConvertCallback
{
protected:
HWND fDlg;
clock_t fLastTime;
uint16_t fPoint;
void IPumpMessageQueue( void )
{
MSG msg;
while( PeekMessage( &msg, fDlg, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
public:
plMyBDFCallback( HWND dlg ) : fDlg( dlg ) {}
virtual void NumChars( uint16_t chars )
{
::SendDlgItemMessage( fDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM( 0, chars ) );
IPumpMessageQueue();
fLastTime = clock();
fPoint = 0;
}
virtual void CharDone( void )
{
fPoint++;
if( clock() - fLastTime > CLOCKS_PER_SEC / 16 )
{
::SendDlgItemMessage( fDlg, IDC_PROGRESS, PBM_SETPOS, fPoint, 0 );
IPumpMessageQueue();
fLastTime = clock();
}
}
};
BOOL CALLBACK ProgressWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
return 0;
}
void IImportFNT( HWND hWnd, const char *path )
{
IMakeNewFont();
if( !gFont->LoadFromFNT( path ) )
MessageBox( hWnd, "Failure converting FNT file", "ERROR", MB_OK | MB_ICONEXCLAMATION );
IUpdateInfo( hWnd );
}
void IImportBDF( HWND hWnd, const char *path )
{
IMakeNewFont();
HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc );
ShowWindow( dialog, SW_SHOW );
EnableWindow( hWnd, false );
plMyBDFCallback callback( dialog );
if( !gFont->LoadFromBDF( path, &callback ) )
MessageBox( hWnd, "Failure converting BDF file", "ERROR", MB_OK | MB_ICONEXCLAMATION );
DestroyWindow( dialog );
EnableWindow( hWnd, true );
IUpdateInfo( hWnd );
}
void IOpenP2F( HWND hWnd, const char *path )
{
IMakeNewFont();
if( !gFont->LoadFromP2FFile( path ) )
MessageBox( hWnd, "Failure opening P2F file", "ERROR", MB_OK | MB_ICONEXCLAMATION );
IUpdateInfo( hWnd );
}
struct ResRecord
{
HRSRC fHandle;
char fName[ 512 ];
ResRecord() { fHandle = nil; fName[ 0 ] = 0; }
ResRecord( HRSRC h, const char *n ) { fHandle = h; strncpy( fName, n, sizeof( fName ) ); }
};
BOOL CALLBACK ResEnumProc( HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR lParam )
{
HRSRC res = FindResource( module, name, type );
if( res != nil )
{
hsTArray<ResRecord *> *array = (hsTArray<ResRecord *> *)lParam;
array->Append( new ResRecord( res, name ) );
}
return true;
}
BOOL CALLBACK ResListWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_INITDIALOG:
{
SendDlgItemMessage( hWnd, IDC_RESLIST, LB_RESETCONTENT, 0, 0 );
hsTArray<ResRecord *> *array = (hsTArray<ResRecord *> *)lParam;
for( uint32_t i = 0; i < array->GetCount(); i++ )
{
ResRecord *rec = array->Get( i );
int idx = SendDlgItemMessage( hWnd, IDC_RESLIST, LB_ADDSTRING, 0, (LPARAM)rec->fName );
SendDlgItemMessage( hWnd, IDC_RESLIST, LB_SETITEMDATA, idx, (LPARAM)rec );
}
}
return 0;
case WM_COMMAND:
if( wParam == IDCANCEL )
EndDialog( hWnd, 0 );
else
{
int idx = SendDlgItemMessage( hWnd, IDC_RESLIST, LB_GETCURSEL, 0, 0 );
if( idx == LB_ERR )
EndDialog( hWnd, 0 );
else
{
ResRecord *rec = (ResRecord *)SendDlgItemMessage( hWnd, IDC_RESLIST, LB_GETITEMDATA, idx, 0 );
EndDialog( hWnd, (int)rec );
}
}
return true;
}
return 0;
}
void IImportFON( HWND hWnd, const char *path )
{
// FON files are really just resource modules
IMakeNewFont();
HMODULE file = LoadLibraryEx( path, nil, LOAD_LIBRARY_AS_DATAFILE | DONT_RESOLVE_DLL_REFERENCES );
if( file == nil )
{
char msg[ 512 ], msg2[ 1024 ];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof( msg ), nil );
sprintf( msg2, "Failure importing FON file: can't open as resource library (%s)", msg );
MessageBox( hWnd, msg2, "Error", MB_OK | MB_ICONEXCLAMATION );
}
else
{
hsTArray<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 = (ResRecord *)DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FONCHOOSER ), hWnd,
ResListWndProc, (LPARAM)&resList );
if( res != nil )
{
// Load the resource into a ram stream
hsRAMStream stream;
HGLOBAL glob = LoadResource( file, res->fHandle );
if( glob != nil )
{
void *data = LockResource( glob );
if( data != nil )
{
stream.Write( SizeofResource( file, res->fHandle ), data );
stream.Rewind();
if( !gFont->LoadFromFNTStream( &stream ) )
MessageBox( hWnd, "Failure importing FON file: can't parse resource as FNT",
"Error", MB_OK | MB_ICONEXCLAMATION );
}
}
}
}
else
{
char msg[ 512 ], msg2[ 1024 ];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nil, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)msg, sizeof( msg ), nil );
sprintf( msg2, "Failure importing FON file: can't enumerate resources (%s)", msg );
MessageBox( hWnd, msg2, "Error", MB_OK | MB_ICONEXCLAMATION );
}
uint32_t i;
for( i = 0; i < resList.GetCount(); i++ )
delete resList[ i ];
resList.Reset();
FreeLibrary( file );
}
IUpdateInfo( hWnd );
}
BOOL CALLBACK FreeTypeDlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
static plFontFreeType::Options *info;
switch( message )
{
case WM_INITDIALOG:
info = (plFontFreeType::Options *)lParam;
SetDlgItemInt( hWnd, IDC_PSIZE, info->fSize, false );
SetDlgItemInt( hWnd, IDC_RES, info->fScreenRes, false );
SetDlgItemInt( hWnd, IDC_MAXCHAR, info->fMaxCharLimit, false );
CheckRadioButton( hWnd, IDC_BITDEPTH, IDC_BITDEPTH2, info->fBitDepth == 1 ? IDC_BITDEPTH : IDC_BITDEPTH2 );
return 0;
case WM_COMMAND:
if( wParam == IDOK || wParam == IDCANCEL || wParam == IDC_BATCH )
{
info->fSize = GetDlgItemInt( hWnd, IDC_PSIZE, nil, false );
info->fScreenRes = GetDlgItemInt( hWnd, IDC_RES, nil, false );
info->fMaxCharLimit = GetDlgItemInt( hWnd, IDC_MAXCHAR, nil, false );
if( IsDlgButtonChecked( hWnd, IDC_BITDEPTH ) )
info->fBitDepth = 1;
else
info->fBitDepth = 8;
EndDialog( hWnd, wParam );
}
return 1;
}
return 0;
}
void IBatchFreeType( HWND hWnd, const char *path );
void IImportFreeType( HWND hWnd, const char *path )
{
static plFontFreeType::Options info;
int ret = DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FREETYPE ), hWnd, FreeTypeDlgProc, (LPARAM)&info );
if( ret == IDCANCEL )
return;
else if( ret == IDC_BATCH )
{
IBatchFreeType( hWnd, path );
return;
}
IMakeNewFont();
HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc );
ShowWindow( dialog, SW_SHOW );
EnableWindow( hWnd, false );
plMyBDFCallback callback( dialog );
plFontFreeType *ft2Convert = (plFontFreeType *)gFont;
if( !ft2Convert->ImportFreeType( path, &info, &callback ) )
MessageBox( hWnd, "Failure converting TrueType file", "ERROR", MB_OK | MB_ICONEXCLAMATION );
DestroyWindow( dialog );
EnableWindow( hWnd, true );
IUpdateInfo( hWnd );
}
static uint8_t sNumSizes = 0;
static uint8_t sSizeArray[ 256 ];
static char sFontName[ 256 ]; // desired font name for FreeType conversions
BOOL CALLBACK FreeTypeBatchDlgProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
static plFontFreeType::Options *info;
switch( message )
{
case WM_INITDIALOG:
info = (plFontFreeType::Options *)lParam;
SetDlgItemText( hWnd, IDC_PSIZE, "12" );
SetDlgItemText( hWnd, IDC_FONTNAME, "Untitled" );
SetDlgItemInt( hWnd, IDC_RES, info->fScreenRes, false );
SetDlgItemInt( hWnd, IDC_MAXCHAR, info->fMaxCharLimit, false );
CheckRadioButton( hWnd, IDC_BITDEPTH, IDC_BITDEPTH2, info->fBitDepth == 1 ? IDC_BITDEPTH : IDC_BITDEPTH2 );
return 0;
case WM_COMMAND:
if( wParam == IDOK || wParam == IDCANCEL )
{
sNumSizes = 0;
char *c, *lastC, str[ 1024 ];
GetDlgItemText( hWnd, IDC_PSIZE, str, sizeof( str ) );
lastC = str;
while( ( c = strchr( lastC, ',' ) ) != nil && sNumSizes < 255 )
{
*c = 0;
sSizeArray[ sNumSizes++ ] = atoi( lastC );
lastC = c + 1;
}
sSizeArray[ sNumSizes++ ] = atoi( lastC );
info->fScreenRes = GetDlgItemInt( hWnd, IDC_RES, nil, false );
info->fMaxCharLimit = GetDlgItemInt( hWnd, IDC_MAXCHAR, nil, false );
if( IsDlgButtonChecked( hWnd, IDC_BITDEPTH ) )
info->fBitDepth = 1;
else
info->fBitDepth = 8;
GetDlgItemText( hWnd, IDC_FONTNAME, sFontName, sizeof(sFontName) );
EndDialog( hWnd, wParam );
}
return 1;
}
return 0;
}
void IBatchFreeType( HWND hWnd, const char *path )
{
static plFontFreeType::Options info;
if( DialogBoxParam( gInstance, MAKEINTRESOURCE( IDD_FREETYPEBATCH ), hWnd, FreeTypeBatchDlgProc, (LPARAM)&info ) == IDCANCEL )
return;
BROWSEINFO bInfo;
LPITEMIDLIST itemList;
LPMALLOC shMalloc;
static char destPath[ MAX_PATH ] = "";
memset( &bInfo, 0, sizeof( bInfo ) );
bInfo.hwndOwner = hWnd;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = destPath;
bInfo.lpszTitle = "Select a path to write the P2F fonts to:";
bInfo.ulFlags = BIF_EDITBOX;
itemList = SHBrowseForFolder( &bInfo );
if( itemList != NULL )
{
SHGetPathFromIDList( itemList, destPath );
SHGetMalloc( &shMalloc );
shMalloc->Free( itemList );
shMalloc->Release();
}
else
return;
HWND dialog = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_PROGRESS ), hWnd, ProgressWndProc );
ShowWindow( dialog, SW_SHOW );
EnableWindow( hWnd, false );
plMyBDFCallback callback( dialog );
callback.NumChars( sNumSizes );
uint8_t i;
for( i = 0; i < sNumSizes; i++ )
{
IMakeNewFont();
plFontFreeType *ft2Convert = (plFontFreeType *)gFont;
info.fSize = sSizeArray[ i ];
if( !ft2Convert->ImportFreeType( path, &info, nil ) )
{
MessageBox( hWnd, "Failure converting TrueType file", "ERROR", MB_OK | MB_ICONEXCLAMATION );
continue;
}
gFont->SetFace(sFontName);
char fileName[ MAX_PATH ];
sprintf( fileName, "%s\\%s-%d.p2f", destPath, gFont->GetFace().c_str(), gFont->GetSize() );
hsUNIXStream stream;
if( !stream.Open( fileName, "wb" ) )
MessageBox( hWnd, "Can't open file for writing", "Error", MB_OK | MB_ICONEXCLAMATION );
else
{
gFont->WriteRaw( &stream );
stream.Close();
}
callback.CharDone();
}
DestroyWindow( dialog );
EnableWindow( hWnd, true );
IUpdateInfo( hWnd );
}
BOOL CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
char fileName[ MAX_PATH ];
PAINTSTRUCT paintInfo;
HDC myDC;
RECT r;
switch( message )
{
case WM_PAINT:
myDC = BeginPaint( hWnd, &paintInfo );
GetClientRect( GetDlgItem( hWnd, IDC_PREVIEW ), &r );
MapWindowPoints( GetDlgItem( hWnd, IDC_PREVIEW ), hWnd, (POINT *)&r, 2 );
if( gPreviewHDC != nil )
BitBlt( myDC, r.left, r.top, r.right - r.left, r.bottom - r.top, gPreviewHDC, 0, 0, SRCCOPY );
else
FillRect( myDC, &r, GetSysColorBrush( COLOR_3DFACE ) );
DrawEdge( myDC, &r, EDGE_SUNKEN, BF_RECT );
EndPaint( hWnd, &paintInfo );
return 0;
case WM_INITDIALOG:
SendMessage( hWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIcon( gInstance, MAKEINTRESOURCE( IDI_APPICON ) ) );
SetDlgItemTextW( hWnd, IDC_PREVTEXT, L"The quick brown fox jumped over the lazy dog! ABCabc012345;,." );
return 0;
case WM_COMMAND:
if( wParam == ID_FILE_ABOUT )
{
DialogBox( gInstance, MAKEINTRESOURCE( IDD_ABOUT ), hWnd, AboutDialogProc );
}
else if( wParam == ID_FILE_EXIT )
PostQuitMessage( 0 );
else if( wParam == ID_FILE_FNT )
{
fileName[ 0 ] = 0;
if( PromptForFile( hWnd, "Choose a FNT file to convert", "Windows FNT files\0*.fnt\0All files\0*.*\0", fileName, sizeof( fileName ), false ) )
IImportFNT( hWnd, fileName );
}
else if( wParam == ID_FILE_P2F )
{
fileName[ 0 ] = 0;
if( PromptForFile( hWnd, "Choose a P2F file to open", "Plasma 2 font files\0*.p2f\0All files\0*.*\0", fileName, sizeof( fileName ), false ) )
IOpenP2F( hWnd, fileName );
}
else if( wParam == ID_FILE_FON )
{
fileName[ 0 ] = 0;
if( PromptForFile( hWnd, "Choose a FON file to convert", "Windows FON files\0*.fon\0All files\0*.*\0", fileName, sizeof( fileName ), false ) )
IImportFON( hWnd, fileName );
}
else if( wParam == ID_FILE_TRUETYPE )
{
fileName[ 0 ] = 0;
if( PromptForFile( hWnd, "Choose a TrueType font to convert", "TrueType files\0*.ttf\0TrueType Collections\0*.ttc\0All files\0*.*\0", fileName, sizeof( fileName ), false ) )
IBatchFreeType( hWnd, fileName );
}
else if( wParam == ID_FILE_EXPORT )
{
// Grab updated values for the font
GetDlgItemText( hWnd, IDC_FACE, fileName, sizeof( fileName ) );
gFont->SetFace( fileName );
gFont->SetSize( GetDlgItemInt( hWnd, IDC_FSIZE, nil, false ) );
gFont->SetFlag( plFont::kFlagBold, IsDlgButtonChecked( hWnd, IDC_BOLD ) == BST_CHECKED );
gFont->SetFlag( plFont::kFlagItalic, IsDlgButtonChecked( hWnd, IDC_ITALIC ) == BST_CHECKED );
// Write out
sprintf( fileName, "%s-%d.p2f", gFont->GetFace().c_str(), gFont->GetSize() );
if( PromptForFile( hWnd, "Specify a file to export to", "Plasma 2 font files\0*.p2f\0", fileName, sizeof( fileName ), true ) )
{
hsUNIXStream stream;
if( !stream.Open( fileName, "wb" ) )
MessageBox( hWnd, "Can't open file for writing", "Error", MB_OK | MB_ICONEXCLAMATION );
else
{
/* sprintf( fileName, "%s-%d", gFont->GetFace(), gFont->GetSize() );
if( gFont->GetKey() == nil )
hsgResMgr::ResMgr()->NewKey( fileName, gFont, plLocation::kGlobalFixedLoc );
*/
gFont->WriteRaw( &stream );
stream.Close();
}
}
}
else if( LOWORD( wParam ) == IDC_PREVTEXT && HIWORD( wParam ) == EN_CHANGE )
{
IUpdateInfo( hWnd );
}
return true;
case WM_CLOSE:
PostQuitMessage( 0 );
return true;
case WM_DROPFILES:
{
int i, fileCount = DragQueryFile( (HDROP)wParam, -1, nil, 0 );
char path[ MAX_PATH ];
for( i = 0; i < fileCount; i++ )
{
if( DragQueryFile( (HDROP)wParam, i, path, sizeof( path ) ) > 0 )
{
char *ext = PathFindExtension( path );
if( stricmp( ext, ".fnt" ) == 0 )
IImportFNT( hWnd, path );
else if( stricmp( ext, ".bdf" ) == 0 )
IImportBDF( hWnd, path );
else if( stricmp( ext, ".fon" ) == 0 )
IImportFON( hWnd, path );
else if( stricmp( ext, ".exe" ) == 0 )
IImportFON( hWnd, path );
else if(( stricmp( ext, ".ttf" ) == 0 ) || ( stricmp( ext, ".ttc" ) == 0 ))
IImportFreeType( hWnd, path );
else if( stricmp( ext, ".p2f" ) == 0 )
IOpenP2F( hWnd, path );
else
// Try using our freeType converter
IImportFreeType( hWnd, path );
}
}
IUpdateInfo( hWnd );
}
break;
}
return 0;//DefWindowProc( hWnd, message, wParam, lParam );
}

8
Sources/Tools/plFontConverter/plFontFreeType.cpp

@ -58,7 +58,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
bool plFontFreeType::ImportFreeType( const char *fontPath, Options *options, plBDFConvertCallback *callback )
bool plFontFreeType::ImportFreeType( const plFileName &fontPath, Options *options, plBDFConvertCallback *callback )
{
FT_Library ftLibrary;
@ -77,7 +77,7 @@ bool plFontFreeType::ImportFreeType( const char *fontPath, Options *options,
// Load our font that we're converting
FT_Face ftFace;
error = FT_New_Face( ftLibrary, fontPath, 0, &ftFace );
error = FT_New_Face( ftLibrary, fontPath.AsString().c_str(), 0, &ftFace );
if( error == FT_Err_Unknown_File_Format )
{
// Unsupported inport format
@ -100,9 +100,9 @@ bool plFontFreeType::ImportFreeType( const char *fontPath, Options *options,
FT_GlyphSlot ftSlot = ftFace->glyph;
FT_ULong ftChar;
FT_UInt ftIndex;
uint32_t numGlyphs = 0, totalHeight = 0, maxChar = 0, i;
uint32_t numGlyphs = 0, totalHeight = 0, maxChar = 0, i;
FT_Glyph ftGlyphs[ kMaxGlyphs ];
uint16_t glyphChars[ kMaxGlyphs ];
uint16_t glyphChars[ kMaxGlyphs ];
FT_Vector ftAdvances[ kMaxGlyphs ];
FT_BBox ftGlyphBox, ftFontBox;
FT_UInt previous = 0;

8
Sources/Tools/plFontConverter/plFontFreeType.h

@ -56,13 +56,13 @@ class plFontFreeType : public plFont
struct Options
{
uint8_t fSize;
bool fUseKerning;
bool fUseKerning;
uint8_t fBitDepth;
uint32_t fScreenRes;
uint32_t fMaxCharLimit;
Options() { fSize = 12; fUseKerning = false; fBitDepth = 1; fScreenRes = 96; fMaxCharLimit = 255; }
Options() : fSize(12), fUseKerning(false), fBitDepth(1), fScreenRes(96), fMaxCharLimit(255) { }
};
bool ImportFreeType( const char *fontPath, Options *options, plBDFConvertCallback *callback );
};
bool ImportFreeType( const plFileName &fontPath, Options *options, plBDFConvertCallback *callback );
};

115
Sources/Tools/plFontConverter/plFontPreview.cpp

@ -0,0 +1,115 @@
/*==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 "plFontPreview.h"
#include "plGImage/plFont.h"
#include "plGImage/plMipmap.h"
#include <QPainter>
#include <QPicture>
#include <memory>
void plFontPreview::Update(plFont *font, const QString &text)
{
fFont = font;
fText = text;
fPreview = QImage(width(), height(), QImage::Format_ARGB32);
if (fFont == nullptr) {
QPainter p(&fPreview);
p.fillRect(0, 0, width(), height(), Qt::white);
update();
return;
}
plString testString = text.toUtf8().constData();
// Create us a mipmap to render onto, render onto it, then copy that to our DC
plMipmap *mip = new plMipmap(width(), height(), plMipmap::kARGB32Config, 1);
memset(mip->GetImage(), 0xff, mip->GetWidth() * mip->GetHeight() * 4);
fFont->SetRenderColor(0xff000000);
fFont->SetRenderFlag(plFont::kRenderClip, true);
fFont->SetRenderClipRect(0, 0, (int16_t)width(), (int16_t)height());
uint16_t w, h, a, lastX, lastY;
uint32_t firstCC;
fFont->CalcStringExtents(testString, w, h, a, firstCC, lastX, lastY);
int cY = ((height() - h) >> 1) + a;
if (cY < 0)
cY = 0;
else if (cY > height() - 1)
cY = height() - 1;
memset(mip->GetAddr32(8, cY), 0xc0, (width() - 8) * 4);
fFont->RenderString(mip, 8, cY, testString);
int x, y;
for (y = 0; y < height(); y++) {
for (x = 0; x < width(); x++) {
uint32_t color = *mip->GetAddr32(x, y);
if (color != 0xffffffff && color != 0xff000000)
{
int q = 0;
}
// One pixel at a time? Surely we can do better...
// But for now this is a pure port
fPreview.setPixel(x, y, color | 0xff000000);
}
}
delete mip;
update();
}
void plFontPreview::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.drawImage(0, 0, fPreview);
QFrame::paintEvent(event);
}

54
Sources/Tools/plFontConverter/hsCodecManagerStub.cpp → Sources/Tools/plFontConverter/plFontPreview.h

@ -39,45 +39,33 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
#include "hsCodecManager.h"
#include "plMipmap.h"
#ifndef _plFontPreview_h
#define _plFontPreview_h
#include <QFrame>
hsCodecManager& hsCodecManager::Instance()
{
static hsCodecManager the_instance;
static bool initialized = false;
if (!initialized)
{
initialized = true;
}
return the_instance;
}
hsCodecManager::hsCodecManager()
{
}
class plFont;
plMipmap *hsCodecManager::CreateCompressedMipmap(uint32_t compressionFormat, plMipmap *uncompressed)
class plFontPreview : public QFrame
{
return nil;
}
public:
plFontPreview(QWidget *parent = nullptr) : QFrame(parent), fFont(nullptr) { }
plMipmap *hsCodecManager::CreateUncompressedMipmap(plMipmap *compressed, uint8_t bitDepth)
{
return nil;
void Update(plFont *font, const QString &text);
}
protected:
virtual void paintEvent(QPaintEvent *event);
bool hsCodecManager::ColorizeCompMipmap( plMipmap *bMap, const uint8_t *colorMask )
{
return false;
}
virtual void resizeEvent(QResizeEvent *event)
{
QFrame::resizeEvent(event);
Update(fFont, fText);
}
bool hsCodecManager::Register(hsCodec *codec, uint32_t compressionFormat, hsScalar priority)
{
return true;
}
private:
plFont *fFont;
QString fText;
QImage fPreview;
};
#endif

81
Sources/Tools/plFontConverter/res/FonChooser.ui

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FonChooser</class>
<widget class="QDialog" name="FonChooser">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>270</width>
<height>260</height>
</rect>
</property>
<property name="windowTitle">
<string>FON Resource List</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Choose which resource to import:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="fResourceList"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FonChooser</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FonChooser</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

137
Sources/Tools/plFontConverter/res/FreeType.ui

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FreeType</class>
<widget class="QDialog" name="FreeType">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>95</height>
</rect>
</property>
<property name="windowTitle">
<string>FreeType Import Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Render Point &amp;Size:</string>
</property>
<property name="buddy">
<cstring>fPointSize</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="fPointSize">
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max &amp;Character:</string>
</property>
<property name="buddy">
<cstring>fMaxChar</cstring>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QSpinBox" name="fMaxChar">
<property name="maximum">
<number>1114111</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Screen &amp;Resolution:</string>
</property>
<property name="buddy">
<cstring>fResolution</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="fResolution">
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="fMonochrome">
<property name="text">
<string>&amp;Monochrome</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="fGrayscale">
<property name="text">
<string>&amp;Grayscale</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="fButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>fButtons</sender>
<signal>accepted()</signal>
<receiver>FreeType</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>fButtons</sender>
<signal>rejected()</signal>
<receiver>FreeType</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

159
Sources/Tools/plFontConverter/res/FreeTypeBatch.ui

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FreeTypeBatch</class>
<widget class="QDialog" name="FreeTypeBatch">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>357</width>
<height>181</height>
</rect>
</property>
<property name="windowTitle">
<string>FreeType Import Options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Render Point &amp;Sizes:</string>
</property>
<property name="buddy">
<cstring>fPointSizes</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fPointSizes"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Common Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QRadioButton" name="fMonochrome">
<property name="text">
<string>&amp;Monochrome</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="fGrayscale">
<property name="text">
<string>&amp;Grayscale</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Screen &amp;Resolution:</string>
</property>
<property name="buddy">
<cstring>fResolution</cstring>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Max &amp;Character:</string>
</property>
<property name="buddy">
<cstring>fMaxChar</cstring>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QSpinBox" name="fMaxChar">
<property name="maximum">
<number>1114111</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="fResolution">
<property name="maximum">
<number>65535</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Font &amp;Name:</string>
</property>
<property name="buddy">
<cstring>fFontName</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fFontName"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FreeTypeBatch</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FreeTypeBatch</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

355
Sources/Tools/plFontConverter/res/MainDialog.ui

@ -0,0 +1,355 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainDialog</class>
<widget class="QMainWindow" name="MainDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>384</width>
<height>316</height>
</rect>
</property>
<property name="windowTitle">
<string>plFontConverter</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="spacing">
<number>8</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>F&amp;ace:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>fFaceName</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="fFaceName"/>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="fExportButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Export P2F...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>fFontSize</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="fFontSize">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>255</number>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fBold">
<property name="text">
<string>&amp;Bold</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="fItalic">
<property name="text">
<string>&amp;Italic</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<property name="spacing">
<number>8</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Starting Glyph:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="fStartingGlyph">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Glyph Count:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="fGlyphCount">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bitmap Width:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="fBitmapWidth">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bitmap Height:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLineEdit" name="fBitmapHeight">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>BPP:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="5">
<widget class="QLineEdit" name="fBPP">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="plFontPreview" name="fPreview">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>32</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fSampleText">
<property name="text">
<string>The quick brown fox jumped over the lazy dog! ABCabc012345;,.</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>384</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="fImportFNTAction"/>
<addaction name="fImportBDFAction"/>
<addaction name="fImportFONAction"/>
<addaction name="fImportTTFAction"/>
<addaction name="separator"/>
<addaction name="fOpenAction"/>
<addaction name="fExportAction"/>
<addaction name="separator"/>
<addaction name="fExitAction"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="fAboutAction"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Help"/>
</widget>
<action name="fImportFNTAction">
<property name="text">
<string>Import &amp;FNT...</string>
</property>
</action>
<action name="fImportBDFAction">
<property name="text">
<string>Import &amp;BDF...</string>
</property>
</action>
<action name="fImportFONAction">
<property name="text">
<string>Import FO&amp;N...</string>
</property>
</action>
<action name="fOpenAction">
<property name="text">
<string>&amp;Open P2F...</string>
</property>
</action>
<action name="fImportTTFAction">
<property name="text">
<string>Import &amp;TrueType...</string>
</property>
</action>
<action name="fExportAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Export P2F...</string>
</property>
</action>
<action name="fExitAction">
<property name="text">
<string>E&amp;xit</string>
</property>
</action>
<action name="fAboutAction">
<property name="text">
<string>&amp;About...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>plFontPreview</class>
<extends>QFrame</extends>
<header>plFontPreview.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

5
Sources/Tools/plFontConverter/res/plFontConverter.qrc

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>icon1.ico</file>
</qresource>
</RCC>

269
Sources/Tools/plFontConverter/res/plFontConverter.rc

@ -1,270 +1 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define IDC_STATIC (-1) // all static controls
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON ICON DISCARDABLE "icon1.ico"
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUT DIALOG DISCARDABLE 0, 0, 247, 57
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About plFontConverter"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,190,7,50,14
ICON IDI_APPICON,IDC_STATIC,11,8,20,20
LTEXT "plFontConverter\n\nA simple Plasma 2.0 utility for converting public font formats into our own bitmap font format",
IDC_STATIC,40,7,140,43
END
IDD_MAINDIALOG DIALOGEX 100, 100, 241, 170
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "plFontConverter"
MENU IDR_APPMENU
FONT 8, "MS Sans Serif", 0, 0, 0x1
BEGIN
PUSHBUTTON "Export P2F...",ID_FILE_EXPORT,184,7,50,14
LTEXT "Face:",IDC_STATIC,7,9,19,8
LTEXT "Size:",IDC_STATIC,10,26,16,8
EDITTEXT IDC_FACE,27,7,148,14,ES_AUTOHSCROLL
EDITTEXT IDC_FSIZE,27,24,30,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Starting glyph:",IDC_STATIC,10,43,46,8
LTEXT "Glyph count:",IDC_STATIC,87,43,41,8
LTEXT "0",IDC_STARTG,58,42,22,12,SS_SUNKEN
LTEXT "0",IDC_GCOUNT,130,42,22,12,SS_SUNKEN
LTEXT "Bitmap width:",IDC_STATIC,13,58,43,8
LTEXT "0",IDC_WIDTH,58,57,22,12,SS_SUNKEN
LTEXT "Bitmap height:",IDC_STATIC,83,58,46,8
LTEXT "0",IDC_HEIGHT,130,57,22,12,SS_SUNKEN
LTEXT "BPP:",IDC_STATIC,160,57,17,8
LTEXT "0",IDC_BPP,179,56,22,12,SS_SUNKEN
CONTROL "",IDC_PREVIEW,"Static",SS_WHITEFRAME | SS_SUNKEN | NOT
WS_VISIBLE,7,73,227,73
CONTROL "Bold",IDC_BOLD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,64,
26,30,10
CONTROL "Italic",IDC_ITALIC,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,97,26,31,10
EDITTEXT IDC_PREVTEXT,7,149,227,14,ES_AUTOHSCROLL
END
IDD_FONCHOOSER DIALOG DISCARDABLE 0, 0, 166, 161
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "FON Resource List"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,109,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,109,24,50,14
LTEXT "Choose which resource to import:",IDC_STATIC,7,7,93,18
LISTBOX IDC_RESLIST,7,27,97,127,LBS_SORT | LBS_NOINTEGRALHEIGHT |
WS_VSCROLL | WS_TABSTOP
END
IDD_PROGRESS DIALOG DISCARDABLE 0, 0, 230, 25
STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "Importing font..."
FONT 8, "MS Sans Serif"
BEGIN
CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH |
WS_BORDER,7,7,216,11
END
IDD_FREETYPE DIALOG DISCARDABLE 0, 0, 234, 68
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "FreeType Import Options"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,177,47,50,14
PUSHBUTTON "Cancel",IDCANCEL,115,47,50,14
LTEXT "Render Point Size:",IDC_STATIC,7,10,60,8
EDITTEXT IDC_PSIZE,70,8,40,14,ES_AUTOHSCROLL | ES_NUMBER
CONTROL "Monochrome",IDC_BITDEPTH,"Button",BS_AUTORADIOBUTTON,
120,27,57,10
CONTROL "Grayscale",IDC_BITDEPTH2,"Button",BS_AUTORADIOBUTTON,
180,27,47,10
LTEXT "Screen Resolution:",IDC_STATIC,7,28,61,8
EDITTEXT IDC_RES,70,26,40,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Max Character:",IDC_STATIC,132,10,49,8
EDITTEXT IDC_MAXCHAR,183,8,40,14,ES_AUTOHSCROLL | ES_NUMBER
PUSHBUTTON "Batch...",IDC_BATCH,7,47,50,14
END
IDD_FREETYPEBATCH DIALOG DISCARDABLE 0, 0, 234, 114
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "FreeType Import Options"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,177,93,50,14
PUSHBUTTON "Cancel",IDCANCEL,115,93,50,14
LTEXT "Render Point Sizes:",IDC_STATIC,7,10,63,8
EDITTEXT IDC_PSIZE,71,8,156,14,ES_AUTOHSCROLL
CONTROL "Monochrome",IDC_BITDEPTH,"Button",BS_AUTORADIOBUTTON,58,
58,57,10
CONTROL "Grayscale",IDC_BITDEPTH2,"Button",BS_AUTORADIOBUTTON,
118,58,47,10
LTEXT "Screen Resolution:",IDC_STATIC,117,41,61,8
EDITTEXT IDC_RES,180,39,40,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "Max Character:",IDC_STATIC,15,41,49,8
EDITTEXT IDC_MAXCHAR,67,39,40,14,ES_AUTOHSCROLL | ES_NUMBER
GROUPBOX "Common Settings",IDC_STATIC,7,27,220,45
LTEXT "Font name:",IDC_STATIC,7,77,36,8
EDITTEXT IDC_FONTNAME,49,75,178,14,ES_AUTOHSCROLL
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 240
TOPMARGIN, 7
BOTTOMMARGIN, 50
END
IDD_MAINDIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 234
TOPMARGIN, 7
BOTTOMMARGIN, 163
END
IDD_FONCHOOSER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 159
TOPMARGIN, 7
BOTTOMMARGIN, 154
END
IDD_PROGRESS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 223
TOPMARGIN, 7
BOTTOMMARGIN, 18
END
IDD_FREETYPE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 227
TOPMARGIN, 7
BOTTOMMARGIN, 61
END
IDD_FREETYPEBATCH, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 227
TOPMARGIN, 8
BOTTOMMARGIN, 107
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_APPMENU MENU DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "Import FNT...", ID_FILE_FNT
MENUITEM "Import BDF...", ID_FILE_BDF
MENUITEM "Import FON...", ID_FILE_FON
MENUITEM "Open P2F...", ID_FILE_P2F
MENUITEM "Batch Convert TrueType...", ID_FILE_TRUETYPE
MENUITEM SEPARATOR
MENUITEM "Export P2F...", ID_FILE_EXPORT
MENUITEM SEPARATOR
MENUITEM "About...", ID_FILE_ABOUT
MENUITEM "Exit", ID_FILE_EXIT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
BEGIN
"A", ID_FILE_ABOUT, VIRTKEY, CONTROL, NOINVERT
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

52
Sources/Tools/plFontConverter/res/resource.h

@ -1,52 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by plFontConverter.rc
//
#define IDI_APPICON 101
#define IDR_APPMENU 102
#define IDD_MAINDIALOG 103
#define IDD_ABOUT 104
#define IDD_FONCHOOSER 105
#define IDR_ACCELERATOR1 106
#define IDD_PROGRESS 106
#define IDD_FREETYPE 107
#define IDD_FREETYPEBATCH 108
#define IDC_FACE 1002
#define IDC_FSIZE 1003
#define IDC_STARTG 1004
#define IDC_GCOUNT 1005
#define IDC_WIDTH 1006
#define IDC_HEIGHT 1007
#define IDC_BPP 1008
#define IDC_PREVIEW 1010
#define IDC_RESLIST 1011
#define IDC_BOLD 1012
#define IDC_ITALIC 1013
#define IDC_PROGRESS 1014
#define IDC_PREVTEXT 1015
#define IDC_PSIZE 1016
#define IDC_BITDEPTH 1017
#define IDC_BITDEPTH2 1018
#define IDC_RES 1019
#define IDC_MAXCHAR 1020
#define IDC_BATCH 1021
#define IDC_FONTNAME 1022
#define ID_FILE_FNT 40000
#define ID_FILE_EXPORT 40001
#define ID_FILE_EXIT 40002
#define ID_FILE_BDF 40003
#define ID_FILE_ABOUT 40004
#define ID_FILE_P2F 40005
#define ID_FILE_FON 40006
#define ID_FILE_TRUETYPE 40007
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40008
#define _APS_NEXT_CONTROL_VALUE 1023
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

48
Sources/Tools/plLocalizationEditor/CMakeLists.txt

@ -8,24 +8,43 @@ add_definitions("-DUNICODE")
set(plLocalizationEditor_HEADERS
plAddDlgs.h
plEditDlg.h
plLocTreeView.h
plEditDlg.h
plLocTreeView.h
)
qt5_wrap_cpp(plLocalizationEditor_MOC ${plLocalizationEditor_HEADERS})
set(plLocalizationEditor_SOURCES
plAddDlgs.cpp
plEditDlg.cpp
plLocalizationEditor.cpp
plLocTreeView.cpp
plEditDlg.cpp
plLocalizationEditor.cpp
plLocTreeView.cpp
)
set(plLocalizationEditor_RESOURCES
res/plLocalizationEditor.rc
res/resource.h
res/icon1.ico
if(WIN32)
set(plLocalizationEditor_SOURCES ${plLocalizationEditor_SOURCES}
res/plLocalizationEditor.rc
)
endif()
set(plLocalizationEditor_RCC_SOURCES
res/plLocalizationEditor.qrc
)
qt5_add_resources(plLocalizationEditor_RCC ${plLocalizationEditor_RCC_SOURCES})
set(plLocalizationEditor_UIC_SOURCES
res/EditDialog.ui
res/AddElement.ui
res/AddLocalization.ui
)
qt5_wrap_ui(plLocalizationEditor_UIC ${plLocalizationEditor_UIC_SOURCES})
# For generated ui_*.h files
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(plLocalizationEditor WIN32 ${plLocalizationEditor_HEADERS} ${plLocalizationEditor_SOURCES} ${plLocalizationEditor_RESOURCES})
add_executable(plLocalizationEditor WIN32 ${plLocalizationEditor_HEADERS}
${plLocalizationEditor_SOURCES} ${plLocalizationEditor_RCC}
${plLocalizationEditor_UIC} ${plLocalizationEditor_MOC})
target_link_libraries(plLocalizationEditor CoreLib)
target_link_libraries(plLocalizationEditor pnSceneObject)
@ -33,12 +52,13 @@ target_link_libraries(plLocalizationEditor pnUUID)
target_link_libraries(plLocalizationEditor plResMgr)
target_link_libraries(plLocalizationEditor pfLocalizationMgr)
target_link_libraries(plLocalizationEditor ${EXPAT_LIBRARY})
target_link_libraries(plLocalizationEditor comctl32)
target_link_libraries(plLocalizationEditor Qt5::Widgets)
if(USE_VLD)
target_link_libraries(plLocalizationEditor ${VLD_LIBRARY})
endif()
source_group("Source Files" FILES ${plLocalizationEditor_SOURCES})
source_group("Source Files" FILES ${plLocalizationEditor_SOURCES} ${plLocalizationEditor_MOC})
source_group("Header Files" FILES ${plLocalizationEditor_HEADERS})
source_group("Resource Files" FILES ${plLocalizationEditor_RESOURCES})
source_group("Resource Files" FILES ${plLocalizationEditor_RCC_SOURCES} ${plLocalizationEditor_RCC}
${plLocalizationEditor_UIC_SOURCES} ${plLocalizationEditor_UIC})

375
Sources/Tools/plLocalizationEditor/plAddDlgs.cpp

@ -41,291 +41,119 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
// basic classes for encapsulating the add dialogs
#include "res/resource.h"
#include "plAddDlgs.h"
#include "plEditDlg.h"
#include "plResMgr/plLocalization.h"
#include "pfLocalizationMgr/pfLocalizationDataMgr.h"
#include <vector>
#include <map>
#include <QPushButton>
#include "ui_AddElement.h"
#include "ui_AddLocalization.h"
extern HINSTANCE gInstance;
#include <vector>
// very simple subclass for edit controls (and combo boxes) so that they only accept alphanumeric values
class AlphaNumericEditCtrl
// very simple validator for edit controls (and combo boxes) so that they only accept alphanumeric values
class AlphaNumericValidator : public QValidator
{
int fCtrlID;
HWND fOwner, fEditBox;
LONG_PTR fPrevProc;
public:
AlphaNumericEditCtrl() : fCtrlID(0), fOwner(NULL), fEditBox(NULL), fPrevProc(NULL) {}
~AlphaNumericEditCtrl() {}
void Setup(int ctrlID, HWND owner, bool comboBox);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
};
std::map<int, AlphaNumericEditCtrl> editBoxMap;
AlphaNumericValidator(QObject *parent = nullptr) : QValidator(parent) { }
// basic setup of the edit control
void AlphaNumericEditCtrl::Setup(int ctrlID, HWND owner, bool comboBox)
{
fCtrlID = ctrlID;
fOwner = owner;
// if we're a combo box, we need to subclass the edit control, not the combo box
if (comboBox)
virtual State validate(QString &input, int &pos) const override
{
COMBOBOXINFO cbinfo;
cbinfo.cbSize = sizeof(COMBOBOXINFO);
GetComboBoxInfo(GetDlgItem(fOwner, fCtrlID), &cbinfo);
fEditBox = cbinfo.hwndItem;
}
else
fEditBox = GetDlgItem(fOwner, fCtrlID);
// subclass the edit box so we can filter input (don't ask me why we have to double cast the
// function pointer to get rid of the compiler warning)
fPrevProc = SetWindowLongPtr(fEditBox, GWLP_WNDPROC, (LONG)(LONG_PTR)AlphaNumericEditCtrl::WndProc);
editBoxMap[fCtrlID] = *this;
}
// Message handler for our edit box
LRESULT CALLBACK AlphaNumericEditCtrl::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int ctrlID = GetDlgCtrlID(hWnd);
if (editBoxMap.find(ctrlID) == editBoxMap.end()) // control ID doesn't exist, so it's probably a combo boxes' edit ctrl
ctrlID = GetDlgCtrlID(GetParent(hWnd)); // so grab the parent's ID number instead
switch (message)
{
case WM_CHAR:
for (int ch = 0; ch < input.size(); ++ch)
{
AlphaNumericEditCtrl editBox = editBoxMap[ctrlID];
char theChar = (char)wParam;
// we only accept 0-9, a-z, A-Z, or backspace
if ((theChar < '0' || theChar > '9') && (theChar < 'a' || theChar > 'z') && (theChar < 'A' || theChar >'Z') && !(theChar == VK_BACK))
{
MessageBeep(-1); // alert the user
return FALSE; // and make sure the default handler doesn't get it
}
ushort theChar = input[ch].unicode();
if ((theChar < '0' || theChar > '9') && (theChar < 'a' || theChar > 'z')
&& (theChar < 'A' || theChar >'Z'))
return Invalid;
}
return Acceptable;
}
// Any messages we don't process must be passed onto the original window function
return CallWindowProc((WNDPROC)editBoxMap[ctrlID].fPrevProc, hWnd, message, wParam, lParam);
}
};
// plAddElementDlg - dialog for adding a single element
INT_PTR CALLBACK plAddElementDlg::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
plAddElementDlg::plAddElementDlg(const plString &parentPath, QWidget *parent)
: QDialog(parent), fBlockUpdates(false)
{
static plAddElementDlg* pthis = NULL;
fUI = new Ui_AddElement;
fUI->setupUi(this);
layout()->setSizeConstraint(QLayout::SetFixedSize);
switch (msg)
{
case WM_INITDIALOG:
pthis = (plAddElementDlg*)lParam;
if (!pthis->IInitDlg(hDlg))
EndDialog(hDlg, 0);
return FALSE;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK)
{
EndDialog(hDlg, 1);
return TRUE;
}
else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, 0);
return TRUE;
}
else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_PARENTAGE)
{
wchar_t buff[256];
// we do this whole get sel, get item because get text won't return the updated text
int index = (int)SendMessage(GetDlgItem(hDlg, IDC_PARENTAGE), CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
SendMessage(GetDlgItem(hDlg, IDC_PARENTAGE), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff);
pthis->fAgeName = plString::FromWchar(buff);
pthis->fAgeChanged = true;
pthis->IUpdateDlg(hDlg);
}
else if (HIWORD(wParam) == CBN_EDITCHANGE && LOWORD(wParam) == IDC_PARENTAGE)
{
wchar_t buff[256];
GetDlgItemTextW(hDlg, IDC_PARENTAGE, buff, 256);
pthis->fAgeName = plString::FromWchar(buff);
pthis->fAgeChanged = true;
pthis->IUpdateDlg(hDlg, false);
}
else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_PARENTSET)
{
wchar_t buff[256];
// we do this whole get sel, get item because get text won't return the updated text
int index = (int)SendMessage(GetDlgItem(hDlg, IDC_PARENTSET), CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
SendMessage(GetDlgItem(hDlg, IDC_PARENTSET), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff);
pthis->fSetName = plString::FromWchar(buff);
pthis->IUpdateDlg(hDlg);
}
else if (HIWORD(wParam) == CBN_EDITCHANGE && LOWORD(wParam) == IDC_PARENTSET)
{
wchar_t buff[256];
GetDlgItemTextW(hDlg, IDC_PARENTSET, buff, 256);
AlphaNumericValidator *validator = new AlphaNumericValidator(this);
fUI->fParentAge->setValidator(validator);
fUI->fParentSet->setValidator(validator);
fUI->fElementName->setValidator(validator);
pthis->fSetName = plString::FromWchar(buff);
pthis->IUpdateDlg(hDlg, false);
}
else if (HIWORD(wParam) == EN_UPDATE && LOWORD(wParam) == IDC_ELEMENTNAME)
{
wchar_t buff[256];
GetDlgItemTextW(hDlg, IDC_ELEMENTNAME, buff, 256);
pthis->fElementName = plString::FromWchar(buff);
connect(fUI->fParentAge, SIGNAL(currentTextChanged(QString)), SLOT(Update(QString)));
connect(fUI->fParentSet, SIGNAL(currentTextChanged(QString)), SLOT(Update(QString)));
connect(fUI->fElementName, SIGNAL(textChanged(QString)), SLOT(Update(QString)));
pthis->IUpdateDlg(hDlg);
}
break;
// throw away vars
plString element, lang;
SplitLocalizationPath(parentPath, fAgeName, fSetName, element, lang);
}
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_CLOSE:
EndDialog(hDlg, 0);
return TRUE;
}
break;
}
return FALSE;
plAddElementDlg::~plAddElementDlg()
{
delete fUI;
}
bool plAddElementDlg::IInitDlg(HWND hDlg)
bool plAddElementDlg::DoPick()
{
HWND listCtrl = GetDlgItem(hDlg, IDC_PARENTAGE);
std::vector<plString> ageNames = pfLocalizationDataMgr::Instance().GetAgeList();
fBlockUpdates = true;
// add the age names to the list
for (int i = 0; i < ageNames.size(); i++)
SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)ageNames[i].c_str());
fUI->fParentAge->addItem(ageNames[i].c_str());
// select the age we were given
SendMessage(listCtrl, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)fAgeName.c_str());
fUI->fParentAge->setCurrentText("");
fBlockUpdates = false;
fUI->fParentAge->setCurrentText(fAgeName.c_str());
AlphaNumericEditCtrl ageCtrl, setCtrl, subCtrl;
ageCtrl.Setup(IDC_PARENTAGE, hDlg, true);
setCtrl.Setup(IDC_PARENTSET, hDlg, true);
subCtrl.Setup(IDC_ELEMENTNAME, hDlg, false);
fAgeChanged = true;
IUpdateDlg(hDlg);
return true;
return exec() == QDialog::Accepted;
}
void plAddElementDlg::IUpdateDlg(HWND hDlg, bool setFocus)
void plAddElementDlg::Update(const QString &text)
{
plString pathStr = plString::Format("Path: %s.%s.%s", fAgeName.c_str(), fSetName.c_str(), fElementName.c_str());
SetDlgItemTextW(hDlg, IDC_PATH, pathStr.ToWchar());
if (fBlockUpdates)
return;
if (sender() == fUI->fParentAge)
fAgeName = plString(text.toUtf8().constData());
else if (sender() == fUI->fParentSet)
fSetName = plString(text.toUtf8().constData());
else if (sender() == fUI->fElementName)
fElementName = plString(text.toUtf8().constData());
if (fAgeChanged) // we only update this if the age changed (saves time and prevents weird bugs, like typing backwards)
fUI->fPathLabel->setText(tr("%1.%2.%3").arg(fAgeName.c_str())
.arg(fSetName.c_str()).arg(fElementName.c_str()));
if (sender() == fUI->fParentAge) // we only update this if the age changed
{
// now add the sets
HWND listCtrl = GetDlgItem(hDlg, IDC_PARENTSET);
SendMessage(listCtrl, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
fUI->fParentSet->clear();
fUI->fParentSet->clearEditText();
std::vector<plString> setNames = pfLocalizationDataMgr::Instance().GetSetList(fAgeName);
// add the set names to the list
fBlockUpdates = true;
for (int i = 0; i < setNames.size(); i++)
SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)setNames[i].c_str());
fUI->fParentSet->addItem(setNames[i].c_str());
// select the set we currently have
int ret = (int)SendMessage(listCtrl, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)fSetName.c_str());
if (ret == CB_ERR) // couldn't find the string, so just set it as the current string in the edit box
SetDlgItemTextW(hDlg, IDC_PARENTSET, fSetName.ToWchar());
fAgeChanged = false;
fUI->fParentSet->setCurrentText("");
fBlockUpdates = false;
fUI->fParentSet->setCurrentText(fSetName.c_str());
}
if (!fSetName.IsEmpty() && setFocus)
SetFocus(GetDlgItem(hDlg, IDC_ELEMENTNAME));
if (!fSetName.IsEmpty() && fElementName.IsEmpty())
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
else
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
plAddElementDlg::plAddElementDlg(plString parentPath)
{
// throw away vars
plString element, lang;
SplitLocalizationPath(parentPath, fAgeName, fSetName, element, lang);
}
bool plAddElementDlg::DoPick(HWND parent)
{
INT_PTR ret = DialogBoxParam(gInstance, MAKEINTRESOURCE(IDD_ADDELEMENT),
parent, IDlgProc, (LPARAM)this);
editBoxMap.clear();
return (ret != 0);
bool valid = !(fAgeName.IsEmpty() || fSetName.IsEmpty() || fElementName.IsEmpty());
fUI->fButtons->button(QDialogButtonBox::Ok)->setEnabled(valid);
}
// plAddLocalizationDlg - dialog for adding a single localization
INT_PTR CALLBACK plAddLocalizationDlg::IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static plAddLocalizationDlg* pthis = NULL;
switch (msg)
{
case WM_INITDIALOG:
pthis = (plAddLocalizationDlg*)lParam;
if (!pthis->IInitDlg(hDlg))
EndDialog(hDlg, 0);
return FALSE;
case WM_COMMAND:
if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK)
{
EndDialog(hDlg, 1);
return TRUE;
}
else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, 0);
return TRUE;
}
else if (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_LANGUAGE)
{
wchar_t buff[256];
// we do this whole get sel, get item because get text won't return the updated text
int index = (int)SendMessage(GetDlgItem(hDlg, IDC_LANGUAGE), CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
SendMessage(GetDlgItem(hDlg, IDC_LANGUAGE), CB_GETLBTEXT, (WPARAM)index, (LPARAM)buff);
pthis->fLanguageName = plString::FromWchar(buff);
pthis->IUpdateDlg(hDlg);
}
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_CLOSE:
EndDialog(hDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
std::vector<plString> IGetAllLanguageNames()
{
int numLocales = plLocalization::GetNumLocales();
@ -342,10 +170,24 @@ std::vector<plString> IGetAllLanguageNames()
return retVal;
}
bool plAddLocalizationDlg::IInitDlg(HWND hDlg)
plAddLocalizationDlg::plAddLocalizationDlg(const plString &parentPath, QWidget *parent)
: QDialog(parent)
{
fUI = new Ui_AddLocalization;
fUI->setupUi(this);
layout()->setSizeConstraint(QLayout::SetFixedSize);
connect(fUI->fLanguage, SIGNAL(currentIndexChanged(int)), SLOT(SelectLanguage(int)));
// throw away vars
plString lang;
SplitLocalizationPath(parentPath, fAgeName, fSetName, fElementName, lang);
}
bool plAddLocalizationDlg::DoPick()
{
plString pathStr = plString::Format("Path: %s.%s.%s", fAgeName.c_str(), fSetName.c_str(), fElementName.c_str());
SetDlgItemTextW(hDlg, IDC_PATH, pathStr.ToWchar());
fUI->fPathLabel->setText(tr("%1.%2.%3").arg(fAgeName.c_str())
.arg(fSetName.c_str()).arg(fElementName.c_str()));
std::vector<plString> existingLanguages;
existingLanguages = pfLocalizationDataMgr::Instance().GetLanguages(fAgeName, fSetName, fElementName);
@ -353,61 +195,30 @@ bool plAddLocalizationDlg::IInitDlg(HWND hDlg)
std::vector<plString> missingLanguages = IGetAllLanguageNames();
for (int i = 0; i < existingLanguages.size(); i++) // remove all languages we already have
{
for (int j = 0; j < missingLanguages.size(); j++)
for (auto lit = missingLanguages.begin(); lit != missingLanguages.end(); )
{
if (missingLanguages[j] == existingLanguages[i])
{
missingLanguages.erase(missingLanguages.begin() + j);
j--;
}
if (*lit == existingLanguages[i])
lit = missingLanguages.erase(lit);
else
++lit;
}
}
HWND listCtrl = GetDlgItem(hDlg, IDC_LANGUAGE);
// see if any languages are missing
if (missingLanguages.size() == 0)
{
// none are missing, so disable the control
EnableWindow(listCtrl, FALSE);
IUpdateDlg(hDlg);
return true;
// none are missing, so close the dialog
return false;
}
// add the missing languages to the list
for (int i = 0; i < missingLanguages.size(); i++)
SendMessage(listCtrl, CB_ADDSTRING, (WPARAM)0, (LPARAM)missingLanguages[i].c_str());
fUI->fLanguage->addItem(missingLanguages[i].c_str());
// select the first language in the list
SendMessage(listCtrl, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
// and put it's value into the internal variable
wchar_t buff[256];
GetDlgItemText(hDlg, IDC_LANGUAGE, buff, 256);
fLanguageName = plString::FromWchar(buff);
IUpdateDlg(hDlg);
return true;
}
void plAddLocalizationDlg::IUpdateDlg(HWND hDlg)
{
if (!fLanguageName.IsEmpty())
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
else
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
plAddLocalizationDlg::plAddLocalizationDlg(plString parentPath)
{
// throw away vars
plString lang;
SplitLocalizationPath(parentPath, fAgeName, fSetName, fElementName, lang);
return exec() == QDialog::Accepted;
}
bool plAddLocalizationDlg::DoPick(HWND parent)
void plAddLocalizationDlg::SelectLanguage(int which)
{
INT_PTR ret = DialogBoxParam(gInstance, MAKEINTRESOURCE(IDD_ADDLOCALIZATION),
parent, IDlgProc, (LPARAM)this);
return (ret != 0);
fLanguageName = fUI->fLanguage->itemText(which).toUtf8().constData();
}

53
Sources/Tools/plLocalizationEditor/plAddDlgs.h

@ -43,41 +43,48 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef __plAddDlgs_h__
#define __plAddDlgs_h__
#include "HeadSpin.h"
#include "hsWindows.h"
#include <QDialog>
#include "plString.h"
class plAddElementDlg
class plAddElementDlg : public QDialog
{
protected:
static INT_PTR CALLBACK IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
Q_OBJECT
bool IInitDlg(HWND hDlg);
void IUpdateDlg(HWND hDlg, bool setFocus = true);
plString fAgeName, fSetName, fElementName;
bool fAgeChanged;
public:
plAddElementDlg(plString parentPath);
plAddElementDlg(const plString &parentPath, QWidget *parent = nullptr);
virtual ~plAddElementDlg();
bool DoPick(); // returns true if [Ok] clicked, false otherwise.
plString GetValue() const
{
return plString::Format("%s.%s.%s", fAgeName.c_str(), fSetName.c_str(), fElementName.c_str());
}
bool DoPick(HWND parent); // returns true if [Ok] clicked, false otherwise.
plString GetValue() {return plString::Format("%s.%s.%s", fAgeName.c_str(), fSetName.c_str(), fElementName.c_str());}
private slots:
void Update(const QString &text);
private:
class Ui_AddElement *fUI;
plString fAgeName, fSetName, fElementName;
bool fBlockUpdates;
};
class plAddLocalizationDlg
class plAddLocalizationDlg : public QDialog
{
protected:
static INT_PTR CALLBACK IDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
Q_OBJECT
bool IInitDlg(HWND hDlg);
void IUpdateDlg(HWND hDlg);
plString fAgeName, fSetName, fElementName, fLanguageName;
public:
plAddLocalizationDlg(plString parentPath);
plAddLocalizationDlg(const plString &parentPath, QWidget *parent = nullptr);
bool DoPick(); // returns true if [Ok] clicked, false otherwise.
const plString &GetValue() const { return fLanguageName; }
bool DoPick(HWND parent); // returns true if [Ok] clicked, false otherwise.
plString GetValue() {return fLanguageName;}
private slots:
void SelectLanguage(int which);
private:
class Ui_AddLocalization *fUI;
plString fAgeName, fSetName, fElementName, fLanguageName;
};
#endif

444
Sources/Tools/plLocalizationEditor/plEditDlg.cpp

@ -41,250 +41,340 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
// Basic edit dialog stuff
#include "plEditDlg.h"
#include "res/resource.h"
#include "plLocTreeView.h"
#include "plAddDlgs.h"
#include "pfLocalizationMgr/pfLocalizationMgr.h"
#include "pfLocalizationMgr/pfLocalizationDataMgr.h"
#include <map>
#include <QDialog>
#include <QMessageBox>
#include <QFileDialog>
#include "ui_EditDialog.h"
HWND gEditDlg = NULL;
extern HINSTANCE gInstance;
extern HWND gTreeView;
#include <functional>
// global data for this dialog
plString gCurrentPath;
// split a subtitle path up into its component parts
void SplitLocalizationPath(plString path, plString &ageName, plString &setName, plString &locName, plString &locLanguage)
static void IAboutDialog(QWidget *parent)
{
ageName = setName = locName = locLanguage = "";
std::vector<plString> tokens = path.Tokenize(".");
if (tokens.size() >= 1)
ageName = tokens[0];
if (tokens.size() >= 2)
setName = tokens[1];
if (tokens.size() >= 3)
locName = tokens[2];
if (tokens.size() >= 4)
locLanguage = tokens[3];
QDialog dlg(parent);
QLabel *image = new QLabel(&dlg);
image->setPixmap(QPixmap(":/icon1.ico"));
QLabel *text = new QLabel(QObject::tr(R"(plLocalizationEditor
A basic editor for Plasma 21 localization resource files
Copyright (C) 2004 Cyan Worlds, Inc.)"), &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();
}
// saves the current localization text to the data manager
void SaveLocalizationText()
EditDialog::EditDialog()
: fEditMode(kEditNothing)
{
if (gCurrentPath.IsEmpty())
return; // no path to save
fUI = new Ui_EditDialog;
fUI->setupUi(this);
uint32_t textLen = (uint32_t)SendMessage(GetDlgItem(gEditDlg, IDC_LOCALIZATIONTEXT), WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0);
wchar_t *buffer = new wchar_t[textLen + 2];
GetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, buffer, textLen + 1);
buffer[textLen + 1] = 0;
plString plainTextData = plString::FromWchar(buffer);
delete [] buffer;
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage);
connect(fUI->fOpenAction, SIGNAL(triggered()), SLOT(OpenDataDirectory()));
connect(fUI->fSaveCurrentAction, SIGNAL(triggered()), SLOT(SaveToCurrent()));
connect(fUI->fSaveOtherAction, SIGNAL(triggered()), SLOT(SaveToDirectory()));
connect(fUI->fExitAction, SIGNAL(triggered()), SLOT(close()));
connect(fUI->fAboutAction, &QAction::triggered, std::bind(&IAboutDialog, this));
plString name = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
pfLocalizationDataMgr::Instance().SetElementPlainTextData(name, elementLanguage, plainTextData);
connect(fUI->fLocalizationTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
SLOT(LocPathChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
connect(fUI->fAddButton, SIGNAL(clicked()), SLOT(AddClicked()));
connect(fUI->fDeleteButton, SIGNAL(clicked()), SLOT(DeleteClicked()));
EnableEdit(false);
}
// Reset all controls to their default values (except for static controls)
void ResetDlgDefaults()
EditDialog::~EditDialog()
{
SetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, L"");
pfLocalizationMgr::Shutdown();
delete fUI;
}
// Enable/disable all edit controls (some won't enable/disable unless an audio file is loaded and the subtitle is timed)
void EnableDlg(BOOL enable)
// saves the current localization text to the data manager
void EditDialog::SaveLocalizationText()
{
if (!enable)
ResetDlgDefaults(); // reset controls to defaults
if (fCurrentLocPath.IsEmpty())
return; // no path to save
plString text = fUI->fLocalizationText->toPlainText().toUtf8().constData();
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(fCurrentLocPath, ageName, setName, elementName, elementLanguage);
EnableWindow(GetDlgItem(gEditDlg, IDC_LOCALIZATIONTEXT), enable);
if (ageName.IsEmpty() || setName.IsEmpty() || elementName.IsEmpty() || elementLanguage.IsEmpty())
return;
plString name = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
pfLocalizationDataMgr::Instance().SetElementPlainTextData(name, elementLanguage, text);
}
// updates the edit dialog based on the path specified
void UpdateEditDlg(plString locPath)
void EditDialog::LoadLocalization(const plString &locPath)
{
if (locPath == gCurrentPath)
if (locPath == fCurrentLocPath)
return;
gCurrentPath = locPath;
plString itemText = plString::Format("Text (%s):", locPath.c_str());
SetDlgItemTextW(gEditDlg, IDC_LOCPATH, itemText.ToWchar());
fCurrentLocPath = locPath;
fUI->fTextPathLabel->setText(QString("&Text (%1):").arg(locPath.c_str()));
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(locPath, ageName, setName, elementName, elementLanguage);
// now make sure they've drilled down deep enough to enable the dialog
if (elementLanguage.IsEmpty()) // not deep enough
EnableDlg(FALSE);
EnableEdit(false);
else
{
EnableDlg(TRUE);
EnableEdit(true);
plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
plString elementText = pfLocalizationDataMgr::Instance().GetElementPlainTextData(key, elementLanguage);
SetDlgItemTextW(gEditDlg, IDC_LOCALIZATIONTEXT, elementText.ToWchar());
fUI->fLocalizationText->setPlainText(elementText.c_str());
}
// now to setup the add/delete buttons
if (!elementLanguage.IsEmpty()) // they have selected a language
{
SetDlgItemText(gEditDlg, IDC_ADD, L"Add Localization");
EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE);
SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Localization");
if (elementLanguage != "English") // don't allow them to delete the default language
EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE);
else
EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
fEditMode = kEditLocalization;
fUI->fAddButton->setText(tr("&Add Localization"));
fUI->fAddButton->setEnabled(true);
fUI->fDeleteButton->setText(tr("&Delete Localization"));
// don't allow them to delete the default language
fUI->fDeleteButton->setEnabled(elementLanguage != "English");
}
else // they have selected something else
{
SetDlgItemText(gEditDlg, IDC_ADD, L"Add Element");
EnableWindow(GetDlgItem(gEditDlg, IDC_ADD), TRUE);
SetDlgItemText(gEditDlg, IDC_DELETE, L"Delete Element");
fEditMode = kEditElement;
fUI->fAddButton->setText(tr("&Add Element"));
fUI->fAddButton->setEnabled(true);
fUI->fDeleteButton->setText(tr("&Delete Element"));
if (!elementName.IsEmpty()) // they have selected an individual element
{
std::vector<plString> elementNames = pfLocalizationDataMgr::Instance().GetElementList(ageName, setName);
if (elementNames.size() > 1) // they can't delete the only subtitle in a set
EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), TRUE);
else
EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
// they can't delete the only subtitle in a set
fUI->fDeleteButton->setEnabled(elementNames.size() > 1);
}
else
EnableWindow(GetDlgItem(gEditDlg, IDC_DELETE), FALSE);
fUI->fDeleteButton->setEnabled(false);
}
}
void EditDialog::EnableEdit(bool enable)
{
if (!enable)
fUI->fLocalizationText->setPlainText("");
fUI->fLocalizationText->setEnabled(enable);
}
void EditDialog::closeEvent(QCloseEvent *event)
{
if (fCurrentSavePath.isEmpty()) // no data open
{
event->accept();
return;
}
SaveLocalizationText(); // make sure any changed text is saved to the manager
QMessageBox::StandardButton result = QMessageBox::question(this, tr("Save Changes"),
tr("Do you wish to save your changes?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (result == QMessageBox::Yes)
SaveToDirectory();
if (result == QMessageBox::Cancel)
event->ignore();
else
event->accept();
}
void EditDialog::OpenDataDirectory()
{
QString path = QFileDialog::getExistingDirectory(this,
tr("Select a localization data directory:"),
QDir::current().absolutePath(),
QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly);
if (!path.isEmpty())
{
plWaitCursor waitCursor(this);
pfLocalizationMgr::Shutdown();
fCurrentSavePath = path;
pfLocalizationMgr::Initialize(fCurrentSavePath.toUtf8().constData());
fUI->fLocalizationTree->clear();
fUI->fLocalizationTree->LoadData("");
SetTitle(path);
fUI->fSaveCurrentAction->setEnabled(true);
fUI->fSaveOtherAction->setEnabled(true);
}
}
void EditDialog::SaveToCurrent()
{
SaveLocalizationText(); // make sure any changed text is saved to the manager
// save it to our current directory
QMessageBox::StandardButton result = QMessageBox::question(this, tr("Save to Current Directory"),
tr("Are you sure you want to save to the current directory? Current data will be overwritten!"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (result == QMessageBox::Yes)
{
plWaitCursor waitCursor(this);
pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(fCurrentSavePath.toUtf8().constData());
}
else if (result == QMessageBox::No)
SaveToDirectory();
// and if it's cancel we don't do anything
}
void EditDialog::SaveToDirectory()
{
SaveLocalizationText(); // make sure any changed text is saved to the manager
QString path = QFileDialog::getExistingDirectory(this,
tr("Select a directory to save the localization data to:"),
fCurrentSavePath, QFileDialog::ShowDirsOnly);
// save it to a new directory
if (!path.isEmpty())
{
plWaitCursor waitCursor(this);
fCurrentSavePath = path;
SetTitle(path);
pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(fCurrentSavePath.toUtf8().constData());
}
}
BOOL HandleCommandMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
void EditDialog::LocPathChanged(QTreeWidgetItem *current, QTreeWidgetItem *)
{
SaveLocalizationText(); // save any current changes to the database
LoadLocalization(fUI->fLocalizationTree->CurrentPath());
}
void EditDialog::AddClicked()
{
int wmID, wmEvent;
wmID = LOWORD(wParam);
wmEvent = HIWORD(wParam);
SaveLocalizationText(); // save any current changes to the database
switch (wmEvent)
if (fEditMode == kEditElement)
{
case BN_CLICKED:
switch (wmID)
plAddElementDlg dlg(fCurrentLocPath, this);
if (dlg.DoPick())
{
case IDC_ADD:
plString path = dlg.GetValue(); // path is age.set.name
if (!pfLocalizationDataMgr::Instance().AddElement(path))
{
SaveLocalizationText(); // save any current changes to the database
plString buttonText;
wchar_t buff[256];
GetDlgItemText(gEditDlg, IDC_ADD, buff, 256);
buttonText = plString::FromWchar(buff);
if (buttonText == "Add Element")
{
plAddElementDlg dlg(gCurrentPath);
if (dlg.DoPick(gEditDlg))
{
plString path = dlg.GetValue(); // path is age.set.name
if (!pfLocalizationDataMgr::Instance().AddElement(path))
MessageBox(gEditDlg, L"Couldn't add new element because one already exists with that name!", L"Error", MB_ICONERROR | MB_OK);
else
{
gCurrentPath = "";
plLocTreeView::ClearTreeView(gTreeView);
plLocTreeView::FillTreeViewFromData(gTreeView, path);
UpdateEditDlg(path);
}
}
}
else if (buttonText == "Add Localization")
{
plAddLocalizationDlg dlg(gCurrentPath);
if (dlg.DoPick(gEditDlg))
{
plString newLanguage = dlg.GetValue();
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage);
plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
if (!pfLocalizationDataMgr::Instance().AddLocalization(key, newLanguage))
MessageBox(gEditDlg, L"Couldn't add additional localization!", L"Error", MB_ICONERROR | MB_OK);
else
{
plString path = plString::Format("%s.%s", key.c_str(), newLanguage.c_str());
gCurrentPath = "";
plLocTreeView::ClearTreeView(gTreeView);
plLocTreeView::FillTreeViewFromData(gTreeView, path);
UpdateEditDlg(path);
}
}
}
return FALSE;
QMessageBox::critical(this, tr("Error"),
tr("Couldn't add new element because one already exists with that name!"));
}
case IDC_DELETE:
else
{
fCurrentLocPath = "";
fUI->fLocalizationTree->clear();
fUI->fLocalizationTree->LoadData(path);
LoadLocalization(path);
}
}
}
else if (fEditMode == kEditLocalization)
{
plAddLocalizationDlg dlg(fCurrentLocPath, this);
if (dlg.DoPick())
{
plString newLanguage = dlg.GetValue();
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(fCurrentLocPath, ageName, setName, elementName, elementLanguage);
plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
if (!pfLocalizationDataMgr::Instance().AddLocalization(key, newLanguage))
QMessageBox::critical(this, tr("Error"), tr("Couldn't add additional localization!"));
else
{
SaveLocalizationText(); // save any current changes to the database
plString messageText = plString::Format("Are you sure that you want to delete %s?", gCurrentPath.c_str());
int res = MessageBoxW(gEditDlg, messageText.ToWchar(), L"Delete", MB_ICONQUESTION | MB_YESNO);
if (res == IDYES)
{
plString buttonText;
wchar_t buff[256];
GetDlgItemText(gEditDlg, IDC_DELETE, buff, 256);
buttonText = plString::FromWchar(buff);
if (buttonText == "Delete Element")
{
if (!pfLocalizationDataMgr::Instance().DeleteElement(gCurrentPath))
MessageBox(gEditDlg, L"Couldn't delete element!", L"Error", MB_ICONERROR | MB_OK);
else
{
plString path = gCurrentPath;
gCurrentPath = "";
plLocTreeView::ClearTreeView(gTreeView);
plLocTreeView::FillTreeViewFromData(gTreeView, path);
UpdateEditDlg(path);
}
}
else if (buttonText == "Delete Localization")
{
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(gCurrentPath, ageName, setName, elementName, elementLanguage);
plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
if (!pfLocalizationDataMgr::Instance().DeleteLocalization(key, elementLanguage))
MessageBox(gEditDlg, L"Couldn't delete localization!", L"Error", MB_ICONERROR | MB_OK);
else
{
plString path = gCurrentPath;
gCurrentPath = "";
plLocTreeView::ClearTreeView(gTreeView);
plLocTreeView::FillTreeViewFromData(gTreeView, path);
UpdateEditDlg(path);
}
}
}
plString path = plString::Format("%s.%s", key.c_str(), newLanguage.c_str());
fCurrentLocPath = "";
fUI->fLocalizationTree->clear();
fUI->fLocalizationTree->LoadData(path);
LoadLocalization(path);
}
return FALSE;
}
}
return (BOOL)DefWindowProc(hWnd, msg, wParam, lParam);
}
// our dialog's window procedure
INT_PTR CALLBACK EditDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
void EditDialog::DeleteClicked()
{
switch(msg)
SaveLocalizationText(); // save any current changes to the database
QMessageBox::StandardButton reply = QMessageBox::question(this, tr("Delete"),
tr("Are you sure that you want to delete %1?").arg(fCurrentLocPath.c_str()));
if (reply == QMessageBox::Yes)
{
case WM_INITDIALOG:
if (fEditMode == kEditElement)
{
if (!pfLocalizationDataMgr::Instance().DeleteElement(fCurrentLocPath))
QMessageBox::critical(this, tr("Error"), tr("Couldn't delete element!"));
else
{
plString path = fCurrentLocPath;
fCurrentLocPath = "";
fUI->fLocalizationTree->clear();
fUI->fLocalizationTree->LoadData(path);
LoadLocalization(path);
}
}
else if (fEditMode == kEditLocalization)
{
gEditDlg = hWnd;
EnableDlg(FALSE);
plString ageName, setName, elementName, elementLanguage;
SplitLocalizationPath(fCurrentLocPath, ageName, setName, elementName, elementLanguage);
plString key = plString::Format("%s.%s.%s", ageName.c_str(), setName.c_str(), elementName.c_str());
if (!pfLocalizationDataMgr::Instance().DeleteLocalization(key, elementLanguage))
QMessageBox::critical(this, tr("Error"), tr("Couldn't delete localization!"));
else
{
plString path = key + ".English";
fCurrentLocPath = "";
fUI->fLocalizationTree->clear();
fUI->fLocalizationTree->LoadData(path);
LoadLocalization(path);
}
}
break;
case WM_COMMAND:
return HandleCommandMessage(hWnd, msg, wParam, lParam);
}
}
return FALSE;
// split a subtitle path up into its component parts
void SplitLocalizationPath(const plString &path, plString &ageName,
plString &setName, plString &locName, plString &locLanguage)
{
ageName = setName = locName = locLanguage = "";
std::vector<plString> tokens = path.Tokenize(".");
if (tokens.size() >= 1)
ageName = tokens[0];
if (tokens.size() >= 2)
setName = tokens[1];
if (tokens.size() >= 3)
locName = tokens[2];
if (tokens.size() >= 4)
locLanguage = tokens[3];
}

61
Sources/Tools/plLocalizationEditor/plEditDlg.h

@ -43,30 +43,69 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef _pfEditDlg_h
#define _pfEditDlg_h
#include "HeadSpin.h"
#include "hsWindows.h"
#include <QMainWindow>
#include "plString.h"
class plString;
class QTreeWidgetItem;
class EditDialog : public QMainWindow
{
Q_OBJECT
public:
EditDialog();
virtual ~EditDialog();
void SetTitle(const QString &path)
{
QString title = "plLocalizationEditor";
if (!path.isEmpty())
title += " - " + path;
setWindowTitle(title);
}
void SaveLocalizationText();
void LoadLocalization(const plString &path);
void EnableEdit(bool enable);
protected:
virtual void closeEvent(QCloseEvent *event);
private slots:
void OpenDataDirectory();
void SaveToCurrent();
void SaveToDirectory();
void LocPathChanged(QTreeWidgetItem *current, QTreeWidgetItem *);
void AddClicked();
void DeleteClicked();
private:
class Ui_EditDialog *fUI;
QString fCurrentSavePath;
plString fCurrentLocPath;
enum { kEditNothing, kEditElement, kEditLocalization } fEditMode;
};
// Little trick to show a wait cursor while something is working
class plWaitCursor
{
HCURSOR fOrig;
QWidget *fParent;
public:
plWaitCursor()
plWaitCursor(QWidget *parent) : fParent(parent)
{
fOrig = SetCursor(LoadCursor(NULL, IDC_WAIT));
fParent->setCursor(Qt::WaitCursor);
}
~plWaitCursor()
{
SetCursor(fOrig);
fParent->unsetCursor();
}
};
void SplitLocalizationPath(plString path, plString &ageName, plString &setName, plString &locName, plString &locLanguage);
void SaveLocalizationText();
void UpdateEditDlg(plString subtitlePath);
INT_PTR CALLBACK EditDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void SplitLocalizationPath(const plString &path, plString &ageName,
plString &setName, plString &locName, plString &locLanguage);
#endif

131
Sources/Tools/plLocalizationEditor/plLocTreeView.cpp

@ -42,45 +42,11 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plLocTreeView.h"
#include "plEditDlg.h"
#include "HeadSpin.h"
#include <commctrl.h>
#include <shlwapi.h>
#include "res/resource.h"
#include <vector>
#include <list>
#include "pfLocalizationMgr/pfLocalizationDataMgr.h"
extern HINSTANCE gInstance;
plString plLocTreeView::fPath = "";
HTREEITEM AddLeaf(HWND hTree, HTREEITEM hParent, plString text, bool sort = true)
{
// Semi-hack to keep these around as Win32 expects
static std::list<plStringBuffer<wchar_t>> bufs;
plStringBuffer<wchar_t> buf = text.ToWchar();
bufs.push_back(buf);
TVITEM tvi = {0};
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.pszText = const_cast<LPWSTR>(buf.GetData());
tvi.cchTextMax = static_cast<int>(buf.GetSize());
tvi.lParam = NULL;
TVINSERTSTRUCT tvins = {0};
tvins.item = tvi;
tvins.hParent = hParent;
if (sort)
tvins.hInsertAfter = TVI_SORT;
else
tvins.hInsertAfter = TVI_LAST;
return TreeView_InsertItem(hTree, &tvins);
}
void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, plString selectionPath)
void plLocTreeView::LoadData(const plString &selectionPath)
{
plString targetAge, targetSet, targetElement, targetLang;
SplitLocalizationPath(selectionPath, targetAge, targetSet, targetElement, targetLang);
@ -92,12 +58,13 @@ void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, plString selectionPath)
for (int curAge = 0; curAge < ages.size(); curAge++)
{
// add the age to the tree
HTREEITEM ageItem = AddLeaf(treeCtrl, NULL, ages[curAge]);
QTreeWidgetItem *ageItem = new QTreeWidgetItem(this, QStringList { ages[curAge].c_str() });
ageItem->setData(0, kLocPathRole, QString(ages[curAge].c_str()));
if (ages[curAge] == targetAge)
{
TreeView_SelectItem(treeCtrl, ageItem);
TreeView_EnsureVisible(treeCtrl, ageItem);
setCurrentItem(ageItem);
scrollToItem(ageItem);
ageMatched = true;
}
else
@ -108,12 +75,13 @@ void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, plString selectionPath)
{
std::vector<plString> elements = pfLocalizationDataMgr::Instance().GetElementList(ages[curAge], sets[curSet]);
HTREEITEM setItem = AddLeaf(treeCtrl, ageItem, sets[curSet]);
QTreeWidgetItem *setItem = new QTreeWidgetItem(ageItem, QStringList { sets[curSet].c_str() });
setItem->setData(0, kLocPathRole, QString("%1.%2").arg(ages[curAge].c_str()).arg(sets[curSet].c_str()));
if ((sets[curSet] == targetSet) && ageMatched)
{
TreeView_SelectItem(treeCtrl, setItem);
TreeView_EnsureVisible(treeCtrl, setItem);
setCurrentItem(setItem);
scrollToItem(setItem);
setMatched = true;
}
else
@ -121,12 +89,14 @@ void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, plString selectionPath)
for (int curElement = 0; curElement < elements.size(); curElement++)
{
HTREEITEM subItem = AddLeaf(treeCtrl, setItem, elements[curElement]);
QTreeWidgetItem *subItem = new QTreeWidgetItem(setItem, QStringList { elements[curElement].c_str() });
subItem->setData(0, kLocPathRole, QString("%1.%2.%3").arg(ages[curAge].c_str())
.arg(sets[curSet].c_str()).arg(elements[curElement].c_str()));
if (elements[curElement] == targetElement && setMatched)
{
TreeView_SelectItem(treeCtrl, subItem);
TreeView_EnsureVisible(treeCtrl, subItem);
setCurrentItem(subItem);
scrollToItem(subItem);
elementMatched = true;
if (targetLang.IsEmpty())
@ -138,78 +108,27 @@ void plLocTreeView::FillTreeViewFromData(HWND treeCtrl, plString selectionPath)
std::vector<plString> languages = pfLocalizationDataMgr::Instance().GetLanguages(ages[curAge], sets[curSet], elements[curElement]);
for (int curLang = 0; curLang < languages.size(); curLang++)
{
HTREEITEM langItem = AddLeaf(treeCtrl, subItem, languages[curLang]);
QTreeWidgetItem *langItem = new QTreeWidgetItem(subItem, QStringList { languages[curLang].c_str() });
langItem->setData(0, kLocPathRole, QString("%1.%2.%3.%4").arg(ages[curAge].c_str())
.arg(sets[curSet].c_str()).arg(elements[curElement].c_str())
.arg(languages[curLang].c_str()));
if (languages[curLang] == targetLang && elementMatched)
{
TreeView_SelectItem(treeCtrl, langItem);
TreeView_EnsureVisible(treeCtrl, langItem);
setCurrentItem(langItem);
scrollToItem(langItem);
}
}
}
}
}
}
void plLocTreeView::ClearTreeView(HWND treeCtrl)
{
TreeView_DeleteAllItems(treeCtrl);
sortByColumn(0, Qt::AscendingOrder);
}
void plLocTreeView::SelectionChanged(HWND treeCtrl)
plString plLocTreeView::CurrentPath() const
{
HTREEITEM hItem = TreeView_GetSelection(treeCtrl);
std::vector<plString> path;
fPath = "";
while (hItem)
{
wchar_t s[200];
TVITEM tvi = {0};
tvi.hItem = hItem;
tvi.mask = TVIF_TEXT;
tvi.pszText = s;
tvi.cchTextMax = 200;
TreeView_GetItem(treeCtrl, &tvi);
path.push_back(plString::FromWchar(tvi.pszText));
hItem = TreeView_GetParent(treeCtrl, hItem);
}
while (!path.empty())
{
fPath += path.back();
path.pop_back();
if (!path.empty())
fPath += ".";
}
}
void plLocTreeView::SelectionDblClicked(HWND treeCtrl)
{
HTREEITEM hItem = TreeView_GetSelection(treeCtrl);
std::vector<plString> path;
fPath = "";
while (hItem)
{
wchar_t s[200];
TVITEM tvi = {0};
tvi.hItem = hItem;
tvi.mask = TVIF_TEXT;
tvi.pszText = s;
tvi.cchTextMax = 200;
TreeView_GetItem(treeCtrl, &tvi);
path.push_back(plString::FromWchar(tvi.pszText));
hItem = TreeView_GetParent(treeCtrl, hItem);
}
while (!path.empty())
{
fPath += path.back();
path.pop_back();
if (!path.empty())
fPath += ".";
}
return (currentItem() != nullptr)
? plString(currentItem()->data(0, kLocPathRole).toString().toUtf8().constData())
: plString();
}

19
Sources/Tools/plLocalizationEditor/plLocTreeView.h

@ -42,22 +42,21 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef _plLocTreeView_h
#define _plLocTreeView_h
#include "HeadSpin.h"
#include <QTreeWidget>
#include "plString.h"
class plLocTreeView
class plLocTreeView : public QTreeWidget
{
protected:
static plString fPath;
public:
static void FillTreeViewFromData(HWND treeCtrl, plString selectionPath);
static void ClearTreeView(HWND treeCtrl);
enum Roles
{
kLocPathRole = Qt::UserRole
};
static void SelectionChanged(HWND treeCtrl);
static void SelectionDblClicked(HWND treeCtrl);
plLocTreeView(QWidget *parent = nullptr) : QTreeWidget(parent) { }
static plString GetPath() {return fPath;}
void LoadData(const plString &path);
plString CurrentPath() const;
};
#endif //_plLocTreeView_h

339
Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp

@ -39,12 +39,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
#define CLASSNAME L"plLocalizationEditor"
#define WINDOWNAME L"plLocalizationEditor"
#define IDC_REGTREEVIEW 1000
#define FILE_MENU_POS 0 // 0-based index of the file sub menu
#include "pnAllCreatables.h"
#include "plResMgr/plResMgrCreatable.h"
@ -57,340 +51,25 @@ REGISTER_CREATABLE(plAgeLoaded2Msg);
REGISTER_CREATABLE(plAgeBeginLoadingMsg);
REGISTER_CREATABLE(plInitialAgeStateLoadedMsg);
#include "pfLocalizationMgr/pfLocalizationMgr.h"
#include "pfLocalizationMgr/pfLocalizationDataMgr.h"
#include "plResMgr/plResManager.h"
#include "plLocTreeView.h"
#include <QApplication>
#include "plEditDlg.h"
#include "HeadSpin.h"
#include <commdlg.h>
#include <commctrl.h>
#include <shlwapi.h>
#include <shlobj.h>
#include "res/resource.h"
HINSTANCE gInstance = NULL;
HWND gMainWindow = NULL;
HWND gTreeView = NULL; // the tree view for display of localization strings
extern HWND gEditDlg; // the main edit dialog for the localization strings
std::wstring gCurPath = L""; // current data path
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL WinInit(HINSTANCE hInst, int nCmdShow);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
int main(int argc, char *argv[])
{
MSG msg;
HACCEL accelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1));
if (!WinInit(hInst, nCmdShow))
return -1;
QApplication app(argc, argv);
app.setApplicationName("plLocalizationEditor");
app.setWindowIcon(QIcon(":/icon1.ico"));
plResManager *rMgr = new plResManager;
hsgResMgr::Init(rMgr);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(gMainWindow, accelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
pfLocalizationMgr::Shutdown();
EditDialog editWin;
editWin.show();
int retn = app.exec();
hsgResMgr::Shutdown();
return 0;
}
BOOL WinInit(HINSTANCE hInst, int nCmdShow)
{
LoadLibrary(L"Riched20.dll"); // so we can use our rich edit control
gInstance = hInst;
WNDCLASSEX wcEx;
wcEx.cbSize = sizeof(WNDCLASSEX);
wcEx.style = CS_HREDRAW | CS_VREDRAW;
wcEx.lpfnWndProc = MainWndProc;
wcEx.cbClsExtra = 0;
wcEx.cbWndExtra = 0;
wcEx.hInstance = hInst;
wcEx.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APPICON));
wcEx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcEx.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wcEx.lpszMenuName = MAKEINTRESOURCE(IDR_APPMENU);
wcEx.lpszClassName = CLASSNAME;
wcEx.hIconSm = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wcEx))
return FALSE;
DWORD dwStyle = WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
DWORD dwExStyle = WS_EX_CONTROLPARENT;
// Create a window
gMainWindow = CreateWindowEx(dwExStyle, CLASSNAME, WINDOWNAME, dwStyle, 10, 10, 800, 500, NULL, NULL, hInst, NULL);
if (gMainWindow == NULL)
return FALSE;
return TRUE;
return retn;
}
void SetWindowTitle(HWND hWnd, std::wstring path)
{
std::wstring title = L"plLocalizationEditor";
if (path != L"")
title += L"-" + path;
SetWindowText(hWnd, title.c_str());
}
INT_PTR CALLBACK AboutDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if(msg == WM_COMMAND)
EndDialog(hWnd, 0);
return 0;
}
void RequestSaveOnExit()
{
if (gCurPath == L"") // no data open
return;
static bool alreadyRequested = false; // make sure we don't ask multiple times
if (alreadyRequested)
return;
alreadyRequested = true;
SaveLocalizationText(); // make sure any changed text is saved to the manager
int res = MessageBox(NULL, L"Do you wish to save your changes?", L"Save Changes", MB_ICONQUESTION | MB_YESNO);
if (res == IDYES)
{
// save it to a new directory
BROWSEINFO bInfo;
LPITEMIDLIST itemList;
LPMALLOC shMalloc;
wchar_t path[MAX_PATH];
memset(&bInfo, 0, sizeof(bInfo));
bInfo.hwndOwner = NULL;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = path;
bInfo.lpszTitle = L"Select a directory to save the localization data to:";
bInfo.ulFlags = BIF_EDITBOX;
itemList = SHBrowseForFolder(&bInfo);
if (itemList != NULL)
{
plWaitCursor waitCursor;
SHGetPathFromIDList(itemList, path);
SHGetMalloc(&shMalloc);
shMalloc->Free(itemList);
shMalloc->Release();
gCurPath = path;
char *sPath = hsWStringToString(gCurPath.c_str());
pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath);
delete [] sPath;
}
}
}
LRESULT CALLBACK HandleCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
RequestSaveOnExit();
PostQuitMessage(0);
break;
case ID_FILE_OPENDATADIRECTORY:
{
BROWSEINFO bInfo;
LPITEMIDLIST itemList;
LPMALLOC shMalloc;
wchar_t path[MAX_PATH];
memset(&bInfo, 0, sizeof(bInfo));
bInfo.hwndOwner = hWnd;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = path;
bInfo.lpszTitle = L"Select a localization data directory:";
bInfo.ulFlags = BIF_USENEWUI | BIF_VALIDATE | BIF_RETURNONLYFSDIRS | BIF_NONEWFOLDERBUTTON;
itemList = SHBrowseForFolder(&bInfo);
if (itemList != NULL)
{
plWaitCursor waitCursor;
SHGetPathFromIDList(itemList, path);
SHGetMalloc(&shMalloc);
shMalloc->Free(itemList);
shMalloc->Release();
pfLocalizationMgr::Shutdown();
char *sPath = hsWStringToString(path);
pfLocalizationMgr::Initialize(sPath);
delete [] sPath;
plLocTreeView::ClearTreeView(gTreeView);
plLocTreeView::FillTreeViewFromData(gTreeView, "");
gCurPath = path;
SetWindowTitle(hWnd, path);
HMENU menu = GetMenu(hWnd);
HMENU fileMenu = GetSubMenu(menu, FILE_MENU_POS);
EnableMenuItem(fileMenu, ID_FILE_SAVETOCUR, MF_ENABLED);
EnableMenuItem(fileMenu, ID_FILE_SAVETONEW, MF_ENABLED);
}
}
break;
case ID_FILE_SAVETOCUR:
{
SaveLocalizationText(); // make sure any changed text is saved to the manager
// save it to our current directory
int res = MessageBox(hWnd, L"Are you sure you want to save to the current directory? Current data will be overwritten!", L"Save to Current Directory", MB_ICONQUESTION | MB_YESNOCANCEL);
if (res == IDYES)
{
plWaitCursor waitCursor;
char *sPath = hsWStringToString(gCurPath.c_str());
pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath);
delete [] sPath;
}
else if (res == IDNO)
SendMessage(hWnd, WM_COMMAND, (WPARAM)ID_FILE_SAVETONEW, (LPARAM)0);
// and if it's cancel we don't do anything
}
break;
case ID_FILE_SAVETONEW:
{
SaveLocalizationText(); // make sure any changed text is saved to the manager
// save it to a new directory
BROWSEINFO bInfo;
LPITEMIDLIST itemList;
LPMALLOC shMalloc;
wchar_t path[MAX_PATH];
memset(&bInfo, 0, sizeof(bInfo));
bInfo.hwndOwner = hWnd;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = path;
bInfo.lpszTitle = L"Select a directory to save the localization data to:";
bInfo.ulFlags = BIF_EDITBOX;
itemList = SHBrowseForFolder(&bInfo);
if (itemList != NULL)
{
plWaitCursor waitCursor;
SHGetPathFromIDList(itemList, path);
SHGetMalloc(&shMalloc);
shMalloc->Free(itemList);
shMalloc->Release();
gCurPath = path;
SetWindowTitle(hWnd, path);
char *sPath = hsWStringToString(gCurPath.c_str());
pfLocalizationDataMgr::Instance().WriteDatabaseToDisk(sPath);
delete [] sPath;
}
}
break;
case ID_HELP_ABOUT:
DialogBox(gInstance, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDialogProc);
break;
}
return 0;
}
void SizeControls(HWND parent)
{
RECT clientRect, editRect;
GetClientRect(parent, &clientRect);
GetClientRect(gEditDlg, &editRect);
SetWindowPos(gTreeView, NULL, 0, 0, clientRect.right - editRect.right - 4, clientRect.bottom, 0);
OffsetRect(&editRect, clientRect.right - editRect.right, (clientRect.bottom >> 1) - (editRect.bottom >> 1));
SetWindowPos(gEditDlg, NULL, editRect.left, editRect.top, 0, 0, SWP_NOSIZE);
}
void InitWindowControls(HWND hWnd)
{
RECT clientRect;
GetClientRect(hWnd, &clientRect);
gTreeView = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, L"Tree View", WS_VISIBLE | WS_CHILD | WS_BORDER |
TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS,
0, 0, 0, 0, hWnd, (HMENU)IDC_REGTREEVIEW, gInstance, NULL);
gEditDlg = CreateDialog(gInstance, MAKEINTRESOURCE(IDD_EDITDLG), hWnd, EditDlgProc);
SizeControls(hWnd);
}
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
InitCommonControls();
InitWindowControls(hWnd);
break;
case WM_CLOSE:
RequestSaveOnExit();
DestroyWindow(hWnd);
break;
case WM_DESTROY:
RequestSaveOnExit();
plLocTreeView::ClearTreeView(gTreeView);
PostQuitMessage(0);
break;
case WM_SIZING:
case WM_SIZE:
SizeControls(hWnd);
break;
case WM_GETMINMAXINFO:
{
MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMinTrackSize.x = 800;
pmmi->ptMinTrackSize.y = 500;
return 0;
}
case WM_NOTIFY:
if(wParam == IDC_REGTREEVIEW)
{
SaveLocalizationText(); // save any current changes to the database
NMHDR *hdr = (NMHDR*)lParam;
if(hdr->code == TVN_SELCHANGED)
plLocTreeView::SelectionChanged(gTreeView);
else if(hdr->code == NM_DBLCLK)
plLocTreeView::SelectionDblClicked(gTreeView);
UpdateEditDlg(plLocTreeView::GetPath());
}
break;
case WM_COMMAND:
return HandleCommand(hWnd, wParam, lParam);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/* Enable themes in Windows XP and later */
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

133
Sources/Tools/plLocalizationEditor/res/AddElement.ui

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddElement</class>
<widget class="QDialog" name="AddElement">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>138</height>
</rect>
</property>
<property name="windowTitle">
<string>Add Element</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="fPathLabel"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Parent &amp;Age:</string>
</property>
<property name="buddy">
<cstring>fParentAge</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="fParentAge">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Parent &amp;Set:</string>
</property>
<property name="buddy">
<cstring>fParentSet</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="fParentSet">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>&amp;Element Name:</string>
</property>
<property name="buddy">
<cstring>fElementName</cstring>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="fElementName"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QDialogButtonBox" name="fButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>fButtons</sender>
<signal>accepted()</signal>
<receiver>AddElement</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>fButtons</sender>
<signal>rejected()</signal>
<receiver>AddElement</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

94
Sources/Tools/plLocalizationEditor/res/AddLocalization.ui

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddLocalization</class>
<widget class="QDialog" name="AddLocalization">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>86</height>
</rect>
</property>
<property name="windowTitle">
<string>Add Localization</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="fPathLabel"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Language</string>
</property>
<property name="buddy">
<cstring>fLanguage</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="fLanguage">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QDialogButtonBox" name="fButtons">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>fButtons</sender>
<signal>accepted()</signal>
<receiver>AddLocalization</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>fButtons</sender>
<signal>rejected()</signal>
<receiver>AddLocalization</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

181
Sources/Tools/plLocalizationEditor/res/EditDialog.ui

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditDialog</class>
<widget class="QMainWindow" name="EditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>500</height>
</rect>
</property>
<property name="windowTitle">
<string>plLocalizationEditor</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="plLocTreeView" name="fLocalizationTree">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Localization Tree</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="fAddButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fDeleteButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Localization Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="fTextPathLabel">
<property name="text">
<string>&amp;Text:</string>
</property>
<property name="buddy">
<cstring>fLocalizationText</cstring>
</property>
</widget>
</item>
<item>
<widget class="QPlainTextEdit" name="fLocalizationText"/>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="fOpenAction"/>
<addaction name="separator"/>
<addaction name="fSaveCurrentAction"/>
<addaction name="fSaveOtherAction"/>
<addaction name="separator"/>
<addaction name="fExitAction"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="fAboutAction"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menu_Help"/>
</widget>
<action name="fOpenAction">
<property name="text">
<string>&amp;Open Data Directory...</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="fSaveCurrentAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Save to Current Directory</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="fSaveOtherAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>S&amp;ave to Specified Directory...</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="fExitAction">
<property name="text">
<string>E&amp;xit</string>
</property>
</action>
<action name="fAboutAction">
<property name="text">
<string>&amp;About</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>plLocTreeView</class>
<extends>QTreeWidget</extends>
<header>plLocTreeView.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

5
Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>icon1.ico</file>
</qresource>
</RCC>

269
Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc

@ -1,268 +1 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON ICON "icon1.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_APPMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open Data Directory...\tCtrl+O",
ID_FILE_OPENDATADIRECTORY
MENUITEM SEPARATOR
MENUITEM "&Save to Current Directory\tCtrl+S", ID_FILE_SAVETOCUR
, GRAYED
MENUITEM "S&ave to Specified Directory...\tCtrl+Shift+S",
ID_FILE_SAVETONEW, GRAYED
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_FILE_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About ...", ID_HELP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUT DIALOGEX 0, 0, 275, 40
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "About plLocalizationEditor"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,221,6,50,14
ICON IDI_APPICON,IDC_STATIC,7,7,21,20
LTEXT "plLocalizationEditor\nA basic editor for Plasma 21 localization resource files\nCopyright (C) 2004 Cyan Worlds, Inc.",
IDC_STATIC,33,7,180,26
END
IDD_EDITDLG DIALOGEX 0, 0, 421, 280
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Add",IDC_ADD,72,20,138,14,WS_DISABLED
PUSHBUTTON "Delete",IDC_DELETE,216,20,132,14,WS_DISABLED
GROUPBOX "Localization Tree",IDC_STATIC,7,7,407,32
GROUPBOX "Localization Information",IDC_STATIC,7,45,407,228
LTEXT "Text:",IDC_LOCPATH,15,57,391,8
CONTROL "",IDC_LOCALIZATIONTEXT,"RichEdit20A",ES_MULTILINE |
ES_AUTOHSCROLL | WS_DISABLED | WS_BORDER | WS_VSCROLL |
WS_HSCROLL | WS_TABSTOP,15,71,391,194
END
IDD_ADDELEMENT DIALOGEX 0, 0, 186, 91
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Add Element"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
COMBOBOX IDC_PARENTAGE,57,19,122,51,CBS_DROPDOWN | CBS_SORT |
WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_PARENTSET,57,34,122,51,CBS_DROPDOWN | CBS_SORT |
WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_ELEMENTNAME,57,49,122,14,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,129,70,50,14
PUSHBUTTON "Cancel",IDCANCEL,73,70,50,14
LTEXT "Path:",IDC_PATH,7,7,172,8
LTEXT "Parent Age:",IDC_STATIC,7,22,48,8
LTEXT "Parent Set:",IDC_STATIC,7,37,38,8
LTEXT "Element Name:",IDC_STATIC,7,52,49,8
END
IDD_ADDLOCALIZATION DIALOGEX 0, 0, 186, 59
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Add Localization"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
COMBOBOX IDC_LANGUAGE,45,19,134,65,CBS_DROPDOWNLIST | CBS_SORT |
WS_VSCROLL | WS_TABSTOP
DEFPUSHBUTTON "OK",IDOK,129,38,50,14
PUSHBUTTON "Cancel",IDCANCEL,73,38,50,14
LTEXT "Path:",IDC_PATH,7,7,172,8
LTEXT "Language:",IDC_STATIC,7,21,35,8
END
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Cyan Worlds, Inc."
VALUE "FileDescription", "plLocalizationEditor"
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "InternalName", "plLocalizationEditor"
VALUE "LegalCopyright", "Copyright © 2004"
VALUE "OriginalFilename", "plLocalizationEditor.exe"
VALUE "ProductName", "Cyan Worlds Localization Editor"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_ABOUT, DIALOG
BEGIN
RIGHTMARGIN, 252
END
IDD_EDITDLG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 414
VERTGUIDE, 15
VERTGUIDE, 72
VERTGUIDE, 210
VERTGUIDE, 216
VERTGUIDE, 348
VERTGUIDE, 406
TOPMARGIN, 7
BOTTOMMARGIN, 273
HORZGUIDE, 71
HORZGUIDE, 265
END
IDD_ADDELEMENT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 84
END
IDD_ADDLOCALIZATION, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 52
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS
BEGIN
"O", ID_FILE_OPENDATADIRECTORY, VIRTKEY, CONTROL, NOINVERT
"S", ID_FILE_SAVETOCUR, VIRTKEY, CONTROL, NOINVERT
"S", ID_FILE_SAVETONEW, VIRTKEY, SHIFT, CONTROL,
NOINVERT
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
IDI_APPICON ICON DISCARDABLE "icon1.ico"

51
Sources/Tools/plLocalizationEditor/res/resource.h

@ -1,51 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by plLocalizationEditor.rc
//
#define IDC_MYICON 2
#define IDI_APPICON 102
#define IDD_PLLOCALIZATIONEDITOR_DIALOG 102
#define IDS_APP_TITLE 103
#define IDD_ABOUTBOX 103
#define IDI_PLLOCALIZATIONEDITOR 107
#define IDI_SMALL 108
#define IDC_PLLOCALIZATIONEDITOR 109
#define IDR_APPMENU 109
#define IDD_ADDELEMENT 113
#define IDD_ADDLOCALIZATION 114
#define IDR_MAINFRAME 128
#define IDD_ABOUT 129
#define IDR_ACCELERATOR1 130
#define IDD_EDITDLG 131
#define IDC_RICHEDIT21 1000
#define IDC_LOCALIZATIONTEXT 1002
#define IDC_APPLY 1014
#define IDC_DISCARD 1015
#define IDC_LOCPATH 1019
#define IDC_ADD 1020
#define IDC_DELETE 1021
#define IDC_PATH 1023
#define IDC_PARENTSET 1026
#define IDC_ELEMENTNAME 1027
#define IDC_PARENTAGE 1028
#define IDC_LANGUAGE 1028
#define ID_FILE_EXIT 32772
#define ID_HELP_ABOUT 32773
#define ID_FILE_OPENDATADIRECTORY 32774
#define ID_FILE_SAVETOSPECIFIEDDIRECTORY 32778
#define ID_FILE_SAVETOCURRENTDIRECTORY 32779
#define ID_FILE_SAVETOCUR 32782
#define ID_FILE_SAVETONEW 32783
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 132
#define _APS_NEXT_COMMAND_VALUE 32784
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif

85
Sources/Tools/plResBrowser/CMakeLists.txt

@ -8,64 +8,55 @@ include_directories("../../Plasma/PubUtilLib/inc")
include_directories("../../Plasma/PubUtilLib")
set(plResBrowser_HEADERS
plResTreeView.h
plWinRegistryTools.h
plResBrowser.h
plResTreeView.h
)
qt5_wrap_cpp(plResBrowser_MOC ${plResBrowser_HEADERS})
set(plResBrowser_SOURCES
plResBrowser.cpp
plResBrowserWndProc.cpp
plResTreeView.cpp
plWinRegistryTools.cpp
)
set(plResBrowser_RESOURCES
res/plResBrowser.rc
res/resource.h
plResBrowser.cpp
plResTreeView.cpp
)
if(WIN32)
set(plResBrowser_HEADERS ${plResBrowser_HEADERS}
plWinRegistryTools.h
)
set(plResBrowser_SOURCES ${plResBrowser_SOURCES}
res/plResBrowser.rc
plWinRegistryTools.cpp
)
endif()
set(plResBrowser_RCC_SOURCES
res/plResBrowser.qrc
)
qt5_add_resources(plResBrowser_RCC ${plResBrowser_RCC_SOURCES})
set(plResBrowser_UIC_SOURCES
res/FindDialog.ui
res/ResBrowser.ui
)
qt5_wrap_ui(plResBrowser_UIC ${plResBrowser_UIC_SOURCES})
res/dataicon.ico
res/icon1.ico
res/icon2.ico
res/indexico.ico
res/mergedda.ico
res/mergedin.ico
)
add_executable(plResBrowser WIN32 ${plResBrowser_SOURCES} ${plResBrowser_HEADERS} ${plResBrowser_RESOURCES})
# For generated ui_*.h files
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(plResBrowser WIN32 ${plResBrowser_SOURCES} ${plResBrowser_HEADERS}
${plResBrowser_RCC} ${plResBrowser_UIC} ${plResBrowser_MOC})
target_link_libraries(plResBrowser CoreLib)
target_link_libraries(plResBrowser plFile)
target_link_libraries(plResBrowser plMessage)
target_link_libraries(plResBrowser plResMgr)
target_link_libraries(plResBrowser plScene)
target_link_libraries(plResBrowser plStatusLog)
target_link_libraries(plResBrowser plUnifiedTime)
target_link_libraries(plResBrowser pnDispatch)
target_link_libraries(plResBrowser pnFactory)
target_link_libraries(plResBrowser pnKeyedObject)
target_link_libraries(plResBrowser pnMessage)
target_link_libraries(plResBrowser pnNetCommon)
target_link_libraries(plResBrowser pnNucleusInc)
target_link_libraries(plResBrowser pnSceneObject)
target_link_libraries(plResBrowser pnTimer)
target_link_libraries(plResBrowser pnUtils)
target_link_libraries(plResBrowser pnUUID)
if (WIN32)
target_link_libraries(plResBrowser rpcrt4)
target_link_libraries(plResBrowser version)
target_link_libraries(plResBrowser vfw32)
target_link_libraries(plResBrowser ws2_32)
target_link_libraries(plResBrowser winmm)
target_link_libraries(plResBrowser strmiids)
target_link_libraries(plResBrowser comctl32)
target_link_libraries(plResBrowser shlwapi)
endif(WIN32)
target_link_libraries(plResBrowser Qt5::Widgets)
if(USE_VLD)
target_link_libraries(plResBrowser ${VLD_LIBRARY})
endif()
source_group("Source Files" FILES ${plResBrowser_SOURCES})
source_group("Source Files" FILES ${plResBrowser_SOURCES} ${plResBrowser_MOC})
source_group("Header Files" FILES ${plResBrowser_HEADERS})
source_group("Resource Files" FILES ${plResBrowser_RESOURCES})
source_group("Resource Files" FILES ${plResBrowser_RCC_SOURCES} ${plResBrowser_RCC}
${plResBrowser_UIC_SOURCES} ${plResBrowser_UIC})

425
Sources/Tools/plResBrowser/plResBrowser.cpp

@ -39,12 +39,13 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
Mead, WA 99021
*==LICENSE==*/
#define CLASSNAME "plResBrowser" // Used in WinInit()
#define WINDOWNAME "plResBrowser"
#include "HeadSpin.h"
#include "hsWindows.h"
#include "res/resource.h"
#include "plResBrowser.h"
#include "ui_ResBrowser.h"
#if HS_BUILD_FOR_WIN32
# include "plWinRegistryTools.h"
#endif
#include "pnAllCreatables.h"
#include "plResMgr/plResMgrCreatable.h"
@ -53,81 +54,381 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plMessage/plResMgrHelperMsg.h"
REGISTER_CREATABLE(plResMgrHelperMsg);
#include "plResMgr/plRegistryHelpers.h"
#include "plResMgr/plRegistryNode.h"
#include "plResMgr/plPageInfo.h"
#include "pnKeyedObject/plUoid.h"
#include "pnKeyedObject/plKey.h"
#include "pnKeyedObject/plKeyImp.h"
#include <QApplication>
#include <QDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QDragEnterEvent>
#include <QMimeData>
#include <functional>
HINSTANCE gInstance;
char *gCommandLine = nil;
HWND gMainWindow = nil;
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"(plResBrowser
A simple Plasma 2.0 packfile browsing utility
Copyright (C) 2002 Cyan Worlds, Inc.
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );
BOOL WinInit( HINSTANCE hInst, int nCmdShow );
Who needs log files?)"), &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);
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
dlg.connect(ok, &QPushButton::clicked, &dlg, &QDialog::accept);
dlg.exec();
}
plResBrowser::plResBrowser()
: QMainWindow()
{
MSG msg;
HACCEL accelTable = LoadAccelerators( hInstance, MAKEINTRESOURCE( IDR_ACCELERATOR1 ) );
fUI = new Ui_ResBrowser;
fUI->setupUi(this);
setAcceptDrops(true);
plResMgrSettings::Get().SetFilterNewerPageVersions( false );
plResMgrSettings::Get().SetFilterOlderPageVersions( false );
// Use window background color for read-only text fields
// Note that we don't set them disabled, so you can still copy their contents
QPalette pal = fUI->fAgeName->palette();
pal.setColor(QPalette::Text, fUI->label->palette().color(QPalette::Text));
pal.setColor(QPalette::Base, fUI->label->palette().color(QPalette::Window));
fUI->fAgeName->setPalette(pal);
fUI->fPageName->setPalette(pal);
fUI->fLocation->setPalette(pal);
fUI->fDataVersion->setPalette(pal);
fUI->fChecksum->setPalette(pal);
fUI->fChecksumType->setPalette(pal);
fUI->fObjectName->setPalette(pal);
fUI->fObjectClass->setPalette(pal);
fUI->fStartPos->setPalette(pal);
fUI->fObjectSize->setPalette(pal);
gCommandLine = (char *)lpCmdLine;
plResManager *rMgr = new plResManager;
hsgResMgr::Init( rMgr );
connect(fUI->fOpenAction, SIGNAL(triggered()), SLOT(OpenFile()));
connect(fUI->fOpenDirectoryAction, SIGNAL(triggered()), SLOT(OpenDirectory()));
connect(fUI->fSaveSelectedAction, SIGNAL(triggered()), SLOT(SaveSelectedObject()));
connect(fUI->fFindAction, SIGNAL(triggered()), fUI->fTreeView, SLOT(FindObject()));
connect(fUI->fFindNextAction, SIGNAL(triggered()), fUI->fTreeView, SLOT(FindNextObject()));
connect(fUI->fShowOnlyLoadableAction, SIGNAL(triggered()), SLOT(RefreshTree()));
connect(fUI->fExitAction, SIGNAL(triggered()), SLOT(close()));
connect(fUI->fAboutAction, &QAction::triggered, std::bind(&IAboutDialog, this));
connect(fUI->fTreeView, &QTreeWidget::currentItemChanged,
std::bind(&plResBrowser::UpdateInfoPage, this));
connect(fUI->fHexValues, SIGNAL(clicked()), SLOT(UpdateInfoPage()));
connect(fUI->fFindButton, SIGNAL(clicked()), fUI->fTreeView, SLOT(FindObject()));
connect(fUI->fFindNextButton, SIGNAL(clicked()), fUI->fTreeView, SLOT(FindNextObject()));
connect(fUI->fSaveButton, SIGNAL(clicked()), SLOT(SaveSelectedObject()));
RegisterFileTypes();
plResMgrSettings::Get().SetLoadPagesOnInit(false);
QStringList args = qApp->arguments();
if (args.size() > 1)
{
plFileName path = args[1].toUtf8().constData();
if (path.GetFileExt() == "prp")
LoadPrpFile(args[1]);
}
}
plResBrowser::~plResBrowser()
{
delete fUI;
}
void plResBrowser::SetWindowTitle(const QString &title)
{
setWindowTitle(QString("plResBrowser%1").arg(title.isEmpty() ? "" : " - " + title));
}
void plResBrowser::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
}
void plResBrowser::dropEvent(QDropEvent *event)
{
QList<QUrl> urls = event->mimeData()->urls();
if (urls.size() == 0)
return;
fUI->fTreeView->clear();
hsgResMgr::Reset();
plResManager *mgr = static_cast<plResManager *>(hsgResMgr::ResMgr());
QString path = urls[0].toLocalFile();
if (urls.size() == 1 && urls[0].isLocalFile() && path.lastIndexOf('.') == -1)
{
// Must be a directory
std::vector<plFileName> prpFiles = plFileSystem::ListDir(path.toUtf8().constData(), "*.prp");
for (auto iter = prpFiles.begin(); iter != prpFiles.end(); ++iter)
mgr->AddSinglePage(*iter);
}
else
{
for (const QUrl &url : urls)
{
if (!url.isLocalFile())
continue;
plFileName fileName = url.toLocalFile().toUtf8().constData();
if (fileName.GetFileExt() == "prp")
{
mgr->AddSinglePage(fileName);
path = fileName.StripFileName().AsString().c_str();
}
}
}
fUI->fTreeView->LoadFromRegistry(fUI->fShowOnlyLoadableAction->isChecked());
SetWindowTitle(path);
}
void plResBrowser::OpenFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a file to browse"),
QString(), "Plasma 2 Pack Files (*.prp);;All files (*.*)");
if( !WinInit( hInstance, nCmdShow ) )
return -1;
if (!fileName.isEmpty())
LoadPrpFile(fileName);
}
while( GetMessage( &msg, NULL, 0, 0 ) )
void plResBrowser::OpenDirectory()
{
QString path = QFileDialog::getExistingDirectory(this,
tr("Select a Plasma 2 Data Directory:"),
QDir::current().absolutePath(),
QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly);
if (!path.isEmpty())
LoadResourcePath(path);
}
void plResBrowser::SaveSelectedObject()
{
plResTreeViewItem *item = static_cast<plResTreeViewItem *>(fUI->fTreeView->currentItem());
plKey itemKey = item ? item->GetKey() : nullptr;
if (!itemKey)
return;
QString fileName = QFileDialog::getSaveFileName(this, tr("Export object"),
QString("%1.bin").arg(itemKey->GetName().c_str()),
"Binary Files (*.bin);;All files (*.*)");
if (!fileName.isEmpty())
{
if( !TranslateAccelerator( gMainWindow, accelTable, &msg ) )
plKeyImp *keyImp = static_cast<plKeyImp *>(itemKey);
if (keyImp->GetDataLen() <= 0)
return;
plResManager *resMgr = static_cast<plResManager *>(hsgResMgr::ResMgr());
plRegistryPageNode *pageNode = resMgr->FindPage(keyImp->GetUoid().GetLocation());
hsStream *stream = pageNode->OpenStream();
if (!stream)
return;
uint8_t *buffer = new uint8_t[keyImp->GetDataLen()];
if (buffer)
{
TranslateMessage( &msg );
DispatchMessage( &msg );
stream->SetPosition(keyImp->GetStartPos());
stream->Read(keyImp->GetDataLen(), buffer);
}
if (!buffer)
return;
hsUNIXStream outStream;
outStream.Open(fileName.toUtf8().constData(), "wb");
outStream.Write(keyImp->GetDataLen(), buffer);
outStream.Close();
delete[] buffer;
}
}
hsgResMgr::Shutdown();
void plResBrowser::RefreshTree()
{
fUI->fTreeView->clear();
fUI->fTreeView->LoadFromRegistry(fUI->fShowOnlyLoadableAction->isChecked());
}
void plResBrowser::UpdateInfoPage()
{
const bool showAsHex = fUI->fHexValues->isChecked();
fUI->fObjectName->setText("");
fUI->fObjectClass->setText("");
fUI->fObjectSize->setText("");
fUI->fStartPos->setText("");
fUI->fSaveSelectedAction->setEnabled(false);
fUI->fSaveButton->setEnabled(false);
plResTreeViewItem *item = static_cast<plResTreeViewItem *>(fUI->fTreeView->currentItem());
if (item)
{
if (item->GetPage())
{
const plPageInfo &pageInfo = item->GetPage()->GetPageInfo();
fUI->fAgeName->setText(pageInfo.GetAge().c_str());
fUI->fPageName->setText(pageInfo.GetPage().c_str());
fUI->fLocation->setText(pageInfo.GetLocation().StringIze().c_str());
fUI->fReserved->setChecked((pageInfo.GetLocation().GetFlags() & plLocation::kReserved) != 0);
fUI->fBuiltIn->setChecked((pageInfo.GetLocation().GetFlags() & plLocation::kBuiltIn) != 0);
fUI->fVolatile->setChecked((pageInfo.GetLocation().GetFlags() & plLocation::kVolatile) != 0);
fUI->fLocalOnly->setChecked((pageInfo.GetLocation().GetFlags() & plLocation::kLocalOnly) != 0);
fUI->fDataVersion->setText(QString::number(pageInfo.GetMajorVersion()));
if (showAsHex)
fUI->fChecksum->setText(QString("0x%1").arg(pageInfo.GetChecksum(), 0, 16));
else
fUI->fChecksum->setText(QString::number(pageInfo.GetChecksum()));
fUI->fChecksumType->setText("Basic (file size)");
}
if (item->GetKey())
{
plKey key = item->GetKey();
fUI->fObjectName->setText(key->GetUoid().GetObjectName().c_str());
const char *cname = plFactory::GetNameOfClass(key->GetUoid().GetClassType());
fUI->fObjectClass->setText(QString("%1 (%2)").arg(cname ? cname : "<unknown>")
.arg(key->GetUoid().GetClassType()));
plKeyImp *imp = static_cast<plKeyImp *>(key);
if (showAsHex)
fUI->fStartPos->setText(QString("0x%1").arg(imp->GetStartPos(), 0, 16));
else
fUI->fStartPos->setText(QString::number(imp->GetStartPos()));
if (showAsHex)
{
fUI->fObjectSize->setText(QString("0x%1").arg(imp->GetDataLen(), 0, 16));
}
else
{
if (imp->GetDataLen() < 1024)
fUI->fObjectSize->setText(QString("%1 bytes").arg(imp->GetDataLen()));
else if (imp->GetDataLen() < 1024 * 1024)
fUI->fObjectSize->setText(QString("%1 kB").arg(imp->GetDataLen() / 1024.f, 0, 'f', 2));
else
fUI->fObjectSize->setText(QString("%1 MB").arg(imp->GetDataLen() / 1024.f / 1024.f, 0, 'f', 2));
}
fUI->fSaveSelectedAction->setEnabled(true);
fUI->fSaveButton->setEnabled(true);
}
}
}
void plResBrowser::RegisterFileTypes()
{
// Only meaningful on Windows currently... For Linux, consider creating
// a .desktop file as part of the make install process
#if HS_BUILD_FOR_WIN32
static bool sFileTypesRegistered = false;
if (sFileTypesRegistered)
return;
// Make sure our file types are created
QString path = QCoreApplication::applicationFilePath();
//plWinRegistryTools::AssociateFileType("PlasmaIdxFile", "Plasma 2 Index File", path, 1);
//plWinRegistryTools::AssociateFileType("PlasmaDatFile", "Plasma 2 Data File", path, 2);
//plWinRegistryTools::AssociateFileType("PlasmaPatchFile", "Plasma 2 Patch File", path, 3);
plWinRegistryTools::AssociateFileType("PlasmaPackFile", "Plasma 2 Packfile", path, 4);
return 0;
// Check our file extensions
QString prpAssoc = plWinRegistryTools::GetCurrentFileExtensionAssociation(".prp");
if (prpAssoc != "PlasmaPackFile")
{
int retn = QMessageBox::question(this, tr("plResBrowser File Type Association"),
tr("The Plasma 2 packed data file extension .prp is not currently associated "
"with plResBrowser. Would you like to associate it now?"));
if (retn == QMessageBox::Yes)
{
// Associate 'em
plWinRegistryTools::AssociateFileExtension(".prp", "PlasmaPackFile");
}
}
sFileTypesRegistered = true;
#endif
}
BOOL WinInit(HINSTANCE hInst, int nCmdShow)
void plResBrowser::LoadPrpFile(const QString &fileName)
{
gInstance = hInst;
// Fill out WNDCLASS info
WNDCLASS wndClass;
wndClass.style = 0; // CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInst;
wndClass.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_APPICON ) );
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetSysColorBrush( COLOR_3DFACE );
wndClass.lpszMenuName = MAKEINTRESOURCE( IDR_APPMENU );
wndClass.lpszClassName = CLASSNAME;
// can only run one at a time anyway, so just quit if another is running
if (!RegisterClass(&wndClass))
return FALSE;
DWORD dwStyle = WS_POPUP | WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE;
DWORD dwExStyle = WS_EX_ACCEPTFILES;
// Create a window
gMainWindow = CreateWindowEx(dwExStyle, CLASSNAME, WINDOWNAME,
dwStyle, 10, 10,
800,
600,
NULL, NULL, hInst, NULL);
return TRUE;
fUI->fTreeView->clear();
hsgResMgr::Reset();
// Load that source
plResManager *mgr = static_cast<plResManager *>(hsgResMgr::ResMgr());
mgr->AddSinglePage(fileName.toUtf8().constData());
fUI->fTreeView->LoadFromRegistry(fUI->fShowOnlyLoadableAction->isChecked());
SetWindowTitle(fileName);
}
/* Enable themes in Windows XP and later */
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
void plResBrowser::LoadResourcePath(const QString &path)
{
fUI->fTreeView->clear();
hsgResMgr::Reset();
// Load that source
plResManager *mgr = static_cast<plResManager *>(hsgResMgr::ResMgr());
std::vector<plFileName> prpFiles = plFileSystem::ListDir(path.toUtf8().constData(), "*.prp");
for (auto iter = prpFiles.begin(); iter != prpFiles.end(); ++iter)
mgr->AddSinglePage(*iter);
fUI->fTreeView->LoadFromRegistry(fUI->fShowOnlyLoadableAction->isChecked());
SetWindowTitle(path);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setApplicationName("plResBrowser");
app.setWindowIcon(QIcon(":/icon1.ico"));
plResMgrSettings::Get().SetFilterNewerPageVersions(false);
plResMgrSettings::Get().SetFilterOlderPageVersions(false);
plResManager *rMgr = new plResManager;
hsgResMgr::Init(rMgr);
int retn;
{
plResBrowser mainWindow;
mainWindow.show();
retn = app.exec();
}
hsgResMgr::Shutdown();
return retn;
}

76
Sources/Tools/plResBrowser/plResBrowser.h

@ -0,0 +1,76 @@
/*==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==*/
#ifndef _plResBrowser_h
#define _plResBrowser_h
#include <QMainWindow>
class plResBrowser : public QMainWindow
{
Q_OBJECT
public:
plResBrowser();
virtual ~plResBrowser();
void SetWindowTitle(const QString &title);
protected:
virtual void dragEnterEvent(QDragEnterEvent *event) override;
virtual void dropEvent(QDropEvent *event) override;
private slots:
void OpenFile();
void OpenDirectory();
void SaveSelectedObject();
void RefreshTree();
void UpdateInfoPage();
private:
class Ui_ResBrowser *fUI;
void RegisterFileTypes();
void LoadPrpFile(const QString &fileName);
void LoadResourcePath(const QString &path);
};
#endif

432
Sources/Tools/plResBrowser/plResBrowserWndProc.cpp

@ -1,432 +0,0 @@
/*==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 "HeadSpin.h"
#include "hsWindows.h"
#include "hsTemplates.h"
#include "res/resource.h"
#include <commdlg.h>
#include <commctrl.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <shlobj.h>
#include "plResTreeView.h"
#include "plResMgr/plResManager.h"
#include "plResMgr/plResMgrSettings.h"
#include "plWinRegistryTools.h"
#define IDC_REGTREEVIEW 1000
extern HINSTANCE gInstance;
extern char *gCommandLine;
HWND gTreeView;
HWND gInfoDlg;
class plWaitCursor
{
HCURSOR fOrig;
public:
plWaitCursor()
{
fOrig = ::SetCursor( ::LoadCursor( nil, IDC_WAIT ) );
}
~plWaitCursor()
{
::SetCursor( fOrig );
}
};
void SetWindowTitle( HWND hWnd, char *path )
{
char fun[ MAX_PATH + 50 ];
sprintf( fun, "plResBrowser%s%s", path != nil ? " - " : "", path != nil ? path : "" );
SetWindowText( hWnd, fun );
}
INT_PTR CALLBACK AboutDialogProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
if( msg == WM_COMMAND )
EndDialog( hWnd, 0 );
return 0;
}
LRESULT CALLBACK HandleCommand( HWND hWnd, WPARAM wParam, LPARAM lParam )
{
OPENFILENAME openInfo;
char fileName[ MAX_PATH ];
char path[ MAX_PATH ];
static bool filter = true;
switch( LOWORD( wParam ) )
{
case ID_FILE_EXIT:
PostQuitMessage( 0 );
break;
case ID_FILE_OPENDIRECTORY:
BROWSEINFO bInfo;
LPITEMIDLIST itemList;
LPMALLOC shMalloc;
memset( &bInfo, 0, sizeof( bInfo ) );
bInfo.hwndOwner = hWnd;
bInfo.pidlRoot = NULL;
bInfo.pszDisplayName = path;
bInfo.lpszTitle = "Select a Plasma 2 Data Directory:";
bInfo.ulFlags = BIF_EDITBOX;
itemList = SHBrowseForFolder( &bInfo );
if( itemList != NULL )
{
plWaitCursor myWaitCursor;
SHGetPathFromIDList( itemList, path );
SHGetMalloc( &shMalloc );
shMalloc->Free( itemList );
shMalloc->Release();
hsgResMgr::Reset();
plResTreeView::ClearTreeView( gTreeView );
// Load that source
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr();
std::vector<plFileName> prpFiles = plFileSystem::ListDir(path, "*.prp");
for (auto iter = prpFiles.begin(); iter != prpFiles.end(); ++iter)
mgr->AddSinglePage(*iter);
plResTreeView::FillTreeViewFromRegistry( gTreeView );
SetWindowTitle( hWnd, path );
}
break;
case ID_FILE_OPEN:
fileName[ 0 ] = 0;
memset( &openInfo, 0, sizeof( OPENFILENAME ) );
openInfo.hInstance = gInstance;
openInfo.hwndOwner = hWnd;
openInfo.lStructSize = sizeof( OPENFILENAME );
openInfo.lpstrFile = fileName;
openInfo.nMaxFile = sizeof( fileName );
openInfo.lpstrFilter = "Plasma 2 Pack Files\0*.prp\0All Files\0*.*\0";
openInfo.lpstrTitle = "Choose a file to browse:";
openInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if( GetOpenFileName( &openInfo ) )
{
plWaitCursor myWaitCursor;
hsgResMgr::Reset();
plResTreeView::ClearTreeView( gTreeView );
// Load that source
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr();
mgr->AddSinglePage(fileName);
plResTreeView::FillTreeViewFromRegistry( gTreeView );
SetWindowTitle( hWnd, fileName );
}
break;
case ID_FILE_ABOUT:
DialogBox( gInstance, MAKEINTRESOURCE( IDD_ABOUT ), hWnd, AboutDialogProc );
break;
case ID_FILE_FINDOBJECT:
plResTreeView::FindObject( gTreeView );
break;
case ID_FILE_FINDNEXT:
plResTreeView::FindNextObject( gTreeView );
break;
case ID_FILE_VERIFYPAGE:
plResTreeView::VerifyCurrentPage( gTreeView );
break;
case IDC_SHOWASHEX:
plResTreeView::UpdateInfoDlg( gTreeView );
break;
case ID_FILE_ONLYLOAD:
filter = !filter;
plResTreeView::FilterLoadables( filter, gTreeView );
{
HMENU menu = ::GetMenu( hWnd );
menu = ::GetSubMenu( menu, 0 );
::CheckMenuItem( menu, ID_FILE_ONLYLOAD, MF_BYCOMMAND | ( filter ? MF_CHECKED : MF_UNCHECKED ) );
}
break;
case ID_FILE_SAVESELECTED:
plResTreeView::SaveSelectedObject(gTreeView);
break;
default:
return DefWindowProc( hWnd, WM_COMMAND, wParam, lParam );
}
return 0;
}
void SizeControls( HWND parent )
{
RECT clientRect, infoRect;
GetClientRect( parent, &clientRect );
GetClientRect( gInfoDlg, &infoRect );
SetWindowPos( gTreeView, NULL, 0, 0, clientRect.right - infoRect.right - 4, clientRect.bottom, 0 );
OffsetRect( &infoRect, clientRect.right - infoRect.right, ( clientRect.bottom >> 1 ) - ( infoRect.bottom >> 1 ) );
SetWindowPos( gInfoDlg, NULL, infoRect.left, infoRect.top, 0, 0, SWP_NOSIZE );
}
void InitWindowControls( HWND hWnd )
{
RECT clientRect;
GetClientRect( hWnd, &clientRect );
gTreeView = CreateWindowEx( WS_EX_CLIENTEDGE, WC_TREEVIEW, "Tree View", WS_VISIBLE | WS_CHILD | WS_BORDER |
TVS_HASLINES | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_SHOWSELALWAYS,
0, 0, 0, 0,
hWnd, (HMENU)IDC_REGTREEVIEW, gInstance, NULL );
gInfoDlg = CreateDialog( gInstance, MAKEINTRESOURCE( IDD_INFODLG ), hWnd, plResTreeView::InfoDlgProc );
SizeControls( hWnd );
}
static bool sFileTypesRegistered = false;
void RegisterFileTypes( HWND mainWnd )
{
if( sFileTypesRegistered )
return;
// Make sure our file types are created
char path[ MAX_PATH ];
if( ::GetModuleFileName( nil, path, sizeof( path ) ) == 0 )
return;
//plWinRegistryTools::AssociateFileType( "PlasmaIdxFile", "Plasma 2 Index File", path, 1 );
//plWinRegistryTools::AssociateFileType( "PlasmaDatFile", "Plasma 2 Data File", path, 2 );
//plWinRegistryTools::AssociateFileType( "PlasmaPatchFile", "Plasma 2 Patch File", path, 3 );
plWinRegistryTools::AssociateFileType( "PlasmaPackFile", "Plasma 2 Packfile", path, 4 );
// Check our file extensions
char prpAssoc[ 512 ];
bool needToRegister = true;
if( plWinRegistryTools::GetCurrentFileExtensionAssociation( ".prp", prpAssoc, sizeof( prpAssoc ) ) )
{
if( strcmp( prpAssoc, "PlasmaPackFile" ) == 0 )
needToRegister = false;
}
if( needToRegister )
{
if( MessageBox( nil, "The Plasma 2 packed data file extension .prp is not currently associated with "
"plResBrowser. Would you like to associate it now?", "plResBrowser File Type Association",
MB_YESNO | MB_ICONQUESTION) == IDYES )
{
// Associate 'em
plWinRegistryTools::AssociateFileExtension( ".prp", "PlasmaPackFile" );
}
}
sFileTypesRegistered = true;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_CREATE:
InitCommonControls();
InitWindowControls( hWnd );
RegisterFileTypes( hWnd );
plResMgrSettings::Get().SetLoadPagesOnInit(false);
{
plResTreeView::FilterLoadables( true, gTreeView );
HMENU menu = ::GetMenu( hWnd );
menu = ::GetSubMenu( menu, 0 );
::CheckMenuItem( menu, ID_FILE_ONLYLOAD, MF_BYCOMMAND | MF_CHECKED );
}
if( gCommandLine != nil )
{
plWaitCursor myWaitCursor;
char path[ MAX_PATH ];
if( gCommandLine[ 0 ] == '"' )
{
strcpy( path, gCommandLine + 1 );
char *c = strchr( path, '"' );
if( c != nil )
*c = 0;
}
else
strcpy( path, gCommandLine );
if( stricmp( PathFindExtension( path ), ".prp" ) == 0 )
{
hsgResMgr::Reset();
plResTreeView::ClearTreeView( gTreeView );
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr();
mgr->AddSinglePage(path);
plResTreeView::FillTreeViewFromRegistry( gTreeView );
SetWindowTitle( hWnd, path );
}
}
break;
case WM_CLOSE:
DestroyWindow( hWnd );
break;
case WM_DESTROY:
plResTreeView::ClearTreeView( gTreeView );
PostQuitMessage(0);
break;
case WM_SIZING:
case WM_SIZE:
SizeControls( hWnd );
break;
case WM_NOTIFY:
if( wParam == IDC_REGTREEVIEW )
{
NMHDR *hdr = (NMHDR *)lParam;
if( hdr->code == TVN_SELCHANGED )
{
plResTreeView::UpdateInfoDlg( gTreeView );
//NMTREEVIEW *tv = (NMTREEVIEW *)hdr;
}
else if( hdr->code == NM_DBLCLK )
{
plResTreeView::SelectionDblClicked( gTreeView );
}
}
break;
case WM_DROPFILES:
{
int i, j, fileCount = DragQueryFile( (HDROP)wParam, -1, nil, 0 );
char path[ MAX_PATH ];
plWaitCursor myWaitCursor;
hsgResMgr::Reset();
plResTreeView::ClearTreeView( gTreeView );
plResManager *mgr = (plResManager *)hsgResMgr::ResMgr();
if( fileCount == 1 && DragQueryFile( (HDROP)wParam, 0, path, sizeof( path ) ) > 0 &&
( (char *)PathFindExtension( path ) )[ 0 ] == 0 )
{
// Must be a directory
std::vector<plFileName> prpFiles = plFileSystem::ListDir(path, "*.prp");
for (auto iter = prpFiles.begin(); iter != prpFiles.end(); ++iter)
mgr->AddSinglePage(*iter);
}
else
{
hsTArray<char *> filesAdded;
filesAdded.Reset();
for( i = 0; i < fileCount; i++ )
{
if( DragQueryFile( (HDROP)wParam, i, path, sizeof( path ) ) > 0 )
{
// Check for duplicates
for( j = 0; j < filesAdded.GetCount(); j++ )
{
if( stricmp( filesAdded[ j ], path ) == 0 )
break;
}
if( j < filesAdded.GetCount() )
continue;
if( stricmp( PathFindExtension( path ), ".prp" ) == 0 )
{
mgr->AddSinglePage(path);
filesAdded.Append( hsStrcpy( path ) );
}
}
}
for( j = 0; j < filesAdded.GetCount(); j++ )
delete [] filesAdded[ j ];
}
plResTreeView::FillTreeViewFromRegistry( gTreeView );
PathRemoveFileSpec( path );
SetWindowTitle( hWnd, path );
}
break;
case WM_COMMAND:
return HandleCommand( hWnd, wParam, lParam );
}
return DefWindowProc( hWnd, message, wParam, lParam );
}

497
Sources/Tools/plResBrowser/plResTreeView.cpp

@ -40,9 +40,9 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
*==LICENSE==*/
#include "HeadSpin.h"
#include "hsWindows.h"
#include "plResTreeView.h"
#include "ui_FindDialog.h"
#include "plResMgr/plResManager.h"
#include "plResMgr/plRegistryHelpers.h"
@ -53,470 +53,141 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "pnKeyedObject/plKeyImp.h"
#include "pnFactory/plFactory.h"
#include <commctrl.h>
#include <shlwapi.h>
#include "res/resource.h"
extern HINSTANCE gInstance;
HWND plResTreeView::fInfoDlg = nil;
bool plResTreeView::fFilter = false;
static char gSearchString[ 512 ];
static HTREEITEM fFoundItem = nil;
extern void ViewPatchDetails( plKey &patchKey );
INT_PTR CALLBACK FindDialogProc( HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_INITDIALOG:
return true;
case WM_COMMAND:
if( LOWORD( wParam ) == IDOK )
{
GetDlgItemText( dlg, IDC_SEARCHSTRING, gSearchString, sizeof( gSearchString ) );
fFoundItem = nil;
EndDialog( dlg, IDOK );
}
else if( LOWORD( wParam ) == IDCANCEL )
EndDialog( dlg, IDCANCEL );
return -1;
}
return 0;
}
#include <QDialog>
#include <QLayout>
#include <QMessageBox>
struct plKeyInfo
{
plKey fKey;
plRegistryPageNode *fPage;
plKeyInfo( plKey k, plRegistryPageNode *p ) : fKey( k ), fPage( p ) {}
};
// How's this for functionality?
class plResDlgLoader : public plRegistryPageIterator, public plRegistryKeyIterator
{
protected:
HWND fTree;
HTREEITEM fCurrItem, fCurrTypeItem;
uint16_t fCurrType;
bool fFilter;
plRegistryPageNode *fCurrPage;
HTREEITEM AddLeaf(HWND hTree, HTREEITEM hParent, const char *text, plKeyInfo *info )
{
TVITEM tvi = {0};
tvi.mask = TVIF_TEXT | TVIF_PARAM;
tvi.pszText = text ? (char*)text : (char*)"<NULL>";
tvi.cchTextMax = text ? strlen(text) : 7;
tvi.lParam = (LPARAM)info;
TVINSERTSTRUCT tvins = {0};
tvins.item = tvi;
tvins.hParent = hParent;
tvins.hInsertAfter = TVI_SORT;
return TreeView_InsertItem(hTree, &tvins);
}
public:
plResDlgLoader( HWND hTree, bool filter )
{
fFilter = filter;
fTree = hTree;
((plResManager *)hsgResMgr::ResMgr())->IterateAllPages( this );
}
virtual bool EatPage( plRegistryPageNode *page )
{
char str[ 512 ];
fCurrPage = page;
const plPageInfo &info = page->GetPageInfo();
sprintf( str, "%s->%s", info.GetAge().c_str(), info.GetPage().c_str());
fCurrItem = AddLeaf( fTree, NULL, str, new plKeyInfo( nil, fCurrPage ) );
fCurrType = (uint16_t)-1;
page->LoadKeys();
page->IterateKeys( this );
return true;
}
virtual bool EatKey( const plKey& key )
{
if( fCurrType != key->GetUoid().GetClassType() )
{
fCurrType = key->GetUoid().GetClassType();
const char *className = plFactory::GetNameOfClass( fCurrType );
fCurrTypeItem = AddLeaf( fTree, fCurrItem, className != nil ? className : "<unknown>", nil );
}
if( !fFilter )
AddLeaf( fTree, fCurrTypeItem, key->GetUoid().GetObjectName().c_str(), new plKeyInfo( key, fCurrPage ) );
return true;
}
plRegistryPageNode *fPage;
};
void plResTreeView::FillTreeViewFromRegistry( HWND hWnd )
plResTreeViewItem::~plResTreeViewItem()
{
plResDlgLoader loader( hWnd, fFilter );
delete fData;
}
HTREEITEM IGetNextTreeItem( HWND tree, HTREEITEM item )
plKey plResTreeViewItem::GetKey() const
{
// First try child items of this one
HTREEITEM next = TreeView_GetChild( tree, item );
if( next == nil )
// If no child items, try next sibling
next = TreeView_GetNextSibling( tree, item );
if( next == nil )
{
// If no siblings, go up to the parent and keep searching until we find a parent with a sibling
next = item;
while( true )
{
next = TreeView_GetParent( tree, next );
if( next == nil )
{
// No parent; not found, so stop
break;
}
else if( TreeView_GetNextSibling( tree, next ) != nil )
{
next = TreeView_GetNextSibling( tree, next );
break;
}
}
}
return next;
return fData ? fData->fKey : nullptr;
}
void plResTreeView::FindNextObject( HWND tree )
plRegistryPageNode *plResTreeViewItem::GetPage() const
{
if( fFoundItem == nil )
FindObject( tree );
else
{
fFoundItem = IGetNextTreeItem( tree, fFoundItem );
IFindNextObject( tree );
}
return fData ? fData->fPage : nullptr;
}
void plResTreeView::FindObject( HWND tree )
// How's this for functionality?
class plResDlgLoader : public plRegistryPageIterator, public plRegistryKeyIterator
{
if( DialogBox( gInstance, MAKEINTRESOURCE( IDD_FINDOBJ ), tree, FindDialogProc ) == IDOK )
protected:
plResTreeView *fTree;
plResTreeViewItem *fCurrItem;
plResTreeViewItem *fCurrTypeItem;
uint16_t fCurrType;
bool fFilter;
plRegistryPageNode *fCurrPage;
public:
plResDlgLoader(plResTreeView *tree, bool filter)
: fFilter(filter), fTree(tree)
{
fFoundItem = TreeView_GetRoot( tree );
IFindNextObject( tree );
static_cast<plResManager *>(hsgResMgr::ResMgr())->IterateAllPages(this);
}
}
void plResTreeView::IFindNextObject( HWND tree )
{
while( fFoundItem != nil )
virtual bool EatPage(plRegistryPageNode *page)
{
// Get the item
TVITEM itemInfo;
itemInfo.mask = TVIF_PARAM | TVIF_HANDLE;
itemInfo.hItem = fFoundItem;
TreeView_GetItem( tree, &itemInfo );
plKeyInfo *keyInfo = (plKeyInfo *)itemInfo.lParam;
if( keyInfo != nil && keyInfo->fKey != nil )
{
if( keyInfo->fKey->GetUoid().GetObjectName().Compare( gSearchString, plString::kCaseInsensitive ) >= 0 )
{
/// FOUND
TreeView_SelectItem( tree, fFoundItem );
return;
}
}
// Keep searching. First try child items of this one
fFoundItem = IGetNextTreeItem( tree, fFoundItem );
fCurrPage = page;
const plPageInfo &info = page->GetPageInfo();
QString name = QString("%1->%2").arg(info.GetAge().c_str()).arg(info.GetPage().c_str());
fCurrItem = new plResTreeViewItem(fTree, name, new plKeyInfo { nullptr, fCurrPage });
fCurrType = static_cast<uint16_t>(-1);
page->LoadKeys();
page->IterateKeys(this);
return true;
}
MessageBox( tree, "No objects found", "Find Object", MB_OK );
}
void IDeleteRecurse( HWND tree, HTREEITEM item )
{
while( item != nil )
virtual bool EatKey(const plKey &key)
{
HTREEITEM child = TreeView_GetChild( tree, item );
if( child != nil )
IDeleteRecurse( tree, child );
TVITEM itemInfo;
itemInfo.mask = TVIF_PARAM | TVIF_HANDLE;
itemInfo.hItem = item;
TreeView_GetItem( tree, &itemInfo );
plKeyInfo *keyInfo = (plKeyInfo *)itemInfo.lParam;
if( keyInfo != nil )
if (fCurrType != key->GetUoid().GetClassType())
{
delete keyInfo;
itemInfo.lParam = 0;
TreeView_SetItem( tree, &itemInfo );
fCurrType = key->GetUoid().GetClassType();
const char *className = plFactory::GetNameOfClass(fCurrType);
fCurrTypeItem = new plResTreeViewItem(fCurrItem, className ? className : "<unknown>", nullptr);
}
item = TreeView_GetNextSibling( tree, item );
if (!fFilter) {
new plResTreeViewItem(fCurrTypeItem, key->GetUoid().GetObjectName().c_str(),
new plKeyInfo { key, fCurrPage });
}
return true;
}
}
};
void plResTreeView::ClearTreeView( HWND hWnd )
void plResTreeView::LoadFromRegistry(bool filter)
{
HTREEITEM root = TreeView_GetRoot( hWnd );
if( root != nil )
IDeleteRecurse( hWnd, root );
TreeView_DeleteAllItems( hWnd );
plResDlgLoader loader(this, filter);
sortItems(0, Qt::AscendingOrder);
}
void plResTreeView::SelectionDblClicked( HWND treeCtrl )
static QTreeWidgetItem *IGetNextTreeItem(QTreeWidgetItem *item)
{
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
}
}
if (!item)
return nullptr;
void plResTreeView::FilterLoadables( bool filter, HWND treeCtrl )
{
fFilter = filter;
ClearTreeView( treeCtrl );
FillTreeViewFromRegistry( treeCtrl );
QTreeWidgetItemIterator iter(item);
return *(++iter);
}
INT_PTR CALLBACK plResTreeView::InfoDlgProc( HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam )
void plResTreeView::FindObject()
{
switch( msg )
{
case WM_INITDIALOG:
fInfoDlg = dlg;
break;
case WM_COMMAND:
return SendMessage( GetParent( dlg ), msg, wParam, lParam );
}
QDialog findDialog(this);
Ui_FindDialog ui;
ui.setupUi(&findDialog);
return 0;
}
findDialog.layout()->setSizeConstraint(QLayout::SetFixedSize);
void plResTreeView::VerifyCurrentPage( HWND treeCtrl )
{
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
if (findDialog.exec() == QDialog::Accepted)
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
plKeyInfo *info = (plKeyInfo *)item.lParam;
if( info != nil )
{
if( info->fPage != nil )
{
// TODO: FIXME
/*
/// HACK. Live with it
class plHackResManager : public plResManager
{
public:
plRegistry *GetRegistry( void ) { return IGetRegistry(); }
};
plRegistry *registry = ((plHackResManager *)hsgResMgr::ResMgr())->GetRegistry();
plRegistry::plPageCond result = registry->VerifyOnePage( info->fPage );
char msg[ 512 ];
if( result == plRegistry::kOK || result == plRegistry::kTooNew )
strcpy( msg, "Page verifies OK" );
else if( result == plRegistry::kChecksumInvalid )
strcpy( msg, "Checksums for page are invalid" );
else if( result == plRegistry::kOutOfDate )
strcpy( msg, "Page is older than the current data version" );
hsMessageBox( msg, "Verification Results", hsMessageBoxNormal );
*/
}
}
fFoundItem = invisibleRootItem();
fSearchString = ui.fObjectName->text().toUtf8().constData();
IFindNextObject();
}
}
void plResTreeView::UpdateInfoDlg( HWND treeCtrl )
void plResTreeView::FindNextObject()
{
bool showAsHex = (bool)IsDlgButtonChecked( fInfoDlg, IDC_SHOWASHEX );
SetDlgItemText( fInfoDlg, IDC_NAME, "" );
SetDlgItemText( fInfoDlg, IDC_CLASS, "" );
SetDlgItemText( fInfoDlg, IDC_LENGTH, "" );
SetDlgItemText( fInfoDlg, IDC_STARTPOS, "" );
EnableWindow( GetDlgItem( fInfoDlg, ID_FILE_VERIFYPAGE ), FALSE );
HTREEITEM sel = TreeView_GetSelection( treeCtrl );
if( sel != nil )
if (!fFoundItem)
FindObject();
else
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if( !TreeView_GetItem( treeCtrl, &item ) )
return;
plKeyInfo *info = (plKeyInfo *)item.lParam;
if( info != nil )
{
if( info->fPage != nil )
{
const plPageInfo &pageInfo = info->fPage->GetPageInfo();
char tempStr[ 32 ];
SetDlgItemText( fInfoDlg, IDC_AGE, pageInfo.GetAge().c_str());
SetDlgItemText( fInfoDlg, IDC_PAGE, pageInfo.GetPage().c_str());
SetDlgItemText( fInfoDlg, IDC_LOCATION, pageInfo.GetLocation().StringIze().c_str() );
CheckDlgButton(fInfoDlg, IDC_RESERVED, (pageInfo.GetLocation().GetFlags() & plLocation::kReserved) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_BUILTIN, (pageInfo.GetLocation().GetFlags() & plLocation::kBuiltIn) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_VOLATILE, (pageInfo.GetLocation().GetFlags() & plLocation::kVolatile) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(fInfoDlg, IDC_LOCAL_ONLY, (pageInfo.GetLocation().GetFlags() & plLocation::kLocalOnly) ? BST_CHECKED : BST_UNCHECKED);
sprintf( tempStr, "%d", pageInfo.GetMajorVersion());
SetDlgItemText( fInfoDlg, IDC_DATAVERSION, tempStr );
SetDlgItemText( fInfoDlg, IDC_CHECKSUMTYPE, "Basic (file size)" );
EnableWindow( GetDlgItem( fInfoDlg, ID_FILE_VERIFYPAGE ), TRUE );
}
if( info->fKey != nil )
{
char str[ 128 ];
SetDlgItemText( fInfoDlg, IDC_NAME, info->fKey->GetUoid().GetObjectName().c_str() );
const char *name = plFactory::GetNameOfClass( info->fKey->GetUoid().GetClassType() );
sprintf( str, "%s (%d)", name != nil ? name : "<unknown>", info->fKey->GetUoid().GetClassType() );
SetDlgItemText( fInfoDlg, IDC_CLASS, str );
plKeyImp *imp = (plKeyImp *)info->fKey;
EnableWindow( GetDlgItem( fInfoDlg, IDC_STARTPOS_LABEL ), true );
EnableWindow( GetDlgItem( fInfoDlg, IDC_SIZE_LABEL ), true );
if( showAsHex )
sprintf( str, "0x%X", imp->GetStartPos() );
else
sprintf( str, "%d", imp->GetStartPos() );
SetDlgItemText( fInfoDlg, IDC_STARTPOS, str );
if( imp->GetDataLen() < 1024 )
sprintf( str, "%d bytes", imp->GetDataLen() );
else if( imp->GetDataLen() < 1024 * 1024 )
sprintf( str, "%4.2f kB", imp->GetDataLen() / 1024.f );
else
sprintf( str, "%4.2f MB", imp->GetDataLen() / 1024.f / 1024.f );
SetDlgItemText( fInfoDlg, IDC_LENGTH, str );
}
}
fFoundItem = IGetNextTreeItem(fFoundItem);
IFindNextObject();
}
}
#include "hsStream.h"
#include <commdlg.h>
void plResTreeView::SaveSelectedObject(HWND treeCtrl)
void plResTreeView::IFindNextObject()
{
// TODO: FIXME
/*
plKey itemKey = nil;
HTREEITEM sel = TreeView_GetSelection(treeCtrl);
if (sel != nil)
while (fFoundItem)
{
TVITEM item;
item.mask = TVIF_PARAM | TVIF_HANDLE;
item.hItem = sel;
if (TreeView_GetItem(treeCtrl, &item))
// Get the item
plKey key = fFoundItem->type() == plResTreeViewItem::Type
? static_cast<plResTreeViewItem *>(fFoundItem)->GetKey()
: nullptr;
if (key && key->GetUoid().GetObjectName().Find(fSearchString, plString::kCaseInsensitive) >= 0)
{
plKeyInfo *info = (plKeyInfo*)item.lParam;
if (info != nil)
itemKey = info->fKey;
}
}
if (!itemKey)
return;
char fileName[MAX_PATH];
sprintf(fileName, "%s.bin", itemKey->GetName());
OPENFILENAME openInfo;
memset( &openInfo, 0, sizeof( OPENFILENAME ) );
// openInfo.hInstance = gInstance;
// openInfo.hwndOwner = hWnd;
openInfo.lStructSize = sizeof( OPENFILENAME );
openInfo.lpstrFile = fileName;
openInfo.nMaxFile = sizeof( fileName );
openInfo.lpstrFilter = "Binary Files\0*.bin\0All Files\0*.*\0";
// openInfo.lpstrTitle = "Choose a pack index file to browse:";
// openInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
if (GetSaveFileName(&openInfo))
{
plKeyImp* keyImp = (plKeyImp*)itemKey;
if (keyImp->GetDataLen() <= 0)
/// FOUND
setCurrentItem(fFoundItem);
return;
plResManager* resMgr = (plResManager*)hsgResMgr::ResMgr();
const plPageInfo& pageInfo = resMgr->FindPage(keyImp->GetUoid().GetLocation())->GetPageInfo();
plRegistryDataStream *stream = registry->OpenPageDataStream( keyImp->GetUoid().GetLocation(), false );
if( stream == nil )
return;
hsStream *dataStream = stream->GetStream();
uint8_t *buffer = new uint8_t[ keyImp->GetDataLen() ];
if( buffer != nil )
{
dataStream->SetPosition( keyImp->GetStartPos() );
dataStream->Read( keyImp->GetDataLen(), buffer );
}
delete stream;
if( buffer == nil )
return;
hsUNIXStream outStream;
outStream.Open(fileName, "wb");
outStream.Write(keyImp->GetDataLen(), buffer);
outStream.Close();
delete [] buffer;
// Keep searching. First try child items of this one
fFoundItem = IGetNextTreeItem(fFoundItem);
}
*/
}
QMessageBox::critical(this, tr("Find Objects"), tr("No objects found"));
}

51
Sources/Tools/plResBrowser/plResTreeView.h

@ -42,34 +42,53 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef _plResTreeView_h
#define _plResTreeView_h
class plResTreeView
#include "plString.h"
#include <QTreeWidget>
struct plKeyInfo;
class plKey;
class plRegistryPageNode;
class plResTreeViewItem : public QTreeWidgetItem
{
protected:
public:
enum { Type = UserType };
static HWND fInfoDlg;
static bool fFilter;
plResTreeViewItem(QTreeWidget *parent, const QString &text, plKeyInfo *key)
: QTreeWidgetItem(parent, QStringList { text }, Type), fData(key) { }
plResTreeViewItem(QTreeWidgetItem *parent, const QString &text, plKeyInfo *key)
: QTreeWidgetItem(parent, QStringList { text }, Type), fData(key) { }
static void IFindNextObject( HWND tree );
virtual ~plResTreeViewItem();
public:
plKey GetKey() const;
plRegistryPageNode *GetPage() const;
static void FindObject( HWND tree );
static void FindNextObject( HWND tree );
private:
plKeyInfo *fData;
};
static void FillTreeViewFromRegistry( HWND hWnd );
static void ClearTreeView( HWND hWnd );
static INT_PTR CALLBACK InfoDlgProc( HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam );
class plResTreeView : public QTreeWidget
{
Q_OBJECT
static void UpdateInfoDlg( HWND treeCtrl );
public:
plResTreeView(QWidget *parent = nullptr)
: QTreeWidget(parent), fFoundItem(nullptr) { }
static void VerifyCurrentPage( HWND treeCtrl );
void LoadFromRegistry(bool filter);
static void SelectionDblClicked( HWND treeCtrl );
public slots:
void FindObject();
void FindNextObject();
static void FilterLoadables( bool filter, HWND treeCtrl );
private:
QTreeWidgetItem *fFoundItem;
plString fSearchString;
static void SaveSelectedObject(HWND treeCtrl);
void IFindNextObject();
};
#endif //_plResTreeView_h

73
Sources/Tools/plResBrowser/plWinRegistryTools.cpp

@ -52,6 +52,8 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "hsWindows.h"
#include "plWinRegistryTools.h"
#include <QString>
#include <string>
//////////////////////////////////////////////////////////////////////////////
@ -62,27 +64,31 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
// Sets the given registry key to the given string value. If valueName = nil,
// sets the (default) value
static bool ISetRegKey( const char *keyName, const char *value, const char *valueName = nil )
static bool ISetRegKey(const QString &keyName, const QString &value, const QString &valueName = QString())
{
HKEY regKey;
DWORD result;
// Create the key (just opens if it already exists)
if( ::RegCreateKeyEx( HKEY_CLASSES_ROOT, keyName, 0, nil, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
nil, &regKey, &result ) != ERROR_SUCCESS )
if (::RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName.toStdWString().c_str(), 0,
nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
nullptr, &regKey, &result) != ERROR_SUCCESS)
{
hsStatusMessageF( "Warning: Registry database open failed for key '%s'.\n", keyName );
hsStatusMessageF("Warning: Registry database open failed for key '%s'.\n", qPrintable(keyName));
return false;
}
// Assign the "default" subkey value
LONG lResult = ::RegSetValueEx( regKey, valueName, 0, REG_SZ, (const BYTE *)value, ( lstrlen( value ) + 1 ) * sizeof( TCHAR ) );
std::wstring wValue = value.toStdWString();
LONG lResult = ::RegSetValueExW(regKey, valueName.toStdWString().c_str(), 0,
REG_SZ, reinterpret_cast<const BYTE *>(wValue.c_str()),
(wValue.size() + 1) * sizeof(wchar_t));
if( ::RegCloseKey( regKey ) == ERROR_SUCCESS && lResult == ERROR_SUCCESS )
if (::RegCloseKey(regKey) == ERROR_SUCCESS && lResult == ERROR_SUCCESS)
return true;
hsStatusMessageF( "Warning: Registry database update failed for key '%s'.\n", keyName );
hsStatusMessageF("Warning: Registry database update failed for key '%s'.\n", qPrintable(keyName));
return false;
}
@ -108,28 +114,26 @@ static bool ISetRegKey( const char *keyName, const char *value, const char *
// |--- command (value = command line)
//
bool plWinRegistryTools::AssociateFileType( const char *fileTypeID, const char *fileTypeName, const char *appPath, int iconIndex )
bool plWinRegistryTools::AssociateFileType(const QString &fileTypeID, const QString &fileTypeName,
const QString &appPath, int iconIndex)
{
char keyName[ 512 ], keyValue[ 512 ];
// Root key
if( !ISetRegKey( fileTypeID, fileTypeName ) )
if (!ISetRegKey(fileTypeID, fileTypeName))
return false;
// DefaultIcon key, if we want one
if( iconIndex != -1 )
if (iconIndex != -1)
{
sprintf( keyName, "%s\\DefaultIcon", fileTypeID );
sprintf( keyValue, "%s,%d", appPath, iconIndex );
if( !ISetRegKey( keyName, keyValue ) )
QString keyName = QString(R"(%1\DefaultIcon)").arg(fileTypeID);
QString keyValue = QString("%1,%2").arg(appPath).arg(iconIndex);
if (!ISetRegKey(keyName, keyValue))
return false;
}
// shell/open/command key
sprintf( keyName, "%s\\shell\\open\\command", fileTypeID );
sprintf( keyValue, "\"%s\" \"%%1\"", appPath );
if( !ISetRegKey( keyName, keyValue ) )
QString keyName = QString(R"(%1\shell\open\command)").arg(fileTypeID);
QString keyValue = QString(R"("%1" "%2")").arg(appPath, "%1");
if (!ISetRegKey(keyName, keyValue))
return false;
// Success!
@ -148,32 +152,33 @@ bool plWinRegistryTools::AssociateFileType( const char *fileTypeID, const cha
// where fileExtension includes the leading . and fileTypeID is the same
// typeID registered with the above function
bool plWinRegistryTools::AssociateFileExtension( const char *fileExtension, const char *fileTypeID )
bool plWinRegistryTools::AssociateFileExtension(const QString &fileExtension, const QString &fileTypeID)
{
return ISetRegKey( fileExtension, fileTypeID );
return ISetRegKey(fileExtension, fileTypeID);
}
//// GetCurrentFileExtensionAssociation //////////////////////////////////////
// Obtains the current fileTypeID associated with the given file extension,
// or a null string if it isn't yet associated.
bool plWinRegistryTools::GetCurrentFileExtensionAssociation( const char *extension, char *buffer, int bufferLen )
QString plWinRegistryTools::GetCurrentFileExtensionAssociation(const QString &extension)
{
long dataLen;
buffer[ 0 ] = 0;
dataLen = bufferLen;
long dataLen = 512;
wchar_t buffer[512];
buffer[0] = 0;
LONG retVal = ::RegQueryValue( HKEY_CLASSES_ROOT, extension, buffer, &dataLen );
if( retVal != ERROR_SUCCESS )
LONG retVal = ::RegQueryValueW(HKEY_CLASSES_ROOT, extension.toStdWString().c_str(), buffer, &dataLen);
if (retVal != ERROR_SUCCESS)
{
char msg[ 512 ];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, retVal, 0, msg, sizeof( msg ), nil );
hsStatusMessageF( "Error querying registry key '%s' : %s\n", extension, msg );
return false;
char msg[512];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, retVal, 0, msg, arrsize(msg), nullptr);
hsStatusMessageF("Error querying registry key '%s' : %s\n", qPrintable(extension), msg);
return QString();
}
return true;
if (dataLen < 512 && buffer[dataLen] == 0)
dataLen -= 1;
return QString::fromWCharArray(buffer, dataLen);
}

21
Sources/Tools/plResBrowser/plWinRegistryTools.h

@ -51,18 +51,25 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#ifndef _plWinRegistryTools_h
#define _plWinRegistryTools_h
class QString;
class plWinRegistryTools
{
public:
// Associates a given file type in the Win32 registry with the given application. Also assigns a default icon if iconIndex != -1
static bool AssociateFileType( const char *fileTypeID, const char *fileTypeName, const char *appPath, int iconIndex = -1 );
/* Associates a given file type in the Win32 registry with the given
application. Also assigns a default icon if iconIndex != -1 */
static bool AssociateFileType(const QString &fileTypeID, const QString &fileTypeName,
const QString &appPath, int iconIndex = -1);
// Assigns a given file extension to a previously registered Win32 file type (using the above function)
static bool AssociateFileExtension( const char *fileExtension, const char *fileTypeID );
/* Assigns a given file extension to a previously registered Win32
file type (using the above function) */
static bool AssociateFileExtension(const QString &fileExtension,
const QString &fileTypeID);
// Obtains the current fileTypeID associated with the given file extension, or a null string if it isn't yet associated
static bool GetCurrentFileExtensionAssociation( const char *extension, char *buffer, int bufferLen );
/* Obtains the current fileTypeID associated with the given file
extension, or a null string if it isn't yet associated */
static QString GetCurrentFileExtensionAssociation(const QString &extension);
};
#endif //_plWinRegistryTools_h
#endif //_plWinRegistryTools_h

76
Sources/Tools/plResBrowser/res/FindDialog.ui

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FindDialog</class>
<widget class="QDialog" name="FindDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>320</width>
<height>71</height>
</rect>
</property>
<property name="windowTitle">
<string>Find Object</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Object Name</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLineEdit" name="fObjectName"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FindDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FindDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

575
Sources/Tools/plResBrowser/res/ResBrowser.ui

@ -0,0 +1,575 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ResBrowser</class>
<widget class="QMainWindow" name="ResBrowser">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>plResBrowser</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="plResTreeView" name="fTreeView">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="fOpenAction"/>
<addaction name="fOpenDirectoryAction"/>
<addaction name="separator"/>
<addaction name="fSaveSelectedAction"/>
<addaction name="separator"/>
<addaction name="fFindAction"/>
<addaction name="fFindNextAction"/>
<addaction name="fShowOnlyLoadableAction"/>
<addaction name="separator"/>
<addaction name="fExitAction"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="fAboutAction"/>
</widget>
<addaction name="menu_File"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QDockWidget" name="dockWidget">
<property name="minimumSize">
<size>
<width>300</width>
<height>520</height>
</size>
</property>
<property name="features">
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
</property>
<property name="allowedAreas">
<set>Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea</set>
</property>
<property name="windowTitle">
<string>Properties</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Page Information</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Age:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="fAgeName">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="fLocation">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Data Version:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Location:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Page</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="fPageName">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="fDataVersion">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="fChecksum">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Checksum:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="fLocalOnly">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="fVolatile">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="fReserved">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="fBuiltIn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Local Only</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_12">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reserved</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Volatile</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_14">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Built-In</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="fChecksumType">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Checksum Type:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Object Information</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0" colspan="4">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Size:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="fStartPos">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="fObjectSize">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Start Pos:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Class:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="fObjectClass">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="fObjectName">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="fHexValues">
<property name="text">
<string>View values as he&amp;x</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="fFindButton">
<property name="text">
<string>Fin&amp;d</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fFindNextButton">
<property name="text">
<string>Find &amp;Next</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="fSaveButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Save Object</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<action name="fOpenAction">
<property name="text">
<string>&amp;Open...</string>
</property>
</action>
<action name="fOpenDirectoryAction">
<property name="text">
<string>Open &amp;Directory...</string>
</property>
</action>
<action name="fSaveSelectedAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Save Selected Object</string>
</property>
</action>
<action name="fFindAction">
<property name="text">
<string>&amp;Find Object...</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
<action name="fFindNextAction">
<property name="text">
<string>Find &amp;Next</string>
</property>
<property name="shortcut">
<string>F3</string>
</property>
</action>
<action name="fShowOnlyLoadableAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Only &amp;Loadable</string>
</property>
</action>
<action name="fExitAction">
<property name="text">
<string>E&amp;xit</string>
</property>
</action>
<action name="fAboutAction">
<property name="text">
<string>&amp;About...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>plResTreeView</class>
<extends>QTreeWidget</extends>
<header>plResTreeView.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

5
Sources/Tools/plResBrowser/res/plResBrowser.qrc

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>icon1.ico</file>
</qresource>
</RCC>

203
Sources/Tools/plResBrowser/res/plResBrowser.rc

@ -1,25 +1,15 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define IDC_STATIC (-1) // all static controls
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
// Icons
//
#define IDI_APPICON 101
#define IDI_INDEXICON 108
#define IDI_DATAICON 109
#define IDI_PATCHICON 110
#define IDI_MERGEDDATAICON 111
#define IDI_MERGEDINDEXICON 112
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPICON ICON "icon1.ico"
@ -28,180 +18,3 @@ IDI_DATAICON ICON "indexico.ico"
IDI_PATCHICON ICON "dataicon.ico"
IDI_MERGEDDATAICON ICON "mergedda.ico"
IDI_MERGEDINDEXICON ICON "mergedin.ico"
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_APPMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open...", ID_FILE_OPEN
MENUITEM "Open &Directory...", ID_FILE_OPENDIRECTORY
MENUITEM SEPARATOR
MENUITEM "Save Selected Object", ID_FILE_SAVESELECTED
MENUITEM SEPARATOR
MENUITEM "Find Object...\tCtrl+F", ID_FILE_FINDOBJECT
MENUITEM "Find Next\tF3", ID_FILE_FINDNEXT
MENUITEM "Show Only Loadable", ID_FILE_ONLYLOAD
MENUITEM SEPARATOR
MENUITEM "About...", ID_FILE_ABOUT
MENUITEM "Exit", ID_FILE_EXIT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_INFODLG DIALOGEX 0, 0, 186, 281
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE
FONT 8, "MS Sans Serif", 0, 0, 0x0
BEGIN
GROUPBOX "Object Information",IDC_STATIC,4,168,178,67
RTEXT "Name:",IDC_STATIC,17,180,22,8
LTEXT "",IDC_NAME,42,179,129,10,SS_SUNKEN | NOT WS_GROUP
GROUPBOX "Page Information",IDC_STATIC,4,2,178,163
RTEXT "Age:",IDC_STATIC,45,14,16,8
LTEXT "",IDC_AGE,63,14,107,10,SS_SUNKEN | NOT WS_GROUP
RTEXT "Page:",IDC_STATIC,41,28,20,8
LTEXT "",IDC_PAGE,63,28,107,10,SS_SUNKEN | NOT WS_GROUP
RTEXT "Location:",IDC_STATIC,31,43,30,8
LTEXT "",IDC_LOCATION,64,43,74,10,SS_SUNKEN | NOT WS_GROUP
CONTROL "Reserved",IDC_RESERVED,"Button",BS_AUTOCHECKBOX |
WS_DISABLED | WS_TABSTOP,64,66,10,10
RTEXT "Class:",IDC_STATIC,19,195,20,8
LTEXT "",IDC_CLASS,42,194,129,10,SS_SUNKEN | NOT WS_GROUP
RTEXT "Start Pos:",IDC_STARTPOS_LABEL,7,221,32,8
LTEXT "",IDC_STARTPOS,42,220,55,10,SS_SUNKEN | NOT WS_GROUP
RTEXT "Size:",IDC_SIZE_LABEL,103,221,17,8
LTEXT "",IDC_LENGTH,124,220,47,10,SS_SUNKEN | NOT WS_GROUP
LTEXT "Reserved",IDC_STATIC,76,67,31,8
PUSHBUTTON "Find",ID_FILE_FINDOBJECT,4,259,50,14
PUSHBUTTON "Find Next",ID_FILE_FINDNEXT,58,259,50,14
RTEXT "Data Version:",IDC_STATIC,17,79,44,8
LTEXT "",IDC_DATAVERSION,64,79,48,10,SS_SUNKEN | NOT WS_GROUP
RTEXT "Checksum:",IDC_STATIC,25,139,36,8
LTEXT "",IDC_IDXCHECKSUM,64,139,53,10,SS_SUNKEN | NOT WS_GROUP
PUSHBUTTON "Verify Page",ID_FILE_VERIFYPAGE,130,259,50,14
RTEXT "Checksum type:",IDC_STATIC,9,151,52,8
LTEXT "",IDC_CHECKSUMTYPE,64,152,89,10,SS_SUNKEN | NOT
WS_GROUP
CONTROL "View values as hex",IDC_SHOWASHEX,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,105,241,77,10
CONTROL "",IDC_LOCAL_ONLY,"Button",BS_AUTOCHECKBOX | WS_DISABLED |
WS_TABSTOP,64,57,11,8
LTEXT "Local Only",IDC_STATIC,76,57,34,8
CONTROL "",IDC_BUILTIN,"Button",BS_AUTOCHECKBOX | WS_DISABLED |
WS_TABSTOP,116,67,11,8
CONTROL "",IDC_VOLATILE,"Button",BS_AUTOCHECKBOX | WS_DISABLED |
WS_TABSTOP,116,57,11,8
LTEXT "Built-In",IDC_STATIC,129,67,22,8
LTEXT "Volatile",IDC_STATIC,129,57,24,8
END
IDD_ABOUT DIALOG 0, 0, 247, 57
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About plResBrowser"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,190,7,50,14
ICON IDI_APPICON,IDC_STATIC,11,8,21,20
LTEXT "plResBrowser\nA simple Plasma 2.0 packfile browsing utility\nCopyright (C) 2002 Cyan Worlds, Inc.\n\nWho needs log files?",
IDC_STATIC,40,7,140,43
END
IDD_FINDOBJ DIALOG 0, 0, 228, 46
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Find Object"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_SEARCHSTRING,13,19,146,14,ES_AUTOHSCROLL
DEFPUSHBUTTON "Find",IDOK,171,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,171,24,50,14
GROUPBOX "Object Name",IDC_STATIC,7,7,157,32
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_ABOUT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 240
TOPMARGIN, 7
BOTTOMMARGIN, 50
END
IDD_FINDOBJ, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 221
TOPMARGIN, 7
BOTTOMMARGIN, 39
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS
BEGIN
"F", ID_FILE_FINDOBJECT, VIRTKEY, CONTROL, NOINVERT
VK_F3, ID_FILE_FINDNEXT, VIRTKEY, NOINVERT
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

68
Sources/Tools/plResBrowser/res/resource.h

@ -1,68 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by plResBrowser.rc
//
#define IDI_ICON1 101
#define IDI_APPICON 101
#define IDR_APPMENU 102
#define IDD_INFODLG 103
#define IDD_ABOUT 104
#define IDR_ACCELERATOR1 106
#define IDD_FINDOBJ 107
#define IDI_INDEXICON 108
#define IDI_DATAICON 109
#define IDI_PATCHICON 110
#define IDI_MERGEDDATAICON 111
#define IDI_MERGEDINDEXICON 112
#define IDC_NAME 1000
#define IDC_AGE 1001
#define IDC_CHAPTER 1002
#define IDC_PAGE 1003
#define IDC_LOCATION 1004
#define IDC_RESERVED 1005
#define IDC_CLASS 1006
#define IDC_STARTPOS 1007
#define IDC_LENGTH 1008
#define IDC_CANLOAD 1009
#define IDC_STARTPOS_LABEL 1010
#define IDC_SIZE_LABEL 1011
#define IDC_INTERLEAVED 1012
#define IDC_RELVERSION 1013
#define IDC_SEARCHSTRING 1014
#define IDC_DATAVERSION 1014
#define IDC_IDXCHECKSUM 1015
#define IDC_DATACHECKSUM 1016
#define IDC_CHECKSUMTYPE 1017
#define IDC_SHOWASHEX 1018
#define IDC_SCROLLBAR 1019
#define IDC_PARTIALPATCH 1019
#define IDC_FRAME 1020
#define IDC_HEADERPATCH 1020
#define IDC_COPIED 1021
#define IDC_NEW 1022
#define IDC_ZOOM 1023
#define IDC_ZOOMSLIDER 1024
#define IDC_SEGINFO 1025
#define IDC_LOCAL_ONLY 1025
#define IDC_BUILTIN 1026
#define IDC_VOLATILE 1027
#define ID_FILE_OPEN 40001
#define ID_FILE_EXIT 40002
#define ID_FILE_OPENDIRECTORY 40003
#define ID_FILE_ABOUT 40004
#define ID_FILE_FINDOBJECT 40005
#define ID_FILE_FINDNEXT 40006
#define ID_FILE_VERIFYPAGE 40007
#define ID_FILE_ONLYLOAD 40008
#define ID_FILE_SAVESELECTED 40009
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 110
#define _APS_NEXT_COMMAND_VALUE 40010
#define _APS_NEXT_CONTROL_VALUE 1026
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
Loading…
Cancel
Save