diff --git a/README.md b/README.md index 04fa0104..e693e7a6 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,9 @@ This README is being written.
* **14 June 2016** * uiDarwinControl now has a `ChildVisibilityChanged()` method and a corresponding `NotifyVisibilityChanged()` function that is called by the default show/hide handlers. This is used to make visibility changes work on OS X; uiBox, uiForm, and uiGrid all respect these now. + * The same has been done on the Windows side as well. + * Hiding and showing controls and padding calculations are now correct on Windows at long last. + * Hiding a control in a uiForm now hides its label on all platforms. * **13 June 2016** * `intmax_t` and `uintmax_t` are no longer used for libui API functions; now we use `int`. This should make things much easier for bindings. `int` should be at least 32 bits wide; this should be sufficient for all but the most extreme cases. diff --git a/darwin/grid.m b/darwin/grid.m index 200c2a1b..5e391fd5 100644 --- a/darwin/grid.m +++ b/darwin/grid.m @@ -148,6 +148,7 @@ struct uiGrid { int firstx, firsty; BOOL *hexpand, *vexpand; BOOL doit; + BOOL onlyEmptyAndSpanning; [self removeOurConstraints]; if ([self->children count] == 0) @@ -158,6 +159,7 @@ struct uiGrid { // ignore hidden controls first = YES; for (gc in self->children) { + // this bit is important: it ensures row ymin and column xmin have at least one cell to draw, so the onlyEmptyAndSpanning logic below will never run on those rows if (!uiControlVisible(gc.c)) continue; if (first) { @@ -177,6 +179,8 @@ struct uiGrid { if (ymax < (gc.top + gc.yspan)) ymax = gc.top + gc.yspan; } + if (first != NO) // the entire grid is hidden; do nothing + return; xcount = xmax - xmin; ycount = ymax - ymin; @@ -204,7 +208,6 @@ struct uiGrid { } // if a row or column only contains emptys and spanning cells of a opposite-direction spannings, remove it by duplicating the previous row or column - BOOL onlyEmptyAndSpanning; for (y = 0; y < ycount; y++) { onlyEmptyAndSpanning = YES; for (x = 0; x < xcount; x++) diff --git a/doc/form b/doc/form new file mode 100644 index 00000000..f24a94dc --- /dev/null +++ b/doc/form @@ -0,0 +1 @@ +hiding a control also hides its label diff --git a/ui_windows.h b/ui_windows.h index 3ea511c9..69dda366 100644 --- a/ui_windows.h +++ b/ui_windows.h @@ -26,6 +26,7 @@ struct uiWindowsControl { void (*MinimumSizeChanged)(uiWindowsControl *); void (*LayoutRect)(uiWindowsControl *c, RECT *r); void (*AssignControlIDZOrder)(uiWindowsControl *, LONG_PTR *, HWND *); + void (*ChildVisibilityChanged)(uiWindowsControl *); }; #define uiWindowsControl(this) ((uiWindowsControl *) (this)) // TODO document @@ -35,6 +36,7 @@ _UI_EXTERN void uiWindowsControlMinimumSize(uiWindowsControl *, int *, int *); _UI_EXTERN void uiWindowsControlMinimumSizeChanged(uiWindowsControl *); _UI_EXTERN void uiWindowsControlLayoutRect(uiWindowsControl *, RECT *); _UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_PTR *, HWND *); +_UI_EXTERN void uiWindowsControlChildVisibilityChanged(uiWindowsControl *); // TODO document #define uiWindowsControlDefaultDestroy(type) \ @@ -74,12 +76,14 @@ _UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_P { \ uiWindowsControl(c)->visible = 1; \ ShowWindow(type(c)->hwnd, SW_SHOW); \ + uiWindowsControlNotifyVisibilityChanged(uiWindowsControl(c)); \ } #define uiWindowsControlDefaultHide(type) \ static void type ## Hide(uiControl *c) \ { \ uiWindowsControl(c)->visible = 0; \ ShowWindow(type(c)->hwnd, SW_HIDE); \ + uiWindowsControlNotifyVisibilityChanged(uiWindowsControl(c)); \ } #define uiWindowsControlDefaultEnabled(type) \ static int type ## Enabled(uiControl *c) \ @@ -131,6 +135,11 @@ _UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_P { \ uiWindowsEnsureAssignControlIDZOrder(type(c)->hwnd, controlID, insertAfter); \ } +#define uiWindowsControlDefaultChildVisibilityChanged(type) \ + static void type ## ChildVisibilityChanged(uiWindowsControl *c) \ + { \ + /* do nothing */ \ + } #define uiWindowsControlAllDefaultsExceptDestroy(type) \ uiWindowsControlDefaultHandle(type) \ @@ -147,7 +156,8 @@ _UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_P uiWindowsControlDefaultSetParentHWND(type) \ uiWindowsControlDefaultMinimumSizeChanged(type) \ uiWindowsControlDefaultLayoutRect(type) \ - uiWindowsControlDefaultAssignControlIDZOrder(type) + uiWindowsControlDefaultAssignControlIDZOrder(type) \ + uiWindowsControlDefaultChildVisibilityChanged(type) #define uiWindowsControlAllDefaults(type) \ uiWindowsControlDefaultDestroy(type) \ @@ -173,6 +183,7 @@ _UI_EXTERN void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *, LONG_P uiWindowsControl(var)->MinimumSizeChanged = type ## MinimumSizeChanged; \ uiWindowsControl(var)->LayoutRect = type ## LayoutRect; \ uiWindowsControl(var)->AssignControlIDZOrder = type ## AssignControlIDZOrder; \ + uiWindowsControl(var)->ChildVisibilityChanged = type ## ChildVisibilityChanged; \ uiWindowsControl(var)->visible = 1; \ uiWindowsControl(var)->enabled = 1; // TODO document @@ -246,6 +257,9 @@ _UI_EXTERN void uiWindowsControlAssignSoleControlIDZOrder(uiWindowsControl *); // TODO document _UI_EXTERN BOOL uiWindowsShouldStopSyncEnableState(uiWindowsControl *c, int enabled); +// TODO document +_UI_EXTERN void uiWindowsControlNotifyVisibilityChanged(uiWindowsControl *c); + #ifdef __cplusplus } #endif diff --git a/unix/form.c b/unix/form.c index 4e1f7fa0..02571d0c 100644 --- a/unix/form.c +++ b/unix/form.c @@ -8,6 +8,7 @@ struct formChild { GtkAlign oldhalign; gboolean oldvexpand; GtkAlign oldvalign; + GBinding *labelBinding; }; struct uiForm { @@ -82,7 +83,10 @@ void uiFormAppend(uiForm *f, const char *label, uiControl *c, int stretchy) gtk_grid_attach(f->grid, fc.label, 0, row, 1, 1); - gtk_widget_show_all(fc.label); + // and make them share visibility so if the control is hidden, so is its label + fc.labelBinding = g_object_bind_property(GTK_WIDGET(uiControlHandle(fc.c)), "visible", + fc.label, "visible", + G_BINDING_SYNC_CREATE); uiControlSetParent(fc.c, uiControl(f)); uiUnixControlSetContainer(uiUnixControl(fc.c), f->container, FALSE); diff --git a/windows/box.cpp b/windows/box.cpp index d87f73e2..9567954b 100644 --- a/windows/box.cpp +++ b/windows/box.cpp @@ -37,6 +37,7 @@ static void boxRelayout(uiBox *b) int stretchywid, stretchyht; int i; int minimumWidth, minimumHeight; + int nVisible; uiWindowsSizing *d; if (b->controls->size() == 0) @@ -51,21 +52,16 @@ static void boxRelayout(uiBox *b) // -1) get this Box's padding boxPadding(b, &xpadding, &ypadding); - // 0) inset the available rect by the needed padding - // TODO this is incorrect if any controls are hidden - if (b->vertical) - height -= (b->controls->size() - 1) * ypadding; - else - width -= (b->controls->size() - 1) * xpadding; - // 1) get width and height of non-stretchy controls // this will tell us how much space will be left for stretchy controls stretchywid = width; stretchyht = height; nStretchy = 0; + nVisible = 0; for (struct boxChild &bc : *(b->controls)) { if (!uiControlVisible(bc.c)) continue; + nVisible++; if (bc.stretchy) { nStretchy++; continue; @@ -81,24 +77,35 @@ static void boxRelayout(uiBox *b) stretchywid -= minimumWidth; } } + if (nVisible == 0) // nothing to do + return; - // 2) now get the size of stretchy controls - if (nStretchy != 0) + // 2) now inset the available rect by the needed padding + if (b->vertical) { + height -= (nVisible - 1) * ypadding; + stretchyht -= (nVisible - 1) * ypadding; + } else { + width -= (nVisible - 1) * xpadding; + stretchywid -= (nVisible - 1) * xpadding; + } + + // 3) now get the size of stretchy controls + if (nStretchy != 0) { if (b->vertical) stretchyht /= nStretchy; else stretchywid /= nStretchy; - // TODO put this in the above if - for (struct boxChild &bc : *(b->controls)) { - if (!uiControlVisible(bc.c)) - continue; - if (bc.stretchy) { - bc.width = stretchywid; - bc.height = stretchyht; + for (struct boxChild &bc : *(b->controls)) { + if (!uiControlVisible(bc.c)) + continue; + if (bc.stretchy) { + bc.width = stretchywid; + bc.height = stretchyht; + } } } - // 3) now we can position controls + // 4) now we can position controls // first, make relative to the top-left corner of the container x = 0; y = 0; @@ -159,6 +166,7 @@ static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height) int maxStretchyWidth, maxStretchyHeight; int i; int minimumWidth, minimumHeight; + int nVisible; uiWindowsSizing sizing; *width = 0; @@ -169,21 +177,16 @@ static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height) // 0) get this Box's padding boxPadding(b, &xpadding, &ypadding); - // 1) initialize the desired rect with the needed padding - // TODO this is wrong if any controls are hidden - if (b->vertical) - *height = (b->controls->size() - 1) * ypadding; - else - *width = (b->controls->size() - 1) * xpadding; - - // 2) add in the size of non-stretchy controls and get (but not add in) the largest widths and heights of stretchy controls + // 1) add in the size of non-stretchy controls and get (but not add in) the largest widths and heights of stretchy controls // we still add in like direction of stretchy controls nStretchy = 0; maxStretchyWidth = 0; maxStretchyHeight = 0; + nVisible = 0; for (const struct boxChild &bc : *(b->controls)) { if (!uiControlVisible(bc.c)) continue; + nVisible++; uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight); if (bc.stretchy) { nStretchy++; @@ -204,6 +207,14 @@ static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height) *height = minimumHeight; } } + if (nVisible == 0) // just return 0x0 + return; + + // 2) now outset the desired rect with the needed padding + if (b->vertical) + *height += (nVisible - 1) * ypadding; + else + *width += (nVisible - 1) * xpadding; // 3) and now we can add in stretchy controls if (b->vertical) @@ -226,6 +237,12 @@ static void uiBoxMinimumSizeChanged(uiWindowsControl *c) uiWindowsControlDefaultLayoutRect(uiBox) uiWindowsControlDefaultAssignControlIDZOrder(uiBox) +static void uiBoxChildVisibilityChanged(uiWindowsControl *c) +{ + // TODO eliminate the redundancy + uiWindowsControlMinimumSizeChanged(c); +} + static void boxArrangeChildren(uiBox *b) { LONG_PTR controlID; diff --git a/windows/control.cpp b/windows/control.cpp index d59132b9..ce953cf9 100644 --- a/windows/control.cpp +++ b/windows/control.cpp @@ -21,6 +21,7 @@ void uiWindowsControlMinimumSizeChanged(uiWindowsControl *c) (*(c->MinimumSizeChanged))(c); } +// TODO get rid of this void uiWindowsControlLayoutRect(uiWindowsControl *c, RECT *r) { (*(c->LayoutRect))(c, r); @@ -31,6 +32,11 @@ void uiWindowsControlAssignControlIDZOrder(uiWindowsControl *c, LONG_PTR *contro (*(c->AssignControlIDZOrder))(c, controlID, insertAfter); } +void uiWindowsControlChildVisibilityChanged(uiWindowsControl *c) +{ + (*(c->ChildVisibilityChanged))(c); +} + HWND uiWindowsEnsureCreateControlHWND(DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, HINSTANCE hInstance, LPVOID lpParam, BOOL useStandardControlFont) { HWND hwnd; @@ -106,3 +112,10 @@ void uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl *c) if (parent != NULL) uiWindowsControlMinimumSizeChanged(uiWindowsControl(parent)); } + +// TODO rename this nad the OS X this and hugging ones to NotifyChild +void uiWindowsControlNotifyVisibilityChanged(uiWindowsControl *c) +{ + // TODO we really need to figure this out; the duplication is a mess + uiWindowsControlContinueMinimumSizeChanged(c); +} diff --git a/windows/form.cpp b/windows/form.cpp index e15e9571..1db4c4d7 100644 --- a/windows/form.cpp +++ b/windows/form.cpp @@ -43,6 +43,7 @@ static void formRelayout(uiForm *f) int minimumWidth, minimumHeight; uiWindowsSizing sizing; int labelht, labelyoff; + int nVisible; if (f->controls->size() == 0) return; @@ -53,22 +54,22 @@ static void formRelayout(uiForm *f) width = r.right - r.left; height = r.bottom - r.top; - // -1) get this Form's padding + // 0) get this Form's padding formPadding(f, &xpadding, &ypadding); - // 0) inset the available rect by the needed padding - // TODO this is incorrect if any controls are hidden - width -= xpadding; - height -= (f->controls->size() - 1) * ypadding; - // 1) get width of labels and height of non-stretchy controls // this will tell us how much space will be left for controls labelwid = 0; stretchyht = height; nStretchy = 0; + nVisible = 0; for (struct formChild &fc : *(f->controls)) { - if (!uiControlVisible(fc.c)) + if (!uiControlVisible(fc.c)) { + ShowWindow(fc.label, SW_HIDE); continue; + } + ShowWindow(fc.label, SW_SHOW); + nVisible++; thiswid = uiWindowsWindowTextWidth(fc.label); if (labelwid < thiswid) labelwid = thiswid; @@ -80,8 +81,15 @@ static void formRelayout(uiForm *f) fc.height = minimumHeight; stretchyht -= minimumHeight; } + if (nVisible == 0) // nothing to do + return; - // 2) now get the width of controls and the height of stretchy controls + // 2) inset the available rect by the needed padding + width -= xpadding; + height -= (nVisible - 1) * ypadding; + stretchyht -= (nVisible - 1) * ypadding; + + // 3) now get the width of controls and the height of stretchy controls width -= labelwid; if (nStretchy != 0) { stretchyht /= nStretchy; @@ -93,12 +101,12 @@ static void formRelayout(uiForm *f) } } - // 3) get the y offset + // 4) get the y offset labelyoff = labelYOffset; uiWindowsGetSizing(f->hwnd, &sizing); uiWindowsSizingDlgUnitsToPixels(&sizing, NULL, &labelyoff); - // 4) now we can position controls + // 5) now we can position controls // first, make relative to the top-left corner of the container // also prefer left alignment on Windows x = labelwid + xpadding; @@ -164,6 +172,7 @@ static void uiFormMinimumSize(uiWindowsControl *c, int *width, int *height) int labelwid; int i; int minimumWidth, minimumHeight; + int nVisible; uiWindowsSizing sizing; *width = 0; @@ -174,20 +183,17 @@ static void uiFormMinimumSize(uiWindowsControl *c, int *width, int *height) // 0) get this Form's padding formPadding(f, &xpadding, &ypadding); - // 1) initialize the desired rect with the needed padding - // TODO this is wrong if any controls are hidden - *width = xpadding; - *height = (f->controls->size() - 1) * ypadding; - - // 2) determine the longest width of all controls and labels; add in the height of non-stretchy controls and get (but not add in) the largest heights of stretchy controls + // 1) determine the longest width of all controls and labels; add in the height of non-stretchy controls and get (but not add in) the largest heights of stretchy controls // we still add in like direction of stretchy controls nStretchy = 0; maxLabelWidth = 0; maxControlWidth = 0; maxStretchyHeight = 0; + nVisible = 0; for (const struct formChild &fc : *(f->controls)) { if (!uiControlVisible(fc.c)) continue; + nVisible++; labelwid = uiWindowsWindowTextWidth(fc.label); if (maxLabelWidth < labelwid) maxLabelWidth = labelwid; @@ -202,8 +208,14 @@ static void uiFormMinimumSize(uiWindowsControl *c, int *width, int *height) if (!fc.stretchy) *height += minimumHeight; } + if (nVisible == 0) // nothing to show; return 0x0 + return; *width += maxLabelWidth + maxControlWidth; + // 2) outset the desired rect with the needed padding + *width += xpadding; + *height += (nVisible - 1) * ypadding; + // 3) and now we can add in stretchy controls *height += nStretchy * maxStretchyHeight; } @@ -222,6 +234,12 @@ static void uiFormMinimumSizeChanged(uiWindowsControl *c) uiWindowsControlDefaultLayoutRect(uiForm) uiWindowsControlDefaultAssignControlIDZOrder(uiForm) +static void uiFormChildVisibilityChanged(uiWindowsControl *c) +{ + // TODO eliminate the redundancy + uiWindowsControlMinimumSizeChanged(c); +} + static void formArrangeChildren(uiForm *f) { LONG_PTR controlID; diff --git a/windows/grid.cpp b/windows/grid.cpp index bcf89980..c63cd1e4 100644 --- a/windows/grid.cpp +++ b/windows/grid.cpp @@ -6,7 +6,7 @@ // - what happens if you call Append() twice? // TODOs -// - make ALL the controls handle hidden children right +// - the Assorted page has clipping and repositioning issues struct gridChild { uiControl *c; @@ -36,25 +36,59 @@ struct uiGrid { 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 { - size_t ycount; + 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)]; @@ -66,6 +100,8 @@ public: 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; @@ -81,6 +117,19 @@ public: 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() @@ -95,6 +144,34 @@ public: 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) @@ -132,10 +209,14 @@ static void gridRelayout(uiGrid *g) gridPadding(g, &xpadding, &ypadding); ld = new gridLayoutData(g); + if (ld->noVisible) { // nothing to do + delete ld; + return; + } // 0) discount padding from width/height - width -= (xcount(g) - 1) * xpadding; - height -= (ycount(g) - 1) * ypadding; + 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 @@ -161,6 +242,8 @@ static void gridRelayout(uiGrid *g) // 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) @@ -171,6 +254,8 @@ static void gridRelayout(uiGrid *g) // 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; @@ -197,7 +282,6 @@ static void gridRelayout(uiGrid *g) } } - // 4) compute and assign expanded widths/heights nhexpand = 0; nvexpand = 0; @@ -221,6 +305,8 @@ static void gridRelayout(uiGrid *g) // 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; @@ -235,6 +321,8 @@ static void gridRelayout(uiGrid *g) 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]; @@ -257,6 +345,8 @@ static void gridRelayout(uiGrid *g) 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]; @@ -277,6 +367,8 @@ static void gridRelayout(uiGrid *g) // 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: @@ -375,6 +467,10 @@ static void uiGridMinimumSize(uiWindowsControl *c, int *width, int *height) 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()) @@ -404,8 +500,8 @@ static void uiGridMinimumSize(uiWindowsControl *c, int *width, int *height) rowheight += ld->rowheights[y]; // and that's it; just account for padding - *width = colwidth + (g->xmax-1) * xpadding; - *height = rowheight + (g->ymax-1) * ypadding; + *width = colwidth + (ld->nVisibleColumns - 1) * xpadding; + *height = rowheight + (ld->nVisibleRows - 1) * ypadding; } static void uiGridMinimumSizeChanged(uiWindowsControl *c) @@ -422,6 +518,12 @@ static void 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) { @@ -455,30 +557,6 @@ static void gridArrangeChildren(uiGrid *g) delete ld; } -static void gridRecomputeMinMax(uiGrid *g) -{ - bool first = true; - - for (struct gridChild *gc : *(g->children)) { - 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; - } -} - static struct gridChild *toChild(uiControl *c, int xspan, int yspan, int hexpand, uiAlign halign, int vexpand, uiAlign valign) { struct gridChild *gc; diff --git a/windows/group.cpp b/windows/group.cpp index 9e2cf6e1..8824c5a4 100644 --- a/windows/group.cpp +++ b/windows/group.cpp @@ -121,6 +121,12 @@ static void uiGroupMinimumSizeChanged(uiWindowsControl *c) uiWindowsControlDefaultLayoutRect(uiGroup) uiWindowsControlDefaultAssignControlIDZOrder(uiGroup) +static void uiGroupChildVisibilityChanged(uiWindowsControl *c) +{ + // TODO eliminate the redundancy + uiWindowsControlMinimumSizeChanged(c); +} + char *uiGroupTitle(uiGroup *g) { return uiWindowsWindowText(g->hwnd); diff --git a/windows/tab.cpp b/windows/tab.cpp index 2af2bff3..365f5a1f 100644 --- a/windows/tab.cpp +++ b/windows/tab.cpp @@ -166,6 +166,12 @@ static void uiTabMinimumSizeChanged(uiWindowsControl *c) uiWindowsControlDefaultLayoutRect(uiTab) uiWindowsControlDefaultAssignControlIDZOrder(uiTab) +static void uiTabChildVisibilityChanged(uiWindowsControl *c) +{ + // TODO eliminate the redundancy + uiWindowsControlMinimumSizeChanged(c); +} + static void tabArrangePages(uiTab *t) { LONG_PTR controlID = 100; diff --git a/windows/window.cpp b/windows/window.cpp index 0edd7183..411cb86e 100644 --- a/windows/window.cpp +++ b/windows/window.cpp @@ -260,6 +260,12 @@ static void uiWindowLayoutRect(uiWindowsControl *c, RECT *r) uiWindowsControlDefaultAssignControlIDZOrder(uiWindow) +static void uiWindowChildVisibilityChanged(uiWindowsControl *c) +{ + // TODO eliminate the redundancy + uiWindowsControlMinimumSizeChanged(c); +} + char *uiWindowTitle(uiWindow *w) { return uiWindowsWindowText(w->hwnd);