File dialog improvements

- Add a globally-accessible function to handle the parsing of filter extensions
- Remove the ability of putting the wildcard ('*') among other patterns; it's either a list of patterns or a single '*' now
- Add a hint to select between portals and Zenity on Unix
This commit is contained in:
Semphris 2024-04-02 16:03:58 -04:00 committed by Sam Lantinga
parent 5fa87e29e7
commit 6ad390fc50
18 changed files with 501 additions and 125 deletions

View file

@ -19,6 +19,7 @@
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "../SDL_dialog_utils.h"
#include <windows.h>
#include <shlobj.h>
@ -122,61 +123,42 @@ void windows_ShowFileDialog(void *ptr)
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, default_folder, -1, filebuffer, MAX_PATH);
}
size_t len = 0;
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
const char *pattern_ptr = filter->pattern;
len += SDL_strlen(filter->name) + SDL_strlen(filter->pattern) + 4;
while (*pattern_ptr) {
if (*pattern_ptr == ';') {
len += 2;
}
pattern_ptr++;
}
}
wchar_t *filterlist = SDL_malloc((len + 1) * sizeof(wchar_t));
/* '\x01' is used in place of a null byte */
char *filterlist = convert_filters(filters, NULL, "", "", "\x01", "",
"\x01", "\x01", "*.", ";*.", "");
if (!filterlist) {
SDL_OutOfMemory();
callback(userdata, NULL, -1);
return;
}
wchar_t *filter_ptr = filterlist;
for (const SDL_DialogFileFilter *filter = filters; filter && filter->name && filter->pattern; filter++) {
size_t l = SDL_strlen(filter->name);
const char *pattern_ptr = filter->pattern;
int filter_len = SDL_strlen(filterlist);
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filter->name, -1, filter_ptr, MAX_PATH);
filter_ptr += l + 1;
*filter_ptr++ = L'*';
*filter_ptr++ = L'.';
while (*pattern_ptr) {
if (*pattern_ptr == ';') {
*filter_ptr++ = L';';
*filter_ptr++ = L'*';
*filter_ptr++ = L'.';
} else if (*pattern_ptr == '*' && (pattern_ptr[1] == '\0' || pattern_ptr[1] == ';')) {
*filter_ptr++ = L'*';
} else if (!((*pattern_ptr >= 'a' && *pattern_ptr <= 'z') || (*pattern_ptr >= 'A' && *pattern_ptr <= 'Z') || (*pattern_ptr >= '0' && *pattern_ptr <= '9') || *pattern_ptr == '.' || *pattern_ptr == '_' || *pattern_ptr == '-')) {
SDL_SetError("Illegal character in pattern name: %c (Only alphanumeric characters, periods, underscores and hyphens allowed)", *pattern_ptr);
callback(userdata, NULL, -1);
} else {
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, pattern_ptr, 1, filter_ptr, 1);
filter_ptr++;
}
pattern_ptr++;
for (char *c = filterlist; *c; c++) {
if (*c == '\x01') {
*c = '\0';
}
*filter_ptr++ = '\0';
}
*filter_ptr = '\0';
int filter_wlen = MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, NULL, 0);
wchar_t *filter_wchar = SDL_malloc(filter_wlen * sizeof(wchar_t));
if (!filter_wchar) {
SDL_OutOfMemory();
SDL_free(filterlist);
callback(userdata, NULL, -1);
return;
}
MultiByteToWideChar(CP_UTF8, 0, filterlist, filter_len, filter_wchar, filter_wlen);
SDL_free(filterlist);
OPENFILENAMEW dialog;
dialog.lStructSize = sizeof(OPENFILENAME);
dialog.hwndOwner = window;
dialog.hInstance = 0;
dialog.lpstrFilter = filterlist;
dialog.lpstrFilter = filter_wchar;
dialog.lpstrCustomFilter = NULL;
dialog.nMaxCustFilter = 0;
dialog.nFilterIndex = 0;
@ -198,7 +180,7 @@ void windows_ShowFileDialog(void *ptr)
BOOL result = pGetAnyFileName(&dialog);
SDL_free(filterlist);
SDL_free(filter_wchar);
if (result) {
if (!(flags & OFN_ALLOWMULTISELECT)) {
@ -401,6 +383,13 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
winArgs *args;
SDL_Thread *thread;
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
SDL_Log("%s", SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER));
SDL_SetError("File dialog driver unsupported");
callback(userdata, NULL, -1);
return;
}
args = SDL_malloc(sizeof(winArgs));
if (args == NULL) {
SDL_OutOfMemory();
@ -421,6 +410,7 @@ void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
if (thread == NULL) {
callback(userdata, NULL, -1);
SDL_free(args);
return;
}
@ -432,6 +422,12 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
winArgs *args;
SDL_Thread *thread;
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
SDL_SetError("File dialog driver unsupported");
callback(userdata, NULL, -1);
return;
}
args = SDL_malloc(sizeof(winArgs));
if (args == NULL) {
SDL_OutOfMemory();
@ -452,6 +448,7 @@ void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL
if (thread == NULL) {
callback(userdata, NULL, -1);
SDL_free(args);
return;
}
@ -463,6 +460,12 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S
winFArgs *args;
SDL_Thread *thread;
if (SDL_GetHint(SDL_HINT_FILE_DIALOG_DRIVER) != NULL) {
SDL_SetError("File dialog driver unsupported");
callback(userdata, NULL, -1);
return;
}
args = SDL_malloc(sizeof(winFArgs));
if (args == NULL) {
SDL_OutOfMemory();
@ -479,6 +482,7 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, S
if (thread == NULL) {
callback(userdata, NULL, -1);
SDL_free(args);
return;
}