From f6d04e78c8b445962820f6b2eac23f73033362e9 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sat, 12 Apr 2014 19:42:36 -0700 Subject: [PATCH 1/9] Port plLocalizationEditor to Qt5 --- Sources/Tools/CMakeLists.txt | 3 + .../Tools/plLocalizationEditor/CMakeLists.txt | 39 +- .../Tools/plLocalizationEditor/plAddDlgs.cpp | 375 ++++----------- .../Tools/plLocalizationEditor/plAddDlgs.h | 53 ++- .../Tools/plLocalizationEditor/plEditDlg.cpp | 441 +++++++++++------- .../Tools/plLocalizationEditor/plEditDlg.h | 61 ++- .../plLocalizationEditor/plLocTreeView.cpp | 131 +----- .../plLocalizationEditor/plLocTreeView.h | 19 +- .../plLocalizationEditor.cpp | 339 +------------- .../plLocalizationEditor/res/AddElement.ui | 124 +++++ .../res/AddLocalization.ui | 91 ++++ .../plLocalizationEditor/res/EditDialog.ui | 178 +++++++ .../res/plLocalizationEditor.qrc | 5 + .../res/plLocalizationEditor.rc | 268 ----------- .../Tools/plLocalizationEditor/res/resource.h | 51 -- 15 files changed, 911 insertions(+), 1267 deletions(-) create mode 100644 Sources/Tools/plLocalizationEditor/res/AddElement.ui create mode 100644 Sources/Tools/plLocalizationEditor/res/AddLocalization.ui create mode 100644 Sources/Tools/plLocalizationEditor/res/EditDialog.ui create mode 100644 Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc delete mode 100644 Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc delete mode 100644 Sources/Tools/plLocalizationEditor/res/resource.h diff --git a/Sources/Tools/CMakeLists.txt b/Sources/Tools/CMakeLists.txt index 8bdc2fb3..f7d07da9 100644 --- a/Sources/Tools/CMakeLists.txt +++ b/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) diff --git a/Sources/Tools/plLocalizationEditor/CMakeLists.txt b/Sources/Tools/plLocalizationEditor/CMakeLists.txt index 2d5f700a..f9d139f9 100644 --- a/Sources/Tools/plLocalizationEditor/CMakeLists.txt +++ b/Sources/Tools/plLocalizationEditor/CMakeLists.txt @@ -8,24 +8,42 @@ 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 ) -add_executable(plLocalizationEditor WIN32 ${plLocalizationEditor_HEADERS} ${plLocalizationEditor_SOURCES} ${plLocalizationEditor_RESOURCES}) +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_BINARY_DIR}) + +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 +51,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}) diff --git a/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp b/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp index b3cdd506..0c7a8733 100644 --- a/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp +++ b/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 -#include +#include +#include "ui_AddElement.h" +#include "ui_AddLocalization.h" -extern HINSTANCE gInstance; +#include -// 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 AlphaNumbericValidator : 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 editBoxMap; + AlphaNumbericValidator(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); + AlphaNumbericValidator *validator = new AlphaNumbericValidator(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 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 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 IGetAllLanguageNames() { int numLocales = plLocalization::GetNumLocales(); @@ -342,10 +170,24 @@ std::vector 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 existingLanguages; existingLanguages = pfLocalizationDataMgr::Instance().GetLanguages(fAgeName, fSetName, fElementName); @@ -353,61 +195,30 @@ bool plAddLocalizationDlg::IInitDlg(HWND hDlg) std::vector 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(); } diff --git a/Sources/Tools/plLocalizationEditor/plAddDlgs.h b/Sources/Tools/plLocalizationEditor/plAddDlgs.h index 0cd3d6e8..027dc12e 100644 --- a/Sources/Tools/plLocalizationEditor/plAddDlgs.h +++ b/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 #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 diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp index 89b9453e..248f47b1 100644 --- a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp @@ -41,250 +41,339 @@ 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 +#include +#include +#include +#include "ui_EditDialog.h" -HWND gEditDlg = NULL; -extern HINSTANCE gInstance; -extern HWND gTreeView; +#include -// global data for this dialog -plString gCurrentPath; +#define ABOUT_TEXT R"(plLocalizationEditor +A basic editor for Plasma 21 localization resource files +Copyright (C) 2004 Cyan Worlds, Inc.)" -// 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 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(ABOUT_TEXT), &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 - EnableWindow(GetDlgItem(gEditDlg, IDC_LOCALIZATIONTEXT), enable); + plString text = fUI->fLocalizationText->toPlainText().toUtf8().constData(); + + plString ageName, setName, elementName, elementLanguage; + SplitLocalizationPath(fCurrentLocPath, ageName, setName, elementName, elementLanguage); + + 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 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); } } -BOOL HandleCommandMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +void EditDialog::EnableEdit(bool enable) { - int wmID, wmEvent; - wmID = LOWORD(wParam); - wmEvent = HIWORD(wParam); + if (!enable) + fUI->fLocalizationText->setPlainText(""); - switch (wmEvent) + fUI->fLocalizationText->setEnabled(enable); +} + +void EditDialog::closeEvent(QCloseEvent *event) +{ + if (fCurrentSavePath.isEmpty()) // no data open { - case BN_CLICKED: - switch (wmID) + 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()); + } +} + +void EditDialog::LocPathChanged(QTreeWidgetItem *current, QTreeWidgetItem *) +{ + SaveLocalizationText(); // save any current changes to the database + LoadLocalization(fUI->fLocalizationTree->CurrentPath()); +} + +void EditDialog::AddClicked() +{ + SaveLocalizationText(); // save any current changes to the database + + if (fEditMode == kEditElement) + { + 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 = fCurrentLocPath; + 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 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]; } diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.h b/Sources/Tools/plLocalizationEditor/plEditDlg.h index 0a793f2e..38c3046e 100644 --- a/Sources/Tools/plLocalizationEditor/plEditDlg.h +++ b/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 +#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 diff --git a/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp b/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp index c614ca18..a22e18f8 100644 --- a/Sources/Tools/plLocalizationEditor/plLocTreeView.cpp +++ b/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 -#include -#include "res/resource.h" - #include -#include #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> bufs; - plStringBuffer buf = text.ToWchar(); - bufs.push_back(buf); - - TVITEM tvi = {0}; - tvi.mask = TVIF_TEXT | TVIF_PARAM; - tvi.pszText = const_cast(buf.GetData()); - tvi.cchTextMax = static_cast(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 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 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 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 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(); } diff --git a/Sources/Tools/plLocalizationEditor/plLocTreeView.h b/Sources/Tools/plLocalizationEditor/plLocTreeView.h index 4a340cc8..93d43ebe 100644 --- a/Sources/Tools/plLocalizationEditor/plLocTreeView.h +++ b/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 #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 diff --git a/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp b/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp index d888ef66..36ecf484 100644 --- a/Sources/Tools/plLocalizationEditor/plLocalizationEditor.cpp +++ b/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 #include "plEditDlg.h" -#include "HeadSpin.h" -#include -#include -#include -#include -#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='*'\"") diff --git a/Sources/Tools/plLocalizationEditor/res/AddElement.ui b/Sources/Tools/plLocalizationEditor/res/AddElement.ui new file mode 100644 index 00000000..e949c8b2 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/res/AddElement.ui @@ -0,0 +1,124 @@ + + + AddElement + + + + 0 + 0 + 300 + 138 + + + + Add Element + + + + + + Path: + + + + + + + + + + Parent Age: + + + + + + + + 0 + 0 + + + + true + + + + + + + Parent Set: + + + + + + + + 0 + 0 + + + + true + + + + + + + Element Name: + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + fButtons + accepted() + AddElement + accept() + + + 248 + 254 + + + 157 + 274 + + + + + fButtons + rejected() + AddElement + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui b/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui new file mode 100644 index 00000000..a4bf4717 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui @@ -0,0 +1,91 @@ + + + AddLocalization + + + + 0 + 0 + 300 + 86 + + + + Add Localization + + + + + + Path: + + + + + + + + + + Language + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + fButtons + accepted() + AddLocalization + accept() + + + 248 + 254 + + + 157 + 274 + + + + + fButtons + rejected() + AddLocalization + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plLocalizationEditor/res/EditDialog.ui b/Sources/Tools/plLocalizationEditor/res/EditDialog.ui new file mode 100644 index 00000000..92c7082c --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/res/EditDialog.ui @@ -0,0 +1,178 @@ + + + EditDialog + + + + 0 + 0 + 800 + 500 + + + + plLocalizationEditor + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + false + + + + 1 + + + + + + + + 10 + + + + + Localization Tree + + + + + + false + + + Add + + + + + + + false + + + Delete + + + + + + + + + + Localization Information + + + + + + Text: + + + + + + + + + + + + + + + + + 0 + 0 + 800 + 21 + + + + + &File + + + + + + + + + + + &Help + + + + + + + + + &Open Data Directory... + + + Ctrl+O + + + + + false + + + &Save to Current Directory + + + Ctrl+S + + + + + false + + + S&ave to Specified Directory... + + + Ctrl+Shift+S + + + + + E&xit + + + + + &About + + + + + + plLocTreeView + QTreeWidget +
plLocTreeView.h
+
+
+ + +
diff --git a/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc b/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc new file mode 100644 index 00000000..81055f95 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.qrc @@ -0,0 +1,5 @@ + + + icon1.ico + + diff --git a/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc b/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc deleted file mode 100644 index 98546cd9..00000000 --- a/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc +++ /dev/null @@ -1,268 +0,0 @@ -// 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 - diff --git a/Sources/Tools/plLocalizationEditor/res/resource.h b/Sources/Tools/plLocalizationEditor/res/resource.h deleted file mode 100644 index a8f59a4b..00000000 --- a/Sources/Tools/plLocalizationEditor/res/resource.h +++ /dev/null @@ -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 From f0ed701d8f39a9ca15c9501f76a8912ffdc19730 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sat, 12 Apr 2014 20:29:00 -0700 Subject: [PATCH 2/9] Fix pfLocalizationDataMgr's SetElementPlainTextData to work properly without a database re-load. --- .../FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp | 3 ++- Sources/Tools/plLocalizationEditor/plEditDlg.cpp | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp b/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp index a82c4d89..2c1dcde9 100644 --- a/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizedString.cpp +++ b/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(); } diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp index 248f47b1..462d9e90 100644 --- a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp @@ -116,6 +116,9 @@ void EditDialog::SaveLocalizationText() plString ageName, setName, elementName, elementLanguage; SplitLocalizationPath(fCurrentLocPath, ageName, setName, elementName, elementLanguage); + 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); } @@ -351,7 +354,7 @@ void EditDialog::DeleteClicked() QMessageBox::critical(this, tr("Error"), tr("Couldn't delete localization!")); else { - plString path = fCurrentLocPath; + plString path = key + ".English"; fCurrentLocPath = ""; fUI->fLocalizationTree->clear(); fUI->fLocalizationTree->LoadData(path); From b48963b904e4e8fdc2948738f463a3d4b9df2ab1 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sat, 12 Apr 2014 20:40:43 -0700 Subject: [PATCH 3/9] Make it compile and work in GCC / Linux --- Sources/Plasma/CoreLib/hsThread_Unix.cpp | 2 +- Sources/Plasma/CoreLib/plFileSystem.cpp | 2 +- Sources/Tools/plLocalizationEditor/CMakeLists.txt | 1 + Sources/Tools/plLocalizationEditor/plEditDlg.cpp | 8 +++----- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Sources/Plasma/CoreLib/hsThread_Unix.cpp b/Sources/Plasma/CoreLib/hsThread_Unix.cpp index 1e298282..786ced38 100644 --- a/Sources/Plasma/CoreLib/hsThread_Unix.cpp +++ b/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); diff --git a/Sources/Plasma/CoreLib/plFileSystem.cpp b/Sources/Plasma/CoreLib/plFileSystem.cpp index 61341c78..eb395efa 100644 --- a/Sources/Plasma/CoreLib/plFileSystem.cpp +++ b/Sources/Plasma/CoreLib/plFileSystem.cpp @@ -394,7 +394,7 @@ std::vector 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); diff --git a/Sources/Tools/plLocalizationEditor/CMakeLists.txt b/Sources/Tools/plLocalizationEditor/CMakeLists.txt index f9d139f9..0882ce44 100644 --- a/Sources/Tools/plLocalizationEditor/CMakeLists.txt +++ b/Sources/Tools/plLocalizationEditor/CMakeLists.txt @@ -39,6 +39,7 @@ set(plLocalizationEditor_UIC_SOURCES 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} diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp index 462d9e90..686ed0a0 100644 --- a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp @@ -54,16 +54,14 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include -#define ABOUT_TEXT R"(plLocalizationEditor -A basic editor for Plasma 21 localization resource files -Copyright (C) 2004 Cyan Worlds, Inc.)" - static void IAboutDialog(QWidget *parent) { QDialog dlg(parent); QLabel *image = new QLabel(&dlg); image->setPixmap(QPixmap(":/icon1.ico")); - QLabel *text = new QLabel(QObject::tr(ABOUT_TEXT), &dlg); + 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); From d4465a2168ec2f76921414649e0bc34d9bd9f788 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 13 Apr 2014 17:58:53 -0700 Subject: [PATCH 4/9] Port plFontConverter to Qt5 --- Sources/Plasma/PubUtilLib/plGImage/plFont.cpp | 6 +- Sources/Plasma/PubUtilLib/plGImage/plFont.h | 4 +- Sources/Tools/plFontConverter/CMakeLists.txt | 57 +- .../Tools/plFontConverter/plFontConverter.cpp | 605 +++++++++++++- .../Tools/plFontConverter/plFontConverter.h | 86 ++ .../plFontConverter/plFontConverterProc.cpp | 756 ------------------ .../Tools/plFontConverter/plFontFreeType.cpp | 8 +- .../Tools/plFontConverter/plFontFreeType.h | 8 +- .../Tools/plFontConverter/plFontPreview.cpp | 115 +++ ...hsCodecManagerStub.cpp => plFontPreview.h} | 54 +- .../Tools/plFontConverter/res/FonChooser.ui | 81 ++ Sources/Tools/plFontConverter/res/FreeType.ui | 137 ++++ .../plFontConverter/res/FreeTypeBatch.ui | 159 ++++ .../Tools/plFontConverter/res/MainDialog.ui | 355 ++++++++ .../plFontConverter/res/plFontConverter.qrc | 5 + .../plFontConverter/res/plFontConverter.rc | 269 ------- Sources/Tools/plFontConverter/res/resource.h | 52 -- .../Tools/plLocalizationEditor/CMakeLists.txt | 10 +- .../Tools/plLocalizationEditor/plAddDlgs.cpp | 6 +- .../plLocalizationEditor/res/AddElement.ui | 15 +- .../res/AddLocalization.ui | 5 +- .../plLocalizationEditor/res/EditDialog.ui | 9 +- .../res/plLocalizationEditor.rc | 1 + 23 files changed, 1626 insertions(+), 1177 deletions(-) create mode 100644 Sources/Tools/plFontConverter/plFontConverter.h delete mode 100644 Sources/Tools/plFontConverter/plFontConverterProc.cpp create mode 100644 Sources/Tools/plFontConverter/plFontPreview.cpp rename Sources/Tools/plFontConverter/{hsCodecManagerStub.cpp => plFontPreview.h} (70%) create mode 100644 Sources/Tools/plFontConverter/res/FonChooser.ui create mode 100644 Sources/Tools/plFontConverter/res/FreeType.ui create mode 100644 Sources/Tools/plFontConverter/res/FreeTypeBatch.ui create mode 100644 Sources/Tools/plFontConverter/res/MainDialog.ui create mode 100644 Sources/Tools/plFontConverter/res/plFontConverter.qrc delete mode 100644 Sources/Tools/plFontConverter/res/resource.h create mode 100644 Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc diff --git a/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp b/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp index 946359ee..5f110bf6 100644 --- a/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp +++ b/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 diff --git a/Sources/Plasma/PubUtilLib/plGImage/plFont.h b/Sources/Plasma/PubUtilLib/plGImage/plFont.h index 68a2f88f..05a1af42 100644 --- a/Sources/Plasma/PubUtilLib/plGImage/plFont.h +++ b/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 ); diff --git a/Sources/Tools/plFontConverter/CMakeLists.txt b/Sources/Tools/plFontConverter/CMakeLists.txt index e102ea6d..8845dd44 100644 --- a/Sources/Tools/plFontConverter/CMakeLists.txt +++ b/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}) diff --git a/Sources/Tools/plFontConverter/plFontConverter.cpp b/Sources/Tools/plFontConverter/plFontConverter.cpp index ebda5e56..08890246 100644 --- a/Sources/Tools/plFontConverter/plFontConverter.cpp +++ b/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,606 @@ REGISTER_CREATABLE(plFont); REGISTER_NONCREATABLE(plBitmap); REGISTER_CREATABLE(plMipmap); +#include "pnKeyedObject/plUoid.h" +#include "pnKeyedObject/plKeyImp.h" + +#include +#include +#include +#include +#include +#include +#include +#include "ui_MainDialog.h" +#include "ui_FonChooser.h" +#include "ui_FreeType.h" +#include "ui_FreeTypeBatch.h" + +#include HINSTANCE gInstance; char *gCommandLine = nil; HWND gMainWindow = nil; -BOOL CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); +static void IAboutDialog(QWidget *parent) +{ + QDialog dlg(parent); + QLabel *image = new QLabel(&dlg); + image->setPixmap(QPixmap(":/icon1.ico")); + QLabel *text = new QLabel(QObject::tr(R"(plFontConverter + +A simple Plasma 2.0 utility for converting public +font formats into our own bitmap font format.)"), &dlg); + QPushButton *ok = new QPushButton(QObject::tr("OK"), &dlg); + ok->setDefault(true); + + QHBoxLayout *layout = new QHBoxLayout(&dlg); + layout->setMargin(8); + layout->setSpacing(10); + layout->addWidget(image); + layout->addWidget(text); + layout->addWidget(ok); + + dlg.connect(ok, &QPushButton::clicked, &dlg, &QDialog::accept); + dlg.exec(); +} + +plFontConverter::plFontConverter() + : QMainWindow(), fFont(nullptr) +{ + fUI = new Ui_MainDialog; + fUI->setupUi(this); + + setAcceptDrops(true); + + connect(fUI->fImportFNTAction, SIGNAL(triggered()), SLOT(OpenFNT())); + connect(fUI->fImportBDFAction, SIGNAL(triggered()), SLOT(OpenBDF())); + connect(fUI->fImportFONAction, SIGNAL(triggered()), SLOT(OpenFON())); + connect(fUI->fImportTTFAction, SIGNAL(triggered()), SLOT(OpenTTF())); + connect(fUI->fOpenAction, SIGNAL(triggered()), SLOT(OpenP2F())); + connect(fUI->fExportAction, SIGNAL(triggered()), SLOT(ExportP2F())); + connect(fUI->fExitAction, SIGNAL(triggered()), SLOT(close())); + connect(fUI->fAboutAction, &QAction::triggered, std::bind(&IAboutDialog, this)); + + connect(fUI->fExportButton, SIGNAL(clicked()), SLOT(ExportP2F())); + + connect(fUI->fSampleText, &QLineEdit::textChanged, [this](const QString &text) + { + fUI->fPreview->Update(fFont, text); + }); +} + +plFontConverter::~plFontConverter() +{ + delete fUI; +} + +void plFontConverter::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasUrls()) + event->acceptProposedAction(); +} + +void plFontConverter::dropEvent(QDropEvent *event) +{ + QList urls = event->mimeData()->urls(); + + for (const QUrl &url : urls) + { + if (!url.isLocalFile()) + continue; + + plFileName fileName = url.toLocalFile().toUtf8().constData(); + plString ext = fileName.GetFileExt(); + if (ext.CompareI("fnt") == 0) + IImportFNT(fileName); + else if (ext.CompareI("bdf") == 0) + IImportBDF(fileName); + else if (ext.CompareI("fon") == 0 || ext.CompareI("exe") == 0) + IImportFON(fileName); + else if (ext.CompareI("ttf") == 0 || ext.CompareI("ttc") == 0) + IImportFreeType(fileName); + else if (ext.CompareI("p2f") == 0) + IOpenP2F(fileName); + else + { + // Try using our freeType converter + IImportFreeType(fileName); + } + } + + IUpdateInfo(); +} + +void plFontConverter::OpenFNT() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a FNT file to convert"), + QString(), "Windows FNT files (*.fnt);;All files (*.*)"); + + if (!fileName.isEmpty()) + IImportFNT(fileName.toUtf8().constData()); +} + +void plFontConverter::OpenBDF() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a BDF file to convert"), + QString(), "Adobe BDF files (*.bdf);;All files (*.*)"); + + if (!fileName.isEmpty()) + IImportBDF(fileName.toUtf8().constData()); +} + +void plFontConverter::OpenFON() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a FON file to convert"), + QString(), "Windows FON files (*.fon *.exe);;All files (*.*)"); + + if (!fileName.isEmpty()) + IImportFON(fileName.toUtf8().constData()); +} + +void plFontConverter::OpenTTF() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a TrueType font to convert"), + QString(), "TrueType files (*.ttf *.ttc);;All files (*.*)"); + + if (!fileName.isEmpty()) + IImportFreeType(fileName.toUtf8().constData()); +} + +void plFontConverter::OpenP2F() +{ + QString fileName = QFileDialog::getOpenFileName(this, tr("Choose a P2F file to open"), + QString(), "Plasma 2 font files (*.p2f);;All files (*.*)"); + + if (!fileName.isEmpty()) + IOpenP2F(fileName.toUtf8().constData()); +} + +void plFontConverter::ExportP2F() +{ + // Grab updated values for the font + plString fileName = fUI->fFaceName->text().toUtf8().constData(); + fFont->SetFace(fileName); + fFont->SetSize(fUI->fFontSize->value()); + fFont->SetFlag(plFont::kFlagBold, fUI->fBold->isChecked()); + fFont->SetFlag(plFont::kFlagItalic, fUI->fItalic->isChecked()); + + // Write out + QString saveFile = QFileDialog::getSaveFileName(this, tr("Specify a file to export to"), + QString("%1-%2.p2f").arg(fFont->GetFace().c_str()).arg(fFont->GetSize()), + "Plasma 2 font files (*.p2f)"); + + if (!saveFile.isEmpty()) + { + fileName = saveFile.toUtf8().constData(); + + hsUNIXStream stream; + if (!stream.Open(fileName, "wb")) + QMessageBox::critical(this, tr("Error"), tr("Can't open file for writing")); + else + { + /* + sprintf( fileName, "%s-%d", gFont->GetFace(), gFont->GetSize() ); + + if( gFont->GetKey() == nil ) + hsgResMgr::ResMgr()->NewKey( fileName, gFont, plLocation::kGlobalFixedLoc ); + */ + fFont->WriteRaw(&stream); + stream.Close(); + } + } +} + +void plFontConverter::IMakeFontGoAway() +{ + if (fFont != nullptr) { + plKeyImp *imp = (plKeyImp *)(fFont->GetKey()); + if (imp != nullptr) + imp->SetObjectPtr(nullptr); + fFont = nullptr; + } +} + +void plFontConverter::IMakeNewFont() +{ + IMakeFontGoAway(); + fFont = new plFont(); +} + +void plFontConverter::IUpdateInfo() +{ + if (fFont != nullptr && fFont->GetNumChars() == 0) + IMakeFontGoAway(); + + if (fFont == nullptr) + { + fUI->fExportAction->setEnabled(false); + fUI->fExportButton->setEnabled(false); + + fUI->fFaceName->setText(""); + fUI->fFontSize->setValue(0); + fUI->fStartingGlyph->setText(""); + fUI->fGlyphCount->setText(""); + + fUI->fBitmapWidth->setText(""); + fUI->fBitmapHeight->setText(""); + fUI->fBPP->setText(""); + + fUI->fBold->setChecked(false); + fUI->fItalic->setChecked(false); + + fUI->fPreview->Update(nullptr, QString()); + return; + } + + fUI->fExportAction->setEnabled(true); + fUI->fExportButton->setEnabled(true); + + fUI->fFaceName->setText(fFont->GetFace().c_str()); + fUI->fFontSize->setValue(fFont->GetSize()); + fUI->fStartingGlyph->setText(QString::number(fFont->GetFirstChar())); + fUI->fGlyphCount->setText(QString::number(fFont->GetNumChars())); + + fUI->fBitmapWidth->setText(QString::number(fFont->GetBitmapWidth())); + fUI->fBitmapHeight->setText(QString::number(fFont->GetBitmapHeight())); + fUI->fBPP->setText(QString::number(fFont->GetBitmapBPP())); + + fUI->fBold->setChecked(fFont->IsFlagSet(plFont::kFlagBold)); + fUI->fItalic->setChecked(fFont->IsFlagSet(plFont::kFlagItalic)); + + fUI->fPreview->Update(fFont, fUI->fSampleText->text()); +} + +void plFontConverter::IImportFNT(const plFileName &path) +{ + IMakeNewFont(); + if (!fFont->LoadFromFNT(path)) + QMessageBox::critical(this, tr("ERROR"), tr("Failure converting FNT file")); + + IUpdateInfo(); +} + +class ProgressRAII +{ + QWidget *fParent; + QProgressDialog *fProgress; + +public: + ProgressRAII(QWidget *parent) + : fParent(parent) + { + fProgress = new QProgressDialog(parent->tr("Importing Font..."), QString(), 0, 100, parent); + fProgress->setAttribute(Qt::WA_DeleteOnClose); + fParent->setEnabled(false); + } + + ~ProgressRAII() + { + fProgress->close(); + fParent->setEnabled(true); + } + + void SetRange(int max) { fProgress->setRange(0, max); } + void SetValue(int val) { fProgress->setValue(val); } +}; + +class plMyBDFCallback : public plBDFConvertCallback +{ + ProgressRAII fProgress; + uint16_t fPoint; + +public: + plMyBDFCallback(QWidget *parent) : fProgress(parent) { } + + virtual void NumChars(uint16_t chars) override + { + fProgress.SetRange(chars); + } + + virtual void CharDone() override + { + fPoint++; + fProgress.SetValue(fPoint); + + qApp->processEvents(); + } +}; +void plFontConverter::IImportBDF(const plFileName &path) +{ + IMakeNewFont(); + + plMyBDFCallback callback(this); + if (!fFont->LoadFromBDF(path, &callback)) + QMessageBox::critical(this, tr("ERROR"), tr("Failure converting BDF file")); + + IUpdateInfo(); +} + +struct ResRecord +{ + HRSRC fHandle; + QString fName; + + ResRecord() : fHandle(nullptr) { } + ResRecord(HRSRC h, const QString &n) : fHandle(h), fName(n) { } +}; -int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) +BOOL CALLBACK ResEnumProc(HMODULE module, LPCTSTR type, LPTSTR name, LONG_PTR lParam) { - HACCEL accelTable = LoadAccelerators( hInstance, MAKEINTRESOURCE( IDR_ACCELERATOR1 ) ); + HRSRC res = FindResource(module, name, type); + if (res != nullptr) + { + QList *array = reinterpret_cast *>(lParam); + array->append(ResRecord(res, name)); + } + return true; +} + +static ResRecord DoSelectResource(const QList &resources) +{ + QDialog dlg; + Ui_FonChooser ui; + ui.setupUi(&dlg); - gCommandLine = (char *)lpCmdLine; + 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(); +} + +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 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) { } - gInstance = hInstance; + 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(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 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(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(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='*'\"") diff --git a/Sources/Tools/plFontConverter/plFontConverter.h b/Sources/Tools/plFontConverter/plFontConverter.h new file mode 100644 index 00000000..29af53c2 --- /dev/null +++ b/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 . + +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 + +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 diff --git a/Sources/Tools/plFontConverter/plFontConverterProc.cpp b/Sources/Tools/plFontConverter/plFontConverterProc.cpp deleted file mode 100644 index ed58b2ff..00000000 --- a/Sources/Tools/plFontConverter/plFontConverterProc.cpp +++ /dev/null @@ -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 . - -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 -#include -#include -#include -#include -#include - -#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 *array = (hsTArray *)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 *array = (hsTArray *)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 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 ); -} - diff --git a/Sources/Tools/plFontConverter/plFontFreeType.cpp b/Sources/Tools/plFontConverter/plFontFreeType.cpp index 55663118..686cb4ec 100644 --- a/Sources/Tools/plFontConverter/plFontFreeType.cpp +++ b/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; diff --git a/Sources/Tools/plFontConverter/plFontFreeType.h b/Sources/Tools/plFontConverter/plFontFreeType.h index 06a4c4ff..ed20dbf0 100644 --- a/Sources/Tools/plFontConverter/plFontFreeType.h +++ b/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 ); -}; \ No newline at end of file + bool ImportFreeType( const plFileName &fontPath, Options *options, plBDFConvertCallback *callback ); +}; diff --git a/Sources/Tools/plFontConverter/plFontPreview.cpp b/Sources/Tools/plFontConverter/plFontPreview.cpp new file mode 100644 index 00000000..b93d1719 --- /dev/null +++ b/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 . + +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 +#include + +#include + +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); +} diff --git a/Sources/Tools/plFontConverter/hsCodecManagerStub.cpp b/Sources/Tools/plFontConverter/plFontPreview.h similarity index 70% rename from Sources/Tools/plFontConverter/hsCodecManagerStub.cpp rename to Sources/Tools/plFontConverter/plFontPreview.h index 9362d260..08cdbffa 100644 --- a/Sources/Tools/plFontConverter/hsCodecManagerStub.cpp +++ b/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 -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 diff --git a/Sources/Tools/plFontConverter/res/FonChooser.ui b/Sources/Tools/plFontConverter/res/FonChooser.ui new file mode 100644 index 00000000..225f7904 --- /dev/null +++ b/Sources/Tools/plFontConverter/res/FonChooser.ui @@ -0,0 +1,81 @@ + + + FonChooser + + + + 0 + 0 + 270 + 260 + + + + FON Resource List + + + + + + + + Choose which resource to import: + + + true + + + + + + + + + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FonChooser + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FonChooser + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plFontConverter/res/FreeType.ui b/Sources/Tools/plFontConverter/res/FreeType.ui new file mode 100644 index 00000000..0713b1c3 --- /dev/null +++ b/Sources/Tools/plFontConverter/res/FreeType.ui @@ -0,0 +1,137 @@ + + + FreeType + + + + 0 + 0 + 340 + 95 + + + + FreeType Import Options + + + + + + + + Render Point &Size: + + + fPointSize + + + + + + + 255 + + + + + + + Max &Character: + + + fMaxChar + + + + + + + 1114111 + + + + + + + Screen &Resolution: + + + fResolution + + + + + + + 65535 + + + + + + + + + &Monochrome + + + + + + + &Grayscale + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + fButtons + accepted() + FreeType + accept() + + + 248 + 254 + + + 157 + 274 + + + + + fButtons + rejected() + FreeType + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plFontConverter/res/FreeTypeBatch.ui b/Sources/Tools/plFontConverter/res/FreeTypeBatch.ui new file mode 100644 index 00000000..d27169f7 --- /dev/null +++ b/Sources/Tools/plFontConverter/res/FreeTypeBatch.ui @@ -0,0 +1,159 @@ + + + FreeTypeBatch + + + + 0 + 0 + 357 + 181 + + + + FreeType Import Options + + + + + + + + Render Point &Sizes: + + + fPointSizes + + + + + + + + + + + + Common Settings + + + + + + + + &Monochrome + + + + + + + &Grayscale + + + + + + + + + Screen &Resolution: + + + fResolution + + + + + + + Max &Character: + + + fMaxChar + + + + + + + 1114111 + + + + + + + 65535 + + + + + + + + + + + + Font &Name: + + + fFontName + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FreeTypeBatch + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FreeTypeBatch + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plFontConverter/res/MainDialog.ui b/Sources/Tools/plFontConverter/res/MainDialog.ui new file mode 100644 index 00000000..489d9d9e --- /dev/null +++ b/Sources/Tools/plFontConverter/res/MainDialog.ui @@ -0,0 +1,355 @@ + + + MainDialog + + + + 0 + 0 + 384 + 316 + + + + plFontConverter + + + + + 8 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + 8 + + + + + F&ace: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + fFaceName + + + + + + + + + + false + + + &Export P2F... + + + + + + + &Size: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + fFontSize + + + + + + + + + + 0 + 0 + + + + 255 + + + + + + + &Bold + + + + + + + &Italic + + + + + + + + + + + 8 + + + + + + 0 + 0 + + + + Starting Glyph: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + 0 + 0 + + + + + + + + Glyph Count: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + + + + + 0 + 0 + + + + Bitmap Width: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Bitmap Height: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + + + + + 0 + 0 + + + + BPP: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + + + + + + + + 0 + 0 + + + + + 0 + 32 + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + + + + The quick brown fox jumped over the lazy dog! ABCabc012345;,. + + + + + + + + + 0 + 0 + 384 + 21 + + + + + &File + + + + + + + + + + + + + + &Help + + + + + + + + + Import &FNT... + + + + + Import &BDF... + + + + + Import FO&N... + + + + + &Open P2F... + + + + + Import &TrueType... + + + + + false + + + &Export P2F... + + + + + E&xit + + + + + &About... + + + + + + plFontPreview + QFrame +
plFontPreview.h
+ 1 +
+
+ + +
diff --git a/Sources/Tools/plFontConverter/res/plFontConverter.qrc b/Sources/Tools/plFontConverter/res/plFontConverter.qrc new file mode 100644 index 00000000..81055f95 --- /dev/null +++ b/Sources/Tools/plFontConverter/res/plFontConverter.qrc @@ -0,0 +1,5 @@ + + + icon1.ico + + diff --git a/Sources/Tools/plFontConverter/res/plFontConverter.rc b/Sources/Tools/plFontConverter/res/plFontConverter.rc index a47b2de3..cba62bb3 100644 --- a/Sources/Tools/plFontConverter/res/plFontConverter.rc +++ b/Sources/Tools/plFontConverter/res/plFontConverter.rc @@ -1,270 +1 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resource.h" - -#define WIN32_LEAN_AND_MEAN -#include -#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 - diff --git a/Sources/Tools/plFontConverter/res/resource.h b/Sources/Tools/plFontConverter/res/resource.h deleted file mode 100644 index 4fa25d9f..00000000 --- a/Sources/Tools/plFontConverter/res/resource.h +++ /dev/null @@ -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 diff --git a/Sources/Tools/plLocalizationEditor/CMakeLists.txt b/Sources/Tools/plLocalizationEditor/CMakeLists.txt index 0882ce44..149e2725 100644 --- a/Sources/Tools/plLocalizationEditor/CMakeLists.txt +++ b/Sources/Tools/plLocalizationEditor/CMakeLists.txt @@ -20,11 +20,11 @@ set(plLocalizationEditor_SOURCES 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 diff --git a/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp b/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp index 0c7a8733..f9180642 100644 --- a/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp +++ b/Sources/Tools/plLocalizationEditor/plAddDlgs.cpp @@ -54,10 +54,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include // very simple validator for edit controls (and combo boxes) so that they only accept alphanumeric values -class AlphaNumbericValidator : public QValidator +class AlphaNumericValidator : public QValidator { public: - AlphaNumbericValidator(QObject *parent = nullptr) : QValidator(parent) { } + AlphaNumericValidator(QObject *parent = nullptr) : QValidator(parent) { } virtual State validate(QString &input, int &pos) const override { @@ -79,7 +79,7 @@ plAddElementDlg::plAddElementDlg(const plString &parentPath, QWidget *parent) fUI->setupUi(this); layout()->setSizeConstraint(QLayout::SetFixedSize); - AlphaNumbericValidator *validator = new AlphaNumbericValidator(this); + AlphaNumericValidator *validator = new AlphaNumericValidator(this); fUI->fParentAge->setValidator(validator); fUI->fParentSet->setValidator(validator); fUI->fElementName->setValidator(validator); diff --git a/Sources/Tools/plLocalizationEditor/res/AddElement.ui b/Sources/Tools/plLocalizationEditor/res/AddElement.ui index e949c8b2..5e5dec38 100644 --- a/Sources/Tools/plLocalizationEditor/res/AddElement.ui +++ b/Sources/Tools/plLocalizationEditor/res/AddElement.ui @@ -27,7 +27,10 @@ - Parent Age: + Parent &Age: + + + fParentAge @@ -47,7 +50,10 @@ - Parent Set: + Parent &Set: + + + fParentSet @@ -67,7 +73,10 @@ - Element Name: + &Element Name: + + + fElementName diff --git a/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui b/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui index a4bf4717..1b63c3b6 100644 --- a/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui +++ b/Sources/Tools/plLocalizationEditor/res/AddLocalization.ui @@ -27,7 +27,10 @@ - Language + &Language + + + fLanguage diff --git a/Sources/Tools/plLocalizationEditor/res/EditDialog.ui b/Sources/Tools/plLocalizationEditor/res/EditDialog.ui index 92c7082c..b88eeb2f 100644 --- a/Sources/Tools/plLocalizationEditor/res/EditDialog.ui +++ b/Sources/Tools/plLocalizationEditor/res/EditDialog.ui @@ -56,7 +56,7 @@ false - Add + &Add @@ -66,7 +66,7 @@ false - Delete + &Delete @@ -82,7 +82,10 @@ - Text: + &Text: + + + fLocalizationText diff --git a/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc b/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc new file mode 100644 index 00000000..cba62bb3 --- /dev/null +++ b/Sources/Tools/plLocalizationEditor/res/plLocalizationEditor.rc @@ -0,0 +1 @@ +IDI_APPICON ICON DISCARDABLE "icon1.ico" From c78137c743c011d4d0e0fe5ac36924be84dff8d2 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 13 Apr 2014 18:12:24 -0700 Subject: [PATCH 5/9] Fixes for Linux compilation of plFontConverter --- CMakeLists.txt | 2 +- Sources/Tools/plFontConverter/plFontConverter.cpp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c8faa28..4f925405 100644 --- a/CMakeLists.txt +++ b/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... diff --git a/Sources/Tools/plFontConverter/plFontConverter.cpp b/Sources/Tools/plFontConverter/plFontConverter.cpp index 08890246..a44ef519 100644 --- a/Sources/Tools/plFontConverter/plFontConverter.cpp +++ b/Sources/Tools/plFontConverter/plFontConverter.cpp @@ -79,10 +79,6 @@ REGISTER_CREATABLE(plMipmap); #include -HINSTANCE gInstance; -char *gCommandLine = nil; -HWND gMainWindow = nil; - static void IAboutDialog(QWidget *parent) { QDialog dlg(parent); @@ -379,6 +375,7 @@ void plFontConverter::IImportBDF(const plFileName &path) IUpdateInfo(); } +#ifdef Q_OS_WIN struct ResRecord { HRSRC fHandle; @@ -414,6 +411,7 @@ static ResRecord DoSelectResource(const QList &resources) return ResRecord(); } +#endif void plFontConverter::IImportFON(const plFileName &path) { From aeb4c27c12c549194648f8039d476ecd0f61ec9a Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sat, 3 May 2014 19:51:05 -0700 Subject: [PATCH 6/9] Clean up localization mgr lookups and add some missing mnemonics --- .../pfLocalizationDataMgr.cpp | 47 ++++++++++++------- .../Tools/plLocalizationEditor/plEditDlg.cpp | 10 ++-- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp b/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp index 441151e9..c9811f23 100644 --- a/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp +++ b/Sources/Plasma/FeatureLib/pfLocalizationMgr/pfLocalizationDataMgr.cpp @@ -691,11 +691,14 @@ bool pfLocalizationDataMgr::pf3PartMap::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::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::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 pfLocalizationDataMgr::pf3PartMap::getSetList(const std::vector retVal; typename std::map >::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 pfLocalizationDataMgr::pf3PartMap::getNameList(const std::vector retVal; typename std::map::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; diff --git a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp index 686ed0a0..1dde33bc 100644 --- a/Sources/Tools/plLocalizationEditor/plEditDlg.cpp +++ b/Sources/Tools/plLocalizationEditor/plEditDlg.cpp @@ -127,7 +127,7 @@ void EditDialog::LoadLocalization(const plString &locPath) return; fCurrentLocPath = locPath; - fUI->fTextPathLabel->setText(QString("Text (%1):").arg(locPath.c_str())); + fUI->fTextPathLabel->setText(QString("&Text (%1):").arg(locPath.c_str())); plString ageName, setName, elementName, elementLanguage; SplitLocalizationPath(locPath, ageName, setName, elementName, elementLanguage); @@ -147,9 +147,9 @@ void EditDialog::LoadLocalization(const plString &locPath) if (!elementLanguage.IsEmpty()) // they have selected a language { fEditMode = kEditLocalization; - fUI->fAddButton->setText(tr("Add Localization")); + fUI->fAddButton->setText(tr("&Add Localization")); fUI->fAddButton->setEnabled(true); - fUI->fDeleteButton->setText(tr("Delete Localization")); + fUI->fDeleteButton->setText(tr("&Delete Localization")); // don't allow them to delete the default language fUI->fDeleteButton->setEnabled(elementLanguage != "English"); @@ -157,9 +157,9 @@ void EditDialog::LoadLocalization(const plString &locPath) else // they have selected something else { fEditMode = kEditElement; - fUI->fAddButton->setText(tr("Add Element")); + fUI->fAddButton->setText(tr("&Add Element")); fUI->fAddButton->setEnabled(true); - fUI->fDeleteButton->setText(tr("Delete Element")); + fUI->fDeleteButton->setText(tr("&Delete Element")); if (!elementName.IsEmpty()) // they have selected an individual element { std::vector elementNames = pfLocalizationDataMgr::Instance().GetElementList(ageName, setName); From 42661cc24735d492e61f1b3df22418cace0e4386 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 4 May 2014 11:31:24 -0700 Subject: [PATCH 7/9] Port plResBrowser to Qt5 --- Sources/Tools/plResBrowser/CMakeLists.txt | 85 ++- Sources/Tools/plResBrowser/plResBrowser.cpp | 418 +++++++++++-- Sources/Tools/plResBrowser/plResBrowser.h | 76 +++ .../plResBrowser/plResBrowserWndProc.cpp | 432 ------------- Sources/Tools/plResBrowser/plResTreeView.cpp | 497 +++------------ Sources/Tools/plResBrowser/plResTreeView.h | 51 +- .../Tools/plResBrowser/plWinRegistryTools.cpp | 73 ++- .../Tools/plResBrowser/plWinRegistryTools.h | 21 +- Sources/Tools/plResBrowser/res/FindDialog.ui | 76 +++ Sources/Tools/plResBrowser/res/ResBrowser.ui | 591 ++++++++++++++++++ .../Tools/plResBrowser/res/plResBrowser.qrc | 5 + .../Tools/plResBrowser/res/plResBrowser.rc | 203 +----- Sources/Tools/plResBrowser/res/resource.h | 68 -- 13 files changed, 1322 insertions(+), 1274 deletions(-) create mode 100644 Sources/Tools/plResBrowser/plResBrowser.h delete mode 100644 Sources/Tools/plResBrowser/plResBrowserWndProc.cpp create mode 100644 Sources/Tools/plResBrowser/res/FindDialog.ui create mode 100644 Sources/Tools/plResBrowser/res/ResBrowser.ui create mode 100644 Sources/Tools/plResBrowser/res/plResBrowser.qrc delete mode 100644 Sources/Tools/plResBrowser/res/resource.h diff --git a/Sources/Tools/plResBrowser/CMakeLists.txt b/Sources/Tools/plResBrowser/CMakeLists.txt index c08bed60..624b3401 100644 --- a/Sources/Tools/plResBrowser/CMakeLists.txt +++ b/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}) diff --git a/Sources/Tools/plResBrowser/plResBrowser.cpp b/Sources/Tools/plResBrowser/plResBrowser.cpp index abf61b92..3f88ce11 100644 --- a/Sources/Tools/plResBrowser/plResBrowser.cpp +++ b/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,374 @@ 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 +#include +#include +#include +#include +#include +#include -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 urls = event->mimeData()->urls(); + if (urls.size() == 0) + return; + + fUI->fTreeView->clear(); + hsgResMgr::Reset(); + plResManager *mgr = static_cast(hsgResMgr::ResMgr()); + + QString path = urls[0].toLocalFile(); + + if (urls.size() == 1 && urls[0].isLocalFile() && path.lastIndexOf('.') == -1) + { + // Must be a directory + std::vector 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(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(itemKey); + + if (keyImp->GetDataLen() <= 0) + return; + + plResManager *resMgr = static_cast(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(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 : "") + .arg(key->GetUoid().GetClassType())); + + plKeyImp *imp = static_cast(key); + if (showAsHex) + fUI->fStartPos->setText(QString("0x%1").arg(imp->GetStartPos(), 0, 16)); + else + fUI->fStartPos->setText(QString::number(imp->GetStartPos())); + + 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(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(hsgResMgr::ResMgr()); + + std::vector 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; +} diff --git a/Sources/Tools/plResBrowser/plResBrowser.h b/Sources/Tools/plResBrowser/plResBrowser.h new file mode 100644 index 00000000..9372db17 --- /dev/null +++ b/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 . + +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 + +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 diff --git a/Sources/Tools/plResBrowser/plResBrowserWndProc.cpp b/Sources/Tools/plResBrowser/plResBrowserWndProc.cpp deleted file mode 100644 index a4966f67..00000000 --- a/Sources/Tools/plResBrowser/plResBrowserWndProc.cpp +++ /dev/null @@ -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 . - -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 -#include -#include -#include -#include - -#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 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 prpFiles = plFileSystem::ListDir(path, "*.prp"); - for (auto iter = prpFiles.begin(); iter != prpFiles.end(); ++iter) - mgr->AddSinglePage(*iter); - } - else - { - hsTArray 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 ); -} - diff --git a/Sources/Tools/plResBrowser/plResTreeView.cpp b/Sources/Tools/plResBrowser/plResTreeView.cpp index fdca3da2..cd1afd71 100644 --- a/Sources/Tools/plResBrowser/plResTreeView.cpp +++ b/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 -#include -#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 +#include +#include 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*)""; - 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 : "", 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(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(-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 : "", 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 : "", 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 - -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(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")); +} diff --git a/Sources/Tools/plResBrowser/plResTreeView.h b/Sources/Tools/plResBrowser/plResTreeView.h index 9281e714..fb9e9a3e 100644 --- a/Sources/Tools/plResBrowser/plResTreeView.h +++ b/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 + +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 diff --git a/Sources/Tools/plResBrowser/plWinRegistryTools.cpp b/Sources/Tools/plResBrowser/plWinRegistryTools.cpp index 46ef0538..07704756 100644 --- a/Sources/Tools/plResBrowser/plWinRegistryTools.cpp +++ b/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 +#include ////////////////////////////////////////////////////////////////////////////// @@ -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, ®Key, &result ) != ERROR_SUCCESS ) + if (::RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName.toStdWString().c_str(), 0, + nullptr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, + nullptr, ®Key, &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(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); } diff --git a/Sources/Tools/plResBrowser/plWinRegistryTools.h b/Sources/Tools/plResBrowser/plWinRegistryTools.h index faa77949..e8c61ce1 100644 --- a/Sources/Tools/plResBrowser/plWinRegistryTools.h +++ b/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 \ No newline at end of file +#endif //_plWinRegistryTools_h diff --git a/Sources/Tools/plResBrowser/res/FindDialog.ui b/Sources/Tools/plResBrowser/res/FindDialog.ui new file mode 100644 index 00000000..cc41e350 --- /dev/null +++ b/Sources/Tools/plResBrowser/res/FindDialog.ui @@ -0,0 +1,76 @@ + + + FindDialog + + + + 0 + 0 + 320 + 71 + + + + Find Object + + + + + + Object Name + + + + + + + + + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FindDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FindDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Sources/Tools/plResBrowser/res/ResBrowser.ui b/Sources/Tools/plResBrowser/res/ResBrowser.ui new file mode 100644 index 00000000..b020eae8 --- /dev/null +++ b/Sources/Tools/plResBrowser/res/ResBrowser.ui @@ -0,0 +1,591 @@ + + + ResBrowser + + + + 0 + 0 + 800 + 600 + + + + plResBrowser + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + false + + + + 1 + + + + + + + + + + 0 + 0 + 800 + 21 + + + + + &File + + + + + + + + + + + + + + + &Help + + + + + + + + + + 300 + 520 + + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea + + + Properties + + + 2 + + + + + 0 + 0 + + + + + 300 + 0 + + + + + 300 + 16777215 + + + + + + + Page Information + + + + + + Age: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + + + + true + + + + + + + Data Version: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Location: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Page + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + Checksum: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + + false + + + + + + + + + + + 0 + 0 + + + + Local Only + + + + + + + + 0 + 0 + + + + Reserved + + + + + + + + 0 + 0 + + + + Volatile + + + + + + + + 0 + 0 + + + + Built-In + + + + + + + + + true + + + + + + + Checksum Type: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 40 + + + + + + + + + + + Object Information + + + + + + Start Pos: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Name: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Class: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + + + + + Size: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 0 + 20 + + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 0 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + View values as he&x + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Fin&d + + + + + + + Find &Next + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + &Save Object + + + + + + + + + + + &Open... + + + + + Open &Directory... + + + + + false + + + &Save Selected Object + + + + + &Find Object... + + + Ctrl+F + + + + + Find &Next + + + F3 + + + + + true + + + Show Only &Loadable + + + + + E&xit + + + + + &About... + + + + + + plResTreeView + QTreeWidget +
plResTreeView.h
+
+
+ + +
diff --git a/Sources/Tools/plResBrowser/res/plResBrowser.qrc b/Sources/Tools/plResBrowser/res/plResBrowser.qrc new file mode 100644 index 00000000..81055f95 --- /dev/null +++ b/Sources/Tools/plResBrowser/res/plResBrowser.qrc @@ -0,0 +1,5 @@ + + + icon1.ico + + diff --git a/Sources/Tools/plResBrowser/res/plResBrowser.rc b/Sources/Tools/plResBrowser/res/plResBrowser.rc index f63d2146..267a81d9 100644 --- a/Sources/Tools/plResBrowser/res/plResBrowser.rc +++ b/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 -#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 - diff --git a/Sources/Tools/plResBrowser/res/resource.h b/Sources/Tools/plResBrowser/res/resource.h deleted file mode 100644 index ea16ff89..00000000 --- a/Sources/Tools/plResBrowser/res/resource.h +++ /dev/null @@ -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 From c2754b3993be004836b9c803bd388ee43b75c40f Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Sun, 4 May 2014 11:35:46 -0700 Subject: [PATCH 8/9] Show size as hex too if requested --- Sources/Tools/plResBrowser/plResBrowser.cpp | 17 +++- Sources/Tools/plResBrowser/res/ResBrowser.ui | 100 ++++++++----------- 2 files changed, 54 insertions(+), 63 deletions(-) diff --git a/Sources/Tools/plResBrowser/plResBrowser.cpp b/Sources/Tools/plResBrowser/plResBrowser.cpp index 3f88ce11..daeb01fa 100644 --- a/Sources/Tools/plResBrowser/plResBrowser.cpp +++ b/Sources/Tools/plResBrowser/plResBrowser.cpp @@ -321,12 +321,19 @@ void plResBrowser::UpdateInfoPage() else fUI->fStartPos->setText(QString::number(imp->GetStartPos())); - 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)); + if (showAsHex) + { + fUI->fObjectSize->setText(QString("0x%1").arg(imp->GetDataLen(), 0, 16)); + } else - fUI->fObjectSize->setText(QString("%1 MB").arg(imp->GetDataLen() / 1024.f / 1024.f, 0, 'f', 2)); + { + 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); diff --git a/Sources/Tools/plResBrowser/res/ResBrowser.ui b/Sources/Tools/plResBrowser/res/ResBrowser.ui index b020eae8..9fdc3687 100644 --- a/Sources/Tools/plResBrowser/res/ResBrowser.ui +++ b/Sources/Tools/plResBrowser/res/ResBrowser.ui @@ -342,30 +342,26 @@ Object Information - - - - Start Pos: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + Qt::Vertical - - - - - - Name: + + QSizePolicy::Fixed - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 0 + 20 + - + - - + + - Class: + Size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -380,68 +376,56 @@ - + + + true + + + + + - Size: + Start Pos: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - Qt::Vertical - - - QSizePolicy::Fixed + + + + Name: - - - 0 - 20 - + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - - - - true + + + + Class: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - + + true - - + + true - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 16 - 0 - - - - From 14dbc7b10d67ae8db78ed72bfdfad5ad1a94c30c Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 19 May 2014 20:17:53 -0700 Subject: [PATCH 9/9] Added line to readme about Qt5 dependency --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0f7fca61..f87a9e51 100644 --- a/README.md +++ b/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.