Redo file prompts with in-game UI

This commit is contained in:
elasota
2020-09-12 22:29:57 -04:00
parent 8518d01c70
commit b23bb93506
44 changed files with 1133 additions and 362 deletions

View File

@@ -286,172 +286,24 @@ PortabilityLayer::HostDirectoryCursor *GpFileSystem_Win32::ScanDirectory(Portabi
return GpDirectoryCursor_Win32::Create(ff, findData); 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]; if (c >= '0' && c <= '9')
wchar_t baseDir[MAX_PATH + 5]; return true;
const size_t existingPathLen = strlen(initialFileName); if (c == '_' || c == '\'')
if (existingPathLen >= MAX_PATH) return true;
return false;
for (size_t i = 0; i < existingPathLen; i++) if (c == ' ')
baseFN[i] = static_cast<wchar_t>(initialFileName[i]); return true;
baseFN[existingPathLen] = 0;
if (!ResolvePath(virtualDirectory, "", baseDir)) if (c >= 'a' && c <= 'z')
return false; return true;
OPENFILENAMEW ofn; if (c >= 'A' && c <= 'Z')
memset(&ofn, 0, sizeof(ofn)); return true;
ofn.lStructSize = sizeof(ofn); return false;
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<int>(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<wchar_t>(0) || fn[i] >= static_cast<wchar_t>(128))
{
MessageBeep(MB_ICONERROR);
MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK);
return false;
}
path[i] = static_cast<char>(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<int>(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<wchar_t>(0) || fn[i] >= static_cast<wchar_t>(128))
{
MessageBeep(MB_ICONERROR);
MessageBoxW(nullptr, unsupportedCharMsg, L"Invalid file path", MB_OK);
return false;
}
path[i] = static_cast<char>(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::ValidateFilePath(const char *str, size_t length) const 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; 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; return true;
} }

View File

@@ -18,10 +18,8 @@ public:
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override; bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
PortabilityLayer::HostDirectoryCursor *ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) 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 ValidateFilePath(const char *path, size_t sz) const override;
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
const wchar_t *GetBasePath() const; const wchar_t *GetBasePath() const;

View File

@@ -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
}
]
}

View File

@@ -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
}
]
}

View File

@@ -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
}
]
}

View File

@@ -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
}
]
}

View File

