From d64290aaffd4721518747713929d79a78ba963f4 Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Sun, 28 Apr 2019 16:14:12 +0200 Subject: add owner-drawn themed button with animation --- alf/alf.cpp | 15 ++ alf/alfbutton.cpp | 432 +++++++++++++++++++++++++++++++++++++++++++++++++++++- alf/alfcompat.cpp | 356 ++++++++++++++++++++++++++++++++++++++++++++ alf/alfcompat.h | 42 ++++++ widgetfactory.cpp | 26 ++++ 5 files changed, 868 insertions(+), 3 deletions(-) diff --git a/alf/alf.cpp b/alf/alf.cpp index 06e6e0c..0e07e0f 100644 --- a/alf/alf.cpp +++ b/alf/alf.cpp @@ -183,6 +183,17 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) return ret; } + if (msg == WM_DRAWITEM) { + LPDRAWITEMSTRUCT dis = (DRAWITEMSTRUCT *)lparam; + LRESULT ret = 0; + if (wparam && dis->hwndItem) { + ret = SendMessage(dis->hwndItem, 0x2000 + WM_DRAWITEM, wparam, lparam); + } + + if (ret) + return ret; + } + if (msg == WM_ACTIVATE) { if (!HIWORD(wparam)) { // if !minimized if (LOWORD(wparam)) { @@ -347,12 +358,16 @@ ALF_CreateApplication(HINSTANCE hInstance) ALF_RegisterPanelClass(app); ALF_RegisterSpacerClass(app); + ALF_Compat_BufferedPaintInit(); + return app; } void ALF_TeardownApplication(ALFAPP app) { + ALF_Compat_BufferedPaintUnInit(); + UnregisterClass(app->comboClass, app->hInstance); UnregisterClass(app->panelClass, app->hInstance); UnregisterClass(app->spacerClass, app->hInstance); diff --git a/alf/alfbutton.cpp b/alf/alfbutton.cpp index 9cf7c1d..fb8d1c3 100644 --- a/alf/alfbutton.cpp +++ b/alf/alfbutton.cpp @@ -1,5 +1,271 @@ #include "alfpriv.h" +#define BP_PUSHBUTTON 1 +#define PBS_NORMAL 1 +#define PBS_HOT 2 +#define PBS_PRESSED 3 +#define PBS_DISABLED 4 +#define PBS_DEFAULTED 5 +#define PBS_DEFAULTED_ANIMATING 6 + + +typedef struct { + BOOL isDefault; + BOOL isHot; + HTHEME hTheme; + UINT uxStatePrev; + UINT uxStateCurrent; + UINT itemStatePrev; + UINT itemStateCurrent; + DWORD uxDefaultAnimationDuration; + BOOL uxIsDefaultAnimating; +} ALFButtonPriv; + +static void CALLBACK +ALF__Button_DefaultAnimatingTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + (void)uMsg; + (void)dwTime; + ALFButtonPriv *priv = (ALFButtonPriv *)idEvent; + + priv->uxIsDefaultAnimating = !priv->uxIsDefaultAnimating; + InvalidateRect(hwnd, NULL, FALSE); +} + +static BOOL CALLBACK +ALF__Button_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 }; + DrawText(hdc, (TCHAR*)lData, -1, &r, (UINT)wData); + + SetBkMode(hdc, oldBkMode); + + return TRUE; +} + +static void +ALF__Button_RenderUxtheme(HWND hwnd, ALFButtonPriv *priv, UINT uxstate, UINT itemState, HDC hDC, LPRECT pRcItem) +{ + if (ALF_Compat_IsThemeBackgroundPartiallyTransparent(priv->hTheme, BP_PUSHBUTTON, uxstate)) { + ALF_Compat_DrawThemeParentBackground(hwnd, hDC, pRcItem); + } + + RECT r = *pRcItem; + InflateRect(&r, 1, 1); // HACK! get rid of 1px transparent border + + ALF_Compat_DrawThemeBackground(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, pRcItem); + + RECT content = r; + ALF_Compat_GetThemeBackgroundContentRect(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, &r, &content); + + if ((itemState & ODS_FOCUS) && !(itemState & ODS_NOFOCUSRECT)) + DrawFocusRect(hDC, &content); + + int textlen = GetWindowTextLengthW(hwnd); + WCHAR *textbuf = ALF_New(WCHAR, textlen + 1); + GetWindowTextW(hwnd, textbuf, textlen+1); + + UINT style = DT_CENTER; + + if (itemState & ODS_NOACCEL) + style |= DT_HIDEPREFIX; + + RECT textbounds = content; + ALF_Compat_GetThemeTextExtent(priv->hTheme, hDC, BP_PUSHBUTTON, uxstate, textbuf, -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, textbuf, -1, style, 0, &texttarget); + + ALF_Free(textbuf); +} + +static void +ALF__Button_Render95(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) +{ + RECT r = dis->rcItem; + DWORD v = GetVersion(); + + int textlen = GetWindowTextLength(hwnd); + TCHAR *textbuf = ALF_New(TCHAR, textlen + 1); + GetWindowText(hwnd, textbuf, textlen+1); + + 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; + if (dis->itemState & ODS_HOTLIGHT) + dfcs |= DFCS_HOT; + + DrawFrameControl(dis->hDC, &r, DFC_BUTTON, dfcs); + + if ((dis->itemState & ODS_FOCUS) && !(dis->itemState & ODS_NOFOCUSRECT)) { + RECT f = r; + InflateRect(&f, -1, -1); + DrawFocusRect(dis->hDC, &f); + } + + 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 - 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); + + if (dis->itemState & ODS_SELECTED) { + texttarget.top += 1; + texttarget.left += 1; + texttarget.right += 1; + texttarget.bottom += 1; + } + + UINT style = DT_CENTER; + + if (dis->itemState & ODS_NOACCEL) + style |= DT_HIDEPREFIX; + + if (dis->itemState & ODS_DISABLED) { + if (v >= 0x80000000) { + // 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)); + + 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); + + SetTextColor(dis->hDC, 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); + } + } 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); + } + + ALF_Free(textbuf); +} + +static void +ALF__Button_Render3x(HWND hwnd, ALFButtonPriv *priv, LPDRAWITEMSTRUCT dis) +{ + RECT r = dis->rcItem; + + int textlen = GetWindowTextLength(hwnd); + TCHAR *textbuf = ALF_New(TCHAR, textlen + 1); + GetWindowText(hwnd, textbuf, textlen+1); + + HBRUSH framecolor = GetSysColorBrush(COLOR_WINDOWFRAME); + HBRUSH facecolor = GetSysColorBrush(COLOR_BTNFACE); + + // 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); + } + + // 3d button + if (dis->itemState & ODS_SELECTED) { + DrawEdge(dis->hDC, &r, BDR_SUNKENOUTER, BF_TOPLEFT); + + RECT f = r; + f.left++; + f.top++; + + FillRect(dis->hDC, &f, facecolor); + + 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); + + FillRect(dis->hDC, &r, facecolor); + } + + 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.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); + + if (dis->itemState & ODS_SELECTED) { + texttarget.top += 1; + texttarget.left += 1; + texttarget.right += 1; + texttarget.bottom += 1; + } + + if (dis->itemState & ODS_FOCUS) { + DrawFocusRect(dis->hDC, &texttarget); + } + + int oldBkMode = SetBkMode(dis->hDC, TRANSPARENT); + + 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)); + + DrawText(dis->hDC, textbuf, -1, &texttarget, DT_CENTER); + + SetTextColor(dis->hDC, oldTextColor); + } else { + DrawText(dis->hDC, textbuf, -1, &texttarget, DT_CENTER); + } + + SetBkMode(dis->hDC, oldBkMode); + + ALF_Free(textbuf); +} + /* BUTTON */ static LRESULT CALLBACK ALF__ButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) @@ -7,6 +273,8 @@ ALF__ButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT (void)uIdSubclass; (void)dwRefData; + ALFButtonPriv *priv = (ALFButtonPriv *)dwRefData; + if (uMsg == ALF_WM_QUERYSIZE) { HDC hdc = GetDC(hwnd); HFONT font = (HFONT)SendMessage(hwnd, WM_GETFONT, 0, 0); @@ -50,7 +318,160 @@ ALF__ButtonSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT SelectFont(hdc, oldFont); ReleaseDC(hwnd, hdc); + } else if (uMsg == 0x2000 + WM_DRAWITEM) { + LPDRAWITEMSTRUCT dis = (DRAWITEMSTRUCT *)lParam; + DWORD v = GetVersion(); + + if (!ALF_Compat_BufferedPaintRenderAnimation(hwnd, dis->hDC)) { + if (priv->hTheme) { + // Draw XP style themed button + UINT 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 == (UINT)-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 (LOBYTE(LOWORD(v)) < 4) { + // Draw pre-95 style button + ALF__Button_Render3x(hwnd, priv, dis); + } else { + // Draw 95 style button + ALF__Button_Render95(hwnd, priv, dis); + } + } + + return TRUE; + } else if (uMsg == WM_GETDLGCODE) { + if (priv->isDefault) { + return DLGC_DEFPUSHBUTTON | DLGC_BUTTON; + } else { + return DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON; + } + } 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); } @@ -63,15 +484,20 @@ ALF_AddButton(HWND win, WORD id, UINT x, UINT y, const TCHAR *text) HWND hwndButton = CreateWindowEx(0, TEXT("BUTTON"), text, - WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_PUSHBUTTON | BS_MULTILINE, + WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_PUSHBUTTON | BS_MULTILINE | BS_OWNERDRAW, 0, 0, 100, 100, win, (HMENU)(int)id, (HINSTANCE)GetWindowLongPtr(win, GWLP_HINSTANCE), NULL); - ALF_Compat_SetWindowSubclass(hwndButton, ALF__ButtonSubclassProc, 0, 0); - SetWindowPos(hwndButton, NULL, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED); + ALFButtonPriv *priv = ALF_New(ALFButtonPriv, 1); + priv->uxStateCurrent = (UINT)-1; + priv->uxStatePrev = (UINT)-1; + + ALF_Compat_SetWindowSubclass(hwndButton, ALF__ButtonSubclassProc, 0, (DWORD_PTR)priv); + + SendMessage(hwndButton, WM_THEMECHANGED, 0, 0); ALFWidgetLayoutParams p; ZeroMemory(&p, sizeof(p)); diff --git a/alf/alfcompat.cpp b/alf/alfcompat.cpp index 2260ed4..c0e11ba 100644 --- a/alf/alfcompat.cpp +++ b/alf/alfcompat.cpp @@ -358,6 +358,346 @@ ALF_Compat_loadSystemParametersInfoForDpi(UINT uiAction, UINT uiParam, PVOID pvP return ALF_Compat_SystemParametersInfoForDpi(uiAction, uiParam, pvParam, fWinIni, dpi); } +static HTHEME WINAPI +ALF_Compat_fallbackOpenThemeData(HWND window, LPCWSTR classNames) +{ + (void)window; + (void)classNames; + + return NULL; +} + +static HTHEME WINAPI +ALF_Compat_loadOpenThemeData(HWND window, LPCWSTR classNames) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "OpenThemeData"); + if (!p) + p = (void*)ALF_Compat_fallbackOpenThemeData; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_OpenThemeData, p, (void*)ALF_Compat_loadOpenThemeData); + + return ALF_Compat_OpenThemeData(window, classNames); +} + +static HRESULT WINAPI +ALF_Compat_fallbackCloseThemeData(HTHEME hTheme) +{ + (void)hTheme; + + return S_OK; +} + +static HRESULT WINAPI +ALF_Compat_loadCloseThemeData(HTHEME hTheme) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "CloseThemeData"); + if (!p) + p = (void*)ALF_Compat_fallbackCloseThemeData; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_CloseThemeData, p, (void*)ALF_Compat_loadCloseThemeData); + + return ALF_Compat_CloseThemeData(hTheme); +} + +static BOOL WINAPI +ALF_Compat_fallbackIsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId) +{ + (void)hTheme; (void)iPartId; (void)iStateId; + + return TRUE; +} + +static BOOL WINAPI +ALF_Compat_loadIsThemeBackgroundPartiallyTransparent(HTHEME hTheme, int iPartId, int iStateId) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "IsThemeBackgroundPartiallyTransparent"); + if (!p) + p = (void*)ALF_Compat_fallbackIsThemeBackgroundPartiallyTransparent; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_IsThemeBackgroundPartiallyTransparent, p, (void*)ALF_Compat_loadIsThemeBackgroundPartiallyTransparent); + + return ALF_Compat_IsThemeBackgroundPartiallyTransparent(hTheme, iPartId, iStateId); +} + +static HRESULT WINAPI +ALF_Compat_fallbackDrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc) +{ + (void)hwnd; + (void)hdc; + (void)prc; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadDrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "DrawThemeParentBackground"); + if (!p) + p = (void*)ALF_Compat_fallbackDrawThemeParentBackground; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_DrawThemeParentBackground, p, (void*)ALF_Compat_loadDrawThemeParentBackground); + + return ALF_Compat_DrawThemeParentBackground(hwnd, hdc, prc); +} + +static HRESULT WINAPI +ALF_Compat_fallbackDrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect) +{ + (void)hTheme; + (void)hdc; + (void)iPartId; + (void)iStateId; + (void)pRect; + (void)pClipRect; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadDrawThemeBackground(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, const RECT *pClipRect) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "DrawThemeBackground"); + if (!p) + p = (void*)ALF_Compat_fallbackDrawThemeBackground; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_DrawThemeBackground, p, (void*)ALF_Compat_loadDrawThemeBackground); + + return ALF_Compat_DrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect); +} + +static HRESULT WINAPI +ALF_Compat_fallbackGetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect) +{ + (void)hTheme; + (void)hdc; + (void)iPartId; + (void)iStateId; + (void)pBoundingRect; + (void)pContentRect; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadGetThemeBackgroundContentRect(HTHEME hTheme, HDC hdc, int iPArtId, int iStateId, const RECT *pBoundingRect, RECT *pContentRect) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "GetThemeBackgroundContentRect"); + if (!p) + p = (void*)ALF_Compat_fallbackGetThemeBackgroundContentRect; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_GetThemeBackgroundContentRect, p, (void*)ALF_Compat_loadGetThemeBackgroundContentRect); + + return ALF_Compat_GetThemeBackgroundContentRect(hTheme, hdc, iPArtId, iStateId, pBoundingRect, pContentRect); +} + +static HRESULT WINAPI +ALF_Compat_fallbackGetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId, + int iStateId, LPCWSTR pszText, int iCharCount, + DWORD dwTextFlags, const RECT *pBoundingRect, + RECT *pExtentRect) +{ + (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pszText; + (void)iCharCount; (void)dwTextFlags; (void)pBoundingRect; (void)pExtentRect; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadGetThemeTextExtent(HTHEME hTheme, HDC hdc, int iPartId, + int iStateId, LPCWSTR pszText, int iCharCount, + DWORD dwTextFlags, const RECT *pBoundingRect, + RECT *pExtentRect) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "GetThemeTextExtent"); + if (!p) + p = (void*)ALF_Compat_fallbackGetThemeTextExtent; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_GetThemeTextExtent, p, (void*)ALF_Compat_loadGetThemeTextExtent); + + return ALF_Compat_GetThemeTextExtent(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, pBoundingRect, pExtentRect); +} + +static HRESULT WINAPI +ALF_Compat_fallbackDrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, + DWORD dwTextFlags2, const RECT *pRect) +{ + (void)hTheme; (void)hdc; (void)iPartId; (void)iStateId; (void)pszText; + (void)iCharCount; (void)dwTextFlags; (void)dwTextFlags2; (void)pRect; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadDrawThemeText(HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + LPCWSTR pszText, int iCharCount, DWORD dwTextFlags, + DWORD dwTextFlags2, const RECT *pRect) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "DrawThemeText"); + if (!p) + p = (void*)ALF_Compat_fallbackDrawThemeText; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_DrawThemeText, p, (void*)ALF_Compat_loadDrawThemeText); + + return ALF_Compat_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect); +} + +static BOOL WINAPI +ALF_Compat_fallbackTrackMouseEvent(LPTRACKMOUSEEVENT tme) +{ + (void)tme; + + return FALSE; +} + +static BOOL WINAPI +ALF_Compat_loadTrackMouseEvent(LPTRACKMOUSEEVENT tme) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("comctl32.dll"), "_TrackMouseEvent"); + if (!p) + p = (void*)ALF_Compat_fallbackTrackMouseEvent; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_TrackMouseEvent, p, (void*)ALF_Compat_loadTrackMouseEvent); + + return ALF_Compat_TrackMouseEvent(tme); +} + +static HRESULT WINAPI +ALF_Compat_fallbackBufferedPaintInit(void) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadBufferedPaintInit(void) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "BufferedPaintInit"); + if (!p) + p = (void*)ALF_Compat_fallbackBufferedPaintInit; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_BufferedPaintInit, p, (void*)ALF_Compat_loadBufferedPaintInit); + + return ALF_Compat_BufferedPaintInit(); +} + +static HRESULT WINAPI +ALF_Compat_fallbackBufferedPaintUnInit(void) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadBufferedPaintUnInit(void) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "BufferedPaintUnInit"); + if (!p) + p = (void*)ALF_Compat_fallbackBufferedPaintUnInit; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_BufferedPaintUnInit, p, (void*)ALF_Compat_loadBufferedPaintUnInit); + + return ALF_Compat_BufferedPaintUnInit(); +} + +static ALF_Compat_HANIMATIONBUFFER WINAPI +ALF_Compat_fallbackBeginBufferedAnimation(HWND hwnd, HDC hdcTarget, + const RECT *prcTarget, DWORD dwFormat, + ALF_Compat_BP_PAINTPARAMS *pPaintParams, + ALF_Compat_BP_ANIMATIONPARAMS *pAnimationParams, + HDC *phdcFrom, HDC *phdcTo) +{ + (void)hwnd; (void)hdcTarget; (void)prcTarget; (void)dwFormat; + (void)pPaintParams; (void)pAnimationParams; (void)phdcFrom; (void)phdcTo; + + return NULL; +} + +static ALF_Compat_HANIMATIONBUFFER WINAPI +ALF_Compat_loadBeginBufferedAnimation(HWND hwnd, HDC hdcTarget, + const RECT *prcTarget, DWORD dwFormat, + ALF_Compat_BP_PAINTPARAMS *pPaintParams, + ALF_Compat_BP_ANIMATIONPARAMS *pAnimationParams, + HDC *phdcFrom, HDC *phdcTo) +{ + void *p = (void *)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "BeginBufferedAnimation"); + if (!p) + p = (void*)ALF_Compat_fallbackBeginBufferedAnimation; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_BeginBufferedAnimation, p, (void*)ALF_Compat_loadBeginBufferedAnimation); + + return ALF_Compat_BeginBufferedAnimation(hwnd, hdcTarget, prcTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); +} + +static HRESULT WINAPI +ALF_Compat_fallbackEndBufferedAnimation(ALF_Compat_HANIMATIONBUFFER hbpAnimation, BOOL fUpdateTarget) +{ + (void)hbpAnimation; (void)fUpdateTarget; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadEndBufferedAnimation(ALF_Compat_HANIMATIONBUFFER hbpAnimation, BOOL fUpdateTarget) +{ + void *p = (void *)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "EndBufferedAnimation"); + if (!p) + p = (void*)ALF_Compat_fallbackEndBufferedAnimation; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_EndBufferedAnimation, p, (void*)ALF_Compat_loadEndBufferedAnimation); + + return ALF_Compat_EndBufferedAnimation(hbpAnimation, fUpdateTarget); +} + +static BOOL WINAPI +ALF_Compat_fallbackBufferedPaintRenderAnimation(HWND hwnd, HDC hdc) +{ + (void)hwnd; (void)hdc; + + return FALSE; +} + +static BOOL WINAPI +ALF_Compat_loadBufferedPaintRenderAnimation(HWND hwnd, HDC hdc) +{ + void *p = (void *)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "BufferedPaintRenderAnimation"); + if (!p) + p = (void *)ALF_Compat_fallbackBufferedPaintRenderAnimation; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_BufferedPaintRenderAnimation, p, (void*)ALF_Compat_loadBufferedPaintRenderAnimation); + + return ALF_Compat_BufferedPaintRenderAnimation(hwnd, hdc); +} + +static HRESULT WINAPI +ALF_Compat_fallbackGetThemeTransitionDuration(HTHEME hTheme, + int iPartId, + int iStateIdFrom, + int iStateIdTo, + int iPropId, + DWORD *pdwDuration) +{ + (void)hTheme; (void)iPartId; (void)iStateIdFrom; (void)iStateIdTo; (void)iPropId; (void)pdwDuration; + + return E_NOTIMPL; +} + +static HRESULT WINAPI +ALF_Compat_loadGetThemeTransitionDuration(HTHEME hTheme, + int iPartId, + int iStateIdFrom, + int iStateIdTo, + int iPropId, + DWORD *pdwDuration) +{ + void *p = (void*)GetProcAddress(GetModuleHandleA("uxtheme.dll"), "GetThemeTransitionDuration"); + + if (!p) + p = (void*)ALF_Compat_fallbackGetThemeTransitionDuration; + + InterlockedCompareExchangePointer((void**)&ALF_Compat_GetThemeTransitionDuration, p, (void*)ALF_Compat_loadGetThemeTransitionDuration); + + return ALF_Compat_GetThemeTransitionDuration(hTheme, iPartId, iStateIdFrom, iStateIdTo, iPropId, pdwDuration); +} BOOL (WINAPI *ALF_Compat_IsAppThemed)(void) = ALF_Compat_loadIsAppThemed; UINT (WINAPI *ALF_Compat_GetDpiForWindow)(HWND /*window*/) = ALF_Compat_loadGetDpiForWindow; @@ -373,3 +713,19 @@ BOOL (WINAPI *ALF_Compat_SystemParametersInfoForDpi)(UINT,UINT,PVOID,UINT,UINT) #else BOOL (WINAPI *ALF_Compat_SystemParametersInfoForDpi)(UINT,UINT,PVOID,UINT,UINT) = ALF_Compat_fallbackSystemParametersInfoForDpi; #endif + +HTHEME (WINAPI *ALF_Compat_OpenThemeData)(HWND, LPCWSTR) = ALF_Compat_loadOpenThemeData; +HRESULT (WINAPI *ALF_Compat_CloseThemeData)(HTHEME) = ALF_Compat_loadCloseThemeData; +BOOL (WINAPI *ALF_Compat_IsThemeBackgroundPartiallyTransparent)(HTHEME,int,int) = ALF_Compat_loadIsThemeBackgroundPartiallyTransparent; +HRESULT (WINAPI *ALF_Compat_DrawThemeParentBackground)(HWND,HDC,RECT *) = ALF_Compat_loadDrawThemeParentBackground; +HRESULT (WINAPI *ALF_Compat_DrawThemeBackground)(HTHEME, HDC, int, int, const RECT *, const RECT *) = ALF_Compat_loadDrawThemeBackground; +HRESULT (WINAPI *ALF_Compat_GetThemeBackgroundContentRect)(HTHEME,HDC,int,int,const RECT *,RECT *) = ALF_Compat_loadGetThemeBackgroundContentRect; +HRESULT (WINAPI *ALF_Compat_GetThemeTextExtent)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,const RECT *, RECT *) = ALF_Compat_loadGetThemeTextExtent; +HRESULT (WINAPI *ALF_Compat_DrawThemeText)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *) = ALF_Compat_loadDrawThemeText; +BOOL (WINAPI *ALF_Compat_TrackMouseEvent)(LPTRACKMOUSEEVENT tme) = ALF_Compat_loadTrackMouseEvent; +HRESULT (WINAPI *ALF_Compat_BufferedPaintInit)(void) = ALF_Compat_loadBufferedPaintInit; +HRESULT (WINAPI *ALF_Compat_BufferedPaintUnInit)(void) = ALF_Compat_loadBufferedPaintUnInit; +ALF_Compat_HANIMATIONBUFFER (WINAPI *ALF_Compat_BeginBufferedAnimation)(HWND,HDC,const RECT *,DWORD,ALF_Compat_BP_PAINTPARAMS *,ALF_Compat_BP_ANIMATIONPARAMS *,HDC *,HDC *) = ALF_Compat_loadBeginBufferedAnimation; +HRESULT (WINAPI *ALF_Compat_EndBufferedAnimation)(ALF_Compat_HANIMATIONBUFFER,BOOL) = ALF_Compat_loadEndBufferedAnimation; +BOOL (WINAPI *ALF_Compat_BufferedPaintRenderAnimation)(HWND,HDC) = ALF_Compat_loadBufferedPaintRenderAnimation; +HRESULT (WINAPI *ALF_Compat_GetThemeTransitionDuration)(HTHEME,int,int,int,int,DWORD*) = ALF_Compat_loadGetThemeTransitionDuration; diff --git a/alf/alfcompat.h b/alf/alfcompat.h index b0a43ec..e0faf62 100644 --- a/alf/alfcompat.h +++ b/alf/alfcompat.h @@ -2,6 +2,7 @@ #include #include +#include #ifndef WM_DPICHANGED #define WM_DPICHANGED 0x02E0 @@ -44,6 +45,32 @@ ALF_GetAveCharWidth(HDC hdc); void ALF_UniqueCounterValue(LONG_PTR *pCounterId, LONG_PTR *pCounterValue); +typedef void *ALF_Compat_HANIMATIONBUFFER; + +typedef enum { + ALF_Compat_BPAS_NONE, + ALF_Compat_BPAS_LINEAR, + ALF_Compat_BPAS_CUBIC, + ALF_Compat_BPAS_SINE +} ALF_Compat_BP_ANIMATIONSTYLE; + +typedef struct { + DWORD cbSize; + DWORD dwFlags; + ALF_Compat_BP_ANIMATIONSTYLE style; + DWORD dwDuration; +} ALF_Compat_BP_ANIMATIONPARAMS; + +typedef struct { + DWORD cbSize; + DWORD dwFlags; + const RECT *prcExclude; + const BLENDFUNCTION *pBlendFunction; +} ALF_Compat_BP_PAINTPARAMS; + +#ifndef TMT_TRANSITIONDURATION +#define TMT_TRANSITIONDURATION 6000 +#endif extern BOOL (WINAPI *ALF_Compat_IsAppThemed)(void); extern UINT (WINAPI *ALF_Compat_GetDpiForWindow)(HWND); @@ -53,3 +80,18 @@ extern BOOL (WINAPI *ALF_Compat_SetWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC extern LRESULT (WINAPI *ALF_Compat_DefSubclassProc)(HWND, UINT, WPARAM, LPARAM); extern BOOL (WINAPI *ALF_Compat_RemoveWindowSubclass)(HWND, ALF_COMPAT_SUBCLASSPROC, UINT_PTR); extern BOOL (WINAPI *ALF_Compat_SystemParametersInfoForDpi)(UINT,UINT,PVOID,UINT,UINT); +extern HTHEME (WINAPI *ALF_Compat_OpenThemeData)(HWND, LPCWSTR); +extern HRESULT (WINAPI *ALF_Compat_CloseThemeData)(HTHEME); +extern BOOL (WINAPI *ALF_Compat_IsThemeBackgroundPartiallyTransparent)(HTHEME,int,int); +extern HRESULT (WINAPI *ALF_Compat_DrawThemeParentBackground)(HWND,HDC,RECT *); +extern HRESULT (WINAPI *ALF_Compat_DrawThemeBackground)(HTHEME, HDC, int, int, const RECT *, const RECT *); +extern HRESULT (WINAPI *ALF_Compat_GetThemeBackgroundContentRect)(HTHEME,HDC,int,int,const RECT *,RECT *); +extern HRESULT (WINAPI *ALF_Compat_GetThemeTextExtent)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,const RECT *, RECT *); +extern HRESULT (WINAPI *ALF_Compat_DrawThemeText)(HTHEME,HDC,int,int,LPCWSTR,int,DWORD,DWORD,const RECT *); +extern BOOL (WINAPI *ALF_Compat_TrackMouseEvent)(LPTRACKMOUSEEVENT tme); +extern HRESULT (WINAPI *ALF_Compat_BufferedPaintInit)(void); +extern HRESULT (WINAPI *ALF_Compat_BufferedPaintUnInit)(void); +extern ALF_Compat_HANIMATIONBUFFER (WINAPI *ALF_Compat_BeginBufferedAnimation)(HWND,HDC,const RECT *,DWORD,ALF_Compat_BP_PAINTPARAMS *,ALF_Compat_BP_ANIMATIONPARAMS *,HDC *,HDC *); +extern HRESULT (WINAPI *ALF_Compat_EndBufferedAnimation)(ALF_Compat_HANIMATIONBUFFER,BOOL); +extern BOOL (WINAPI *ALF_Compat_BufferedPaintRenderAnimation)(HWND,HDC); +extern HRESULT (WINAPI *ALF_Compat_GetThemeTransitionDuration)(HTHEME,int,int,int,int,DWORD*); diff --git a/widgetfactory.cpp b/widgetfactory.cpp index e22f4d9..8f7961c 100644 --- a/widgetfactory.cpp +++ b/widgetfactory.cpp @@ -17,6 +17,8 @@ enum { ID_BC1, ID_BC2, ID_BC3, + ID_BC4, + ID_BC5, ID__MAX }; @@ -164,6 +166,30 @@ WinMain ALF_AddButton(panel, ID_BC3, 2, 0, TEXT("3")); ALF_AddSpacer(panel, (WORD)-1, 0, 1, 5000, 0, ALF_VEXPAND); + HWND hwndBc4 = CreateWindowEx(0, + TEXT("BUTTON"), + TEXT("4"), + WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_PUSHBUTTON, + 0, 0, 100, 100, + panel, + (HMENU)(int)ID_BC4, + (HINSTANCE)GetWindowLongPtr(panel, GWLP_HINSTANCE), + NULL); + HWND hwndBc5 = CreateWindowEx(0, + TEXT("BUTTON"), + TEXT("5"), + WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_PUSHBUTTON, + 0, 0, 100, 100, + panel, + (HMENU)(int)ID_BC5, + (HINSTANCE)GetWindowLongPtr(panel, GWLP_HINSTANCE), + NULL); + EnableWindow(hwndBc5, FALSE); + ALF_AddWidget(panel, 3, 0, hwndBc4, 1000, 0, ALF_MESSAGEFONT); + ALF_AddWidget(panel, 4, 0, hwndBc5, 1000, 0, ALF_MESSAGEFONT); + + EnableWindow(ALF_WidgetHwndById(win, ID_BC2), FALSE); + ALF_ApplyFonts(win); ALF_RecalculateLayout(win); ALF_SetDefaultButton(win, ID_B2); -- cgit v1.2.3