Input dialogs

This commit is contained in:
Semphris 2025-06-07 17:07:22 -04:00
parent 685f1720fe
commit 96f2406794
10 changed files with 1816 additions and 26 deletions

View File

@ -332,6 +332,369 @@ extern SDL_DECLSPEC void SDLCALL SDL_ShowFileDialogWithProperties(SDL_FileDialog
#define SDL_PROP_FILE_DIALOG_ACCEPT_STRING "SDL.filedialog.accept"
#define SDL_PROP_FILE_DIALOG_CANCEL_STRING "SDL.filedialog.cancel"
/**
* Result of dialogs.
*
* This is passed as an argument for the callback of many dialog-related
* functions.
*
* \since This enum is available since SDL 3.4.0.
*/
typedef enum SDL_DialogResult
{
/** An error occured. The dialog may or may not have been shown to the user
before the error happened, but the chosen input couldn't be obtained. */
SDL_DIALOGRESULT_ERROR,
/** The user has canceled the dialog, or the program aborted the dialog. */
SDL_DIALOGRESULT_CANCEL,
/** The user finished the input and confirmed the result. */
SDL_DIALOGRESULT_SUCCESS
} SDL_DialogResult;
/**
* Callback used by input dialog functions.
*
* \param userdata an app-provided pointer, for the callback's use.
* \param input the text input by the user.
* \param result the success status of the dialog.
*
* \since This datatype is available since SDL 3.4.0.
*
* \sa SDL_DialogResult
* \sa SDL_ShowInputDialogWithProperties
*/
typedef void (SDLCALL *SDL_DialogInputCallback)(void *userdata, const char *input, SDL_DialogResult result);
/**
* Create and launch a text input dialog with the specified properties.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
* The callback will be invoked with the string input by the user, an empty
* string if the user canceled the dialog, and NULL if an error occured.
*
* Note that the callback may be called from a different thread than the one
* the function was invoked on.
*
* These are the supported properties:
*
* - `SDL_PROP_INPUT_DIALOG_WINDOW_POINTER`: the window that the dialog should
* be modal for.
* - `SDL_PROP_INPUT_DIALOG_TITLE_STRING`: the title for the dialog.
* - `SDL_PROP_INPUT_DIALOG_PROMPT_STRING`: the prompt for the dialog.
* - `SDL_PROP_INPUT_DIALOG_DEFAULT_STRING`: the default value to fill in the
* dialog.
* - `SDL_PROP_INPUT_DIALOG_ACCEPT_STRING`: the label that the accept button
* should have.
* - `SDL_PROP_INPUT_DIALOG_CANCEL_STRING`: the label that the cancel button
* should have.
* - `SDL_PROP_INPUT_DIALOG_PASSWORD_BOOLEAN`: if true, the text field will
* treat its contents as a password, which usually involves displaying one
* character (such as an asterisk) in place of all characters in the field.
* Defaults to false.
*
* Note that each platform may or may not support any of the properties.
*
* \param callback a function pointer to be invoked when the user finishes
* entering the prompt.
* \param userdata an optional pointer to pass extra data to the callback when
* it will be invoked.
* \param props the properties to use.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.4.0.
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowInputDialogWithProperties(SDL_DialogInputCallback callback, void *userdata, SDL_PropertiesID props);
#define SDL_PROP_INPUT_DIALOG_WINDOW_POINTER "SDL.inputdialog.window"
#define SDL_PROP_INPUT_DIALOG_TITLE_STRING "SDL.inputdialog.title"
#define SDL_PROP_INPUT_DIALOG_PROMPT_STRING "SDL.inputdialog.prompt"
#define SDL_PROP_INPUT_DIALOG_DEFAULT_STRING "SDL.inputdialog.default"
#define SDL_PROP_INPUT_DIALOG_ACCEPT_STRING "SDL.inputdialog.accept"
#define SDL_PROP_INPUT_DIALOG_CANCEL_STRING "SDL.inputdialog.cancel"
#define SDL_PROP_INPUT_DIALOG_PASSWORD_BOOLEAN "SDL.inputdialog.password"
/**
* A progress dialog.
*
* \since This datatype is available since SDL 3.4.0.
*
* \sa SDL_ShowProgressDialogWithProperties
*/
typedef struct SDL_ProgressDialog SDL_ProgressDialog;
/**
* Callback used by progress dialog functions.
*
* \param userdata an app-provided pointer, for the callback's use.
* \param result the success status of the dialog.
*
* \since This datatype is available since SDL 3.4.0.
*
* \sa SDL_ShowProgressDialogWithProperties
*/
typedef void (SDLCALL *SDL_DialogProgressCallback)(void *userdata, SDL_DialogResult result);
/**
* Create and launch a text input dialog with the specified properties.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
* Note that the callback may be called from a different thread than the one
* the function was invoked on.
*
* These are the supported properties:
*
* - `SDL_PROP_PROGRESS_DIALOG_WINDOW_POINTER`: the window that the dialog
* should be modal for.
* - `SDL_PROP_PROGRESS_DIALOG_TITLE_STRING`: the title for the dialog.
* - `SDL_PROP_PROGRESS_DIALOG_PROMPT_STRING`: the prompt for the dialog.
* - `SDL_PROP_PROGRESS_DIALOG_ACCEPT_STRING`: the label that the accept button
* should have.
* - `SDL_PROP_PROGRESS_DIALOG_CANCEL_STRING`: the label that the cancel button
* should have.
* - `SDL_PROP_PROGRESS_DIALOG_CAN_CANCEL_BOOLEAN`: if true, the user can cancel
* the dialog anytime with a "Cancel" button. It may be possible to cancel the
* dialog even if this property is set to false. Defaults to true.
* - `SDL_PROP_PROGRESS_DIALOG_PROGRESS_NUMBER`: a float betweeon 0 and 1
* representing the value of the progress bar. Ignored if the property
* `SDL_PROP_PROGRESS_DIALOG_INDEFINITE_BOOLEAN` is set to true.
* - `SDL_PROP_PROGRESS_DIALOG_INDEFINITE_BOOLEAN`: If true, the progress bar
* won't show any meaningful value and will adopt a generic progress-less
* loading behavior. Defaults to false.
* - `SDL_PROP_PROGRESS_DIALOG_SHOW_TIME_REMAINING_BOOLEAN`: If true, the dialog
* will show an estimate of the remaining time for the progress bar to finish.
* Defaults to false.
* - `SDL_PROP_PROGRESS_DIALOG_AUTO_CLOSE_BOOLEAN`: If true, the dialog will be
* closed automatically when the progress bar reaches 100%. Defaults to false.
*
* Note that each platform may or may not support any of the properties.
*
* \param callback a function pointer to be invoked when the progress finishes,
* successfully or not.
* \param userdata an optional pointer to pass extra data to the callback when
* it will be invoked.
* \param props the properties to use.
*
* \returns a progress dialog handle.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.4.0.
*
* \sa SDL_DialogProgressCallback
* \sa SDL_UpdateProgressDialog
* \sa SDL_DestroyProgressDialog
*/
extern SDL_DECLSPEC SDL_ProgressDialog* SDLCALL SDL_ShowProgressDialogWithProperties(SDL_DialogProgressCallback callback, void *userdata, SDL_PropertiesID props);
#define SDL_PROP_PROGRESS_DIALOG_WINDOW_POINTER "SDL.progressdialog.window"
#define SDL_PROP_PROGRESS_DIALOG_TITLE_STRING "SDL.progressdialog.title"
#define SDL_PROP_PROGRESS_DIALOG_PROMPT_STRING "SDL.progressdialog.prompt"
#define SDL_PROP_PROGRESS_DIALOG_ACCEPT_STRING "SDL.progressdialog.accept"
#define SDL_PROP_PROGRESS_DIALOG_CANCEL_STRING "SDL.progressdialog.cancel"
#define SDL_PROP_PROGRESS_DIALOG_CAN_CANCEL_BOOLEAN "SDL.progressdialog.can_cancel"
#define SDL_PROP_PROGRESS_DIALOG_INDEFINITE_BOOLEAN "SDL.progressdialog.indefinite"
#define SDL_PROP_PROGRESS_DIALOG_SHOW_TIME_REMAINING_BOOLEAN "SDL.progressdialog.show_time_remaining"
#define SDL_PROP_PROGRESS_DIALOG_AUTO_CLOSE_BOOLEAN "SDL.progressdialog.auto_close"
/**
* Update a progress dialog to a new progress status.
*
* For auto-closing progress dialogs, calling this function with a progress of 1
* (corresponding to 100%) will close the dialog and invoke the callback with
* success status. To close the dialog with error status, use
* SDL_CloseProgressDialog() instead.
*
* For indefinite progress dialogs, this function has no effect unless progress
* is 1, in which case it will report a successful completion.
*
* \param dialog the progress dialog.
* \param progress the new progress for the dialog, which is a float between
* 0 and 1 inclusively.
* \param new_prompt a new prompt, or NULL to keep the same prompt.
*
* \threadsafety This function is not thread-safe.
*
* \since This function is available since SDL 3.4.0.
*
* \sa SDL_ShowProgressDialogWithProperties
* \sa SDL_DestroyProgressDialog
*/
extern SDL_DECLSPEC void SDLCALL SDL_UpdateProgressDialog(SDL_ProgressDialog* dialog, float progress, const char *new_prompt);
/**
* Close and destroy a progress dialog, invoking the callback with error
* status if it hasn't yet been called.
*
* It is safe to call this function while the dialog is still open; it will
* abort the dialog if it hasn't already completed.
*
* \param dialog the dialog to be destroyed.
*
* \threadsafety This function is not thread-safe.
*
* \since This function is available since SDL 3.4.0.
*
* \sa SDL_ShowProgressDialogWithProperties
* \sa SDL_UpdateProgressDialog
*/
extern SDL_DECLSPEC void SDLCALL SDL_DestroyProgressDialog(SDL_ProgressDialog* dialog);
/**
* Callback used by color dialog functions.
*
* \param userdata an app-provided pointer, for the callback's use.
* \param color the color chosen by the user.
* \param result the success status of the dialog.
*
* \since This datatype is available since SDL 3.4.0.
*
* \sa SDL_DialogResult
* \sa SDL_ShowColorPickerDialogWithProperties
*/
typedef void (SDLCALL *SDL_DialogColorCallback)(void *userdata, SDL_Color color, SDL_DialogResult result);
/**
* Create and launch a color picker dialog with the specified properties.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
* The callback will be invoked with the color chosen by the user, or black if
* the dialog was canceled or an error occured.
*
* Note that the callback may be called from a different thread than the one
* the function was invoked on.
*
* These are the supported properties:
*
* - `SDL_PROP_COLOR_DIALOG_WINDOW_POINTER`: the window that the dialog should
* be modal for.
* - `SDL_PROP_COLOR_DIALOG_TITLE_STRING`: the title for the dialog.
* - `SDL_PROP_COLOR_DIALOG_PROMPT_STRING`: the prompt for the dialog.
* - `SDL_PROP_COLOR_DIALOG_DEFAULT_POINTER`: the default value for the dialog.
* Must be a pointer to SDL_Color; NULL has the same effect as not setting
* this property.
* - `SDL_PROP_COLOR_DIALOG_ACCEPT_STRING`: the label that the accept button
* should have.
* - `SDL_PROP_COLOR_DIALOG_CANCEL_STRING`: the label that the cancel button
* should have.
*
* Note that each platform may or may not support any of the properties.
*
* If the platform's native color picker does not support selecting an alpha
* value, and a non-NULL default color is provided, the resulting color will
* have the same alpha value as the default color. Otherwise, it will be opaque.
*
* \param callback a function pointer to be invoked when the user finishes
* entering the prompt.
* \param userdata an optional pointer to pass extra data to the callback when
* it will be invoked.
* \param props the properties to use.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.4.0.
*
* \sa SDL_Color
* \sa SDL_DialogColorCallback
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowColorPickerDialogWithProperties(SDL_DialogColorCallback callback, void *userdata, SDL_PropertiesID props);
#define SDL_PROP_COLOR_DIALOG_WINDOW_POINTER "SDL.colordialog.window"
#define SDL_PROP_COLOR_DIALOG_TITLE_STRING "SDL.colordialog.title"
#define SDL_PROP_COLOR_DIALOG_PROMPT_STRING "SDL.colordialog.prompt"
#define SDL_PROP_COLOR_DIALOG_DEFAULT_POINTER "SDL.colordialog.default"
#define SDL_PROP_COLOR_DIALOG_ACCEPT_STRING "SDL.colordialog.accept"
#define SDL_PROP_COLOR_DIALOG_CANCEL_STRING "SDL.colordialog.cancel"
typedef struct SDL_Date
{
Uint16 y;
Uint8 m;
Uint8 d;
} SDL_Date;
/**
* Callback used by date picker dialog functions.
*
* \param userdata an app-provided pointer, for the callback's use.
* \param date the date chosen by the user.
* \param result the success status of the dialog.
*
* \since This datatype is available since SDL 3.4.0.
*
* \sa SDL_DialogResult
* \sa SDL_ShowDatePickerDialogWithProperties
*/
typedef void (SDLCALL *SDL_DialogDateCallback)(void *userdata, SDL_Date date, SDL_DialogResult result);
/**
* Create and launch a date picker dialog with the specified properties.
*
* This function only supports dates from the Gregorian calendar, with years
* 1-9999, months 1-12 and days 1-31. Field can be set to 0 to retain the
* default value.
*
* This is an asynchronous function; it will return immediately, and the
* result will be passed to the callback.
*
* The callback will be invoked with the date chosen by the user, or { 0, 0, 0 }
* if the dialog was canceled or an error occured.
*
* Note that the callback may be called from a different thread than the one
* the function was invoked on.
*
* These are the supported properties:
*
* - `SDL_PROP_DATE_DIALOG_WINDOW_POINTER`: the window that the dialog should
* be modal for.
* - `SDL_PROP_DATE_DIALOG_TITLE_STRING`: the title for the dialog.
* - `SDL_PROP_DATE_DIALOG_PROMPT_STRING`: the prompt for the dialog.
* - `SDL_PROP_DATE_DIALOG_DEFAULT_POINTER`: the default value for the dialog.
* Should be a pointer to SDL_Date. Fields can be set to 0 to keep the default
* value.
* - `SDL_PROP_DATE_DIALOG_ACCEPT_STRING`: the label that the accept button
* should have.
* - `SDL_PROP_DATE_DIALOG_CANCEL_STRING`: the label that the cancel button
* should have.
*
* Note that each platform may or may not support any of the properties.
*
* \param callback a function pointer to be invoked when the user finishes
* entering the prompt.
* \param userdata an optional pointer to pass extra data to the callback when
* it will be invoked.
* \param props the properties to use.
*
* \threadsafety This function should be called only from the main thread. The
* callback may be invoked from the same thread or from a
* different one, depending on the OS's constraints.
*
* \since This function is available since SDL 3.4.0.
*
* \sa SDL_Date
* \sa SDL_DialogDateCallback
*/
extern SDL_DECLSPEC void SDLCALL SDL_ShowDatePickerDialogWithProperties(SDL_DialogDateCallback callback, void *userdata, SDL_PropertiesID props);
#define SDL_PROP_DATE_DIALOG_WINDOW_POINTER "SDL.datedialog.window"
#define SDL_PROP_DATE_DIALOG_TITLE_STRING "SDL.datedialog.title"
#define SDL_PROP_DATE_DIALOG_PROMPT_STRING "SDL.datedialog.prompt"
#define SDL_PROP_DATE_DIALOG_DEFAULT_POINTER "SDL.datedialog.default"
#define SDL_PROP_DATE_DIALOG_ACCEPT_STRING "SDL.datedialog.accept"
#define SDL_PROP_DATE_DIALOG_CANCEL_STRING "SDL.datedialog.cancel"
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}

