Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dialog: Add filter size argument, remove NULL termination #9856

Merged
merged 1 commit into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions include/SDL3/SDL_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,9 @@ typedef struct SDL_DialogFileFilter
* The filelist argument does not need to be freed; it will automatically be
* freed when the callback returns.
*
* The filter argument is the index of the filter that was selected, or one
* more than the size of the list (therefore the index of the terminating NULL
* entry) if no filter was selected, or -1 if the platform or method doesn't
* support fetching the selected filter.
* The filter argument is the index of the filter that was selected, or -1 if
* no filter was selected or if the platform or method doesn't support fetching
* the selected filter.
*
* \param userdata An app-provided pointer, for the callback's use.
* \param filelist The file(s) chosen by the user.
Expand Down Expand Up @@ -135,9 +134,10 @@ typedef void(SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const
* it will be invoked.
* \param window The window that the dialog should be modal for. May be NULL.
* Not all platforms support this option.
* \param filters A null-terminated list of SDL_DialogFileFilter's. May be
* NULL. Not all platforms support this option, and platforms
* that do support it may allow the user to ignore the filters.
* \param filters A list of SDL_DialogFileFilter's. May be NULL. Not all
* platforms support this option, and platforms that do support
* it may allow the user to ignore the filters.
* \param nfilters The number of filters. Ignored if filters is NULL.
* \param default_location The default folder or file to start the dialog at.
* May be NULL. Not all platforms support this option.
* \param allow_many If non-zero, the user will be allowed to select multiple
Expand All @@ -150,7 +150,7 @@ typedef void(SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const
* \sa SDL_ShowSaveFileDialog
* \sa SDL_ShowOpenFolderDialog
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many);
extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, SDL_bool allow_many);

