diff --git a/Aerofoil/GpSystemServices_Win32.cpp b/Aerofoil/GpSystemServices_Win32.cpp index f1e5f86..7c56fa0 100644 --- a/Aerofoil/GpSystemServices_Win32.cpp +++ b/Aerofoil/GpSystemServices_Win32.cpp @@ -262,6 +262,11 @@ bool GpSystemServices_Win32::IsFullscreenOnStartup() const return false; } +bool GpSystemServices_Win32::HasNativeFileManager() const +{ + return false; +} + unsigned int GpSystemServices_Win32::GetCPUCount() const { SYSTEM_INFO sysInfo; diff --git a/Aerofoil/GpSystemServices_Win32.h b/Aerofoil/GpSystemServices_Win32.h index d72e2b8..8830ed2 100644 --- a/Aerofoil/GpSystemServices_Win32.h +++ b/Aerofoil/GpSystemServices_Win32.h @@ -34,6 +34,7 @@ public: bool IsTextInputObstructive() const override; bool IsFullscreenPreferred() const override; bool IsFullscreenOnStartup() const override; + bool HasNativeFileManager() const override; unsigned int GetCPUCount() const override; void SetTextInputEnabled(bool isEnabled) override; bool IsTextInputEnabled() const override; diff --git a/ApplicationResourcePatches/DITL/2009.json b/ApplicationResourcePatches/DITL/2009.json new file mode 100644 index 0000000..f5ad077 --- /dev/null +++ b/ApplicationResourcePatches/DITL/2009.json @@ -0,0 +1,61 @@ +{ + "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" : [ 196, 16 ], + "id" : 4, + "enabled" : true + }, + { + "name" : "^0", + "itemType" : "Label", + "pos" : [ 16, 16 ], + "size" : [ 418, 16 ], + "id" : 10, + "enabled" : true + }, + { + "name" : "Delete", + "itemType" : "Button", + "pos" : [ 228, 240 ], + "size" : [ 58, 20 ], + "id" : 2, + "enabled" : false + } + ] +} \ No newline at end of file diff --git a/ApplicationResourcePatches/manifest.json b/ApplicationResourcePatches/manifest.json index fb2e19e..b05a6ab 100644 --- a/ApplicationResourcePatches/manifest.json +++ b/ApplicationResourcePatches/manifest.json @@ -12,6 +12,7 @@ "DITL/2006.json" : "ApplicationResourcePatches/DITL/2006.json", "DITL/2007.json" : "ApplicationResourcePatches/DITL/2007.json", "DITL/2008.json" : "ApplicationResourcePatches/DITL/2008.json", + "DITL/2009.json" : "ApplicationResourcePatches/DITL/2009.json", "PICT/1300.bmp" : "ApplicationResourcePatches/PICT/1300.bmp", "PICT/1301.bmp" : "ApplicationResourcePatches/PICT/1301.bmp", "PICT/1971.bmp" : "ApplicationResourcePatches/PICT/1971.bmp", diff --git a/GpApp/House.cpp b/GpApp/House.cpp index 94da04a..b07bdea 100644 --- a/GpApp/House.cpp +++ b/GpApp/House.cpp @@ -76,6 +76,14 @@ static bool FBUI_House_FilterFile(PortabilityLayer::VirtualDirectory_t dirID, co return PortabilityLayer::ResTypeIDCodec::Decode(cfile->GetProperties().m_fileType) == 'gliH'; } +static bool FBUI_House_IsDeleteValid(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &filename) +{ + if (dirID != PortabilityLayer::VirtualDirectories::kUserData) + return false; + + return !StrCmp::EqualCaseInsensitive(thisHouseName, filename); +} + static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetHouseDetailsAPI() { PortabilityLayer::FileBrowserUI_DetailsCallbackAPI api; @@ -85,6 +93,7 @@ static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetHouseDetailsAPI() api.m_loadFileDetailsCallback = FBUI_House_LoadFileDetails; api.m_freeFileDetailsCallback = FBUI_House_FreeFileDetails; api.m_filterFileCallback = FBUI_House_FilterFile; + api.m_isDeleteValidCallback = FBUI_House_IsDeleteValid; return api; } diff --git a/GpApp/SavedGames.cpp b/GpApp/SavedGames.cpp index 10aa2c7..a009124 100644 --- a/GpApp/SavedGames.cpp +++ b/GpApp/SavedGames.cpp @@ -107,6 +107,11 @@ static bool FBUI_Save_FilterFile(PortabilityLayer::VirtualDirectory_t dirID, con return true; } +static bool FBUI_Save_IsDeleteValid(PortabilityLayer::VirtualDirectory_t dirID, const PLPasStr &filename) +{ + return true; +} + static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetSavedGameDetailsAPI() { PortabilityLayer::FileBrowserUI_DetailsCallbackAPI api; @@ -116,6 +121,7 @@ static PortabilityLayer::FileBrowserUI_DetailsCallbackAPI GetSavedGameDetailsAPI api.m_loadFileDetailsCallback = FBUI_Save_LoadFileDetails; api.m_freeFileDetailsCallback = FBUI_Save_FreeFileDetails; api.m_filterFileCallback = FBUI_Save_FilterFile; + api.m_isDeleteValidCallback = FBUI_Save_IsDeleteValid; return api; } diff --git a/GpCommon/IGpSystemServices.h b/GpCommon/IGpSystemServices.h index e60e9a9..e774e8d 100644 --- a/GpCommon/IGpSystemServices.h +++ b/GpCommon/IGpSystemServices.h @@ -32,6 +32,7 @@ public: virtual bool IsFullscreenPreferred() const = 0; virtual bool IsFullscreenOnStartup() const = 0; virtual bool IsTextInputObstructive() const = 0; + virtual bool HasNativeFileManager() const = 0; virtual unsigned int GetCPUCount() const = 0; virtual void SetTextInputEnabled(bool isEnabled) = 0; virtual bool IsTextInputEnabled() const = 0; diff --git a/PortabilityLayer/FileBrowserUI.cpp b/PortabilityLayer/FileBrowserUI.cpp index 4735d03..d6cddea 100644 --- a/PortabilityLayer/FileBrowserUI.cpp +++ b/PortabilityLayer/FileBrowserUI.cpp @@ -40,13 +40,15 @@ static const int kCancelButton = 2; static const int kFileList = 3; static const int kFileListScrollBar = 4; static const int kFileNameEditBox = 5; -static const int kDeleteButton = 5; +static const int kOpenDeleteButton = 5; +static const int kSaveDeleteButton = 7; static const int kFileBrowserUIOpenDialogTemplateID = 2001; static const int kFileBrowserUISaveDialogTemplateID = 2002; static const int kFileBrowserUIOverwriteDialogTemplateID = 2003; static const int kFileBrowserUIBadNameDialogTemplateID = 2004; static const int kFileBrowserUISaveDialogUnobstructiveTemplateID = 2007; static const int kFileBrowserUIDeleteDialogTemplateID = 2008; +static const int kFileBrowserUISaveDialogWithDeleteButtonTemplateID = 2009; static const int kOverwriteNoButton = 1; @@ -57,7 +59,7 @@ namespace PortabilityLayer class FileBrowserUIImpl { public: - explicit FileBrowserUIImpl(const FileBrowserUI_DetailsCallbackAPI &callbackAPI); + FileBrowserUIImpl(VirtualDirectory_t dir, const FileBrowserUI_DetailsCallbackAPI &callbackAPI); ~FileBrowserUIImpl(); static void PubScrollBarCallback(void *captureContext, Widget *control, int part); @@ -111,6 +113,8 @@ namespace PortabilityLayer uint32_t m_doubleClickTime; bool m_haveFirstClick; + VirtualDirectory_t m_dir; + const FileBrowserUI_DetailsCallbackAPI m_api; }; } @@ -128,7 +132,7 @@ static int16_t FileBrowserUIImpl_PopUpAlertUIFilter(void *context, Dialog *dialo namespace PortabilityLayer { - FileBrowserUIImpl::FileBrowserUIImpl(const FileBrowserUI_DetailsCallbackAPI &callbackAPI) + FileBrowserUIImpl::FileBrowserUIImpl(VirtualDirectory_t dir, const FileBrowserUI_DetailsCallbackAPI &callbackAPI) : m_offset(0) , m_surface(nullptr) , m_window(nullptr) @@ -142,6 +146,7 @@ namespace PortabilityLayer , m_doubleClickTime(0) , m_haveFirstClick(false) , m_api(callbackAPI) + , m_dir(dir) { } @@ -439,8 +444,19 @@ namespace PortabilityLayer dialog->GetItems()[kOkayButton - 1].GetWidget()->SetEnabled(selection >= 0); + bool isDeleteValid = (selection >= 0); + + if (isDeleteValid) + { + const FileBrowserUIImpl::FileEntry &entry = (*m_entries)[selection]; + isDeleteValid = m_api.m_isDeleteValidCallback(m_dir, entry.m_nameStr.ToShortStr()); + } + if (gs_currentFileBrowserUIMode == FileBrowserUI::Mode_Open) - dialog->GetItems()[kDeleteButton - 1].GetWidget()->SetEnabled(selection >= 0); + dialog->GetItems()[kOpenDeleteButton - 1].GetWidget()->SetEnabled(isDeleteValid); + else if (gs_currentFileBrowserUIMode == FileBrowserUI::Mode_SaveWithDelete) + dialog->GetItems()[kSaveDeleteButton - 1].GetWidget()->SetEnabled(isDeleteValid); + DrawFileList(); } @@ -585,16 +601,22 @@ namespace PortabilityLayer int windowHeight = 272; if (mode == Mode_Open) dialogID = kFileBrowserUIOpenDialogTemplateID; - else if (mode == Mode_Save) + else if (mode == Mode_SaveWithDelete || mode == Mode_SaveNoDelete) { if (PLDrivers::GetSystemServices()->IsTextInputObstructive()) { dialogID = kFileBrowserUISaveDialogUnobstructiveTemplateID; windowHeight = 208; isObstructive = true; + mode = Mode_SaveNoDelete; // HACK HACK HACK } else - dialogID = kFileBrowserUISaveDialogTemplateID; + { + if (mode == Mode_SaveWithDelete) + dialogID = kFileBrowserUISaveDialogWithDeleteButtonTemplateID; + else + dialogID = kFileBrowserUISaveDialogTemplateID; + } } else { @@ -602,7 +624,7 @@ namespace PortabilityLayer return false; } - FileBrowserUIImpl uiImpl(callbackAPI); + FileBrowserUIImpl uiImpl(dirID, callbackAPI); // Enumerate files IGpFileSystem *fs = PLDrivers::GetFileSystem(); @@ -674,7 +696,7 @@ namespace PortabilityLayer const Rect scrollBarRect = dialog->GetItems()[kFileListScrollBar - 1].GetWidget()->GetRect(); EditboxWidget *editbox = nullptr; - if (mode == Mode_Save) + if (mode == Mode_SaveWithDelete || mode == Mode_SaveNoDelete) { editbox = static_cast(dialog->GetItems()[kFileNameEditBox - 1].GetWidget()); editbox->SetCharacterFilter(&uiImpl, FileBrowserUIImpl::PubEditBoxCharFilter); @@ -725,7 +747,7 @@ namespace PortabilityLayer if (hit == kFileListScrollBar) uiImpl.SetScrollOffset(scrollBar->GetState()); - if (hit == kOkayButton && mode == Mode_Save) + if (hit == kOkayButton && (mode == Mode_SaveWithDelete || mode == Mode_SaveNoDelete)) { IGpFileSystem *fs = PLDrivers::GetFileSystem(); @@ -759,7 +781,7 @@ namespace PortabilityLayer } } - if (mode == Mode_Open && hit == kDeleteButton) + if ((mode == Mode_Open && hit == kOpenDeleteButton) || (mode == Mode_SaveWithDelete && hit == kSaveDeleteButton)) { PLDrivers::GetSystemServices()->Beep(); int16_t subHit = FileBrowserUIImpl::PopUpAlert(Rect::Create(0, 0, 135, 327), kFileBrowserUIDeleteDialogTemplateID, &substitutions); @@ -768,14 +790,18 @@ namespace PortabilityLayer { PLPasStr uiFileName = uiImpl.GetSelectedFileName(); + bool deleted = false; if (composites) - PortabilityLayer::FileManager::GetInstance()->DeleteCompositeFile(dirID, uiFileName); + deleted = PortabilityLayer::FileManager::GetInstance()->DeleteCompositeFile(dirID, uiFileName); else - PortabilityLayer::FileManager::GetInstance()->DeleteNonCompositeFile(dirID, uiFileName, extension); + deleted = PortabilityLayer::FileManager::GetInstance()->DeleteNonCompositeFile(dirID, uiFileName, extension); uiImpl.RemoveSelectedFile(); dialog->GetItems()[kOkayButton - 1].GetWidget()->SetEnabled(false); - dialog->GetItems()[kDeleteButton - 1].GetWidget()->SetEnabled(false); + if (mode == Mode_Open) + dialog->GetItems()[kOpenDeleteButton - 1].GetWidget()->SetEnabled(false); + else if (mode == Mode_SaveWithDelete) + dialog->GetItems()[kSaveDeleteButton - 1].GetWidget()->SetEnabled(false); } hit = -1; } @@ -793,7 +819,7 @@ namespace PortabilityLayer uiFileName = uiImpl.GetSelectedFileName(); confirmed = true; } - else if (mode == Mode_Save) + else if (mode == Mode_SaveWithDelete || mode == Mode_SaveNoDelete) { uiFileName = editbox->GetString(); confirmed = true; diff --git a/PortabilityLayer/FileBrowserUI.h b/PortabilityLayer/FileBrowserUI.h index df7c2bc..e0994b3 100644 --- a/PortabilityLayer/FileBrowserUI.h +++ b/PortabilityLayer/FileBrowserUI.h @@ -20,8 +20,9 @@ namespace PortabilityLayer void(*m_drawFileDetailsCallback)(DrawSurface *surface, const Point &basePoint, const Rect &constraintRect, void *fileDetails); void *(*m_loadFileDetailsCallback)(VirtualDirectory_t dirID, const PLPasStr &filename); - void(*m_freeFileDetailsCallback)(void *fileDetails); - bool(*m_filterFileCallback)(VirtualDirectory_t dirID, const PLPasStr &filename); + void (*m_freeFileDetailsCallback)(void *fileDetails); + bool (*m_filterFileCallback)(VirtualDirectory_t dirID, const PLPasStr &filename); + bool (*m_isDeleteValidCallback)(VirtualDirectory_t dirID, const PLPasStr &filename); }; class FileBrowserUI @@ -30,7 +31,8 @@ namespace PortabilityLayer enum Mode { - Mode_Save, + Mode_SaveNoDelete, + Mode_SaveWithDelete, Mode_Open, }; diff --git a/PortabilityLayer/FileManager.cpp b/PortabilityLayer/FileManager.cpp index 9bc0987..303d041 100644 --- a/PortabilityLayer/FileManager.cpp +++ b/PortabilityLayer/FileManager.cpp @@ -282,7 +282,11 @@ namespace PortabilityLayer if (!FileManagerTools::ConstructFilename(extFN, initialFileName, "")) return false; - return FileBrowserUI::Prompt(FileBrowserUI::Mode_Save, dirID, extension, path, outPathLength, pathCapacity, initialFileName, promptText, composites, detailsAPI); + FileBrowserUI::Mode mode = FileBrowserUI::Mode_SaveNoDelete; + if (!PLDrivers::GetSystemServices()->HasNativeFileManager()) + mode = FileBrowserUI::Mode_SaveWithDelete; + + return FileBrowserUI::Prompt(mode, dirID, extension, path, outPathLength, pathCapacity, initialFileName, promptText, composites, detailsAPI); } bool FileManagerImpl::PromptOpenFile(VirtualDirectory_t dirID, const char *extension, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText, bool composites, const FileBrowserUI_DetailsCallbackAPI &detailsAPI)