diff options
| author | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2020-04-24 21:01:11 +0200 |
|---|---|---|
| committer | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2020-04-24 21:01:11 +0200 |
| commit | 0dee09478a7b975b3921478966d4c78b7a032189 (patch) | |
| tree | 07316cf55c87b1eeb11f5e3fa029acf87ccf8678 /alf/alfbutton.cpp | |
| parent | 6280671b1897ac0a47cb7e8f3463d4f60f2490cc (diff) | |
button class redesign
now using completely custom control on NT, and a stripped down owner-drawn
version on Win9x. The old Win3.1 rendering style has been removed, buttons
on NT 3.51 and Win32s will now look like on Win95.
Diffstat (limited to 'alf/alfbutton.cpp')
| -rw-r--r-- | alf/alfbutton.cpp | 946 |
1 files changed, 630 insertions, 316 deletions
diff --git a/alf/alfbutton.cpp b/alf/alfbutton.cpp index 579fdce..667287a 100644 --- a/alf/alfbutton.cpp +++ b/alf/alfbutton.cpp @@ -1,5 +1,7 @@ #include "alfpriv.h" +/* Themed "NT" Button for Win2k and up */ + #define BP_PUSHBUTTON 1 #define PBS_NORMAL 1 #define PBS_HOT 2 @@ -8,36 +10,155 @@ #define PBS_DEFAULTED 5 #define PBS_DEFAULTED_ANIMATING 6 +#define ALF_NTBTN_FLAG_UXTHEME 1 +#define ALF_NTBTN_FLAG_IS_DISABLED 2 +#define ALF_NTBTN_FLAG_IS_DEFAULT 4 +#define ALF_NTBTN_FLAG_IS_HOT 8 +#define ALF_NTBTN_FLAG_IS_FOCUSED 16 +#define ALF_NTBTN_FLAG_IS_PRESSED 32 +#define ALF_NTBTN_FLAG_HIDEFOCUS 64 +#define ALF_NTBTN_FLAG_HIDEACCEL 128 +#define ALF_NTBTN_FLAG_DEFAULT_ANIMATING 256 typedef struct { - BOOL isDefault; - BOOL isHot; + DWORD drawFlags; HTHEME hTheme; int uxStatePrev; int uxStateCurrent; - UINT itemStatePrev; - UINT itemStateCurrent; + DWORD uxDrawFlagsCurrent; + DWORD uxDrawFlagsPrev; DWORD uxDefaultAnimationDuration; - BOOL uxIsDefaultAnimating; int dpi; -} ALFButtonPriv; + HFONT font; +} ALFNtButtonPriv; + +TCHAR *_alf_buttonClass = NULL; + +static ALFNtButtonPriv * +ALF_NtButton_InitializePriv(void) +{ + ALFNtButtonPriv *priv = ALF_New(ALFNtButtonPriv, 1); + + priv->drawFlags = ALF_NTBTN_FLAG_UXTHEME; + priv->uxStateCurrent = -1; + priv->uxStatePrev = -1; + priv->dpi = 96; + + return priv; +} + +static void +ALF_NtButton_FreePriv(ALFNtButtonPriv *priv) +{ + ALF_Compat_CloseThemeData(priv->hTheme); + ALF_Free(priv); +} + +static void +ALF_NtButton_ModifyDrawFlags(HWND hwnd, ALFNtButtonPriv *priv, DWORD add, DWORD remove, BOOL redraw) +{ + DWORD newFlags = priv->drawFlags; + newFlags |= add; + newFlags &= ~remove; + + if (newFlags != priv->drawFlags) { + priv->drawFlags = newFlags; + if (redraw) { + InvalidateRect(hwnd, NULL, TRUE); + } + } +} + +static void +ALF_NtButton_HandleUIState(HWND hwnd, ALFNtButtonPriv *priv) +{ + LRESULT uiState = SendMessage(hwnd, WM_QUERYUISTATE, 0, 0); + DWORD add = 0; + DWORD remove = 0; + if (uiState & UISF_HIDEACCEL) { + add |= ALF_NTBTN_FLAG_HIDEACCEL; + } else { + remove |= ALF_NTBTN_FLAG_HIDEACCEL; + } + if (uiState & UISF_HIDEFOCUS) { + add |= ALF_NTBTN_FLAG_HIDEFOCUS; + } else { + remove |= ALF_NTBTN_FLAG_HIDEFOCUS; + } + ALF_NtButton_ModifyDrawFlags(hwnd, priv, add, remove, TRUE); +} + +static void +ALF_NtButton_HandleThemeChange(HWND hwnd, ALFNtButtonPriv *priv) +{ + ALF_Compat_CloseThemeData(priv->hTheme); + priv->hTheme = NULL; + if (ALF_Compat_IsAppThemed()) + priv->hTheme = ALF_Compat_OpenThemeData(hwnd, L"Button"); + priv->uxDefaultAnimationDuration = 0; + ALF_Compat_GetThemeTransitionDuration(priv->hTheme, + BP_PUSHBUTTON, + PBS_DEFAULTED, + PBS_DEFAULTED_ANIMATING, + TMT_TRANSITIONDURATION, + &priv->uxDefaultAnimationDuration); + InvalidateRect(hwnd, NULL, TRUE); +} + +static void +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 }; + + TCHAR *textbuf = ALF_Text(hwnd); + + DrawText(hdc, textbuf, -1, &r, format); + + ALF_Free(textbuf); + + 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); + + ReleaseDC(hwnd, hdc); +} static void CALLBACK -ALF__Button_DefaultAnimatingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +ALF_NtButton_DefaultAnimatingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { (void)uMsg; (void)dwTime; - ALFButtonPriv *priv = (ALFButtonPriv *)idEvent; + ALFNtButtonPriv *priv = (ALFNtButtonPriv *)idEvent; - priv->uxIsDefaultAnimating = !priv->uxIsDefaultAnimating; - InvalidateRect(hwnd, NULL, FALSE); + if (priv->drawFlags & ALF_NTBTN_FLAG_DEFAULT_ANIMATING) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_DEFAULT_ANIMATING, TRUE); + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_DEFAULT_ANIMATING, 0, TRUE); + } } static BOOL CALLBACK -ALF__Button_Text_DrawStateProc(HDC hdc, LPARAM lData, WPARAM wData, int cx, int cy) +ALF_NtButton_Text_DrawStateProc(HDC hdc, LPARAM lData, WPARAM wData, int cx, int cy) { - (void)wData; - int oldBkMode = SetBkMode(hdc, TRANSPARENT); RECT r = { 0, 0, cx, cy }; @@ -49,21 +170,23 @@ ALF__Button_Text_DrawStateProc(HDC hdc, LPARAM lData, WPARAM wData, int cx, int } static void -ALF__Button_RenderUxtheme(HWND hwnd, ALFButtonPriv *priv, int uxstate, UINT itemState, HDC hDC, LPRECT pRcItem) +ALF_NtButton_RenderUxtheme(HWND hwnd, ALFNtButtonPriv *priv, 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, pRcItem); + ALF_Compat_DrawThemeParentBackground(hwnd, hDC, rcPaint); } - RECT r = *pRcItem; - InflateRect(&r, 1, 1); // HACK! get rid of 1px transparent border + RECT r; + GetClientRect(hwnd, &r); - ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, pRcItem); + 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 ((itemState & ODS_FOCUS) && !(itemState & ODS_NOFOCUSRECT)) + if ((drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) DrawFocusRect(hDC, &content); int textlen = GetWindowTextLengthW(hwnd); @@ -72,7 +195,7 @@ ALF__Button_RenderUxtheme(HWND hwnd, ALFButtonPriv *priv, int uxstate, UINT item UINT style = DT_CENTER; - if (itemState & ODS_NOACCEL) + if (drawFlags & ALF_NTBTN_FLAG_HIDEACCEL) style |= DT_HIDEPREFIX; RECT textbounds = content; @@ -87,47 +210,56 @@ ALF__Button_RenderUxtheme(HWND hwnd, ALFButtonPriv *priv, int uxstate, UINT item ALF_Compat_DrawThemeText(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, textbuf, -1, style, 0, &texttarget); ALF_Free(textbuf); + + SelectFont(hDC, oldfont); } static void -ALF__Button_Render95(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) +ALF_NtButton_RenderClassic(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *rcPaint) { - RECT r = dis->rcItem; + (void)rcPaint; + + RECT rcClient; + GetClientRect(hwnd, &rcClient); + + HFONT oldfont = SelectFont(dc, priv->font); + + RECT r = rcClient; TCHAR *textbuf = ALF_Text(hwnd); - if (priv->isDefault) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) { HBRUSH framecolor = GetSysColorBrush(COLOR_WINDOWFRAME); - FrameRect(dis->hDC, &r, framecolor); + FrameRect(dc, &r, framecolor); InflateRect(&r, -1, -1); } UINT dfcs = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT; - if (dis->itemState & ODS_SELECTED) + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) dfcs |= DFCS_FLAT; - if (dis->itemState & ODS_DISABLED) + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) dfcs |= DFCS_INACTIVE; - if (dis->itemState & ODS_HOTLIGHT) + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT) dfcs |= DFCS_HOT; - DrawFrameControl(dis->hDC, &r, DFC_BUTTON, dfcs); + DrawFrameControl(dc, &r, DFC_BUTTON, dfcs); - if ((dis->itemState & ODS_FOCUS) && !(dis->itemState & ODS_NOFOCUSRECT)) { + if ((priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED) && !(priv->drawFlags & ALF_NTBTN_FLAG_HIDEFOCUS)) { RECT f = r; InflateRect(&f, -1, -1); - DrawFocusRect(dis->hDC, &f); + DrawFocusRect(dc, &f); } - RECT textbounds = dis->rcItem; - DrawText(dis->hDC, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT); + RECT textbounds = rcClient; + DrawText(dc, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT); - RECT texttarget = dis->rcItem; - texttarget.top += ((dis->rcItem.bottom - dis->rcItem.top) - (textbounds.bottom - textbounds.top)) / 2 - 1; - texttarget.left += ((dis->rcItem.right - dis->rcItem.left) - (textbounds.right - textbounds.left)) / 2; + RECT texttarget = rcClient; + texttarget.top += ((rcClient.bottom - rcClient.top) - (textbounds.bottom - textbounds.top)) / 2 - 1; + texttarget.left += ((rcClient.right - rcClient.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) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) { texttarget.top += 1; texttarget.left += 1; texttarget.right += 1; @@ -136,101 +268,447 @@ ALF__Button_Render95(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) UINT style = DT_CENTER; - if (dis->itemState & ODS_NOACCEL) + if (priv->drawFlags & ALF_NTBTN_FLAG_HIDEACCEL) style |= DT_HIDEPREFIX; - if (dis->itemState & ODS_DISABLED) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DISABLED) { if (ALF_Compat_IsWin9x()) { // Win9x just uses gray text. DSS_DISABLED is broken there, too, // so we can't get the NT look even if we wanted to - COLORREF oldTextColor = SetTextColor(dis->hDC, GetSysColor(COLOR_GRAYTEXT)); + COLORREF oldTextColor = SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT)); POINT oldorg = { 0, 0 }; - SetViewportOrgEx(dis->hDC, texttarget.left, texttarget.top, &oldorg); - ALF__Button_Text_DrawStateProc(dis->hDC, (LPARAM)textbuf, (WPARAM)style, + SetViewportOrgEx(dc, texttarget.left, texttarget.top, &oldorg); + ALF_NtButton_Text_DrawStateProc(dc, (LPARAM)textbuf, (WPARAM)style, texttarget.right - texttarget.left, texttarget.bottom - texttarget.top); - SetViewportOrgEx(dis->hDC, oldorg.x, oldorg.y, NULL); + SetViewportOrgEx(dc, oldorg.x, oldorg.y, NULL); - SetTextColor(dis->hDC, oldTextColor); + SetTextColor(dc, oldTextColor); } else { - DrawState(dis->hDC, NULL, ALF__Button_Text_DrawStateProc, - (LPARAM)textbuf, (WPARAM)style, - texttarget.left, texttarget.top, - texttarget.right - texttarget.left, texttarget.bottom - texttarget.top, - DST_COMPLEX | DSS_DISABLED); + DrawState(dc, NULL, ALF_NtButton_Text_DrawStateProc, + (LPARAM)textbuf, (WPARAM)style, + texttarget.left, texttarget.top, + texttarget.right - texttarget.left, texttarget.bottom - texttarget.top, + DST_COMPLEX | DSS_DISABLED); } } else { POINT oldorg = { 0, 0 }; - SetViewportOrgEx(dis->hDC, texttarget.left, texttarget.top, &oldorg); - ALF__Button_Text_DrawStateProc(dis->hDC, (LPARAM)textbuf, (WPARAM)style, - texttarget.right - texttarget.left, texttarget.bottom - texttarget.top); - SetViewportOrgEx(dis->hDC, oldorg.x, oldorg.y, NULL); + SetViewportOrgEx(dc, texttarget.left, texttarget.top, &oldorg); + ALF_NtButton_Text_DrawStateProc(dc, (LPARAM)textbuf, (WPARAM)style, + texttarget.right - texttarget.left, texttarget.bottom - texttarget.top); + SetViewportOrgEx(dc, oldorg.x, oldorg.y, NULL); } + SelectFont(dc, oldfont); ALF_Free(textbuf); } static void -ALF__Button_Render3x(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) +ALF_NtButton_Paint(HWND hwnd, ALFNtButtonPriv *priv, HDC dc, RECT *r) { - RECT r = dis->rcItem; + if (!ALF_Compat_BufferedPaintRenderAnimation(hwnd, dc)) { + if ((priv->drawFlags & ALF_NTBTN_FLAG_UXTHEME) && priv->hTheme) { + // Draw XP style themed button + int 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->uxDrawFlagsCurrent = priv->drawFlags; + + if (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) + priv->uxStateCurrent = PBS_NORMAL; + } + + priv->uxStatePrev = priv->uxStateCurrent; + priv->uxStateCurrent = stateid; + priv->uxDrawFlagsPrev = priv->uxDrawFlagsCurrent; + priv->uxDrawFlagsCurrent = priv->drawFlags; + + ALF_Compat_BP_ANIMATIONPARAMS animParams; + ZeroMemory(&animParams, sizeof(animParams)); + 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)) { + animParams.dwDuration = priv->uxDefaultAnimationDuration; + } 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, + priv->uxStatePrev, + PBS_DEFAULTED, + TMT_TRANSITIONDURATION, + &animParams.dwDuration); + } 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, + PBS_DEFAULTED, + priv->uxStateCurrent, + TMT_TRANSITIONDURATION, + &animParams.dwDuration); + } else { + ALF_Compat_GetThemeTransitionDuration(priv->hTheme, + BP_PUSHBUTTON, + 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)) { + 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) + && (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) + && priv->uxDefaultAnimationDuration) { + SetTimer(hwnd, (UINT_PTR)priv, priv->uxDefaultAnimationDuration, ALF_NtButton_DefaultAnimatingTimerProc); + } + } + + HDC hdcFrom = NULL, hdcTo = NULL; + ALF_Compat_HANIMATIONBUFFER hbpAnimation; + + 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); + } + + if (hdcTo) { + SelectFont(hdcTo, font); + ALF_NtButton_RenderUxtheme(hwnd, priv, priv->uxStateCurrent, priv->uxDrawFlagsCurrent, hdcTo, r); + } + + ALF_Compat_EndBufferedAnimation(hbpAnimation, TRUE); + } else { + ALF_NtButton_RenderUxtheme(hwnd, priv, stateid, priv->uxDrawFlagsCurrent, dc, r); + } + } else { + // Draw classic unthemed button + ALF_NtButton_RenderClassic(hwnd, priv, dc, r); + } + } +} + +static void +ALF_NtButton_Clicked(HWND hwnd, ALFNtButtonPriv *priv) +{ + (void)priv; + SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLong(hwnd, GWL_ID), BN_CLICKED), (LPARAM)hwnd); +} + +static LRESULT CALLBACK +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(); + + SetWindowLongPtr(hwnd, 0, (LONG_PTR)priv); + + ALF_NtButton_HandleThemeChange(hwnd, priv); + ALF_NtButton_HandleUIState(hwnd, priv); + } else if (uMsg == ALF_WM_QUERYSIZE) { + ALF_NtButton_CalculateSize(hwnd, priv, (SIZE*)lParam);; + return TRUE; + } else if (uMsg == WM_PAINT) { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + ALF_NtButton_Paint(hwnd, priv, hdc, &ps.rcPaint); + + EndPaint(hwnd, &ps); + + return TRUE; + } else if (uMsg == WM_PRINTCLIENT) { + RECT rc; + GetClientRect(hwnd, &rc); + + ALF_NtButton_Paint(hwnd, priv, (HDC)wParam, &rc); + } else if (uMsg == WM_GETDLGCODE) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_DEFAULT) { + return DLGC_DEFPUSHBUTTON | DLGC_BUTTON; + } else { + return DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON; + } + } else if (uMsg == BM_SETSTYLE) { + BOOL newDefault = (wParam & BS_DEFPUSHBUTTON) ? 1 : 0; + + if (newDefault) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_DEFAULT, 0, TRUE); + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_DEFAULT, TRUE); + } + } else if (uMsg == WM_STYLECHANGED) { + BOOL newDefault = (GetWindowLong(hwnd, GWL_STYLE) & BS_DEFPUSHBUTTON) ? 1 : 0; + + if (newDefault) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_DEFAULT, 0, TRUE); + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_DEFAULT, TRUE); + } + } else if (uMsg == WM_THEMECHANGED) { + ALF_NtButton_HandleThemeChange(hwnd, priv); + } else if (uMsg == WM_MOUSEMOVE) { + if (!(priv->drawFlags & ALF_NTBTN_FLAG_IS_HOT)) { + TRACKMOUSEEVENT tme; + ZeroMemory(&tme, sizeof(tme)); + tme.cbSize = sizeof(tme); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd; + if (ALF_Compat_TrackMouseEvent(&tme)) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_HOT, 0, TRUE); + } + } + + RECT rcWindow; + GetWindowRect(hwnd, &rcWindow); + + DWORD pos = GetMessagePos(); + + if (GET_X_LPARAM(pos) >= rcWindow.left && GET_X_LPARAM(pos) < rcWindow.right + && GET_Y_LPARAM(pos) >= rcWindow.top && GET_Y_LPARAM(pos) < rcWindow.bottom) { + if (wParam & MK_LBUTTON) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_PRESSED, 0, TRUE); + } + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_PRESSED, TRUE); + } + } else if (uMsg == WM_MOUSELEAVE) { + 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); + } 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) { + if (IsWindowEnabled(hwnd)) { + if (!(priv->drawFlags & ALF_NTBTN_FLAG_IS_FOCUSED)) { + SetFocus(hwnd); + } + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_PRESSED, 0, TRUE); + SetCapture(hwnd); + } + return 0; + } else if (uMsg == WM_LBUTTONUP) { + ReleaseCapture(); + + if (IsWindowEnabled(hwnd)) { + RECT rcClient; + GetClientRect(hwnd, &rcClient); + + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_PRESSED, TRUE); + + if (GET_X_LPARAM(lParam) >= rcClient.left && GET_X_LPARAM(lParam) < rcClient.right + && GET_Y_LPARAM(lParam) >= rcClient.top && GET_Y_LPARAM(lParam) < rcClient.bottom) { + ALF_NtButton_Clicked(hwnd, priv); + } + } + return 0; + } else if (uMsg == WM_KEYDOWN) { + if (GetCapture() != hwnd && IsWindowEnabled(hwnd)) { + if (wParam == VK_SPACE && LOWORD(lParam) == 1) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_PRESSED, 0, TRUE); + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_PRESSED, TRUE); + } + } + } else if (uMsg == WM_KEYUP) { + if (GetCapture() != hwnd && IsWindowEnabled(hwnd)) { + if (wParam == VK_SPACE) { + if (priv->drawFlags & ALF_NTBTN_FLAG_IS_PRESSED) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_PRESSED, TRUE); + ALF_NtButton_Clicked(hwnd, priv); + } + } + } + } else if (uMsg == WM_ERASEBKGND) { + return TRUE; + } else if (uMsg == WM_SETTEXT) { + ALF_InvalidateLayout(GetParent(hwnd)); + } else if (uMsg == WM_SETFONT) { + priv->font = (HFONT)wParam; + if (LOWORD(lParam) != 0) + InvalidateRect(hwnd, NULL, TRUE); + + ALF_InvalidateLayout(GetParent(hwnd)); + + return 0; + } else if (uMsg == WM_GETFONT) { + return (LRESULT)priv->font; + } else if (uMsg == ALF_WM_DPICHANGE) { + priv->dpi = (int)lParam; + ALF_InvalidateLayout(GetParent(hwnd)); + return TRUE; + } else if (uMsg == WM_SIZE) { + InvalidateRect(hwnd, NULL, TRUE); + } else if (uMsg == WM_UPDATEUISTATE) { + LRESULT rv = DefWindowProc(hwnd, uMsg, wParam, lParam); + + ALF_NtButton_HandleUIState(hwnd, priv); + + return rv; + } else if (uMsg == WM_ENABLE) { + if (wParam) { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, 0, ALF_NTBTN_FLAG_IS_DISABLED, TRUE); + } else { + ALF_NtButton_ModifyDrawFlags(hwnd, priv, ALF_NTBTN_FLAG_IS_DISABLED, ALF_NTBTN_FLAG_IS_PRESSED, TRUE); + } + } else if (uMsg == WM_DESTROY) { + ALF_NtButton_FreePriv(priv); + priv = NULL; + SetWindowLongPtr(hwnd, 0, 0); + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void +ALF_RegisterButtonClass(void) +{ + if (ALF_Compat_IsWin9x() || !ALF_Compat_IsMinWindowsVersion(4, 0)) + return; // use classic button on Win9x and NT 3.51 + + WNDCLASS cls; + ZeroMemory(&cls, sizeof(cls)); + + TCHAR classNameBuf[256]; + ALF_BuildUniqueName(classNameBuf, TEXT("ALFNtButton."), (ULONG_PTR)&_alf_buttonClass); + + cls.hInstance = ALF_HINSTANCE; + cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); + cls.lpszClassName = classNameBuf; + cls.cbWndExtra = sizeof(void*); + cls.lpfnWndProc = ALF_NtButton_WndProc; + + ATOM classatom = RegisterClass(&cls); + if (!classatom) + MessageBox(NULL, TEXT("FATAL: Could not register button class"), NULL, MB_OK); + + _alf_buttonClass = MAKEINTATOM(classatom); +} + +static HWND +ALF_NtButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text) +{ + HWND hwndButton = CreateWindowEx(0, + _alf_buttonClass, + text, + WS_CHILD | WS_TABSTOP | WS_VISIBLE, + 0, 0, 100, 100, + win, + (HMENU)(int)id, + ALF_HINSTANCE, + NULL); + + ALF_AddWidget(win, x, y, hwndButton, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE | ALF_LAYOUT_TRANSPARENTBG); + + return hwndButton; +} + + +/* Classic Button for Win9x and NT3.51 */ +// Win9x/Win32s absolutely needs a real button window, otherwise the dialog manager will get confused + +typedef struct { + WNDPROC origWndProc; + BOOL isDefault; +} ALFClassicButtonPriv; + +static ALFClassicButtonPriv * +ALF_ClassicButton_InitializePriv(void) +{ + return ALF_New(ALFClassicButtonPriv, 1); +} + +static void +ALF_ClassicButton_FreePriv(ALFClassicButtonPriv *priv) +{ + ALF_Free(priv); +} + +static void +ALF_ClassicButton_CalculateSize(HWND hwnd, SIZE *pSize) +{ + HDC hdc = GetDC(hwnd); + HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); + HFONT oldFont = SelectFont(hdc, font); - ALF_Compat_DrawThemeParentBackground(hwnd, dis->hDC, &r); + // calc drawtext style + UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT; + + RECT r = { 0, 0, 0x7FFFFFFF, 100 }; TCHAR *textbuf = ALF_Text(hwnd); - HBRUSH framecolor = GetSysColorBrush(COLOR_WINDOWFRAME); - HBRUSH facecolor = GetSysColorBrush(COLOR_BTNFACE); + DrawText(hdc, textbuf, -1, &r, format); - // black frame - if (priv->isDefault) { - RECT rt = { r.left + 1, r.top, r.right - 1, r.top + 2 }; - RECT rl = { r.left, r.top + 1, r.left + 2, r.bottom - 1 }; - RECT rr = { r.right - 2, r.top + 1, r.right, r.bottom - 1 }; - RECT rb = { r.left + 1, r.bottom - 2, r.right - 1, r.bottom }; - FillRect(dis->hDC, &rt, framecolor); - FillRect(dis->hDC, &rl, framecolor); - FillRect(dis->hDC, &rr, framecolor); - FillRect(dis->hDC, &rb, framecolor); - InflateRect(&r, -2, -2); - } else { - RECT rt = { r.left + 1, r.top, r.right - 1, r.top + 1 }; - RECT rl = { r.left, r.top + 1, r.left + 1, r.bottom - 1 }; - RECT rr = { r.right - 1, r.top + 1, r.right, r.bottom - 1 }; - RECT rb = { r.left + 1, r.bottom - 1, r.right - 1, r.bottom }; - FillRect(dis->hDC, &rt, framecolor); - FillRect(dis->hDC, &rl, framecolor); - FillRect(dis->hDC, &rr, framecolor); - FillRect(dis->hDC, &rb, framecolor); - InflateRect(&r, -1, -1); + ALF_Free(textbuf); + + 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; } - // 3d button - if (dis->itemState & ODS_SELECTED) { - DrawEdge(dis->hDC, &r, BDR_SUNKENOUTER, BF_TOPLEFT); + SelectFont(hdc, oldFont); - RECT f = r; - f.left++; - f.top++; + ReleaseDC(hwnd, hdc); +} - FillRect(dis->hDC, &f, facecolor); +static void +ALF_ClassicButton_Paint(HWND hwnd, ALFClassicButtonPriv *priv, DRAWITEMSTRUCT *dis) +{ + RECT r = dis->rcItem; - InflateRect(&r, -2, -2); - } else { - DrawEdge(dis->hDC, &r, BDR_RAISEDINNER, BF_RECT); - InflateRect(&r, -1, -1); - DrawEdge(dis->hDC, &r, BDR_RAISEDINNER, BF_RECT); - InflateRect(&r, -1, -1); + TCHAR *textbuf = ALF_Text(hwnd); - FillRect(dis->hDC, &r, facecolor); + if (priv->isDefault) { + HBRUSH framecolor = GetSysColorBrush(COLOR_WINDOWFRAME); + FrameRect(dis->hDC, &r, framecolor); + InflateRect(&r, -1, -1); } + UINT dfcs = DFCS_BUTTONPUSH | DFCS_ADJUSTRECT; + if (dis->itemState & ODS_SELECTED) + dfcs |= DFCS_FLAT; + if (dis->itemState & ODS_DISABLED) + dfcs |= DFCS_INACTIVE; + + DrawFrameControl(dis->hDC, &r, DFC_BUTTON, dfcs); + RECT textbounds = dis->rcItem; DrawText(dis->hDC, textbuf, -1, &textbounds, DT_LEFT | DT_CALCRECT); RECT texttarget = dis->rcItem; - texttarget.top += ((dis->rcItem.bottom - dis->rcItem.top) - (textbounds.bottom - textbounds.top)) / 2; + texttarget.top += ((dis->rcItem.bottom - dis->rcItem.top) - (textbounds.bottom - textbounds.top)) / 2 - 1; texttarget.left += ((dis->rcItem.right - dis->rcItem.left) - (textbounds.right - textbounds.left)) / 2; texttarget.right = texttarget.left + (textbounds.right - textbounds.left); texttarget.bottom = texttarget.top + (textbounds.bottom - textbounds.top); @@ -242,274 +720,110 @@ ALF__Button_Render3x(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) texttarget.bottom += 1; } - if (dis->itemState & ODS_FOCUS) { - DrawFocusRect(dis->hDC, &texttarget); - } - - int oldBkMode = SetBkMode(dis->hDC, TRANSPARENT); + UINT style = DT_CENTER; + COLORREF oldBkColor = SetBkColor(dis->hDC, GetSysColor(COLOR_BTNFACE)); if (dis->itemState & ODS_DISABLED) { - // FIXME! This is how NT 3.51 does it, but Win 3.1 is different - COLORREF oldTextColor = SetTextColor(dis->hDC, GetSysColor(COLOR_BTNSHADOW)); + // Win9x just uses gray text. DSS_DISABLED is broken there, too, + // so we can't get the NT look even if we wanted to + COLORREF disabledColor = ALF_Compat_IsMinWindowsVersion(4, 0) ? GetSysColor(COLOR_GRAYTEXT) : GetSysColor(COLOR_BTNSHADOW); + COLORREF oldTextColor = SetTextColor(dis->hDC, disabledColor); - DrawText(dis->hDC, textbuf, -1, &texttarget, DT_CENTER); + DrawText(dis->hDC, textbuf, -1, &texttarget, style); SetTextColor(dis->hDC, oldTextColor); } else { - DrawText(dis->hDC, textbuf, -1, &texttarget, DT_CENTER); + COLORREF oldTextColor = SetTextColor(dis->hDC, GetSysColor(COLOR_BTNTEXT)); + + DrawText(dis->hDC, textbuf, -1, &texttarget, style); + + SetTextColor(dis->hDC, oldTextColor); } + SetBkColor(dis->hDC, oldBkColor); - SetBkMode(dis->hDC, oldBkMode); + if (dis->itemState & ODS_FOCUS) { + RECT f = r; + InflateRect(&f, -1, -1); + DrawFocusRect(dis->hDC, &f); + } ALF_Free(textbuf); } -/* BUTTON */ static LRESULT CALLBACK -ALF__ButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +ALF_ClassicButton_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - (void)uIdSubclass; - (void)dwRefData; - - ALFButtonPriv *priv = (ALFButtonPriv *)dwRefData; + ALFClassicButtonPriv *priv = (ALFClassicButtonPriv *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (!priv) + return DefWindowProc(hwnd, uMsg, wParam, lParam); if (uMsg == ALF_WM_QUERYSIZE) { - HDC hdc = GetDC(hwnd); - HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); - HFONT oldFont = 0; - if (font) - oldFont = SelectFont(hdc, font); - - // calc drawtext style - LONG style = GetWindowLong(hwnd, GWL_STYLE); - UINT format = DT_LEFT | DT_EXPANDTABS | DT_CALCRECT; - if ((style & BS_MULTILINE) == 0) - format |= DT_SINGLELINE; - - RECT r = { 0, 0, 0x7FFFFFFF, 100 }; - - TCHAR *textbuf = ALF_Text(hwnd); - - DrawText(hdc, textbuf, -1, &r, format); - - ALF_Free(textbuf); - - int xpadding = ALF_Compat_GetSystemMetricsForDpi(SM_CXEDGE, - (UINT)priv->dpi) * 2 + 6; - int ypadding = ALF_Compat_GetSystemMetricsForDpi(SM_CYEDGE, - (UINT)priv->dpi) * 2 + 4; - - SIZE *pSize = (SIZE*)(void*)lParam; - 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 (font) - SelectFont(hdc, oldFont); - - ReleaseDC(hwnd, hdc); + ALF_ClassicButton_CalculateSize(hwnd, (SIZE*)lParam);; + return TRUE; } else if (uMsg == 0x2000 + WM_DRAWITEM) { LPDRAWITEMSTRUCT dis = (DRAWITEMSTRUCT *)lParam; - if (!ALF_Compat_BufferedPaintRenderAnimation(hwnd, dis->hDC)) { - if (priv->hTheme) { - // Draw XP style themed button - int stateid = PBS_NORMAL; - - if (priv->isDefault && IsChild(GetForegroundWindow(), hwnd)) - stateid = priv->uxIsDefaultAnimating ? PBS_DEFAULTED_ANIMATING : PBS_DEFAULTED; - if (priv->isHot) - stateid = PBS_HOT; - if (dis->itemState & ODS_SELECTED) - stateid = PBS_PRESSED; - if (dis->itemState & ODS_DISABLED) - stateid = PBS_DISABLED; - - if (priv->uxStatePrev == -1) { - // initial draw - priv->uxStateCurrent = stateid; - priv->itemStateCurrent = dis->itemState; - - if (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) - priv->uxStateCurrent = PBS_NORMAL; - } - - priv->uxStatePrev = priv->uxStateCurrent; - priv->uxStateCurrent = stateid; - priv->itemStatePrev = priv->itemStateCurrent; - priv->itemStateCurrent = dis->itemState; - - ALF_Compat_BP_ANIMATIONPARAMS animParams; - ZeroMemory(&animParams, sizeof(animParams)); - 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)) { - animParams.dwDuration = priv->uxDefaultAnimationDuration; - } 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, - priv->uxStatePrev, - PBS_DEFAULTED, - TMT_TRANSITIONDURATION, - &animParams.dwDuration); - } 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, - PBS_DEFAULTED, - priv->uxStateCurrent, - TMT_TRANSITIONDURATION, - &animParams.dwDuration); - } else { - ALF_Compat_GetThemeTransitionDuration(priv->hTheme, - BP_PUSHBUTTON, - 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)) { - KillTimer(hwnd, (UINT_PTR)priv); - priv->uxIsDefaultAnimating = FALSE; - } - - if (!(priv->uxStatePrev == PBS_DEFAULTED || priv->uxStatePrev == PBS_DEFAULTED_ANIMATING) - && (priv->uxStateCurrent == PBS_DEFAULTED || priv->uxStateCurrent == PBS_DEFAULTED_ANIMATING) - && priv->uxDefaultAnimationDuration) { - SetTimer(hwnd, (UINT_PTR)priv, priv->uxDefaultAnimationDuration, ALF__Button_DefaultAnimatingTimerProc); - } - } - - HDC hdcFrom = NULL, hdcTo = NULL; - ALF_Compat_HANIMATIONBUFFER hbpAnimation; - - hbpAnimation = ALF_Compat_BeginBufferedAnimation(hwnd, dis->hDC, &dis->rcItem, 0, NULL, &animParams, &hdcFrom, &hdcTo); - if (hbpAnimation) { - HFONT font = (HFONT)GetCurrentObject(dis->hDC, OBJ_FONT); - - if (hdcFrom) { - SelectFont(hdcFrom, font); - ALF__Button_RenderUxtheme(hwnd, priv, priv->uxStatePrev, priv->itemStatePrev, hdcFrom, &dis->rcItem); - } - - if (hdcTo) { - SelectFont(hdcTo, font); - ALF__Button_RenderUxtheme(hwnd, priv, priv->uxStateCurrent, priv->itemStateCurrent, hdcTo, &dis->rcItem); - } - - ALF_Compat_EndBufferedAnimation(hbpAnimation, TRUE); - } else { - ALF__Button_RenderUxtheme(hwnd, priv, stateid, dis->itemState, dis->hDC, &dis->rcItem); - } - } else if (ALF_Compat_IsMinWindowsVersion(4, 0)) { - // Draw 95 style button - ALF__Button_Render95(hwnd, priv, dis); - } else { - // Draw pre-95 style button - ALF__Button_Render3x(hwnd, priv, dis); - } - } + ALF_ClassicButton_Paint(hwnd, priv, dis); return TRUE; + } else if (uMsg == WM_ERASEBKGND) { + return TRUE; + } else if (uMsg == BM_SETSTYLE) { + priv->isDefault = (wParam & BS_DEFPUSHBUTTON); + wParam = BS_OWNERDRAW; } else if (uMsg == WM_GETDLGCODE) { if (priv->isDefault) { - return DLGC_DEFPUSHBUTTON | DLGC_BUTTON; + return (LRESULT)DLGC_DEFPUSHBUTTON; } else { - return DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON; + return (LRESULT)DLGC_UNDEFPUSHBUTTON; } - } else if (uMsg == BM_SETSTYLE) { - // HACK! stop windows from resetting the owner draw flag - priv->isDefault = (wParam & BS_DEFPUSHBUTTON) ? 1 : 0; - - return ALF_Compat_DefSubclassProc(hwnd, BM_SETSTYLE, (wParam & 0xFFFFFFF0) | BS_OWNERDRAW, lParam); - } else if (uMsg == WM_THEMECHANGED) { - ALF_Compat_CloseThemeData(priv->hTheme); - priv->hTheme = NULL; - if (ALF_Compat_IsAppThemed()) - priv->hTheme = ALF_Compat_OpenThemeData(hwnd, L"Button"); - priv->uxDefaultAnimationDuration = 0; - ALF_Compat_GetThemeTransitionDuration(priv->hTheme, - BP_PUSHBUTTON, - PBS_DEFAULTED, - PBS_DEFAULTED_ANIMATING, - TMT_TRANSITIONDURATION, - &priv->uxDefaultAnimationDuration); - InvalidateRect(hwnd, NULL, TRUE); - } else if (uMsg == WM_MOUSEMOVE) { - if (!priv->isHot) { - TRACKMOUSEEVENT tme; - ZeroMemory(&tme, sizeof(tme)); - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd; - if (ALF_Compat_TrackMouseEvent(&tme)) { - priv->isHot = TRUE; - InvalidateRect(hwnd, NULL, FALSE); - } - } - } else if (uMsg == WM_MOUSELEAVE) { - if (priv->isHot) { - priv->isHot = FALSE; - InvalidateRect(hwnd, NULL, FALSE); - } - } else if (uMsg == WM_DESTROY) { - ALF_Compat_CloseThemeData(priv->hTheme); - ALF_Free(priv); - ALF_Compat_RemoveWindowSubclass(hwnd, ALF__ButtonSubclassProc, 0); - } else if (uMsg == WM_ERASEBKGND) { - return TRUE; - } else if (uMsg == WM_SETTEXT) { - ALF_InvalidateLayout(GetParent(hwnd)); } else if (uMsg == WM_SETFONT) { ALF_InvalidateLayout(GetParent(hwnd)); - } else if (uMsg == ALF_WM_DPICHANGE) { - priv->dpi = (int)lParam; - ALF_InvalidateLayout(GetParent(hwnd)); - return TRUE; + InvalidateRect(hwnd, NULL, TRUE); + } else if (uMsg == WM_DESTROY) { + WNDPROC o = priv->origWndProc; + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)o); + SetWindowLongPtr(hwnd, GWLP_USERDATA, 0); + ALF_ClassicButton_FreePriv(priv); + return CallWindowProc(o, hwnd, uMsg, wParam, lParam); } - return ALF_Compat_DefSubclassProc(hwnd, uMsg, wParam, lParam); + return CallWindowProc(priv->origWndProc, hwnd, uMsg, wParam, lParam); } -HWND -ALF_AddButton(HWND win, WORD id, int x, int y, const TCHAR *text) +static HWND +ALF_ClassicButton_Create(HWND win, WORD id, int x, int y, const TCHAR *text) { HWND hwndButton = CreateWindowEx(0, TEXT("BUTTON"), text, - WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_PUSHBUTTON | BS_MULTILINE | BS_OWNERDRAW, + WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_OWNERDRAW, 0, 0, 100, 100, win, (HMENU)(int)id, - (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE), + ALF_HINSTANCE, NULL); - ALFButtonPriv *priv = ALF_New(ALFButtonPriv, 1); - priv->uxStateCurrent = -1; - priv->uxStatePrev = -1; - priv->dpi = 96; - - ALF_Compat_SetWindowSubclass(hwndButton, ALF__ButtonSubclassProc, 0, (DWORD_PTR)priv); - - SendMessage(hwndButton, WM_THEMECHANGED, 0, 0); + ALFClassicButtonPriv *priv = ALF_ClassicButton_InitializePriv(); + SetWindowLongPtr(hwndButton, GWLP_USERDATA, (LONG_PTR)priv); + priv->origWndProc = (WNDPROC)SetWindowLongPtr(hwndButton, GWLP_WNDPROC, (LONG_PTR)ALF_ClassicButton_WndProc); - ALF_AddWidget(win, x, y, hwndButton, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_SENDDPICHANGE); + ALF_AddWidget(win, x, y, hwndButton, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT); return hwndButton; } +/* Factory and helper functions for both button types */ + +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); + } else { + return ALF_ClassicButton_Create(win, id, x, y, text); + } +} void ALF_SetDefaultButton(HWND win, WORD id) |
