summaryrefslogtreecommitdiff
path: root/alf/alfspinbox.cpp
diff options
context:
space:
mode:
authorJonas Kümmerlin <jonas@kuemmerlin.eu>2020-06-26 14:28:27 +0200
committerJonas Kümmerlin <jonas@kuemmerlin.eu>2020-06-26 14:29:32 +0200
commit960f0cef228a64ea598c4531d0a7d159dfb7ed0d (patch)
tree9baf7baa580723487fcb5da95b555580830d1942 /alf/alfspinbox.cpp
parentcd9b72745abd06012777f130f1f19c4ae853489d (diff)
spin box: initial implementation
Diffstat (limited to 'alf/alfspinbox.cpp')
-rw-r--r--alf/alfspinbox.cpp306
1 files changed, 306 insertions, 0 deletions
diff --git a/alf/alfspinbox.cpp b/alf/alfspinbox.cpp
new file mode 100644
index 0000000..bd3dd70
--- /dev/null
+++ b/alf/alfspinbox.cpp
@@ -0,0 +1,306 @@
+#include "alfpriv.h"
+
+typedef struct {
+ HWND hwndEdit;
+ HWND hwndUpdown;
+ int dpi;
+} ALFSpinBoxPriv;
+
+static void
+ALF_SpinBox_Initialize(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ priv->dpi = 96;
+
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ priv->hwndEdit = CreateWindowEx(ALF_Compat_Is40() ? WS_EX_CLIENTEDGE : 0,
+ TEXT("EDIT"),
+ TEXT("0"),
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP | (ALF_Compat_Is40() ? 0 : WS_BORDER),
+ 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top,
+ hwnd,
+ NULL,
+ ALF_HINSTANCE,
+ NULL);
+ priv->hwndUpdown = CreateWindowEx(0,
+ TEXT("msctls_updown32"),
+ NULL,
+ WS_CHILD | WS_VISIBLE | (ALF_Compat_Is40() ? UDS_ALIGNRIGHT : WS_BORDER) | UDS_AUTOBUDDY | UDS_SETBUDDYINT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,
+ 0, 0,
+ 0, 0,
+ hwnd,
+ NULL,
+ ALF_HINSTANCE,
+ NULL);
+}
+
+static void
+ALF_SpinBox_Destroy(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ (void)priv;
+ (void)hwnd;
+
+ // nothing to do here (yet)
+ // child windows are destroyed automatically
+}
+
+static void
+ALF_SpinBox_Resize(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ (void)hwnd;
+
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ int overlap = GetWindowLong(priv->hwndEdit, GWL_EXSTYLE) & WS_EX_CLIENTEDGE
+ ? ALF_Compat_GetSystemMetricsForDpi(SM_CXBORDER, (UINT)priv->dpi) * 2
+ : ALF_Compat_GetSystemMetricsForDpi(SM_CXBORDER, (UINT)priv->dpi);
+ int updownwidth = ALF_Compat_GetSystemMetricsForDpi(SM_CXVSCROLL, (UINT)priv->dpi) - ALF_Compat_GetSystemMetricsForDpi(SM_CXBORDER, (UINT)priv->dpi);
+
+ if (updownwidth > rcClient.bottom - rcClient.top)
+ updownwidth = rcClient.bottom - rcClient.top;
+
+
+ RECT rcEdit = {
+ 0, 0, rcClient.right - rcClient.left - updownwidth, rcClient.bottom - rcClient.top
+ };
+ RECT rcUpdown = {
+ rcEdit.right - overlap, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top
+ };
+
+ HDWP hdwp = BeginDeferWindowPos(2);
+ hdwp = DeferWindowPos(hdwp, priv->hwndEdit, NULL, rcEdit.left, rcEdit.top, rcEdit.right - rcEdit.left, rcEdit.bottom - rcEdit.top, SWP_NOACTIVATE|SWP_NOZORDER);
+ hdwp = DeferWindowPos(hdwp, priv->hwndUpdown, NULL, rcUpdown.left, rcUpdown.top, rcUpdown.right - rcUpdown.left, rcUpdown.bottom - rcUpdown.top, SWP_NOACTIVATE|SWP_NOZORDER);
+ EndDeferWindowPos(hdwp);
+}
+
+static void
+ALF_SpinBox_SetFont(ALFSpinBoxPriv *priv, HFONT font, LPARAM lparam)
+{
+ SendMessage(priv->hwndEdit, WM_SETFONT, (WPARAM)font, lparam);
+}
+
+static LRESULT
+ALF_SpinBox_GetFont(ALFSpinBoxPriv *priv, WPARAM wp, LPARAM lp)
+{
+ return SendMessage(priv->hwndEdit, WM_GETFONT, wp, lp);
+}
+
+static void
+ALF_SpinBox_HandleDpiChange(ALFSpinBoxPriv *priv, HWND hwnd, int newdpi)
+{
+ if (priv->dpi == newdpi)
+ return;
+
+ priv->dpi = newdpi;
+ ALF_SpinBox_Resize(priv, hwnd);
+}
+
+static LRESULT
+ALF_SpinBox_HandleGetRange(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ (void)hwnd;
+ return SendMessage(priv->hwndUpdown, UDM_GETRANGE, 0, 0);
+}
+
+static LRESULT
+ALF_SpinBox_HandleSetRange(ALFSpinBoxPriv *priv, HWND hwnd, LPARAM lparam)
+{
+ (void)hwnd;
+
+ SendMessage(priv->hwndUpdown, UDM_SETRANGE, 0, lparam);
+ return 1;
+}
+
+static LRESULT
+ALF_SpinBox_HandleGetPos(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ (void)hwnd;
+
+ return SendMessage(priv->hwndUpdown, UDM_GETPOS, 0, 0);
+}
+
+static LRESULT
+ALF_SpinBox_HandleSetPos(ALFSpinBoxPriv *priv, HWND hwnd, LPARAM lparam)
+{
+ (void)hwnd;
+
+ SendMessage(priv->hwndUpdown, UDM_SETPOS, 0, lparam);
+ return 1;
+}
+
+static LRESULT
+ALF_SpinBox_HandleCommand(ALFSpinBoxPriv *priv, HWND hwnd, WORD code, WORD id, HWND control)
+{
+ if (control == priv->hwndEdit) {
+ return SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), code), (LPARAM)hwnd);
+ } else {
+ return SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(id, code), (LPARAM)control);
+ }
+}
+
+static LRESULT
+ALF_SpinBox_HandleNotify(ALFSpinBoxPriv *priv, HWND hwnd, WPARAM wparam, const NMHDR *pnmh)
+{
+ if (pnmh->hwndFrom == priv->hwndUpdown && pnmh->code == UDN_DELTAPOS) {
+ NMUPDOWN nmud = *(const NMUPDOWN *)pnmh;
+ nmud.hdr.hwndFrom = hwnd;
+ nmud.hdr.idFrom = (UINT_PTR)GetWindowLongPtr(hwnd, GWLP_ID);
+
+ return SendMessage(GetParent(hwnd), WM_NOTIFY, nmud.hdr.idFrom, (LPARAM)&nmud);
+ } else {
+ return SendMessage(GetParent(hwnd), WM_NOTIFY, wparam, (LPARAM)pnmh);
+ }
+}
+
+static LRESULT
+ALF_SpinBox_HandleGetEditControl(ALFSpinBoxPriv *priv)
+{
+ return (LRESULT)priv->hwndEdit;
+}
+
+static LRESULT
+ALF_SpinBox_HandleGetUpDownControl(ALFSpinBoxPriv *priv)
+{
+ return (LRESULT)priv->hwndUpdown;
+}
+
+static LRESULT
+ALF_SpinBox_HandlePaint(ALFSpinBoxPriv *priv, HWND hwnd)
+{
+ (void)priv;
+
+ PAINTSTRUCT ps;
+ HDC dc = BeginPaint(hwnd, &ps);
+ FillRect(dc, &ps.rcPaint, GetSysColorBrush(COLOR_BTNFACE));
+ EndPaint(hwnd, &ps);
+ return 0;
+}
+
+static LRESULT WINAPI
+ALF_SpinBox_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+ ALFSpinBoxPriv *priv = (ALFSpinBoxPriv *)GetWindowLongPtr(hwnd, 0);
+
+ if (!priv && msg == WM_NCCREATE) {
+ priv = ALF_New(ALFSpinBoxPriv, 1);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR)priv);
+ }
+
+ if (!priv)
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+
+ switch (msg) {
+ case WM_CREATE:
+ ALF_SpinBox_Initialize(priv, hwnd);
+ break;
+ case WM_DESTROY:
+ ALF_SpinBox_Destroy(priv, hwnd);
+ SetWindowLongPtr(hwnd, 0, 0);
+ ALF_Free(priv);
+ priv = NULL;
+ break;
+ case WM_SETFONT:
+ ALF_SpinBox_SetFont(priv, (HFONT)wparam, lparam);
+ break;
+ case WM_GETFONT:
+ return ALF_SpinBox_GetFont(priv, wparam, lparam);
+ case WM_SIZE:
+ ALF_SpinBox_Resize(priv, hwnd);
+ break;
+ case ALF_WM_DPICHANGE:
+ ALF_SpinBox_HandleDpiChange(priv, hwnd, (int)lparam);
+ return 0;
+ case ALF_WM_SPINBOX_GETRANGE:
+ return ALF_SpinBox_HandleGetRange(priv, hwnd);
+ case ALF_WM_SPINBOX_SETRANGE:
+ return ALF_SpinBox_HandleSetRange(priv, hwnd, lparam);
+ case ALF_WM_SPINBOX_GETPOS:
+ return ALF_SpinBox_HandleGetPos(priv, hwnd);
+ case ALF_WM_SPINBOX_SETPOS:
+ return ALF_SpinBox_HandleSetPos(priv, hwnd, lparam);
+ case ALF_WM_SPINBOX_GETEDIT:
+ return ALF_SpinBox_HandleGetEditControl(priv);
+ case ALF_WM_SPINBOX_GETUDCTL:
+ return ALF_SpinBox_HandleGetUpDownControl(priv);
+ case WM_GETTEXT:
+ return (LRESULT)GetWindowText(priv->hwndEdit, (TCHAR *)lparam, (int)wparam);
+ case WM_GETTEXTLENGTH:
+ return (LRESULT)GetWindowTextLength(priv->hwndEdit);
+ case WM_SETTEXT:
+ return (LRESULT)SetWindowText(priv->hwndEdit, (const TCHAR *)lparam);
+ case WM_COMMAND:
+ return ALF_SpinBox_HandleCommand(priv, hwnd, HIWORD(wparam), LOWORD(wparam), (HWND)lparam);
+ case WM_NOTIFY:
+ return ALF_SpinBox_HandleNotify(priv, hwnd, wparam, (const NMHDR *)lparam);
+ case WM_PAINT:
+ return ALF_SpinBox_HandlePaint(priv, hwnd);
+ case WM_ERASEBKGND:
+ return 1;
+ }
+
+ if (ALF_ShouldMessageBubble(hwnd, msg, wparam, lparam))
+ return SendMessage(GetParent(hwnd), msg, wparam, lparam);
+
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+HWND
+ALF_AddNumericSpinBox(HWND parent, WORD id, int x, int y, short val, short min, short max)
+{
+ HWND hwnd = ALF_CreateControlWindow(WS_EX_CONTROLPARENT,
+ TEXT(""),
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
+ 0, 0, 0, 0,
+ parent,
+ (HMENU)(ULONG_PTR)id,
+ ALF_SpinBox_WndProc,
+ NULL);
+
+ ALF_AddControl(parent, x, y, hwnd, 0, 0, ALF_LAYOUT_SIZE_EDIT | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE);
+
+ ALF_SpinBox_SetRange(hwnd, min, max);
+ ALF_SpinBox_SetPos(hwnd, val);
+
+ return hwnd;
+}
+
+BOOL
+ALF_SpinBox_Range(HWND spinbox, short *pmin, short *pmax)
+{
+ LRESULT r = SendMessage(spinbox, ALF_WM_SPINBOX_GETRANGE, 0, 0);
+ *pmin = GET_X_LPARAM(r);
+ *pmax = GET_Y_LPARAM(r);
+ return TRUE;
+}
+
+BOOL
+ALF_SpinBox_SetRange(HWND spinbox, short min, short max)
+{
+ return (BOOL)SendMessage(spinbox, ALF_WM_SPINBOX_SETRANGE, 0, MAKELPARAM((WORD)max, (WORD)min));
+}
+
+short
+ALF_SpinBox_Pos(HWND spinbox)
+{
+ return (short)SendMessage(spinbox, ALF_WM_SPINBOX_GETPOS, 0, 0);
+}
+
+BOOL
+ALF_SpinBox_SetPos(HWND spinbox, short pos)
+{
+ return (BOOL)SendMessage(spinbox, ALF_WM_SPINBOX_SETPOS, 0, (LPARAM)pos);
+}
+
+HWND
+ALF_SpinBox_EditControl(HWND spinbox)
+{
+ return (HWND)SendMessage(spinbox, ALF_WM_SPINBOX_GETEDIT, 0, 0);
+}
+
+HWND
+ALF_SpinBox_UpDownControl(HWND spinbox)
+{
+ return (HWND)SendMessage(spinbox, ALF_WM_SPINBOX_GETUDCTL, 0, 0);
+}