summaryrefslogtreecommitdiff
path: root/alf/alfgroupbox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alf/alfgroupbox.cpp')
-rw-r--r--alf/alfgroupbox.cpp299
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;
+}
+