diff options
| author | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2019-01-05 22:07:51 +0100 |
|---|---|---|
| committer | Jonas Kümmerlin <jonas@kuemmerlin.eu> | 2019-01-05 22:07:51 +0100 |
| commit | db2f529599cea4c86481ed6ca650a5b069c003b0 (patch) | |
| tree | 7f7f6c3449d8811fdf68f28f761efcc9fa4e9b9d /alf/alflayout.cpp | |
| parent | cd7552ae1ce7f6c92d03b7d0a83fe4aec073aeff (diff) | |
move layout into own file, implement expand flag
Diffstat (limited to 'alf/alflayout.cpp')
| -rw-r--r-- | alf/alflayout.cpp | 324 |
1 files changed, 324 insertions, 0 deletions
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; +} + |
