From b23bb935068e2fb63b92c7270ff72018272f9e0c Mon Sep 17 00:00:00 2001 From: elasota Date: Sat, 12 Sep 2020 22:29:57 -0400 Subject: [PATCH] Redo file prompts with in-game UI --- Aerofoil/GpFileSystem_Win32.cpp | 237 ++---- Aerofoil/GpFileSystem_Win32.h | 4 +- ApplicationResourcePatches/DITL/2001.json | 45 ++ ApplicationResourcePatches/DITL/2002.json | 53 ++ ApplicationResourcePatches/DITL/2003.json | 29 + ApplicationResourcePatches/DITL/2004.json | 21 + ApplicationResourcePatches/manifest.json | 6 +- GpApp/About.cpp | 12 +- GpApp/HighScores.cpp | 12 +- GpApp/House.cpp | 8 +- GpApp/HouseInfo.cpp | 6 +- GpApp/Link.cpp | 2 +- GpApp/Map.cpp | 12 +- GpApp/ObjectInfo.cpp | 52 +- GpApp/RoomInfo.cpp | 12 +- GpApp/SavedGames.cpp | 4 +- GpApp/SelectHouse.cpp | 4 +- GpApp/Settings.cpp | 22 +- GpApp/Tools.cpp | 2 +- PortabilityLayer/DialogManager.cpp | 22 +- PortabilityLayer/FileBrowserUI.cpp | 680 ++++++++++++++++++ PortabilityLayer/FileBrowserUI.h | 20 + PortabilityLayer/FileManager.cpp | 14 +- PortabilityLayer/FileManager.h | 4 +- PortabilityLayer/HostFileSystem.h | 3 +- PortabilityLayer/PLButtonWidget.cpp | 6 +- PortabilityLayer/PLButtonWidget.h | 4 +- PortabilityLayer/PLDialogs.h | 4 +- PortabilityLayer/PLEditboxWidget.cpp | 31 +- PortabilityLayer/PLEditboxWidget.h | 10 +- PortabilityLayer/PLIconWidget.cpp | 2 +- PortabilityLayer/PLIconWidget.h | 2 +- PortabilityLayer/PLInvisibleWidget.cpp | 2 +- PortabilityLayer/PLInvisibleWidget.h | 2 +- PortabilityLayer/PLPopupMenuWidget.cpp | 6 +- PortabilityLayer/PLPopupMenuWidget.h | 4 +- PortabilityLayer/PLScrollBarWidget.cpp | 36 +- PortabilityLayer/PLScrollBarWidget.h | 12 +- PortabilityLayer/PLSysCalls.cpp | 59 -- PortabilityLayer/PLSysCalls.h | 2 - PortabilityLayer/PLWidgets.cpp | 10 +- PortabilityLayer/PLWidgets.h | 9 +- PortabilityLayer/PortabilityLayer.vcxproj | 2 + .../PortabilityLayer.vcxproj.filters | 6 + 44 files changed, 1133 insertions(+), 362 deletions(-) create mode 100644 ApplicationResourcePatches/DITL/2001.json create mode 100644 ApplicationResourcePatches/DITL/2002.json create mode 100644 ApplicationResourcePatches/DITL/2003.json create mode 100644 ApplicationResourcePatches/DITL/2004.json create mode 100644 PortabilityLayer/FileBrowserUI.cpp create mode 100644 PortabilityLayer/FileBrowserUI.h diff --git a/Aerofoil/GpFileSystem_Win32.cpp b/Aerofoil/GpFileSystem_Win32.cpp index 14d1c83..865cc03 100644 --- a/Aerofoil/GpFileSystem_Win32.cpp +++ b/Aerofoil/GpFileSystem_Win32.cpp @@ -286,172 +286,24 @@ PortabilityLayer::HostDirectoryCursor *GpFileSystem_Win32::ScanDirectory(Portabi return GpDirectoryCursor_Win32::Create(ff, findData); } -bool GpFileSystem_Win32::PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) +bool GpFileSystem_Win32::ValidateFilePathUnicodeChar(uint32_t c) const { - wchar_t baseFN[MAX_PATH + 5]; - wchar_t baseDir[MAX_PATH + 5]; + if (c >= '0' && c <= '9') + return true; - const size_t existingPathLen = strlen(initialFileName); - if (existingPathLen >= MAX_PATH) - return false; + if (c == '_' || c == '\'') + return true; - for (size_t i = 0; i < existingPathLen; i++) - baseFN[i] = static_cast(initialFileName[i]); - baseFN[existingPathLen] = 0; + if (c == ' ') + return true; - if (!ResolvePath(virtualDirectory, "", baseDir)) - return false; + if (c >= 'a' && c <= 'z') + return true; - OPENFILENAMEW ofn; - memset(&ofn, 0, sizeof(ofn)); + if (c >= 'A' && c <= 'Z') + return true; - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = GP_APPLICATION_NAME_W L" File (*.gpf)\0*.gpf\0"; - ofn.lpstrFile = baseFN; - ofn.lpstrDefExt = L"gpf"; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrInitialDir = baseDir; - ofn.Flags = OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT; - ofn.hwndOwner = g_gpWindowsGlobals.m_hwnd; - - if (!GetSaveFileNameW(&ofn)) - return false; - - if (ofn.Flags & OFN_EXTENSIONDIFFERENT) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, L"Save file failed: Saved files must have the '.gpf' extension", L"Invalid file path", MB_OK); - return false; - } - - const wchar_t *fn = ofn.lpstrFile + ofn.nFileOffset; - size_t fnLengthWithoutExt = wcslen(fn); - if (ofn.nFileExtension - 1 > ofn.nFileOffset) // Off by 1 because extension doesn't include . - fnLengthWithoutExt = ofn.nFileExtension - ofn.nFileOffset - 1; - - if (fnLengthWithoutExt >= pathCapacity) - { - wchar_t msg[256]; - wsprintfW(msg, L"Save file failed: File name is too long. Limit is %i characters.", static_cast(pathCapacity)); - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, msg, L"Invalid file path", MB_OK); - return false; - } - - if (ofn.nFileOffset != wcslen(baseDir) || memcmp(ofn.lpstrFile, baseDir, ofn.nFileOffset * sizeof(wchar_t))) - { - wchar_t msg[256 + MAX_PATH]; - wsprintfW(msg, L"Save file failed: File can't be saved here, it must be saved in %s", baseDir); - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, msg, L"Invalid file path", MB_OK); - return false; - } - - const wchar_t *unsupportedCharMsg = L"File name contains unsupported characters."; - - for (size_t i = 0; i < fnLengthWithoutExt; i++) - { - if (fn[i] < static_cast(0) || fn[i] >= static_cast(128)) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK); - return false; - } - - path[i] = static_cast(fn[i]); - } - - if (!ValidateFilePath(path, fnLengthWithoutExt)) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK); - return false; - } - - outPathLength = fnLengthWithoutExt; - - return true; -} - -bool GpFileSystem_Win32::PromptOpenFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity) -{ - wchar_t baseFN[MAX_PATH + 5]; - wchar_t baseDir[MAX_PATH + 5]; - - baseFN[0] = 0; - - if (!ResolvePath(virtualDirectory, "", baseDir)) - return false; - - OPENFILENAMEW ofn; - memset(&ofn, 0, sizeof(ofn)); - - ofn.lStructSize = sizeof(ofn); - ofn.lpstrFilter = GP_APPLICATION_NAME_W L" File (*.gpf)\0*.gpf\0"; - ofn.lpstrFile = baseFN; - ofn.lpstrDefExt = L"gpf"; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrInitialDir = baseDir; - ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST; - ofn.hwndOwner = g_gpWindowsGlobals.m_hwnd; - - if (!GetOpenFileNameW(&ofn)) - return false; - - if (ofn.Flags & OFN_EXTENSIONDIFFERENT) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, L"Open file failed: Files must have the '.gpf' extension", L"Invalid file path", MB_OK); - return false; - } - - const wchar_t *fn = ofn.lpstrFile + ofn.nFileOffset; - size_t fnLengthWithoutExt = wcslen(fn); - if (ofn.nFileExtension - 1 > ofn.nFileOffset) // Off by 1 because extension doesn't include . - fnLengthWithoutExt = ofn.nFileExtension - ofn.nFileOffset - 1; - - if (fnLengthWithoutExt >= pathCapacity) - { - wchar_t msg[256]; - wsprintfW(msg, L"Open file failed: File name is too long. Limit is %i characters.", static_cast(pathCapacity)); - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, msg, L"Invalid file path", MB_OK); - return false; - } - - if (ofn.nFileOffset != wcslen(baseDir) || memcmp(ofn.lpstrFile, baseDir, ofn.nFileOffset * sizeof(wchar_t))) - { - wchar_t msg[256 + MAX_PATH]; - wsprintfW(msg, L"Open file failed: File can't be opened from here, it must be in %s", baseDir); - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, msg, L"Invalid file path", MB_OK); - return false; - } - - const wchar_t *unsupportedCharMsg = L"File name contains unsupported characters."; - - for (size_t i = 0; i < fnLengthWithoutExt; i++) - { - if (fn[i] < static_cast(0) || fn[i] >= static_cast(128)) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK); - return false; - } - - path[i] = static_cast(fn[i]); - } - - if (!ValidateFilePath(path, fnLengthWithoutExt)) - { - MessageBeep(MB_ICONERROR); - MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK); - return false; - } - - outPathLength = fnLengthWithoutExt; - - return true; + return false; } bool GpFileSystem_Win32::ValidateFilePath(const char *str, size_t length) const @@ -477,6 +329,71 @@ bool GpFileSystem_Win32::ValidateFilePath(const char *str, size_t length) const return false; } + const char *bannedNames[] = + { + "CON", + "PRN", + "AUX", + "NUL", + "COM1", + "COM2", + "COM3", + "COM4", + "COM5", + "COM6", + "COM7", + "COM8", + "COM9", + "LPT1", + "LPT2", + "LPT3", + "LPT4", + "LPT5", + "LPT6", + "LPT7", + "LPT8", + "LPT9" + }; + + size_t nameLengthWithoutExt = length; + for (size_t i = 0; i < length; i++) + { + if (str[i] == '.') + { + nameLengthWithoutExt = i; + break; + } + } + + const size_t numBannedNames = sizeof(bannedNames) / sizeof(bannedNames[0]); + + for (size_t i = 0; i < numBannedNames; i++) + { + const char *bannedName = bannedNames[i]; + const size_t banLength = strlen(bannedName); + + if (banLength == nameLengthWithoutExt) + { + bool isBanned = true; + + for (size_t j = 0; j < banLength; j++) + { + char checkCH = str[j]; + if (checkCH >= 'a' && checkCH <= 'z') + checkCH += ('A' - 'a'); + + if (bannedName[j] != checkCH) + { + isBanned = false; + break; + } + } + + if (isBanned) + return false; + } + } + return true; } diff --git a/Aerofoil/GpFileSystem_Win32.h b/Aerofoil/GpFileSystem_Win32.h index 739f8ae..d19cb53 100644 --- a/Aerofoil/GpFileSystem_Win32.h +++ b/Aerofoil/GpFileSystem_Win32.h @@ -18,10 +18,8 @@ public: bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override; PortabilityLayer::HostDirectoryCursor *ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) override; - bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) override; - bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) override; - bool ValidateFilePath(const char *path, size_t sz) const override; + bool ValidateFilePathUnicodeChar(uint32_t ch) const override; const wchar_t *GetBasePath() const; diff --git a/ApplicationResourcePatches/DITL/2001.json b/ApplicationResourcePatches/DITL/2001.json new file mode 100644 index 0000000..e4b9dc1 --- /dev/null +++ b/ApplicationResourcePatches/DITL/2001.json @@ -0,0 +1,45 @@ +{ + "items" : + [ + { + "name" : "Okay", + "itemType" : "Button", + "pos" : [ 376, 240 ], + "size" : [ 58, 20 ], + "id" : 1, + "enabled" : false + }, + { + "name" : "Cancel", + "itemType" : "Button", + "pos" : [ 302, 240 ], + "size" : [ 58, 20 ], + "id" : 2, + "enabled" : true + }, + { + "name" : "", + "itemType" : "CustomControl", + "pos" : [ 17, 33 ], + "size" : [ 401, 190 ], + "id" : 2, + "enabled" : true + }, + { + "name" : "", + "itemType" : "CustomControl", + "pos" : [ 418, 32 ], + "size" : [ 16, 192 ], + "id" : 3, + "enabled" : true + }, + { + "name" : "^0", + "itemType" : "Label", + "pos" : [ 16, 16 ], + "size" : [ 418, 16 ], + "id" : 10, + "enabled" : true + } + ] +} \ No newline at end of file diff --git a/ApplicationResourcePatches/DITL/2002.json b/ApplicationResourcePatches/DITL/2002.json new file mode 100644 index 0000000..4df0d21 --- /dev/null +++ b/ApplicationResourcePatches/DITL/2002.json @@ -0,0 +1,53 @@ +{ + "items" : + [ + { + "name" : "Okay", + "itemType" : "Button", + "pos" : [ 376, 240 ], + "size" : [ 58, 20 ], + "id" : 1, + "enabled" : true + }, + { + "name" : "Cancel", + "itemType" : "Button", + "pos" : [ 302, 240 ], + "size" : [ 58, 20 ], + "id" : 2, + "enabled" : true + }, + { + "name" : "", + "itemType" : "CustomControl", + "pos" : [ 17, 33 ], + "size" : [ 401, 186 ], + "id" : 2, + "enabled" : true + }, + { + "name" : "", + "itemType" : "CustomControl", + "pos" : [ 418, 32 ], + "size" : [ 16, 188 ], + "id" : 3, + "enabled" : true + }, + { + "name" : "", + "itemType" : "EditBox", + "pos" : [ 16, 240 ], + "size" : [ 270, 16 ], + "id" : 4, + "enabled" : true + }, + { + "name" : "^0", + "itemType" : "Label", + "pos" : [ 16, 16 ], + "size" : [ 418, 16 ], + "id" : 10, + "enabled" : true + } + ] +} \ No newline at end of file diff --git a/ApplicationResourcePatches/DITL/2003.json b/ApplicationResourcePatches/DITL/2003.json new file mode 100644 index 0000000..a08c725 --- /dev/null +++ b/ApplicationResourcePatches/DITL/2003.json @@ -0,0 +1,29 @@ +{ + "items" : + [ + { + "name" : "No", + "itemType" : "Button", + "pos" : [ 253, 99 ], + "size" : [ 58, 20 ], + "id" : 1, + "enabled" : true + }, + { + "name" : "Yes", + "itemType" : "Button", + "pos" : [ 184, 99 ], + "size" : [ 58, 20 ], + "id" : 2, + "enabled" : true + }, + { + "name" : "^0 already exists.\rDo you want to replace it?", + "itemType" : "Label", + "pos" : [ 16, 16 ], + "size" : [ 295, 74 ], + "id" : 0, + "enabled" : false + } + ] +} \ No newline at end of file diff --git a/ApplicationResourcePatches/DITL/2004.json b/ApplicationResourcePatches/DITL/2004.json new file mode 100644 index 0000000..ee271db --- /dev/null +++ b/ApplicationResourcePatches/DITL/2004.json @@ -0,0 +1,21 @@ +{ + "items" : + [ + { + "name" : "Okay", + "itemType" : "Button", + "pos" : [ 253, 99 ], + "size" : [ 58, 20 ], + "id" : 0, + "enabled" : true + }, + { + "name" : "The file name that you've specified is invalid.", + "itemType" : "Label", + "pos" : [ 16, 16 ], + "size" : [ 295, 74 ], + "id" : 0, + "enabled" : false + } + ] +} \ No newline at end of file diff --git a/ApplicationResourcePatches/manifest.json b/ApplicationResourcePatches/manifest.json index 138a1f8..df473e1 100644 --- a/ApplicationResourcePatches/manifest.json +++ b/ApplicationResourcePatches/manifest.json @@ -2,7 +2,11 @@ "add" : { "DITL/1017.json" : "ApplicationResourcePatches/DITL/1017.json", - "DITL/2000.json" : "ApplicationResourcePatches/DITL/2000.json" + "DITL/2000.json" : "ApplicationResourcePatches/DITL/2000.json", + "DITL/2001.json" : "ApplicationResourcePatches/DITL/2001.json", + "DITL/2002.json" : "ApplicationResourcePatches/DITL/2002.json", + "DITL/2003.json" : "ApplicationResourcePatches/DITL/2003.json", + "DITL/2004.json" : "ApplicationResourcePatches/DITL/2004.json" }, "delete" : [ diff --git a/GpApp/About.cpp b/GpApp/About.cpp index ea52f68..865911b 100644 --- a/GpApp/About.cpp +++ b/GpApp/About.cpp @@ -38,8 +38,8 @@ static void HiLiteOkayButton (DrawSurface *surface); static void UnHiLiteOkayButton (DrawSurface *surface); static void UpdateMainPict (Dialog *); -static int16_t AboutFilter(Dialog *, const TimeTaggedVOSEvent *evt); -static int16_t AboutFrameworkFilter(Dialog *, const TimeTaggedVOSEvent *evt); +static int16_t AboutFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt); +static int16_t AboutFrameworkFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt); static Point okayButtLowerV, okayButtUpperV; @@ -91,7 +91,7 @@ void DoAbout (void) do // Loop until user wants to exit { - hit = aboutDialog->ExecuteModal(AboutFilter); + hit = aboutDialog->ExecuteModal(nullptr, AboutFilter); } while (hit != kOkayButton); @@ -152,7 +152,7 @@ void DoAboutFramework (void) do { - hit = dialog->ExecuteModal(AboutFrameworkFilter); + hit = dialog->ExecuteModal(nullptr, AboutFrameworkFilter); } while (hit != kOkayButton); dialog->Destroy(); @@ -248,7 +248,7 @@ static bool PointIsInDiagonalOkayButton(const Point &pt) //-------------------------------------------------------------- AboutFilter // Dialog filter for the About dialog. -static int16_t AboutFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) +static int16_t AboutFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt) { bool handledIt = false; int16_t hit = -1; @@ -330,7 +330,7 @@ static int16_t AboutFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- AboutFrameworkFilter // Dialog filter for the About Framework dialog. -static int16_t AboutFrameworkFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) +static int16_t AboutFrameworkFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt) { bool handledIt = false; int16_t hit = -1; diff --git a/GpApp/HighScores.cpp b/GpApp/HighScores.cpp index 686ef24..eb73da7 100644 --- a/GpApp/HighScores.cpp +++ b/GpApp/HighScores.cpp @@ -41,10 +41,10 @@ void DrawHighScores (DrawSurface *); void UpdateNameDialog (Dialog *); -int16_t NameFilter (Dialog *dial, const TimeTaggedVOSEvent *evt); +int16_t NameFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt); void GetHighScoreName (short); void UpdateBannerDialog (Dialog *); -int16_t BannerFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); +int16_t BannerFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); void GetHighScoreBanner (void); Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream); @@ -456,7 +456,7 @@ static bool EventIsTyping(const GpKeyboardInputEvent &kbEvent) //-------------------------------------------------------------- NameFilter // Dialog filter for the "Enter High Score Name" dialog. -int16_t NameFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t NameFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { short nChars; @@ -537,7 +537,7 @@ void GetHighScoreName (short place) while (!leaving) { - item = theDial->ExecuteModal(NameFilter); + item = theDial->ExecuteModal(nullptr, NameFilter); if (item == kOkayButton) { @@ -571,7 +571,7 @@ void UpdateBannerDialog (Dialog *theDialog) //-------------------------------------------------------------- BannerFilter // Dialog filter for the "Enter Message" dialog. -int16_t BannerFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t BannerFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { short nChars; @@ -647,7 +647,7 @@ void GetHighScoreBanner (void) while (!leaving) { - item = theDial->ExecuteModal(BannerFilter); + item = theDial->ExecuteModal(nullptr, BannerFilter); if (item == kOkayButton) { diff --git a/GpApp/House.cpp b/GpApp/House.cpp index 9b4f219..3076662 100644 --- a/GpApp/House.cpp +++ b/GpApp/House.cpp @@ -26,7 +26,7 @@ void UpdateGoToDialog (Dialog *); -int16_t GoToFilter (Dialog *dial, const TimeTaggedVOSEvent *evt); +int16_t GoToFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt); extern PortabilityLayer::ResourceArchive *houseResFork; @@ -67,7 +67,7 @@ Boolean CreateNewHouse (void) char savePath[sizeof(theSpec.m_name) + 1]; size_t savePathLength = 0; - if (!fm->PromptSaveFile(theSpec.m_dir, savePath, savePathLength, sizeof(theSpec.m_name), PSTR("My House"))) + if (!fm->PromptSaveFile(theSpec.m_dir, savePath, savePathLength, sizeof(theSpec.m_name), PSTR("My House"), PSTR("Create House"))) return false; assert(savePathLength < sizeof(theSpec.m_name) - 1); @@ -599,7 +599,7 @@ void UpdateGoToDialog (Dialog *theDialog) //-------------------------------------------------------------- GoToFilter // Dialog filter for the "Go To Room..." dialog. -int16_t GoToFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t GoToFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -656,7 +656,7 @@ int16_t GoToFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) while (!leaving) { - item = theDialog->ExecuteModal(GoToFilter); + item = theDialog->ExecuteModal(nullptr, GoToFilter); if (item == kOkayButton) { diff --git a/GpApp/HouseInfo.cpp b/GpApp/HouseInfo.cpp index c9c29fa..6e6e2c6 100644 --- a/GpApp/HouseInfo.cpp +++ b/GpApp/HouseInfo.cpp @@ -34,7 +34,7 @@ long CountTotalHousePoints (void); void UpdateHouseInfoDialog (Dialog *); -int16_t HouseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt); +int16_t HouseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt); Boolean WarnLockingHouse (void); void HowToZeroScores (void); @@ -123,7 +123,7 @@ void UpdateHouseInfoDialog (Dialog *theDialog) //-------------------------------------------------------------- HouseFilter -int16_t HouseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t HouseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { Point mouseIs; short nChars; @@ -248,7 +248,7 @@ void DoHouseInfo (void) while (!leaving) { - item = houseInfoDialog->ExecuteModal(HouseFilter); + item = houseInfoDialog->ExecuteModal(nullptr, HouseFilter); if (item == kOkayButton) { diff --git a/GpApp/Link.cpp b/GpApp/Link.cpp index c1ba9dc..b7a48c7 100644 --- a/GpApp/Link.cpp +++ b/GpApp/Link.cpp @@ -383,7 +383,7 @@ void HandleLinkClick (Point wherePt) part = FindControl(wherePt, linkWindow, &theControl); if ((theControl != nil) && (part != 0)) { - part = theControl->Capture(wherePt, nullptr); + part = theControl->Capture(nullptr, wherePt, nullptr); if (part != 0) { if (theControl == linkControl) diff --git a/GpApp/Map.cpp b/GpApp/Map.cpp index 0992c8c..da5d644 100644 --- a/GpApp/Map.cpp +++ b/GpApp/Map.cpp @@ -489,7 +489,7 @@ void ToggleMapWindow (void) //-------------------------------------------------------------- LiveHScrollAction #ifndef COMPILEDEMO -void LiveHScrollAction (PortabilityLayer::Widget *theControl, int thePart) +void LiveHScrollAction (void *captureContext, PortabilityLayer::Widget *theControl, int thePart) { short wasValue, newValue; @@ -546,7 +546,7 @@ void LiveHScrollAction (PortabilityLayer::Widget *theControl, int thePart) //-------------------------------------------------------------- LiveVScrollAction #ifndef COMPILEDEMO -void LiveVScrollAction (PortabilityLayer::Widget *theControl, int thePart) +void LiveVScrollAction (void *captureContext, PortabilityLayer::Widget *theControl, int thePart) { short wasValue, newValue; @@ -695,11 +695,11 @@ void HandleMapClick (const GpMouseInputEvent &theEvent) case kControlDownButtonPart: case kControlPageUpPart: case kControlPageDownPart: - whichControl->Capture(wherePt, LiveHScrollAction); + whichControl->Capture(nullptr, wherePt, LiveHScrollAction); break; case kControlIndicatorPart: - if (whichControl->Capture(wherePt, nil)) + if (whichControl->Capture(nullptr, wherePt, nil)) { mapLeftRoom = whichControl->GetState(); RedrawMapContents(); @@ -715,11 +715,11 @@ void HandleMapClick (const GpMouseInputEvent &theEvent) case kControlDownButtonPart: case kControlPageUpPart: case kControlPageDownPart: - whichControl->Capture(wherePt, LiveVScrollAction); + whichControl->Capture(nullptr, wherePt, LiveVScrollAction); break; case kControlIndicatorPart: - if (whichControl->Capture(wherePt, nil)) + if (whichControl->Capture(nullptr, wherePt, nil)) { mapTopRoom = whichControl->GetState(); RedrawMapContents(); diff --git a/GpApp/ObjectInfo.cpp b/GpApp/ObjectInfo.cpp index b8ff680..7c4281c 100644 --- a/GpApp/ObjectInfo.cpp +++ b/GpApp/ObjectInfo.cpp @@ -347,7 +347,7 @@ void UpdateFlowerInfo (Dialog *theDialog) //-------------------------------------------------------------- BlowerFilter -int16_t BlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t BlowerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -381,7 +381,7 @@ int16_t BlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- FurnitureFilter -int16_t FurnitureFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t FurnitureFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -407,7 +407,7 @@ int16_t FurnitureFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- CustPictFilter -int16_t CustPictFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t CustPictFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -431,7 +431,7 @@ int16_t CustPictFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- SwitchFilter -int16_t SwitchFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t SwitchFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -459,7 +459,7 @@ int16_t SwitchFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- TriggerFilter -int16_t TriggerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t TriggerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -491,7 +491,7 @@ int16_t TriggerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- LightFilter -int16_t LightFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t LightFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -519,7 +519,7 @@ int16_t LightFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- ApplianceFilter -int16_t ApplianceFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t ApplianceFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -551,7 +551,7 @@ int16_t ApplianceFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- MicrowaveFilter -int16_t MicrowaveFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t MicrowaveFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -579,7 +579,7 @@ int16_t MicrowaveFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- GreaseFilter -int16_t GreaseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t GreaseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -607,7 +607,7 @@ int16_t GreaseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- InvisBonusFilter -int16_t InvisBonusFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t InvisBonusFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -631,7 +631,7 @@ int16_t InvisBonusFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- TransFilter -int16_t TransFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t TransFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -659,7 +659,7 @@ int16_t TransFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- EnemyFilter -int16_t EnemyFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t EnemyFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -691,7 +691,7 @@ int16_t EnemyFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) //-------------------------------------------------------------- FlowerFilter -int16_t FlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t FlowerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -785,7 +785,7 @@ void DoBlowerObjectInfo (short what) { bool redrawMain = false; - item = infoDial->ExecuteModal(BlowerFilter); + item = infoDial->ExecuteModal(nullptr, BlowerFilter); if (item == kOkayButton) { @@ -937,7 +937,7 @@ void DoFurnitureObjectInfo (void) while (!leaving) { - item = infoDial->ExecuteModal(FurnitureFilter); + item = infoDial->ExecuteModal(nullptr, FurnitureFilter); if (item == kOkayButton) leaving = true; @@ -997,7 +997,7 @@ void DoCustPictObjectInfo (void) { bool redrawMain = false; - item = infoDial->ExecuteModal(CustPictFilter); + item = infoDial->ExecuteModal(nullptr, CustPictFilter); if (item == kOkayButton) { @@ -1106,7 +1106,7 @@ void DoSwitchObjectInfo (void) while (!leaving) { - item = infoDial->ExecuteModal(SwitchFilter); + item = infoDial->ExecuteModal(nullptr, SwitchFilter); if (item == kOkayButton) { @@ -1231,7 +1231,7 @@ void DoTriggerObjectInfo (void) while (!leaving) { - item = infoDial->ExecuteModal(TriggerFilter); + item = infoDial->ExecuteModal(nullptr, TriggerFilter); if (item == kOkayButton) { @@ -1371,7 +1371,7 @@ void DoLightObjectInfo (void) while (!leaving) { bool redrawMain = false; - item = infoDial->ExecuteModal(LightFilter); + item = infoDial->ExecuteModal(nullptr, LightFilter); if (item == kOkayButton) { @@ -1465,7 +1465,7 @@ void DoApplianceObjectInfo (short what) while (!leaving) { bool redrawMain = false; - item = infoDial->ExecuteModal(ApplianceFilter); + item = infoDial->ExecuteModal(nullptr, ApplianceFilter); if (item == kOkayButton) { @@ -1585,7 +1585,7 @@ void DoMicrowaveObjectInfo (void) while (!leaving) { bool redrawMain = false; - item = infoDial->ExecuteModal(MicrowaveFilter); + item = infoDial->ExecuteModal(nullptr, MicrowaveFilter); if (item == kOkayButton) { @@ -1695,7 +1695,7 @@ void DoGreaseObjectInfo (void) { bool redrawMain = false; - item = infoDial->ExecuteModal(GreaseFilter); + item = infoDial->ExecuteModal(nullptr, GreaseFilter); if (item == kOkayButton) { @@ -1783,7 +1783,7 @@ void DoInvisBonusObjectInfo (void) while (!leaving) { - item = infoDial->ExecuteModal(InvisBonusFilter); + item = infoDial->ExecuteModal(nullptr, InvisBonusFilter); if (item == kOkayButton) { @@ -1907,7 +1907,7 @@ void DoTransObjectInfo (short what) while (!leaving) { - item = infoDial->ExecuteModal(TransFilter); + item = infoDial->ExecuteModal(nullptr, TransFilter); if (item == kOkayButton) { @@ -2017,7 +2017,7 @@ void DoEnemyObjectInfo (short what) while (!leaving) { - item = infoDial->ExecuteModal(EnemyFilter); + item = infoDial->ExecuteModal(nullptr, EnemyFilter); if (item == kOkayButton) { @@ -2113,7 +2113,7 @@ void DoFlowerObjectInfo (void) { bool redrawMain = false; - item = infoDial->ExecuteModal(FlowerFilter); + item = infoDial->ExecuteModal(nullptr, FlowerFilter); if (item == kOkayButton) { diff --git a/GpApp/RoomInfo.cpp b/GpApp/RoomInfo.cpp index 236626e..0bc1236 100644 --- a/GpApp/RoomInfo.cpp +++ b/GpApp/RoomInfo.cpp @@ -47,11 +47,11 @@ void UpdateRoomInfoDialog (Dialog *); void DragMiniTile (Window *, DrawSurface *, Point, short *); void HiliteTileOver (DrawSurface *, Point); -int16_t RoomFilter (Dialog *dialog, const TimeTaggedVOSEvent *evt); +int16_t RoomFilter (void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); short ChooseOriginalArt (short); void UpdateOriginalArt (Dialog *); -int16_t OriginalArtFilter (Dialog *dialog, const TimeTaggedVOSEvent *evt); +int16_t OriginalArtFilter (void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); Boolean PictIDExists (short); short GetFirstPICT (void); void BitchAboutPICTNotFound (void); @@ -344,7 +344,7 @@ void HiliteTileOver (DrawSurface *surface, Point mouseIs) //-------------------------------------------------------------- RoomFilter #ifndef COMPILEDEMO -int16_t RoomFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t RoomFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { Point mouseIs; short newTileOver; @@ -502,7 +502,7 @@ void DoRoomInfo(void) { bool needRedraw = false; - item = roomInfoDialog->ExecuteModal(RoomFilter); + item = roomInfoDialog->ExecuteModal(nullptr, RoomFilter); if (item == kOkayButton) { @@ -639,7 +639,7 @@ void UpdateOriginalArt (Dialog *theDialog) //-------------------------------------------------------------- OriginalArtFilter #ifndef COMPILEDEMO -int16_t OriginalArtFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t OriginalArtFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { Point mouseIs; @@ -737,7 +737,7 @@ short ChooseOriginalArt (short was) while (!leaving) { - item = theDialog->ExecuteModal(OriginalArtFilter); + item = theDialog->ExecuteModal(nullptr, OriginalArtFilter); if (item == kOkayButton) { diff --git a/GpApp/SavedGames.cpp b/GpApp/SavedGames.cpp index 109e1f4..811271a 100644 --- a/GpApp/SavedGames.cpp +++ b/GpApp/SavedGames.cpp @@ -82,7 +82,7 @@ void SaveGame2 (void) char savePath[sizeof(spec.m_name) + 1]; size_t savePathLength = 0; - if (!fm->PromptSaveFile(spec.m_dir, savePath, savePathLength, sizeof(spec.m_name), PLPasStr(gameNameStr))) + if (!fm->PromptSaveFile(spec.m_dir, savePath, savePathLength, sizeof(spec.m_name), PLPasStr(gameNameStr), PSTR("Save Game"))) { mm->Release(savedGame); return; @@ -191,7 +191,7 @@ Boolean OpenSavedGame (void) char savePath[sizeof(spec.m_name) + 1]; size_t savePathLength = 0; - if (!fm->PromptOpenFile(spec.m_dir, savePath, savePathLength, sizeof(spec.m_name))) + if (!fm->PromptOpenFile(spec.m_dir, savePath, savePathLength, sizeof(spec.m_name), PSTR("Open Saved Game"))) return false; assert(savePathLength < sizeof(spec.m_name) - 1); diff --git a/GpApp/SelectHouse.cpp b/GpApp/SelectHouse.cpp index f4db1c4..a63dc53 100644 --- a/GpApp/SelectHouse.cpp +++ b/GpApp/SelectHouse.cpp @@ -201,7 +201,7 @@ void PageDownHouses (Dialog *theDial) //-------------------------------------------------------------- LoadFilter #ifndef COMPILEDEMO -int16_t LoadFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t LoadFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { short screenCount, i, wasIndex; @@ -398,7 +398,7 @@ void DoLoadHouse (void) while (!leaving) { - int16_t item = theDial->ExecuteModal(LoadFilter); + int16_t item = theDial->ExecuteModal(nullptr, LoadFilter); bool requiresRedraw = false; diff --git a/GpApp/Settings.cpp b/GpApp/Settings.cpp index 01de43d..6e31f20 100644 --- a/GpApp/Settings.cpp +++ b/GpApp/Settings.cpp @@ -97,7 +97,7 @@ void DoDisplayPrefs (void); void SetAllDefaults (void); void FlashSettingsButton (DrawSurface *, short); void UpdateSettingsMain (Dialog *); -int16_t PrefsFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); +int16_t PrefsFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); void BitchAboutChanges (void); @@ -158,7 +158,7 @@ void UpdateSettingsBrains (Dialog *theDialog) //-------------------------------------------------------------- BrainsFilter -int16_t BrainsFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t BrainsFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -253,7 +253,7 @@ void DoBrainsPrefs (void) while (!leaving) { - itemHit = prefDlg->ExecuteModal(BrainsFilter); + itemHit = prefDlg->ExecuteModal(nullptr, BrainsFilter); switch (itemHit) { case kOkayButton: @@ -383,7 +383,7 @@ void UpdateSettingsControl (Dialog *theDialog) //-------------------------------------------------------------- ControlFilter -int16_t ControlFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t ControlFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { intptr_t wasKeyMap; @@ -535,7 +535,7 @@ void DoControlPrefs (void) while (!leaving) { - itemHit = prefDlg->ExecuteModal(ControlFilter); + itemHit = prefDlg->ExecuteModal(nullptr, ControlFilter); switch (itemHit) { case kOkayButton: @@ -660,7 +660,7 @@ void HandleSoundMusicChange (short newVolume, Boolean sayIt) //-------------------------------------------------------------- SoundFilter -int16_t SoundFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t SoundFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { short newVolume; @@ -757,7 +757,7 @@ void DoSoundPrefs (void) while (!leaving) { - itemHit = prefDlg->ExecuteModal(SoundFilter); + itemHit = prefDlg->ExecuteModal(nullptr, SoundFilter); switch (itemHit) { @@ -928,7 +928,7 @@ void DisplayUpdate (Dialog *theDialog) //-------------------------------------------------------------- DisplayFilter -int16_t DisplayFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t DisplayFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { if (!evt) return -1; @@ -1025,7 +1025,7 @@ void DoDisplayPrefs (void) while (!leaving) { - int16_t itemHit = prefDlg->ExecuteModal(DisplayFilter); + int16_t itemHit = prefDlg->ExecuteModal(nullptr, DisplayFilter); switch (itemHit) { case kOkayButton: @@ -1202,7 +1202,7 @@ void UpdateSettingsMain (Dialog *theDialog) //-------------------------------------------------------------- PrefsFilter -int16_t PrefsFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) +int16_t PrefsFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt) { short i; Boolean foundHit; @@ -1292,7 +1292,7 @@ void DoSettingsMain (void) while (!leaving) { - int16_t selectedItem = prefDlg->ExecuteModal(PrefsFilter); + int16_t selectedItem = prefDlg->ExecuteModal(nullptr, PrefsFilter); switch (selectedItem) { diff --git a/GpApp/Tools.cpp b/GpApp/Tools.cpp index c844f82..d41d5ae 100644 --- a/GpApp/Tools.cpp +++ b/GpApp/Tools.cpp @@ -473,7 +473,7 @@ void HandleToolsClick (Point wherePt) part = FindControl(wherePt, toolsWindow, &theControl); if ((theControl != nil) && (part != 0)) { - part = theControl->Capture(wherePt, nullptr); + part = theControl->Capture(nullptr, wherePt, nullptr); if (part != 0) { newMode = theControl->GetState(); diff --git a/PortabilityLayer/DialogManager.cpp b/PortabilityLayer/DialogManager.cpp index 325d45a..f7d6c0d 100644 --- a/PortabilityLayer/DialogManager.cpp +++ b/PortabilityLayer/DialogManager.cpp @@ -88,7 +88,7 @@ namespace PortabilityLayer ArrayView GetItems() const override; void SetItemVisibility(unsigned int itemIndex, bool isVisible) override; - int16_t ExecuteModal(DialogFilterFunc_t filterFunc) override; + int16_t ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc) override; bool ReplaceWidget(unsigned int itemIndex, Widget *widget) override; @@ -106,7 +106,7 @@ namespace PortabilityLayer static void MakeStringSubstitutions(uint8_t *outStr, const uint8_t *inStr, const DialogTextSubstitutions *substitutions); - int16_t ExecuteModalInDarkenStack(DialogFilterFunc_t filterFunc); + int16_t ExecuteModalInDarkenStack(void *captureContext, DialogFilterFunc_t filterFunc); Window *m_window; DialogItem *m_items; @@ -334,20 +334,20 @@ namespace PortabilityLayer } } - int16_t DialogImpl::ExecuteModal(DialogFilterFunc_t filterFunc) + int16_t DialogImpl::ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc) { Window *exclWindow = this->GetWindow(); WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); - int16_t result = ExecuteModalInDarkenStack(filterFunc); + int16_t result = ExecuteModalInDarkenStack(captureContext, filterFunc); WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); return result; } - int16_t DialogImpl::ExecuteModalInDarkenStack(DialogFilterFunc_t filterFunc) + int16_t DialogImpl::ExecuteModalInDarkenStack(void *captureContext, DialogFilterFunc_t filterFunc) { Window *window = this->GetWindow(); Widget *capturingWidget = nullptr; @@ -362,7 +362,7 @@ namespace PortabilityLayer if (window->IsHandlingTickEvents()) window->OnTick(); - const int16_t selection = filterFunc(this, haveEvent ? &evt : nullptr); + const int16_t selection = (filterFunc != nullptr) ? filterFunc(captureContext, this, haveEvent ? &evt : nullptr) : -1; if (selection >= 0) return selection; @@ -371,7 +371,7 @@ namespace PortabilityLayer { if (capturingWidget != nullptr) { - const WidgetHandleState_t state = capturingWidget->ProcessEvent(evt); + const WidgetHandleState_t state = capturingWidget->ProcessEvent(captureContext, evt); if (state != WidgetHandleStates::kDigested) capturingWidget = nullptr; @@ -398,7 +398,7 @@ namespace PortabilityLayer { Widget *widget = this->m_items[i].GetWidget(); - const WidgetHandleState_t state = widget->ProcessEvent(evt); + const WidgetHandleState_t state = widget->ProcessEvent(captureContext, evt); if (state == WidgetHandleStates::kActivated) return static_cast(i + 1); @@ -621,7 +621,7 @@ namespace PortabilityLayer private: - static int16_t AlertFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); + static int16_t AlertFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); static DialogManagerImpl ms_instance; }; @@ -706,7 +706,7 @@ namespace PortabilityLayer return dialog; } - int16_t DialogManagerImpl::AlertFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) + int16_t DialogManagerImpl::AlertFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt) { return -1; } @@ -767,7 +767,7 @@ namespace PortabilityLayer if (!dialog) return 0; - int16_t hit = dialog->ExecuteModal(DialogManagerImpl::AlertFilter); + int16_t hit = dialog->ExecuteModal(nullptr, DialogManagerImpl::AlertFilter); dialog->Destroy(); return hit; diff --git a/PortabilityLayer/FileBrowserUI.cpp b/PortabilityLayer/FileBrowserUI.cpp new file mode 100644 index 0000000..a994608 --- /dev/null +++ b/PortabilityLayer/FileBrowserUI.cpp @@ -0,0 +1,680 @@ +#include "FileBrowserUI.h" + +#include "DialogManager.h" +#include "PLButtonWidget.h" +#include "FileManager.h" +#include "FontFamily.h" +#include "GpApplicationName.h" +#include "GpBuildVersion.h" +#include "GpRenderedFontMetrics.h" +#include "HostFileSystem.h" +#include "HostDirectoryCursor.h" +#include "HostSystemServices.h" +#include "IGpFont.h" +#include "WindowManager.h" +#include "MemoryManager.h" +#include "PLStandardColors.h" +#include "RenderedFont.h" +#include "ResolveCachingColor.h" +#include "WindowDef.h" +#include "MacRomanConversion.h" + +#include "PLArrayView.h" +#include "PLControlDefinitions.h" +#include "PLCore.h" +#include "PLDialogs.h" +#include "PLEditboxWidget.h" +#include "PLKeyEncoding.h" +#include "PLQDraw.h" +#include "PLScrollBarWidget.h" +#include "PLSysCalls.h" +#include "PLTimeTaggedVOSEvent.h" + +#include + +static const int kOkayButton = 1; +static const int kCancelButton = 2; +static const int kFileList = 3; +static const int kFileListScrollBar = 4; +static const int kFileNameEditBox = 5; +static const int kFileBrowserUIOpenDialogTemplateID = 2001; +static const int kFileBrowserUISaveDialogTemplateID = 2002; +static const int kFileBrowserUIOverwriteDialogTemplateID = 2003; +static const int kFileBrowserUIBadNameDialogTemplateID = 2004; + +static const int kOverwriteNoButton = 1; +static const int kOverwriteYesButton = 2; + +namespace PortabilityLayer +{ + class FileBrowserUIImpl + { + public: + FileBrowserUIImpl(); + ~FileBrowserUIImpl(); + + static void PubScrollBarCallback(void *captureContext, Widget *control, int part); + static bool PubEditBoxCharFilter(void *context, uint8_t ch); + static int16_t PubFileBrowserUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); + static int16_t PubPopUpAlertUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); + + bool AppendName(const char *name, size_t nameLength); + void SortNames(); + void DrawFileList(); + + void CaptureFileListDrag(); + void SetScrollOffset(int32_t offset); + uint16_t GetScrollCapacity() const; + + void SetUIComponents(Window *window, DrawSurface *surface, const Rect &fileListRect, EditboxWidget *editBox); + + PLPasStr GetSelectedFileName() const; + + static int16_t PopUpAlert(const Rect &rect, int dialogResID, const DialogTextSubstitutions *substitutions); + + private: + typedef PascalStr<255> NameStr_t; + void ScrollBarCallback(Widget *control, int part); + int16_t FileBrowserUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); + int16_t PopUpAlertUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); + + static bool NameSortPred(const NameStr_t &a, const NameStr_t &b); + + int m_offset; + int m_selectedIndex; + int32_t m_scrollOffset; + int32_t m_fontSpacing; + THandle m_names; + size_t m_numNames; + DrawSurface *m_surface; + Window *m_window; + EditboxWidget *m_editBox; + Rect m_rect; + + Point m_doubleClickPos; + uint32_t m_doubleClickTime; + bool m_haveFirstClick; + }; + + FileBrowserUIImpl::FileBrowserUIImpl() + : m_offset(0) + , m_surface(nullptr) + , m_window(nullptr) + , m_editBox(nullptr) + , m_rect(Rect::Create(0, 0, 0, 0)) + , m_selectedIndex(-1) + , m_scrollOffset(0) + , m_fontSpacing(1) + , m_numNames(0) + , m_doubleClickPos(Point::Create(0, 0)) + , m_doubleClickTime(0) + , m_haveFirstClick(false) + { + } + + FileBrowserUIImpl::~FileBrowserUIImpl() + { + m_names.Dispose(); + } + + void FileBrowserUIImpl::PubScrollBarCallback(void *captureContext, Widget *control, int part) + { + static_cast(captureContext)->ScrollBarCallback(control, part); + } + + int16_t FileBrowserUIImpl::PubFileBrowserUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt) + { + return static_cast(context)->FileBrowserUIFilter(dialog, evt); + } + + int16_t FileBrowserUIImpl::PubPopUpAlertUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt) + { + return static_cast(context)->PopUpAlertUIFilter(dialog, evt); + } + + bool FileBrowserUIImpl::PubEditBoxCharFilter(void *context, uint8_t ch) + { + uint16_t unicodeChar = MacRoman::ToUnicode(ch); + + return HostFileSystem::GetInstance()->ValidateFilePathUnicodeChar(unicodeChar); + } + + bool FileBrowserUIImpl::AppendName(const char *name, size_t nameLen) + { + MemoryManager *mm = MemoryManager::GetInstance(); + if (!m_names) + { + m_names = THandle(mm->AllocHandle(0)); + if (!m_names) + return false; + } + + size_t oldSize = m_names.MMBlock()->m_size; + + if (!mm->ResizeHandle(m_names.MMBlock(), oldSize + sizeof(NameStr_t))) + return false; + + (*m_names)[m_numNames++] = NameStr_t(nameLen, name); + + return true; + } + + void FileBrowserUIImpl::SortNames() + { + if (!m_names) + return; + + NameStr_t *names = *m_names; + + std::sort(names, names + m_numNames, NameSortPred); + } + + void FileBrowserUIImpl::DrawFileList() + { + if (!m_names.MMBlock()) + return; + + PortabilityLayer::RenderedFont *font = GetApplicationFont(12, PortabilityLayer::FontFamilyFlags::FontFamilyFlag_Bold, true); + + GpRenderedFontMetrics metrics = font->GetMetrics(); + int32_t spacing = metrics.m_linegap; + int32_t glyphOffset = (metrics.m_linegap + metrics.m_ascent) / 2; + + Rect itemRect = Rect::Create(m_rect.top, m_rect.left, m_rect.top + spacing, m_rect.right); + itemRect.top -= m_scrollOffset; + itemRect.bottom -= m_scrollOffset; + + ResolveCachingColor blackColor = StdColors::Black(); + ResolveCachingColor whiteColor = StdColors::White(); + ResolveCachingColor focusColor = RGBAColor::Create(153, 153, 255, 255); + + m_surface->FillRect(m_rect, whiteColor); + + for (size_t i = 0; i < m_numNames; i++) + { + if (m_selectedIndex >= 0 && static_cast(m_selectedIndex) == i) + { + Rect focusRect = itemRect.Intersect(m_rect); + if (focusRect.IsValid()) + m_surface->FillRect(focusRect, focusColor); + } + + Point itemStringPoint = Point::Create(itemRect.left + 2, itemRect.top + glyphOffset); + m_surface->DrawStringConstrained(itemStringPoint, (*m_names)[i].ToShortStr(), m_rect, blackColor, font); + + itemRect.top += spacing; + itemRect.bottom += spacing; + } + + m_fontSpacing = spacing; + } + + void FileBrowserUIImpl::CaptureFileListDrag() + { + } + + void FileBrowserUIImpl::SetScrollOffset(int32_t offset) + { + m_scrollOffset = offset; + DrawFileList(); + } + + uint16_t FileBrowserUIImpl::GetScrollCapacity() const + { + int32_t boxHeight = m_rect.Height(); + int32_t overCapacity = (static_cast(m_numNames) * m_fontSpacing - boxHeight); + + if (overCapacity < 0) + return 0; + else + return static_cast(overCapacity); + } + + void FileBrowserUIImpl::SetUIComponents(Window *window, DrawSurface *surface, const Rect &rect, EditboxWidget *editbox) + { + m_surface = surface; + m_rect = rect; + m_window = window; + m_editBox = editbox; + } + + PLPasStr FileBrowserUIImpl::GetSelectedFileName() const + { + if (m_selectedIndex < 0) + return PSTR(""); + else + return (*m_names)[m_selectedIndex].ToShortStr(); + } + + void FileBrowserUIImpl::ScrollBarCallback(Widget *control, int part) + { + const int pageStepping = 5; + + switch (part) + { + case kControlUpButtonPart: + control->SetState(control->GetState() - m_fontSpacing); + break; + case kControlDownButtonPart: + control->SetState(control->GetState() + m_fontSpacing); + break; + case kControlPageUpPart: + control->SetState(control->GetState() - pageStepping * m_fontSpacing); + break; + case kControlPageDownPart: + control->SetState(control->GetState() + pageStepping * m_fontSpacing); + break; + default: + break; + }; + + SetScrollOffset(control->GetState()); + } + + int16_t FileBrowserUIImpl::FileBrowserUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) + { + bool handledIt = false; + int16_t hit = -1; + + if (!evt) + return -1; + + Window *window = dialog->GetWindow(); + DrawSurface *surface = window->GetDrawSurface(); + + if (evt->IsKeyDownEvent()) + { + switch (PackVOSKeyCode(evt->m_vosEvent.m_event.m_keyboardInputEvent)) + { + case PL_KEY_SPECIAL(kEnter): + case PL_KEY_NUMPAD_SPECIAL(kEnter): + { + Widget *okayButton = dialog->GetItems()[kOkayButton - 1].GetWidget(); + + if (okayButton->IsEnabled()) + { + okayButton->SetHighlightStyle(kControlButtonPart, true); + PLSysCalls::Sleep(8); + okayButton->SetHighlightStyle(kControlButtonPart, false); + + hit = kOkayButton; + handledIt = true; + } + } + break; + + case PL_KEY_SPECIAL(kEscape): + { + Widget *cancelButton = dialog->GetItems()[kCancelButton - 1].GetWidget(); + + cancelButton->SetHighlightStyle(kControlButtonPart, true); + PLSysCalls::Sleep(8); + cancelButton->SetHighlightStyle(kControlButtonPart, false); + + hit = kCancelButton; + handledIt = true; + } + break; + + default: + handledIt = false; + break; + } + } + + if (evt->IsLMouseDownEvent()) + { + Point mousePt = m_window->MouseToLocal(evt->m_vosEvent.m_event.m_mouseInputEvent); + bool haveDoubleClick = false; + + if (m_rect.Contains(mousePt)) + { + if (m_haveFirstClick) + { + const uint32_t doubleTime = 30; // PL_NotYetImplemented_TODO: Get this from the system settings + + if (mousePt == m_doubleClickPos && evt->m_timestamp - m_doubleClickTime < doubleTime) + haveDoubleClick = true; + } + + if (!haveDoubleClick) + { + m_haveFirstClick = true; + m_doubleClickPos = mousePt; + m_doubleClickTime = evt->m_timestamp; + + const TimeTaggedVOSEvent *rcvEvt = evt; + + TimeTaggedVOSEvent evtHolder; + for (;;) + { + if (rcvEvt) + { + if (rcvEvt->m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput) + { + mousePt = m_window->MouseToLocal(rcvEvt->m_vosEvent.m_event.m_mouseInputEvent); + if (mousePt != m_doubleClickPos) + m_haveFirstClick = false; + + if (m_rect.Contains(mousePt)) + { + int32_t selection = (mousePt.v - m_rect.top + m_scrollOffset) / m_fontSpacing; + + if (selection < 0 || static_cast(selection) >= m_numNames) + selection = -1; + + if (selection >= 0) + { + if (selection != m_selectedIndex) + { + m_selectedIndex = selection; + + dialog->GetItems()[kOkayButton - 1].GetWidget()->SetEnabled(selection >= 0); + + DrawFileList(); + } + + if (m_editBox) + { + PLPasStr nameStr = (*m_names)[m_selectedIndex].ToShortStr(); + m_editBox->SetString(nameStr); + m_editBox->SetSelection(0, nameStr.Length()); + } + } + } + } + + if (rcvEvt->IsLMouseUpEvent()) + break; + } + + if (WaitForEvent(&evtHolder, 1)) + rcvEvt = &evtHolder; + else + rcvEvt = nullptr; + } + } + } + + if (haveDoubleClick && m_selectedIndex >= 0) + { + handledIt = true; + hit = kOkayButton; + } + } + + if (!handledIt) + return -1; + + return hit; + } + + int16_t FileBrowserUIImpl::PopUpAlertUIFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) + { + bool handledIt = false; + int16_t hit = -1; + + if (!evt) + return -1; + + Window *window = dialog->GetWindow(); + DrawSurface *surface = window->GetDrawSurface(); + + if (evt->IsKeyDownEvent()) + { + switch (PackVOSKeyCode(evt->m_vosEvent.m_event.m_keyboardInputEvent)) + { + case PL_KEY_SPECIAL(kEnter): + case PL_KEY_NUMPAD_SPECIAL(kEnter): + { + Widget *okayButton = dialog->GetItems()[kOkayButton - 1].GetWidget(); + + if (okayButton->IsEnabled()) + { + okayButton->SetHighlightStyle(kControlButtonPart, true); + PLSysCalls::Sleep(8); + okayButton->SetHighlightStyle(kControlButtonPart, false); + + hit = kOkayButton; + handledIt = true; + } + } + break; + + default: + handledIt = false; + break; + } + } + + if (!handledIt) + return -1; + + return hit; + } + + bool FileBrowserUIImpl::NameSortPred(const NameStr_t &a, const NameStr_t &b) + { + const size_t lenA = a.Length(); + const size_t lenB = b.Length(); + + const size_t shorterLength = std::min(lenA, lenB); + + int comparison = memcmp(a.UnsafeCharPtr(), b.UnsafeCharPtr(), shorterLength); + if (comparison > 0) + return false; + + if (comparison < 0) + return true; + + return lenA < lenB; + } + + int16_t FileBrowserUIImpl::PopUpAlert(const Rect &rect, int dialogResID, const DialogTextSubstitutions *substitutions) + { + PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance(); + Dialog *dialog = dialogManager->LoadDialogFromTemplate(dialogResID, rect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), substitutions); + + const PortabilityLayer::DialogItem &firstItem = *dialog->GetItems().begin(); + Rect itemRect = firstItem.GetWidget()->GetRect(); + + PortabilityLayer::ButtonWidget::DrawDefaultButtonChrome(itemRect, dialog->GetWindow()->GetDrawSurface()); + + int16_t hit = 0; + do + { + hit = dialog->ExecuteModal(nullptr, PubPopUpAlertUIFilter); + } while (hit != kOkayButton && hit != kCancelButton); + + dialog->Destroy(); + + return hit; + } + + bool FileBrowserUI::Prompt(Mode mode, VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) + { + int dialogID = 0; + if (mode == Mode_Open) + dialogID = kFileBrowserUIOpenDialogTemplateID; + else if (mode == Mode_Save) + dialogID = kFileBrowserUISaveDialogTemplateID; + else + { + assert(false); + return false; + } + + FileBrowserUIImpl uiImpl; + + // Enumerate files + PortabilityLayer::HostFileSystem *fs = PortabilityLayer::HostFileSystem::GetInstance(); + PortabilityLayer::HostDirectoryCursor *dirCursor = fs->ScanDirectory(dirID); + + if (!dirCursor) + return false; + + const char *fileName; + while (dirCursor->GetNext(fileName)) + { + size_t nameLength = strlen(fileName); + + if (nameLength < 4) + continue; + + const char *nameExt = fileName + (nameLength - 4); + + if (!memcmp(nameExt, ".gpf", 4)) + { + if (!uiImpl.AppendName(fileName, nameLength - 4)) + { + dirCursor->Destroy(); + return false; + } + } + } + + uiImpl.SortNames(); + + dirCursor->Destroy(); + + const int scrollBarWidth = 16; + const Rect windowRect = Rect::Create(0, 0, 272, 450); + + PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(windowRect, PortabilityLayer::WindowStyleFlags::kAlert, true, 0, 0, PSTR("")); + + PortabilityLayer::ResolveCachingColor blackColor = StdColors::Black(); + PortabilityLayer::RenderedFont *font = GetApplicationFont(12, PortabilityLayer::FontFamilyFlag_Bold, true); + PortabilityLayer::RenderedFont *fontLight = GetApplicationFont(8, PortabilityLayer::FontFamilyFlag_None, true); + + int16_t verticalPoint = 16 + font->GetMetrics().m_ascent; + int16_t horizontalOffset = 16; + const int16_t spacing = 12; + + PortabilityLayer::DialogManager *dialogManager = PortabilityLayer::DialogManager::GetInstance(); + + DialogTextSubstitutions substitutions(promptText); + Dialog *dialog = dialogManager->LoadDialogFromTemplate(dialogID, windowRect, true, false, 0, 0, PL_GetPutInFrontWindowPtr(), PSTR(""), &substitutions); + + Window *window = dialog->GetWindow(); + + DrawSurface *surface = window->GetDrawSurface(); + + const PortabilityLayer::DialogItem &firstItem = *dialog->GetItems().begin(); + Rect itemRect = firstItem.GetWidget()->GetRect(); + + PortabilityLayer::ButtonWidget::DrawDefaultButtonChrome(itemRect, surface); + + // Get item rects + const Rect fileListRect = dialog->GetItems()[kFileList - 1].GetWidget()->GetRect(); + const Rect scrollBarRect = dialog->GetItems()[kFileListScrollBar - 1].GetWidget()->GetRect(); + + EditboxWidget *editbox = nullptr; + if (mode == Mode_Save) + { + editbox = static_cast(dialog->GetItems()[kFileNameEditBox - 1].GetWidget()); + editbox->SetCharacterFilter(&uiImpl, FileBrowserUIImpl::PubEditBoxCharFilter); + editbox->SetCapacity(31); + editbox->SetString(initialFileName); + + dialog->GetWindow()->FocusWidget(editbox); + } + + // Draw file list frame + surface->FrameRect(fileListRect.Inset(-1, -1), blackColor); + + // Draw initial stuff + uiImpl.SetUIComponents(dialog->GetWindow(), surface, fileListRect, editbox); + uiImpl.DrawFileList(); + + PortabilityLayer::ScrollBarWidget *scrollBar = nullptr; + + { + PortabilityLayer::WidgetBasicState state; + state.m_rect = scrollBarRect; + state.m_refConstant = 0; + state.m_window = nullptr; + state.m_max = uiImpl.GetScrollCapacity(); + state.m_state = 0; + state.m_defaultCallback = FileBrowserUIImpl::PubScrollBarCallback; + scrollBar = PortabilityLayer::ScrollBarWidget::Create(state, nullptr); + } + + dialog->ReplaceWidget(kFileListScrollBar - 1, scrollBar); + + window->DrawControls(); + + int16_t hit = 0; + + Window *exclWindow = dialog->GetWindow(); + + WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); + + do + { + hit = dialog->ExecuteModal(&uiImpl, FileBrowserUIImpl::PubFileBrowserUIFilter); + + if (hit == kFileListScrollBar) + uiImpl.SetScrollOffset(scrollBar->GetState()); + + if (hit == kOkayButton && mode == Mode_Save) + { + HostFileSystem *fs = HostFileSystem::GetInstance(); + + EditboxWidget *editBox = static_cast(dialog->GetItems()[kFileNameEditBox - 1].GetWidget()); + + PLPasStr nameStr = editBox->GetString(); + if (nameStr.Length() == 0 || !fs->ValidateFilePath(nameStr.Chars(), nameStr.Length())) + { + PortabilityLayer::HostSystemServices::GetInstance()->Beep(); + FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIBadNameDialogTemplateID, nullptr); + hit = -1; + } + else if (PortabilityLayer::FileManager::GetInstance()->FileExists(dirID, nameStr)) + { + DialogTextSubstitutions substitutions(nameStr); + + PortabilityLayer::HostSystemServices::GetInstance()->Beep(); + int16_t subHit = FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIOverwriteDialogTemplateID, &substitutions); + + if (subHit == kOverwriteNoButton) + hit = -1; + } + } + } while (hit != kOkayButton && hit != kCancelButton); + + WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); + + bool confirmed = false; + PLPasStr uiFileName; + + if (hit == kOkayButton) + { + if (mode == Mode_Open) + { + uiFileName = uiImpl.GetSelectedFileName(); + confirmed = true; + } + else if (mode == Mode_Save) + { + uiFileName = editbox->GetString(); + confirmed = true; + } + } + + if (confirmed) + { + if (uiFileName.Length() > pathCapacity) + confirmed = false; + } + + if (confirmed) + { + memcpy(path, uiFileName.Chars(), uiFileName.Length()); + outPathLength = uiFileName.Length(); + } + + dialog->Destroy(); + + return confirmed; + } +} diff --git a/PortabilityLayer/FileBrowserUI.h b/PortabilityLayer/FileBrowserUI.h new file mode 100644 index 0000000..407ea46 --- /dev/null +++ b/PortabilityLayer/FileBrowserUI.h @@ -0,0 +1,20 @@ +#pragma once + +#include "VirtualDirectory.h" + +class PLPasStr; + +namespace PortabilityLayer +{ + class FileBrowserUI + { + public: + enum Mode + { + Mode_Save, + Mode_Open, + }; + + static bool Prompt(Mode mode, VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText); + }; +} diff --git a/PortabilityLayer/FileManager.cpp b/PortabilityLayer/FileManager.cpp index e51498f..35c9be7 100644 --- a/PortabilityLayer/FileManager.cpp +++ b/PortabilityLayer/FileManager.cpp @@ -1,4 +1,6 @@ #include "FileManager.h" + +#include "FileBrowserUI.h" #include "HostFileSystem.h" #include "HostMemoryBuffer.h" #include "MemReaderStream.h" @@ -33,8 +35,8 @@ namespace PortabilityLayer PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override; PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t creationDisposition, GpIOStream *&outStream) override; - bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName) override; - bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) override; + bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) override; + bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) override; static FileManagerImpl *GetInstance(); @@ -174,18 +176,18 @@ namespace PortabilityLayer return RawOpenFileFork(dirID, filename, ".gpa", permission, ignoreMeta, createDisposition, outStream); } - bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName) + bool FileManagerImpl::PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) { ExtendedFileName_t extFN; if (!ConstructFilename(extFN, initialFileName, "")) return false; - return PortabilityLayer::HostFileSystem::GetInstance()->PromptSaveFile(dirID, path, outPathLength, pathCapacity, extFN); + return FileBrowserUI::Prompt(FileBrowserUI::Mode_Save, dirID, path, outPathLength, pathCapacity, initialFileName, promptText); } - bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) + bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) { - return PLSysCalls::PromptOpenFile(dirID, path, outPathLength, pathCapacity); + return FileBrowserUI::Prompt(FileBrowserUI::Mode_Open, dirID, path, outPathLength, pathCapacity, PSTR(""), promptText); } FileManagerImpl *FileManagerImpl::GetInstance() diff --git a/PortabilityLayer/FileManager.h b/PortabilityLayer/FileManager.h index 3fb9b4e..eaf4d8a 100644 --- a/PortabilityLayer/FileManager.h +++ b/PortabilityLayer/FileManager.h @@ -35,8 +35,8 @@ namespace PortabilityLayer virtual PLError_t RawOpenFileData(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0; virtual PLError_t RawOpenFileResources(VirtualDirectory_t dirID, const PLPasStr &filename, EFilePermission filePermission, bool ignoreMeta, GpFileCreationDisposition_t createDisposition, GpIOStream *&outStream) = 0; - virtual bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName) = 0; - virtual bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) = 0; + virtual bool PromptSaveFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &initialFileName, const PLPasStr &promptText) = 0; + virtual bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) = 0; static FileManager *GetInstance(); }; diff --git a/PortabilityLayer/HostFileSystem.h b/PortabilityLayer/HostFileSystem.h index 624e8f8..506e9df 100644 --- a/PortabilityLayer/HostFileSystem.h +++ b/PortabilityLayer/HostFileSystem.h @@ -20,9 +20,8 @@ namespace PortabilityLayer virtual bool DeleteFile(VirtualDirectory_t virtualDirectory, const char *path, bool &existed) = 0; virtual HostDirectoryCursor *ScanDirectory(VirtualDirectory_t virtualDirectory) = 0; - virtual bool PromptSaveFile(VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) = 0; - virtual bool PromptOpenFile(VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity) = 0; virtual bool ValidateFilePath(const char *path, size_t pathLen) const = 0; + virtual bool ValidateFilePathUnicodeChar(uint32_t ch) const = 0; static HostFileSystem *GetInstance(); static void SetInstance(HostFileSystem *instance); diff --git a/PortabilityLayer/PLButtonWidget.cpp b/PortabilityLayer/PLButtonWidget.cpp index d253a43..8205802 100644 --- a/PortabilityLayer/PLButtonWidget.cpp +++ b/PortabilityLayer/PLButtonWidget.cpp @@ -229,7 +229,7 @@ namespace PortabilityLayer { } - WidgetHandleState_t ButtonWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t ButtonWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (!m_visible || !m_enabled) return WidgetHandleStates::kIgnored; @@ -240,7 +240,7 @@ namespace PortabilityLayer if (m_rect.Contains(pt)) { - if (Capture(pt, nullptr) == RegionIDs::kNone) + if (Capture(captureContext, pt, nullptr) == RegionIDs::kNone) return WidgetHandleStates::kDigested; else return WidgetHandleStates::kActivated; @@ -264,7 +264,7 @@ namespace PortabilityLayer DrawControl(m_window->GetDrawSurface()); } - int16_t ButtonWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback) + int16_t ButtonWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) { if (!m_enabled || !m_visible) return 0; diff --git a/PortabilityLayer/PLButtonWidget.h b/PortabilityLayer/PLButtonWidget.h index 26af111..ea1f9a9 100644 --- a/PortabilityLayer/PLButtonWidget.h +++ b/PortabilityLayer/PLButtonWidget.h @@ -30,10 +30,10 @@ namespace PortabilityLayer void SetString(const PLPasStr &str) override; PLPasStr GetString() const override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override; void OnEnabledChanged() override; void OnStateChanged() override; - int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback) override; + int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) override; void SetHighlightStyle(int16_t style, bool enabled) override; static void DrawDefaultButtonChrome(const Rect &rect, DrawSurface *surface); diff --git a/PortabilityLayer/PLDialogs.h b/PortabilityLayer/PLDialogs.h index bbebe91..8377370 100644 --- a/PortabilityLayer/PLDialogs.h +++ b/PortabilityLayer/PLDialogs.h @@ -14,7 +14,7 @@ class PLPasStr; struct Control; struct Dialog; -typedef int16_t(*DialogFilterFunc_t)(Dialog *dialog, const TimeTaggedVOSEvent *evt); +typedef int16_t(*DialogFilterFunc_t)(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt); struct DialogTextSubstitutions { @@ -39,7 +39,7 @@ struct Dialog virtual void SetItemVisibility(unsigned int itemIndex, bool isVisible) = 0; - virtual int16_t ExecuteModal(DialogFilterFunc_t filterFunc) = 0; + virtual int16_t ExecuteModal(void *captureContext, DialogFilterFunc_t filterFunc) = 0; virtual bool ReplaceWidget(unsigned int itemIndex, PortabilityLayer::Widget *widget) = 0; }; diff --git a/PortabilityLayer/PLEditboxWidget.cpp b/PortabilityLayer/PLEditboxWidget.cpp index dcb5f81..1bc9242 100644 --- a/PortabilityLayer/PLEditboxWidget.cpp +++ b/PortabilityLayer/PLEditboxWidget.cpp @@ -35,6 +35,8 @@ namespace PortabilityLayer , m_isDraggingSelection(false) , m_dragSelectionStartChar(false) , m_scrollOffset(0, 0) + , m_characterFilter(nullptr) + , m_characterFilterContext(nullptr) { } @@ -121,17 +123,17 @@ namespace PortabilityLayer m_length = len; memcpy(m_chars, str.UChars(), len); + if (m_selStartChar > len) + m_selStartChar = len; + if (m_selEndChar > len) + m_selEndChar = len; + if (m_window) { DrawSurface *surface = m_window->GetDrawSurface(); DrawControl(surface); } - - if (m_selStartChar > len) - m_selStartChar = len; - if (m_selEndChar > len) - m_selEndChar = len; } PLPasStr EditboxWidget::GetString() const @@ -166,7 +168,7 @@ namespace PortabilityLayer Redraw(); } - WidgetHandleState_t EditboxWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t EditboxWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (m_isDraggingSelection) return HandleDragSelection(evt); @@ -200,6 +202,12 @@ namespace PortabilityLayer resolvedChar = MacRoman::FromUnicode(ch, keyEvent.m_key.m_unicodeChar); } + if (resolvedChar) + { + if (m_characterFilter) + resolvedChar = m_characterFilter(m_characterFilterContext, ch); + } + if (resolvedChar) { if (ch >= 0x20 && ch <= 0x7e) @@ -979,4 +987,15 @@ namespace PortabilityLayer Redraw(); } } + + void EditboxWidget::SetCharacterFilter(void *context, CharacterFilterCallback_t callback) + { + m_characterFilterContext = context; + m_characterFilter = callback; + } + + void EditboxWidget::SetCapacity(size_t capacity) + { + m_capacity = std::min(255, capacity); + } } diff --git a/PortabilityLayer/PLEditboxWidget.h b/PortabilityLayer/PLEditboxWidget.h index 9f95054..e99852a 100644 --- a/PortabilityLayer/PLEditboxWidget.h +++ b/PortabilityLayer/PLEditboxWidget.h @@ -11,6 +11,8 @@ namespace PortabilityLayer class EditboxWidget final : public WidgetSpec { public: + typedef bool (*CharacterFilterCallback_t)(void *context, uint8_t character); + EditboxWidget(const WidgetBasicState &state); ~EditboxWidget(); @@ -23,7 +25,7 @@ namespace PortabilityLayer void GainFocus() override; void LoseFocus() override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override; Rect GetExpandedRect() const override; @@ -33,6 +35,9 @@ namespace PortabilityLayer void SetMultiLine(bool isMultiLine); + void SetCharacterFilter(void *context, CharacterFilterCallback_t callback); + void SetCapacity(size_t capacity); + private: static const unsigned int kCaratBlinkRate = 20; static const unsigned int kMouseScrollRate = 20; @@ -92,5 +97,8 @@ namespace PortabilityLayer size_t m_dragSelectionStartChar; uint16_t m_caratTimer; + + CharacterFilterCallback_t m_characterFilter; + void *m_characterFilterContext; }; } diff --git a/PortabilityLayer/PLIconWidget.cpp b/PortabilityLayer/PLIconWidget.cpp index 3a281f6..90a5c6b 100644 --- a/PortabilityLayer/PLIconWidget.cpp +++ b/PortabilityLayer/PLIconWidget.cpp @@ -48,7 +48,7 @@ namespace PortabilityLayer surface->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents); } - WidgetHandleState_t IconWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t IconWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (!m_visible || !m_enabled) return WidgetHandleStates::kIgnored; diff --git a/PortabilityLayer/PLIconWidget.h b/PortabilityLayer/PLIconWidget.h index 85bc67b..bdea5f8 100644 --- a/PortabilityLayer/PLIconWidget.h +++ b/PortabilityLayer/PLIconWidget.h @@ -17,7 +17,7 @@ namespace PortabilityLayer void DrawControl(DrawSurface *surface) override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override; private: THandle m_iconImage; diff --git a/PortabilityLayer/PLInvisibleWidget.cpp b/PortabilityLayer/PLInvisibleWidget.cpp index c97636b..0c4e9e7 100644 --- a/PortabilityLayer/PLInvisibleWidget.cpp +++ b/PortabilityLayer/PLInvisibleWidget.cpp @@ -21,7 +21,7 @@ namespace PortabilityLayer return true; } - WidgetHandleState_t InvisibleWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t InvisibleWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (!m_visible || !m_enabled) return WidgetHandleStates::kIgnored; diff --git a/PortabilityLayer/PLInvisibleWidget.h b/PortabilityLayer/PLInvisibleWidget.h index c331f8a..f23770e 100644 --- a/PortabilityLayer/PLInvisibleWidget.h +++ b/PortabilityLayer/PLInvisibleWidget.h @@ -12,7 +12,7 @@ namespace PortabilityLayer bool Init(const WidgetBasicState &state, const void *additionalData) override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override; private: bool m_clickable; diff --git a/PortabilityLayer/PLPopupMenuWidget.cpp b/PortabilityLayer/PLPopupMenuWidget.cpp index 48beb97..d36562d 100644 --- a/PortabilityLayer/PLPopupMenuWidget.cpp +++ b/PortabilityLayer/PLPopupMenuWidget.cpp @@ -39,7 +39,7 @@ namespace PortabilityLayer return true; } - WidgetHandleState_t PopupMenuWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t PopupMenuWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (evt.IsLMouseDownEvent()) { @@ -49,7 +49,7 @@ namespace PortabilityLayer if (this->m_rect.Contains(Point::Create(localPoint.m_x, localPoint.m_y))) { - int16_t part = Capture(Point::Create(localPoint.m_x, localPoint.m_y), nullptr); + int16_t part = Capture(captureContext, Point::Create(localPoint.m_x, localPoint.m_y), nullptr); if (part >= 1) return WidgetHandleStates::kActivated; else @@ -60,7 +60,7 @@ namespace PortabilityLayer return WidgetHandleStates::kIgnored; } - int16_t PopupMenuWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback) + int16_t PopupMenuWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) { MenuManager *mm = PortabilityLayer::MenuManager::GetInstance(); diff --git a/PortabilityLayer/PLPopupMenuWidget.h b/PortabilityLayer/PLPopupMenuWidget.h index de5a542..a289ba0 100644 --- a/PortabilityLayer/PLPopupMenuWidget.h +++ b/PortabilityLayer/PLPopupMenuWidget.h @@ -14,8 +14,8 @@ namespace PortabilityLayer bool Init(const WidgetBasicState &state, const void *additionalData) override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt); - int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback); + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt); + int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback); void DrawControl(DrawSurface *surface) override; void OnStateChanged() override; diff --git a/PortabilityLayer/PLScrollBarWidget.cpp b/PortabilityLayer/PLScrollBarWidget.cpp index 0db7845..b84c485 100644 --- a/PortabilityLayer/PLScrollBarWidget.cpp +++ b/PortabilityLayer/PLScrollBarWidget.cpp @@ -4,6 +4,8 @@ #include "PLTimeTaggedVOSEvent.h" #include "ResolveCachingColor.h" +#include "PLRegions.h" + namespace PortabilityLayer { ScrollBarWidget::ScrollBarWidget(const WidgetBasicState &state) @@ -15,14 +17,30 @@ namespace PortabilityLayer , m_laneCapacity(0) , m_isActive(false) , m_activePart(0) + , m_callback(state.m_defaultCallback) { } - WidgetHandleState_t ScrollBarWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t ScrollBarWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { if (!m_visible || !m_enabled) return WidgetHandleStates::kIgnored; + if (evt.IsLMouseDownEvent()) + { + const Point pt = m_window->MouseToLocal(evt.m_vosEvent.m_event.m_mouseInputEvent); + + if (m_rect.Contains(pt)) + { + if (Capture(captureContext, pt, m_callback) == RegionIDs::kNone) + return WidgetHandleStates::kDigested; + else + return WidgetHandleStates::kActivated; + } + else + return WidgetHandleStates::kIgnored; + } + return WidgetHandleStates::kIgnored; } @@ -279,19 +297,19 @@ namespace PortabilityLayer } } - int16_t ScrollBarWidget::Capture(const Point &pos, WidgetUpdateCallback_t callback) + int16_t ScrollBarWidget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) { int part = ResolvePart(pos); if (!part) return 0; if (part == kControlIndicatorPart) - return CaptureIndicator(pos, callback); + return CaptureIndicator(captureContext, pos, callback); else - return CaptureScrollSegment(pos, part, callback); + return CaptureScrollSegment(captureContext, pos, part, callback); } - int16_t ScrollBarWidget::CaptureScrollSegment(const Point &pos, int part, WidgetUpdateCallback_t callback) + int16_t ScrollBarWidget::CaptureScrollSegment(void *captureContext, const Point &pos, int part, WidgetUpdateCallback_t callback) { int tickDelay = 15; @@ -308,7 +326,7 @@ namespace PortabilityLayer if (ticksUntilIterate == 0) { if (m_isActive) - IterateScrollSegment(part, callback); + IterateScrollSegment(captureContext, part, callback); ticksUntilIterate = tickDelay; } @@ -349,7 +367,7 @@ namespace PortabilityLayer } } - int16_t ScrollBarWidget::CaptureIndicator(const Point &pos, WidgetUpdateCallback_t callback) + int16_t ScrollBarWidget::CaptureIndicator(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) { const bool isHorizontal = IsHorizontal(); @@ -428,10 +446,10 @@ namespace PortabilityLayer } } - void ScrollBarWidget::IterateScrollSegment(int part, WidgetUpdateCallback_t callback) + void ScrollBarWidget::IterateScrollSegment(void *captureContext, int part, WidgetUpdateCallback_t callback) { if (callback != nullptr) - callback(this, part); + callback(captureContext, this, part); } int ScrollBarWidget::ResolvePart(const Point &point) const diff --git a/PortabilityLayer/PLScrollBarWidget.h b/PortabilityLayer/PLScrollBarWidget.h index 79e4998..9166ed6 100644 --- a/PortabilityLayer/PLScrollBarWidget.h +++ b/PortabilityLayer/PLScrollBarWidget.h @@ -15,7 +15,7 @@ namespace PortabilityLayer bool Init(const WidgetBasicState &state, const void *additionalData) override; void OnEnabledChanged() override; - WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; + WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override; void DrawControl(DrawSurface *surface) override; void SetState(int16_t state) override; @@ -24,7 +24,7 @@ namespace PortabilityLayer void SetMin(int32_t v) override; void SetMax(int32_t v) override; - int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback) override; + int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) override; int ResolvePart(const Point &point) const override; @@ -39,9 +39,9 @@ namespace PortabilityLayer static void DrawBeveledBox(DrawSurface *surface, const Rect &rect); - int16_t CaptureScrollSegment(const Point &pos, int part, WidgetUpdateCallback_t callback); - int16_t CaptureIndicator(const Point &pos, WidgetUpdateCallback_t callback); - void IterateScrollSegment(int part, WidgetUpdateCallback_t callback); + int16_t CaptureScrollSegment(void *captureContext, const Point &pos, int part, WidgetUpdateCallback_t callback); + int16_t CaptureIndicator(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback); + void IterateScrollSegment(void *captureContext, int part, WidgetUpdateCallback_t callback); int32_t m_min; int32_t m_max; @@ -51,5 +51,7 @@ namespace PortabilityLayer bool m_isActive; int m_activePart; + + WidgetUpdateCallback_t m_callback; }; } diff --git a/PortabilityLayer/PLSysCalls.cpp b/PortabilityLayer/PLSysCalls.cpp index 163c258..b65660d 100644 --- a/PortabilityLayer/PLSysCalls.cpp +++ b/PortabilityLayer/PLSysCalls.cpp @@ -175,63 +175,4 @@ namespace PLSysCalls AnimationManager::GetInstance()->TickPlayers(ticks); } } - - static void PromptOpenFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue) - { - bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptOpenFile(static_cast(args[0].m_int), static_cast(args[1].m_pointer), *static_cast(args[2].m_pointer), args[3].m_uint); - returnValue->m_uint = (result ? 1 : 0); - } - - bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity) - { - PortabilityLayer::HostSuspendCallArgument cbArgs[4]; - cbArgs[0].m_int = static_cast(dirID); - cbArgs[1].m_pointer = path; - cbArgs[2].m_pointer = &outPathLength; - cbArgs[3].m_size = pathCapacity; - - PortabilityLayer::HostSuspendCallArgument cbReturnValue; - - PortabilityLayer::HostSuspendCallArgument dispatchArgs[3]; - dispatchArgs[0].m_functionPtr = PromptOpenFileCallback; - dispatchArgs[1].m_constPointer = cbArgs; - dispatchArgs[2].m_pointer = &cbReturnValue; - - PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr); - - return cbReturnValue.m_uint != 0; - } - - static void PromptSaveFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue) - { - bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptSaveFile( - static_cast(args[0].m_int), - static_cast(args[1].m_pointer), - *static_cast(args[2].m_pointer), - args[3].m_uint, - static_cast(args[4].m_constPointer)); - - returnValue->m_uint = (result ? 1 : 0); - } - - bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName) - { - PortabilityLayer::HostSuspendCallArgument cbArgs[5]; - cbArgs[0].m_int = static_cast(virtualDirectory); - cbArgs[1].m_pointer = path; - cbArgs[2].m_pointer = &outPathLength; - cbArgs[3].m_size = pathCapacity; - cbArgs[3].m_constPointer = initialFileName; - - PortabilityLayer::HostSuspendCallArgument cbReturnValue; - - PortabilityLayer::HostSuspendCallArgument dispatchArgs[3]; - dispatchArgs[0].m_functionPtr = PromptSaveFileCallback; - dispatchArgs[1].m_constPointer = cbArgs; - dispatchArgs[2].m_pointer = &cbReturnValue; - - PortabilityLayer::SuspendApplication(PortabilityLayer::HostSuspendCallID_CallOnVOSThread, dispatchArgs, nullptr); - - return cbReturnValue.m_uint != 0; - } } diff --git a/PortabilityLayer/PLSysCalls.h b/PortabilityLayer/PLSysCalls.h index 8178aa5..0afce1e 100644 --- a/PortabilityLayer/PLSysCalls.h +++ b/PortabilityLayer/PLSysCalls.h @@ -7,6 +7,4 @@ namespace PLSysCalls { void Sleep(uint32_t ticks); - bool PromptOpenFile(PortabilityLayer::VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity); - bool PromptSaveFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, char *path, size_t &outPathLength, size_t pathCapacity, const char *initialFileName); } diff --git a/PortabilityLayer/PLWidgets.cpp b/PortabilityLayer/PLWidgets.cpp index 813b13f..d99a7df 100644 --- a/PortabilityLayer/PLWidgets.cpp +++ b/PortabilityLayer/PLWidgets.cpp @@ -13,17 +13,18 @@ namespace PortabilityLayer , m_max(0) , m_state(0) , m_enabled(true) + , m_defaultCallback(nullptr) { } - WidgetHandleState_t Widget::ProcessEvent(const TimeTaggedVOSEvent &evt) + WidgetHandleState_t Widget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) { (void)evt; return WidgetHandleStates::kIgnored; } - int16_t Widget::Capture(const Point &pos, WidgetUpdateCallback_t callback) + int16_t Widget::Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback) { return 0; } @@ -64,6 +65,11 @@ namespace PortabilityLayer OnEnabledChanged(); } + bool Widget::IsEnabled() const + { + return m_enabled; + } + void Widget::SetState(int16_t state) { m_state = state; diff --git a/PortabilityLayer/PLWidgets.h b/PortabilityLayer/PLWidgets.h index c707c3d..3f5f45e 100644 --- a/PortabilityLayer/PLWidgets.h +++ b/PortabilityLayer/PLWidgets.h @@ -25,7 +25,7 @@ namespace PortabilityLayer typedef WidgetHandleStates::WidgetHandleState WidgetHandleState_t; - typedef void (*WidgetUpdateCallback_t)(Widget *control, int part); + typedef void (*WidgetUpdateCallback_t)(void *captureContext, Widget *control, int part); struct WidgetBasicState { @@ -40,6 +40,8 @@ namespace PortabilityLayer int16_t m_state; int16_t m_resID; bool m_enabled; + + WidgetUpdateCallback_t m_defaultCallback; }; class Widget @@ -47,8 +49,8 @@ namespace PortabilityLayer public: virtual bool Init(const WidgetBasicState &state, const void *additionalData) = 0; virtual void Destroy() = 0; - virtual WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt); - virtual int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback); + virtual WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt); + virtual int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback); virtual void DrawControl(DrawSurface *surface); virtual void SetMin(int32_t v); @@ -58,6 +60,7 @@ namespace PortabilityLayer void Resize(uint16_t width, uint16_t height); void SetEnabled(bool enabled); + bool IsEnabled() const; virtual void SetState(int16_t state); int16_t GetState() const; diff --git a/PortabilityLayer/PortabilityLayer.vcxproj b/PortabilityLayer/PortabilityLayer.vcxproj index fcc1386..3c4f4f8 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj +++ b/PortabilityLayer/PortabilityLayer.vcxproj @@ -160,6 +160,7 @@ + @@ -303,6 +304,7 @@ + diff --git a/PortabilityLayer/PortabilityLayer.vcxproj.filters b/PortabilityLayer/PortabilityLayer.vcxproj.filters index ee488c6..a7d7b1d 100644 --- a/PortabilityLayer/PortabilityLayer.vcxproj.filters +++ b/PortabilityLayer/PortabilityLayer.vcxproj.filters @@ -459,6 +459,9 @@ Header Files + + Header Files + @@ -731,5 +734,8 @@ Source Files + + Source Files + \ No newline at end of file