View File

@ -129,3 +129,109 @@ void SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, S
SDL_DestroyProperties(props);
#endif
}
// TODO: Dialogs after this should be implemented with XDG Portals
void SDL_ShowInputDialogWithProperties(SDL_DialogInputCallback callback, void *userdata, SDL_PropertiesID props)
{
if (!callback) {
return;
}
#ifdef SDL_DIALOG_DISABLED
SDL_SetError("SDL not built with dialog support");
callback(userdata, NULL, SDL_DIALOGRESULT_ERROR);
#else
SDL_SYS_ShowInputDialogWithProperties(callback, userdata, props);
#endif
}
SDL_ProgressDialog* SDL_ShowProgressDialogWithProperties(SDL_DialogProgressCallback callback, void *userdata, SDL_PropertiesID props)
{
if (!callback) {
return NULL;
}
#ifdef SDL_DIALOG_DISABLED
SDL_SetError("SDL not built with dialog support");
callback(userdata, NULL, SDL_DIALOGRESULT_ERROR);
return NULL;
#else
return SDL_SYS_ShowProgressDialogWithProperties(callback, userdata, props);
#endif
}
void SDL_UpdateProgressDialog(SDL_ProgressDialog* dialog, float progress, const char *new_prompt)
{
#ifdef SDL_DIALOG_DISABLED
SDL_SetError("SDL not built with dialog support");
#else
if (!dialog) {
SDL_InvalidParamError("dialog");
return;
}
if (progress < 0.0f || progress > 1.0f) {
SDL_InvalidParamError("progress");
return;
}
SDL_SYS_UpdateProgressDialog(dialog, progress, new_prompt);
#endif
}
void SDL_DestroyProgressDialog(SDL_ProgressDialog* dialog)
{
#ifdef SDL_DIALOG_DISABLED
SDL_SetError("SDL not built with dialog support");
#else
if (!dialog) {
SDL_InvalidParamError("dialog");
return;
}
SDL_SYS_DestroyProgressDialog(dialog);
#endif
}
void SDL_ShowColorPickerDialogWithProperties(SDL_DialogColorCallback callback, void *userdata, SDL_PropertiesID props)
{
if (!callback) {
return;
}
#ifdef SDL_DIALOG_DISABLED
SDL_Color c;
c.r = 0;
c.g = 0;
c.b = 0;
c.a = 0;
SDL_SetError("SDL not built with dialog support");
callback(userdata, c, SDL_DIALOGRESULT_ERROR);
#else
SDL_SYS_ShowColorPickerDialogWithProperties(callback, userdata, props);
#endif
}
void SDL_ShowDatePickerDialogWithProperties(SDL_DialogDateCallback callback, void *userdata, SDL_PropertiesID props)
{
if (!callback) {
return;
}
SDL_Date d;
d.y = 0;
d.m = 0;
d.d = 0;
#ifdef SDL_DIALOG_DISABLED
SDL_SetError("SDL not built with dialog support");
callback(userdata, d, SDL_DIALOGRESULT_ERROR);
#else
SDL_Date *date = SDL_GetPointerProperty(props, SDL_PROP_DATE_DIALOG_DEFAULT_POINTER, NULL);
// A value of 0 is "null" for that field
if (date && (date->y > 9999 || date->m > 12 || date->d > 31)) {
SDL_SetError("Invalid default date: %d-%d-%d", date->y, date->m, date->d);
callback(userdata, d, SDL_DIALOGRESULT_ERROR);
}
SDL_SYS_ShowDatePickerDialogWithProperties(callback, userdata, props);
#endif
}

