libui/windows/box.cpp

304 lines
7.1 KiB
C++
Raw Normal View History

2015-04-22 16:04:30 -05:00
// 7 april 2015
#include "uipriv_windows.hpp"
struct boxChild {
uiControl *c;
int stretchy;
int width;
int height;
};
2015-04-22 16:04:30 -05:00
struct uiBox {
uiWindowsControl c;
HWND hwnd;
std::vector<struct boxChild> *controls;
2015-04-22 16:04:30 -05:00
int vertical;
int padded;
};
static void boxPadding(uiBox *b, int *xpadding, int *ypadding)
{
uiWindowsSizing sizing;
*xpadding = 0;
*ypadding = 0;
2015-04-22 16:04:30 -05:00
if (b->padded) {
uiWindowsGetSizing(b->hwnd, &sizing);
uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding);
2015-04-22 16:04:30 -05:00
}
}
static void boxRelayout(uiBox *b)
2015-04-22 16:04:30 -05:00
{
RECT r;
int x, y, width, height;
2015-04-22 16:04:30 -05:00
int xpadding, ypadding;
int nStretchy;
int stretchywid, stretchyht;
int i;
int minimumWidth, minimumHeight;
2015-09-01 08:18:37 -05:00
uiWindowsSizing *d;
2015-04-22 16:04:30 -05:00
if (b->controls->size() == 0)
2015-04-22 16:04:30 -05:00
return;
uiWindowsEnsureGetClientRect(b->hwnd, &r);
x = r.left;
y = r.top;
width = r.right - r.left;
height = r.bottom - r.top;
2015-09-01 08:18:37 -05:00
2015-04-22 16:04:30 -05:00
// -1) get this Box's padding
boxPadding(b, &xpadding, &ypadding);
2015-04-22 16:04:30 -05:00
// 0) inset the available rect by the needed padding
// TODO this is incorrect if any controls are hidden
2015-04-22 16:04:30 -05:00
if (b->vertical)
height -= (b->controls->size() - 1) * ypadding;
2015-04-22 16:04:30 -05:00
else
width -= (b->controls->size() - 1) * xpadding;
2015-04-22 16:04:30 -05:00
// 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;
for (struct boxChild &bc : *(b->controls)) {
if (!uiControlVisible(bc.c))
2015-09-01 15:44:09 -05:00
continue;
if (bc.stretchy) {
2015-04-22 16:04:30 -05:00
nStretchy++;
continue;
}
uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight);
2015-04-22 16:04:30 -05:00
if (b->vertical) { // all controls have same width
bc.width = width;
bc.height = minimumHeight;
2015-09-01 08:18:37 -05:00
stretchyht -= minimumHeight;
2015-04-22 16:04:30 -05:00
} else { // all controls have same height
bc.width = minimumWidth;
bc.height = height;
2015-09-01 08:18:37 -05:00
stretchywid -= minimumWidth;
2015-04-22 16:04:30 -05:00
}
}
// 2) 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))
2015-09-01 15:44:09 -05:00
continue;
if (bc.stretchy) {
bc.width = stretchywid;
bc.height = stretchyht;
2015-04-22 16:04:30 -05:00
}
}
// 3) now we can position controls
// first, make relative to the top-left corner of the container
x = 0;
y = 0;
for (const struct boxChild &bc : *(b->controls)) {
if (!uiControlVisible(bc.c))
2015-09-01 15:44:09 -05:00
continue;
uiWindowsEnsureMoveWindowDuringResize((HWND) uiControlHandle(bc.c), x, y, bc.width, bc.height);
2015-04-22 16:04:30 -05:00
if (b->vertical)
y += bc.height + ypadding;
2015-04-22 16:04:30 -05:00
else
x += bc.width + xpadding;
}
}
static void uiBoxDestroy(uiControl *c)
{
uiBox *b = uiBox(c);
for (const struct boxChild &bc : *(b->controls)) {
uiControlSetParent(bc.c, NULL);
uiControlDestroy(bc.c);
2015-04-22 16:04:30 -05:00
}
delete b->controls;
uiWindowsEnsureDestroyWindow(b->hwnd);
uiFreeControl(uiControl(b));
}
2015-09-01 08:18:37 -05:00
uiWindowsControlDefaultHandle(uiBox)
uiWindowsControlDefaultParent(uiBox)
uiWindowsControlDefaultSetParent(uiBox)
uiWindowsControlDefaultToplevel(uiBox)
uiWindowsControlDefaultVisible(uiBox)
uiWindowsControlDefaultShow(uiBox)
uiWindowsControlDefaultHide(uiBox)
uiWindowsControlDefaultEnabled(uiBox)
uiWindowsControlDefaultEnable(uiBox)
uiWindowsControlDefaultDisable(uiBox)
static void uiBoxSyncEnableState(uiWindowsControl *c, int enabled)
{
uiBox *b = uiBox(c);
if (uiWindowsShouldStopSyncEnableState(uiWindowsControl(b), enabled))
return;
for (const struct boxChild &bc : *(b->controls))
uiWindowsControlSyncEnableState(uiWindowsControl(bc.c), enabled);
2015-04-22 16:04:30 -05:00
}
uiWindowsControlDefaultSetParentHWND(uiBox)
static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height)
2015-05-15 23:44:24 -05:00
{
uiBox *b = uiBox(c);
int xpadding, ypadding;
int nStretchy;
// these two contain the largest minimum width and height of all stretchy controls in the box
// all stretchy controls will use this value to determine the final minimum size
int maxStretchyWidth, maxStretchyHeight;
int i;
int minimumWidth, minimumHeight;
uiWindowsSizing sizing;
*width = 0;
*height = 0;
if (b->controls->size() == 0)
return;
// 0) get this Box's padding
boxPadding(b, &xpadding, &ypadding);
2015-05-15 23:44:24 -05:00
// 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
// we still add in like direction of stretchy controls
nStretchy = 0;
maxStretchyWidth = 0;
maxStretchyHeight = 0;
for (const struct boxChild &bc : *(b->controls)) {
if (!uiControlVisible(bc.c))
continue;
uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight);
if (bc.stretchy) {
nStretchy++;
if (maxStretchyWidth < minimumWidth)
maxStretchyWidth = minimumWidth;
if (maxStretchyHeight < minimumHeight)
maxStretchyHeight = minimumHeight;
}
if (b->vertical) {
if (*width < minimumWidth)
*width = minimumWidth;
if (!bc.stretchy)
*height += minimumHeight;
} else {
if (!bc.stretchy)
*width += minimumWidth;
if (*height < minimumHeight)
*height = minimumHeight;
}
2015-05-15 23:44:24 -05:00
}
// 3) and now we can add in stretchy controls
if (b->vertical)
*height += nStretchy * maxStretchyHeight;
else
*width += nStretchy * maxStretchyWidth;
2015-05-15 23:44:24 -05:00
}
static void uiBoxMinimumSizeChanged(uiWindowsControl *c)
2015-04-22 16:04:30 -05:00
{
uiBox *b = uiBox(c);
if (uiWindowsControlTooSmall(uiWindowsControl(b))) {
uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(b));
return;
}
boxRelayout(b);
2015-09-02 08:36:53 -05:00
}
uiWindowsControlDefaultLayoutRect(uiBox)
uiWindowsControlDefaultAssignControlIDZOrder(uiBox)
static void boxArrangeChildren(uiBox *b)
{
LONG_PTR controlID;
HWND insertAfter;
controlID = 100;
insertAfter = NULL;
for (const struct boxChild &bc : *(b->controls))
uiWindowsControlAssignControlIDZOrder(uiWindowsControl(bc.c), &controlID, &insertAfter);
}
2015-09-02 08:36:53 -05:00
void uiBoxAppend(uiBox *b, uiControl *c, int stretchy)
{
struct boxChild bc;
bc.c = c;
bc.stretchy = stretchy;
uiControlSetParent(bc.c, uiControl(b));
uiWindowsControlSetParentHWND(uiWindowsControl(bc.c), b->hwnd);
b->controls->push_back(bc);
boxArrangeChildren(b);
uiWindowsControlMinimumSizeChanged(uiWindowsControl(b));
2015-04-22 16:04:30 -05:00
}
void uiBoxDelete(uiBox *b, int index)
2015-04-22 16:04:30 -05:00
{
uiControl *c;
c = (*(b->controls))[index].c;
uiControlSetParent(c, NULL);
uiWindowsControlSetParentHWND(uiWindowsControl(c), NULL);
b->controls->erase(b->controls->begin() + index);
boxArrangeChildren(b);
uiWindowsControlMinimumSizeChanged(uiWindowsControl(b));
2015-04-22 16:04:30 -05:00
}
int uiBoxPadded(uiBox *b)
2015-04-22 16:04:30 -05:00
{
return b->padded;
}
void uiBoxSetPadded(uiBox *b, int padded)
2015-04-22 16:04:30 -05:00
{
b->padded = padded;
uiWindowsControlMinimumSizeChanged(uiWindowsControl(b));
}
static void onResize(uiWindowsControl *c)
{
boxRelayout(uiBox(c));
2015-04-22 16:04:30 -05:00
}
static uiBox *finishNewBox(int vertical)
2015-04-22 16:04:30 -05:00
{
uiBox *b;
2015-04-22 16:04:30 -05:00
uiWindowsNewControl(uiBox, b);
2015-04-22 16:04:30 -05:00
b->hwnd = uiWindowsMakeContainer(uiWindowsControl(b), onResize);
b->vertical = vertical;
b->controls = new std::vector<struct boxChild>;
return b;
2015-04-22 16:04:30 -05:00
}
uiBox *uiNewHorizontalBox(void)
2015-04-22 16:04:30 -05:00
{
return finishNewBox(0);
}
2015-04-22 16:04:30 -05:00
uiBox *uiNewVerticalBox(void)
{
return finishNewBox(1);
2015-04-22 16:04:30 -05:00
}