summaryrefslogtreecommitdiff
path: root/alf/alfmessagedlg.cpp
diff options
context:
space:
mode:
authorJonas Kümmerlin <jonas@kuemmerlin.eu>2020-06-24 11:19:34 +0200
committerJonas Kümmerlin <jonas@kuemmerlin.eu>2020-06-24 11:19:34 +0200
commitcd9b72745abd06012777f130f1f19c4ae853489d (patch)
treec2bbf90ea7618d82faae560d42f268f62567168a /alf/alfmessagedlg.cpp
parent02c1f4e9165084589941ce205defaf5f3f1ea90f (diff)
messagedlg: initial implementation
Diffstat (limited to 'alf/alfmessagedlg.cpp')
-rw-r--r--alf/alfmessagedlg.cpp438
1 files changed, 438 insertions, 0 deletions
diff --git a/alf/alfmessagedlg.cpp b/alf/alfmessagedlg.cpp
new file mode 100644
index 0000000..554d55d
--- /dev/null
+++ b/alf/alfmessagedlg.cpp
@@ -0,0 +1,438 @@
+#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_AddNativeButton(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; // [] <space> 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;
+}