summaryrefslogtreecommitdiff
path: root/alf
diff options
context:
space:
mode:
Diffstat (limited to 'alf')
-rw-r--r--alf/alf.cpp318
-rw-r--r--alf/alf.h4
-rw-r--r--alf/alfcompat.h2
-rw-r--r--alf/alflayout.cpp324
-rw-r--r--alf/alflayout.h70
-rw-r--r--alf/alflist.h1
-rw-r--r--alf/alfpriv.h39
7 files changed, 435 insertions, 323 deletions
diff --git a/alf/alf.cpp b/alf/alf.cpp
index 03c0fbf..5ee591d 100644
--- a/alf/alf.cpp
+++ b/alf/alf.cpp
@@ -10,8 +10,8 @@ ALF_InitializeWindowPriv(HWND hwnd, ALFWindowPriv *priv, void *closure)
priv->vtbl = (ALFWindowVTable*)GetClassLongPtr(hwnd, 0);
priv->app = (ALFAPP)GetClassLongPtr(hwnd, sizeof(void*));
priv->closure = closure;
- ALF_ListInit(&priv->widgets);
priv->defid = (WORD)-1;
+ ALF_Layout_Init(&priv->layout);
}
static void
@@ -20,10 +20,7 @@ ALF_DestroyWindowPriv(ALFWindowPriv *priv)
if (priv->vtbl->postdestroy)
priv->vtbl->postdestroy(priv->closure);
- ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, w) {
- HeapFree(GetProcessHeap(), 0, w);
- }
- ALF_ListInit(&priv->widgets);
+ ALF_Layout_Clear(&priv->layout);
if (priv->fonts.hMessageFont)
DeleteObject(priv->fonts.hMessageFont);
@@ -39,18 +36,6 @@ ALF_CentipointsToPxPriv(ALFWindowPriv *priv, int cptValue)
return MulDiv(cptValue, priv->fonts.dpi, 7200);
}
-static void
-ALF_UpdateFontForWidget(ALFWindowPriv *priv, ALFWidgetPriv *widget)
-{
- if (widget->hwnd && (widget->flags & ALF_MESSAGEFONT) == ALF_MESSAGEFONT) {
- SendMessage(widget->hwnd, WM_SETFONT, (WPARAM)priv->fonts.hMessageFont, (LPARAM)NULL);
-
- // XXX: Invalidating should IMHO be the decision of the control, but at
- // least the commctl32 V5 static control doesn't do it.
- InvalidateRect(widget->hwnd, NULL, TRUE);
- }
-}
-
void
ALF_UpdateFonts(HWND win)
{
@@ -89,9 +74,7 @@ ALF_UpdateFontsPriv(HWND win, ALFWindowPriv *priv)
priv->fonts.hMessageFont = CreateFontIndirect(&priv->fonts.lfMessageFont);
}
- ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, i) {
- ALF_UpdateFontForWidget(priv, i);
- }
+ ALF_Layout_UpdateFonts(&priv->layout, win, &priv->fonts);
if (priv->vtbl->updatefonts) {
priv->vtbl->updatefonts(priv->closure, win, &priv->fonts);
@@ -107,264 +90,6 @@ ALF_RecalculateLayout(HWND hwnd)
}
static void
-ALF_CalculateSizes(ALFWindowPriv *win)
-{
- for (int i = 0; i < win->layout.nColumns; ++i) {
- ZeroMemory(&win->layout.columns[i], sizeof(win->layout.columns[i]));
- }
- for (int i = 0; i < win->layout.nRows; ++i) {
- ZeroMemory(&win->layout.rows[i], sizeof(win->layout.rows[i]));
- }
-
- ALF_FOR_LIST(ALFWidgetPriv, list, &win->widgets, c) {
- while ((int)c->x >= win->layout.nColumns) {
- // FIXME! overflow, use reallocarray(2) equivalent
- if (win->layout.nColumns == 0) {
- win->layout.nColumns = 1;
- win->layout.columns = (ALFRowOrColumn*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, win->layout.nColumns*sizeof(win->layout.columns[0]));
- } else {
- win->layout.nColumns *= 2;
- win->layout.columns = (ALFRowOrColumn*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, win->layout.columns, win->layout.nColumns*sizeof(win->layout.columns[0]));
- }
- }
- while ((int)c->y >= win->layout.nRows) {
- // FIXME! overflow, use reallocarray(2) equivalent
- if (win->layout.nRows == 0) {
- win->layout.nRows = 1;
- win->layout.rows = (ALFRowOrColumn*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, win->layout.nRows*sizeof(win->layout.rows[0]));
- } else {
- win->layout.nRows *= 2;
- win->layout.rows = (ALFRowOrColumn*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, win->layout.rows, win->layout.nRows*sizeof(win->layout.rows[0]));
- }
- }
-
- // TODO: ignore spanning cell
-
- SIZE qs = { ALF_CentipointsToPxPriv(win, c->cptWidth),
- ALF_CentipointsToPxPriv(win, c->cptHeight) };
- if ((c->flags & ALF_QUERYSIZE) == ALF_QUERYSIZE) {
- SendMessage(c->hwnd, ALF_WM_QUERYSIZE, 0, (LPARAM)&qs);
- }
-
- qs.cx += ALF_CentipointsToPxPriv(win, c->cptMarginLeft);
- qs.cx += ALF_CentipointsToPxPriv(win, c->cptMarginRight);
- qs.cy += ALF_CentipointsToPxPriv(win, c->cptMarginTop);
- qs.cy += ALF_CentipointsToPxPriv(win, c->cptMarginBottom);
-
- if (qs.cx > win->layout.columns[c->x].minWidth)
- win->layout.columns[c->x].minWidth = qs.cx;
- if (qs.cy > win->layout.rows[c->y].minWidth)
- win->layout.rows[c->y].minWidth = qs.cy;
-
- // TODO: expand flag
- }
-
- // TODO: second pass for spanning cells
-
- // update min width bookkeeping
- win->layout.totalMinWidth = 0;
- win->layout.occupiedColumnCount = 0;
- for (int i = 0; i < win->layout.nColumns; ++i) {
- if (win->layout.columns[i].minWidth > 0) {
- win->layout.totalMinWidth += win->layout.columns[i].minWidth;
- win->layout.occupiedColumnCount++;
- // TODO: expand flag
- }
- }
- win->layout.totalMinHeight = 0;
- win->layout.occupiedRowCount = 0;
- for (int i = 0; i < win->layout.nRows; ++i) {
- if (win->layout.rows[i].minWidth > 0) {
- win->layout.totalMinHeight += win->layout.rows[i].minWidth;
- win->layout.occupiedRowCount++;
- // TODO: expand flag
- }
- }
-
- // TODO: split here into allocation function
-}
-
-static void
-ALF_ApplyLayout(HWND hwnd, ALFWindowPriv *win)
-{
- // allocate cell positions
- // distribute free space
- int extraWidth = 0;
- int extraHeight = 0;
- RECT client;
- if (GetClientRect(hwnd, &client)) {
- if (client.right - client.left > win->layout.totalMinWidth)
- extraWidth = client.right - client.left - win->layout.totalMinWidth;
- if (client.bottom - client.top > win->layout.totalMinHeight)
- extraHeight = client.bottom - client.top - win->layout.totalMinHeight;
- }
-
- int extraWidthPart = 0;
- int extraWidthError = 0;
- if (win->layout.occupiedColumnCount) {
- extraWidthPart = extraWidth / win->layout.occupiedColumnCount;
- extraWidthError = extraWidth - extraWidthPart * win->layout.occupiedColumnCount;
- }
-
- for (int i = 0; i < win->layout.nColumns; ++i) {
- win->layout.columns[i].allocatedWidth = win->layout.columns[i].minWidth;
-
- if (win->layout.columns[i].minWidth > 0) {
- win->layout.columns[i].allocatedWidth += extraWidthPart;
- if (extraWidthError) {
- win->layout.columns[i].allocatedWidth++;
- extraWidthError--;
- }
- }
-
- if (i == 0) {
- win->layout.columns[i].allocatedPosition = 0;
- } else {
- win->layout.columns[i].allocatedPosition =
- win->layout.columns[i-1].allocatedPosition + win->layout.columns[i-1].allocatedWidth;
- }
- }
-
-
- int extraHeightPart = 0;
- int extraHeightError = 0;
- if (win->layout.occupiedRowCount) {
- extraHeightPart = extraHeight / win->layout.occupiedRowCount;
- extraHeightError = extraHeight - extraHeightPart * win->layout.occupiedRowCount;
- }
-
- for (int i = 0; i < win->layout.nRows; ++i) {
- win->layout.rows[i].allocatedWidth = win->layout.rows[i].minWidth;
-
- if (win->layout.rows[i].minWidth > 0) {
- win->layout.rows[i].allocatedWidth += extraHeightPart;
- if (extraHeightError) {
- win->layout.rows[i].allocatedWidth++;
- extraHeightError--;
- }
- }
-
- if (i == 0) {
- win->layout.rows[i].allocatedPosition = 0;
- } else {
- win->layout.rows[i].allocatedPosition =
- win->layout.rows[i-1].allocatedPosition + win->layout.rows[i-1].allocatedWidth;
- }
- }
-
- HDWP hdwp = BeginDeferWindowPos(win->layout.occupiedColumnCount * win->layout.occupiedRowCount);
-
- ALF_FOR_LIST(ALFWidgetPriv, list, &win->widgets, c) {
- if ((int)c->x >= win->layout.nColumns || (int)c->y >= win->layout.nRows)
- continue;
-
- int marginleft = ALF_CentipointsToPxPriv(win, c->cptMarginLeft);
- int marginright = ALF_CentipointsToPxPriv(win, c->cptMarginRight);
- int margintop = ALF_CentipointsToPxPriv(win, c->cptMarginTop);
- int marginbottom = ALF_CentipointsToPxPriv(win, c->cptMarginBottom);
-
- RECT r = { 0,0,0,0 };
- r.left = win->layout.columns[c->x].allocatedPosition + marginleft;
- r.right = r.left + win->layout.columns[c->x].allocatedWidth - marginleft - marginright;
- r.top = win->layout.rows[c->y].allocatedPosition + margintop;
- r.bottom = r.top + win->layout.rows[c->y].allocatedWidth - margintop - marginbottom;
-
- if (c->flags & ALF_APPLYSIZE) {
- hdwp = (HDWP)SendMessage(c->hwnd, ALF_WM_APPLYSIZE, (WPARAM)hdwp, (LPARAM)&r);
- } else {
- hdwp = DeferWindowPos(hdwp,
- c->hwnd, 0,
- r.left, r.top, r.right - r.left, r.bottom - r.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
- }
- }
-
- EndDeferWindowPos(hdwp);
-}
-
-static void
-ALF_InternalAddWidget(HWND hwnd, ALFWindowPriv *priv, ALFWidgetLayoutParams *params)
-{
- ALFWidgetPriv *w = (ALFWidgetPriv*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, sizeof(ALFWidgetPriv));
- w->hwnd = params->hwnd;
- w->x = params->x;
- w->y = params->y;
- w->cptWidth = params->width;
- w->cptHeight = params->height;
- w->flags = params->flags;
- w->cptMarginTop = params->margins[0];
- w->cptMarginRight = params->margins[1];
- w->cptMarginBottom = params->margins[2];
- w->cptMarginLeft = params->margins[3];
-
- if (GetParent(w->hwnd) != hwnd)
- SetParent(w->hwnd, hwnd);
-
- // TODO: QUERYUISTATE on parent, then replicate in child. But wait, XP appears to do this automatically!??
-
- ALF_ListInsert(priv->widgets.prev, &w->list);
- ALF_UpdateFontForWidget(priv, w);
-}
-
-static BOOL
-ALF_InternalSetLayoutParams(ALFWindowPriv *priv, HWND widget, const ALFWidgetLayoutParams *params)
-{
- ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, w) {
- if (w->hwnd == widget) {
- w->hwnd = params->hwnd;
- w->x = params->x;
- w->y = params->y;
- w->cptWidth = params->width;
- w->cptHeight = params->height;
- w->flags = params->flags;
- w->cptMarginTop = params->margins[0];
- w->cptMarginRight = params->margins[1];
- w->cptMarginBottom = params->margins[2];
- w->cptMarginLeft = params->margins[3];
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static BOOL
-ALF_InternalGetLayoutParams(ALFWindowPriv *priv, HWND widget, ALFWidgetLayoutParams *params)
-{
- ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, w) {
- if (w->hwnd == widget) {
- params->hwnd = w->hwnd;
- params->x = w->x;
- params->y = w->y;
- params->width = w->cptWidth;
- params->height = w->cptHeight;
- params->flags = w->flags;
- params->margins[0] = w->cptMarginTop;
- params->margins[1] = w->cptMarginRight;
- params->margins[2] = w->cptMarginBottom;
- params->margins[3] = w->cptMarginLeft;
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static HWND
-ALF_InternalGetWidgetAtPos(ALFWindowPriv *priv, UINT x, UINT y)
-{
- ALF_FOR_LIST(ALFWidgetPriv, list, &priv->widgets, w) {
- if (w->x == x && w->y == y) {
- return w->hwnd;
- }
- }
-
- return NULL;
-}
-
-static void
ALF_ApplyFocus(HWND hwnd, ALFWindowPriv *priv, BOOL restoringFocus)
{
if (priv->hwndFocus) {
@@ -386,7 +111,7 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
ALFWindowPriv *priv = (ALFWindowPriv*)GetWindowLongPtr(hwnd, 0);
if (msg == ALF_WM_QUERYSIZE) {
- ALF_CalculateSizes(priv);
+ ALF_Layout_CalcSizes(&priv->layout, hwnd);
SIZE *ps = (SIZE*)lparam;
ps->cx = priv->layout.totalMinWidth;
ps->cy = priv->layout.totalMinHeight;
@@ -394,7 +119,7 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
if (msg == ALF_WM_APPLYLAYOUT) {
- ALF_ApplyLayout(hwnd, priv);
+ ALF_Layout_Apply(&priv->layout, hwnd);
return 0;
}
@@ -411,20 +136,20 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
if (msg == ALF_WM_ADDWIDGET) {
- ALF_InternalAddWidget(hwnd, priv, (ALFWidgetLayoutParams *)lparam);
+ ALF_Layout_AddWidget(&priv->layout, hwnd, (ALFWidgetLayoutParams *)lparam);
return 0;
}
if (msg == ALF_WM_GETLAYOUTPARAMS) {
- return (LRESULT)ALF_InternalGetLayoutParams(priv, (HWND)wparam, (ALFWidgetLayoutParams *)lparam);
+ return (LRESULT)ALF_Layout_GetWidgetParams(&priv->layout, (ALFWidgetLayoutParams *)lparam, (HWND)wparam);
}
if (msg == ALF_WM_SETLAYOUTPARAMS) {
- return (LRESULT)ALF_InternalSetLayoutParams(priv, (HWND)wparam, (const ALFWidgetLayoutParams *)lparam);
+ return (LRESULT)ALF_Layout_SetWidgetParams(&priv->layout, (const ALFWidgetLayoutParams *)lparam, (HWND)wparam);
}
if (msg == ALF_WM_GETWIDGETATPOS) {
- return (LRESULT)ALF_InternalGetWidgetAtPos(priv, ((UINT*)lparam)[0], ((UINT*)lparam)[1]);
+ return (LRESULT)ALF_Layout_WidgetAtPos(&priv->layout, ((UINT*)lparam)[0], ((UINT*)lparam)[1]);
}
if (msg == ALF_WM_SETFOCUS) {
@@ -442,6 +167,11 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
return 0;
}
+ if (msg == ALF_WM_GETWINDOWFONTS) {
+ *((ALFWindowFonts *)lparam) = priv->fonts;
+ return TRUE;
+ }
+
if (msg == WM_COMMAND) {
HWND source = (HWND)lparam;
WORD code = HIWORD(wparam);
@@ -481,7 +211,7 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
if (msg == WM_SIZE) {
- ALF_ApplyLayout(hwnd, priv);
+ ALF_Layout_Apply(&priv->layout, hwnd);
return 0;
}
@@ -514,8 +244,8 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
SendMessage(hwnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
}
ALF_UpdateFontsPriv(hwnd, priv);
- ALF_CalculateSizes(priv);
- ALF_ApplyLayout(hwnd, priv);
+ ALF_Layout_CalcSizes(&priv->layout, hwnd);
+ ALF_Layout_Apply(&priv->layout, hwnd);
}
if (msg == WM_DESTROY && priv->vtbl->destroy) {
@@ -537,15 +267,15 @@ ALF_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
if (msg == WM_DPICHANGED) {
ALF_UpdateFontsPriv(hwnd, priv);
- ALF_CalculateSizes(priv);
+ ALF_Layout_CalcSizes(&priv->layout, hwnd);
RECT *r = (RECT*)lparam;
SetWindowPos(hwnd, NULL, r->left, r->top, r->right-r->left, r->bottom-r->top, SWP_NOACTIVATE|SWP_NOZORDER);
}
if (msg == WM_THEMECHANGED || msg == WM_SETTINGCHANGE) {
ALF_UpdateFontsPriv(hwnd, priv);
- ALF_CalculateSizes(priv);
- ALF_ApplyLayout(hwnd, priv);
+ ALF_Layout_CalcSizes(&priv->layout, hwnd);
+ ALF_Layout_Apply(&priv->layout, hwnd);
}
if (msg == DM_GETDEFID) {
@@ -979,3 +709,11 @@ ALF_WidgetAtLayoutPosition(HWND parent, UINT x, UINT y)
return (HWND)SendMessage(parent, ALF_WM_GETWIDGETATPOS, 0, (LPARAM)&xy);
}
+
+
+BOOL
+ALF_WindowFonts(HWND window, ALFWindowFonts *fonts)
+{
+ return (BOOL)SendMessage(window, ALF_WM_GETWINDOWFONTS, 0, (LPARAM)fonts);
+}
+
diff --git a/alf/alf.h b/alf/alf.h
index 13b2571..b60ae2a 100644
--- a/alf/alf.h
+++ b/alf/alf.h
@@ -48,6 +48,7 @@ typedef struct {
#define ALF_WM_GETLAYOUTPARAMS (ALF_WM__BASE + 13)
#define ALF_WM_SETLAYOUTPARAMS (ALF_WM__BASE + 14)
#define ALF_WM_GETWIDGETATPOS (ALF_WM__BASE + 15)
+#define ALF_WM_GETWINDOWFONTS (ALF_WM__BASE + 16)
typedef struct {
const TCHAR *className;
@@ -193,6 +194,9 @@ ALF_SetWidgetLayoutSize(HWND parent, HWND widget, UINT cptWidth, UINT cptHeight)
HWND
ALF_WidgetAtLayoutPosition(HWND parent, UINT x, UINT y);
+BOOL
+ALF_WindowFonts(HWND window, ALFWindowFonts *fonts);
+
// combo box
HWND
diff --git a/alf/alfcompat.h b/alf/alfcompat.h
index 2d590c8..98a2abc 100644
--- a/alf/alfcompat.h
+++ b/alf/alfcompat.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include <windows.h>
#include <rpc.h>
diff --git a/alf/alflayout.cpp b/alf/alflayout.cpp
new file mode 100644
index 0000000..8d03a6b
--- /dev/null
+++ b/alf/alflayout.cpp
@@ -0,0 +1,324 @@
+#include "alfpriv.h"
+
+void
+ALF_Layout_Init(ALFLayout *layout)
+{
+ ZeroMemory(layout, sizeof(*layout));
+ ALF_ListInit(&layout->widgets);
+}
+
+void
+ALF_Layout_Clear(ALFLayout *layout)
+{
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, w) {
+ HeapFree(GetProcessHeap(), 0, w);
+ }
+ ALF_ListInit(&layout->widgets);
+}
+
+
+static void
+ALF_UpdateFontForWidget(ALFWidgetPriv *widget, const ALFWindowFonts *fonts)
+{
+ if (widget->hwnd && (widget->flags & ALF_MESSAGEFONT) == ALF_MESSAGEFONT) {
+ SendMessage(widget->hwnd, WM_SETFONT, (WPARAM)fonts->hMessageFont, (LPARAM)NULL);
+
+ // XXX: Invalidating should IMHO be the decision of the control, but at
+ // least the commctl32 V5 static control doesn't do it.
+ InvalidateRect(widget->hwnd, NULL, TRUE);
+ }
+}
+
+void
+ALF_Layout_UpdateFonts(ALFLayout *layout, HWND window, const ALFWindowFonts *fonts)
+{
+ (void)window;
+
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, i) {
+ ALF_UpdateFontForWidget(i, fonts);
+ }
+}
+
+void
+ALF_Layout_CalcSizes(ALFLayout* layout, HWND window)
+{
+ for (int i = 0; i < layout->nColumns; ++i) {
+ ZeroMemory(&layout->columns[i], sizeof(layout->columns[i]));
+ }
+ for (int i = 0; i < layout->nRows; ++i) {
+ ZeroMemory(&layout->rows[i], sizeof(layout->rows[i]));
+ }
+
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, c) {
+ while ((int)c->x >= layout->nColumns) {
+ // FIXME! overflow, use reallocarray(2) equivalent
+ if (layout->nColumns == 0) {
+ layout->nColumns = 1;
+ layout->columns = (ALFLayoutRowOrColumn*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, layout->nColumns*sizeof(layout->columns[0]));
+ } else {
+ layout->nColumns *= 2;
+ layout->columns = (ALFLayoutRowOrColumn*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, layout->columns, layout->nColumns*sizeof(layout->columns[0]));
+ }
+ }
+ while ((int)c->y >= layout->nRows) {
+ // FIXME! overflow, use reallocarray(2) equivalent
+ if (layout->nRows == 0) {
+ layout->nRows = 1;
+ layout->rows = (ALFLayoutRowOrColumn*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, layout->nRows*sizeof(layout->rows[0]));
+ } else {
+ layout->nRows *= 2;
+ layout->rows = (ALFLayoutRowOrColumn*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, layout->rows, layout->nRows*sizeof(layout->rows[0]));
+ }
+ }
+
+ // TODO: ignore spanning cell
+
+ SIZE qs = { ALF_CentipointsToPixels(window, c->cptWidth),
+ ALF_CentipointsToPixels(window, c->cptHeight) };
+ if ((c->flags & ALF_QUERYSIZE) == ALF_QUERYSIZE) {
+ SendMessage(c->hwnd, ALF_WM_QUERYSIZE, 0, (LPARAM)&qs);
+ }
+
+ qs.cx += ALF_CentipointsToPixels(window, c->cptMarginLeft);
+ qs.cx += ALF_CentipointsToPixels(window, c->cptMarginRight);
+ qs.cy += ALF_CentipointsToPixels(window, c->cptMarginTop);
+ qs.cy += ALF_CentipointsToPixels(window, c->cptMarginBottom);
+
+ if (qs.cx > layout->columns[c->x].minWidth)
+ layout->columns[c->x].minWidth = qs.cx;
+ if (qs.cy > layout->rows[c->y].minWidth)
+ layout->rows[c->y].minWidth = qs.cy;
+
+ // expand flag
+ if (c->flags & ALF_HEXPAND)
+ layout->columns[c->x].expand = 1;
+ if (c->flags & ALF_VEXPAND)
+ layout->rows[c->y].expand = 1;
+ }
+
+ // TODO: second pass for spanning cells
+
+ // update min width bookkeeping
+ layout->totalMinWidth = 0;
+ layout->expandoColumnCount = 0;
+ for (int i = 0; i < layout->nColumns; ++i) {
+ layout->totalMinWidth += layout->columns[i].minWidth;
+
+ if (layout->columns[i].expand)
+ layout->expandoColumnCount++;
+ }
+
+ if (layout->expandoColumnCount == 0) {
+ // mark all columns as expanding
+ for (int i = 0; i < layout->nColumns; ++i) {
+ if (layout->columns[i].minWidth > 0) {
+ layout->columns[i].expand = 1;
+ layout->expandoColumnCount++;
+ }
+ }
+ }
+
+ layout->totalMinHeight = 0;
+ layout->expandoRowCount = 0;
+ for (int i = 0; i < layout->nRows; ++i) {
+ layout->totalMinHeight += layout->rows[i].minWidth;
+
+ if (layout->rows[i].expand)
+ layout->expandoRowCount++;
+ }
+
+ if (layout->expandoRowCount == 0) {
+ // mark all rows as expanding
+ for (int i = 0; i < layout->nRows; ++i) {
+ if (layout->rows[i].minWidth > 0) {
+ layout->rows[i].expand = 1;
+ layout->expandoRowCount++;
+ }
+ }
+ }
+}
+
+void
+ALF_Layout_Apply(ALFLayout* layout, HWND window)
+{
+ // allocate cell positions
+ // distribute free space
+ int extraWidth = 0;
+ int extraHeight = 0;
+ RECT client;
+ if (GetClientRect(window, &client)) {
+ if (client.right - client.left > layout->totalMinWidth)
+ extraWidth = client.right - client.left - layout->totalMinWidth;
+ if (client.bottom - client.top > layout->totalMinHeight)
+ extraHeight = client.bottom - client.top - layout->totalMinHeight;
+ }
+
+ int extraWidthPart = 0;
+ int extraWidthError = 0;
+ if (layout->expandoColumnCount) {
+ extraWidthPart = extraWidth / layout->expandoColumnCount;
+ extraWidthError = extraWidth - extraWidthPart * layout->expandoColumnCount;
+ }
+
+ for (int i = 0; i < layout->nColumns; ++i) {
+ layout->columns[i].allocatedWidth = layout->columns[i].minWidth;
+
+ if (layout->columns[i].expand) {
+ layout->columns[i].allocatedWidth += extraWidthPart;
+ if (extraWidthError) {
+ layout->columns[i].allocatedWidth++;
+ extraWidthError--;
+ }
+ }
+
+ if (i == 0) {
+ layout->columns[i].allocatedPosition = 0;
+ } else {
+ layout->columns[i].allocatedPosition =
+ layout->columns[i-1].allocatedPosition + layout->columns[i-1].allocatedWidth;
+ }
+ }
+
+
+ int extraHeightPart = 0;
+ int extraHeightError = 0;
+ if (layout->expandoRowCount) {
+ extraHeightPart = extraHeight / layout->expandoRowCount;
+ extraHeightError = extraHeight - extraHeightPart * layout->expandoRowCount;
+ }
+
+ for (int i = 0; i < layout->nRows; ++i) {
+ layout->rows[i].allocatedWidth = layout->rows[i].minWidth;
+
+ if (layout->rows[i].expand) {
+ layout->rows[i].allocatedWidth += extraHeightPart;
+ if (extraHeightError) {
+ layout->rows[i].allocatedWidth++;
+ extraHeightError--;
+ }
+ }
+
+ if (i == 0) {
+ layout->rows[i].allocatedPosition = 0;
+ } else {
+ layout->rows[i].allocatedPosition =
+ layout->rows[i-1].allocatedPosition + layout->rows[i-1].allocatedWidth;
+ }
+ }
+
+ HDWP hdwp = BeginDeferWindowPos(layout->nColumns * layout->nRows);
+
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, c) {
+ if ((int)c->x >= layout->nColumns || (int)c->y >= layout->nRows)
+ continue;
+
+ int marginleft = ALF_CentipointsToPixels(window, c->cptMarginLeft);
+ int marginright = ALF_CentipointsToPixels(window, c->cptMarginRight);
+ int margintop = ALF_CentipointsToPixels(window, c->cptMarginTop);
+ int marginbottom = ALF_CentipointsToPixels(window, c->cptMarginBottom);
+
+ RECT r = { 0,0,0,0 };
+ r.left = layout->columns[c->x].allocatedPosition + marginleft;
+ r.right = r.left + layout->columns[c->x].allocatedWidth - marginleft - marginright;
+ r.top = layout->rows[c->y].allocatedPosition + margintop;
+ r.bottom = r.top + layout->rows[c->y].allocatedWidth - margintop - marginbottom;
+
+ if (c->flags & ALF_APPLYSIZE) {
+ hdwp = (HDWP)SendMessage(c->hwnd, ALF_WM_APPLYSIZE, (WPARAM)hdwp, (LPARAM)&r);
+ } else {
+ hdwp = DeferWindowPos(hdwp,
+ c->hwnd, 0,
+ r.left, r.top, r.right - r.left, r.bottom - r.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+ }
+
+ EndDeferWindowPos(hdwp);
+}
+
+void
+ALF_Layout_AddWidget(ALFLayout* layout, HWND window, const ALFWidgetLayoutParams* params)
+{
+ ALFWidgetPriv *w = (ALFWidgetPriv*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY|HEAP_GENERATE_EXCEPTIONS, sizeof(ALFWidgetPriv));
+ w->hwnd = params->hwnd;
+ w->x = params->x;
+ w->y = params->y;
+ w->cptWidth = params->width;
+ w->cptHeight = params->height;
+ w->flags = params->flags;
+ w->cptMarginTop = params->margins[0];
+ w->cptMarginRight = params->margins[1];
+ w->cptMarginBottom = params->margins[2];
+ w->cptMarginLeft = params->margins[3];
+
+ if (GetParent(w->hwnd) != window)
+ SetParent(w->hwnd, window);
+
+ ALF_ListInsert(layout->widgets.prev, &w->list);
+
+ if (w->flags & ALF_MESSAGEFONT) {
+ ALFWindowFonts fonts;
+ ZeroMemory(&fonts, sizeof(fonts));
+ ALF_WindowFonts(window, &fonts);
+ ALF_UpdateFontForWidget(w, &fonts);
+ }
+}
+
+BOOL
+ALF_Layout_SetWidgetParams(ALFLayout* layout, const ALFWidgetLayoutParams* params, HWND widget)
+{
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, w) {
+ if (w->hwnd == widget) {
+ w->hwnd = params->hwnd;
+ w->x = params->x;
+ w->y = params->y;
+ w->cptWidth = params->width;
+ w->cptHeight = params->height;
+ w->flags = params->flags;
+ w->cptMarginTop = params->margins[0];
+ w->cptMarginRight = params->margins[1];
+ w->cptMarginBottom = params->margins[2];
+ w->cptMarginLeft = params->margins[3];
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL
+ALF_Layout_GetWidgetParams(ALFLayout* layout, ALFWidgetLayoutParams* params, HWND widget)
+{
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, w) {
+ if (w->hwnd == widget) {
+ params->hwnd = w->hwnd;
+ params->x = w->x;
+ params->y = w->y;
+ params->width = w->cptWidth;
+ params->height = w->cptHeight;
+ params->flags = w->flags;
+ params->margins[0] = w->cptMarginTop;
+ params->margins[1] = w->cptMarginRight;
+ params->margins[2] = w->cptMarginBottom;
+ params->margins[3] = w->cptMarginLeft;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+HWND
+ALF_Layout_WidgetAtPos(ALFLayout* layout, UINT x, UINT y)
+{
+ ALF_FOR_LIST(ALFWidgetPriv, list, &layout->widgets, w) {
+ if (w->x == x && w->y == y) {
+ return w->hwnd;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/alf/alflayout.h b/alf/alflayout.h
new file mode 100644
index 0000000..4787550
--- /dev/null
+++ b/alf/alflayout.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "alf.h"
+#include "alflist.h"
+
+typedef struct {
+ ALFListHeader list;
+ HWND hwnd;
+ UINT x;
+ UINT y;
+ UINT cptWidth;
+ UINT cptHeight;
+ UINT cptMarginTop;
+ UINT cptMarginRight;
+ UINT cptMarginBottom;
+ UINT cptMarginLeft;
+ DWORD flags;
+} ALFWidgetPriv;
+
+typedef struct {
+ int minWidth;
+ int allocatedWidth;
+ int allocatedPosition;
+ int expand : 1;
+} ALFLayoutRowOrColumn;
+
+typedef struct {
+ ALFListHeader widgets;
+ ALFLayoutRowOrColumn *columns;
+ ALFLayoutRowOrColumn *rows;
+ int nColumns;
+ int nRows;
+ int totalMinWidth;
+ int totalMinHeight;
+ int expandoColumnCount;
+ int expandoRowCount;
+} ALFLayout;
+
+void
+ALF_Layout_Init(ALFLayout *layout);
+
+void
+ALF_Layout_Clear(ALFLayout *layout);
+
+void
+ALF_Layout_CalcSizes(ALFLayout *layout, HWND window);
+
+void
+ALF_Layout_Apply(ALFLayout *layout, HWND window);
+
+void
+ALF_Layout_AddWidget(ALFLayout *layout, HWND window, const ALFWidgetLayoutParams *params);
+
+BOOL
+ALF_Layout_RemoveWidget(ALFLayout *layout, HWND window, HWND widget, BOOL destroy);
+
+BOOL
+ALF_Layout_SetWidgetParams(ALFLayout *layout, const ALFWidgetLayoutParams *params, HWND widget);
+
+BOOL
+ALF_Layout_GetWidgetParams(ALFLayout *layout, ALFWidgetLayoutParams *params, HWND widget);
+
+BOOL
+ALF_Layout_HandleMessage(ALFLayout *layout, HWND window, WPARAM wparam, LPARAM lparam);
+
+HWND
+ALF_Layout_WidgetAtPos(ALFLayout *layout, UINT x, UINT y);
+
+void
+ALF_Layout_UpdateFonts(ALFLayout *layout, HWND window, const ALFWindowFonts *fonts);
diff --git a/alf/alflist.h b/alf/alflist.h
index 6f63626..7b4ca66 100644
--- a/alf/alflist.h
+++ b/alf/alflist.h
@@ -1,3 +1,4 @@
+#pragma once
typedef struct ALFListHeader {
struct ALFListHeader *prev;
diff --git a/alf/alfpriv.h b/alf/alfpriv.h
index 95bcda4..acea53a 100644
--- a/alf/alfpriv.h
+++ b/alf/alfpriv.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include "alf.h"
#include <windows.h>
@@ -13,45 +15,13 @@
#include "alflist.h"
#include "alfcompat.h"
-
-typedef struct {
- ALFListHeader list;
- HWND hwnd;
- UINT x;
- UINT y;
- UINT cptWidth;
- UINT cptHeight;
- UINT cptMarginTop;
- UINT cptMarginRight;
- UINT cptMarginBottom;
- UINT cptMarginLeft;
- DWORD flags;
-} ALFWidgetPriv;
-
-typedef struct {
- int minWidth;
- int allocatedWidth;
- int allocatedPosition;
- int expand : 1;
-} ALFRowOrColumn;
-
-typedef struct {
- ALFRowOrColumn *columns;
- ALFRowOrColumn *rows;
- int nColumns;
- int nRows;
- int totalMinWidth;
- int totalMinHeight;
- int occupiedColumnCount;
- int occupiedRowCount;
-} ALFLayout;
+#include "alflayout.h"
typedef struct {
ALFAPP app;
ALFWindowVTable *vtbl;
void *closure;
ALFWindowFonts fonts;
- ALFListHeader widgets;
int modalResult;
ALFLayout layout;
WORD defid;
@@ -64,6 +34,9 @@ struct ALFAppPriv {
TCHAR *comboClass;
};
+int
+ALF_CentipointsToPxPriv(ALFWindowPriv *priv, int cptValue);
+
void
ALF_UpdateFontsPriv(HWND hwnd, ALFWindowPriv *priv);