View File

@ -20,3 +20,9 @@
*/
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props);
void SDL_SYS_ShowInputDialogWithProperties(SDL_DialogInputCallback callback, void *userdata, SDL_PropertiesID props);
SDL_ProgressDialog* SDL_SYS_ShowProgressDialogWithProperties(SDL_DialogProgressCallback callback, void *userdata, SDL_PropertiesID props);
void SDL_SYS_UpdateProgressDialog(SDL_ProgressDialog* dialog, float progress, const char *new_prompt);
void SDL_SYS_DestroyProgressDialog(SDL_ProgressDialog* dialog);
void SDL_SYS_ShowColorPickerDialogWithProperties(SDL_DialogColorCallback callback, void *userdata, SDL_PropertiesID props);
void SDL_SYS_ShowDatePickerDialogWithProperties(SDL_DialogDateCallback callback, void *userdata, SDL_PropertiesID props);

View File

@ -26,8 +26,57 @@
void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, NULL, -1);
SDL_Unsupported();
callback(userdata, NULL, -1);
}
void SDL_SYS_ShowInputDialogWithProperties(SDL_DialogInputCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, NULL, SDL_DIALOGRESULT_ERROR);
}
SDL_ProgressDialog* SDL_SYS_ShowProgressDialogWithProperties(SDL_DialogProgressCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, SDL_DIALOGRESULT_ERROR);
// In case the callback calls SDL_SetError()
SDL_Unsupported();
return NULL;
}
void SDL_SYS_UpdateProgressDialog(SDL_ProgressDialog* dialog, float progress, const char *new_prompt)
{
SDL_Unsupported();
}
void SDL_SYS_DestroyProgressDialog(SDL_ProgressDialog* dialog)
{
SDL_Unsupported();
}
void SDL_SYS_ShowColorPickerDialogWithProperties(SDL_DialogColorCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Color color;
color.r = 0;
color.g = 0;
color.b = 0;
color.a = 0;
SDL_Unsupported();
callback(userdata, color, SDL_DIALOGRESULT_ERROR);
}
void SDL_SYS_ShowDatePickerDialogWithProperties(SDL_DialogDateCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Date date;
date.y = 0;
date.m = 0;
date.d = 0;
SDL_Unsupported();
callback(userdata, date, SDL_DIALOGRESULT_ERROR);
}
#endif // SDL_DIALOG_DUMMY

