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; }
int WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) { WIN_DialogData *dialog; int i, x, y; UINT_PTR which; const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; HFONT DialogFont; SIZE Size; RECT TextSize; wchar_t* wmessage; TEXTMETRIC TM; const int ButtonWidth = 88; const int ButtonHeight = 26; const int TextMargin = 16; const int ButtonMargin = 12; /* Jan 25th, 2013 - [email protected] * * * I've tried to make this more reasonable, but I've run in to a lot * of nonsense. * * The original issue is the code was written in pixels and not * dialog units (DLUs). All DialogBox functions use DLUs, which * vary based on the selected font (yay). * * According to MSDN, the most reliable way to convert is via * MapDialogUnits, which requires an HWND, which we don't have * at time of template creation. * * We do however have: * The system font (DLU width 8 for me) * The font we select for the dialog (DLU width 6 for me) * * Based on experimentation, *neither* of these return the value * actually used. Stepping in to MapDialogUnits(), the conversion * is fairly clear, and uses 7 for me. * * As a result, some of this is hacky to ensure the sizing is * somewhat correct. * * Honestly, a long term solution is to use CreateWindow, not CreateDialog. * * * In order to get text dimensions we need to have a DC with the desired font. * I'm assuming a dialog box in SDL is rare enough we can to the create. */ HDC FontDC = CreateCompatibleDC(0); { /* Create a duplicate of the font used in system message boxes. */ LOGFONT lf; NONCLIENTMETRICS NCM; NCM.cbSize = sizeof(NCM); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0); lf = NCM.lfMessageFont; DialogFont = CreateFontIndirect(&lf); } /* Select the font in to our DC */ SelectObject(FontDC, DialogFont); { /* Get the metrics to try and figure our DLU conversion. */ GetTextMetrics(FontDC, &TM); s_BaseUnitsX = TM.tmAveCharWidth + 1; s_BaseUnitsY = TM.tmHeight; } /* Measure the *pixel* size of the string. */ wmessage = WIN_UTF8ToString(messageboxdata->message); SDL_zero(TextSize); Size.cx = DrawText(FontDC, wmessage, -1, &TextSize, DT_CALCRECT); /* Add some padding for hangs, etc. */ TextSize.right += 2; TextSize.bottom += 2; /* Done with the DC, and the string */ DeleteDC(FontDC); SDL_free(wmessage); /* Increase the size of the dialog by some border spacing around the text. */ Size.cx = TextSize.right - TextSize.left; Size.cy = TextSize.bottom - TextSize.top; Size.cx += TextMargin * 2; Size.cy += TextMargin * 2; /* Ensure the size is wide enough for all of the buttons. */ if (Size.cx < messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin) Size.cx = messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin; /* Add vertical space for the buttons and border. */ Size.cy += ButtonHeight + TextMargin; dialog = CreateDialogData(Size.cx, Size.cy, messageboxdata->title); if (!dialog) { return -1; } if (!AddDialogStatic(dialog, TextMargin, TextMargin, TextSize.right - TextSize.left, TextSize.bottom - TextSize.top, messageboxdata->message)) { FreeDialogData(dialog); return -1; } /* Align the buttons to the right/bottom. */ x = Size.cx - (ButtonWidth + ButtonMargin) * messageboxdata->numbuttons; y = Size.cy - ButtonHeight - ButtonMargin; for (i = messageboxdata->numbuttons - 1; i >= 0; --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, ButtonWidth, ButtonHeight, buttons[i].text, i, isDefault)) { FreeDialogData(dialog); return -1; } x += ButtonWidth + ButtonMargin; } /* FIXME: If we have a parent window, get the Instance and HWND for them */ which = DialogBoxIndirect(NULL, (DLGTEMPLATE*)dialog->lpDialog, NULL, (DLGPROC)MessageBoxDialogProc); *buttonid = buttons[which].buttonid; FreeDialogData(dialog); return 0; }
static WIN_DialogData *CreateDialogData(int w, int h, const char *caption) { WIN_DialogData *dialog; DLGTEMPLATEEX dialogTemplate; WORD WordToPass; SDL_zero(dialogTemplate); dialogTemplate.dlgVer = 1; dialogTemplate.signature = 0xffff; dialogTemplate.style = (WS_CAPTION | DS_CENTER | DS_SHELLFONT); dialogTemplate.x = 0; dialogTemplate.y = 0; dialogTemplate.cx = w; dialogTemplate.cy = h; Vec2ToDLU(&dialogTemplate.cx, &dialogTemplate.cy); dialog = (WIN_DialogData *)SDL_calloc(1, sizeof(*dialog)); if (!dialog) { return NULL; } if (!AddDialogData(dialog, &dialogTemplate, sizeof(dialogTemplate))) { FreeDialogData(dialog); return NULL; } /* No menu */ WordToPass = 0; if (!AddDialogData(dialog, &WordToPass, 2)) { FreeDialogData(dialog); return NULL; } /* No custom class */ if (!AddDialogData(dialog, &WordToPass, 2)) { FreeDialogData(dialog); return NULL; } /* title */ if (!AddDialogString(dialog, caption)) { FreeDialogData(dialog); return NULL; } /* Font stuff */ { /* * We want to use the system messagebox font. */ BYTE ToPass; NONCLIENTMETRICSA NCM; NCM.cbSize = sizeof(NCM); SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0); /* Font size - convert to logical font size for dialog parameter. */ { HDC ScreenDC = GetDC(NULL); int LogicalPixelsY = GetDeviceCaps(ScreenDC, LOGPIXELSY); if (!LogicalPixelsY) /* This can happen if the application runs out of GDI handles */ LogicalPixelsY = 72; WordToPass = (WORD)(-72 * NCM.lfMessageFont.lfHeight / LogicalPixelsY); ReleaseDC(NULL, ScreenDC); } if (!AddDialogData(dialog, &WordToPass, 2)) { FreeDialogData(dialog); return NULL; } /* Font weight */ WordToPass = (WORD)NCM.lfMessageFont.lfWeight; if (!AddDialogData(dialog, &WordToPass, 2)) { FreeDialogData(dialog); return NULL; } /* italic? */ ToPass = NCM.lfMessageFont.lfItalic; if (!AddDialogData(dialog, &ToPass, 1)) { FreeDialogData(dialog); return NULL; } /* charset? */ ToPass = NCM.lfMessageFont.lfCharSet; if (!AddDialogData(dialog, &ToPass, 1)) { FreeDialogData(dialog); return NULL; } /* font typeface. */ if (!AddDialogString(dialog, NCM.lfMessageFont.lfFaceName)) { FreeDialogData(dialog); return NULL; } } return dialog; }