#include "alfpriv.h" typedef struct { ALFLayout layout; const ALFPanelVTable *vtbl; void *closure; DWORD edge; } ALFPanelPriv; static void ALF_Panel_CalculateContainerMetrics(ALFLayout *layout, HWND hwnd, SIZE *minSize); static void ALF_Panel_IntializePriv(ALFPanelPriv *priv) { ALF_Layout_Init(&priv->layout); priv->layout.endCalcSizes = ALF_Panel_CalculateContainerMetrics; } static void ALF_Panel_ClearPriv(ALFPanelPriv *priv) { ALF_Layout_Clear(&priv->layout); } static void ALF_Panel_InternalDefPaint(ALFPanelPriv *priv, HWND hwnd, HDC dc, RECT *r) { RECT r2; GetClientRect(hwnd, &r2); if (priv->edge) { DrawEdge(dc, &r2, priv->edge, BF_ADJUST|BF_RECT); } IntersectRect(&r2, &r2, r); if (priv->layout.bgcolor == ALF_COLOR_TRANSPARENT) { ALF_Compat_DrawThemeParentBackground(hwnd, dc, &r2); } else { ALF_FillRect(dc, &r2, priv->layout.bgcolor); } } void ALF_Panel_DefPaint(HWND panel, HDC hDC, RECT *rcPaint) { ALFPanelPriv *priv = (ALFPanelPriv*)GetWindowLongPtr(panel, 0); ALF_Panel_InternalDefPaint(priv, panel, hDC, rcPaint); } static void ALF_Panel_Paint(ALFPanelPriv *priv, HWND hwnd, HDC dc, RECT *r) { if (priv->vtbl && priv->vtbl->paint) { priv->vtbl->paint(priv->closure, hwnd, dc, r); } else { ALF_Panel_InternalDefPaint(priv, hwnd, dc, r); } } static void ALF_Panel_InternalSetEdge(ALFPanelPriv *priv, HWND hwnd, DWORD edge) { if (priv->edge == edge) return; priv->edge = edge; ALF_Layout_Invalidate(&priv->layout, hwnd); InvalidateRect(hwnd, NULL, TRUE); } void ALF_Panel_SetVTable(HWND panel, const ALFPanelVTable *vtbl, void *closure) { ALFPanelSetVtblParams p = { vtbl, closure }; SendMessage(panel, ALF_WM_PANEL_SETVTABLE, 0, (LPARAM)&p); } static void ALF_Panel_CalculateContainerMetrics(ALFLayout *layout, HWND hwnd, SIZE *minSize) { (void)hwnd; ALFPanelPriv *priv = (ALFPanelPriv *)layout; int w = 0; if (priv->edge & BDR_INNER) w++; if (priv->edge & BDR_OUTER) w++; priv->layout.containerMargins.left = w; priv->layout.containerMargins.top = w; priv->layout.containerMargins.right = w; priv->layout.containerMargins.bottom = w; minSize->cx = minSize->cy = 2*w; } LRESULT ALF_Panel_DefWindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) { ALFPanelPriv *priv = (ALFPanelPriv *)GetWindowLongPtr(window, 0); if (msg == WM_DESTROY) { if (priv->vtbl && priv->vtbl->destroy) priv->vtbl->destroy(priv->closure, window); } if (msg == WM_ERASEBKGND) { return TRUE; } if (msg == WM_PRINTCLIENT) { RECT r = { 0, 0, 0, 0 }; GetClientRect(window, &r); ALF_Panel_Paint(priv, window, (HDC)wparam, &r); return TRUE; } if (msg == WM_PAINT) { PAINTSTRUCT ps; HDC dc = BeginPaint(window, &ps); ALF_Panel_Paint(priv, window, dc, &ps.rcPaint); EndPaint(window, &ps); return 0; } if (msg == ALF_WM_PANEL_SETVTABLE) { const ALFPanelSetVtblParams *params = (const ALFPanelSetVtblParams *)lparam; if (!params) return FALSE; priv->vtbl = params->vtbl; priv->closure = params->closure; if (priv->vtbl->attachvtbl) { priv->vtbl->attachvtbl(priv->closure, window); } return TRUE; } if (msg == ALF_WM_PANEL_GETEDGE) { return (LRESULT)priv->edge; } if (msg == ALF_WM_PANEL_SETEDGE) { ALF_Panel_InternalSetEdge(priv, window, (DWORD)lparam); return TRUE; } if (ALF_ShouldMessageBubble(window, msg, wparam, lparam)) return SendMessage(GetParent(window), msg, wparam, lparam); if (msg == WM_SIZE) { // if we have a border, invalidate that (and only that) when resizing if (priv->edge) { RECT c; GetClientRect(window, &c); if (c.right > priv->layout.allocatedWidgetRect.right + priv->layout.containerMargins.right) { // enlarged to the right -> invalidate place occupied by old border RECT i = { priv->layout.allocatedWidgetRect.right, 0, c.right, c.bottom }; InvalidateRect(window, &i, TRUE); } if (c.bottom > priv->layout.allocatedWidgetRect.bottom + priv->layout.containerMargins.bottom) { // enlarged to the bottom -> invalidate place occupied by old border RECT i = { 0, priv->layout.allocatedWidgetRect.bottom, c.right, c.bottom }; InvalidateRect(window, &i, TRUE); } if (c.right < priv->layout.allocatedWidgetRect.right + priv->layout.containerMargins.right) { // shrunk horizontally -> invalidate place now occupied by new border RECT i = { c.right - priv->layout.containerMargins.right, 0, c.right, c.bottom }; InvalidateRect(window, &i, TRUE); } if (c.bottom < priv->layout.allocatedWidgetRect.bottom + priv->layout.containerMargins.bottom) { // shrunk vertically -> invalidate place now ocuupied by new border RECT i = { 0, c.bottom - priv->layout.containerMargins.bottom, c.right, c.bottom }; InvalidateRect(window, &i, TRUE); } } ALF_Layout_Apply(&priv->layout, window); } LRESULT ret = 0; if (ALF_Layout_HandleMessage(&priv->layout, window, msg, wparam, lparam, &ret)) return ret; return DefWindowProc(window, msg, wparam, lparam); } DWORD ALF_Panel_Edge(HWND panel) { return (DWORD)SendMessage(panel, ALF_WM_PANEL_GETEDGE, 0, 0); } void ALF_Panel_SetEdge(HWND panel, DWORD edge) { SendMessage(panel, ALF_WM_PANEL_SETEDGE, 0, (LPARAM)edge); } static LRESULT WINAPI ALF_Panel_WindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) { if (msg == WM_NCCREATE) { ALFPanelPriv *p = ALF_New(ALFPanelPriv, 1); ALF_Panel_IntializePriv(p); SetWindowLongPtr(window, 0, (LONG_PTR)p); } ALFPanelPriv *priv = (ALFPanelPriv *)GetWindowLongPtr(window, 0); if (msg == WM_NCDESTROY) { ALF_Panel_ClearPriv(priv); ALF_Free(priv); priv = NULL; SetWindowLongPtr(window, 0, 0); } if (priv) { if (priv->vtbl && priv->vtbl->message) { return priv->vtbl->message(priv->closure, window, msg, wparam, lparam); } else { return ALF_Panel_DefWindowProc(window, msg, wparam, lparam); } } else { return DefWindowProc(window, msg, wparam, lparam); } } HWND ALF_CreatePanelWindow(HWND parent, WORD id) { return ALF_CreateControlWindow(WS_EX_CONTROLPARENT, TEXT(""), WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0, 0, 0, 0, parent, (HMENU)(ULONG_PTR)id, ALF_Panel_WindowProc, NULL); } HWND 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_LAYOUT_INHERITBGCOLOR | ALF_LAYOUT_SENDBGCHANGE | ALF_LAYOUT_SENDDPICHANGE); return hwndPanel; }