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 --- DEFECTS.txt | 4 + Makefile.mingw | 7 +- Makefile.mingw-amd64 | 7 +- Makefile.vc6 | 5 +- Makefile.vc6-ansi | 5 +- alf/alf.cpp | 2 +- alf/alf.h | 28 +++++ alf/alfcompat.cpp | 11 ++ alf/alfcompat.h | 1 + alf/alfpanel.cpp | 16 +++ alf/alfspinbox.cpp | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++ widgetfactory.cpp | 66 ++++++++++- 12 files changed, 449 insertions(+), 9 deletions(-) create mode 100644 DEFECTS.txt create mode 100644 alf/alfspinbox.cpp diff --git a/DEFECTS.txt b/DEFECTS.txt new file mode 100644 index 0000000..46d7663 --- /dev/null +++ b/DEFECTS.txt @@ -0,0 +1,4 @@ +spin box: +- on vista+: drawing bug when resized in reaction to clicking the up button +- doesn’t look good on Win32s/NT3.51 + diff --git a/Makefile.mingw b/Makefile.mingw index def3fa3..e61640a 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -8,7 +8,7 @@ LDFLAGS = -luser32 -lcomctl32 -lshell32 -lversion -static all: out/widgetfactory.exe out/alf/alf.c out/widgetfactory-c.exe -out/widgetfactory.exe: out/widgetfactory.o out/alfbutton.o out/alfcombobox.o out/alfcompat.o out/alfcontrol.o out/alf.o out/alfdpiaware.o out/alfedit.o out/alfgroupbox.o out/alficon.o out/alflabel.o out/alflayout.o out/alfmessagedlg.o out/alfnativebtn.o out/alfnotebook.o out/alfpanel.o out/alftoplevel.o +out/widgetfactory.exe: out/widgetfactory.o out/alfbutton.o out/alfcombobox.o out/alfcompat.o out/alfcontrol.o out/alf.o out/alfdpiaware.o out/alfedit.o out/alfgroupbox.o out/alficon.o out/alflabel.o out/alflayout.o out/alfmessagedlg.o out/alfnativebtn.o out/alfnotebook.o out/alfpanel.o out/alfspinbox.o out/alftoplevel.o $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) out/alfbutton.o: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h @@ -56,13 +56,16 @@ out/alfnotebook.o: alf/alfnotebook.cpp alf/alfcompat.h alf/alf.h alf/alflayout. out/alfpanel.o: alf/alfpanel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CXXFLAGS) -c -o $@ $< +out/alfspinbox.o: alf/alfspinbox.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CXXFLAGS) -c -o $@ $< + out/alftoplevel.o: alf/alftoplevel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CXXFLAGS) -c -o $@ $< out/widgetfactory.o: widgetfactory.cpp alf/alf.h $(CXX) $(CXXFLAGS) -c -o $@ $< -out/alf/alf.c: alf/alflist.h alf/alflayout.h alf/alfcompat.h alf/alfpriv.h alf/alfbutton.cpp alf/alfcombobox.cpp alf/alfcompat.cpp alf/alfcontrol.cpp alf/alf.cpp alf/alfdpiaware.cpp alf/alfedit.cpp alf/alfgroupbox.cpp alf/alficon.cpp alf/alflabel.cpp alf/alflayout.cpp alf/alfmessagedlg.cpp alf/alfnativebtn.cpp alf/alfnotebook.cpp alf/alfpanel.cpp alf/alftoplevel.cpp +out/alf/alf.c: alf/alflist.h alf/alflayout.h alf/alfcompat.h alf/alfpriv.h alf/alfbutton.cpp alf/alfcombobox.cpp alf/alfcompat.cpp alf/alfcontrol.cpp alf/alf.cpp alf/alfdpiaware.cpp alf/alfedit.cpp alf/alfgroupbox.cpp alf/alficon.cpp alf/alflabel.cpp alf/alflayout.cpp alf/alfmessagedlg.cpp alf/alfnativebtn.cpp alf/alfnotebook.cpp alf/alfpanel.cpp alf/alfspinbox.cpp alf/alftoplevel.cpp @mkdir -p out/alf @printf "#include \"alf.h\"\\n" > $@ @cat $^ | grep -v "^#pragma once" | grep -v "^#include \"alf" >> $@ diff --git a/Makefile.mingw-amd64 b/Makefile.mingw-amd64 index 57b79c4..5a87ede 100644 --- a/Makefile.mingw-amd64 +++ b/Makefile.mingw-amd64 @@ -8,7 +8,7 @@ LDFLAGS = -luser32 -lcomctl32 -lshell32 -lversion -static all: out/widgetfactory64.exe out/alf/alf64.c out/widgetfactory64-c.exe -out/widgetfactory64.exe: out/widgetfactory.amd64.o out/alfbutton.amd64.o out/alfcombobox.amd64.o out/alfcompat.amd64.o out/alfcontrol.amd64.o out/alf.amd64.o out/alfdpiaware.amd64.o out/alfedit.amd64.o out/alfgroupbox.amd64.o out/alficon.amd64.o out/alflabel.amd64.o out/alflayout.amd64.o out/alfmessagedlg.amd64.o out/alfnativebtn.amd64.o out/alfnotebook.amd64.o out/alfpanel.amd64.o out/alftoplevel.amd64.o +out/widgetfactory64.exe: out/widgetfactory.amd64.o out/alfbutton.amd64.o out/alfcombobox.amd64.o out/alfcompat.amd64.o out/alfcontrol.amd64.o out/alf.amd64.o out/alfdpiaware.amd64.o out/alfedit.amd64.o out/alfgroupbox.amd64.o out/alficon.amd64.o out/alflabel.amd64.o out/alflayout.amd64.o out/alfmessagedlg.amd64.o out/alfnativebtn.amd64.o out/alfnotebook.amd64.o out/alfpanel.amd64.o out/alfspinbox.amd64.o out/alftoplevel.amd64.o $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) out/alfbutton.amd64.o: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h @@ -56,13 +56,16 @@ out/alfnotebook.amd64.o: alf/alfnotebook.cpp alf/alfcompat.h alf/alf.h alf/alfl out/alfpanel.amd64.o: alf/alfpanel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CXXFLAGS) -c -o $@ $< +out/alfspinbox.amd64.o: alf/alfspinbox.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CXXFLAGS) -c -o $@ $< + out/alftoplevel.amd64.o: alf/alftoplevel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CXXFLAGS) -c -o $@ $< out/widgetfactory.amd64.o: widgetfactory.cpp alf/alf.h $(CXX) $(CXXFLAGS) -c -o $@ $< -out/alf/alf64.c: alf/alflist.h alf/alflayout.h alf/alfcompat.h alf/alfpriv.h alf/alfbutton.cpp alf/alfcombobox.cpp alf/alfcompat.cpp alf/alfcontrol.cpp alf/alf.cpp alf/alfdpiaware.cpp alf/alfedit.cpp alf/alfgroupbox.cpp alf/alficon.cpp alf/alflabel.cpp alf/alflayout.cpp alf/alfmessagedlg.cpp alf/alfnativebtn.cpp alf/alfnotebook.cpp alf/alfpanel.cpp alf/alftoplevel.cpp +out/alf/alf64.c: alf/alflist.h alf/alflayout.h alf/alfcompat.h alf/alfpriv.h alf/alfbutton.cpp alf/alfcombobox.cpp alf/alfcompat.cpp alf/alfcontrol.cpp alf/alf.cpp alf/alfdpiaware.cpp alf/alfedit.cpp alf/alfgroupbox.cpp alf/alficon.cpp alf/alflabel.cpp alf/alflayout.cpp alf/alfmessagedlg.cpp alf/alfnativebtn.cpp alf/alfnotebook.cpp alf/alfpanel.cpp alf/alfspinbox.cpp alf/alftoplevel.cpp @mkdir -p out/alf @printf "#include \"alf.h\"\\n" > $@ @cat $^ | grep -v "^#pragma once" | grep -v "^#include \"alf" >> $@ diff --git a/Makefile.vc6 b/Makefile.vc6 index 635e5eb..03a30cf 100644 --- a/Makefile.vc6 +++ b/Makefile.vc6 @@ -4,7 +4,7 @@ CXX = cl.exe CFLAGS = -O2 -GA -W3 -DUNICODE -D_UNICODE -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo LDFLAGS = /link unicows.lib kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib -out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alfcontrol.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alfgroupbox.obj out/alficon.obj out/alflabel.obj out/alflayout.obj out/alfmessagedlg.obj out/alfnativebtn.obj out/alfnotebook.obj out/alfpanel.obj out/alftoplevel.obj +out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alfcontrol.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alfgroupbox.obj out/alficon.obj out/alflabel.obj out/alflayout.obj out/alfmessagedlg.obj out/alfnativebtn.obj out/alfnotebook.obj out/alfpanel.obj out/alfspinbox.obj out/alftoplevel.obj $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) out/alfbutton.obj: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h @@ -52,6 +52,9 @@ out/alfnotebook.obj: alf/alfnotebook.cpp alf/alfcompat.h alf/alf.h alf/alflayou out/alfpanel.obj: alf/alfpanel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CFLAGS) -c -Fo$@ alf/alfpanel.cpp +out/alfspinbox.obj: alf/alfspinbox.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfspinbox.cpp + out/alftoplevel.obj: alf/alftoplevel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CFLAGS) -c -Fo$@ alf/alftoplevel.cpp diff --git a/Makefile.vc6-ansi b/Makefile.vc6-ansi index 174532f..759b494 100644 --- a/Makefile.vc6-ansi +++ b/Makefile.vc6-ansi @@ -4,7 +4,7 @@ CXX = cl.exe CFLAGS = -O2 -GA -W3 -D_WIN32=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0501 -nologo LDFLAGS = /link /entry:_entry /opt:nowin98 /fixed:no kernel32.lib user32.lib comctl32.lib shell32.lib gdi32.lib version.lib -out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alfcontrol.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alfgroupbox.obj out/alficon.obj out/alflabel.obj out/alflayout.obj out/alfmessagedlg.obj out/alfnativebtn.obj out/alfnotebook.obj out/alfpanel.obj out/alftoplevel.obj +out/widgetfactory.exe: out/widgetfactory.obj out/alfbutton.obj out/alfcombobox.obj out/alfcompat.obj out/alfcontrol.obj out/alf.obj out/alfdpiaware.obj out/alfedit.obj out/alfgroupbox.obj out/alficon.obj out/alflabel.obj out/alflayout.obj out/alfmessagedlg.obj out/alfnativebtn.obj out/alfnotebook.obj out/alfpanel.obj out/alfspinbox.obj out/alftoplevel.obj $(CXX) $(CFLAGS) -Fe$@ $** $(LDFLAGS) out/alfbutton.obj: alf/alfbutton.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h @@ -52,6 +52,9 @@ out/alfnotebook.obj: alf/alfnotebook.cpp alf/alfcompat.h alf/alf.h alf/alflayou out/alfpanel.obj: alf/alfpanel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CFLAGS) -c -Fo$@ alf/alfpanel.cpp +out/alfspinbox.obj: alf/alfspinbox.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h + $(CXX) $(CFLAGS) -c -Fo$@ alf/alfspinbox.cpp + out/alftoplevel.obj: alf/alftoplevel.cpp alf/alfcompat.h alf/alf.h alf/alflayout.h alf/alflist.h alf/alfpriv.h $(CXX) $(CFLAGS) -c -Fo$@ alf/alftoplevel.cpp diff --git a/alf/alf.cpp b/alf/alf.cpp index c2f99ce..a6c9e01 100644 --- a/alf/alf.cpp +++ b/alf/alf.cpp @@ -168,7 +168,7 @@ ALF_ShouldMessageBubble(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) return FALSE; return msg == ALF_WM_GETDPI - || msg == WM_COMMAND || msg == WM_NOTIFY + || msg == WM_COMMAND || msg == WM_NOTIFY || msg == WM_NOTIFYFORMAT || msg == WM_MEASUREITEM || msg == WM_DRAWITEM || msg == WM_CTLCOLORBTN || msg == WM_CTLCOLOREDIT || msg == WM_CTLCOLORLISTBOX || msg == WM_CTLCOLORSCROLLBAR diff --git a/alf/alf.h b/alf/alf.h index 8969ee1..f6ef21d 100644 --- a/alf/alf.h +++ b/alf/alf.h @@ -125,6 +125,13 @@ typedef struct { #define ALF_WM_ICONVIEW_GETICON (ALF_WM__BASE + 201) #define ALF_WM_ICONVIEW_SETICON (ALF_WM__BASE + 202) +#define ALF_WM_SPINBOX_GETRANGE (ALF_WM__BASE + 201) +#define ALF_WM_SPINBOX_SETRANGE (ALF_WM__BASE + 202) +#define ALF_WM_SPINBOX_GETPOS (ALF_WM__BASE + 203) +#define ALF_WM_SPINBOX_SETPOS (ALF_WM__BASE + 204) +#define ALF_WM_SPINBOX_GETEDIT (ALF_WM__BASE + 205) +#define ALF_WM_SPINBOX_GETUDCTL (ALF_WM__BASE + 206) + #define ALF_WM_USER (ALF_WM__BASE + 300) typedef DWORD ALFColor; @@ -656,6 +663,27 @@ ALF_MessageDlg_Confirm(HWND owner, const TCHAR *text, const TCHAR *caption, cons WORD ALF_MessageDlg_ConfirmDanger(HWND owner, const TCHAR *text, const TCHAR *caption, const TCHAR *okBtnText, const TCHAR *cancelBtnText); +// spin box +HWND +ALF_AddNumericSpinBox(HWND parent, WORD id, int x, int y, short val, short min, short max); + +BOOL +ALF_SpinBox_Range(HWND spinbox, short *pmin, short *pmax); + +BOOL +ALF_SpinBox_SetRange(HWND spinbox, short min, short max); + +short +ALF_SpinBox_Pos(HWND spinbox); + +BOOL +ALF_SpinBox_SetPos(HWND spinbox, short pos); + +HWND +ALF_SpinBox_EditControl(HWND spinbox); + +HWND +ALF_SpinBox_UpDownControl(HWND spinbox); #ifdef __cplusplus } // extern C diff --git a/alf/alfcompat.cpp b/alf/alfcompat.cpp index f5bed22..d764895 100644 --- a/alf/alfcompat.cpp +++ b/alf/alfcompat.cpp @@ -433,6 +433,14 @@ ALF_Compat_fallbackBufferedPaintRenderAnimation(HWND hwnd, HDC hdc) return FALSE; } +static HRESULT WINAPI +ALF_Compat_fallbackBufferedPaintStopAllAnimations(HWND hwnd) +{ + (void)hwnd; + + return E_NOTIMPL; +} + static HRESULT WINAPI ALF_Compat_fallbackGetThemeTransitionDuration(HTHEME hTheme, int iPartId, @@ -679,6 +687,7 @@ void ALF_LoadCompatFunctions(void) LOAD_FUNC(uxtheme, EndBufferedAnimation); LOAD_FUNC(uxtheme, EndBufferedPaint); LOAD_FUNC(uxtheme, BufferedPaintRenderAnimation); + LOAD_FUNC(uxtheme, BufferedPaintStopAllAnimations); LOAD_FUNC(uxtheme, GetThemeTransitionDuration); LOAD_FUNC(uxtheme, GetThemePartSize); LOAD_FUNC(uxtheme, GetThemeColor); @@ -774,6 +783,7 @@ void ALF_UnloadCompatFunctions(void) UNLOAD_FUNC(EndBufferedAnimation); UNLOAD_FUNC(EndBufferedPaint); UNLOAD_FUNC(BufferedPaintRenderAnimation); + UNLOAD_FUNC(BufferedPaintStopAllAnimations); UNLOAD_FUNC(GetThemeTransitionDuration); UNLOAD_FUNC(GetThemePartSize); UNLOAD_FUNC(GetThemeColor); @@ -814,6 +824,7 @@ ALF_Compat_HPAINTBUFFER (WINAPI *ALF_Compat_BeginBufferedPaint)(HDC,const RECT * HRESULT (WINAPI *ALF_Compat_EndBufferedAnimation)(ALF_Compat_HANIMATIONBUFFER,BOOL) = NULL; HRESULT (WINAPI *ALF_Compat_EndBufferedPaint)(ALF_Compat_HPAINTBUFFER,BOOL) = NULL; BOOL (WINAPI *ALF_Compat_BufferedPaintRenderAnimation)(HWND,HDC) = NULL; +HRESULT (WINAPI *ALF_Compat_BufferedPaintStopAllAnimations)(HWND) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeTransitionDuration)(HTHEME,int,int,int,int,DWORD*) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeColor)(HTHEME,int,int,int,COLORREF*) = NULL; HRESULT (WINAPI *ALF_Compat_GetThemeMargins)(HTHEME,HDC,int,int,int,const RECT *,MARGINS *) = NULL; diff --git a/alf/alfcompat.h b/alf/alfcompat.h index 8f6b80f..2946453 100644 --- a/alf/alfcompat.h +++ b/alf/alfcompat.h @@ -140,6 +140,7 @@ extern ALF_Compat_HPAINTBUFFER (WINAPI *ALF_Compat_BeginBufferedPaint)(HDC,const extern HRESULT (WINAPI *ALF_Compat_EndBufferedAnimation)(ALF_Compat_HANIMATIONBUFFER,BOOL); extern HRESULT (WINAPI *ALF_Compat_EndBufferedPaint)(ALF_Compat_HPAINTBUFFER,BOOL); extern BOOL (WINAPI *ALF_Compat_BufferedPaintRenderAnimation)(HWND,HDC); +extern HRESULT (WINAPI *ALF_Compat_BufferedPaintStopAllAnimations)(HWND); extern HRESULT (WINAPI *ALF_Compat_GetThemeTransitionDuration)(HTHEME,int,int,int,int,DWORD*); extern HRESULT (WINAPI *ALF_Compat_GetThemeColor)(HTHEME,int,int,int,COLORREF*); extern HRESULT (WINAPI *ALF_Compat_GetThemeMargins)(HTHEME,HDC,int,int,int,const RECT *,MARGINS *); diff --git a/alf/alfpanel.cpp b/alf/alfpanel.cpp index 62bac1e..be02890 100644 --- a/alf/alfpanel.cpp +++ b/alf/alfpanel.cpp @@ -152,6 +152,22 @@ ALF_Panel_DefWindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) return TRUE; } + if (msg == WM_COMMAND && priv->vtbl && priv->vtbl->command) { + HWND source = (HWND)lparam; + WORD code = HIWORD(wparam); + WORD id = LOWORD(wparam); + LRESULT r = priv->vtbl->command(priv->closure, window, code, id, source); + if (r) + return r; + } + + if (msg == WM_NOTIFY && priv->vtbl && priv->vtbl->notify) { + NMHDR *nmhdr = (NMHDR *)lparam; + LRESULT r = priv->vtbl->notify(priv->closure, window, wparam, nmhdr); + if (r) + return r; + } + if (ALF_ShouldMessageBubble(window, msg, wparam, lparam)) return SendMessage(GetParent(window), msg, wparam, lparam); 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); +} diff --git a/widgetfactory.cpp b/widgetfactory.cpp index 3298d81..b2c3396 100644 --- a/widgetfactory.cpp +++ b/widgetfactory.cpp @@ -10,6 +10,7 @@ enum { PANE_CHECKBOX, PANE_GROUPBOX, PANE_ICONVIEW, + PANE_SPINBOX, PANE__MAX }; @@ -20,7 +21,8 @@ static const TCHAR *g_paneLabels[PANE__MAX] = { TEXT("Notebook"), //PANE_NOTEBOOK, TEXT("Checkbox"), //PANE_CHECKBOX, TEXT("GroupBox"), //PANE_GROUPBOX, - TEXT("Icon View") //PANE_ICONVIEW + TEXT("Icon View"), //PANE_ICONVIEW, + TEXT("Spin Box") //PANE_SPINBOX }; enum { @@ -30,6 +32,8 @@ enum { ID_BTNCOMBOCLEAR, ID_NOTEBOOK, ID_HELLO, + ID_SPINBOX, + ID_SPINBOXOUT, IDM_FILE, IDM_FILE_CLOSE, IDM_HELP, @@ -808,6 +812,62 @@ iconviewPanelInit(HWND panel) ALF_Panel_SetVTable(panel, &iconviewPanelVtbl, priv); } +/* spinbox panel */ + +static LRESULT +spinboxPanelCommand(void *closure, HWND panel, WORD notificationcode, WORD sourceid, HWND control) +{ + (void)closure; + + if (notificationcode == EN_CHANGE && sourceid == ID_SPINBOX) { + HWND out = ALF_ControlHwndById(panel, ID_SPINBOXOUT); + TCHAR buf[12]; + wsprintf(buf, TEXT("%d"), (int)ALF_SpinBox_Pos(control)); + ALF_SetText(out, buf); + return 1; + } + + return 0; +} + +static void +spinboxPanelAttach(void *closure, HWND panel) +{ + (void)closure; + + ALF_AddLabel(panel, (WORD)-1, 1, 1, TEXT("Spin Box -10 to +42")); + ALF_AddNumericSpinBox(panel, ID_SPINBOX, 3, 1, 12, -10, 42); + ALF_AddLabel(panel, ID_SPINBOXOUT, 3, 3, TEXT("initial")); + + ALF_Layout_SetRowMinSize(panel, 0, 825); + ALF_Layout_SetRowMinSize(panel, 2, 825); + ALF_Layout_SetRowMinSize(panel, 4, 825); + ALF_Layout_SetColumnMinSize(panel, 0, 825); + ALF_Layout_SetColumnMinSize(panel, 2, 525); + ALF_Layout_SetColumnMinSize(panel, 4, 825); + ALF_Layout_SetRowExpandNumerator(panel, 1, 1); + ALF_Layout_SetRowExpandNumerator(panel, 3, 1); + ALF_Layout_SetColumnExpandNumerator(panel, 3, 1); + ALF_Layout_SetColumnExpandNumerator(panel, 4, 1); +} + +static ALFPanelVTable spinboxPanelVtbl = { + spinboxPanelAttach, + commonPanelDestroy, + commonPanelMessage, + spinboxPanelCommand, + NULL, + commonPanelPaint, + NULL +}; + +static void +spinboxPanelInit(HWND panel) +{ + CommonPanelPriv *priv = ALF_New(CommonPanelPriv, 1); + ALF_Panel_SetVTable(panel, &spinboxPanelVtbl, priv); +} + void (*g_paneInitTable[PANE__MAX])(HWND) = { buttonPanelInit, //PANE_BUTTONS labelPanelInit, //PANE_LABEL, @@ -815,7 +875,8 @@ void (*g_paneInitTable[PANE__MAX])(HWND) = { notebookPanelInit, //PANE_NOTEBOOK, checkboxPanelInit, //PANE_CHECKBOX, groupboxPanelInit, //PANE_GROUPBOX, - iconviewPanelInit //PANE_ICONVIEW + iconviewPanelInit, //PANE_ICONVIEW, + spinboxPanelInit //PANE_SPINBOX }; static void @@ -1094,6 +1155,7 @@ WinMain addPaneToNotebook(hwndNtbk, PANE_COMBO); addPaneToNotebook(hwndNtbk, PANE_GROUPBOX); addPaneToNotebook(hwndNtbk, PANE_ICONVIEW); + addPaneToNotebook(hwndNtbk, PANE_SPINBOX); ALF_AddNativeButton(win, ID_HELLO, 1, 3, TEXT("&Hello World!")); ALF_AddNativeButton(win, (WORD)-1, 3, 3, TEXT("Goodbye, World")); -- cgit v1.2.3