diff options
Diffstat (limited to 'alf/alfgroupbox.cpp')
| -rw-r--r-- | alf/alfgroupbox.cpp | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/alf/alfgroupbox.cpp b/alf/alfgroupbox.cpp new file mode 100644 index 0000000..a2dfb9b --- /dev/null +++ b/alf/alfgroupbox.cpp @@ -0,0 +1,299 @@ +#include "alfpriv.h" + +TCHAR *_alf_groupboxClass = NULL; + +typedef struct { + ALFLayout layout; + HTHEME theme; + HWND label; + SIZE calculatedLabelSize; +} ALFGroupBoxPriv; + +static void ALF_GroupBox_BeginCalcSizes(ALFLayout *layout, HWND hwnd); + +static void ALF_GroupBox_HandleContainerWidgetSize(ALFLayout *layout, HWND groupbox, HWND child, SIZE *s); + +static void ALF_GroupBox_EndCalcSizes(ALFLayout *layout, HWND hwnd, SIZE *containerMinSize); + +static void ALF_GroupBox_PreContainerWidgetApplyPos(ALFLayout *layout, HWND groupbox, HWND child, RECT *r); + +static void +ALF_GroupBox_IntializePriv(ALFGroupBoxPriv *priv, HWND window, const TCHAR *text) +{ + ALF_Layout_Init(&priv->layout); + priv->layout.beginCalcSizes = ALF_GroupBox_BeginCalcSizes; + priv->layout.handleContainerWidgetSize = ALF_GroupBox_HandleContainerWidgetSize; + priv->layout.endCalcSizes = ALF_GroupBox_EndCalcSizes; + priv->layout.preApplyLayoutToContainerWidget = ALF_GroupBox_PreContainerWidgetApplyPos; + + priv->label = ALF_AddLabel(window, (WORD)-1, -1, -1, text); + ALF_LabelSetStyle(priv->label, ALF_LABEL_ALIGN_LEFT | ALF_LABEL_ALIGN_TOP); +} + +static void +ALF_GroupBox_ClearPriv(ALFGroupBoxPriv *priv) +{ + ALF_Layout_Clear(&priv->layout); +} + +static void +ALF_GroupBox_PaintFrameClassic(ALFGroupBoxPriv *priv, HWND hwnd, HDC dc) +{ + (void)priv; + + HFONT oldfont = SelectFont(dc, priv->layout.font); + + RECT rcClient = { 0,0,0,0 }; + GetClientRect(hwnd, &rcClient); + + + RECT rcLabel = { 0,0,0,0 }; + GetWindowRect(priv->label, &rcLabel); + MapWindowRect(NULL, hwnd, &rcLabel); + + RECT rcFrame; + rcFrame.top = (rcLabel.bottom - rcLabel.top) / 2; + rcFrame.left = 0; + rcFrame.bottom = rcLabel.bottom; + rcFrame.right = rcLabel.left - 2; // XXX: is that correct? + DrawEdge(dc, &rcFrame, EDGE_ETCHED, BF_TOPLEFT); + + rcFrame.left = rcLabel.right + 2; // XXX: is that correct? + rcFrame.right = rcClient.right; + DrawEdge(dc, &rcFrame, EDGE_ETCHED, BF_TOPRIGHT); + + rcFrame.top = rcLabel.bottom; + rcFrame.left = 0; + rcFrame.right = rcClient.right; + rcFrame.bottom = rcClient.bottom; + DrawEdge(dc, &rcFrame, EDGE_ETCHED, BF_LEFT | BF_BOTTOM | BF_RIGHT); + + SelectFont(dc, oldfont); +} + +static void +ALF_GroupBox_Paint(ALFGroupBoxPriv *priv, HWND hwnd, HDC dc, RECT *r) +{ + if (priv->layout.bgcolor == ALF_COLOR_TRANSPARENT) { + ALF_Compat_DrawThemeParentBackground(hwnd, dc, r); + } else { + ALF_FillRect(dc, r, priv->layout.bgcolor); + } + + // unthemed paint + ALF_GroupBox_PaintFrameClassic(priv, hwnd, dc); +} + +static void +ALF_GroupBox_BeginCalcSizes(ALFLayout *layout, HWND hwnd) +{ + ALFGroupBoxPriv *priv = (ALFGroupBoxPriv *)layout; + (void)hwnd; + + priv->layout.containerMargins.left = 2 + ALF_CentipointsToPixels(525, priv->layout.dpi); + priv->layout.containerMargins.top = 2 + ALF_CentipointsToPixels(300, priv->layout.dpi); + priv->layout.containerMargins.right = 2 + ALF_CentipointsToPixels(525, priv->layout.dpi); + priv->layout.containerMargins.bottom = 2 + ALF_CentipointsToPixels(525, priv->layout.dpi); + priv->calculatedLabelSize.cx = 0; + priv->calculatedLabelSize.cy = 0; +} + +static void +ALF_GroupBox_HandleContainerWidgetSize(ALFLayout *layout, HWND groupbox, HWND child, SIZE *s) +{ + ALFGroupBoxPriv *priv = (ALFGroupBoxPriv *)layout; + (void)groupbox; + + if (child == priv->label) { + priv->calculatedLabelSize = *s; + + int h = priv->calculatedLabelSize.cy + ALF_CentipointsToPixels(300, priv->layout.dpi); + if (h > priv->layout.containerMargins.top) { + priv->layout.containerMargins.top = h; + } + } +} + +static void ALF_GroupBox_EndCalcSizes(ALFLayout *layout, HWND hwnd, SIZE *containerMinSize) +{ + ALFGroupBoxPriv *priv = (ALFGroupBoxPriv *)layout; + (void)hwnd; + + containerMinSize->cx = priv->layout.containerMargins.left + priv->layout.containerMargins.right + + priv->calculatedLabelSize.cx; + containerMinSize->cy = priv->layout.containerMargins.top + priv->layout.containerMargins.bottom; +} + +static void ALF_GroupBox_PreContainerWidgetApplyPos(ALFLayout *layout, HWND groupbox, HWND child, RECT *r) +{ + ALFGroupBoxPriv *priv = (ALFGroupBoxPriv *)layout; + + if (child == priv->label) { + RECT rOld; + GetClientRect(child, &rOld); + + if (rOld.bottom - rOld.top != priv->calculatedLabelSize.cy || + rOld.right - rOld.left != priv->calculatedLabelSize.cx) { + // if the label changed, the top part of the border needs to be redrawn + RECT rcGb; + GetClientRect(groupbox, &rcGb); + RECT i = { 0, 0, rcGb.right - rcGb.left, priv->calculatedLabelSize.cy }; + InvalidateRect(groupbox, &i, TRUE); + } + + + r->left = priv->layout.containerMargins.left; + r->top = 0; + r->right = r->left + priv->calculatedLabelSize.cx; + r->bottom = priv->calculatedLabelSize.cy; + } +} + +static LRESULT WINAPI +ALF_GroupBox_WindowProc(HWND window, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_NCCREATE) { + ALFGroupBoxPriv *p = ALF_New(ALFGroupBoxPriv, 1); + SetWindowLongPtr(window, 0, (LONG_PTR)p); + + ALF_GroupBox_IntializePriv(p, window, ((CREATESTRUCT *)lparam)->lpszName); + } + + ALFGroupBoxPriv *priv = (ALFGroupBoxPriv *)GetWindowLongPtr(window, 0); + if (!priv) + return DefWindowProc(window, msg, wparam, lparam); // FIXME! shouldn't happen + + if (msg == WM_NCDESTROY) { + ALF_GroupBox_ClearPriv(priv); + ALF_Free(priv); + priv = NULL; + SetWindowLongPtr(window, 0, 0); + } + + if (msg == WM_ERASEBKGND) { + return TRUE; + } + + if (msg == WM_PRINTCLIENT) { + RECT r = { 0, 0, 0, 0 }; + GetClientRect(window, &r); + + ALF_GroupBox_Paint(priv, window, (HDC)wparam, &r); + + return TRUE; + } + + if (msg == WM_PAINT) { + PAINTSTRUCT ps; + HDC dc = BeginPaint(window, &ps); + + ALF_GroupBox_Paint(priv, window, dc, &ps.rcPaint); + + EndPaint(window, &ps); + + return 0; + } + + if (msg == WM_SETTEXT) { + return SendMessage(priv->label, WM_SETTEXT, wparam, lparam); + } + + if (msg == WM_GETTEXT) { + return SendMessage(priv->label, WM_GETTEXT, wparam, lparam); + } + + if (ALF_ShouldMessageBubble(window, msg, wparam, lparam)) + return SendMessage(GetParent(window), msg, wparam, lparam); + + if (msg == WM_SIZE) { + 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); + } + + if (msg == WM_ENABLE) { + EnableWindow(priv->label, (BOOL)wparam); + } + + LRESULT ret = 0; + if (ALF_Layout_HandleMessage(&priv->layout, window, msg, wparam, lparam, &ret)) + return ret; + + return DefWindowProc(window, msg, wparam, lparam); +} + +void +ALF_RegisterGroupBoxClass(void) +{ + WNDCLASS cls; + ZeroMemory(&cls, sizeof(cls)); + + TCHAR classNameBuf[256]; + ALF_BuildUniqueName(classNameBuf, TEXT("ALFGroupBox."), (ULONG_PTR)&_alf_groupboxClass); + + cls.hInstance = ALF_HINSTANCE; + cls.hCursor = LoadCursor(NULL, (LPTSTR)IDC_ARROW); + cls.lpszClassName = classNameBuf; + cls.cbWndExtra = sizeof(void*); + cls.lpfnWndProc = ALF_GroupBox_WindowProc; + + ATOM classatom = RegisterClass(&cls); + if (!classatom) + MessageBox(NULL, TEXT("FATAL: Could not register groupbox class"), NULL, MB_OK); + + _alf_groupboxClass = MAKEINTATOM(classatom); +} + +HWND +ALF_AddGroupBox(HWND parent, WORD id, int x, int y, const TCHAR *text) +{ + HWND hwndPanel = CreateWindowEx(WS_EX_CONTROLPARENT, + _alf_groupboxClass, + text, + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_TABSTOP, + 0, 0, 0, 0, + parent, + (HMENU)(UINT_PTR)id, + ALF_HINSTANCE, + NULL); + + 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; +} + |
