From 479d1226faaa937ef6820b14f36099ef3f575883 Mon Sep 17 00:00:00 2001 From: Jonas Kümmerlin Date: Sat, 18 Apr 2020 17:34:55 +0200 Subject: implement background color reduce flickering by keeping pixels if we know the background didn't change panel text is now gone, it would require us to redraw every transparent widget on top, which is a bad tradeoff since that panel text isn't very useful anyway. --- alf/alf.cpp | 24 ++++++++++++++++++++++++ alf/alf.h | 17 ++++++++++++++--- alf/alflabel.cpp | 13 +++++++++++++ alf/alflayout.cpp | 31 ++++++++++++++++++++++++++++++- alf/alfnotebook.cpp | 33 +++++++++++++++++++++++++-------- alf/alfpanel.cpp | 44 ++++++++++++++++++++------------------------ alf/alfpriv.h | 3 +++ alf/alfwindow.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 174 insertions(+), 37 deletions(-) (limited to 'alf') diff --git a/alf/alf.cpp b/alf/alf.cpp index d40522f..311c65b 100644 --- a/alf/alf.cpp +++ b/alf/alf.cpp @@ -415,3 +415,27 @@ ALF_ShouldMessageBubble(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) || msg == WM_CTLCOLORLISTBOX || msg == WM_CTLCOLORSCROLLBAR || msg == WM_CTLCOLORSTATIC; } + +void +ALF_FillRect(HDC dc, const RECT *rc, ALFColor color) +{ + if (color == ALF_COLOR_TRANSPARENT) + return; + + COLORREF gdicolor = ALF_ColorToGdi(color); + COLORREF oldBkColor = SetBkColor(dc, gdicolor); + ExtTextOut(dc, 0, 0, ETO_OPAQUE, rc, NULL, 0, NULL); + SetBkColor(dc, oldBkColor); +} + +COLORREF +ALF_ColorToGdi(ALFColor color) +{ + if (color == ALF_COLOR_TRANSPARENT) { + return (COLORREF)-1; + } else if (color & 0x80000000) { + return GetSysColor((color & 0x7f000000) >> 24); + } else { + return (COLORREF)color; + } +} diff --git a/alf/alf.h b/alf/alf.h index 3274016..20dccfc 100644 --- a/alf/alf.h +++ b/alf/alf.h @@ -33,9 +33,10 @@ typedef struct { #define ALF_LAYOUT_SIZE_RADIOBUTTON 0x07 /* unimplemented */ #define ALF_LAYOUT_SIZE_CHECKBOX 0x07 /* unimplemented */ #define ALF_LAYOUT_SIZETYPE_MASK 0x0f -#define ALF_LAYOUT_INHERITFONT 0x10 -#define ALF_LAYOUT_CUSTOMPOS 0x20 -#define ALF_LAYOUT_SIZE_PX 0x40 +#define ALF_LAYOUT_INHERITFONT 0x10 +#define ALF_LAYOUT_CUSTOMPOS 0x20 +#define ALF_LAYOUT_SIZE_PX 0x40 +#define ALF_LAYOUT_INHERITBGCOLOR 0x80 // label style flags @@ -64,6 +65,8 @@ typedef struct { #define ALF_WM_CENTIPOINTTOPX (ALF_WM__BASE + 9) #define ALF_WM_SETFOCUS (ALF_WM__BASE + 10) #define ALF_WM_APPLYSIZE (ALF_WM__BASE + 12) +#define ALF_WM_SETBGCOLOR (ALF_WM__BASE + 13) +#define ALF_WM_GETBGCOLOR (ALF_WM__BASE + 14) #define ALF_WM_GETWIDGETATPOS (ALF_WM__BASE + 15) #define ALF_WM_PRETRANSLATEMSG (ALF_WM__BASE + 16) #define ALF_WM_INVALIDATELAYOUT (ALF_WM__BASE + 17) @@ -90,6 +93,11 @@ typedef struct { #define ALF_WM_LBL_GETSTYLE (ALF_WM__BASE + 201) #define ALF_WM_LBL_SETSTYLE (ALF_WM__BASE + 202) +typedef DWORD ALFColor; + +#define ALF_COLOR_TRANSPARENT ((ALFColor)-1) +#define ALF_COLOR_RGB(r, g, b) ((ALFColor)(((DWORD)(BYTE)r) | (((DWORD)(BYTE)g) << 8) | (((DWORD)(BYTE)b) << 16))) +#define ALF_COLOR_SYS(i) ((ALFColor)(0x80000000 | (((DWORD)(BYTE)i) << 24))) typedef struct { const TCHAR *className; @@ -124,6 +132,9 @@ ALF_ReAlloc(void *ptr, SIZE_T nmemb, SIZE_T size); void ALF_Free(const void *p); +COLORREF +ALF_ColorToGdi(ALFColor color); + LPTSTR ALF_RegisterWindowClass(HINSTANCE instance, const ALFWindowClassParams *params); diff --git a/alf/alflabel.cpp b/alf/alflabel.cpp index 59c92fa..f424486 100644 --- a/alf/alflabel.cpp +++ b/alf/alflabel.cpp @@ -203,6 +203,19 @@ ALF__LabelWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ReleaseDC(hwnd, hdcLabel); } + } else if (uMsg == WM_WINDOWPOSCHANGED) { + WINDOWPOS *p = (WINDOWPOS *)lParam; + if (!(p->flags & SWP_NOSIZE)) { + // for left-top aligned labels, no redraw is necessary + // right/bottom/center alignment basically needs to redraw the whole thing + DWORD halign = priv->style & ALF_LABEL_HALIGN_MASK; + DWORD valign = priv->style & ALF_LABEL_VALIGN_MASK; + + if ((halign != ALF_LABEL_ALIGN_LEFT && halign != ALF_LABEL_ALIGN_LEFT_LIKE_EDIT) + || (valign != ALF_LABEL_ALIGN_TOP && valign != ALF_LABEL_ALIGN_TOP_LIKE_EDIT)) { + InvalidateRect(hwnd, NULL, TRUE); + } + } } else if (uMsg == WM_DESTROY) { ALF_Free(priv); SetWindowLongPtr(hwnd, 0, 0); diff --git a/alf/alflayout.cpp b/alf/alflayout.cpp index c05d355..73b05a8 100644 --- a/alf/alflayout.cpp +++ b/alf/alflayout.cpp @@ -102,6 +102,18 @@ ALF_Layout_ForwardFont(ALFLayout *layout, HWND window, HFONT font, LPARAM redraw } } +static void +ALF_Layout_ForwardBgColor(ALFLayout *layout, HWND window, WPARAM wparam, LPARAM lparam) +{ + (void)window; + + ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, i) { + if (i->flags & ALF_LAYOUT_INHERITBGCOLOR) { + SendMessage(i->hwnd, ALF_WM_SETBGCOLOR, wparam, lparam); + } + } +} + void ALF_Layout_EnsureRowExists(ALFLayout *layout, int rowno) { @@ -305,6 +317,8 @@ ALF_Layout_Apply(ALFLayout* layout, HWND window) // now apply positions to widgets HDWP hdwp = BeginDeferWindowPos(layout->nColumns * layout->nRows); + ALFColor bgcolor = (ALFColor)SendMessage(window, ALF_WM_GETBGCOLOR, 0, 0); + ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, c) { int col = c->x; int row = c->y; @@ -320,10 +334,15 @@ ALF_Layout_Apply(ALFLayout* layout, HWND window) if (c->flags & ALF_LAYOUT_CUSTOMPOS) { hdwp = (HDWP)SendMessage(c->hwnd, ALF_WM_APPLYSIZE, (WPARAM)hdwp, (LPARAM)&r); } else { + UINT flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER; + + if (bgcolor == ALF_COLOR_TRANSPARENT) + flags |= SWP_NOCOPYBITS; + hdwp = DeferWindowPos(hdwp, c->hwnd, 0, r.left, r.top, r.right - r.left, r.bottom - r.top, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOCOPYBITS); + flags); } } @@ -349,6 +368,9 @@ ALF_Layout_AddWidget(ALFLayout* layout, HWND window, const ALFAddWidgetParams* p if (w->flags & ALF_LAYOUT_INHERITFONT) { SendMessage(w->hwnd, WM_SETFONT, (WPARAM)SendMessage(window, WM_GETFONT, 0, 0), 0); } + if (w->flags & ALF_LAYOUT_INHERITBGCOLOR) { + SendMessage(w->hwnd, ALF_WM_SETBGCOLOR, (WPARAM)SendMessage(window, ALF_WM_GETBGCOLOR, 0, 0), 0); + } ALF_ListInsert(layout->widgets.prev, &w->list); @@ -502,6 +524,8 @@ ALF_Layout_SetWidgetFlags(ALFLayout *layout, HWND window, HWND needle, DWORD fla if (flags & ALF_LAYOUT_INHERITFONT) SendMessage(w->hwnd, WM_SETFONT, (WPARAM)SendMessage(window, WM_GETFONT, 0, 0), 0); + if (flags & ALF_LAYOUT_INHERITBGCOLOR) + SendMessage(w->hwnd, ALF_WM_SETBGCOLOR, (WPARAM)SendMessage(window, ALF_WM_GETBGCOLOR, 0, 0), 0); ALF_InvalidateLayout(window); @@ -681,6 +705,11 @@ ALF_Layout_HandleMessage(ALFLayout *layout, HWND hwnd, UINT msg, WPARAM wparam, return TRUE; } + if (msg == ALF_WM_SETBGCOLOR) { + ALF_Layout_ForwardBgColor(layout, hwnd, wparam, lparam); + return TRUE; + } + if (msg == ALF_WM_INVALIDATELAYOUT) { ALF_Layout_Invalidate(layout, hwnd); return TRUE; diff --git a/alf/alfnotebook.cpp b/alf/alfnotebook.cpp index dc56769..ddc37b3 100644 --- a/alf/alfnotebook.cpp +++ b/alf/alfnotebook.cpp @@ -90,21 +90,38 @@ ALF_Notebook_InternalHandleThemeChange(HWND hwndNotebook, ALFNotebookPriv *priv) InvalidateRect(hwndNotebook, NULL, TRUE); ALF_InvalidateLayout(hwndNotebook); + + int n = ALF_Notebook_InternalTabCount(hwndNotebook, priv->hwndTabCtrl); + for (int i = 0; i < n; ++i) { + HWND panel = ALF_Notebook_InternalTabPanel(hwndNotebook, priv->hwndTabCtrl, i); + + if (priv->hTheme) { + SendMessage(panel, ALF_WM_SETBGCOLOR, (WPARAM)ALF_COLOR_TRANSPARENT, 0); + } else { + SendMessage(panel, ALF_WM_SETBGCOLOR, (WPARAM)ALF_COLOR_SYS(COLOR_BTNFACE), 0); + } + } } static HWND -ALF_Notebook_InternalAddTab(HWND notebook, HWND tabControl, const TCHAR *title) +ALF_Notebook_InternalAddTab(HWND notebook, ALFNotebookPriv *priv, const TCHAR *title) { RECT r; - GetClientRect(tabControl, &r); - TabCtrl_AdjustRect(tabControl, FALSE, &r); - MapWindowRect(tabControl, notebook, &r); + GetClientRect(priv->hwndTabCtrl, &r); + TabCtrl_AdjustRect(priv->hwndTabCtrl, FALSE, &r); + MapWindowRect(priv->hwndTabCtrl, notebook, &r); HWND hwndPanel = ALF_CreatePanelWindow(notebook, (WORD)-1); SetWindowPos(hwndPanel, NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOOWNERZORDER); - SendMessage(hwndPanel, WM_SETFONT, (WPARAM)SendMessage(tabControl, WM_GETFONT, 0, 0), 0); + SendMessage(hwndPanel, WM_SETFONT, (WPARAM)SendMessage(priv->hwndTabCtrl, WM_GETFONT, 0, 0), 0); + + if (priv->hTheme) { + SendMessage(hwndPanel, ALF_WM_SETBGCOLOR, (WPARAM)ALF_COLOR_TRANSPARENT, 0); + } else { + SendMessage(hwndPanel, ALF_WM_SETBGCOLOR, (WPARAM)ALF_COLOR_SYS(COLOR_BTNFACE), 0); + } TCITEM tie; ZeroMemory(&tie, sizeof(tie)); @@ -113,8 +130,8 @@ ALF_Notebook_InternalAddTab(HWND notebook, HWND tabControl, const TCHAR *title) tie.pszText = (TCHAR*)title; tie.lParam = (LPARAM)hwndPanel; - TabCtrl_InsertItem(tabControl, ALF_Notebook_InternalTabCount(notebook, tabControl), &tie); - ALF_Notebook_InternalHandleTabChange(notebook, tabControl); + TabCtrl_InsertItem(priv->hwndTabCtrl, ALF_Notebook_InternalTabCount(notebook, priv->hwndTabCtrl), &tie); + ALF_Notebook_InternalHandleTabChange(notebook, priv->hwndTabCtrl); ALF_InvalidateLayout(notebook); @@ -266,7 +283,7 @@ ALF__NotebookWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } } } else if (uMsg == ALF_NB_ADDTAB) { - return (LRESULT)ALF_Notebook_InternalAddTab(hwnd, priv->hwndTabCtrl, (TCHAR *)lParam); + return (LRESULT)ALF_Notebook_InternalAddTab(hwnd, priv, (TCHAR *)lParam); } else if (uMsg == ALF_NB_TABCOUNT) { return (LRESULT)ALF_Notebook_InternalTabCount(hwnd, priv->hwndTabCtrl); } else if (uMsg == ALF_NB_GETPANEL) { diff --git a/alf/alfpanel.cpp b/alf/alfpanel.cpp index 9496e43..2f39ef1 100644 --- a/alf/alfpanel.cpp +++ b/alf/alfpanel.cpp @@ -4,6 +4,7 @@ TCHAR *_alf_panelClass = NULL; typedef struct { ALFLayout layout; + ALFColor bgcolor; HFONT font; } ALFPanelPriv; @@ -11,6 +12,7 @@ static void ALF_Panel_IntializePriv(ALFPanelPriv *priv) { ALF_Layout_Init(&priv->layout); + priv->bgcolor = ALF_COLOR_TRANSPARENT; } static void @@ -22,29 +24,11 @@ ALF_Panel_ClearPriv(ALFPanelPriv *priv) static void ALF_Panel_Paint(ALFPanelPriv *priv, HWND hwnd, HDC dc, RECT *r) { - (void)priv; - ALF_Compat_DrawThemeParentBackground(hwnd, dc, r); - - int textlen = GetWindowTextLength(hwnd); - if (textlen < 1) - return; - - TCHAR *textbuf = ALF_New(TCHAR, (SIZE_T)textlen + 1); - GetWindowText(hwnd, textbuf, textlen+1); - - HFONT oldFont = SelectFont(dc, priv->font); - - SetTextColor(dc, GetSysColor(COLOR_BTNTEXT)); - SetBkMode(dc, TRANSPARENT); - - RECT rc; - GetClientRect(hwnd, &rc); - - DrawText(dc, textbuf, -1, &rc, DT_SINGLELINE | DT_EXPANDTABS | DT_HIDEPREFIX | DT_CENTER | DT_VCENTER); - - ALF_Free(textbuf); - - SelectFont(dc, oldFont); + if (priv->bgcolor == ALF_COLOR_TRANSPARENT) { + ALF_Compat_DrawThemeParentBackground(hwnd, dc, r); + } else { + ALF_FillRect(dc, r, priv->bgcolor); + } } static LRESULT WINAPI @@ -78,6 +62,18 @@ ALF__PanelWindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) // fallthrough to layout, will propagate font to children } + if (msg == ALF_WM_GETBGCOLOR) { + return (LRESULT)priv->bgcolor; + } + + if (msg == ALF_WM_SETBGCOLOR) { + priv->bgcolor = (ALFColor)wparam; + + InvalidateRect(window, NULL, TRUE); + + // fallthrough to layout, will propagate color to children + } + if (msg == WM_GETFONT) { return (LRESULT)priv->font; } @@ -160,7 +156,7 @@ ALF_AddPanel(HWND parent, WORD id, int x, int y) { HWND hwndPanel = ALF_CreatePanelWindow(parent, id); - ALF_AddWidget(parent, x, y, hwndPanel, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT); + ALF_AddWidget(parent, x, y, hwndPanel, 0, 0, ALF_LAYOUT_SIZE_QUERY | ALF_LAYOUT_INHERITFONT | ALF_LAYOUT_INHERITBGCOLOR); return hwndPanel; } diff --git a/alf/alfpriv.h b/alf/alfpriv.h index d539baf..90a4e9f 100644 --- a/alf/alfpriv.h +++ b/alf/alfpriv.h @@ -42,3 +42,6 @@ ALF_BuildUniqueName(TCHAR *buf, const TCHAR *prefix, ULONG_PTR uniquifier); BOOL ALF_ShouldMessageBubble(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + +void +ALF_FillRect(HDC dc, const RECT *rc, ALFColor color); diff --git a/alf/alfwindow.cpp b/alf/alfwindow.cpp index 0b395b6..c3f8573 100644 --- a/alf/alfwindow.cpp +++ b/alf/alfwindow.cpp @@ -9,6 +9,7 @@ typedef struct { WORD defid; HWND hwndFocus; HFONT font; + ALFColor bgcolor; } ALFWindowPriv; static void @@ -17,6 +18,7 @@ ALF_InitializeWindowPriv(HWND hwnd, ALFWindowPriv *priv, void *closure) priv->vtbl = (ALFWindowVTable*)GetClassLongPtr(hwnd, 0); priv->closure = closure; priv->defid = (WORD)-1; + priv->bgcolor = ALF_COLOR_SYS(COLOR_BTNFACE); ALF_Layout_Init(&priv->layout); } @@ -148,6 +150,13 @@ ALF_WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) } } +static void +ALF_Window_Paint(ALFWindowPriv *priv, HWND hwnd, HDC dc, RECT *r) +{ + (void)hwnd; + ALF_FillRect(dc, r, priv->bgcolor); +} + LRESULT ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { @@ -184,6 +193,41 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) // fallthrough to layout, will propagate font to children } + if (msg == ALF_WM_SETBGCOLOR) { + priv->bgcolor = (ALFColor)wparam; + + InvalidateRect(hwnd, NULL, TRUE); + + // fallthrough to layout, will propagate color to children + } + + if (msg == ALF_WM_GETBGCOLOR) { + return (LRESULT)priv->bgcolor; + } + + if (msg == WM_ERASEBKGND) { + return TRUE; // handled in WM_PAINT + } + + if (msg == WM_PRINTCLIENT) { + RECT r = { 0, 0, 0, 0 }; + GetClientRect(hwnd, &r); + + ALF_Window_Paint(priv, hwnd, (HDC)wparam, &r); + return TRUE; + } + + if (msg == WM_PAINT) { + PAINTSTRUCT ps; + HDC dc = BeginPaint(hwnd, &ps); + + ALF_Window_Paint(priv, hwnd, dc, &ps.rcPaint); + + EndPaint(hwnd, &ps); + + return 0; + } + if (msg == WM_GETFONT) { return (LRESULT)priv->font; } @@ -390,7 +434,7 @@ ALF_RegisterWindowClass(HINSTANCE hInstance, const ALFWindowClassParams *params) cls.style = params->classStyle; cls.hInstance = hInstance; cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); - cls.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + cls.hbrBackground = NULL; cls.lpszClassName = classNamePtr; cls.cbWndExtra = sizeof(void*); cls.cbClsExtra = sizeof(void*); -- cgit v1.2.3