From adae3e093d6939d392c951b49923d4f51fc07200 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 30 Oct 2012 18:59:56 -0700 Subject: [PATCH] Added Windows message box implementation, but it needs a little work on layout. --- VisualC/SDL/SDL_VS2008.vcproj | 8 + src/video/SDL_video.c | 8 + src/video/windows/SDL_windowsmessagebox.c | 282 ++++++++++++++++++++++ src/video/windows/SDL_windowsmessagebox.h | 29 +++ 4 files changed, 327 insertions(+) create mode 100644 src/video/windows/SDL_windowsmessagebox.c create mode 100644 src/video/windows/SDL_windowsmessagebox.h diff --git a/VisualC/SDL/SDL_VS2008.vcproj b/VisualC/SDL/SDL_VS2008.vcproj index 2ff9f0c8a..3c06ac90b 100644 --- a/VisualC/SDL/SDL_VS2008.vcproj +++ b/VisualC/SDL/SDL_VS2008.vcproj @@ -1216,6 +1216,14 @@ RelativePath="..\..\src\video\windows\SDL_windowskeyboard.h" > + + + + diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 834bd19c0..5d12d10af 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -2841,6 +2841,9 @@ SDL_IsScreenKeyboardShown(SDL_Window *window) return SDL_FALSE; } +#if SDL_VIDEO_DRIVER_WINDOWS +#include "windows/SDL_windowsmessagebox.h" +#endif #if SDL_VIDEO_DRIVER_COCOA #include "cocoa/SDL_cocoamessagebox.h" #endif @@ -2866,6 +2869,11 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) } /* It's completely fine to call this function before video is initialized */ +#if SDL_VIDEO_DRIVER_WINDOWS + if (WIN_ShowMessageBox(messageboxdata, buttonid) == 0) { + return 0; + } +#endif #if SDL_VIDEO_DRIVER_COCOA if (Cocoa_ShowMessageBox(messageboxdata, buttonid) == 0) { return 0; diff --git a/src/video/windows/SDL_windowsmessagebox.c b/src/video/windows/SDL_windowsmessagebox.c new file mode 100644 index 000000000..bb5eaaf24 --- /dev/null +++ b/src/video/windows/SDL_windowsmessagebox.c @@ -0,0 +1,282 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + 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 "SDL_config.h" + +#if SDL_VIDEO_DRIVER_WINDOWS + +#include "SDL.h" +#include "SDL_windowsvideo.h" + + +/* Display a Windows message box */ + +typedef struct +{ + LPDLGTEMPLATE lpDialog; + Uint8 *data; + size_t size; + size_t used; +} WIN_DialogData; + + +static INT_PTR MessageBoxDialogProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam) +{ + switch ( iMessage ) { + case WM_COMMAND: + /* Return the ID of the button that was pushed */ + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + + default: + break; + } + return FALSE; +} + +static SDL_bool ExpandDialogSpace(WIN_DialogData *dialog, size_t space) +{ + size_t size = dialog->size; + + if (size == 0) { + size = space; + } else { + while ((dialog->used + space) > size) { + size *= 2; + } + } + if (size > dialog->size) { + void *data = SDL_realloc(dialog->data, size); + if (!data) { + SDL_OutOfMemory(); + return SDL_FALSE; + } + dialog->data = data; + dialog->size = size; + dialog->lpDialog = (LPDLGTEMPLATE)dialog->data; + } + return SDL_TRUE; +} + +static SDL_bool AlignDialogData(WIN_DialogData *dialog, size_t size) +{ + size_t padding = (dialog->used % size); + + if (!ExpandDialogSpace(dialog, padding)) { + return SDL_FALSE; + } + + dialog->used += padding; + + return SDL_TRUE; +} + +static SDL_bool AddDialogData(WIN_DialogData *dialog, const void *data, size_t size) +{ + if (!ExpandDialogSpace(dialog, size)) { + return SDL_FALSE; + } + + SDL_memcpy(dialog->data+dialog->used, data, size); + dialog->used += size; + + return SDL_TRUE; +} + +static SDL_bool AddDialogString(WIN_DialogData *dialog, const char *string) +{ + WCHAR *wstring; + WCHAR *p; + size_t count; + SDL_bool status; + + if (!string) { + string = ""; + } + + wstring = WIN_UTF8ToString(string); + if (!wstring) { + return SDL_FALSE; + } + + /* Find out how many characters we have, including null terminator */ + count = 0; + for (p = wstring; *p; ++p) { + ++count; + } + ++count; + + status = AddDialogData(dialog, wstring, count*sizeof(WCHAR)); + SDL_free(wstring); + return status; +} + +static 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) +{ + DLGITEMTEMPLATE item; + WORD marker = 0xFFFF; + WORD extraData = 0; + + SDL_zero(item); + item.style = style; + item.dwExtendedStyle = exStyle; + item.x = x; + item.y = y; + item.cx = w; + item.cy = h; + item.id = id; + + if (!AlignDialogData(dialog, sizeof(DWORD))) { + return SDL_FALSE; + } + if (!AddDialogData(dialog, &item, sizeof(item))) { + return SDL_FALSE; + } + if (!AddDialogData(dialog, &marker, sizeof(marker))) { + return SDL_FALSE; + } + if (!AddDialogData(dialog, &type, sizeof(type))) { + return SDL_FALSE; + } + if (!AddDialogString(dialog, caption)) { + return SDL_FALSE; + } + if (!AddDialogData(dialog, &extraData, sizeof(extraData))) { + return SDL_FALSE; + } + ++dialog->lpDialog->cdit; + + return SDL_TRUE; +} + +static SDL_bool AddDialogStatic(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text) +{ + DWORD style = WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOPREFIX; + return AddDialogControl(dialog, 0x0082, style, 0, x, y, w, h, -1, text); +} + +static SDL_bool AddDialogButton(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text, int id, SDL_bool isDefault) +{ + DWORD style = WS_VISIBLE | WS_CHILD; + if (isDefault) { + style |= BS_DEFPUSHBUTTON; + } else { + style |= BS_PUSHBUTTON; + } + return AddDialogControl(dialog, 0x0080, style, 0, x, y, w, h, id, text); +} + +static void FreeDialogData(WIN_DialogData *dialog) +{ + if (dialog->data) { + SDL_free(dialog->data); + } + SDL_free(dialog); +} + +static WIN_DialogData *CreateDialogData(int w, int h, const char *caption) +{ + WIN_DialogData *dialog; + DLGTEMPLATE dialogTemplate; + + SDL_zero(dialogTemplate); + dialogTemplate.style = (WS_CAPTION | DS_CENTER); + dialogTemplate.x = 0; + dialogTemplate.y = 0; + dialogTemplate.cx = w; + dialogTemplate.cy = h; + + dialog = (WIN_DialogData *)SDL_calloc(1, sizeof(*dialog)); + if (!dialog) { + return NULL; + } + + if (!AddDialogData(dialog, &dialogTemplate, sizeof(dialogTemplate))) { + FreeDialogData(dialog); + return NULL; + } + + /* There is no menu or special class */ + if (!AddDialogString(dialog, "") || !AddDialogString(dialog, "")) { + FreeDialogData(dialog); + return NULL; + } + + if (!AddDialogString(dialog, caption)) { + FreeDialogData(dialog); + return NULL; + } + + return dialog; +} + +int +WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + WIN_DialogData *dialog; + int i, x, y, w, h, gap, which; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + + /* FIXME: Need a better algorithm for laying out the message box */ + + dialog = CreateDialogData(570, 260, messageboxdata->title); + if (!dialog) { + return -1; + } + + w = 100; + h = 25; + gap = 10; + x = gap; + y = 50; + + if (!AddDialogStatic(dialog, x, y, 550, 100, messageboxdata->message)) { + FreeDialogData(dialog); + return -1; + } + + y += 110; + + for (i = 0; i < messageboxdata->numbuttons; ++i) { + SDL_bool isDefault; + + if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) { + isDefault = SDL_TRUE; + } else { + isDefault = SDL_FALSE; + } + if (!AddDialogButton(dialog, x, y, w, h, buttons[i].text, i, isDefault)) { + FreeDialogData(dialog); + return -1; + } + x += w + gap; + } + + /* FIXME: If we have a parent window, get the Instance and HWND for them */ + which = DialogBoxIndirect(NULL, dialog->lpDialog, NULL, (DLGPROC)MessageBoxDialogProc); + *buttonid = buttons[which].buttonid; + + FreeDialogData(dialog); + return 0; +} + +#endif /* SDL_VIDEO_DRIVER_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/windows/SDL_windowsmessagebox.h b/src/video/windows/SDL_windowsmessagebox.h new file mode 100644 index 000000000..29c3eb850 --- /dev/null +++ b/src/video/windows/SDL_windowsmessagebox.h @@ -0,0 +1,29 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + 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 "SDL_config.h" + +#if SDL_VIDEO_DRIVER_WINDOWS + +extern int WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid); + +#endif /* SDL_VIDEO_DRIVER_WINDOWS */ + +/* vi: set ts=4 sw=4 expandtab: */