@@ -2,7 +2,11 @@
"add" : "add" :
{ {
"DITL/1017.json" : "ApplicationResourcePatches/DITL/1017.json", "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" : "delete" :
[ [

View File

@@ -38,8 +38,8 @@
static void HiLiteOkayButton (DrawSurface *surface); static void HiLiteOkayButton (DrawSurface *surface);
static void UnHiLiteOkayButton (DrawSurface *surface); static void UnHiLiteOkayButton (DrawSurface *surface);
static void UpdateMainPict (Dialog *); static void UpdateMainPict (Dialog *);
static int16_t AboutFilter(Dialog *, const TimeTaggedVOSEvent *evt); static int16_t AboutFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt);
static int16_t AboutFrameworkFilter(Dialog *, const TimeTaggedVOSEvent *evt); static int16_t AboutFrameworkFilter(void *context, Dialog *, const TimeTaggedVOSEvent *evt);
static Point okayButtLowerV, okayButtUpperV; static Point okayButtLowerV, okayButtUpperV;
@@ -91,7 +91,7 @@ void DoAbout (void)
do // Loop until user wants to exit do // Loop until user wants to exit
{ {
hit = aboutDialog->ExecuteModal(AboutFilter); hit = aboutDialog->ExecuteModal(nullptr, AboutFilter);
} }
while (hit != kOkayButton); while (hit != kOkayButton);
@@ -152,7 +152,7 @@ void DoAboutFramework (void)
do do
{ {
hit = dialog->ExecuteModal(AboutFrameworkFilter); hit = dialog->ExecuteModal(nullptr, AboutFrameworkFilter);
} while (hit != kOkayButton); } while (hit != kOkayButton);
dialog->Destroy(); dialog->Destroy();
@@ -248,7 +248,7 @@ static bool PointIsInDiagonalOkayButton(const Point &pt)
//-------------------------------------------------------------- AboutFilter //-------------------------------------------------------------- AboutFilter
// Dialog filter for the About dialog. // 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; bool handledIt = false;
int16_t hit = -1; int16_t hit = -1;
@@ -330,7 +330,7 @@ static int16_t AboutFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- AboutFrameworkFilter //-------------------------------------------------------------- AboutFrameworkFilter
// Dialog filter for the About Framework dialog. // 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; bool handledIt = false;
int16_t hit = -1; int16_t hit = -1;

View File

@@ -41,10 +41,10 @@
void DrawHighScores (DrawSurface *); void DrawHighScores (DrawSurface *);
void UpdateNameDialog (Dialog *); 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 GetHighScoreName (short);
void UpdateBannerDialog (Dialog *); void UpdateBannerDialog (Dialog *);
int16_t BannerFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); int16_t BannerFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
void GetHighScoreBanner (void); void GetHighScoreBanner (void);
Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream); Boolean OpenHighScoresFile (const VFileSpec &spec, GpIOStream *&outStream);
@@ -456,7 +456,7 @@ static bool EventIsTyping(const GpKeyboardInputEvent &kbEvent)
//-------------------------------------------------------------- NameFilter //-------------------------------------------------------------- NameFilter
// Dialog filter for the "Enter High Score Name" dialog. // 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; short nChars;
@@ -537,7 +537,7 @@ void GetHighScoreName (short place)
while (!leaving) while (!leaving)
{ {
item = theDial->ExecuteModal(NameFilter); item = theDial->ExecuteModal(nullptr, NameFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -571,7 +571,7 @@ void UpdateBannerDialog (Dialog *theDialog)
//-------------------------------------------------------------- BannerFilter //-------------------------------------------------------------- BannerFilter
// Dialog filter for the "Enter Message" dialog. // 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; short nChars;
@@ -647,7 +647,7 @@ void GetHighScoreBanner (void)
while (!leaving) while (!leaving)
{ {
item = theDial->ExecuteModal(BannerFilter); item = theDial->ExecuteModal(nullptr, BannerFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {

View File

@@ -26,7 +26,7 @@
void UpdateGoToDialog (Dialog *); 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; extern PortabilityLayer::ResourceArchive *houseResFork;
@@ -67,7 +67,7 @@ Boolean CreateNewHouse (void)
char savePath[sizeof(theSpec.m_name) + 1]; char savePath[sizeof(theSpec.m_name) + 1];
size_t savePathLength = 0; 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; return false;
assert(savePathLength < sizeof(theSpec.m_name) - 1); assert(savePathLength < sizeof(theSpec.m_name) - 1);
@@ -599,7 +599,7 @@ void UpdateGoToDialog (Dialog *theDialog)
//-------------------------------------------------------------- GoToFilter //-------------------------------------------------------------- GoToFilter
// Dialog filter for the "Go To Room..." dialog. // 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) if (!evt)
return -1; return -1;
@@ -656,7 +656,7 @@ int16_t GoToFilter(Dialog *dial, const TimeTaggedVOSEvent *evt)
while (!leaving) while (!leaving)
{ {
item = theDialog->ExecuteModal(GoToFilter); item = theDialog->ExecuteModal(nullptr, GoToFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {

View File

@@ -34,7 +34,7 @@
long CountTotalHousePoints (void); long CountTotalHousePoints (void);
void UpdateHouseInfoDialog (Dialog *); void UpdateHouseInfoDialog (Dialog *);
int16_t HouseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt); int16_t HouseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt);
Boolean WarnLockingHouse (void); Boolean WarnLockingHouse (void);
void HowToZeroScores (void); void HowToZeroScores (void);
@@ -123,7 +123,7 @@ void UpdateHouseInfoDialog (Dialog *theDialog)
//-------------------------------------------------------------- HouseFilter //-------------------------------------------------------------- HouseFilter
int16_t HouseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t HouseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
Point mouseIs; Point mouseIs;
short nChars; short nChars;
@@ -248,7 +248,7 @@ void DoHouseInfo (void)
while (!leaving) while (!leaving)
{ {
item = houseInfoDialog->ExecuteModal(HouseFilter); item = houseInfoDialog->ExecuteModal(nullptr, HouseFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {

View File

@@ -383,7 +383,7 @@ void HandleLinkClick (Point wherePt)
part = FindControl(wherePt, linkWindow, &theControl); part = FindControl(wherePt, linkWindow, &theControl);
if ((theControl != nil) && (part != 0)) if ((theControl != nil) && (part != 0))
{ {
part = theControl->Capture(wherePt, nullptr); part = theControl->Capture(nullptr, wherePt, nullptr);
if (part != 0) if (part != 0)
{ {
if (theControl == linkControl) if (theControl == linkControl)

View File

@@ -489,7 +489,7 @@ void ToggleMapWindow (void)
//-------------------------------------------------------------- LiveHScrollAction //-------------------------------------------------------------- LiveHScrollAction
#ifndef COMPILEDEMO #ifndef COMPILEDEMO
void LiveHScrollAction (PortabilityLayer::Widget *theControl, int thePart) void LiveHScrollAction (void *captureContext, PortabilityLayer::Widget *theControl, int thePart)
{ {
short wasValue, newValue; short wasValue, newValue;
@@ -546,7 +546,7 @@ void LiveHScrollAction (PortabilityLayer::Widget *theControl, int thePart)
//-------------------------------------------------------------- LiveVScrollAction //-------------------------------------------------------------- LiveVScrollAction
#ifndef COMPILEDEMO #ifndef COMPILEDEMO
void LiveVScrollAction (PortabilityLayer::Widget *theControl, int thePart) void LiveVScrollAction (void *captureContext, PortabilityLayer::Widget *theControl, int thePart)
{ {
short wasValue, newValue; short wasValue, newValue;
@@ -695,11 +695,11 @@ void HandleMapClick (const GpMouseInputEvent &theEvent)
case kControlDownButtonPart: case kControlDownButtonPart:
case kControlPageUpPart: case kControlPageUpPart:
case kControlPageDownPart: case kControlPageDownPart:
whichControl->Capture(wherePt, LiveHScrollAction); whichControl->Capture(nullptr, wherePt, LiveHScrollAction);
break; break;
case kControlIndicatorPart: case kControlIndicatorPart:
if (whichControl->Capture(wherePt, nil)) if (whichControl->Capture(nullptr, wherePt, nil))
{ {
mapLeftRoom = whichControl->GetState(); mapLeftRoom = whichControl->GetState();
RedrawMapContents(); RedrawMapContents();
@@ -715,11 +715,11 @@ void HandleMapClick (const GpMouseInputEvent &theEvent)
case kControlDownButtonPart: case kControlDownButtonPart:
case kControlPageUpPart: case kControlPageUpPart:
case kControlPageDownPart: case kControlPageDownPart:
whichControl->Capture(wherePt, LiveVScrollAction); whichControl->Capture(nullptr, wherePt, LiveVScrollAction);
break; break;
case kControlIndicatorPart: case kControlIndicatorPart:
if (whichControl->Capture(wherePt, nil)) if (whichControl->Capture(nullptr, wherePt, nil))
{ {
mapTopRoom = whichControl->GetState(); mapTopRoom = whichControl->GetState();
RedrawMapContents(); RedrawMapContents();

View File

@@ -347,7 +347,7 @@ void UpdateFlowerInfo (Dialog *theDialog)
//-------------------------------------------------------------- BlowerFilter //-------------------------------------------------------------- BlowerFilter
int16_t BlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t BlowerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -381,7 +381,7 @@ int16_t BlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- FurnitureFilter //-------------------------------------------------------------- FurnitureFilter
int16_t FurnitureFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t FurnitureFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -407,7 +407,7 @@ int16_t FurnitureFilter(Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- CustPictFilter //-------------------------------------------------------------- CustPictFilter
int16_t CustPictFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t CustPictFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -431,7 +431,7 @@ int16_t CustPictFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- SwitchFilter //-------------------------------------------------------------- SwitchFilter
int16_t SwitchFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t SwitchFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -459,7 +459,7 @@ int16_t SwitchFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- TriggerFilter //-------------------------------------------------------------- TriggerFilter
int16_t TriggerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t TriggerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -491,7 +491,7 @@ int16_t TriggerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- LightFilter //-------------------------------------------------------------- LightFilter
int16_t LightFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t LightFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -519,7 +519,7 @@ int16_t LightFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- ApplianceFilter //-------------------------------------------------------------- ApplianceFilter
int16_t ApplianceFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t ApplianceFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -551,7 +551,7 @@ int16_t ApplianceFilter(Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- MicrowaveFilter //-------------------------------------------------------------- MicrowaveFilter
int16_t MicrowaveFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t MicrowaveFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -579,7 +579,7 @@ int16_t MicrowaveFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- GreaseFilter //-------------------------------------------------------------- GreaseFilter
int16_t GreaseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t GreaseFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -607,7 +607,7 @@ int16_t GreaseFilter(Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- InvisBonusFilter //-------------------------------------------------------------- InvisBonusFilter
int16_t InvisBonusFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t InvisBonusFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -631,7 +631,7 @@ int16_t InvisBonusFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- TransFilter //-------------------------------------------------------------- TransFilter
int16_t TransFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t TransFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -659,7 +659,7 @@ int16_t TransFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- EnemyFilter //-------------------------------------------------------------- EnemyFilter
int16_t EnemyFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t EnemyFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -691,7 +691,7 @@ int16_t EnemyFilter (Dialog *dial, const TimeTaggedVOSEvent *evt)
//-------------------------------------------------------------- FlowerFilter //-------------------------------------------------------------- FlowerFilter
int16_t FlowerFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t FlowerFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -785,7 +785,7 @@ void DoBlowerObjectInfo (short what)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(BlowerFilter); item = infoDial->ExecuteModal(nullptr, BlowerFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -937,7 +937,7 @@ void DoFurnitureObjectInfo (void)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(FurnitureFilter); item = infoDial->ExecuteModal(nullptr, FurnitureFilter);
if (item == kOkayButton) if (item == kOkayButton)
leaving = true; leaving = true;
@@ -997,7 +997,7 @@ void DoCustPictObjectInfo (void)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(CustPictFilter); item = infoDial->ExecuteModal(nullptr, CustPictFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1106,7 +1106,7 @@ void DoSwitchObjectInfo (void)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(SwitchFilter); item = infoDial->ExecuteModal(nullptr, SwitchFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1231,7 +1231,7 @@ void DoTriggerObjectInfo (void)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(TriggerFilter); item = infoDial->ExecuteModal(nullptr, TriggerFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1371,7 +1371,7 @@ void DoLightObjectInfo (void)
while (!leaving) while (!leaving)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(LightFilter); item = infoDial->ExecuteModal(nullptr, LightFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1465,7 +1465,7 @@ void DoApplianceObjectInfo (short what)
while (!leaving) while (!leaving)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(ApplianceFilter); item = infoDial->ExecuteModal(nullptr, ApplianceFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1585,7 +1585,7 @@ void DoMicrowaveObjectInfo (void)
while (!leaving) while (!leaving)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(MicrowaveFilter); item = infoDial->ExecuteModal(nullptr, MicrowaveFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1695,7 +1695,7 @@ void DoGreaseObjectInfo (void)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(GreaseFilter); item = infoDial->ExecuteModal(nullptr, GreaseFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1783,7 +1783,7 @@ void DoInvisBonusObjectInfo (void)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(InvisBonusFilter); item = infoDial->ExecuteModal(nullptr, InvisBonusFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -1907,7 +1907,7 @@ void DoTransObjectInfo (short what)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(TransFilter); item = infoDial->ExecuteModal(nullptr, TransFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -2017,7 +2017,7 @@ void DoEnemyObjectInfo (short what)
while (!leaving) while (!leaving)
{ {
item = infoDial->ExecuteModal(EnemyFilter); item = infoDial->ExecuteModal(nullptr, EnemyFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -2113,7 +2113,7 @@ void DoFlowerObjectInfo (void)
{ {
bool redrawMain = false; bool redrawMain = false;
item = infoDial->ExecuteModal(FlowerFilter); item = infoDial->ExecuteModal(nullptr, FlowerFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {

View File

@@ -47,11 +47,11 @@
void UpdateRoomInfoDialog (Dialog *); void UpdateRoomInfoDialog (Dialog *);
void DragMiniTile (Window *, DrawSurface *, Point, short *); void DragMiniTile (Window *, DrawSurface *, Point, short *);
void HiliteTileOver (DrawSurface *, Point); 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); short ChooseOriginalArt (short);
void UpdateOriginalArt (Dialog *); void UpdateOriginalArt (Dialog *);
int16_t OriginalArtFilter (Dialog *dialog, const TimeTaggedVOSEvent *evt); int16_t OriginalArtFilter (void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
Boolean PictIDExists (short); Boolean PictIDExists (short);
short GetFirstPICT (void); short GetFirstPICT (void);
void BitchAboutPICTNotFound (void); void BitchAboutPICTNotFound (void);
@@ -344,7 +344,7 @@ void HiliteTileOver (DrawSurface *surface, Point mouseIs)
//-------------------------------------------------------------- RoomFilter //-------------------------------------------------------------- RoomFilter
#ifndef COMPILEDEMO #ifndef COMPILEDEMO
int16_t RoomFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t RoomFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
Point mouseIs; Point mouseIs;
short newTileOver; short newTileOver;
@@ -502,7 +502,7 @@ void DoRoomInfo(void)
{ {
bool needRedraw = false; bool needRedraw = false;
item = roomInfoDialog->ExecuteModal(RoomFilter); item = roomInfoDialog->ExecuteModal(nullptr, RoomFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {
@@ -639,7 +639,7 @@ void UpdateOriginalArt (Dialog *theDialog)
//-------------------------------------------------------------- OriginalArtFilter //-------------------------------------------------------------- OriginalArtFilter
#ifndef COMPILEDEMO #ifndef COMPILEDEMO
int16_t OriginalArtFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t OriginalArtFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
Point mouseIs; Point mouseIs;
@@ -737,7 +737,7 @@ short ChooseOriginalArt (short was)
while (!leaving) while (!leaving)
{ {
item = theDialog->ExecuteModal(OriginalArtFilter); item = theDialog->ExecuteModal(nullptr, OriginalArtFilter);
if (item == kOkayButton) if (item == kOkayButton)
{ {

View File

@@ -82,7 +82,7 @@ void SaveGame2 (void)
char savePath[sizeof(spec.m_name) + 1]; char savePath[sizeof(spec.m_name) + 1];
size_t savePathLength = 0; 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); mm->Release(savedGame);
return; return;
@@ -191,7 +191,7 @@ Boolean OpenSavedGame (void)
char savePath[sizeof(spec.m_name) + 1]; char savePath[sizeof(spec.m_name) + 1];
size_t savePathLength = 0; 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; return false;
assert(savePathLength < sizeof(spec.m_name) - 1); assert(savePathLength < sizeof(spec.m_name) - 1);

View File

@@ -201,7 +201,7 @@ void PageDownHouses (Dialog *theDial)
//-------------------------------------------------------------- LoadFilter //-------------------------------------------------------------- LoadFilter
#ifndef COMPILEDEMO #ifndef COMPILEDEMO
int16_t LoadFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t LoadFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
short screenCount, i, wasIndex; short screenCount, i, wasIndex;
@@ -398,7 +398,7 @@ void DoLoadHouse (void)
while (!leaving) while (!leaving)
{ {
int16_t item = theDial->ExecuteModal(LoadFilter); int16_t item = theDial->ExecuteModal(nullptr, LoadFilter);
bool requiresRedraw = false; bool requiresRedraw = false;

View File

@@ -97,7 +97,7 @@ void DoDisplayPrefs (void);
void SetAllDefaults (void); void SetAllDefaults (void);
void FlashSettingsButton (DrawSurface *, short); void FlashSettingsButton (DrawSurface *, short);
void UpdateSettingsMain (Dialog *); void UpdateSettingsMain (Dialog *);
int16_t PrefsFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt); int16_t PrefsFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt);
void BitchAboutChanges (void); void BitchAboutChanges (void);
@@ -158,7 +158,7 @@ void UpdateSettingsBrains (Dialog *theDialog)
//-------------------------------------------------------------- BrainsFilter //-------------------------------------------------------------- BrainsFilter
int16_t BrainsFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t BrainsFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -253,7 +253,7 @@ void DoBrainsPrefs (void)
while (!leaving) while (!leaving)
{ {
itemHit = prefDlg->ExecuteModal(BrainsFilter); itemHit = prefDlg->ExecuteModal(nullptr, BrainsFilter);
switch (itemHit) switch (itemHit)
{ {
case kOkayButton: case kOkayButton:
@@ -383,7 +383,7 @@ void UpdateSettingsControl (Dialog *theDialog)
//-------------------------------------------------------------- ControlFilter //-------------------------------------------------------------- ControlFilter
int16_t ControlFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t ControlFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
intptr_t wasKeyMap; intptr_t wasKeyMap;
@@ -535,7 +535,7 @@ void DoControlPrefs (void)
while (!leaving) while (!leaving)
{ {
itemHit = prefDlg->ExecuteModal(ControlFilter); itemHit = prefDlg->ExecuteModal(nullptr, ControlFilter);
switch (itemHit) switch (itemHit)
{ {
case kOkayButton: case kOkayButton:
@@ -660,7 +660,7 @@ void HandleSoundMusicChange (short newVolume, Boolean sayIt)
//-------------------------------------------------------------- SoundFilter //-------------------------------------------------------------- SoundFilter
int16_t SoundFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t SoundFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
short newVolume; short newVolume;
@@ -757,7 +757,7 @@ void DoSoundPrefs (void)
while (!leaving) while (!leaving)
{ {
itemHit = prefDlg->ExecuteModal(SoundFilter); itemHit = prefDlg->ExecuteModal(nullptr, SoundFilter);
switch (itemHit) switch (itemHit)
{ {
@@ -928,7 +928,7 @@ void DisplayUpdate (Dialog *theDialog)
//-------------------------------------------------------------- DisplayFilter //-------------------------------------------------------------- DisplayFilter
int16_t DisplayFilter(Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t DisplayFilter(void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
if (!evt) if (!evt)
return -1; return -1;
@@ -1025,7 +1025,7 @@ void DoDisplayPrefs (void)
while (!leaving) while (!leaving)
{ {
int16_t itemHit = prefDlg->ExecuteModal(DisplayFilter); int16_t itemHit = prefDlg->ExecuteModal(nullptr, DisplayFilter);
switch (itemHit) switch (itemHit)
{ {
case kOkayButton: case kOkayButton:
@@ -1202,7 +1202,7 @@ void UpdateSettingsMain (Dialog *theDialog)
//-------------------------------------------------------------- PrefsFilter //-------------------------------------------------------------- PrefsFilter
int16_t PrefsFilter (Dialog *dial, const TimeTaggedVOSEvent *evt) int16_t PrefsFilter (void *context, Dialog *dial, const TimeTaggedVOSEvent *evt)
{ {
short i; short i;
Boolean foundHit; Boolean foundHit;
@@ -1292,7 +1292,7 @@ void DoSettingsMain (void)
while (!leaving) while (!leaving)
{ {
int16_t selectedItem = prefDlg->ExecuteModal(PrefsFilter); int16_t selectedItem = prefDlg->ExecuteModal(nullptr, PrefsFilter);
switch (selectedItem) switch (selectedItem)
{ {

View File

@@ -473,7 +473,7 @@ void HandleToolsClick (Point wherePt)
part = FindControl(wherePt, toolsWindow, &theControl); part = FindControl(wherePt, toolsWindow, &theControl);
if ((theControl != nil) && (part != 0)) if ((theControl != nil) && (part != 0))
{ {
part = theControl->Capture(wherePt, nullptr); part = theControl->Capture(nullptr, wherePt, nullptr);
if (part != 0) if (part != 0)
{ {
newMode = theControl->GetState(); newMode = theControl->GetState();

View File

@@ -88,7 +88,7 @@ namespace PortabilityLayer
ArrayView<const DialogItem> GetItems() const override; ArrayView<const DialogItem> GetItems() const override;
void SetItemVisibility(unsigned int itemIndex, bool isVisible) 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; 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); 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; Window *m_window;
DialogItem *m_items; 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(); Window *exclWindow = this->GetWindow();
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
int16_t result = ExecuteModalInDarkenStack(filterFunc); int16_t result = ExecuteModalInDarkenStack(captureContext, filterFunc);
WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow); WindowManager::GetInstance()->SwapExclusiveWindow(exclWindow);
return result; return result;
} }
int16_t DialogImpl::ExecuteModalInDarkenStack(DialogFilterFunc_t filterFunc) int16_t DialogImpl::ExecuteModalInDarkenStack(void *captureContext, DialogFilterFunc_t filterFunc)
{ {
Window *window = this->GetWindow(); Window *window = this->GetWindow();
Widget *capturingWidget = nullptr; Widget *capturingWidget = nullptr;
@@ -362,7 +362,7 @@ namespace PortabilityLayer
if (window->IsHandlingTickEvents()) if (window->IsHandlingTickEvents())
window->OnTick(); 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) if (selection >= 0)
return selection; return selection;
@@ -371,7 +371,7 @@ namespace PortabilityLayer
{ {
if (capturingWidget != nullptr) if (capturingWidget != nullptr)
{ {
const WidgetHandleState_t state = capturingWidget->ProcessEvent(evt); const WidgetHandleState_t state = capturingWidget->ProcessEvent(captureContext, evt);
if (state != WidgetHandleStates::kDigested) if (state != WidgetHandleStates::kDigested)
capturingWidget = nullptr; capturingWidget = nullptr;
@@ -398,7 +398,7 @@ namespace PortabilityLayer
{ {
Widget *widget = this->m_items[i].GetWidget(); 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) if (state == WidgetHandleStates::kActivated)
return static_cast<int16_t>(i + 1); return static_cast<int16_t>(i + 1);
@@ -621,7 +621,7 @@ namespace PortabilityLayer
private: 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; static DialogManagerImpl ms_instance;
}; };
@@ -706,7 +706,7 @@ namespace PortabilityLayer
return dialog; return dialog;
} }
int16_t DialogManagerImpl::AlertFilter(Dialog *dialog, const TimeTaggedVOSEvent *evt) int16_t DialogManagerImpl::AlertFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
{ {
return -1; return -1;
} }
@@ -767,7 +767,7 @@ namespace PortabilityLayer
if (!dialog) if (!dialog)
return 0; return 0;
int16_t hit = dialog->ExecuteModal(DialogManagerImpl::AlertFilter); int16_t hit = dialog->ExecuteModal(nullptr, DialogManagerImpl::AlertFilter);
dialog->Destroy(); dialog->Destroy();
return hit; return hit;

View File

@@ -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 <algorithm>
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<NameStr_t> 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<FileBrowserUIImpl*>(captureContext)->ScrollBarCallback(control, part);
}
int16_t FileBrowserUIImpl::PubFileBrowserUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
{
return static_cast<FileBrowserUIImpl*>(context)->FileBrowserUIFilter(dialog, evt);
}
int16_t FileBrowserUIImpl::PubPopUpAlertUIFilter(void *context, Dialog *dialog, const TimeTaggedVOSEvent *evt)
{
return static_cast<FileBrowserUIImpl*>(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<NameStr_t>(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<size_t>(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<int32_t>(m_numNames) * m_fontSpacing - boxHeight);
if (overCapacity < 0)
return 0;
else
return static_cast<uint16_t>(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<size_t>(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<EditboxWidget*>(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<EditboxWidget*>(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;
}
}

View File

@@ -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);
};
}

View File

@@ -1,4 +1,6 @@
#include "FileManager.h" #include "FileManager.h"
#include "FileBrowserUI.h"
#include "HostFileSystem.h" #include "HostFileSystem.h"
#include "HostMemoryBuffer.h" #include "HostMemoryBuffer.h"
#include "MemReaderStream.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 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; 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 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) override; bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) override;
static FileManagerImpl *GetInstance(); static FileManagerImpl *GetInstance();
@@ -174,18 +176,18 @@ namespace PortabilityLayer
return RawOpenFileFork(dirID, filename, ".gpa", permission, ignoreMeta, createDisposition, outStream); 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; ExtendedFileName_t extFN;
if (!ConstructFilename(extFN, initialFileName, "")) if (!ConstructFilename(extFN, initialFileName, ""))
return false; 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() FileManagerImpl *FileManagerImpl::GetInstance()

View File

@@ -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 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 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 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) = 0; virtual bool PromptOpenFile(VirtualDirectory_t dirID, char *path, size_t &outPathLength, size_t pathCapacity, const PLPasStr &promptText) = 0;
static FileManager *GetInstance(); static FileManager *GetInstance();
}; };

View File

@@ -20,9 +20,8 @@ namespace PortabilityLayer
virtual bool DeleteFile(VirtualDirectory_t virtualDirectory, const char *path, bool &existed) = 0; virtual bool DeleteFile(VirtualDirectory_t virtualDirectory, const char *path, bool &existed) = 0;
virtual HostDirectoryCursor *ScanDirectory(VirtualDirectory_t virtualDirectory) = 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 ValidateFilePath(const char *path, size_t pathLen) const = 0;
virtual bool ValidateFilePathUnicodeChar(uint32_t ch) const = 0;
static HostFileSystem *GetInstance(); static HostFileSystem *GetInstance();
static void SetInstance(HostFileSystem *instance); static void SetInstance(HostFileSystem *instance);

View File

@@ -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) if (!m_visible || !m_enabled)
return WidgetHandleStates::kIgnored; return WidgetHandleStates::kIgnored;
@@ -240,7 +240,7 @@ namespace PortabilityLayer
if (m_rect.Contains(pt)) if (m_rect.Contains(pt))
{ {
if (Capture(pt, nullptr) == RegionIDs::kNone) if (Capture(captureContext, pt, nullptr) == RegionIDs::kNone)
return WidgetHandleStates::kDigested; return WidgetHandleStates::kDigested;
else else
return WidgetHandleStates::kActivated; return WidgetHandleStates::kActivated;
@@ -264,7 +264,7 @@ namespace PortabilityLayer
DrawControl(m_window->GetDrawSurface()); 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) if (!m_enabled || !m_visible)
return 0; return 0;

View File

@@ -30,10 +30,10 @@ namespace PortabilityLayer
void SetString(const PLPasStr &str) override; void SetString(const PLPasStr &str) override;
PLPasStr GetString() const 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 OnEnabledChanged() override;
void OnStateChanged() 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; void SetHighlightStyle(int16_t style, bool enabled) override;
static void DrawDefaultButtonChrome(const Rect &rect, DrawSurface *surface); static void DrawDefaultButtonChrome(const Rect &rect, DrawSurface *surface);

View File

@@ -14,7 +14,7 @@ class PLPasStr;
struct Control; struct Control;
struct Dialog; 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 struct DialogTextSubstitutions
{ {
@@ -39,7 +39,7 @@ struct Dialog
virtual void SetItemVisibility(unsigned int itemIndex, bool isVisible) = 0; 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; virtual bool ReplaceWidget(unsigned int itemIndex, PortabilityLayer::Widget *widget) = 0;
}; };

View File

@@ -35,6 +35,8 @@ namespace PortabilityLayer
, m_isDraggingSelection(false) , m_isDraggingSelection(false)
, m_dragSelectionStartChar(false) , m_dragSelectionStartChar(false)
, m_scrollOffset(0, 0) , m_scrollOffset(0, 0)
, m_characterFilter(nullptr)
, m_characterFilterContext(nullptr)
{ {
} }
@@ -121,17 +123,17 @@ namespace PortabilityLayer
m_length = len; m_length = len;
memcpy(m_chars, str.UChars(), len); memcpy(m_chars, str.UChars(), len);
if (m_selStartChar > len)
m_selStartChar = len;
if (m_selEndChar > len)
m_selEndChar = len;
if (m_window) if (m_window)
{ {
DrawSurface *surface = m_window->GetDrawSurface(); DrawSurface *surface = m_window->GetDrawSurface();
DrawControl(surface); DrawControl(surface);
} }
if (m_selStartChar > len)
m_selStartChar = len;
if (m_selEndChar > len)
m_selEndChar = len;
} }
PLPasStr EditboxWidget::GetString() const PLPasStr EditboxWidget::GetString() const
@@ -166,7 +168,7 @@ namespace PortabilityLayer
Redraw(); Redraw();
} }
WidgetHandleState_t EditboxWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) WidgetHandleState_t EditboxWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
{ {
if (m_isDraggingSelection) if (m_isDraggingSelection)
return HandleDragSelection(evt); return HandleDragSelection(evt);
@@ -200,6 +202,12 @@ namespace PortabilityLayer
resolvedChar = MacRoman::FromUnicode(ch, keyEvent.m_key.m_unicodeChar); resolvedChar = MacRoman::FromUnicode(ch, keyEvent.m_key.m_unicodeChar);
} }
if (resolvedChar)
{
if (m_characterFilter)
resolvedChar = m_characterFilter(m_characterFilterContext, ch);
}
if (resolvedChar) if (resolvedChar)
{ {
if (ch >= 0x20 && ch <= 0x7e) if (ch >= 0x20 && ch <= 0x7e)
@@ -979,4 +987,15 @@ namespace PortabilityLayer
Redraw(); 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<size_t>(255, capacity);
}
} }

View File

@@ -11,6 +11,8 @@ namespace PortabilityLayer
class EditboxWidget final : public WidgetSpec<EditboxWidget> class EditboxWidget final : public WidgetSpec<EditboxWidget>
{ {
public: public:
typedef bool (*CharacterFilterCallback_t)(void *context, uint8_t character);
EditboxWidget(const WidgetBasicState &state); EditboxWidget(const WidgetBasicState &state);
~EditboxWidget(); ~EditboxWidget();
@@ -23,7 +25,7 @@ namespace PortabilityLayer
void GainFocus() override; void GainFocus() override;
void LoseFocus() override; void LoseFocus() override;
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
Rect GetExpandedRect() const override; Rect GetExpandedRect() const override;
@@ -33,6 +35,9 @@ namespace PortabilityLayer
void SetMultiLine(bool isMultiLine); void SetMultiLine(bool isMultiLine);
void SetCharacterFilter(void *context, CharacterFilterCallback_t callback);
void SetCapacity(size_t capacity);
private: private:
static const unsigned int kCaratBlinkRate = 20; static const unsigned int kCaratBlinkRate = 20;
static const unsigned int kMouseScrollRate = 20; static const unsigned int kMouseScrollRate = 20;
@@ -92,5 +97,8 @@ namespace PortabilityLayer
size_t m_dragSelectionStartChar; size_t m_dragSelectionStartChar;
uint16_t m_caratTimer; uint16_t m_caratTimer;
CharacterFilterCallback_t m_characterFilter;
void *m_characterFilterContext;
}; };
} }

View File

@@ -48,7 +48,7 @@ namespace PortabilityLayer
surface->m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents); 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) if (!m_visible || !m_enabled)
return WidgetHandleStates::kIgnored; return WidgetHandleStates::kIgnored;

View File

@@ -17,7 +17,7 @@ namespace PortabilityLayer
void DrawControl(DrawSurface *surface) override; void DrawControl(DrawSurface *surface) override;
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt) override; WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt) override;
private: private:
THandle<PixMapImpl> m_iconImage; THandle<PixMapImpl> m_iconImage;

View File

@@ -21,7 +21,7 @@ namespace PortabilityLayer
return true; return true;
} }
WidgetHandleState_t InvisibleWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) WidgetHandleState_t InvisibleWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
{ {
if (!m_visible || !m_enabled) if (!m_visible || !m_enabled)
return WidgetHandleStates::kIgnored; return WidgetHandleStates::kIgnored;

View File

@@ -12,7 +12,7 @@ namespace PortabilityLayer
bool Init(const WidgetBasicState &state, const void *additionalData) override; 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: private:
bool m_clickable; bool m_clickable;

View File

@@ -39,7 +39,7 @@ namespace PortabilityLayer
return true; return true;
} }
WidgetHandleState_t PopupMenuWidget::ProcessEvent(const TimeTaggedVOSEvent &evt) WidgetHandleState_t PopupMenuWidget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
{ {
if (evt.IsLMouseDownEvent()) if (evt.IsLMouseDownEvent())
{ {
@@ -49,7 +49,7 @@ namespace PortabilityLayer
if (this->m_rect.Contains(Point::Create(localPoint.m_x, localPoint.m_y))) 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) if (part >= 1)
return WidgetHandleStates::kActivated; return WidgetHandleStates::kActivated;
else else
@@ -60,7 +60,7 @@ namespace PortabilityLayer
return WidgetHandleStates::kIgnored; 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(); MenuManager *mm = PortabilityLayer::MenuManager::GetInstance();

View File

@@ -14,8 +14,8 @@ namespace PortabilityLayer
bool Init(const WidgetBasicState &state, const void *additionalData) override; bool Init(const WidgetBasicState &state, const void *additionalData) override;
WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt); WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt);
int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback); int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
void DrawControl(DrawSurface *surface) override; void DrawControl(DrawSurface *surface) override;
void OnStateChanged() override; void OnStateChanged() override;

View File

@@ -4,6 +4,8 @@
#include "PLTimeTaggedVOSEvent.h" #include "PLTimeTaggedVOSEvent.h"
#include "ResolveCachingColor.h" #include "ResolveCachingColor.h"
#include "PLRegions.h"
namespace PortabilityLayer namespace PortabilityLayer
{ {
ScrollBarWidget::ScrollBarWidget(const WidgetBasicState &state) ScrollBarWidget::ScrollBarWidget(const WidgetBasicState &state)
@@ -15,14 +17,30 @@ namespace PortabilityLayer
, m_laneCapacity(0) , m_laneCapacity(0)
, m_isActive(false) , m_isActive(false)
, m_activePart(0) , 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) if (!m_visible || !m_enabled)
return WidgetHandleStates::kIgnored; 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; 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); int part = ResolvePart(pos);
if (!part) if (!part)
return 0; return 0;
if (part == kControlIndicatorPart) if (part == kControlIndicatorPart)
return CaptureIndicator(pos, callback); return CaptureIndicator(captureContext, pos, callback);
else 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; int tickDelay = 15;
@@ -308,7 +326,7 @@ namespace PortabilityLayer
if (ticksUntilIterate == 0) if (ticksUntilIterate == 0)
{ {
if (m_isActive) if (m_isActive)
IterateScrollSegment(part, callback); IterateScrollSegment(captureContext, part, callback);
ticksUntilIterate = tickDelay; 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(); 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) if (callback != nullptr)
callback(this, part); callback(captureContext, this, part);
} }
int ScrollBarWidget::ResolvePart(const Point &point) const int ScrollBarWidget::ResolvePart(const Point &point) const

View File

@@ -15,7 +15,7 @@ namespace PortabilityLayer
bool Init(const WidgetBasicState &state, const void *additionalData) override; bool Init(const WidgetBasicState &state, const void *additionalData) override;
void OnEnabledChanged() 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 DrawControl(DrawSurface *surface) override;
void SetState(int16_t state) override; void SetState(int16_t state) override;
@@ -24,7 +24,7 @@ namespace PortabilityLayer
void SetMin(int32_t v) override; void SetMin(int32_t v) override;
void SetMax(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; int ResolvePart(const Point &point) const override;
@@ -39,9 +39,9 @@ namespace PortabilityLayer
static void DrawBeveledBox(DrawSurface *surface, const Rect &rect); static void DrawBeveledBox(DrawSurface *surface, const Rect &rect);
int16_t CaptureScrollSegment(const Point &pos, int part, WidgetUpdateCallback_t callback); int16_t CaptureScrollSegment(void *captureContext, const Point &pos, int part, WidgetUpdateCallback_t callback);
int16_t CaptureIndicator(const Point &pos, WidgetUpdateCallback_t callback); int16_t CaptureIndicator(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
void IterateScrollSegment(int part, WidgetUpdateCallback_t callback); void IterateScrollSegment(void *captureContext, int part, WidgetUpdateCallback_t callback);
int32_t m_min; int32_t m_min;
int32_t m_max; int32_t m_max;
@@ -51,5 +51,7 @@ namespace PortabilityLayer
bool m_isActive; bool m_isActive;
int m_activePart; int m_activePart;
WidgetUpdateCallback_t m_callback;
}; };
} }

View File

@@ -175,63 +175,4 @@ namespace PLSysCalls
AnimationManager::GetInstance()->TickPlayers(ticks); AnimationManager::GetInstance()->TickPlayers(ticks);
} }
} }
static void PromptOpenFileCallback(const PortabilityLayer::HostSuspendCallArgument *args, PortabilityLayer::HostSuspendCallArgument *returnValue)
{
bool result = PortabilityLayer::HostFileSystem::GetInstance()->PromptOpenFile(static_cast<PortabilityLayer::VirtualDirectory_t>(args[0].m_int), static_cast<char*>(args[1].m_pointer), *static_cast<size_t*>(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<int32_t>(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<PortabilityLayer::VirtualDirectory_t>(args[0].m_int),
static_cast<char*>(args[1].m_pointer),
*static_cast<size_t*>(args[2].m_pointer),
args[3].m_uint,
static_cast<const char*>(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<int32_t>(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;
}
} }

View File

@@ -7,6 +7,4 @@
namespace PLSysCalls namespace PLSysCalls
{ {
void Sleep(uint32_t ticks); 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);
} }

View File

@@ -13,17 +13,18 @@ namespace PortabilityLayer
, m_max(0) , m_max(0)
, m_state(0) , m_state(0)
, m_enabled(true) , m_enabled(true)
, m_defaultCallback(nullptr)
{ {
} }
WidgetHandleState_t Widget::ProcessEvent(const TimeTaggedVOSEvent &evt) WidgetHandleState_t Widget::ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt)
{ {
(void)evt; (void)evt;
return WidgetHandleStates::kIgnored; 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; return 0;
} }
@@ -64,6 +65,11 @@ namespace PortabilityLayer
OnEnabledChanged(); OnEnabledChanged();
} }
bool Widget::IsEnabled() const
{
return m_enabled;
}
void Widget::SetState(int16_t state) void Widget::SetState(int16_t state)
{ {
m_state = state; m_state = state;

View File

@@ -25,7 +25,7 @@ namespace PortabilityLayer
typedef WidgetHandleStates::WidgetHandleState WidgetHandleState_t; 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 struct WidgetBasicState
{ {
@@ -40,6 +40,8 @@ namespace PortabilityLayer
int16_t m_state; int16_t m_state;
int16_t m_resID; int16_t m_resID;
bool m_enabled; bool m_enabled;
WidgetUpdateCallback_t m_defaultCallback;
}; };
class Widget class Widget
@@ -47,8 +49,8 @@ namespace PortabilityLayer
public: public:
virtual bool Init(const WidgetBasicState &state, const void *additionalData) = 0; virtual bool Init(const WidgetBasicState &state, const void *additionalData) = 0;
virtual void Destroy() = 0; virtual void Destroy() = 0;
virtual WidgetHandleState_t ProcessEvent(const TimeTaggedVOSEvent &evt); virtual WidgetHandleState_t ProcessEvent(void *captureContext, const TimeTaggedVOSEvent &evt);
virtual int16_t Capture(const Point &pos, WidgetUpdateCallback_t callback); virtual int16_t Capture(void *captureContext, const Point &pos, WidgetUpdateCallback_t callback);
virtual void DrawControl(DrawSurface *surface); virtual void DrawControl(DrawSurface *surface);
virtual void SetMin(int32_t v); virtual void SetMin(int32_t v);
@@ -58,6 +60,7 @@ namespace PortabilityLayer
void Resize(uint16_t width, uint16_t height); void Resize(uint16_t width, uint16_t height);
void SetEnabled(bool enabled); void SetEnabled(bool enabled);
bool IsEnabled() const;
virtual void SetState(int16_t state); virtual void SetState(int16_t state);
int16_t GetState() const; int16_t GetState() const;

View File

@@ -160,6 +160,7 @@
<ClInclude Include="DialogManager.h" /> <ClInclude Include="DialogManager.h" />
<ClInclude Include="DisplayDeviceManager.h" /> <ClInclude Include="DisplayDeviceManager.h" />
<ClInclude Include="EllipsePlotter.h" /> <ClInclude Include="EllipsePlotter.h" />
<ClInclude Include="FileBrowserUI.h" />
<ClInclude Include="FileManager.h" /> <ClInclude Include="FileManager.h" />
<ClInclude Include="FilePermission.h" /> <ClInclude Include="FilePermission.h" />
<ClInclude Include="FilePos.h" /> <ClInclude Include="FilePos.h" />
@@ -303,6 +304,7 @@
<ClCompile Include="DialogManager.cpp" /> <ClCompile Include="DialogManager.cpp" />
<ClCompile Include="DisplayDeviceManager.cpp" /> <ClCompile Include="DisplayDeviceManager.cpp" />
<ClCompile Include="EllipsePlotter.cpp" /> <ClCompile Include="EllipsePlotter.cpp" />
<ClCompile Include="FileBrowserUI.cpp" />
<ClCompile Include="FileManager.cpp" /> <ClCompile Include="FileManager.cpp" />
<ClCompile Include="FontFamily.cpp" /> <ClCompile Include="FontFamily.cpp" />
<ClCompile Include="FontManager.cpp" /> <ClCompile Include="FontManager.cpp" />

View File

@@ -459,6 +459,9 @@
<ClInclude Include="HostLogDriver.h"> <ClInclude Include="HostLogDriver.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FileBrowserUI.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="CFileStream.cpp"> <ClCompile Include="CFileStream.cpp">
@@ -731,5 +734,8 @@
<ClCompile Include="HostInputDriver.cpp"> <ClCompile Include="HostInputDriver.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FileBrowserUI.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>