aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl/libui/windows/box.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl/libui/windows/box.cpp')
-rw-r--r--src/libui_sdl/libui/windows/box.cpp320
1 files changed, 320 insertions, 0 deletions
diff --git a/src/libui_sdl/libui/windows/box.cpp b/src/libui_sdl/libui/windows/box.cpp
new file mode 100644
index 0000000..9567954
--- /dev/null
+++ b/src/libui_sdl/libui/windows/box.cpp
@@ -0,0 +1,320 @@
+// 7 april 2015
+#include "uipriv_windows.hpp"
+
+struct boxChild {
+ uiControl *c;
+ int stretchy;
+ int width;
+ int height;
+};
+
+struct uiBox {
+ uiWindowsControl c;
+ HWND hwnd;
+ std::vector<struct boxChild> *controls;
+ int vertical;
+ int padded;
+};
+
+static void boxPadding(uiBox *b, int *xpadding, int *ypadding)
+{
+ uiWindowsSizing sizing;
+
+ *xpadding = 0;
+ *ypadding = 0;
+ if (b->padded) {
+ uiWindowsGetSizing(b->hwnd, &sizing);
+ uiWindowsSizingStandardPadding(&sizing, xpadding, ypadding);
+ }
+}
+
+static void boxRelayout(uiBox *b)
+{
+ RECT r;
+ int x, y, width, height;
+ int xpadding, ypadding;
+ int nStretchy;
+ int stretchywid, stretchyht;
+ int i;
+ int minimumWidth, minimumHeight;
+ int nVisible;
+ uiWindowsSizing *d;
+
+ if (b->controls->size() == 0)
+ return;
+
+ uiWindowsEnsureGetClientRect(b->hwnd, &r);
+ x = r.left;
+ y = r.top;
+ width = r.right - r.left;
+ height = r.bottom - r.top;
+
+ // -1) get this Box's padding
+ boxPadding(b, &xpadding, &ypadding);
+
+ // 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;
+ }
+ uiWindowsControlMinimumSize(uiWindowsControl(bc.c), &minimumWidth, &minimumHeight);
+ if (b->vertical) { // all controls have same width
+ bc.width = width;
+ bc.height = minimumHeight;
+ stretchyht -= minimumHeight;
+ } else { // all controls have same height
+ bc.width = minimumWidth;
+ bc.height = height;
+ stretchywid -= minimumWidth;
+ }
+ }
+ if (nVisible == 0) // nothing to do
+ return;
+
+ // 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;
+ for (struct boxChild &bc : *(b->controls)) {
+ if (!uiControlVisible(bc.c))
+ continue;
+ if (bc.stretchy) {
+ bc.width = stretchywid;
+ bc.height = stretchyht;
+ }
+ }
+ }
+
+ // 4) 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))
+ continue;
+ uiWindowsEnsureMoveWindowDuringResize((HWND) uiControlHandle(bc.c), x, y, bc.width, bc.height);
+ if (b->vertical)
+ y += bc.height + ypadding;
+ 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);
+ }
+ delete b->controls;
+ uiWindowsEnsureDestroyWindow(b->hwnd);
+ uiFreeControl(uiControl(b));
+}
+
+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);
+}
+
+uiWindowsControlDefaultSetParentHWND(uiBox)
+
+static void uiBoxMinimumSize(uiWindowsControl *c, int *width, int *height)
+{
+ 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;
+ int nVisible;
+ uiWindowsSizing sizing;
+
+ *width = 0;
+ *height = 0;
+ if (b->controls->size() == 0)
+ return;
+
+ // 0) get this Box's padding
+ boxPadding(b, &xpadding, &ypadding);
+
+ // 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++;
+ 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;
+ }
+ }
+ 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)
+ *height += nStretchy * maxStretchyHeight;
+ else
+ *width += nStretchy * maxStretchyWidth;
+}
+
+static void uiBoxMinimumSizeChanged(uiWindowsControl *c)
+{
+ uiBox *b = uiBox(c);
+
+ if (uiWindowsControlTooSmall(uiWindowsControl(b))) {
+ uiWindowsControlContinueMinimumSizeChanged(uiWindowsControl(b));
+ return;
+ }
+ boxRelayout(b);
+}
+
+uiWindowsControlDefaultLayoutRect(uiBox)
+uiWindowsControlDefaultAssignControlIDZOrder(uiBox)
+
+static void uiBoxChildVisibilityChanged(uiWindowsControl *c)
+{
+ // TODO eliminate the redundancy
+ uiWindowsControlMinimumSizeChanged(c);
+}
+
+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);
+}
+
+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));
+}
+
+void uiBoxDelete(uiBox *b, int index)
+{
+ 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));
+}
+
+int uiBoxPadded(uiBox *b)
+{
+ return b->padded;
+}
+
+void uiBoxSetPadded(uiBox *b, int padded)
+{
+ b->padded = padded;
+ uiWindowsControlMinimumSizeChanged(uiWindowsControl(b));
+}
+
+static void onResize(uiWindowsControl *c)
+{
+ boxRelayout(uiBox(c));
+}
+
+static uiBox *finishNewBox(int vertical)
+{
+ uiBox *b;
+
+ uiWindowsNewControl(uiBox, b);
+
+ b->hwnd = uiWindowsMakeContainer(uiWindowsControl(b), onResize);
+
+ b->vertical = vertical;
+ b->controls = new std::vector<struct boxChild>;
+
+ return b;
+}
+
+uiBox *uiNewHorizontalBox(void)
+{
+ return finishNewBox(0);
+}
+
+uiBox *uiNewVerticalBox(void)
+{
+ return finishNewBox(1);
+}