/**
* Displays a dialog that lets the user choose a new or existing file on their
Expand Down Expand Up @@ -191,9 +191,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
* it will be invoked.
* \param window The window that the dialog should be modal for. May be NULL.
* Not all platforms support this option.
* \param filters A null-terminated list of SDL_DialogFileFilter's. May be
* NULL. Not all platforms support this option, and platforms
* that do support it may allow the user to ignore the filters.
* \param filters A list of SDL_DialogFileFilter's. May be NULL. Not all
* platforms support this option, and platforms that do support
* it may allow the user to ignore the filters.
* \param nfilters The number of filters. Ignored if filters is NULL.
* \param default_location The default folder or file to start the dialog at.
* May be NULL. Not all platforms support this option.
*
Expand All @@ -204,7 +205,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback c
* \sa SDL_ShowOpenFileDialog
* \sa SDL_ShowOpenFolderDialog
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location);
extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location);

/**
* Displays a dialog that lets the user select a folder on their filesystem.
Expand Down
13 changes: 4 additions & 9 deletions src/core/android/SDL_android.c
Original file line number Diff line number Diff line change
Expand Up @@ -2908,7 +2908,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeFileDialog)(

SDL_bool Android_JNI_OpenFileDialog(
SDL_DialogFileCallback callback, void* userdata,
const SDL_DialogFileFilter *filters, SDL_bool forwrite, SDL_bool multiple)
const SDL_DialogFileFilter *filters, int nfilters, SDL_bool forwrite,
SDL_bool multiple)
{
if (mAndroidFileDialogData.callback != NULL) {
SDL_SetError("Only one file dialog can be run at a time.");
Expand All @@ -2924,17 +2925,11 @@ SDL_bool Android_JNI_OpenFileDialog(
/* Setup filters */
jobjectArray filtersArray = NULL;
if (filters) {
/* Count how many filters */
int count = 0;
for (const SDL_DialogFileFilter *f = filters; f->name != NULL && f->pattern != NULL; f++) {
count++;
}

jclass stringClass = (*env)->FindClass(env, "java/lang/String");
filtersArray = (*env)->NewObjectArray(env, count, stringClass, NULL);
filtersArray = (*env)->NewObjectArray(env, nfilters, stringClass, NULL);

/* Convert to string */
for (int i = 0; i < count; i++) {
for (int i = 0; i < nfilters; i++) {
jstring str = (*env)->NewStringUTF(env, filters[i].pattern);
(*env)->SetObjectArrayElement(env, filtersArray, i, str);
(*env)->DeleteLocalRef(env, str);
Expand Down
3 changes: 2 additions & 1 deletion src/core/android/SDL_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ void Android_ActivityMutex_Lock_Running(void);

/* File Dialogs */
SDL_bool Android_JNI_OpenFileDialog(SDL_DialogFileCallback callback, void* userdata,
const SDL_DialogFileFilter *filters, SDL_bool forwrite, SDL_bool multiple);
const SDL_DialogFileFilter *filters, int nfilters, SDL_bool forwrite,
SDL_bool multiple);

/* Ends C function definitions when using C++ */
#ifdef __cplusplus
Expand Down
34 changes: 21 additions & 13 deletions src/dialog/SDL_dialog_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,34 @@

#include "SDL_dialog_utils.h"

char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
const char *prefix, const char *separator,
const char *suffix, const char *filt_prefix,
const char *filt_separator, const char *filt_suffix,
const char *ext_prefix, const char *ext_separator,
const char *ext_suffix)
char *convert_filters(const SDL_DialogFileFilter *filters, int nfilters,
NameTransform ntf, const char *prefix,
const char *separator, const char *suffix,
const char *filt_prefix, const char *filt_separator,
const char *filt_suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix)
{
char *combined;
char *new_combined;
char *converted;
const char *terminator;
size_t new_length;
int i;

if (!filters) {
SDL_SetError("Called convert_filters() with NULL filters (SDL bug)");
return NULL;
}

combined = SDL_strdup(prefix);

if (!combined) {
return NULL;
}

for (const SDL_DialogFileFilter *f = filters; f->name && f->pattern; f++) {
for (i = 0; i < nfilters; i++) {
const SDL_DialogFileFilter *f = &filters[i];

converted = convert_filter(*f, ntf, filt_prefix, filt_separator,
filt_suffix, ext_prefix, ext_separator,
ext_suffix);
Expand Down Expand Up @@ -90,9 +98,9 @@ char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
}

char *convert_filter(const SDL_DialogFileFilter filter, NameTransform ntf,
const char *prefix, const char *separator,
const char *suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix)
const char *prefix, const char *separator,
const char *suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix)
{
char *converted;
char *name_filtered;
Expand Down Expand Up @@ -208,11 +216,11 @@ char *convert_ext_list(const char *list, const char *prefix,
return converted;
}

const char *validate_filters(const SDL_DialogFileFilter *filters)
const char *validate_filters(const SDL_DialogFileFilter *filters, int nfilters)
{
if (filters) {
for (const SDL_DialogFileFilter *f = filters; f->name && f->pattern; f++) {
const char *msg = validate_list(f->pattern);
for (int i = 0; i < nfilters; i++) {
const char *msg = validate_list(filters[i].pattern);

if (msg) {
return msg;
Expand Down
22 changes: 12 additions & 10 deletions src/dialog/SDL_dialog_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ typedef char *(NameTransform)(const char * name);

/* Converts all the filters into a single string. */
/* <prefix>[filter]{<separator>[filter]...}<suffix> */
char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
const char *prefix, const char *separator,
const char *suffix, const char *filt_prefix,
const char *filt_separator, const char *filt_suffix,
const char *ext_prefix, const char *ext_separator,
const char *ext_suffix);
char *convert_filters(const SDL_DialogFileFilter *filters, int nfilters,
NameTransform ntf, const char *prefix,
const char *separator, const char *suffix,
const char *filt_prefix, const char *filt_separator,
const char *filt_suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix);

/* Converts one filter into a single string. */
/* <prefix>[filter name]<separator>[filter extension list]<suffix> */
char *convert_filter(const SDL_DialogFileFilter filter, NameTransform ntf,
const char *prefix, const char *separator,
const char *suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix);
const char *prefix, const char *separator,
const char *suffix, const char *ext_prefix,
const char *ext_separator, const char *ext_suffix);

/* Converts the extenstion list of a filter into a single string. */
/* <prefix>[extension]{<separator>[extension]...}<suffix> */
Expand All @@ -53,5 +53,7 @@ char *convert_ext_list(const char *list, const char *prefix,

/* Must be used if convert_* functions aren't used */
/* Returns an error message if there's a problem, NULL otherwise */
const char *validate_filters(const SDL_DialogFileFilter *filters);
const char *validate_filters(const SDL_DialogFileFilter *filters,
int nfilters);

const char *validate_list(const char *list);
8 changes: 4 additions & 4 deletions src/dialog/android/SDL_androiddialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
#include "SDL_internal.h"
#include "../../core/android/SDL_android.h"

void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location, SDL_bool allow_many)
void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, SDL_bool allow_many)
{
if (!Android_JNI_OpenFileDialog(callback, userdata, filters, SDL_FALSE, allow_many)) {
if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, SDL_FALSE, allow_many)) {
/* SDL_SetError is already called when it fails */
callback(userdata, NULL, -1);
}
}

void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, const char *default_location)
void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location)
{
if (!Android_JNI_OpenFileDialog(callback, userdata, filters, SDL_TRUE, SDL_FALSE)) {
if (!Android_JNI_OpenFileDialog(callback, userdata, filters, nfilters, SDL_TRUE, SDL_FALSE)) {
/* SDL_SetError is already called when it fails */
callback(userdata, NULL, -1);
}
Expand Down
20 changes: 9 additions & 11 deletions src/dialog/cocoa/SDL_cocoadialog.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@
FDT_OPENFOLDER
} cocoa_FileDialogType;

void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
{
#if defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_IOS)
SDL_SetError("tvOS and iOS don't support path-based file dialogs");
callback(userdata, NULL, -1);
#else
if (filters) {
const char *msg = validate_filters(filters);
const char *msg = validate_filters(filters, nfilters);

if (msg) {
SDL_SetError("%s", msg);
Expand Down Expand Up @@ -76,13 +76,11 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
};

if (filters) {
int n = -1;
while (filters[++n].name && filters[n].pattern);
// On macOS 11.0 and up, this is an array of UTType. Prior to that, it's an array of NSString
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:n ];
NSMutableArray *types = [[NSMutableArray alloc] initWithCapacity:nfilters ];

int has_all_files = 0;
for (int i = 0; i < n; i++) {
for (int i = 0; i < nfilters; i++) {
char *pattern = SDL_strdup(filters[i].pattern);
char *pattern_ptr = pattern;

Expand Down Expand Up @@ -180,17 +178,17 @@ void show_file_dialog(cocoa_FileDialogType type, SDL_DialogFileCallback callback
#endif // defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_IOS)
}

void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
{
show_file_dialog(FDT_OPEN, callback, userdata, window, filters, default_location, allow_many);
show_file_dialog(FDT_OPEN, callback, userdata, window, filters, nfilters, default_location, allow_many);
}

void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
{
show_file_dialog(FDT_SAVE, callback, userdata, window, filters, default_location, 0);
show_file_dialog(FDT_SAVE, callback, userdata, window, filters, nfilters, default_location, 0);
}

void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const char* default_location, SDL_bool allow_many)
{
show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, default_location, allow_many);
show_file_dialog(FDT_OPENFOLDER, callback, userdata, window, NULL, 0, default_location, allow_many);
}
4 changes: 2 additions & 2 deletions src/dialog/dummy/SDL_dummydialog.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
*/
#include "SDL_internal.h"

void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location, SDL_bool allow_many)
void SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location, SDL_bool allow_many)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
}

void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, const char* default_location)
void SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void* userdata, SDL_Window* window, const SDL_DialogFileFilter *filters, int nfilters, const char* default_location)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
Expand Down
Loading
Loading