21#include "../../SDL_internal.h"
23#if SDL_VIDEO_DRIVER_WINDOWS
29#define SIZE_MAX ((size_t)-1)
33#include "../../core/windows/SDL_windows.h"
40#define SS_EDITCONTROL 0x2000
53#define IDINVALPTRINIT 50
54#define IDINVALPTRCOMMAND 51
55#define IDINVALPTRSETFOCUS 52
56#define IDINVALPTRDLGITEM 53
58#define IDBUTTONINDEX0 100
60#define DLGITEMTYPEBUTTON 0x0080
61#define DLGITEMTYPESTATIC 0x0082
68#define MAX_BUTTONS (0xffff - 100)
105 DLGTEMPLATEEX* lpDialog;
122static INT_PTR MessageBoxDialogProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
127 switch ( iMessage ) {
130 EndDialog(hDlg, IDINVALPTRINIT);
134 SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
138 HWND buttonctl = GetDlgItem(hDlg, (
int)(IDBUTTONINDEX0 + buttonindex));
139 if (buttonctl ==
NULL) {
140 EndDialog(hDlg, IDINVALPTRDLGITEM);
142 PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)buttonctl,
TRUE);
150 if (messageboxdata ==
NULL) {
151 EndDialog(hDlg, IDINVALPTRSETFOCUS);
162 if (messageboxdata ==
NULL) {
163 EndDialog(hDlg, IDINVALPTRCOMMAND);
168 if (wParam == IDOK) {
170 EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
172 }
else if (wParam == IDCANCEL) {
174 EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
177 EndDialog(hDlg, IDCLOSED);
179 }
else if (wParam >= IDBUTTONINDEX0 && (
int)wParam - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
180 EndDialog(hDlg, wParam);
190static SDL_bool ExpandDialogSpace(WIN_DialogData *dialog,
size_t space)
193 const size_t sizestep = 0x10000;
194 size_t size = dialog->size;
201 }
else if (space >
size) {
202 size = (space + sizestep) & ~(sizestep - 1);
204 }
else if (
SIZE_MAX - dialog->used < space) {
207 }
else if (
SIZE_MAX - (dialog->used + space) < sizestep) {
209 size = dialog->used + space;
212 size = dialog->used + space;
216 if (
size > dialog->size) {
224 dialog->lpDialog = (DLGTEMPLATEEX*)dialog->data;
229static SDL_bool AlignDialogData(WIN_DialogData *dialog,
size_t size)
231 size_t padding = (dialog->used %
size);
233 if (!ExpandDialogSpace(dialog, padding)) {
237 dialog->used += padding;
242static SDL_bool AddDialogData(WIN_DialogData *dialog,
const void *
data,
size_t size)
244 if (!ExpandDialogSpace(dialog,
size)) {
249 dialog->used +=
size;
254static SDL_bool AddDialogString(WIN_DialogData *dialog,
const char *
string)
272 for (
p = wstring; *
p; ++
p) {
277 status = AddDialogData(dialog, wstring,
count*
sizeof(WCHAR));
282static int s_BaseUnitsX;
283static int s_BaseUnitsY;
284static void Vec2ToDLU(
short *
x,
short *
y)
288 *
x = MulDiv(*
x, 4, s_BaseUnitsX);
289 *
y = MulDiv(*
y, 8, s_BaseUnitsY);
293static SDL_bool AddDialogControl(WIN_DialogData *dialog, WORD
type, DWORD style, DWORD exStyle,
int x,
int y,
int w,
int h,
int id,
const char *caption, WORD ordinal)
295 DLGITEMTEMPLATEEX item;
301 item.exStyle = exStyle;
308 Vec2ToDLU(&item.x, &item.y);
309 Vec2ToDLU(&item.cx, &item.cy);
311 if (!AlignDialogData(dialog,
sizeof(DWORD))) {
314 if (!AddDialogData(dialog, &item,
sizeof(item))) {
320 if (!AddDialogData(dialog, &
type,
sizeof(
type))) {
323 if (
type == DLGITEMTYPEBUTTON || (
type == DLGITEMTYPESTATIC && caption !=
NULL)) {
324 if (!AddDialogString(dialog, caption)) {
331 if (!AddDialogData(dialog, &ordinal,
sizeof(ordinal))) {
335 if (!AddDialogData(dialog, &extraData,
sizeof(extraData))) {
338 if (
type == DLGITEMTYPEBUTTON) {
339 dialog->numbuttons++;
341 ++dialog->lpDialog->cDlgItems;
346static SDL_bool AddDialogStaticText(WIN_DialogData *dialog,
int x,
int y,
int w,
int h,
const char *
text)
348 DWORD style = WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOPREFIX | SS_EDITCONTROL | WS_GROUP;
349 return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0,
x,
y,
w,
h, -1,
text, 0);
352static SDL_bool AddDialogStaticIcon(WIN_DialogData *dialog,
int x,
int y,
int w,
int h,
Uint16 ordinal)
354 DWORD style = WS_VISIBLE | WS_CHILD | SS_ICON | WS_GROUP;
355 return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0,
x,
y,
w,
h, -2,
NULL, ordinal);
358static SDL_bool AddDialogButton(WIN_DialogData *dialog,
int x,
int y,
int w,
int h,
const char *
text,
int id,
SDL_bool isDefault)
360 DWORD style = WS_VISIBLE | WS_CHILD | WS_TABSTOP;
362 style |= BS_DEFPUSHBUTTON;
364 style |= BS_PUSHBUTTON;
367 if (dialog->numbuttons == 0) {
370 return AddDialogControl(dialog, DLGITEMTYPEBUTTON, style, 0,
x,
y,
w,
h, IDBUTTONINDEX0 + dialog->numbuttons,
text, 0);
373static void FreeDialogData(WIN_DialogData *dialog)
379static WIN_DialogData *CreateDialogData(
int w,
int h,
const char *caption)
381 WIN_DialogData *dialog;
382 DLGTEMPLATEEX dialogTemplate;
386 dialogTemplate.dlgVer = 1;
387 dialogTemplate.signature = 0xffff;
388 dialogTemplate.style = (WS_CAPTION | DS_CENTER | DS_SHELLFONT);
389 dialogTemplate.x = 0;
390 dialogTemplate.y = 0;
391 dialogTemplate.cx =
w;
392 dialogTemplate.cy =
h;
393 Vec2ToDLU(&dialogTemplate.cx, &dialogTemplate.cy);
395 dialog = (WIN_DialogData *)
SDL_calloc(1,
sizeof(*dialog));
400 if (!AddDialogData(dialog, &dialogTemplate,
sizeof(dialogTemplate))) {
401 FreeDialogData(dialog);
407 if (!AddDialogData(dialog, &WordToPass, 2)) {
408 FreeDialogData(dialog);
413 if (!AddDialogData(dialog, &WordToPass, 2)) {
414 FreeDialogData(dialog);
419 if (!AddDialogString(dialog, caption)) {
420 FreeDialogData(dialog);
431 NONCLIENTMETRICSA NCM;
432 NCM.cbSize =
sizeof(NCM);
433 SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
437 HDC ScreenDC = GetDC(
NULL);
438 int LogicalPixelsY = GetDeviceCaps(ScreenDC, LOGPIXELSY);
441 WordToPass = (WORD)(-72 * NCM.lfMessageFont.lfHeight / LogicalPixelsY);
442 ReleaseDC(
NULL, ScreenDC);
445 if (!AddDialogData(dialog, &WordToPass, 2)) {
446 FreeDialogData(dialog);
451 WordToPass = (WORD)NCM.lfMessageFont.lfWeight;
452 if (!AddDialogData(dialog, &WordToPass, 2)) {
453 FreeDialogData(dialog);
458 ToPass = NCM.lfMessageFont.lfItalic;
459 if (!AddDialogData(dialog, &ToPass, 1)) {
460 FreeDialogData(dialog);
465 ToPass = NCM.lfMessageFont.lfCharSet;
466 if (!AddDialogData(dialog, &ToPass, 1)) {
467 FreeDialogData(dialog);
472 if (!AddDialogString(dialog, NCM.lfMessageFont.lfFaceName)) {
473 FreeDialogData(dialog);
490static const char *EscapeAmpersands(
char **
dst,
size_t *dstlen,
const char *
src)
500 while (
src[srclen]) {
501 if (
src[srclen] ==
'&') {
515 if (*
dst ==
NULL || *dstlen < srclen + ampcount) {
517 size_t extraspace =
SIZE_MAX - (srclen + ampcount);
518 if (extraspace > 512) {
521 *dstlen = srclen + ampcount + extraspace;
525 if (newdst ==
NULL) {
548 WIN_DialogData *dialog;
558 char *ampescape =
NULL;
559 size_t ampescapesize = 0;
560 Uint16 defbuttoncount = 0;
563 HWND ParentWindow =
NULL;
565 const int ButtonWidth = 88;
566 const int ButtonHeight = 26;
567 const int TextMargin = 16;
568 const int ButtonMargin = 12;
569 const int IconWidth = GetSystemMetrics(SM_CXICON);
570 const int IconHeight = GetSystemMetrics(SM_CYICON);
571 const int IconMargin = 20;
573 if (messageboxdata->
numbuttons > MAX_BUTTONS) {
574 return SDL_SetError(
"Number of butons exceeds limit of %d", MAX_BUTTONS);
577 switch (messageboxdata->
flags) {
579 icon = (
Uint16)(
size_t)IDI_ERROR;
582 icon = (
Uint16)(
size_t)IDI_WARNING;
585 icon = (
Uint16)(
size_t)IDI_INFORMATION;
621 FontDC = CreateCompatibleDC(0);
626 NONCLIENTMETRICS NCM;
627 NCM.cbSize =
sizeof(NCM);
628 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
629 lf = NCM.lfMessageFont;
630 DialogFont = CreateFontIndirect(&lf);
634 SelectObject(FontDC, DialogFont);
638 GetTextMetrics(FontDC, &TM);
646 GetTextExtentPoint32A(FontDC,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &extent);
647 s_BaseUnitsX = (extent.cx / 26 + 1) / 2;
650 s_BaseUnitsY = TM.tmHeight;
656 DrawText(FontDC, wmessage, -1, &TextSize, DT_CALCRECT | DT_LEFT | DT_NOPREFIX | DT_EDITCONTROL);
659 TextSize.left += TextMargin;
660 TextSize.right += TextMargin + 2;
661 TextSize.top += TextMargin;
662 TextSize.bottom += TextMargin + 2;
669 Size.cx = TextSize.right - TextSize.left;
670 Size.cy = TextSize.bottom - TextSize.top;
671 Size.cx += TextMargin * 2;
672 Size.cy += TextMargin * 2;
676 Size.cx += IconMargin + IconWidth;
677 TextSize.left += IconMargin + IconWidth;
678 TextSize.right += IconMargin + IconWidth;
682 if (Size.cx < messageboxdata->
numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin)
683 Size.cx = messageboxdata->
numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin;
686 if (icon && Size.cy < IconMargin * 2 + IconHeight) {
687 Size.cy = IconMargin * 2 + IconHeight;
691 Size.cy += ButtonHeight + TextMargin;
693 dialog = CreateDialogData(Size.cx, Size.cy, messageboxdata->
title);
698 if (icon && ! AddDialogStaticIcon(dialog, IconMargin, IconMargin, IconWidth, IconHeight, icon)) {
699 FreeDialogData(dialog);
703 if (!AddDialogStaticText(dialog, TextSize.left, TextSize.top, TextSize.right - TextSize.left, TextSize.bottom - TextSize.top, messageboxdata->
message)) {
704 FreeDialogData(dialog);
709 x = Size.cx - (ButtonWidth + ButtonMargin) * messageboxdata->
numbuttons;
710 y = Size.cy - ButtonHeight - ButtonMargin;
713 const char *buttontext;
717 if (defbuttoncount == 1) {
722 buttontext = EscapeAmpersands(&escape, &escapesize, buttons[
i].
text);
723 if (buttontext ==
NULL || !AddDialogButton(dialog,
x,
y, ButtonWidth, ButtonHeight, buttontext, buttons[
i].buttonid, isdefault)) {
724 FreeDialogData(dialog);
728 x += ButtonWidth + ButtonMargin;
734 if (messageboxdata->
window) {
738 result = DialogBoxIndirectParam(
NULL, (DLGTEMPLATE*)dialog->lpDialog, ParentWindow, (DLGPROC)MessageBoxDialogProc, (LPARAM)messageboxdata);
739 if (
result >= IDBUTTONINDEX0 &&
result - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
742 }
else if (
result == IDCLOSED) {
750 }
else if (
result == -1) {
752 }
else if (
result == IDINVALPTRINIT ||
result == IDINVALPTRSETFOCUS ||
result == IDINVALPTRCOMMAND) {
753 SDL_SetError(
"Invalid message box pointer in dialog procedure");
754 }
else if (
result == IDINVALPTRDLGITEM) {
755 SDL_SetError(
"Couldn't find dialog control of the default enter-key button");
762 FreeDialogData(dialog);
769typedef HRESULT(
FAR WINAPI *TASKDIALOGINDIRECTPROC)(
const TASKDIALOGCONFIG *pTaskConfig,
int *pnButton,
int *pnRadioButton, BOOL *pfVerificationFlagChecked);
774 HWND ParentWindow =
NULL;
781 TASKDIALOGINDIRECTPROC pfnTaskDialogIndirect;
783 char *ampescape =
NULL;
784 size_t ampescapesize = 0;
794 hComctl32 = LoadLibrary(TEXT(
"Comctl32.dll"));
795 if (hComctl32 ==
NULL) {
796 return WIN_ShowOldMessageBox(messageboxdata, buttonid);
806 pfnTaskDialogIndirect = (TASKDIALOGINDIRECTPROC) GetProcAddress(hComctl32,
"TaskDialogIndirect");
807 if (pfnTaskDialogIndirect ==
NULL) {
808 FreeLibrary(hComctl32);
809 return WIN_ShowOldMessageBox(messageboxdata, buttonid);
814 if (messageboxdata->
window) {
843 const char *buttontext;
844 pButton = &pButtons[messageboxdata->
numbuttons-1-
i];
854 buttontext = EscapeAmpersands(&escape, &escapesize, messageboxdata->
buttons[
i].
text);
855 if (buttontext ==
NULL) {
857 FreeLibrary(hComctl32);
861 for (
j = 0;
j <
i;
j++) {
862 SDL_free((
wchar_t *) pButtons[
j].pszButtonText);
875 hr = pfnTaskDialogIndirect(&TaskConfig, &nButton,
NULL,
NULL);
878 FreeLibrary(hComctl32);
883 SDL_free((
wchar_t *) pButtons[
i].pszButtonText);
890 *buttonid = nCancelButton;
891 }
else if (nButton > 2) {
892 *buttonid = nButton-1-1;
894 *buttonid = nButton-1;
900 return WIN_ShowOldMessageBox(messageboxdata, buttonid);
#define SDL_assert(condition)
#define SDL_OutOfMemory()
@ SDL_MESSAGEBOX_INFORMATION
@ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT
@ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT
GLint GLint GLint GLint GLint GLint y
GLuint GLuint GLsizei count
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLint GLint GLint GLint GLint x
GLuint GLuint GLsizei GLenum type
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
#define WIN_UTF8ToString(S)
#define TD_INFORMATION_ICON
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
MessageBox structure containing title, text, window, etc.
const SDL_MessageBoxButtonData * buttons
const TASKDIALOG_BUTTON * pButtons
static char text[MAX_TEXT_LENGTH]