From 9d237b5fd80e55d8b5e367323b6ee58be896f968 Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Sat, 23 May 2020 14:26:28 +0200 Subject: move radio button into button class --- alf/alfbutton.cpp | 174 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 160 insertions(+), 14 deletions(-) (limited to 'alf/alfbutton.cpp') diff --git a/alf/alfbutton.cpp b/alf/alfbutton.cpp index e63b5ce..f809410 100644 --- a/alf/alfbutton.cpp +++ b/alf/alfbutton.cpp @@ -24,6 +24,16 @@ #define CBS_MIXEDPRESSED 11 #define CBS_MIXEDDISABLED 12 +#define BP_RADIOBUTTON 2 +#define RBS_UNCHECKEDNORMAL 1 +#define RBS_UNCHECKEDHOT 2 +#define RBS_UNCHECKEDPRESSED 3 +#define RBS_UNCHECKEDDISABLED 4 +#define RBS_CHECKEDNORMAL 5 +#define RBS_CHECKEDHOT 6 +#define RBS_CHECKEDPRESSED 7 +#define RBS_CHECKEDDISABLED 8 + #define ALF_NTBTN_FLAG_UXTHEME 1 #define ALF_NTBTN_FLAG_IS_DISABLED 2 #define ALF_NTBTN_FLAG_IS_DEFAULT 4 @@ -242,7 +252,7 @@ ALF_NtButton_CalculateSize(HWND hwnd, ALFNtButtonPriv *priv, SIZE *pSize) DrawTextW(hdc, priv->text, -1, &r, format); - if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) { + if (priv->drawFlags & (ALF_NTBTN_FLAG_DRAW_CHECKBOX | ALF_NTBTN_FLAG_DRAW_RADIOBTN | ALF_NTBTN_FLAG_DRAW_TRISTATE)) { int checkwidth = 12 * priv->dpi / 96 + 1; int space = ALF_Button_CalcCheckboxTextSpace(hdc); @@ -300,7 +310,7 @@ ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxpart, int uxs RECT r; GetClientRect(hwnd, &r); - if (uxpart == BP_CHECKBOX) { + if (uxpart == BP_CHECKBOX || uxpart == BP_RADIOBUTTON) { if (priv->bgcolor == ALF_COLOR_TRANSPARENT) { ALF_Compat_DrawThemeParentBackground(hwnd, hDC, rcPaint); } else { @@ -320,7 +330,7 @@ ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxpart, int uxs r.right - r.left, r.bottom - r.top }; - ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_CHECKBOX, uxstate, &rcCheckmark, rcPaint); + ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, uxpart, uxstate, &rcCheckmark, rcPaint); RECT textbounds = rcText; DrawTextW(hDC, priv->text, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_EXPANDTABS); @@ -335,7 +345,7 @@ ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxpart, int uxs if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEACCEL) style |= DT_HIDEPREFIX; - ALF_Compat_DrawThemeText(priv->hTheme, hDC, BP_CHECKBOX, uxstate, priv->text, -1, style, 0, &texttarget); + ALF_Compat_DrawThemeText(priv->hTheme, hDC, uxpart, uxstate, priv->text, -1, style, 0, &texttarget); if ((priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) { RECT f = texttarget; @@ -395,7 +405,7 @@ ALF_NtButton_RenderClassicCheckbox(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, REC HFONT oldfont = SelectFont(dc, priv->font); - UINT dfcs = DFCS_BUTTONCHECK; + UINT dfcs = priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK; if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) dfcs |= DFCS_CHECKED; if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) @@ -517,7 +527,7 @@ ALF_NtButton_RenderClassicPushBtn(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT static void ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint) { - if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) { + if (priv->drawFlags & (ALF_NTBTN_FLAG_DRAW_CHECKBOX | ALF_NTBTN_FLAG_DRAW_RADIOBTN)) { ALF_NtButton_RenderClassicCheckbox(hwnd, priv, dc, rcPaint); } else { ALF_NtButton_RenderClassicPushBtn(hwnd, priv, dc, rcPaint); @@ -555,6 +565,28 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r) if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) stateid = CBS_UNCHECKEDDISABLED; } + } else if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) { + partid = BP_RADIOBUTTON; + + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) { + stateid = RBS_CHECKEDNORMAL; + + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT) + stateid = RBS_CHECKEDHOT; + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) + stateid = RBS_CHECKEDPRESSED; + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) + stateid = RBS_CHECKEDDISABLED; + } else { + stateid = RBS_UNCHECKEDNORMAL; + + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT) + stateid = RBS_UNCHECKEDHOT; + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) + stateid = RBS_UNCHECKEDPRESSED; + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) + stateid = RBS_UNCHECKEDDISABLED; + } } else { partid = BP_PUSHBUTTON; stateid = PBS_NORMAL; @@ -659,6 +691,39 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r) } } +static void +ALF_NtButton_FixRadioButtonCheck(HWND hwnd, ALFNtButtonPriv *priv, BOOL unselectOthers) +{ + if ((priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) == 0) + return; + + // fix WS_TABSTOP style + LONG s = GetWindowLong(hwnd, GWL_STYLE); + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) + s |= WS_TABSTOP; + else + s &= ~WS_TABSTOP; + SetWindowLong(hwnd, GWL_STYLE, s); + + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED && unselectOthers) { + // uncheck all other radio buttons in the group + HWND p = GetParent(hwnd); + HWND h = GetNextDlgGroupItem(p, hwnd, FALSE); + for (int limit = 1000; limit > 0; --limit) { + if (h == hwnd || h == NULL) + break; + + LRESULT dlgc = SendMessage(h, WM_GETDLGCODE, 0, 0); + if (dlgc & DLGC_RADIOBUTTON) { + SendMessage(h, BM_SETCHECK, BST_UNCHECKED, 0); + } + + h = GetNextDlgGroupItem(p, h, FALSE); + } + } +} + + static void ALF_NtButton_Clicked(HWND hwnd, ALFNtButtonPriv *priv) { @@ -668,6 +733,12 @@ ALF_NtButton_Clicked(HWND hwnd, ALFNtButtonPriv *priv) } else { ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_CHECKED, 0, TRUE); } + } else if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) + return; + + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_CHECKED, 0, TRUE); + ALF_NtButton_FixRadioButtonCheck(hwnd, priv, TRUE); } SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), BN_CLICKED), (LPARAM)hwnd); @@ -681,8 +752,10 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (uMsg == WM_CREATE) { priv = ALF_NtButton_InitializePriv((CREATESTRUCTW *)lParam); - if (((CREATESTRUCTW *)lParam)->style & BS_CHECKBOX) + if ((((CREATESTRUCTW *)lParam)->style & 0x0C0F) == BS_AUTOCHECKBOX) priv->drawFlags |= ALF_NTBTN_FLAG_DRAW_CHECKBOX; + if ((((CREATESTRUCTW *)lParam)->style & 0x0C0F) == BS_AUTORADIOBUTTON) + priv->drawFlags |= ALF_NTBTN_FLAG_DRAW_RADIOBTN; SetWindowLongPtrW(hwnd, 0, (LONG_PTR)priv); @@ -729,6 +802,9 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } else { ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_CHECKED, TRUE); } + + ALF_NtButton_FixRadioButtonCheck(hwnd, priv, FALSE); + return 0; } else if (uMsg == BM_GETCHECK) { if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) @@ -777,6 +853,10 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_HOT, TRUE); } else if (uMsg == WM_SETFOCUS) { ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_FOCUSED, 0, TRUE); + + if ((priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) && !(priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED)) { + ALF_NtButton_Clicked(hwnd, priv); + } } else if (uMsg == WM_KILLFOCUS) { ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_FOCUSED | ALF_NTBTN_FLAG_IS_PRESSED, TRUE); } else if (uMsg == WM_LBUTTONDOWN) { @@ -950,7 +1030,7 @@ ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD ad int minwidth = 5625; int minheight = 1725; - if (addstyle & (BS_CHECKBOX | BS_RADIOBUTTON)) { + if (addstyle & (BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTORADIOBUTTON)) { minwidth = 0; minheight = 0; } @@ -967,6 +1047,7 @@ ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD ad #define ALF_CLSCBTN_FLAG_IS_DEFAULT ((DWORD)1) #define ALF_CLSCBTN_FLAG_DRAW_CHECKBOX ((DWORD)2) #define ALF_CLSCBTN_FLAG_IS_CHECKED ((DWORD)4) +#define ALF_CLSCBTN_FLAG_DRAW_RADIO ((DWORD)8) typedef struct { WNDPROC origWndProc; @@ -1021,7 +1102,7 @@ ALF_ClassicButton_CalculateSize(HWND hwnd, ALFClassicButtonPriv *priv, SIZE *pSi ALF_Free(textbuf); - if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) { + if (priv->flags & (ALF_CLSCBTN_FLAG_DRAW_CHECKBOX | ALF_CLSCBTN_FLAG_DRAW_RADIO)) { int checkwidth = 13; int space = ALF_Button_CalcCheckboxTextSpace(hdc); @@ -1072,7 +1153,7 @@ ALF_ClassicButton_PaintCheckbox(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMS } if (dis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) { - UINT dfcs = DFCS_BUTTONCHECK; + UINT dfcs = priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK; if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED) dfcs |= DFCS_CHECKED; if (dis->itemState & ODS_SELECTED) @@ -1192,13 +1273,45 @@ ALF_ClassicButton_PaintButton(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTR static void ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis) { - if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) { + if (priv->flags & (ALF_CLSCBTN_FLAG_DRAW_CHECKBOX | ALF_CLSCBTN_FLAG_DRAW_RADIO)) { ALF_ClassicButton_PaintCheckbox(hwnd, priv, dis); } else { ALF_ClassicButton_PaintButton(hwnd, priv, dis); } } +static void +ALF_ClassicButton_FixRadioButtonCheck(HWND hwnd, ALFClassicButtonPriv *priv, BOOL unselectOthers) +{ + if ((priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO) == 0) + return; + + // fix WS_TABSTOP style + LONG s = GetWindowLong(hwnd, GWL_STYLE); + if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED) + s |= WS_TABSTOP; + else + s &= ~WS_TABSTOP; + SetWindowLong(hwnd, GWL_STYLE, s); + + if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED && unselectOthers) { + // uncheck all other radio buttons in the group + HWND p = GetParent(hwnd); + HWND h = GetNextDlgGroupItem(p, hwnd, FALSE); + for (int limit = 1000; limit > 0; --limit) { + if (h == hwnd || h == NULL) + break; + + LRESULT dlgc = SendMessage(h, WM_GETDLGCODE, 0, 0); + if (dlgc & DLGC_RADIOBUTTON) { + SendMessage(h, BM_SETCHECK, BST_UNCHECKED, 0); + } + + h = GetNextDlgGroupItem(p, h, FALSE); + } + } +} + static LRESULT CALLBACK ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -1231,6 +1344,10 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR rcCheck.right = 13; rcCheck.bottom = rcClient.bottom - rcClient.top; InvalidateRect(hwnd, &rcCheck, TRUE); + } else if (HIWORD(wParam) == BN_CLICKED && priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO) { + priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED; + InvalidateRect(hwnd, NULL, TRUE); + ALF_ClassicButton_FixRadioButtonCheck(hwnd, priv, TRUE); } } else if (uMsg == WM_ERASEBKGND) { return TRUE; @@ -1245,6 +1362,8 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR if (wParam & BST_CHECKED) priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED; + ALF_ClassicButton_FixRadioButtonCheck(hwnd, priv, FALSE); + InvalidateRect(hwnd, NULL, TRUE); return 0; } else if (uMsg == BM_GETCHECK) { @@ -1256,11 +1375,19 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR } else if (uMsg == WM_GETDLGCODE) { if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) { return (LRESULT)DLGC_BUTTON; + } else if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO) { + return (LRESULT)DLGC_RADIOBUTTON; } else if (priv->flags & ALF_CLSCBTN_FLAG_IS_DEFAULT) { return (LRESULT)DLGC_DEFPUSHBUTTON; } else { return (LRESULT)DLGC_UNDEFPUSHBUTTON; } + } else if (uMsg == WM_SETFOCUS) { + if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO && !(priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED)) { + priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED; + ALF_ClassicButton_FixRadioButtonCheck(hwnd, priv, TRUE); + InvalidateRect(hwnd, NULL, TRUE); + } } else if (uMsg == WM_SETFONT) { ALF_InvalidateLayout(GetParent(hwnd)); InvalidateRect(hwnd, NULL, TRUE); @@ -1292,11 +1419,20 @@ ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWO int minwidth = 5625; int minheight = 1725; - if (style & BS_CHECKBOX) { + if ((style & 0x0C0F) == BS_AUTOCHECKBOX) { minwidth = 0; minheight = 0; priv->flags |= ALF_CLSCBTN_FLAG_DRAW_CHECKBOX; } + if ((style & 0x0C0F) == BS_AUTORADIOBUTTON) { + minwidth = 0; + minheight = 0; + priv->flags |= ALF_CLSCBTN_FLAG_DRAW_RADIO; + + LONG s = GetWindowLong(hwndButton, GWL_STYLE); + s &= ~WS_TABSTOP; + SetWindowLong(hwndButton, GWL_STYLE, s); + } priv->origWndProc = (WNDPROC)GetWindowLongPtr(hwndButton, GWLP_WNDPROC); @@ -1323,9 +1459,19 @@ HWND ALF_AddCheckbox(HWND win, WORD id, int x, int y, const TCHAR *text) { if (_alf_buttonClass) { - return ALF_NtButton_Create(win, id, x, y, text, WS_TABSTOP | BS_CHECKBOX); + return ALF_NtButton_Create(win, id, x, y, text, WS_TABSTOP | BS_AUTOCHECKBOX); + } else { + return ALF_ClassicButton_Create(win, id, x, y, text, BS_AUTOCHECKBOX); + } +} + +HWND +ALF_AddRadioButton(HWND parent, WORD id, int x, int y, const TCHAR *text) +{ + if (_alf_buttonClass) { + return ALF_NtButton_Create(parent, id, x, y, text, BS_AUTORADIOBUTTON); } else { - return ALF_ClassicButton_Create(win, id, x, y, text, BS_CHECKBOX); + return ALF_ClassicButton_Create(parent, id, x, y, text, BS_AUTORADIOBUTTON); } } -- cgit v1.2.3