mirror of https://github.com/encounter/SDL.git
windows: Message boxes use Task Dialogs if possible (thanks, Jack!).
This lets the message box have an icon. Unless the app has opted-in to using the v6 common controls, though, this will fall back to the usual SDL message boxes.
This commit is contained in:
parent
8536130aa2
commit
a749035f10
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "SDL_assert.h"
|
||||
#include "SDL_windowsvideo.h"
|
||||
|
||||
#include "SDL_windowstaskdialog.h"
|
||||
|
||||
#ifndef SS_EDITCONTROL
|
||||
#define SS_EDITCONTROL 0x2000
|
||||
|
@ -341,8 +341,9 @@ static WIN_DialogData *CreateDialogData(int w, int h, const char *caption)
|
|||
return dialog;
|
||||
}
|
||||
|
||||
int
|
||||
WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
||||
/* This function is called if a Task Dialog is unsupported. */
|
||||
static int
|
||||
WIN_ShowOldMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
||||
{
|
||||
WIN_DialogData *dialog;
|
||||
int i, x, y;
|
||||
|
@ -491,6 +492,121 @@ WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* TaskDialogIndirect procedure
|
||||
* This is because SDL targets Windows XP (0x501), so this is not defined in the platform SDK.
|
||||
*/
|
||||
typedef HRESULT(FAR WINAPI *TASKDIALOGINDIRECTPROC)(_In_ const TASKDIALOGCONFIG *pTaskConfig, _Out_opt_ int *pnButton, _Out_opt_ int *pnRadioButton, _Out_opt_ BOOL *pfVerificationFlagChecked);
|
||||
|
||||
int
|
||||
WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
|
||||
{
|
||||
HWND ParentWindow = NULL;
|
||||
wchar_t *wmessage;
|
||||
wchar_t *wtitle;
|
||||
TASKDIALOGCONFIG TaskConfig;
|
||||
TASKDIALOG_BUTTON *pButtons;
|
||||
TASKDIALOG_BUTTON *pButton;
|
||||
HMODULE hComctl32;
|
||||
TASKDIALOGINDIRECTPROC pfnTaskDialogIndirect;
|
||||
HRESULT hr;
|
||||
int nButton;
|
||||
int nCancelButton;
|
||||
int i;
|
||||
|
||||
/* If we cannot load comctl32.dll use the old messagebox! */
|
||||
hComctl32 = LoadLibrary(TEXT("Comctl32.dll"));
|
||||
if (hComctl32 == NULL) {
|
||||
return WIN_ShowOldMessageBox(messageboxdata,buttonid);
|
||||
}
|
||||
|
||||
/* If TaskDialogIndirect doesn't exist use the old messagebox!
|
||||
This will fail prior to Windows Vista.
|
||||
The manifest file in the application may require targeting version 6 of comctl32.dll, even
|
||||
when we use LoadLibrary here!
|
||||
If you don't want to bother with manifests, put this #pragma in your app's source code somewhere:
|
||||
pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
*/
|
||||
pfnTaskDialogIndirect = (TASKDIALOGINDIRECTPROC) GetProcAddress(hComctl32, "TaskDialogIndirect");
|
||||
if (pfnTaskDialogIndirect == NULL) {
|
||||
FreeLibrary(hComctl32);
|
||||
return WIN_ShowOldMessageBox(messageboxdata, buttonid);
|
||||
}
|
||||
|
||||
/* If we have a parent window, get the Instance and HWND for them
|
||||
so that our little dialog gets exclusive focus at all times. */
|
||||
if (messageboxdata->window) {
|
||||
ParentWindow = ((SDL_WindowData *) messageboxdata->window->driverdata)->hwnd;
|
||||
}
|
||||
|
||||
wmessage = WIN_UTF8ToString(messageboxdata->message);
|
||||
wtitle = WIN_UTF8ToString(messageboxdata->title);
|
||||
|
||||
SDL_zero(TaskConfig);
|
||||
TaskConfig.cbSize = sizeof (TASKDIALOGCONFIG);
|
||||
TaskConfig.hwndParent = ParentWindow;
|
||||
TaskConfig.dwFlags = TDF_SIZE_TO_CONTENT;
|
||||
TaskConfig.pszWindowTitle = wtitle;
|
||||
if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
|
||||
TaskConfig.pszMainIcon = TD_ERROR_ICON;
|
||||
} else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
|
||||
TaskConfig.pszMainIcon = TD_WARNING_ICON;
|
||||
} else if (messageboxdata->flags & SDL_MESSAGEBOX_INFORMATION) {
|
||||
TaskConfig.pszMainIcon = TD_INFORMATION_ICON;
|
||||
} else {
|
||||
TaskConfig.pszMainIcon = NULL;
|
||||
}
|
||||
|
||||
TaskConfig.pszContent = wmessage;
|
||||
TaskConfig.cButtons = messageboxdata->numbuttons;
|
||||
pButtons = SDL_malloc(sizeof (TASKDIALOG_BUTTON) * messageboxdata->numbuttons);
|
||||
TaskConfig.nDefaultButton = 0;
|
||||
for (i = 0; i < messageboxdata->numbuttons; i++)
|
||||
{
|
||||
pButton = &pButtons[messageboxdata->numbuttons-1-i];
|
||||
if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
|
||||
nCancelButton = messageboxdata->buttons[i].buttonid;
|
||||
pButton->nButtonID = 2;
|
||||
} else {
|
||||
pButton->nButtonID = messageboxdata->buttons[i].buttonid + 1;
|
||||
if (pButton->nButtonID >= 2) {
|
||||
pButton->nButtonID++;
|
||||
}
|
||||
}
|
||||
pButton->pszButtonText = WIN_UTF8ToString(messageboxdata->buttons[i].text);
|
||||
if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
|
||||
TaskConfig.nDefaultButton = pButton->nButtonID;
|
||||
}
|
||||
}
|
||||
TaskConfig.pButtons = pButtons;
|
||||
|
||||
/* Show the Task Dialog */
|
||||
hr = pfnTaskDialogIndirect(&TaskConfig, &nButton, NULL, NULL);
|
||||
|
||||
/* Free everything */
|
||||
FreeLibrary(hComctl32);
|
||||
SDL_free(wmessage);
|
||||
SDL_free(wtitle);
|
||||
for (i = 0; i < messageboxdata->numbuttons; i++) {
|
||||
SDL_free((wchar_t *) pButtons[i].pszButtonText);
|
||||
}
|
||||
SDL_free(pButtons);
|
||||
|
||||
/* Check the Task Dialog was successful and give the result */
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (nButton == 2) {
|
||||
*buttonid = nCancelButton;
|
||||
} else if (nButton > 2) {
|
||||
*buttonid = nButton-1-1;
|
||||
} else {
|
||||
*buttonid = nButton-1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We failed showing the Task Dialog, use the old message box! */
|
||||
return WIN_ShowOldMessageBox(messageboxdata, buttonid);
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include <pshpack1.h>
|
||||
|
||||
typedef HRESULT(CALLBACK *PFTASKDIALOGCALLBACK)(_In_ HWND hwnd, _In_ UINT msg, _In_ WPARAM wParam, _In_ LPARAM lParam, _In_ LONG_PTR lpRefData);
|
||||
|
||||
enum _TASKDIALOG_FLAGS
|
||||
{
|
||||
TDF_ENABLE_HYPERLINKS = 0x0001,
|
||||
TDF_USE_HICON_MAIN = 0x0002,
|
||||
TDF_USE_HICON_FOOTER = 0x0004,
|
||||
TDF_ALLOW_DIALOG_CANCELLATION = 0x0008,
|
||||
TDF_USE_COMMAND_LINKS = 0x0010,
|
||||
TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020,
|
||||
TDF_EXPAND_FOOTER_AREA = 0x0040,
|
||||
TDF_EXPANDED_BY_DEFAULT = 0x0080,
|
||||
TDF_VERIFICATION_FLAG_CHECKED = 0x0100,
|
||||
TDF_SHOW_PROGRESS_BAR = 0x0200,
|
||||
TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400,
|
||||
TDF_CALLBACK_TIMER = 0x0800,
|
||||
TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000,
|
||||
TDF_RTL_LAYOUT = 0x2000,
|
||||
TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000,
|
||||
TDF_CAN_BE_MINIMIZED = 0x8000,
|
||||
//#if (NTDDI_VERSION >= NTDDI_WIN8)
|
||||
TDF_NO_SET_FOREGROUND = 0x00010000, // Don't call SetForegroundWindow() when activating the dialog
|
||||
//#endif // (NTDDI_VERSION >= NTDDI_WIN8)
|
||||
TDF_SIZE_TO_CONTENT = 0x01000000 // used by ShellMessageBox to emulate MessageBox sizing behavior
|
||||
};
|
||||
typedef int TASKDIALOG_FLAGS; // Note: _TASKDIALOG_FLAGS is an int
|
||||
|
||||
typedef enum _TASKDIALOG_MESSAGES
|
||||
{
|
||||
TDM_NAVIGATE_PAGE = WM_USER + 101,
|
||||
TDM_CLICK_BUTTON = WM_USER + 102, // wParam = Button ID
|
||||
TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee)
|
||||
TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, // wParam = new progress state
|
||||
TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange)
|
||||
TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, // wParam = new position
|
||||
TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints)
|
||||
TDM_SET_ELEMENT_TEXT = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
|
||||
TDM_CLICK_RADIO_BUTTON = WM_USER + 110, // wParam = Radio Button ID
|
||||
TDM_ENABLE_BUTTON = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID
|
||||
TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID
|
||||
TDM_CLICK_VERIFICATION = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus)
|
||||
TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR)
|
||||
TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required)
|
||||
TDM_UPDATE_ICON = WM_USER + 116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise)
|
||||
} TASKDIALOG_MESSAGES;
|
||||
|
||||
typedef enum _TASKDIALOG_NOTIFICATIONS
|
||||
{
|
||||
TDN_CREATED = 0,
|
||||
TDN_NAVIGATED = 1,
|
||||
TDN_BUTTON_CLICKED = 2, // wParam = Button ID
|
||||
TDN_HYPERLINK_CLICKED = 3, // lParam = (LPCWSTR)pszHREF
|
||||
TDN_TIMER = 4, // wParam = Milliseconds since dialog created or timer reset
|
||||
TDN_DESTROYED = 5,
|
||||
TDN_RADIO_BUTTON_CLICKED = 6, // wParam = Radio Button ID
|
||||
TDN_DIALOG_CONSTRUCTED = 7,
|
||||
TDN_VERIFICATION_CLICKED = 8, // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0
|
||||
TDN_HELP = 9,
|
||||
TDN_EXPANDO_BUTTON_CLICKED = 10 // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded)
|
||||
} TASKDIALOG_NOTIFICATIONS;
|
||||
|
||||
typedef struct _TASKDIALOG_BUTTON
|
||||
{
|
||||
int nButtonID;
|
||||
PCWSTR pszButtonText;
|
||||
} TASKDIALOG_BUTTON;
|
||||
|
||||
typedef enum _TASKDIALOG_ELEMENTS
|
||||
{
|
||||
TDE_CONTENT,
|
||||
TDE_EXPANDED_INFORMATION,
|
||||
TDE_FOOTER,
|
||||
TDE_MAIN_INSTRUCTION
|
||||
} TASKDIALOG_ELEMENTS;
|
||||
|
||||
typedef enum _TASKDIALOG_ICON_ELEMENTS
|
||||
{
|
||||
TDIE_ICON_MAIN,
|
||||
TDIE_ICON_FOOTER
|
||||
} TASKDIALOG_ICON_ELEMENTS;
|
||||
|
||||
#define TD_WARNING_ICON MAKEINTRESOURCEW(-1)
|
||||
#define TD_ERROR_ICON MAKEINTRESOURCEW(-2)
|
||||
#define TD_INFORMATION_ICON MAKEINTRESOURCEW(-3)
|
||||
#define TD_SHIELD_ICON MAKEINTRESOURCEW(-4)
|
||||
|
||||
enum _TASKDIALOG_COMMON_BUTTON_FLAGS
|
||||
{
|
||||
TDCBF_OK_BUTTON = 0x0001, // selected control return value IDOK
|
||||
TDCBF_YES_BUTTON = 0x0002, // selected control return value IDYES
|
||||
TDCBF_NO_BUTTON = 0x0004, // selected control return value IDNO
|
||||
TDCBF_CANCEL_BUTTON = 0x0008, // selected control return value IDCANCEL
|
||||
TDCBF_RETRY_BUTTON = 0x0010, // selected control return value IDRETRY
|
||||
TDCBF_CLOSE_BUTTON = 0x0020 // selected control return value IDCLOSE
|
||||
};
|
||||
typedef int TASKDIALOG_COMMON_BUTTON_FLAGS; // Note: _TASKDIALOG_COMMON_BUTTON_FLAGS is an int
|
||||
|
||||
typedef struct _TASKDIALOGCONFIG
|
||||
{
|
||||
UINT cbSize;
|
||||
HWND hwndParent; // incorrectly named, this is the owner window, not a parent.
|
||||
HINSTANCE hInstance; // used for MAKEINTRESOURCE() strings
|
||||
TASKDIALOG_FLAGS dwFlags; // TASKDIALOG_FLAGS (TDF_XXX) flags
|
||||
TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons; // TASKDIALOG_COMMON_BUTTON (TDCBF_XXX) flags
|
||||
PCWSTR pszWindowTitle; // string or MAKEINTRESOURCE()
|
||||
union
|
||||
{
|
||||
HICON hMainIcon;
|
||||
PCWSTR pszMainIcon;
|
||||
} DUMMYUNIONNAME;
|
||||
PCWSTR pszMainInstruction;
|
||||
PCWSTR pszContent;
|
||||
UINT cButtons;
|
||||
const TASKDIALOG_BUTTON *pButtons;
|
||||
int nDefaultButton;
|
||||
UINT cRadioButtons;
|
||||
const TASKDIALOG_BUTTON *pRadioButtons;
|
||||
int nDefaultRadioButton;
|
||||
PCWSTR pszVerificationText;
|
||||
PCWSTR pszExpandedInformation;
|
||||
PCWSTR pszExpandedControlText;
|
||||
PCWSTR pszCollapsedControlText;
|
||||
union
|
||||
{
|
||||
HICON hFooterIcon;
|
||||
PCWSTR pszFooterIcon;
|
||||
} DUMMYUNIONNAME2;
|
||||
PCWSTR pszFooter;
|
||||
PFTASKDIALOGCALLBACK pfCallback;
|
||||
LONG_PTR lpCallbackData;
|
||||
UINT cxWidth; // width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width.
|
||||
} TASKDIALOGCONFIG;
|
||||
|
||||
#include <poppack.h>
|
Loading…
Reference in New Issue