zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
SDL_windowsmessagebox.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "SDL_config.h"
22 
23 #if SDL_VIDEO_DRIVER_WINDOWS
24 
25 #include "SDL.h"
26 #include "SDL_windowsvideo.h"
27 
28 
29 #ifndef SS_EDITCONTROL
30 #define SS_EDITCONTROL 0x2000
31 #endif
32 
33 /* Display a Windows message box */
34 
35 #pragma pack(push, 1)
36 
37 typedef struct
38 {
39  WORD dlgVer;
40  WORD signature;
41  DWORD helpID;
42  DWORD exStyle;
43  DWORD style;
44  WORD cDlgItems;
45  short x;
46  short y;
47  short cx;
48  short cy;
49 } DLGTEMPLATEEX;
50 
51 typedef struct
52 {
53  DWORD helpID;
54  DWORD exStyle;
55  DWORD style;
56  short x;
57  short y;
58  short cx;
59  short cy;
60  DWORD id;
61 } DLGITEMTEMPLATEEX;
62 
63 #pragma pack(pop)
64 
65 typedef struct
66 {
67  DLGTEMPLATEEX* lpDialog;
68  Uint8 *data;
69  size_t size;
70  size_t used;
71 } WIN_DialogData;
72 
73 
74 static INT_PTR MessageBoxDialogProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
75 {
76  switch ( iMessage ) {
77  case WM_COMMAND:
78  /* Return the ID of the button that was pushed */
79  EndDialog(hDlg, LOWORD(wParam));
80  return TRUE;
81 
82  default:
83  break;
84  }
85  return FALSE;
86 }
87 
88 static SDL_bool ExpandDialogSpace(WIN_DialogData *dialog, size_t space)
89 {
90  size_t size = dialog->size;
91 
92  if (size == 0) {
93  size = space;
94  } else {
95  while ((dialog->used + space) > size) {
96  size *= 2;
97  }
98  }
99  if (size > dialog->size) {
100  void *data = SDL_realloc(dialog->data, size);
101  if (!data) {
102  SDL_OutOfMemory();
103  return SDL_FALSE;
104  }
105  dialog->data = data;
106  dialog->size = size;
107  dialog->lpDialog = (DLGTEMPLATEEX*)dialog->data;
108  }
109  return SDL_TRUE;
110 }
111 
112 static SDL_bool AlignDialogData(WIN_DialogData *dialog, size_t size)
113 {
114  size_t padding = (dialog->used % size);
115 
116  if (!ExpandDialogSpace(dialog, padding)) {
117  return SDL_FALSE;
118  }
119 
120  dialog->used += padding;
121 
122  return SDL_TRUE;
123 }
124 
125 static SDL_bool AddDialogData(WIN_DialogData *dialog, const void *data, size_t size)
126 {
127  if (!ExpandDialogSpace(dialog, size)) {
128  return SDL_FALSE;
129  }
130 
131  SDL_memcpy(dialog->data+dialog->used, data, size);
132  dialog->used += size;
133 
134  return SDL_TRUE;
135 }
136 
137 static SDL_bool AddDialogString(WIN_DialogData *dialog, const char *string)
138 {
139  WCHAR *wstring;
140  WCHAR *p;
141  size_t count;
142  SDL_bool status;
143 
144  if (!string) {
145  string = "";
146  }
147 
148  wstring = WIN_UTF8ToString(string);
149  if (!wstring) {
150  return SDL_FALSE;
151  }
152 
153  /* Find out how many characters we have, including null terminator */
154  count = 0;
155  for (p = wstring; *p; ++p) {
156  ++count;
157  }
158  ++count;
159 
160  status = AddDialogData(dialog, wstring, count*sizeof(WCHAR));
161  SDL_free(wstring);
162  return status;
163 }
164 
165 static int s_BaseUnitsX;
166 static int s_BaseUnitsY;
167 static void Vec2ToDLU(short *x, short *y)
168 {
169  SDL_assert(s_BaseUnitsX != 0); /* we init in WIN_ShowMessageBox(), which is the only public function... */
170 
171  *x = MulDiv(*x, 4, s_BaseUnitsX);
172  *y = MulDiv(*y, 8, s_BaseUnitsY);
173 }
174 
175 
176 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)
177 {
178  DLGITEMTEMPLATEEX item;
179  WORD marker = 0xFFFF;
180  WORD extraData = 0;
181 
182  SDL_zero(item);
183  item.style = style;
184  item.exStyle = exStyle;
185  item.x = x;
186  item.y = y;
187  item.cx = w;
188  item.cy = h;
189  item.id = id;
190 
191  Vec2ToDLU(&item.x, &item.y);
192  Vec2ToDLU(&item.cx, &item.cy);
193 
194  if (!AlignDialogData(dialog, sizeof(DWORD))) {
195  return SDL_FALSE;
196  }
197  if (!AddDialogData(dialog, &item, sizeof(item))) {
198  return SDL_FALSE;
199  }
200  if (!AddDialogData(dialog, &marker, sizeof(marker))) {
201  return SDL_FALSE;
202  }
203  if (!AddDialogData(dialog, &type, sizeof(type))) {
204  return SDL_FALSE;
205  }
206  if (!AddDialogString(dialog, caption)) {
207  return SDL_FALSE;
208  }
209  if (!AddDialogData(dialog, &extraData, sizeof(extraData))) {
210  return SDL_FALSE;
211  }
212  ++dialog->lpDialog->cDlgItems;
213 
214  return SDL_TRUE;
215 }
216 
217 static SDL_bool AddDialogStatic(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text)
218 {
219  DWORD style = WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOPREFIX | SS_EDITCONTROL;
220  return AddDialogControl(dialog, 0x0082, style, 0, x, y, w, h, -1, text);
221 }
222 
223 static SDL_bool AddDialogButton(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text, int id, SDL_bool isDefault)
224 {
225  DWORD style = WS_VISIBLE | WS_CHILD;
226  if (isDefault) {
227  style |= BS_DEFPUSHBUTTON;
228  } else {
229  style |= BS_PUSHBUTTON;
230  }
231  return AddDialogControl(dialog, 0x0080, style, 0, x, y, w, h, id, text);
232 }
233 
234 static void FreeDialogData(WIN_DialogData *dialog)
235 {
236  SDL_free(dialog->data);
237  SDL_free(dialog);
238 }
239 
240 static WIN_DialogData *CreateDialogData(int w, int h, const char *caption)
241 {
242  WIN_DialogData *dialog;
243  DLGTEMPLATEEX dialogTemplate;
244  WORD WordToPass;
245 
246  SDL_zero(dialogTemplate);
247  dialogTemplate.dlgVer = 1;
248  dialogTemplate.signature = 0xffff;
249  dialogTemplate.style = (WS_CAPTION | DS_CENTER | DS_SHELLFONT);
250  dialogTemplate.x = 0;
251  dialogTemplate.y = 0;
252  dialogTemplate.cx = w;
253  dialogTemplate.cy = h;
254  Vec2ToDLU(&dialogTemplate.cx, &dialogTemplate.cy);
255 
256  dialog = (WIN_DialogData *)SDL_calloc(1, sizeof(*dialog));
257  if (!dialog) {
258  return NULL;
259  }
260 
261  if (!AddDialogData(dialog, &dialogTemplate, sizeof(dialogTemplate))) {
262  FreeDialogData(dialog);
263  return NULL;
264  }
265 
266  /* No menu */
267  WordToPass = 0;
268  if (!AddDialogData(dialog, &WordToPass, 2)) {
269  FreeDialogData(dialog);
270  return NULL;
271  }
272 
273  /* No custom class */
274  if (!AddDialogData(dialog, &WordToPass, 2)) {
275  FreeDialogData(dialog);
276  return NULL;
277  }
278 
279  /* title */
280  if (!AddDialogString(dialog, caption)) {
281  FreeDialogData(dialog);
282  return NULL;
283  }
284 
285  /* Font stuff */
286  {
287  /*
288  * We want to use the system messagebox font.
289  */
290  BYTE ToPass;
291 
292  NONCLIENTMETRICSA NCM;
293  NCM.cbSize = sizeof(NCM);
294  SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
295 
296  /* Font size - convert to logical font size for dialog parameter. */
297  {
298  HDC ScreenDC = GetDC(0);
299  WordToPass = (WORD)(-72 * NCM.lfMessageFont.lfHeight / GetDeviceCaps(ScreenDC, LOGPIXELSY));
300  ReleaseDC(0, ScreenDC);
301  }
302 
303  if (!AddDialogData(dialog, &WordToPass, 2)) {
304  FreeDialogData(dialog);
305  return NULL;
306  }
307 
308  /* Font weight */
309  WordToPass = (WORD)NCM.lfMessageFont.lfWeight;
310  if (!AddDialogData(dialog, &WordToPass, 2)) {
311  FreeDialogData(dialog);
312  return NULL;
313  }
314 
315  /* italic? */
316  ToPass = NCM.lfMessageFont.lfItalic;
317  if (!AddDialogData(dialog, &ToPass, 1)) {
318  FreeDialogData(dialog);
319  return NULL;
320  }
321 
322  /* charset? */
323  ToPass = NCM.lfMessageFont.lfCharSet;
324  if (!AddDialogData(dialog, &ToPass, 1)) {
325  FreeDialogData(dialog);
326  return NULL;
327  }
328 
329  /* font typeface. */
330  if (!AddDialogString(dialog, NCM.lfMessageFont.lfFaceName)) {
331  FreeDialogData(dialog);
332  return NULL;
333  }
334  }
335 
336  return dialog;
337 }
338 
339 int
340 WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
341 {
342  WIN_DialogData *dialog;
343  int i, x, y, which;
344  const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
345  HFONT DialogFont;
346  SIZE Size;
347  RECT TextSize;
348  wchar_t* wmessage;
349  TEXTMETRIC TM;
350 
351 
352  const int ButtonWidth = 88;
353  const int ButtonHeight = 26;
354  const int TextMargin = 16;
355  const int ButtonMargin = 12;
356 
357 
358  /* Jan 25th, 2013 - dant@fleetsa.com
359  *
360  *
361  * I've tried to make this more reasonable, but I've run in to a lot
362  * of nonsense.
363  *
364  * The original issue is the code was written in pixels and not
365  * dialog units (DLUs). All DialogBox functions use DLUs, which
366  * vary based on the selected font (yay).
367  *
368  * According to MSDN, the most reliable way to convert is via
369  * MapDialogUnits, which requires an HWND, which we don't have
370  * at time of template creation.
371  *
372  * We do however have:
373  * The system font (DLU width 8 for me)
374  * The font we select for the dialog (DLU width 6 for me)
375  *
376  * Based on experimentation, *neither* of these return the value
377  * actually used. Stepping in to MapDialogUnits(), the conversion
378  * is fairly clear, and uses 7 for me.
379  *
380  * As a result, some of this is hacky to ensure the sizing is
381  * somewhat correct.
382  *
383  * Honestly, a long term solution is to use CreateWindow, not CreateDialog.
384  *
385 
386  *
387  * In order to get text dimensions we need to have a DC with the desired font.
388  * I'm assuming a dialog box in SDL is rare enough we can to the create.
389  */
390  HDC FontDC = CreateCompatibleDC(0);
391 
392  {
393  /* Create a duplicate of the font used in system message boxes. */
394  LOGFONT lf;
395  NONCLIENTMETRICS NCM;
396  NCM.cbSize = sizeof(NCM);
397  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
398  lf = NCM.lfMessageFont;
399  DialogFont = CreateFontIndirect(&lf);
400  }
401 
402  /* Select the font in to our DC */
403  SelectObject(FontDC, DialogFont);
404 
405  {
406  /* Get the metrics to try and figure our DLU conversion. */
407  GetTextMetrics(FontDC, &TM);
408  s_BaseUnitsX = TM.tmAveCharWidth + 1;
409  s_BaseUnitsY = TM.tmHeight;
410  }
411 
412  /* Measure the *pixel* size of the string. */
413  wmessage = WIN_UTF8ToString(messageboxdata->message);
414  SDL_zero(TextSize);
415  Size.cx = DrawText(FontDC, wmessage, -1, &TextSize, DT_CALCRECT);
416 
417  /* Add some padding for hangs, etc. */
418  TextSize.right += 2;
419  TextSize.bottom += 2;
420 
421  /* Done with the DC, and the string */
422  DeleteDC(FontDC);
423  SDL_free(wmessage);
424 
425  /* Increase the size of the dialog by some border spacing around the text. */
426  Size.cx = TextSize.right - TextSize.left;
427  Size.cy = TextSize.bottom - TextSize.top;
428  Size.cx += TextMargin * 2;
429  Size.cy += TextMargin * 2;
430 
431  /* Ensure the size is wide enough for all of the buttons. */
432  if (Size.cx < messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin)
433  Size.cx = messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin;
434 
435  /* Add vertical space for the buttons and border. */
436  Size.cy += ButtonHeight + TextMargin;
437 
438  dialog = CreateDialogData(Size.cx, Size.cy, messageboxdata->title);
439  if (!dialog) {
440  return -1;
441  }
442 
443  if (!AddDialogStatic(dialog, TextMargin, TextMargin, TextSize.right - TextSize.left, TextSize.bottom - TextSize.top, messageboxdata->message)) {
444  FreeDialogData(dialog);
445  return -1;
446  }
447 
448  /* Align the buttons to the right/bottom. */
449  x = Size.cx - ButtonWidth - ButtonMargin;
450  y = Size.cy - ButtonHeight - ButtonMargin;
451  for (i = 0; i < messageboxdata->numbuttons; ++i) {
452  SDL_bool isDefault;
453 
455  isDefault = SDL_TRUE;
456  } else {
457  isDefault = SDL_FALSE;
458  }
459  if (!AddDialogButton(dialog, x, y, ButtonWidth, ButtonHeight, buttons[i].text, i, isDefault)) {
460  FreeDialogData(dialog);
461  return -1;
462  }
463  x -= ButtonWidth + ButtonMargin;
464  }
465 
466  /* FIXME: If we have a parent window, get the Instance and HWND for them */
467  which = DialogBoxIndirect(NULL, (DLGTEMPLATE*)dialog->lpDialog, NULL, (DLGPROC)MessageBoxDialogProc);
468  *buttonid = buttons[which].buttonid;
469 
470  FreeDialogData(dialog);
471  return 0;
472 }
473 
474 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
475 
476 /* vi: set ts=4 sw=4 expandtab: */
const char * message
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:42
GLfloat GLfloat GLfloat GLfloat h
Definition: glew.h:7294
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
Definition: gl2ext.h:845
const GLchar * marker
Definition: gl2ext.h:1092
DECLSPEC void *SDLCALL SDL_calloc(size_t nmemb, size_t size)
const char * title
#define NULL
Definition: ftobjs.h:61
SDL_bool
Definition: SDL_stdinc.h:116
EGLSurface EGLint x
Definition: eglext.h:293
DECLSPEC void *SDLCALL SDL_realloc(void *mem, size_t size)
DECLSPEC void SDLCALL SDL_free(void *mem)
typedef UINT(WINAPI *PFNWGLGETCONTEXTGPUIDAMDPROC)(HGLRC hglrc)
if(!yyg->yy_init)
GLuint id
Definition: gl2ext.h:1142
typedef HDC(WINAPI *PFNWGLGETCURRENTREADDCARBPROC)(VOID)
Individual button data.
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl2ext.h:848
GLint GLsizei count
Definition: gl2ext.h:1011
GLfloat GLfloat p
Definition: glew.h:14938
#define FALSE
Definition: ftobjs.h:57
const SDL_MessageBoxButtonData * buttons
MessageBox structure containing title, text, window, etc.
#define SDL_assert(condition)
Definition: SDL_assert.h:159
EGLSurface EGLint EGLint y
Definition: eglext.h:293
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
DECLSPEC void *SDLCALL SDL_memcpy(void *dst, const void *src, size_t len)
Definition: SDL_string.c:293
GLenum GLsizei GLsizei GLsizei GLsizei GLbitfield flags
Definition: glew.h:2767
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:129
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex
GLint GLint GLint GLint GLint w
Definition: gl2ext.h:1215
#define SDL_zero(x)
Definition: SDL_stdinc.h:254
int i
Definition: pngrutil.c:1377
#define TRUE
Definition: ftobjs.h:53
GLsizei size
Definition: gl2ext.h:1467