File diff suppressed because it is too large Load Diff

View File

@ -617,3 +617,117 @@ void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFil
break;
};
}
void SDL_SYS_ShowInputDialogWithProperties(SDL_DialogInputCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, NULL, SDL_DIALOGRESULT_ERROR);
}
SDL_ProgressDialog* SDL_SYS_ShowProgressDialogWithProperties(SDL_DialogProgressCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Unsupported();
callback(userdata, SDL_DIALOGRESULT_ERROR);
// In case the callback calls SDL_SetError()
SDL_Unsupported();
return NULL;
}
void SDL_SYS_UpdateProgressDialog(SDL_ProgressDialog* dialog, float progress, const char *new_prompt)
{
SDL_Unsupported();
}
void SDL_SYS_DestroyProgressDialog(SDL_ProgressDialog* dialog)
{
SDL_Unsupported();
}
void SDL_SYS_ShowColorPickerDialogWithProperties(SDL_DialogColorCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Window *window = SDL_GetPointerProperty(props, SDL_PROP_COLOR_DIALOG_WINDOW_POINTER, NULL);
SDL_Color *default_color = SDL_GetPointerProperty(props, SDL_PROP_COLOR_DIALOG_DEFAULT_POINTER, NULL);
SDL_Color result;
result.r = 0;
result.g = 0;
result.b = 0;
result.a = 0;
typedef BOOL (WINAPI *pfnChooseColorW)(LPCHOOSECOLOR);
typedef DWORD (WINAPI *pfnCommDlgExtendedError)(void);
HMODULE lib = LoadLibraryW(L"Comdlg32.dll");
pfnChooseColorW pChooseColor = NULL;
pfnCommDlgExtendedError pCommDlgExtendedError = NULL;
if (lib) {
pChooseColor = (pfnChooseColorW) GetProcAddress(lib, "ChooseColorW");
pCommDlgExtendedError = (pfnCommDlgExtendedError) GetProcAddress(lib, "CommDlgExtendedError");
} else {
SDL_SetError("Couldn't load Comdlg32.dll");
callback(userdata, result, SDL_DIALOGRESULT_ERROR);
return;
}
if (!pChooseColor) {
SDL_SetError("Couldn't load ChooseColor from library");
callback(userdata, result, SDL_DIALOGRESULT_ERROR);
return;
}
if (!pCommDlgExtendedError) {
SDL_SetError("Couldn't load CommDlgExtendedError from library");
callback(userdata, result, SDL_DIALOGRESULT_ERROR);
return;
}
// Custom color history is generally expected to persist across invocations
static COLORREF acrCustClr[16];
CHOOSECOLOR cc;
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.lpCustColors = acrCustClr;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
if (window) {
HWND hwnd = (HWND) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
if (hwnd) {
cc.hwndOwner = hwnd;
}
}
if (default_color) {
cc.rgbResult = RGB(default_color->r, default_color->g, default_color->b);
}
if (pChooseColor(&cc)) {
result.r = GetRValue(cc.rgbResult);
result.g = GetGValue(cc.rgbResult);
result.b = GetBValue(cc.rgbResult);
result.a = SDL_ALPHA_OPAQUE;
callback(userdata, result, SDL_DIALOGRESULT_SUCCESS);
} else {
DWORD error = pCommDlgExtendedError();
// Error code 0 means the user clicked the cancel button.
if (error == 0) {
callback(userdata, result, SDL_DIALOGRESULT_CANCEL);
} else {
WIN_SetError("Error while invoking color picker dialog");
callback(userdata, result, SDL_DIALOGRESULT_ERROR);
}
}
}
void SDL_SYS_ShowDatePickerDialogWithProperties(SDL_DialogDateCallback callback, void *userdata, SDL_PropertiesID props)
{
SDL_Date date;
date.y = 0;
date.m = 0;
date.d = 0;
SDL_Unsupported();
callback(userdata, date, SDL_DIALOGRESULT_ERROR);
}

