aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/windows/grid.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl/libui/windows/grid.cpp')
-rw-r--r--src/libui_sdl/libui/windows/grid.cpp665
1 files changed, 0 insertions, 665 deletions
diff --git a/src/libui_sdl/libui/windows/grid.cpp b/src/libui_sdl/libui/windows/grid.cpp
deleted file mode 100644
index 0a854c5..0000000
--- a/src/libui_sdl/libui/windows/grid.cpp
+++ /dev/null
@@ -1,665 +0,0 @@
-// 10 june 2016
-#include "uipriv_windows.hpp"
-
-// TODO compare with GTK+:
-// - what happens if you call InsertAt() twice?
-// - what happens if you call Append() twice?
-
-// TODOs
-// - the Assorted page has clipping and repositioning issues
-
-struct gridChild {
- uiControl *c;
- int left;
- int top;
- int xspan;
- int yspan;
- int hexpand;
- uiAlign halign;
- int vexpand;
- uiAlign valign;
-
- // have these here so they don't need to be reallocated each relayout
- int finalx, finaly;
- int finalwidth, finalheight;
- int minwidth, minheight;
-};
-
-struct uiGrid {
- uiWindowsControl c;
- HWND hwnd;
- std::vector<struct gridChild *> *children;
- std::map<uiControl *, size_t> *indexof;
- int padded;
-
- int xmin, ymin;
- int xmax, ymax;
-};
-
-static bool gridRecomputeMinMax(uiGrid *g)
-{
- bool first = true;
-
- for (struct gridChild *gc : *(g->children)) {
- // this is important; we want g->xmin/g->ymin to satisfy gridLayoutData::visibleRow()/visibleColumn()
- if (!uiControlVisible(gc->c))
- continue;
- if (first) {
- g->xmin = gc->left;
- g->ymin = gc->top;
- g->xmax = gc->left + gc->xspan;
- g->ymax = gc->top + gc->yspan;
- first = false;
- continue;
- }
- if (g->xmin > gc->left)
- g->xmin = gc->left;
- if (g->ymin > gc->top)
- g->ymin = gc->top;
- if (g->xmax < (gc->left + gc->xspan))
- g->xmax = gc->left + gc->xspan;
- if (g->ymax < (gc->top + gc->yspan))
- g->ymax = gc->top + gc->yspan;
- }
- return first != false;
-}
-
-#define xcount(g) ((g)->xmax - (g)->xmin)
-#define ycount(g) ((g)->ymax - (g)->ymin)
-#define toxindex(g, x) ((x) - (g)->xmin)
-#define toyindex(g, y) ((y) - (g)->ymin)
-
-class gridLayoutData {
- int ycount;
-public:
- int **gg; // topological map gg[y][x] = control index
- int *colwidths;
- int *rowheights;
- bool *hexpand;
- bool *vexpand;
- int nVisibleRows;
- int nVisibleColumns;
-
- bool noVisible;
-
- gridLayoutData(uiGrid *g)
- {
- size_t i;
- int x, y;
-
- this->noVisible = gridRecomputeMinMax(g);
-
- this->gg = new int *[ycount(g)];
- for (y = 0; y < ycount(g); y++) {
- this->gg[y] = new int[xcount(g)];
- for (x = 0; x < xcount(g); x++)
- this->gg[y][x] = -1;
- }
-
- for (i = 0; i < g->children->size(); i++) {
- struct gridChild *gc;
-
- gc = (*(g->children))[i];
- if (!uiControlVisible(gc->c))
- continue;
- for (y = gc->top; y < gc->top + gc->yspan; y++)
- for (x = gc->left; x < gc->left + gc->xspan; x++)
- this->gg[toyindex(g, y)][toxindex(g, x)] = i;
- }
-
- this->colwidths = new int[xcount(g)];
- ZeroMemory(this->colwidths, xcount(g) * sizeof (int));
- this->rowheights = new int[ycount(g)];
- ZeroMemory(this->rowheights, ycount(g) * sizeof (int));
- this->hexpand = new bool[xcount(g)];
- ZeroMemory(this->hexpand, xcount(g) * sizeof (bool));
- this->vexpand = new bool[ycount(g)];
- ZeroMemory(this->vexpand, ycount(g) * sizeof (bool));
-
- this->ycount = ycount(g);
-
- // if a row or column only contains emptys and spanning cells of a opposite-direction spannings, it is invisible and should not be considered for padding amount calculations
- // note that the first row and column will always be visible because gridRecomputeMinMax() computed a smallest fitting rectangle
- if (this->noVisible)
- return;
- this->nVisibleRows = 0;
- for (y = 0; y < this->ycount; y++)
- if (this->visibleRow(g, y))
- this->nVisibleRows++;
- this->nVisibleColumns = 0;
- for (x = 0; x < xcount(g); x++)
- if (this->visibleColumn(g, x))
- this->nVisibleColumns++;
- }
-
- ~gridLayoutData()
- {
- size_t y;
-
- delete[] this->hexpand;
- delete[] this->vexpand;
- delete[] this->colwidths;
- delete[] this->rowheights;
- for (y = 0; y < this->ycount; y++)
- delete[] this->gg[y];
- delete[] this->gg;
- }
-
- bool visibleRow(uiGrid *g, int y)
- {
- int x;
- struct gridChild *gc;
-
- for (x = 0; x < xcount(g); x++)
- if (this->gg[y][x] != -1) {
- gc = (*(g->children))[this->gg[y][x]];
- if (gc->yspan == 1 || gc->top - g->ymin == y)
- return true;
- }
- return false;
- }
-
- bool visibleColumn(uiGrid *g, int x)
- {
- int y;
- struct gridChild *gc;
-
- for (y = 0; y < this->ycount; y++)
- if (this->gg[y][x] != -1) {
- gc = (*(g->children))[this->gg[y][x]];
- if (gc->xspan == 1 || gc->left - g->xmin == x)
- return true;
- }
- return false;
- }
-};
-
-static void gridPadding(uiGrid *g, int *xpadding, int *ypadding)
-{
- uiWindowsSizing sizing;
-
- *xpadding = 0;
- *ypadding = 0;
- if (g->padded) {
- uiWindowsGetSizing(g->hwnd, &sizing);
- uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding);
- }
-}
-
-static void gridRelayout(uiGrid *g)
-{
- RECT r;
- int x, y, width, height;
- gridLayoutData *ld;
- int xpadding, ypadding;
- int ix, iy;
- int iwidth, iheight;
- int i;
- struct gridChild *gc;
- int nhexpand, nvexpand;
-
- if (g->children->size() == 0)
- return; // nothing to do
-
- uiWindowsEnsureGetClientRect(g->hwnd, &r);
- x = r.left;
- y = r.top;
- width = r.right - r.left;
- height = r.bottom - r.top;
-
- gridPadding(g, &xpadding, &ypadding);
- ld = new gridLayoutData(g);
- if (ld->noVisible) { // nothing to do
- delete ld;
- return;
- }
-
- // 0) discount padding from width/height
- width -= (ld->nVisibleColumns - 1) * xpadding;
- height -= (ld->nVisibleRows - 1) * ypadding;
-
- // 1) compute colwidths and rowheights before handling expansion
- // we only count non-spanning controls to avoid weirdness
- for (iy = 0; iy < ycount(g); iy++)
- for (ix = 0; ix < xcount(g); ix++) {
- i = ld->gg[iy][ix];
- if (i == -1)
- continue;
- gc = (*(g->children))[i];
- uiWindowsControlMinimumSize(uiWindowsControl(gc->c), &iwidth, &iheight);
- if (gc->xspan == 1)
- if (ld->colwidths[ix] < iwidth)
- ld->colwidths[ix] = iwidth;
- if (gc->yspan == 1)
- if (ld->rowheights[iy] < iheight)
- ld->rowheights[iy] = iheight;
- // save these for step 6
- gc->minwidth = iwidth;
- gc->minheight = iheight;
- }
-
- // 2) figure out which rows/columns expand but not span
- // we need to know which expanding rows/columns don't span before we can handle the ones that do
- for (i = 0; i < g->children->size(); i++) {
- gc = (*(g->children))[i];
- if (!uiControlVisible(gc->c))
- continue;
- if (gc->hexpand && gc->xspan == 1)
- ld->hexpand[toxindex(g, gc->left)] = true;
- if (gc->vexpand && gc->yspan == 1)
- ld->vexpand[toyindex(g, gc->top)] = true;
- }
-
- // 3) figure out which rows/columns expand that do span
- // the way we handle this is simple: if none of the spanned rows/columns expand, make all rows/columns expand
- for (i = 0; i < g->children->size(); i++) {
- gc = (*(g->children))[i];
- if (!uiControlVisible(gc->c))
- continue;
- if (gc->hexpand && gc->xspan != 1) {
- bool doit = true;
-
- for (ix = gc->left; ix < gc->left + gc->xspan; ix++)
- if (ld->hexpand[toxindex(g, ix)]) {
- doit = false;
- break;
- }
- if (doit)
- for (ix = gc->left; ix < gc->left + gc->xspan; ix++)
- ld->hexpand[toxindex(g, ix)] = true;
- }
- if (gc->vexpand && gc->yspan != 1) {
- bool doit = true;
-
- for (iy = gc->top; iy < gc->top + gc->yspan; iy++)
- if (ld->vexpand[toyindex(g, iy)]) {
- doit = false;
- break;
- }
- if (doit)
- for (iy = gc->top; iy < gc->top + gc->yspan; iy++)
- ld->vexpand[toyindex(g, iy)] = true;
- }
- }
-
- // 4) compute and assign expanded widths/heights
- nhexpand = 0;
- nvexpand = 0;
- for (i = 0; i < xcount(g); i++)
- if (ld->hexpand[i])
- nhexpand++;
- else
- width -= ld->colwidths[i];
- for (i = 0; i < ycount(g); i++)
- if (ld->vexpand[i])
- nvexpand++;
- else
- height -= ld->rowheights[i];
- for (i = 0; i < xcount(g); i++)
- if (ld->hexpand[i])
- ld->colwidths[i] = width / nhexpand;
- for (i = 0; i < ycount(g); i++)
- if (ld->vexpand[i])
- ld->rowheights[i] = height / nvexpand;
-
- // 5) reset the final coordinates for the next step
- for (i = 0; i < g->children->size(); i++) {
- gc = (*(g->children))[i];
- if (!uiControlVisible(gc->c))
- continue;
- gc->finalx = 0;
- gc->finaly = 0;
- gc->finalwidth = 0;
- gc->finalheight = 0;
- }
-
- // 6) compute cell positions and sizes
- for (iy = 0; iy < ycount(g); iy++) {
- int curx;
- int prev;
-
- curx = 0;
- prev = -1;
- for (ix = 0; ix < xcount(g); ix++) {
- if (!ld->visibleColumn(g, ix))
- continue;
- i = ld->gg[iy][ix];
- if (i != -1) {
- gc = (*(g->children))[i];
- if (iy == toyindex(g, gc->top)) { // don't repeat this step if the control spans vertically
- if (i != prev)
- gc->finalx = curx;
- else
- gc->finalwidth += xpadding;
- gc->finalwidth += ld->colwidths[ix];
- }
- }
- curx += ld->colwidths[ix] + xpadding;
- prev = i;
- }
- }
- for (ix = 0; ix < xcount(g); ix++) {
- int cury;
- int prev;
-
- cury = 0;
- prev = -1;
- for (iy = 0; iy < ycount(g); iy++) {
- if (!ld->visibleRow(g, iy))
- continue;
- i = ld->gg[iy][ix];
- if (i != -1) {
- gc = (*(g->children))[i];
- if (ix == toxindex(g, gc->left)) { // don't repeat this step if the control spans horizontally
- if (i != prev)
- gc->finaly = cury;
- else
- gc->finalheight += ypadding;
- gc->finalheight += ld->rowheights[iy];
- }
- }
- cury += ld->rowheights[iy] + ypadding;
- prev = i;
- }
- }
-
- // 7) everything as it stands now is set for xalign == Fill yalign == Fill; set the correct alignments
- // this is why we saved minwidth/minheight above
- for (i = 0; i < g->children->size(); i++) {
- gc = (*(g->children))[i];
- if (!uiControlVisible(gc->c))
- continue;
- if (gc->halign != uiAlignFill) {
- switch (gc->halign) {
- case uiAlignEnd:
- gc->finalx += gc->finalwidth - gc->minwidth;
- break;
- case uiAlignCenter:
- gc->finalx += (gc->finalwidth - gc->minwidth) / 2;
- break;
- }
- gc->finalwidth = gc->minwidth; // for all three
- }
- if (gc->valign != uiAlignFill) {
- switch (gc->valign) {
- case uiAlignEnd:
- gc->finaly += gc->finalheight - gc->minheight;
- break;
- case uiAlignCenter:
- gc->finaly += (gc->finalheight - gc->minheight) / 2;
- break;
- }
- gc->finalheight = gc->minheight; // for all three
- }
- }
-
- // 8) and FINALLY we resize
- for (iy = 0; iy < ycount(g); iy++)
- for (ix = 0; ix < xcount(g); ix++) {
- i = ld->gg[iy][ix];
- if (i != -1) { // treat empty cells like spaces
- gc = (*(g->children))[i];
- uiWindowsEnsureMoveWindowDuringResize(
- (HWND) uiControlHandle(gc->c),
- gc->finalx,//TODO + x,
- gc->finaly,//TODO + y,
- gc->finalwidth,
- gc->finalheight);
- }
- }
-
- delete ld;
-}
-
-static void uiGridDestroy(uiControl *c)
-{
- uiGrid *g = uiGrid(c);
-
- for (struct gridChild *gc : *(g->children)) {
- uiControlSetParent(gc->c, NULL);
- uiControlDestroy(gc->c);
- uiFree(gc);
- }
- delete g->indexof;
- delete g->children;
- uiWindowsEnsureDestroyWindow(g->hwnd);
- uiFreeControl(uiControl(g));
-}
-
-uiWindowsControlDefaultHandle(uiGrid)
-uiWindowsControlDefaultParent(uiGrid)
-uiWindowsControlDefaultSetParent(uiGrid)
-uiWindowsControlDefaultToplevel(uiGrid)
-uiWindowsControlDefaultVisible(uiGrid)
-uiWindowsControlDefaultShow(uiGrid)
-uiWindowsControlDefaultHide(uiGrid)
-uiWindowsControlDefaultEnabled(uiGrid)
-uiWindowsControlDefaultEnable(uiGrid)
-uiWindowsControlDefaultDisable(uiGrid)
-uiWindowsControlDefaultSetFocus(uiGrid)
-
-static void uiGridSyncEnableState(uiWindowsControl *c, int enabled)
-{
- uiGrid *g = uiGrid(c);
-
- if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(g), enabled))
- return;
- for (const struct gridChild *gc : *(g->children))
- uiWindowsControlSyncEnableState(uiWindowsControl(gc->c), enabled);
-}
-
-uiWindowsControlDefaultSetParentHWND(uiGrid)
-
-static void uiGridMinimumSize(uiWindowsControl *c, int *width, int *height)
-{
- uiGrid *g = uiGrid(c);
- int xpadding, ypadding;
- gridLayoutData *ld;
- int x, y;
- int i;
- struct gridChild *gc;
- int minwid, minht;
- int colwidth, rowheight;
-
- *width = 0;
- *height = 0;
- if (g->children->size() == 0)
- return; // nothing to do
-
- gridPadding(g, &xpadding, &ypadding);
- ld = new gridLayoutData(g);
- if (ld->noVisible) { // nothing to do; return 0x0
- delete ld;
- return;
- }
-
- // 1) compute colwidths and rowheights before handling expansion
- // TODO put this in its own function (but careful about the spanning calculation in gridRelayout())
- for (y = 0; y < ycount(g); y++)
- for (x = 0; x < xcount(g); x++) {
- i = ld->gg[y][x];
- if (i == -1)
- continue;
- gc = (*(g->children))[i];
- uiWindowsControlMinimumSize(uiWindowsControl(gc->c), &minwid, &minht);
- // allot equal space in the presence of spanning to keep things sane
- if (ld->colwidths[x] < minwid / gc->xspan)
- ld->colwidths[x] = minwid / gc->xspan;
- if (ld->rowheights[y] < minht / gc->yspan)
- ld->rowheights[y] = minht / gc->yspan;
- // save these for step 6
- gc->minwidth = minwid;
- gc->minheight = minht;
- }
-
- // 2) compute total column width/row height
- colwidth = 0;
- rowheight = 0;
- for (x = 0; x < xcount(g); x++)
- colwidth += ld->colwidths[x];
- for (y = 0; y < ycount(g); y++)
- rowheight += ld->rowheights[y];
-
- // and that's it; just account for padding
- *width = colwidth + (ld->nVisibleColumns - 1) * xpadding;
- *height = rowheight + (ld->nVisibleRows - 1) * ypadding;
-}
-
-static void uiGridMinimumSizeChanged(uiWindowsControl *c)
-{
- uiGrid *g = uiGrid(c);
-
- if (uiWindowsControlTooSmall(uiWindowsControl(g))) {
- uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(g));
- return;
- }
- gridRelayout(g);
-}
-
-static void uiGridSetMinSize(uiControl *c, int w, int h)
-{
- // checkme
- uiGridMinimumSizeChanged(uiWindowsControl(c));
-}
-
-uiWindowsControlDefaultLayoutRect(uiGrid)
-uiWindowsControlDefaultAssignControlIDZOrder(uiGrid)
-
-static void uiGridChildVisibilityChanged(uiWindowsControl *c)
-{
- // TODO eliminate the redundancy
- uiWindowsControlMinimumSizeChanged(c);
-}
-
-// must have called gridRecomputeMinMax() first
-static void gridArrangeChildren(uiGrid *g)
-{
- LONG_PTR controlID;
- HWND insertAfter;
- gridLayoutData *ld;
- bool *visited;
- int x, y;
- int i;
- struct gridChild *gc;
-
- if (g->children->size() == 0)
- return; // nothing to do
- ld = new gridLayoutData(g);
- controlID = 100;
- insertAfter = NULL;
- visited = new bool[g->children->size()];
- ZeroMemory(visited, g->children->size() * sizeof (bool));
- for (y = 0; y < ycount(g); y++)
- for (x = 0; x < xcount(g); x++) {
- i = ld->gg[y][x];
- if (i == -1)
- continue;
- if (visited[i])
- continue;
- visited[i] = true;
- gc = (*(g->children))[i];
- uiWindowsControlAssignControlIDZOrder(uiWindowsControl(gc->c), &controlID, &insertAfter);
- }
- delete[] visited;
- delete ld;
-}
-
-static struct gridChild *toChild(uiControl *c, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
-{
- struct gridChild *gc;
-
- if (xspan < 0)
- userbug("You cannot have a negative xspan in a uiGrid cell.");
- if (yspan < 0)
- userbug("You cannot have a negative yspan in a uiGrid cell.");
- gc = uiNew(struct gridChild);
- gc->c = c;
- gc->xspan = xspan;
- gc->yspan = yspan;
- gc->hexpand = hexpand;
- gc->halign = halign;
- gc->vexpand = vexpand;
- gc->valign = valign;
- return gc;
-}
-
-static void add(uiGrid *g, struct gridChild *gc)
-{
- uiControlSetParent(gc->c, uiControl(g));
- uiWindowsControlSetParentHWND(uiWindowsControl(gc->c), g->hwnd);
- g->children->push_back(gc);
- (*(g->indexof))[gc->c] = g->children->size() - 1;
- gridRecomputeMinMax(g);
- gridArrangeChildren(g);
- uiWindowsControlMinimumSizeChanged(uiWindowsControl(g));
-}
-
-void uiGridAppend(uiGrid *g, uiControl *c, int left, int top, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
-{
- struct gridChild *gc;
-
- gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign);
- gc->left = left;
- gc->top = top;
- add(g, gc);
-}
-
-// TODO decide what happens if existing is NULL
-void uiGridInsertAt(uiGrid *g, uiControl *c, uiControl *existing, uiAt at, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign)
-{
- struct gridChild *gc;
- struct gridChild *other;
-
- gc = toChild(c, xspan, yspan, hexpand, halign, vexpand, valign);
- other = (*(g->children))[(*(g->indexof))[existing]];
- switch (at) {
- case uiAtLeading:
- gc->left = other->left - gc->xspan;
- gc->top = other->top;
- break;
- case uiAtTop:
- gc->left = other->left;
- gc->top = other->top - gc->yspan;
- break;
- case uiAtTrailing:
- gc->left = other->left + other->xspan;
- gc->top = other->top;
- break;
- case uiAtBottom:
- gc->left = other->left;
- gc->top = other->top + other->yspan;
- break;
- // TODO add error checks to ALL enums
- }
- add(g, gc);
-}
-
-int uiGridPadded(uiGrid *g)
-{
- return g->padded;
-}
-
-void uiGridSetPadded(uiGrid *g, int padded)
-{
- g->padded = padded;
- uiWindowsControlMinimumSizeChanged(uiWindowsControl(g));
-}
-
-static void onResize(uiWindowsControl *c)
-{
- gridRelayout(uiGrid(c));
-}
-
-uiGrid *uiNewGrid(void)
-{
- uiGrid *g;
-
- uiWindowsNewControl(uiGrid, g);
-
- g->hwnd = uiWindowsMakeContainer(uiWindowsControl(g), onResize);
-
- g->children = new std::vector<struct gridChild *>;
- g->indexof = new std::map<uiControl *, size_t>;
-
- return g;
-}