#include "alfpriv.h" #define ALF_WM_MESSAGEDLG_SETCAPTION (ALF_WM_USER + 1) #define ALF_WM_MESSAGEDLG_SETTEXT (ALF_WM_USER + 2) #define ALF_WM_MESSAGEDLG_ADDBUTTON (ALF_WM_USER + 3) #define ALF_WM_MESSAGEDLG_SETICON (ALF_WM_USER + 4) #define ALF_WM_MESSAGEDLG_BEEP (ALF_WM_USER + 5) typedef struct { HINSTANCE hIconInstance; PCTSTR pszIconName; HWND hwndIconView; HWND hwndIconWrapper; HWND hwndText; HWND hwndTextWrapper; int nButtons; } ALFMessageDlgPriv; static BOOL ALF_MessageDlg_Initialize(void *closure, HWND hwnd) { ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; priv->hwndIconWrapper = ALF_AddPanel(hwnd, (WORD)-1, 0, 0); priv->hwndTextWrapper = ALF_AddPanel(hwnd, (WORD)-1, 1, 0); priv->hwndIconView = ALF_AddIconView(priv->hwndIconWrapper, (WORD)-1, 1, 1, NULL); priv->hwndText = ALF_AddLabel(priv->hwndTextWrapper, (WORD)-1, 0, 1, TEXT("")); ALF_SetBackgroundColor(priv->hwndIconWrapper, ALF_COLOR_SYS(COLOR_WINDOW)); ALF_SetBackgroundColor(priv->hwndTextWrapper, ALF_COLOR_SYS(COLOR_WINDOW)); ALF_SetTextColor(priv->hwndText, ALF_COLOR_SYS(COLOR_WINDOWTEXT)); ALF_Label_SetStyle(priv->hwndText, ALF_LABEL_ALIGN_LEFT | ALF_LABEL_ALIGN_VCENTER); ALF_Layout_SetColumnMinSize(priv->hwndIconWrapper, 0, 1650); ALF_Layout_SetColumnMinSize(priv->hwndIconWrapper, 2, 825); ALF_Layout_SetRowMinSize(priv->hwndIconWrapper, 0, 1650); ALF_Layout_SetRowMinSize(priv->hwndIconWrapper, 2, 1650); ALF_Layout_SetRowExpandNumerator(priv->hwndIconWrapper, 2, 1); ALF_Layout_SetColumnExpandNumerator(priv->hwndIconWrapper, 1, 1); ALF_Layout_SetColumnMinSize(priv->hwndTextWrapper, 1, 1650); ALF_Layout_SetRowMinSize(priv->hwndTextWrapper, 0, 1650); ALF_Layout_SetRowMinSize(priv->hwndTextWrapper, 2, 1650); ALF_Layout_SetColumnExpandNumerator(priv->hwndTextWrapper, 1, 1); ALF_Layout_SetRowExpandNumerator(priv->hwndTextWrapper, 2, 1); ALF_Layout_SetRowFlags(priv->hwndTextWrapper, 1, ALF_LAYOUT_SIZE_PX); ALF_Layout_SetRowMinSize(hwnd, 1, 825); ALF_Layout_SetRowMinSize(hwnd, 3, 825); ALF_Layout_SetRowExpandNumerator(hwnd, 0, 1); ALF_Layout_SetColumnExpandNumerator(hwnd, 1, 1); return FALSE; } static void ALF_MessageDlg_HandleAddButton(ALFMessageDlgPriv *priv, HWND hwnd, WORD id, const TCHAR *text) { (void)hwnd; HWND hwndBtn = ALF_AddButton(hwnd, id, 2 * priv->nButtons + 2, 2, text); ALF_Layout_SetColumnMinSize(hwnd, 2 * priv->nButtons + 3, 525); ALF_Layout_SetControlSpan(hwnd, priv->hwndTextWrapper, priv->nButtons * 2 + 3, 1); if (priv->nButtons == 0) ALF_SetFocus(hwndBtn); priv->nButtons += 1; } static void ALF_MessageDlg_Destroy(void *closure, HWND hwnd) { (void)hwnd; ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; HICON hicon = ALF_IconView_Icon(priv->hwndIconView); DestroyIcon(hicon); } static void ALF_MessageDlg_PostDestroy(void *closure) { ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; ALF_StrOrIntresourceFree(priv->pszIconName); ALF_Free(priv); } static void ALF_MessageDlg_UpdateIcon(ALFMessageDlgPriv *priv, HWND hwnd) { UINT dpi = (UINT)ALF_GetDpi(hwnd); HICON n = ALF_LoadIcon(priv->hIconInstance, priv->pszIconName, ALF_Compat_GetSystemMetricsForDpi(SM_CXICON, dpi), ALF_Compat_GetSystemMetricsForDpi(SM_CYICON, dpi)); HICON o = ALF_IconView_SetIcon(priv->hwndIconView, n); DestroyIcon(o); SIZE s = { 0, 0 }; SendMessage(priv->hwndIconView, ALF_WM_QUERYSIZE, 0, (LPARAM)&s); ALF_Layout_SetRowMinSize(priv->hwndTextWrapper, 1, s.cy); } static void ALF_MessageDlg_HandleFontsDpiChange(void *closure, HWND hwnd) { ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; ALF_MessageDlg_UpdateIcon(priv, hwnd); ALF_Toplevel_SetDefaultFont(hwnd); } static LRESULT ALF_MessageDlg_HandleCommand(void *closure, HWND hwnd, WORD code, WORD sourceid, HWND control) { (void)closure; if (control && code == BN_CLICKED) { ALF_Toplevel_SetModalResult(hwnd, sourceid); return 1; } return 0; } static void ALF_MessageDlg_HandleSetIcon(ALFMessageDlgPriv *priv, HWND hwnd, HINSTANCE inst, const TCHAR *iconName) { priv->hIconInstance = inst; ALF_StrOrIntresourceFree(priv->pszIconName); priv->pszIconName = ALF_StrOrIntresourceDup(iconName); ALF_MessageDlg_UpdateIcon(priv, hwnd); } static void ALF_MessageDlg_HandleSetCaption(ALFMessageDlgPriv *priv, HWND hwnd, const TCHAR *caption) { (void)priv; ALF_SetText(hwnd, caption); } static void ALF_MessageDlg_HandleSetText(ALFMessageDlgPriv *priv, HWND hwnd, const TCHAR *text) { (void)hwnd; ALF_SetText(priv->hwndText, text); } static void ALF_MessageDlg_HandleBeep(ALFMessageDlgPriv *priv, HWND hwnd) { (void)hwnd; if (priv->hIconInstance == NULL && priv->pszIconName == IDI_EXCLAMATION) MessageBeep(MB_ICONEXCLAMATION); else if (priv->hIconInstance == NULL && priv->pszIconName == IDI_HAND) MessageBeep(MB_ICONHAND); else if (priv->hIconInstance == NULL && priv->pszIconName == IDI_QUESTION) MessageBeep(MB_ICONQUESTION); else MessageBeep(MB_ICONASTERISK); } static LRESULT ALF_MessageDlg_HandleWindowPosChanging(ALFMessageDlgPriv *priv, HWND hwnd, WPARAM wparam, WINDOWPOS *wp) { (void)priv; // XXX: for WS_THICKFRAME windows this is done automatically, but we need to do it ourselves // investigate whether it should be done in ALFToplevel if (!(wp->flags & SWP_NOSIZE)) { MINMAXINFO tmp = { { 0, 0 }, { wp->cx, wp->cy}, { 0, 0 }, { wp->cx, wp->cy }, { wp->cx, wp->cy } }; SendMessage(hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&tmp); if (tmp.ptMinTrackSize.x > wp->cx) wp->cx = tmp.ptMinTrackSize.x; if (tmp.ptMinTrackSize.y > wp->cy) wp->cy = tmp.ptMinTrackSize.y; } return ALF_Toplevel_DefWindowProc(hwnd, WM_WINDOWPOSCHANGING, wparam, (LPARAM)wp); } static int ALF_MessageDlg_AsTextLength(ALFMessageDlgPriv *priv, HWND hwnd) { int l = 0; int titlelength = GetWindowTextLength(hwnd); l += titlelength; l += 2; //\r\n l += titlelength; // underline l += 4; //\r\n\r\n l += GetWindowTextLength(priv->hwndText); l += 4; //\r\n\r\n for (int i = 0; i < priv->nButtons; ++i) { l += GetWindowTextLength(ALF_Layout_ControlAtPosition(hwnd, i * 2 + 2, 2)); l += 3; // [] or \r } l += 1; // \n return l; } static void ALF_MessageDlg_AsText(ALFMessageDlgPriv *priv, HWND hwnd, TCHAR *buf) { int titlelength = GetWindowText(hwnd, buf, 0x7fffffff); buf += titlelength; *buf++ = '\r'; *buf++ = '\n'; for (int i = 0; i < titlelength; ++i) *buf++ = '='; *buf++ = '\r'; *buf++ = '\n'; *buf++ = '\r'; *buf++ = '\n'; buf += GetWindowText(priv->hwndText, buf, 0x7fffffff); *buf++ = '\r'; *buf++ = '\n'; *buf++ = '\r'; *buf++ = '\n'; for (int i = 0; i < priv->nButtons; ++i) { if (i != 0) *buf++ = ' '; *buf++ = '['; buf += GetWindowText(ALF_Layout_ControlAtPosition(hwnd, i * 2 + 2, 2), buf, 0x7fffffff); *buf++ = ']'; } *buf++ = '\r'; *buf++ = '\n'; *buf = 0; } static BOOL ALF_MessageDlg_PreTranslateMessage(void *closure, HWND hwnd, MSG *msg) { ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; if (msg->message == WM_KEYDOWN && (msg->wParam == VK_ESCAPE || msg->wParam == VK_CANCEL)) { ALF_Toplevel_SetModalResult(hwnd, IDCANCEL); return TRUE; } else if (msg->message == WM_KEYDOWN && msg->wParam == 'C' && GetKeyState(VK_CONTROL) & 0x8000) { if (OpenClipboard(hwnd)) { EmptyClipboard(); int len = ALF_MessageDlg_AsTextLength(priv, hwnd); HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, ((SIZE_T)len+1)*sizeof(TCHAR)); TCHAR *buf = (TCHAR* )GlobalLock(hMem); ALF_MessageDlg_AsText(priv, hwnd, buf); GlobalUnlock(hMem); #ifdef UNICODE SetClipboardData(CF_UNICODETEXT, hMem); #else SetClipboardData(CF_TEXT, hMem); #endif CloseClipboard(); return TRUE; } else { return FALSE; } } else { return FALSE; } } static LRESULT ALF_MessageDlg_HandleMessage(void *closure, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { ALFMessageDlgPriv *priv = (ALFMessageDlgPriv *)closure; switch (msg) { case ALF_WM_MESSAGEDLG_SETCAPTION: ALF_MessageDlg_HandleSetCaption(priv, hwnd, (const TCHAR *)lparam); return 1; case ALF_WM_MESSAGEDLG_SETTEXT: ALF_MessageDlg_HandleSetText(priv, hwnd, (const TCHAR *)lparam); return 1; case ALF_WM_MESSAGEDLG_ADDBUTTON: ALF_MessageDlg_HandleAddButton(priv, hwnd, (WORD)wparam, (const TCHAR *)lparam); return 1; case ALF_WM_MESSAGEDLG_SETICON: ALF_MessageDlg_HandleSetIcon(priv, hwnd, (HINSTANCE)wparam, (const TCHAR *)lparam); return 1; case ALF_WM_MESSAGEDLG_BEEP: ALF_MessageDlg_HandleBeep(priv, hwnd); return 1; case WM_WINDOWPOSCHANGING: return ALF_MessageDlg_HandleWindowPosChanging(priv, hwnd, wparam, (WINDOWPOS *)lparam); } return ALF_Toplevel_DefWindowProc(hwnd, msg, wparam, lparam); } static void ALF_MessageDlg_HandleClose(void *closure, HWND hwnd) { (void)closure; ALF_Toplevel_SetModalResult(hwnd, IDCANCEL); } static ALFToplevelVTable _alf_messageDlgVtbl = { ALF_MessageDlg_Initialize, /* initialize */ ALF_MessageDlg_Destroy, /* destroy */ ALF_MessageDlg_HandleClose, /* close */ ALF_MessageDlg_PostDestroy, /* postdestroy */ ALF_MessageDlg_HandleMessage, /* message */ ALF_MessageDlg_HandleCommand, /* command */ NULL, /* notify */ ALF_MessageDlg_PreTranslateMessage, /* pretranslatemessage */ NULL, /* paint */ NULL, /* windowposchanged */ ALF_MessageDlg_HandleFontsDpiChange /* updatefontsdpi */ }; HWND ALF_MessageDlg_Create(HWND owner) { ALFMessageDlgPriv *priv = ALF_New(ALFMessageDlgPriv, 1); return ALF_CreateToplevelWindow(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE, WS_POPUPWINDOW | WS_DLGFRAME | WS_CAPTION | DS_MODALFRAME, owner, NULL, &_alf_messageDlgVtbl, priv); } void ALF_MessageDlg_SetCaption(HWND msg, const TCHAR *caption) { SendMessage(msg, ALF_WM_MESSAGEDLG_SETCAPTION, 0, (LPARAM)caption); } void ALF_MessageDlg_SetText(HWND msg, const TCHAR *text) { SendMessage(msg, ALF_WM_MESSAGEDLG_SETTEXT, 0, (LPARAM)text); } void ALF_MessageDlg_SetIcon(HWND msg, HINSTANCE hinst, const TCHAR *name) { SendMessage(msg, ALF_WM_MESSAGEDLG_SETICON, (WPARAM)hinst, (LPARAM)name); } void ALF_MessageDlg_AddButton(HWND msg, WORD id, const TCHAR *text) { SendMessage(msg, ALF_WM_MESSAGEDLG_ADDBUTTON, (WPARAM)id, (LPARAM)text); } WORD ALF_MessageDlg_Run(HWND msg) { ALF_Toplevel_CenterOnOwnerMonitor(msg); SendMessage(msg, ALF_WM_MESSAGEDLG_BEEP, 0, 0); return (WORD)ALF_Toplevel_ShowModal(msg); } // message box shortcuts void ALF_MessageDlg_Error(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText) { HWND m = ALF_MessageDlg_Create(owner); ALF_MessageDlg_SetCaption(m, caption); ALF_MessageDlg_SetText(m, text); ALF_MessageDlg_SetIcon(m, NULL, IDI_HAND); ALF_MessageDlg_AddButton(m, IDOK, okBtnText ? okBtnText : TEXT("OK")); ALF_MessageDlg_Run(m); DestroyWindow(m); } void ALF_MessageDlg_Warning(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText) { HWND m = ALF_MessageDlg_Create(owner); ALF_MessageDlg_SetCaption(m, caption); ALF_MessageDlg_SetText(m, text); ALF_MessageDlg_SetIcon(m, NULL, IDI_EXCLAMATION); ALF_MessageDlg_AddButton(m, IDOK, okBtnText ? okBtnText : TEXT("OK")); ALF_MessageDlg_Run(m); DestroyWindow(m); } void ALF_MessageDlg_Information(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText) { HWND m = ALF_MessageDlg_Create(owner); ALF_MessageDlg_SetCaption(m, caption); ALF_MessageDlg_SetText(m, text); ALF_MessageDlg_SetIcon(m, NULL, IDI_ASTERISK); ALF_MessageDlg_AddButton(m, IDOK, okBtnText ? okBtnText : TEXT("OK")); ALF_MessageDlg_Run(m); DestroyWindow(m); } WORD // IDOK or IDCANCEL ALF_MessageDlg_Confirm(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText, const TCHAR *cancelBtnText) { HWND m = ALF_MessageDlg_Create(owner); ALF_MessageDlg_SetCaption(m, caption); ALF_MessageDlg_SetText(m, text); ALF_MessageDlg_SetIcon(m, NULL, IDI_QUESTION); ALF_MessageDlg_AddButton(m, IDOK, okBtnText ? okBtnText : TEXT("OK")); ALF_MessageDlg_AddButton(m, IDCANCEL, cancelBtnText ? cancelBtnText : TEXT("Cancel")); WORD r = ALF_MessageDlg_Run(m); DestroyWindow(m); return r; } // like ALF_MessageDlg_Confirm, but shows an exclamation icon and preselects the cancel button WORD ALF_MessageDlg_ConfirmDanger(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText, const TCHAR *cancelBtnText) { HWND m = ALF_MessageDlg_Create(owner); ALF_MessageDlg_SetCaption(m, caption); ALF_MessageDlg_SetText(m, text); ALF_MessageDlg_SetIcon(m, NULL, IDI_EXCLAMATION); ALF_MessageDlg_AddButton(m, IDOK, okBtnText ? okBtnText : TEXT("OK")); ALF_MessageDlg_AddButton(m, IDCANCEL, cancelBtnText ? cancelBtnText : TEXT("Cancel")); ALF_Toplevel_SetDefaultButton(m, IDCANCEL); ALF_SetFocus(ALF_ControlHwndById(m, IDCANCEL)); WORD r = ALF_MessageDlg_Run(m); DestroyWindow(m); return r; }