View File

@ -1254,6 +1254,12 @@ SDL3_0.0.0 {
SDL_SetAudioIterationCallbacks;
SDL_GetEventDescription;
SDL_PutAudioStreamDataNoCopy;
SDL_ShowInputDialogWithProperties;
SDL_ShowProgressDialogWithProperties;
SDL_UpdateProgressDialog;
SDL_DestroyProgressDialog;
SDL_ShowColorPickerDialogWithProperties;
SDL_ShowDatePickerDialogWithProperties;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@ -1279,3 +1279,9 @@
#define SDL_SetAudioIterationCallbacks SDL_SetAudioIterationCallbacks_REAL
#define SDL_GetEventDescription SDL_GetEventDescription_REAL
#define SDL_PutAudioStreamDataNoCopy SDL_PutAudioStreamDataNoCopy_REAL
#define SDL_ShowInputDialogWithProperties SDL_ShowInputDialogWithProperties_REAL
#define SDL_ShowProgressDialogWithProperties SDL_ShowProgressDialogWithProperties_REAL
#define SDL_UpdateProgressDialog SDL_UpdateProgressDialog_REAL
#define SDL_DestroyProgressDialog SDL_DestroyProgressDialog_REAL
#define SDL_ShowColorPickerDialogWithProperties SDL_ShowColorPickerDialogWithProperties_REAL
#define SDL_ShowDatePickerDialogWithProperties SDL_ShowDatePickerDialogWithProperties_REAL

View File

@ -1287,3 +1287,9 @@ SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamPlanarData,(SDL_AudioStream *a,const void
SDL_DYNAPI_PROC(bool,SDL_SetAudioIterationCallbacks,(SDL_AudioDeviceID a,SDL_AudioIterationCallback b,SDL_AudioIterationCallback c,void *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetEventDescription,(const SDL_Event *a,char *b,int c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_PutAudioStreamDataNoCopy,(SDL_AudioStream *a,const void *b,int c,SDL_AudioStreamDataCompleteCallback d,void *e),(a,b,c,d,e),return)
SDL_DYNAPI_PROC(void,SDL_ShowInputDialogWithProperties,(SDL_DialogInputCallback a,void *b,SDL_PropertiesID c),(a,b,c),)
SDL_DYNAPI_PROC(SDL_ProgressDialog*,SDL_ShowProgressDialogWithProperties,(SDL_DialogProgressCallback a,void *b,SDL_PropertiesID c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_UpdateProgressDialog,(SDL_ProgressDialog *a,float b,const char *c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_DestroyProgressDialog,(SDL_ProgressDialog *a),(a),)
SDL_DYNAPI_PROC(void,SDL_ShowColorPickerDialogWithProperties,(SDL_DialogColorCallback a,void *b,SDL_PropertiesID c),(a,b,c),)
SDL_DYNAPI_PROC(void,SDL_ShowDatePickerDialogWithProperties,(SDL_DialogDateCallback a,void *b,SDL_PropertiesID c),(a,b,c),)

View File

@ -22,7 +22,7 @@ const SDL_DialogFileFilter filters[] = {
{ "PNG images", "png" }
};
static void SDLCALL callback(void *userdata, const char * const *files, int filter) {
static void SDLCALL file_callback(void *userdata, const char * const *files, int filter) {
if (files) {
const char* filter_name = "(filter fetching unsupported)";
@ -45,16 +45,109 @@ static void SDLCALL callback(void *userdata, const char * const *files, int filt
}
}
static void SDLCALL input_callback(void *userdata, const char *input, SDL_DialogResult result) {
switch (result)
{
case SDL_DIALOGRESULT_ERROR:
SDL_Log("Error: %s\n", SDL_GetError());
break;
case SDL_DIALOGRESULT_CANCEL:
SDL_Log("Cancel\n");
break;
case SDL_DIALOGRESULT_SUCCESS:
SDL_Log("'%s'\n", input);
break;
default:
SDL_Log("Unknown result: %d\n", result);
}
}
static bool progress_done = false;
static void SDLCALL progress_callback(void* dialog, SDL_DialogResult result)
{
switch (result)
{
case SDL_DIALOGRESULT_ERROR:
SDL_Log("Error: %s\n", SDL_GetError());
break;
case SDL_DIALOGRESULT_CANCEL:
SDL_Log("Cancel\n");
break;
case SDL_DIALOGRESULT_SUCCESS:
SDL_Log("Success\n");
break;
default:
SDL_Log("Unknown result: %d\n", result);
}
progress_done = true;
}
static void SDLCALL color_callback(void* userdata, SDL_Color c, SDL_DialogResult result)
{
switch (result)
{
case SDL_DIALOGRESULT_ERROR:
SDL_Log("Error: %s\n", SDL_GetError());
break;
case SDL_DIALOGRESULT_CANCEL:
SDL_Log("Cancel\n");
break;
case SDL_DIALOGRESULT_SUCCESS:
SDL_Log("%d, %d, %d, %d\n", c.r, c.g, c.b, c.a);
break;
default:
SDL_Log("Unknown result: %d\n", result);
}
}
static void SDLCALL date_callback(void* userdata, SDL_Date d, SDL_DialogResult result)
{
switch (result)
{
case SDL_DIALOGRESULT_ERROR:
SDL_Log("Error: %s\n", SDL_GetError());
break;
case SDL_DIALOGRESULT_CANCEL:
SDL_Log("Cancel\n");
break;
case SDL_DIALOGRESULT_SUCCESS:
SDL_Log("%04d-%02d-%02d\n", d.y, d.m, d.d);
break;
default:
SDL_Log("Unknown result: %d\n", result);
}
}
int main(int argc, char *argv[])
{
SDL_Window *w;
SDL_Renderer *r;
SDLTest_CommonState *state;
const SDL_FRect open_file_rect = { 50, 50, 220, 140 };
const SDL_FRect save_file_rect = { 50, 290, 220, 140 };
const SDL_FRect open_folder_rect = { 370, 50, 220, 140 };
const SDL_FRect open_file_rect = { 50, 50, 220, 70 };
const SDL_FRect save_file_rect = { 370, 50, 220, 70 };
const SDL_FRect open_folder_rect = { 50, 140, 220, 70 };
const SDL_FRect input_rect = { 370, 140, 220, 70 };
const SDL_FRect progress_rect = { 50, 230, 220, 70 };
const SDL_FRect color_rect = { 370, 230, 220, 70 };
const SDL_FRect date_rect = { 50, 320, 220, 70 };
int i;
const char *initial_path = NULL;
SDL_ProgressDialog* progress_dialog = NULL;
int progress;
/* Initialize test framework */
state = SDLTest_CommonCreateState(argv, 0);
@ -112,11 +205,37 @@ int main(int argc, char *argv[])
* - Nonzero if the user is allowed to choose multiple entries (not for SDL_ShowSaveFileDialog)
*/
if (SDL_PointInRectFloat(&p, &open_file_rect)) {
SDL_ShowOpenFileDialog(callback, NULL, w, filters, SDL_arraysize(filters), initial_path, 1);
SDL_ShowOpenFileDialog(file_callback, NULL, w, filters, SDL_arraysize(filters), initial_path, 1);
} else if (SDL_PointInRectFloat(&p, &open_folder_rect)) {
SDL_ShowOpenFolderDialog(callback, NULL, w, initial_path, 1);
SDL_ShowOpenFolderDialog(file_callback, NULL, w, initial_path, 1);
} else if (SDL_PointInRectFloat(&p, &save_file_rect)) {
SDL_ShowSaveFileDialog(callback, NULL, w, filters, SDL_arraysize(filters), initial_path);
SDL_ShowSaveFileDialog(file_callback, NULL, w, filters, SDL_arraysize(filters), initial_path);
} else if (SDL_PointInRectFloat(&p, &input_rect)) {
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_INPUT_DIALOG_WINDOW_POINTER, w);
SDL_ShowInputDialogWithProperties(input_callback, NULL, props);
SDL_DestroyProperties(props);
} else if (SDL_PointInRectFloat(&p, &progress_rect)) {
if (progress_dialog) {
continue;
}
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_PROGRESS_DIALOG_WINDOW_POINTER, w);
progress_dialog = SDL_ShowProgressDialogWithProperties(progress_callback, NULL, props);
SDL_DestroyProperties(props);
progress = 0;
progress_done = false;
/* Check creating and immediately destroying a progress dialog */
} else if (SDL_PointInRectFloat(&p, &color_rect)) {
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_COLOR_DIALOG_WINDOW_POINTER, w);
SDL_ShowColorPickerDialogWithProperties(color_callback, NULL, props);
SDL_DestroyProperties(props);
} else if (SDL_PointInRectFloat(&p, &date_rect)) {
SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetPointerProperty(props, SDL_PROP_DATE_DIALOG_WINDOW_POINTER, w);
SDL_ShowDatePickerDialogWithProperties(date_callback, NULL, props);
SDL_DestroyProperties(props);
}
}
}
@ -137,12 +256,37 @@ int main(int argc, char *argv[])
SDL_SetRenderDrawColor(r, 0, 0, 255, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(r, &open_folder_rect);
SDL_SetRenderDrawColor(r, 255, 255, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(r, &input_rect);
SDL_SetRenderDrawColor(r, 255, 0, 255, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(r, &progress_rect);
SDL_SetRenderDrawColor(r, 0, 255, 255, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(r, &color_rect);
SDL_SetRenderDrawColor(r, 255, 255, 255, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(r, &date_rect);
SDL_SetRenderDrawColor(r, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDLTest_DrawString(r, open_file_rect.x+5, open_file_rect.y+open_file_rect.h/2, "Open File...");
SDLTest_DrawString(r, save_file_rect.x+5, save_file_rect.y+save_file_rect.h/2, "Save File...");
SDLTest_DrawString(r, open_folder_rect.x+5, open_folder_rect.y+open_folder_rect.h/2, "Open Folder...");
SDLTest_DrawString(r, input_rect.x+5, input_rect.y+input_rect.h/2, "Input test...");
SDLTest_DrawString(r, progress_rect.x+5, progress_rect.y+progress_rect.h/2, "Progress...");
SDLTest_DrawString(r, color_rect.x+5, color_rect.y+color_rect.h/2, "Choose color...");
SDLTest_DrawString(r, date_rect.x+5, date_rect.y+date_rect.h/2, "Choose date...");
SDL_RenderPresent(r);
if (progress_dialog) {
if (progress_done) {
SDL_DestroyProgressDialog(progress_dialog);
progress_dialog = NULL;
} else if (progress < 30) {
SDL_UpdateProgressDialog(progress_dialog, ((float) ++progress) / 30.0f, NULL);
}
}
}
SDLTest_CleanupTextDrawing();