commit
578ff39525
|
@ -20,6 +20,9 @@ This README is being written.<br>
|
|||
|
||||
* **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.
|
||||
|
|
|
@ -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++)
|
||||
|
|
16
ui_windows.h
16
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
140
windows/grid.cpp
140
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue