summaryrefslogtreecommitdiff
path: root/alf/alfbutton.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alf/alfbutton.cpp')
-rw-r--r--alf/alfbutton.cpp592
1 files changed, 506 insertions, 86 deletions
diff --git a/alf/alfbutton.cpp b/alf/alfbutton.cpp
index 2c67074..e63b5ce 100644
--- a/alf/alfbutton.cpp
+++ b/alf/alfbutton.cpp
@@ -10,6 +10,20 @@
#define PBS_DEFAULTED 5
#define PBS_DEFAULTED_ANIMATING 6
+#define BP_CHECKBOX 3
+#define CBS_UNCHECKEDNORMAL 1
+#define CBS_UNCHECKEDHOT 2
+#define CBS_UNCHECKEDPRESSED 3
+#define CBS_UNCHECKEDDISABLED 4
+#define CBS_CHECKEDNORMAL 5
+#define CBS_CHECKEDHOT 6
+#define CBS_CHECKEDPRESSED 7
+#define CBS_CHECKEDDISABLED 8
+#define CBS_MIXEDNORMAL 9
+#define CBS_MIXEDHOT 10
+#define CBS_MIXEDPRESSED 11
+#define CBS_MIXEDDISABLED 12
+
#define ALF_NTBTN_FLAG_UXTHEME 1
#define ALF_NTBTN_FLAG_IS_DISABLED 2
#define ALF_NTBTN_FLAG_IS_DEFAULT 4
@@ -19,6 +33,10 @@
#define ALF_NTBTN_FLAG_HIDEFOCUS 64
#define ALF_NTBTN_FLAG_HIDEACCEL 128
#define ALF_NTBTN_FLAG_DEFAULT_ANIMATING 256
+#define ALF_NTBTN_FLAG_IS_CHECKED 512
+#define ALF_NTBTN_FLAG_DRAW_CHECKBOX 1024
+#define ALF_NTBTN_FLAG_DRAW_RADIOBTN 2048
+#define ALF_NTBTN_FLAG_DRAW_TRISTATE 4096
typedef struct {
DWORD drawFlags;
@@ -28,9 +46,12 @@ typedef struct {
DWORD uxDrawFlagsCurrent;
DWORD uxDrawFlagsPrev;
DWORD uxDefaultAnimationDuration;
+ int uxPartPrev;
+ int uxPartCurrent;
int dpi;
HFONT font;
WCHAR *text;
+ ALFColor bgcolor;
} ALFNtButtonPriv;
TCHAR *_alf_buttonClass = NULL;
@@ -115,6 +136,21 @@ ALF_Button_DrawDisabledText31(HDC hdc,
return r;
}
+// FIXME! this doesn’t really look correct
+static int
+ALF_Button_CalcCheckboxTextSpace(HDC hdc)
+{
+ SIZE s = {0,0};
+ GetTextExtentPoint(hdc, TEXT("0"), 1, &s);
+
+ s.cx /= 2;
+
+ if (s.cx < 2)
+ s.cx = 2;
+
+ return s.cx;
+}
+
static ALFNtButtonPriv *
ALF_NtButton_InitializePriv(CREATESTRUCTW *cs)
@@ -125,6 +161,7 @@ ALF_NtButton_InitializePriv(CREATESTRUCTW *cs)
priv->uxStateCurrent = -1;
priv->uxStatePrev = -1;
priv->dpi = 96;
+ priv->bgcolor = ALF_COLOR_SYS(COLOR_BTNFACE);
SIZE_T l = (SIZE_T)lstrlenW(cs->lpszName);
priv->text = ALF_New(WCHAR, l + 1);
@@ -205,19 +242,35 @@ ALF_NtButton_CalculateSize(HWND hwnd, ALFNtButtonPriv *priv, SIZE *pSize)
DrawTextW(hdc, priv->text, -1, &r, format);
- int xpadding = ALF_Compat_GetSystemMetricsForDpi(SM_CXEDGE,
- (UINT)priv->dpi) * 2 + 6;
- int ypadding = ALF_Compat_GetSystemMetricsForDpi(SM_CYEDGE,
- (UINT)priv->dpi) * 2 + 4;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
+ int checkwidth = 12 * priv->dpi / 96 + 1;
- if (pSize->cx < r.right - r.left + xpadding) {
- pSize->cx = r.right - r.left + xpadding;
- }
- if (pSize->cy < r.bottom - r.top + ypadding) {
- pSize->cy = r.bottom - r.top + ypadding;
- }
- if (pSize->cx < pSize->cy) {
- pSize->cx = pSize->cy;
+ int space = ALF_Button_CalcCheckboxTextSpace(hdc);
+ int cx = checkwidth + space + r.right - r.left + 1;
+ int cy = r.bottom - r.top;
+ if (cy < checkwidth)
+ cy = checkwidth;
+
+ if (pSize->cx < cx)
+ pSize->cx = cx;
+
+ if (pSize->cy < cy)
+ pSize->cy = cy;
+ } else {
+ int xpadding = ALF_Compat_GetSystemMetricsForDpi(SM_CXEDGE,
+ (UINT)priv->dpi) * 2 + 6;
+ int ypadding = ALF_Compat_GetSystemMetricsForDpi(SM_CYEDGE,
+ (UINT)priv->dpi) * 2 + 4;
+
+ if (pSize->cx < r.right - r.left + xpadding) {
+ pSize->cx = r.right - r.left + xpadding;
+ }
+ if (pSize->cy < r.bottom - r.top + ypadding) {
+ pSize->cy = r.bottom - r.top + ypadding;
+ }
+ if (pSize->cx < pSize->cy) {
+ pSize->cx = pSize->cy;
+ }
}
SelectFont(hdc, oldFont);
@@ -240,46 +293,162 @@ ALF_NtButton_DefaultAnimatingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, D
}
static void
-ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxstate, DWORD drawFlags, HDC hDC, RECT *rcPaint)
+ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxpart, int uxstate, DWORD drawFlags, HDC hDC, RECT *rcPaint)
{
HFONT oldfont = SelectFont(hDC, priv->font);
- if (ALF_Compat_IsThemeBackgroundPartiallyTransparent(priv->hTheme, BP_PUSHBUTTON, uxstate)) {
- ALF_Compat_DrawThemeParentBackground(hwnd, hDC, rcPaint);
- }
-
RECT r;
GetClientRect(hwnd, &r);
- ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, rcPaint);
+ if (uxpart == BP_CHECKBOX) {
+ if (priv->bgcolor == ALF_COLOR_TRANSPARENT) {
+ ALF_Compat_DrawThemeParentBackground(hwnd, hDC, rcPaint);
+ } else {
+ ALF_FillRect(hDC, rcPaint, priv->bgcolor);
+ }
- RECT content = r;
- ALF_Compat_GetThemeBackgroundContentRect(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, &content);
+ int checkwidth = 12 * priv->dpi / 96 + 1;
- if ((drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS))
- DrawFocusRect(hDC, &content);
+ RECT rcCheckmark = { 0, 0, checkwidth, checkwidth };
+ rcCheckmark.top += (r.bottom - r.top - checkwidth) / 2;
+ rcCheckmark.bottom = rcCheckmark.top + checkwidth;
- UINT style = DT_CENTER | DT_NOCLIP;
+ int space = ALF_Button_CalcCheckboxTextSpace(hDC);
- if (drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
- style |= DT_HIDEPREFIX;
+ RECT rcText = { checkwidth + space,
+ 0,
+ r.right - r.left,
+ r.bottom - r.top };
- RECT textbounds = content;
- ALF_Compat_GetThemeTextExtent(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, priv->text, -1, style, &content, &textbounds);
+ ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_CHECKBOX, uxstate, &rcCheckmark, rcPaint);
- RECT texttarget = content;
- texttarget.top += ((content.bottom - content.top) - (textbounds.bottom - textbounds.top)) / 2;
- texttarget.left += ((content.right - content.left) - (textbounds.right - textbounds.left)) / 2;
- texttarget.right = texttarget.left + (textbounds.right - textbounds.left);
- texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+ RECT textbounds = rcText;
+ DrawTextW(hDC, priv->text, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_EXPANDTABS);
+
+ RECT texttarget = rcText;
+ texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
+ texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+ texttarget.right = texttarget.left + textbounds.right - textbounds.left;
+
+ UINT style = DT_LEFT | DT_NOCLIP | DT_EXPANDTABS;
+
+ 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);
+
+ if ((priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) {
+ RECT f = texttarget;
+ InflateRect(&f, 1, 0);
+ DrawFocusRect(hDC, &f);
+ }
+ } else {
+ if (ALF_Compat_IsThemeBackgroundPartiallyTransparent(priv->hTheme, uxpart, uxstate)) {
+ if (priv->bgcolor == ALF_COLOR_TRANSPARENT) {
+ ALF_Compat_DrawThemeParentBackground(hwnd, hDC, rcPaint);
+ } else {
+ ALF_FillRect(hDC, rcPaint, priv->bgcolor);
+ }
+ }
+
+ ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, rcPaint);
- ALF_Compat_DrawThemeText(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, priv->text, -1, style, 0, &texttarget);
+ RECT content = r;
+ ALF_Compat_GetThemeBackgroundContentRect(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, &content);
+
+ if ((drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS))
+ DrawFocusRect(hDC, &content);
+
+ UINT style = DT_CENTER | DT_NOCLIP;
+
+ if (drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
+ style |= DT_HIDEPREFIX;
+
+ RECT textbounds = content;
+ ALF_Compat_GetThemeTextExtent(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, priv->text, -1, style, &content, &textbounds);
+
+ RECT texttarget = content;
+ texttarget.top += ((content.bottom - content.top) - (textbounds.bottom - textbounds.top)) / 2;
+ texttarget.left += ((content.right - content.left) - (textbounds.right - textbounds.left)) / 2;
+ texttarget.right = texttarget.left + (textbounds.right - textbounds.left);
+ texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+
+ ALF_Compat_DrawThemeText(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, priv->text, -1, style, 0, &texttarget);
+ }
SelectFont(hDC, oldfont);
}
static void
-ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
+ALF_NtButton_RenderClassicCheckbox(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
+{
+ int checkwidth = 12 * priv->dpi / 96 + 1;
+
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ if (priv->bgcolor == ALF_COLOR_TRANSPARENT) {
+ ALF_Compat_DrawThemeParentBackground(hwnd, dc, rcPaint);
+ } else {
+ ALF_FillRect(dc, rcPaint, priv->bgcolor);
+ }
+
+ HFONT oldfont = SelectFont(dc, priv->font);
+
+ UINT dfcs = DFCS_BUTTONCHECK;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED)
+ dfcs |= DFCS_CHECKED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ dfcs |= DFCS_PUSHED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ dfcs |= DFCS_INACTIVE;
+
+ RECT rcCheckmark = { 0, 0, checkwidth, checkwidth };
+ rcCheckmark.top += (rcClient.bottom - rcClient.top - checkwidth) / 2;
+ rcCheckmark.bottom = rcCheckmark.top + checkwidth;
+
+ // lol
+ int space = ALF_Button_CalcCheckboxTextSpace(dc);
+
+ RECT rcText = { checkwidth + space,
+ 0,
+ rcClient.right - rcClient.left,
+ rcClient.bottom - rcClient.top };
+
+ DrawFrameControl(dc, &rcCheckmark, DFC_BUTTON, dfcs);
+
+ RECT textbounds = rcText;
+ DrawTextW(dc, priv->text, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_EXPANDTABS);
+
+ RECT texttarget = rcText;
+ texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
+ texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+ texttarget.right = texttarget.left + textbounds.right - textbounds.left;
+
+ UINT style = DT_LEFT | DT_NOCLIP | DT_EXPANDTABS;
+
+ if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
+ style |= DT_HIDEPREFIX;
+
+ COLORREF oldBkColor = SetBkColor(dc, GetSysColor(COLOR_BTNFACE));
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) {
+ ALF_Button_DrawDisabledTextNtW(dc, priv->text, -1, &texttarget, style);
+ } else {
+ DrawTextW(dc, priv->text, -1, &texttarget, style);
+ }
+ SetBkColor(dc, oldBkColor);
+
+ if ((priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) {
+ RECT f = texttarget;
+ InflateRect(&f, 1, 0);
+ DrawFocusRect(dc, &f);
+ }
+
+ SelectFont(dc, oldfont);
+}
+
+static void
+ALF_NtButton_RenderClassicPushBtn(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
{
(void)rcPaint;
@@ -346,31 +515,71 @@ ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPai
}
static void
+ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
+{
+ if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
+ ALF_NtButton_RenderClassicCheckbox(hwnd, priv, dc, rcPaint);
+ } else {
+ ALF_NtButton_RenderClassicPushBtn(hwnd, priv, dc, rcPaint);
+ }
+}
+
+static void
ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
{
if (!ALF_Compat_BufferedPaintRenderAnimation(hwnd, dc)) {
if ((priv->drawFlags & ALF_NTBTN_FLAG_UXTHEME) && priv->hTheme) {
// Draw XP style themed button
- int stateid = PBS_NORMAL;
+ int partid = 0;
+ int stateid = 0;
+
+ if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
+ partid = BP_CHECKBOX;
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT)
- stateid = (priv->drawFlags & ALF_NTBTN_FLAG_DEFAULT_ANIMATING) ? PBS_DEFAULTED_ANIMATING : PBS_DEFAULTED;
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)
- stateid = PBS_HOT;
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
- stateid = PBS_PRESSED;
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
- stateid = PBS_DISABLED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) {
+ stateid = CBS_CHECKEDNORMAL;
+
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)
+ stateid = CBS_CHECKEDHOT;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ stateid = CBS_CHECKEDPRESSED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ stateid = CBS_CHECKEDDISABLED;
+ } else {
+ stateid = CBS_UNCHECKEDNORMAL;
+
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)
+ stateid = CBS_UNCHECKEDHOT;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ stateid = CBS_UNCHECKEDPRESSED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ stateid = CBS_UNCHECKEDDISABLED;
+ }
+ } else {
+ partid = BP_PUSHBUTTON;
+ stateid = PBS_NORMAL;
+
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT)
+ stateid = (priv->drawFlags & ALF_NTBTN_FLAG_DEFAULT_ANIMATING) ? PBS_DEFAULTED_ANIMATING : PBS_DEFAULTED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)
+ stateid = PBS_HOT;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ stateid = PBS_PRESSED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ stateid = PBS_DISABLED;
+ }
if (priv->uxStatePrev == -1) {
// initial draw
priv->uxStateCurrent = stateid;
+ priv->uxPartCurrent = partid;
priv->uxDrawFlagsCurrent = priv->drawFlags;
if (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING)
priv->uxStateCurrent = PBS_NORMAL;
}
+ priv->uxPartPrev = priv->uxPartCurrent;
priv->uxStatePrev = priv->uxStateCurrent;
priv->uxStateCurrent = stateid;
priv->uxDrawFlagsPrev = priv->uxDrawFlagsCurrent;
@@ -381,11 +590,12 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
animParams.cbSize = sizeof(animParams);
animParams.style = ALF_Compat_BPAS_LINEAR;
- if (priv->uxStateCurrent != priv->uxStatePrev) {
- if ((priv->uxStateCurrent == PBS_DEFAULTED && priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) ||
- (priv->uxStatePrev == PBS_DEFAULTED && priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING)) {
+ if (priv->uxStateCurrent != priv->uxStatePrev && priv->uxPartCurrent == priv->uxPartPrev) {
+ if (priv->uxPartCurrent == BP_PUSHBUTTON &&
+ ((priv->uxStateCurrent == PBS_DEFAULTED && priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) ||
+ (priv->uxStatePrev == PBS_DEFAULTED && priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING))) {
animParams.dwDuration = priv->uxDefaultAnimationDuration;
- } else if (priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) {
+ } else if (priv->uxPartCurrent == BP_PUSHBUTTON && priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) {
// Win7 misses these transition times, use the one for PBS_DEFAULTED
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
BP_PUSHBUTTON,
@@ -393,7 +603,7 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
PBS_DEFAULTED,
TMT_TRANSITIONDURATION,
&animParams.dwDuration);
- } else if (priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) {
+ } else if (priv->uxPartCurrent == BP_PUSHBUTTON && priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) {
// Win7 misses these transition times, use the one for PBS_DEFAULTED
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
BP_PUSHBUTTON,
@@ -403,22 +613,24 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
&animParams.dwDuration);
} else {
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
- BP_PUSHBUTTON,
+ priv->uxPartCurrent,
priv->uxStatePrev,
priv->uxStateCurrent,
TMT_TRANSITIONDURATION,
&animParams.dwDuration);
}
- if ((priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
- && !(priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING)) {
+ if ((priv->uxPartCurrent == BP_PUSHBUTTON || priv->uxPartPrev == BP_PUSHBUTTON) &&
+ ((priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
+ && !(priv->uxPartCurrent == BP_PUSHBUTTON && (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING)))) {
KillTimer(hwnd, (UINT_PTR)priv);
ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_DEFAULT_ANIMATING, FALSE);
}
- if (!(priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
+ if (priv->uxPartCurrent == BP_PUSHBUTTON &&
+ (!(priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
&& (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING)
- && priv->uxDefaultAnimationDuration) {
+ && priv->uxDefaultAnimationDuration)) {
SetTimer(hwnd, (UINT_PTR)priv, priv->uxDefaultAnimationDuration, ALF_NtButton_DefaultAnimatingTimerProc);
}
}
@@ -428,21 +640,17 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
hbpAnimation = ALF_Compat_BeginBufferedAnimation(hwnd, dc, r, 0, NULL, &animParams, &hdcFrom, &hdcTo);
if (hbpAnimation) {
- HFONT font = (HFONT)GetCurrentObject(dc, OBJ_FONT);
-
if (hdcFrom) {
- SelectFont(hdcFrom, font);
- ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxStatePrev, priv->uxDrawFlagsPrev, hdcFrom, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartPrev, priv->uxStatePrev, priv->uxDrawFlagsPrev, hdcFrom, r);
}
if (hdcTo) {
- SelectFont(hdcTo, font);
- ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, hdcTo, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartCurrent, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, hdcTo, r);
}
ALF_Compat_EndBufferedAnimation(hbpAnimation, TRUE);
} else {
- ALF_NtButton_RenderUxtheme(hwnd, priv, stateid, priv->uxDrawFlagsCurrent, dc, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartCurrent, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, dc, r);
}
} else {
// Draw classic unthemed button
@@ -454,7 +662,14 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
static void
ALF_NtButton_Clicked(HWND hwnd, ALFNtButtonPriv *priv)
{
- (void)priv;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) {
+ ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_CHECKED, TRUE);
+ } else {
+ ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_CHECKED, 0, TRUE);
+ }
+ }
+
SendMessageW(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), BN_CLICKED), (LPARAM)hwnd);
}
@@ -466,6 +681,9 @@ 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)
+ priv->drawFlags |= ALF_NTBTN_FLAG_DRAW_CHECKBOX;
+
SetWindowLongPtrW(hwnd, 0, (LONG_PTR)priv);
ALF_NtButton_HandleThemeChange(hwnd, priv);
@@ -488,7 +706,11 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
ALF_NtButton_Paint(hwnd, priv, (HDC)wParam, &rc);
} else if (uMsg == WM_GETDLGCODE) {
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) {
+ if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX || priv->drawFlags & ALF_NTBTN_FLAG_DRAW_TRISTATE) {
+ return DLGC_BUTTON;
+ } else if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) {
+ return DLGC_RADIOBUTTON;
+ } else if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) {
return DLGC_DEFPUSHBUTTON | DLGC_BUTTON;
} else {
return DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON;
@@ -501,6 +723,21 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} else {
ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_DEFAULT, TRUE);
}
+ } else if (uMsg == BM_SETCHECK) {
+ if (wParam & BST_CHECKED) {
+ ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_CHECKED, 0, TRUE);
+ } else {
+ ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_CHECKED, TRUE);
+ }
+ return 0;
+ } else if (uMsg == BM_GETCHECK) {
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED)
+ return BST_CHECKED;
+ else
+ return BST_UNCHECKED;
+ } else if (uMsg == BM_CLICK) {
+ ALF_NtButton_Clicked(hwnd, priv);
+ return 0;
} else if (uMsg == WM_STYLECHANGED) {
BOOL newDefault = (GetWindowLong(hwnd, GWL_STYLE) & BS_DEFPUSHBUTTON) ? 1 : 0;
@@ -620,8 +857,23 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return (LRESULT)priv->font;
} else if (uMsg == ALF_WM_DPICHANGE) {
priv->dpi = (int)lParam;
+ ALF_NtButton_HandleThemeChange(hwnd, priv); // theme caches bitmaps, need to reload them
ALF_InvalidateLayout(GetParent(hwnd));
return TRUE;
+ } else if (uMsg == ALF_WM_SETBGCOLOR) {
+ ALFColor newcolor = (ALFColor)lParam;
+ if (priv->bgcolor != newcolor) {
+ priv->bgcolor = newcolor;
+ // FIXME! optimize classic button which is not transparent
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
+ } else if (uMsg == ALF_WM_GETBGCOLOR) {
+ return (LRESULT)priv->bgcolor;
+ } else if (uMsg == ALF_WM_BACKGROUNDCHANGE) {
+ if (priv->bgcolor == ALF_COLOR_TRANSPARENT) {
+ // FIXME! optimize classic button which is not transparent
+ InvalidateRect(hwnd, NULL, TRUE);
+ }
} else if (uMsg == WM_SIZE) {
InvalidateRect(hwnd, NULL, TRUE);
} else if (uMsg == WM_UPDATEUISTATE) {
@@ -683,19 +935,27 @@ ALF_RegisterButtonClass(void)
}
static HWND
-ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text)
+ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD addstyle)
{
HWND hwndButton = CreateWindowEx(0,
_alf_buttonClass,
text,
- WS_CHILD | WS_TABSTOP | WS_VISIBLE,
+ WS_CHILD | WS_VISIBLE | addstyle,
0, 0, 100, 100,
win,
(HMENU)(ULONG_PTR)id,
ALF_HINSTANCE,
NULL);
- ALF_AddWidget(win, x, y, hwndButton, 5625, 1725, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE | ALF_LAYOUT_TRANSPARENTBG);
+ int minwidth = 5625;
+ int minheight = 1725;
+
+ if (addstyle & (BS_CHECKBOX | BS_RADIOBUTTON)) {
+ minwidth = 0;
+ minheight = 0;
+ }
+
+ ALF_AddWidget(win, x, y, hwndButton, minwidth, minheight, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE | ALF_LAYOUT_INHERITBGCOLOR | ALF_LAYOUT_SENDBGCHANGE);
return hwndButton;
}
@@ -704,9 +964,13 @@ ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text)
/* Classic Button for Win9x and NT3.51 */
// Win9x/Win32s absolutely needs a real button window, otherwise the dialog manager will get confused
+#define ALF_CLSCBTN_FLAG_IS_DEFAULT ((DWORD)1)
+#define ALF_CLSCBTN_FLAG_DRAW_CHECKBOX ((DWORD)2)
+#define ALF_CLSCBTN_FLAG_IS_CHECKED ((DWORD)4)
+
typedef struct {
WNDPROC origWndProc;
- BOOL isDefault;
+ DWORD flags;
BYTE thunk[12];
} ALFClassicButtonPriv;
@@ -740,7 +1004,7 @@ ALF_ClassicButton_FreePriv(ALFClassicButtonPriv *priv)
}
static void
-ALF_ClassicButton_CalculateSize(HWND hwnd, SIZE *pSize)
+ALF_ClassicButton_CalculateSize(HWND hwnd, ALFClassicButtonPriv *priv, SIZE *pSize)
{
HDC hdc = GetDC(hwnd);
HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
@@ -757,17 +1021,33 @@ ALF_ClassicButton_CalculateSize(HWND hwnd, SIZE *pSize)
ALF_Free(textbuf);
- int xpadding = GetSystemMetrics(SM_CXEDGE) * 2 + 6;
- int ypadding = GetSystemMetrics(SM_CYEDGE) * 2 + 4;
+ if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
+ int checkwidth = 13;
- if (pSize->cx < r.right - r.left + xpadding) {
- pSize->cx = r.right - r.left + xpadding;
- }
- if (pSize->cy < r.bottom - r.top + ypadding) {
- pSize->cy = r.bottom - r.top + ypadding;
- }
- if (pSize->cx < pSize->cy) {
- pSize->cx = pSize->cy;
+ int space = ALF_Button_CalcCheckboxTextSpace(hdc);
+ int cx = checkwidth + space + r.right - r.left + 1;
+ int cy = r.bottom - r.top;
+ if (cy < checkwidth)
+ cy = checkwidth;
+
+ if (pSize->cx < cx)
+ pSize->cx = cx;
+
+ if (pSize->cy < cy)
+ pSize->cy = cy;
+ } else {
+ int xpadding = GetSystemMetrics(SM_CXEDGE) * 2 + 6;
+ int ypadding = GetSystemMetrics(SM_CYEDGE) * 2 + 4;
+
+ if (pSize->cx < r.right - r.left + xpadding) {
+ pSize->cx = r.right - r.left + xpadding;
+ }
+ if (pSize->cy < r.bottom - r.top + ypadding) {
+ pSize->cy = r.bottom - r.top + ypadding;
+ }
+ if (pSize->cx < pSize->cy) {
+ pSize->cx = pSize->cy;
+ }
}
SelectFont(hdc, oldFont);
@@ -776,13 +1056,86 @@ ALF_ClassicButton_CalculateSize(HWND hwnd, SIZE *pSize)
}
static void
-ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
+ALF_ClassicButton_PaintCheckbox(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
+{
+ int checkwidth = 13;
+
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ if (dis->itemAction & ODA_DRAWENTIRE) {
+ //if (priv->bgcolor == ALF_COLOR_TRANSPARENT) {
+ // ALF_Compat_DrawThemeParentBackground(hwnd, dc, rcPaint);
+ //} else {
+ ALF_FillRect(dis->hDC, &dis->rcItem, ALF_COLOR_SYS(COLOR_BTNFACE));
+ //}
+ }
+
+ if (dis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
+ UINT dfcs = DFCS_BUTTONCHECK;
+ if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED)
+ dfcs |= DFCS_CHECKED;
+ if (dis->itemState & ODS_SELECTED)
+ dfcs |= DFCS_PUSHED;
+ if (dis->itemState & ODS_DISABLED)
+ dfcs |= DFCS_INACTIVE;
+
+ RECT rcCheckmark = { 0, 0, checkwidth, checkwidth };
+ rcCheckmark.top += (rcClient.bottom - rcClient.top - checkwidth) / 2;
+ rcCheckmark.bottom = rcCheckmark.top + checkwidth;
+
+ DrawFrameControl(dis->hDC, &rcCheckmark, DFC_BUTTON, dfcs);
+ }
+
+ if (dis->itemAction & (ODA_DRAWENTIRE | ODA_FOCUS)) {
+ // lol
+ int space = ALF_Button_CalcCheckboxTextSpace(dis->hDC);
+
+ RECT rcText = { checkwidth + space,
+ 0,
+ rcClient.right - rcClient.left,
+ rcClient.bottom - rcClient.top };
+
+ TCHAR *textbuf = ALF_Text(hwnd);
+
+ RECT textbounds = rcText;
+ DrawText(dis->hDC, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_EXPANDTABS);
+
+ RECT texttarget = rcText;
+ texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
+ texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+ texttarget.right = texttarget.left + textbounds.right - textbounds.left;
+
+ if (dis->itemAction & ODA_DRAWENTIRE) {
+ UINT style = DT_LEFT | DT_NOCLIP | DT_EXPANDTABS;
+
+ COLORREF oldBkColor = SetBkColor(dis->hDC, GetSysColor(COLOR_BTNFACE));
+ if (dis->itemState & ODS_DISABLED) {
+ ALF_Button_DrawDisabledText(dis->hDC, textbuf, -1, &texttarget, style);
+ } else {
+ DrawText(dis->hDC, textbuf, -1, &texttarget, style);
+ }
+ SetBkColor(dis->hDC, oldBkColor);
+ }
+
+ if (dis->itemState & ODS_FOCUS) {
+ RECT f = texttarget;
+ InflateRect(&f, 1, 0);
+ DrawFocusRect(dis->hDC, &f);
+ }
+
+ ALF_Free(textbuf);
+ }
+}
+
+static void
+ALF_ClassicButton_PaintButton(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
{
RECT r = dis->rcItem;
TCHAR *textbuf = ALF_Text(hwnd);
- if (priv->isDefault) {
+ if (priv->flags & ALF_CLSCBTN_FLAG_IS_DEFAULT) {
HBRUSH framecolor = GetSysColorBrush(COLOR_WINDOWFRAME);
FrameRect(dis->hDC, &r, framecolor);
InflateRect(&r, -1, -1);
@@ -836,6 +1189,16 @@ ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *d
ALF_Free(textbuf);
}
+static void
+ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
+{
+ if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
+ ALF_ClassicButton_PaintCheckbox(hwnd, priv, dis);
+ } else {
+ ALF_ClassicButton_PaintButton(hwnd, priv, dis);
+ }
+}
+
static LRESULT CALLBACK
ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -843,7 +1206,7 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR
return DefWindowProc(hwnd, uMsg, wParam, lParam);
if (uMsg == ALF_WM_QUERYSIZE) {
- ALF_ClassicButton_CalculateSize(hwnd, (SIZE*)lParam);;
+ ALF_ClassicButton_CalculateSize(hwnd, priv, (SIZE*)lParam);
return TRUE;
} else if (uMsg == 0x2000 + WM_DRAWITEM) {
LPDRAWITEMSTRUCT dis = (DRAWITEMSTRUCT *)lParam;
@@ -851,13 +1214,49 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR
ALF_ClassicButton_Paint(hwnd, priv, dis);
return TRUE;
+ } else if (uMsg == 0x2000 + WM_COMMAND) {
+ if (HIWORD(wParam) == BN_CLICKED && priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
+ if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED) {
+ priv->flags &= ~ALF_CLSCBTN_FLAG_IS_CHECKED;
+ } else {
+ priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED;
+ }
+
+ RECT rcCheck;
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ rcCheck.left = 0;
+ rcCheck.top = 0;
+ rcCheck.right = 13;
+ rcCheck.bottom = rcClient.bottom - rcClient.top;
+ InvalidateRect(hwnd, &rcCheck, TRUE);
+ }
} else if (uMsg == WM_ERASEBKGND) {
return TRUE;
} else if (uMsg == BM_SETSTYLE) {
- priv->isDefault = (wParam & BS_DEFPUSHBUTTON);
+ priv->flags &= ~ALF_CLSCBTN_FLAG_IS_DEFAULT;
+ if (wParam & BS_DEFPUSHBUTTON)
+ priv->flags |= ALF_CLSCBTN_FLAG_IS_DEFAULT;
+
wParam = BS_OWNERDRAW;
+ } else if (uMsg == BM_SETCHECK) {
+ priv->flags &= ~ALF_CLSCBTN_FLAG_IS_CHECKED;
+ if (wParam & BST_CHECKED)
+ priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED;
+
+ InvalidateRect(hwnd, NULL, TRUE);
+ return 0;
+ } else if (uMsg == BM_GETCHECK) {
+ if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED) {
+ return BST_CHECKED;
+ } else {
+ return BST_UNCHECKED;
+ }
} else if (uMsg == WM_GETDLGCODE) {
- if (priv->isDefault) {
+ if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
+ return (LRESULT)DLGC_BUTTON;
+ } else if (priv->flags & ALF_CLSCBTN_FLAG_IS_DEFAULT) {
return (LRESULT)DLGC_DEFPUSHBUTTON;
} else {
return (LRESULT)DLGC_UNDEFPUSHBUTTON;
@@ -876,7 +1275,7 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR
}
static HWND
-ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text)
+ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD style)
{
HWND hwndButton = CreateWindowEx(0,
TEXT("BUTTON"),
@@ -889,10 +1288,21 @@ ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text)
NULL);
ALFClassicButtonPriv *priv = ALF_ClassicButton_InitializePriv();
+
+ int minwidth = 5625;
+ int minheight = 1725;
+
+ if (style & BS_CHECKBOX) {
+ minwidth = 0;
+ minheight = 0;
+ priv->flags |= ALF_CLSCBTN_FLAG_DRAW_CHECKBOX;
+ }
+
+
priv->origWndProc = (WNDPROC)GetWindowLongPtr(hwndButton, GWLP_WNDPROC);
SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)priv->thunk);
- ALF_AddWidget(win, x, y, hwndButton, 5625, 1725, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT);
+ ALF_AddWidget(win, x, y, hwndButton, minwidth, minheight, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT);
return hwndButton;
}
@@ -903,9 +1313,19 @@ HWND
ALF_AddButton(HWND win, WORD id, int x, int y, const TCHAR *text)
{
if (_alf_buttonClass) {
- return ALF_NtButton_Create(win, id, x, y, text);
+ return ALF_NtButton_Create(win, id, x, y, text, WS_TABSTOP);
+ } else {
+ return ALF_ClassicButton_Create(win, id, x, y, text, 0);
+ }
+}
+
+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);
} else {
- return ALF_ClassicButton_Create(win, id, x, y, text);
+ return ALF_ClassicButton_Create(win, id, x, y, text, BS_CHECKBOX);
}
}