summaryrefslogtreecommitdiff
path: root/alf/alfbutton.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alf/alfbutton.cpp')
-rw-r--r--alf/alfbutton.cpp1060
1 files changed, 268 insertions, 792 deletions
diff --git a/alf/alfbutton.cpp b/alf/alfbutton.cpp
index 8f8ced4..70e0894 100644
--- a/alf/alfbutton.cpp
+++ b/alf/alfbutton.cpp
@@ -10,30 +10,6 @@
#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 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
@@ -43,10 +19,12 @@
#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 {
+ ALFCustomButtonMeasureFunc measureFunc;
+ ALFCustomButtonPaintFunc paintFunc;
+ void *closure;
+} ALFCustomButtonCreateParams;
typedef struct {
DWORD drawFlags;
@@ -56,58 +34,16 @@ typedef struct {
DWORD uxDrawFlagsCurrent;
DWORD uxDrawFlagsPrev;
DWORD uxDefaultAnimationDuration;
- int uxPartPrev;
- int uxPartCurrent;
int dpi;
HFONT font;
- WCHAR *text;
ALFColor bgcolor;
+ ALFCustomButtonMeasureFunc measureFunc;
+ ALFCustomButtonPaintFunc paintFunc;
+ void *closure;
} ALFNtButtonPriv;
-static BOOL CALLBACK
-ALF_Button_DrawDisabledTextW_DrawStateProc(HDC hdc,
- LPARAM lData,
- WPARAM wData,
- int cx,
- int cy)
-{
- RECT rc = { 0, 0, cx, cy };
- DrawTextW(hdc, (const WCHAR *)lData, -1, &rc, (UINT)wData);
- return TRUE;
-}
-
-static int
-ALF_Button_DrawDisabledTextNtW(HDC hdc,
- LPCWSTR lpchText,
- int cchText,
- LPRECT lprc,
- UINT format)
-{
- (void)cchText;
- return DrawStateW(hdc, NULL, ALF_Button_DrawDisabledTextW_DrawStateProc,
- (LPARAM)lpchText, (WPARAM)format,
- lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top,
- DST_COMPLEX | DSS_DISABLED);
-}
-
-// 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)
+ALF_NtButton_InitializePriv(CREATESTRUCT *cs)
{
ALFNtButtonPriv *priv = ALF_New(ALFNtButtonPriv, 1);
@@ -117,9 +53,13 @@ ALF_NtButton_InitializePriv(CREATESTRUCTW *cs)
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);
- CopyMemory(priv->text, cs->lpszName, l * sizeof(WCHAR));
+ ALFControlCreateParams *ccp = (ALFControlCreateParams *)cs->lpCreateParams;
+ if (ccp->param) {
+ ALFCustomButtonCreateParams *p = (ALFCustomButtonCreateParams *)ccp->param;
+ priv->measureFunc = p->measureFunc;
+ priv->paintFunc = p->paintFunc;
+ priv->closure = p->closure;
+ }
return priv;
}
@@ -128,7 +68,6 @@ static void
ALF_NtButton_FreePriv(ALFNtButtonPriv *priv)
{
ALF_Compat_CloseThemeData(priv->hTheme);
- ALF_Free(priv->text);
ALF_Free(priv);
}
@@ -189,44 +128,25 @@ ALF_NtButton_CalculateSize(HWND hwnd, ALFNtButtonPriv *priv, SIZE *pSize)
HDC hdc = GetDC(hwnd);
HFONT oldFont = SelectFont(hdc, priv->font);
- // calc drawtext style
- UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT;
-
- RECT r = { 0, 0, 0x7FFFFFFF, 100 };
-
- DrawTextW(hdc, priv->text, -1, &r, format);
+ int xpadding = ALF_CentipointsToPixels(600, priv->dpi);
+ int ypadding = ALF_CentipointsToPixels(600, priv->dpi);
- 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);
- 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_CentipointsToPixels(1800, priv->dpi);
- int ypadding = ALF_CentipointsToPixels(600, priv->dpi);
+ SIZE s = { 0, 0 };
+ if (priv->measureFunc) {
+ s = priv->measureFunc(hwnd, priv->closure, priv->dpi, hdc, priv->hTheme, BP_PUSHBUTTON, PBS_NORMAL);
+ }
- 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;
- }
+ if (pSize->cx < s.cx + xpadding) {
+ pSize->cx = s.cx + xpadding;
+ }
+ if (pSize->cy < s.cy + ypadding) {
+ pSize->cy = s.cy + ypadding;
+ }
+ if (pSize->cx < pSize->cy) {
+ pSize->cx = pSize->cy;
}
SelectFont(hdc, oldFont);
-
ReleaseDC(hwnd, hdc);
}
@@ -252,155 +172,47 @@ ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, int uxpart, int uxs
RECT r;
GetClientRect(hwnd, &r);
- if (uxpart == BP_CHECKBOX || uxpart == BP_RADIOBUTTON) {
+ 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);
}
-
- int checkwidth = 12 * priv->dpi / 96 + 1;
-
- RECT rcCheckmark = { 0, 0, checkwidth, checkwidth };
- rcCheckmark.top += (r.bottom - r.top - checkwidth) / 2;
- rcCheckmark.bottom = rcCheckmark.top + checkwidth;
-
- int space = ALF_Button_CalcCheckboxTextSpace(hDC);
-
- RECT rcText = { checkwidth + space,
- 0,
- r.right - r.left,
- r.bottom - r.top };
-
- 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);
-
- 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, 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;
- 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);
-
- 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);
-}
+ ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, rcPaint);
-static void
-ALF_NtButton_RenderClassicCheckbox(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
-{
- int checkwidth = 12 * priv->dpi / 96 + 1;
+ RECT content = r;
+ ALF_Compat_GetThemeBackgroundContentRect(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, &content);
- 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 = 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)
- dfcs |= DFCS_PUSHED;
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
- dfcs |= DFCS_INACTIVE;
+ if ((drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS))
+ DrawFocusRect(hDC, &content);
- RECT rcCheckmark = { 0, 0, checkwidth, checkwidth };
- rcCheckmark.top += (rcClient.bottom - rcClient.top - checkwidth) / 2;
- rcCheckmark.bottom = rcCheckmark.top + checkwidth;
+ UINT itemState = 0;
+ if (drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT)
+ itemState |= ODS_DEFAULT;
+ if (drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ itemState |= ODS_DISABLED;
+ if (drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED)
+ itemState |= ODS_FOCUS;
+ if (drawFlags & ALF_NTBTN_FLAG_IS_HOT)
+ itemState |= ODS_HOTLIGHT;
+ if (drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ itemState |= ODS_SELECTED;
+ if (drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
+ itemState |= ODS_NOACCEL;
+ if (drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)
+ itemState |= ODS_NOFOCUSRECT;
- // 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);
+ if (priv->paintFunc) {
+ priv->paintFunc(hwnd, priv->closure, priv->dpi, itemState, hDC, &content, priv->hTheme, BP_PUSHBUTTON, uxstate);
}
- 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);
+ SelectFont(hDC, oldfont);
}
static void
-ALF_NtButton_RenderClassicPushBtn(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
+ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint)
{
(void)rcPaint;
@@ -427,35 +239,34 @@ ALF_NtButton_RenderClassicPushBtn(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT
DrawFrameControl(dc, &r, DFC_BUTTON, dfcs);
- RECT textbounds = r;
- DrawTextW(dc, priv->text, -1, &textbounds, DT_LEFT | DT_CALCRECT);
- textbounds.bottom++; // this appears to be the secret for correct vertical centering
-
- RECT texttarget = r;
- texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
- texttarget.left += (texttarget.right - texttarget.left - textbounds.right + textbounds.left) / 2;
- texttarget.right = texttarget.left + (textbounds.right - textbounds.left);
- texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
-
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) {
- texttarget.top += 1;
- texttarget.left += 1;
- texttarget.right += 1;
- texttarget.bottom += 1;
- }
+ UINT itemState = 0;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT)
+ itemState |= ODS_DEFAULT;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED)
+ itemState |= ODS_DISABLED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED)
+ itemState |= ODS_FOCUS;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)
+ itemState |= ODS_HOTLIGHT;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED)
+ itemState |= ODS_SELECTED;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
+ itemState |= ODS_NOACCEL;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)
+ itemState |= ODS_NOFOCUSRECT;
- UINT style = DT_CENTER | DT_NOCLIP;
+ if (priv->paintFunc) {
+ RECT c = r;
- if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEACCEL)
- style |= DT_HIDEPREFIX;
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) {
+ c.left += 1;
+ c.top += 1;
+ c.right += 1;
+ c.bottom += 1;
+ }
- 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);
+ priv->paintFunc(hwnd, priv->closure, priv->dpi, itemState, dc, &c, NULL, 0, 0);
}
- SetBkColor(dc, oldBkColor);
if ((priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) {
RECT f = r;
@@ -467,93 +278,31 @@ 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 | ALF_NTBTN_FLAG_DRAW_RADIOBTN)) {
- 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 partid = 0;
- int stateid = 0;
-
- if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
- partid = BP_CHECKBOX;
+ int stateid = PBS_NORMAL;
- 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 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;
-
- 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_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;
@@ -564,12 +313,11 @@ 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 && 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))) {
+ if (priv->uxStateCurrent != priv->uxStatePrev) {
+ if ((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->uxPartCurrent == BP_PUSHBUTTON && priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) {
+ } else if (priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) {
// Win7 misses these transition times, use the one for PBS_DEFAULTED
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
BP_PUSHBUTTON,
@@ -577,7 +325,7 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
PBS_DEFAULTED,
TMT_TRANSITIONDURATION,
&animParams.dwDuration);
- } else if (priv->uxPartCurrent == BP_PUSHBUTTON && priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) {
+ } else if (priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) {
// Win7 misses these transition times, use the one for PBS_DEFAULTED
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
BP_PUSHBUTTON,
@@ -587,24 +335,22 @@ ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r)
&animParams.dwDuration);
} else {
ALF_Compat_GetThemeTransitionDuration(priv->hTheme,
- priv->uxPartCurrent,
+ BP_PUSHBUTTON,
priv->uxStatePrev,
priv->uxStateCurrent,
TMT_TRANSITIONDURATION,
&animParams.dwDuration);
}
- 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)))) {
+ if ((priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
+ && !(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->uxPartCurrent == BP_PUSHBUTTON &&
- (!(priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING)
+ if (!(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);
}
}
@@ -615,16 +361,16 @@ 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) {
if (hdcFrom) {
- ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartPrev, priv->uxStatePrev, priv->uxDrawFlagsPrev, hdcFrom, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, BP_PUSHBUTTON, priv->uxStatePrev, priv->uxDrawFlagsPrev, hdcFrom, r);
}
if (hdcTo) {
- ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartCurrent, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, hdcTo, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, BP_PUSHBUTTON, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, hdcTo, r);
}
ALF_Compat_EndBufferedAnimation(hbpAnimation, TRUE);
} else {
- ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxPartCurrent, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, dc, r);
+ ALF_NtButton_RenderUxtheme(hwnd, priv, BP_PUSHBUTTON, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, dc, r);
}
} else {
// Draw classic unthemed button
@@ -634,56 +380,10 @@ 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)
{
- 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);
- }
- } 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);
+ (void)priv;
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), BN_CLICKED), (LPARAM)hwnd);
}
static LRESULT CALLBACK
@@ -692,14 +392,9 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
ALFNtButtonPriv *priv = (ALFNtButtonPriv *)GetWindowLongPtr(hwnd, 0);
if (uMsg == WM_CREATE) {
- priv = ALF_NtButton_InitializePriv((CREATESTRUCTW *)lParam);
-
- 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;
+ priv = ALF_NtButton_InitializePriv((CREATESTRUCT *)lParam);
- SetWindowLongPtrW(hwnd, 0, (LONG_PTR)priv);
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR)priv);
ALF_NtButton_HandleThemeChange(hwnd, priv);
ALF_NtButton_HandleUIState(hwnd, priv);
@@ -721,16 +416,7 @@ 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_DRAW_CHECKBOX || priv->drawFlags & ALF_NTBTN_FLAG_DRAW_TRISTATE) {
- if (lParam && ((MSG *)lParam)->message == WM_CHAR && (
- ((MSG *)lParam)->wParam == '+' || ((MSG *)lParam)->wParam == '-' || ((MSG *)lParam)->wParam == '=')) {
- return DLGC_WANTCHARS | DLGC_BUTTON;
- }
-
- return DLGC_BUTTON;
- } else if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_RADIOBTN) {
- return DLGC_RADIOBUTTON;
- } else if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) {
+ if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) {
return DLGC_DEFPUSHBUTTON | DLGC_BUTTON;
} else {
return DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON;
@@ -743,21 +429,6 @@ 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);
- }
-
- ALF_NtButton_FixRadioButtonCheck(hwnd, priv, FALSE);
-
- 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;
@@ -800,10 +471,6 @@ 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) {
@@ -847,45 +514,11 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
}
}
}
- } else if (uMsg == WM_CHAR) {
- if (priv->drawFlags & ALF_NTBTN_FLAG_DRAW_CHECKBOX) {
- if (wParam == '+' || wParam == '=') {
- // check
- if (!(priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED)) {
- ALF_NtButton_Clicked(hwnd, priv);
- }
- } else if (wParam == '-') {
- // uncheck
- if (priv->drawFlags & ALF_NTBTN_FLAG_IS_CHECKED) {
- ALF_NtButton_Clicked(hwnd, priv);
- }
- }
- }
} else if (uMsg == WM_ERASEBKGND) {
return TRUE;
} else if (uMsg == WM_SETTEXT) {
- const WCHAR *newtext = (const WCHAR *)lParam;
- if (newtext) {
- SIZE_T len = (SIZE_T)lstrlenW(newtext);
- ALF_Free(priv->text);
- priv->text = ALF_New(WCHAR, len+1);
- CopyMemory(priv->text, newtext, (len+1)*sizeof(WCHAR));
- ALF_InvalidateLayout(GetParent(hwnd));
- return TRUE;
- }
- return FALSE;
- } else if (uMsg == WM_GETTEXTLENGTH) {
- return (LRESULT)lstrlenW(priv->text);
- } else if (uMsg == WM_GETTEXT) {
- if (wParam < 1)
- return 0;
-
- SIZE_T selflen = (SIZE_T)lstrlenW(priv->text);
- SIZE_T buflen = (SIZE_T)wParam - 1;
- SIZE_T tocopy = selflen < buflen ? selflen : buflen;
- CopyMemory((WCHAR*)lParam, priv->text, tocopy * sizeof(WCHAR));
- ((WCHAR*)lParam)[tocopy] = 0;
- return (LRESULT)tocopy;
+ ALF_InvalidateLayout(GetParent(hwnd));
+ InvalidateRect(hwnd, NULL, TRUE);
} else if (uMsg == WM_SETFONT) {
priv->font = (HFONT)wParam;
if (LOWORD(lParam) != 0)
@@ -909,6 +542,7 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
InvalidateRect(hwnd, NULL, TRUE);
}
}
+ return TRUE;
} else if (uMsg == ALF_WM_GETBGCOLOR) {
return (LRESULT)priv->bgcolor;
} else if (uMsg == ALF_WM_BACKGROUNDCHANGE) {
@@ -918,7 +552,7 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} else if (uMsg == WM_SIZE) {
InvalidateRect(hwnd, NULL, TRUE);
} else if (uMsg == WM_UPDATEUISTATE) {
- LRESULT rv = DefWindowProcW(hwnd, uMsg, wParam, lParam);
+ LRESULT rv = DefWindowProc(hwnd, uMsg, wParam, lParam);
ALF_NtButton_HandleUIState(hwnd, priv);
@@ -932,47 +566,31 @@ ALF_NtButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
} else if (uMsg == WM_DESTROY) {
ALF_NtButton_FreePriv(priv);
priv = NULL;
- SetWindowLongPtrW(hwnd, 0, 0);
+ SetWindowLongPtr(hwnd, 0, 0);
}
- return DefWindowProcW(hwnd, uMsg, wParam, lParam);
-}
-
-#ifdef UNICODE
-# define ALF_NtButton_WndProcStart ALF_NtButton_WndProc
-#else
-
-// HACK to get a unicode window
-static LRESULT CALLBACK
-ALF_NtButton_WndProcStart(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
-{
- SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)ALF_NtButton_WndProc);
- WNDPROC thunk = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
- return CallWindowProc(thunk, hwnd, msg, wparam, lparam);
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
-#endif
-
static HWND
-ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD addstyle)
+ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text,
+ ALFCustomButtonMeasureFunc measureFunc,
+ ALFCustomButtonPaintFunc paintFunc, void *closure)
{
+ ALFCustomButtonCreateParams p = { measureFunc, paintFunc, closure };
+
HWND hwndButton = ALF_CreateControlWindow(0,
text,
- WS_CHILD | WS_VISIBLE | addstyle,
+ WS_CHILD | WS_VISIBLE | WS_TABSTOP,
0, 0, 100, 100,
win,
(HMENU)(ULONG_PTR)id,
- ALF_NtButton_WndProcStart,
- NULL);
+ ALF_NtButton_WndProc,
+ &p);
int minwidth = 5625;
int minheight = 1725;
- if (addstyle & (BS_CHECKBOX | BS_RADIOBUTTON | BS_AUTORADIOBUTTON)) {
- minwidth = 0;
- minheight = 0;
- }
-
ALF_AddControl(win, x, y, hwndButton, minwidth, minheight, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE | ALF_LAYOUT_INHERITBGCOLOR | ALF_LAYOUT_SENDBGCHANGE);
return hwndButton;
@@ -983,21 +601,22 @@ ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWORD ad
// 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)
-#define ALF_CLSCBTN_FLAG_DRAW_RADIO ((DWORD)8)
typedef struct {
WNDPROC origWndProc;
DWORD flags;
+ int dpi;
BYTE thunk[12];
+ ALFCustomButtonMeasureFunc measureFunc;
+ ALFCustomButtonPaintFunc paintFunc;
+ void *closure;
} ALFClassicButtonPriv;
static LRESULT CALLBACK
ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static ALFClassicButtonPriv *
-ALF_ClassicButton_InitializePriv(void)
+ALF_ClassicButton_InitializePriv(HWND hwnd)
{
ALFClassicButtonPriv *priv = ALF_New(ALFClassicButtonPriv, 1);
@@ -1013,6 +632,8 @@ ALF_ClassicButton_InitializePriv(void)
DWORD procptr = (DWORD)((ULONG_PTR)ALF_ClassicButton_WndProc - ((ULONG_PTR)priv->thunk + sizeof(priv->thunk)));
CopyMemory(&priv->thunk[8], &procptr, 4);
+ priv->dpi = (int)ALF_Compat_GetDpiForWindow(hwnd); // on Win9x/NT4, DPI will not ever change
+
return priv;
}
@@ -1025,130 +646,36 @@ ALF_ClassicButton_FreePriv(ALFClassicButtonPriv *priv)
static void
ALF_ClassicButton_CalculateSize(HWND hwnd, ALFClassicButtonPriv *priv, SIZE *pSize)
{
+ (void)priv;
+
HDC hdc = GetDC(hwnd);
HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0);
HFONT oldFont = SelectFont(hdc, font);
- // calc drawtext style
- UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT;
-
- RECT r = { 0, 0, 0x7FFFFFFF, 100 };
-
- TCHAR *textbuf = ALF_Text(hwnd);
-
- DrawText(hdc, textbuf, -1, &r, format);
-
- ALF_Free(textbuf);
-
- if (priv->flags & (ALF_CLSCBTN_FLAG_DRAW_CHECKBOX | ALF_CLSCBTN_FLAG_DRAW_RADIO)) {
- int checkwidth = 13;
-
- 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;
+ SIZE s = { 0, 0 };
+ if (priv->measureFunc)
+ s = priv->measureFunc(hwnd, priv->closure, priv->dpi, hdc, NULL, 0, 0);
- if (pSize->cx < cx)
- pSize->cx = cx;
-
- if (pSize->cy < cy)
- pSize->cy = cy;
- } else {
- int xpadding = 24;
- int ypadding = 8;
+ int xpadding = 8;
+ int ypadding = 8;
- 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;
- }
+ if (pSize->cx < s.cx + xpadding) {
+ pSize->cx = s.cx + xpadding;
}
-
- SelectFont(hdc, oldFont);
-
- ReleaseDC(hwnd, hdc);
-}
-
-static void
-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 (pSize->cy < s.cy + ypadding) {
+ pSize->cy = s.cy + ypadding;
}
-
- if (dis->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)) {
- 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)
- 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 (pSize->cx < pSize->cy) {
+ pSize->cx = pSize->cy;
}
- 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_Compat_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);
- }
+ SelectFont(hdc, oldFont);
- ALF_Free(textbuf);
- }
+ ReleaseDC(hwnd, hdc);
}
static void
-ALF_ClassicButton_PaintButton(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
+ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
{
RECT r = dis->rcItem;
@@ -1168,36 +695,18 @@ ALF_ClassicButton_PaintButton(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTR
DrawFrameControl(dis->hDC, &r, DFC_BUTTON, dfcs);
- RECT textbounds = r;
- DrawText(dis->hDC, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_NOCLIP);
- textbounds.bottom++; // this appears to be the secret for correct vertical centering
-
- RECT texttarget = r;
- texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
- texttarget.left += (texttarget.right - texttarget.left - textbounds.right + textbounds.left) / 2;
- texttarget.right = texttarget.left + (textbounds.right - textbounds.left);
- texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
-
- if (dis->itemState & ODS_SELECTED) {
- texttarget.top += 1;
- texttarget.left += 1;
- texttarget.right += 1;
- texttarget.bottom += 1;
- }
-
- UINT style = DT_CENTER;
+ if (priv->paintFunc) {
+ RECT texttarget = r;
- COLORREF oldBkColor = SetBkColor(dis->hDC, GetSysColor(COLOR_BTNFACE));
- if (dis->itemState & ODS_DISABLED) {
- ALF_Compat_DrawDisabledText(dis->hDC, textbuf, -1, &texttarget, style);
- } else {
- COLORREF oldTextColor = SetTextColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
-
- DrawText(dis->hDC, textbuf, -1, &texttarget, style);
+ if (dis->itemState & ODS_SELECTED) {
+ texttarget.top += 1;
+ texttarget.left += 1;
+ texttarget.right += 1;
+ texttarget.bottom += 1;
+ }
- SetTextColor(dis->hDC, oldTextColor);
+ priv->paintFunc(hwnd, priv->closure, priv->dpi, dis->itemState, dis->hDC, &texttarget, NULL, 0, 0);
}
- SetBkColor(dis->hDC, oldBkColor);
if (dis->itemState & ODS_FOCUS) {
RECT f = r;
@@ -1208,74 +717,6 @@ ALF_ClassicButton_PaintButton(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTR
ALF_Free(textbuf);
}
-static void
-ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis)
-{
- 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 void
-ALF_ClassicButton_HandleClick(ALFClassicButtonPriv *priv, HWND hwnd)
-{
- if (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 (priv->flags & ALF_CLSCBTN_FLAG_DRAW_RADIO) {
- priv->flags |= ALF_CLSCBTN_FLAG_IS_CHECKED;
- InvalidateRect(hwnd, NULL, TRUE);
- ALF_ClassicButton_FixRadioButtonCheck(hwnd, priv, TRUE);
- }
-}
-
static LRESULT CALLBACK
ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
@@ -1291,10 +732,6 @@ 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) {
- ALF_ClassicButton_HandleClick(priv, hwnd);
- }
} else if (uMsg == WM_ERASEBKGND) {
return TRUE;
} else if (uMsg == BM_SETSTYLE) {
@@ -1303,59 +740,15 @@ ALF_ClassicButton_WndProc(ALFClassicButtonPriv *priv, HWND hwnd, UINT uMsg, WPAR
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;
-
- ALF_ClassicButton_FixRadioButtonCheck(hwnd, priv, FALSE);
-
- 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->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
- if (lParam && ((MSG *)lParam)->message == WM_CHAR && (
- ((MSG *)lParam)->wParam == '+' || ((MSG *)lParam)->wParam == '-' || ((MSG *)lParam)->wParam == '=')) {
- return DLGC_WANTCHARS | DLGC_BUTTON;
- }
-
- 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) {
+ 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);
- } else if (uMsg == WM_CHAR) {
- if (priv->flags & ALF_CLSCBTN_FLAG_DRAW_CHECKBOX) {
- if (wParam == '+' || wParam == '=') {
- // check
- if (!(priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED)) {
- ALF_ClassicButton_HandleClick(priv, hwnd);
- }
- } else if (wParam == '-') {
- // uncheck
- if (priv->flags & ALF_CLSCBTN_FLAG_IS_CHECKED) {
- ALF_ClassicButton_HandleClick(priv, hwnd);
- }
- }
- }
} else if (uMsg == WM_DESTROY) {
WNDPROC o = priv->origWndProc;
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)o);
@@ -1367,7 +760,8 @@ 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, DWORD style)
+ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text,
+ ALFCustomButtonMeasureFunc measureFunc, ALFCustomButtonPaintFunc paintFunc, void *closure)
{
HWND hwndButton = CreateWindowEx(0,
TEXT("BUTTON"),
@@ -1379,27 +773,14 @@ ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWO
ALF_HINSTANCE,
NULL);
- ALFClassicButtonPriv *priv = ALF_ClassicButton_InitializePriv();
+ ALFClassicButtonPriv *priv = ALF_ClassicButton_InitializePriv(hwndButton);
+ priv->measureFunc = measureFunc;
+ priv->paintFunc = paintFunc;
+ priv->closure = closure;
int minwidth = 5625;
int minheight = 1725;
- 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);
SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)priv->thunk);
@@ -1411,32 +792,127 @@ ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text, DWO
/* Factory and helper functions for both button types */
HWND
-ALF_AddButton(HWND win, WORD id, int x, int y, const TCHAR *text)
+ALF_AddCustomButton(HWND win, WORD id, int x, int y, const TCHAR *text, ALFCustomButtonMeasureFunc measureFunc, ALFCustomButtonPaintFunc paintFunc, void *closure)
{
if (ALF_Compat_Is2k()) {
- return ALF_NtButton_Create(win, id, x, y, text, WS_TABSTOP);
+ return ALF_NtButton_Create(win, id, x, y, text, measureFunc, paintFunc, closure);
} else {
- return ALF_ClassicButton_Create(win, id, x, y, text, 0);
+ return ALF_ClassicButton_Create(win, id, x, y, text, measureFunc, paintFunc, closure);
}
}
-HWND
-ALF_AddCheckbox(HWND win, WORD id, int x, int y, const TCHAR *text)
+/* text measurement and painting functions */
+SIZE
+ALF_CustomButtonMeasureText(HWND btn, void *closure, int dpi, HDC hdc, HANDLE theme, int themePartId, int themeStateId)
{
- if (ALF_Compat_Is2k()) {
- return ALF_NtButton_Create(win, id, x, y, text, WS_TABSTOP | BS_AUTOCHECKBOX);
+ (void)closure;
+
+ RECT r = { 0, 0, 0x7FFFFFFF, 100 };
+
+ if (theme) {
+ int l = GetWindowTextLengthW(btn);
+ WCHAR *text = ALF_New(WCHAR, (SIZE_T)l + 1);
+ GetWindowTextW(btn, text, l + 1);
+
+ ALF_Compat_GetThemeTextExtent(theme, hdc, themePartId, themeStateId, text, -1, DT_LEFT | DT_EXPANDTABS, &r, &r);
+
+ ALF_Free(text);
} else {
- return ALF_ClassicButton_Create(win, id, x, y, text, BS_AUTOCHECKBOX);
+ TCHAR *text = ALF_Text(btn);
+
+ DrawText(hdc, text, -1, &r, DT_LEFT | DT_EXPANDTABS | DT_CALCRECT);
+
+ ALF_Free(text);
}
+
+ int xpadding = ALF_CentipointsToPixels(1200, dpi);
+
+ SIZE s = { r.right - r.left + xpadding, r.bottom - r.top };
+ return s;
}
-HWND
-ALF_AddRadioButton(HWND parent, WORD id, int x, int y, const TCHAR *text)
+void
+ALF_CustomButtonPaintText(HWND btn, void *closure, int dpi, UINT itemState, HDC hdc, RECT *rc, HANDLE theme, int themePartId, int themeStateId)
{
- if (ALF_Compat_Is2k()) {
- return ALF_NtButton_Create(parent, id, x, y, text, BS_AUTORADIOBUTTON);
+ (void)closure; (void)dpi;
+
+ if (theme) {
+ int l = GetWindowTextLengthW(btn);
+ WCHAR *text = ALF_New(WCHAR, (SIZE_T)l + 1);
+ GetWindowTextW(btn, text, l + 1);
+
+ UINT style = DT_CENTER | DT_NOCLIP;
+
+ if (itemState & ODS_NOACCEL)
+ style |= DT_HIDEPREFIX;
+
+ RECT textbounds = *rc;
+ ALF_Compat_GetThemeTextExtent(theme, hdc, themePartId, themeStateId, text, -1, style, rc, &textbounds);
+
+ RECT texttarget = *rc;
+ texttarget.top += ((rc->bottom - rc->top) - (textbounds.bottom - textbounds.top)) / 2;
+ texttarget.left += ((rc->right - rc->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(theme, hdc, themePartId, themeStateId, text, -1, style, 0, &texttarget);
+
+ ALF_Free(text);
} else {
- return ALF_ClassicButton_Create(parent, id, x, y, text, BS_AUTORADIOBUTTON);
+ TCHAR *textbuf = ALF_Text(btn);
+
+ RECT textbounds = *rc;
+ DrawText(hdc, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT | DT_NOCLIP);
+ textbounds.bottom++; // this appears to be the secret for correct vertical centering
+
+ RECT texttarget = *rc;
+ texttarget.top += (texttarget.bottom - texttarget.top - textbounds.bottom + textbounds.top) / 2;
+ texttarget.left += (texttarget.right - texttarget.left - textbounds.right + textbounds.left) / 2;
+ texttarget.right = texttarget.left + (textbounds.right - textbounds.left);
+ texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top);
+
+ UINT style = DT_CENTER;
+
+ COLORREF oldBkColor = SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
+ if (itemState & ODS_DISABLED) {
+ ALF_Compat_DrawDisabledText(hdc, textbuf, -1, &texttarget, style);
+ } else {
+ COLORREF oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
+
+ DrawText(hdc, textbuf, -1, &texttarget, style);
+
+ SetTextColor(hdc, oldTextColor);
+ }
+ SetBkColor(hdc, oldBkColor);
+
+ ALF_Free(textbuf);
}
}
+SIZE
+ALF_CustomButtonMeasureIcon(HWND btn, void *closure, int dpi, HDC hdc, HANDLE theme, int themePartId, int themeState)
+{
+ (void)btn; (void)dpi; (void)hdc; (void)theme; (void)themePartId; (void)themeState;
+
+ return ALF_IconSize((HICON)closure);
+}
+
+void
+ALF_CustomButtonPaintIcon(HWND btn, void *closure, int dpi, UINT itemState, HDC hdc, RECT *rcContent, HANDLE theme, int themePartId, int themeStateId)
+{
+ (void)btn;
+ (void)dpi;
+ (void)itemState;
+ (void)theme;
+ (void)themePartId;
+ (void)themeStateId;
+
+ SIZE iconsize = ALF_IconSize((HICON)closure);
+
+ int iconx = (rcContent->right - rcContent->left - iconsize.cx) / 2;
+ int icony = (rcContent->bottom - rcContent->top - iconsize.cy) / 2;
+
+ DrawIconEx(hdc, rcContent->left + iconx, rcContent->top + icony, ((HICON)closure), 0, 0, 0, NULL, DI_NORMAL);
+}
+
+