From 960f0cef228a64ea598c4531d0a7d159dfb7ed0d Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Fri, 26 Jun 2020 14:28:27 +0200 Subject: spin box: initial implementation --- alf/alfspinbox.cpp | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 alf/alfspinbox.cpp (limited to 'alf/alfspinbox.cpp') 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); +} -- cgit v1.2.3