diff --git a/GNUmakefile b/GNUmakefile index f0e1f055..37365beb 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -23,6 +23,7 @@ baseHFILES = \ $(osHFILES) baseCFILES = \ + bin.c \ box.c \ ptrarray.c \ shouldquit.c \ diff --git a/bin.c b/bin.c new file mode 100644 index 00000000..d6e48033 --- /dev/null +++ b/bin.c @@ -0,0 +1,134 @@ +// 27 april 2015 +#include "uipriv_windows.h" + +struct bin { + uiBin b; + void (*baseDestroy)(uiControl *); + uiControl *mainControl; + intmax_t marginLeft; + intmax_t marginTop; + intmax_t marginRight; + intmax_t marginBottom; +}; + +static void binDestroy(uiControl *c) +{ + struct bin *b = (struct bin *) c; + HWND hwnd; + + // ensure clean removal by making sure the bin has no OS parent + if (uiBinHasOSParent(uiBin(b))) + complain("attempt to destroy bin %p while it has an OS parent", b); + // don't chain up to base here; we need to destroy children ourselves first + if (b->mainControl != NULL) { + uiControlSetParent(b->mainControl, NULL); + uiControlDestroy(b->mainControl); + } + // NOW we can chain up to base + (*(b->baseDestroy))(uiControl(b)); + uiFree(b); +} + +static void binPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) +{ + struct bin *b = (struct bin *) c; + intmax_t left, top, right, bottom; + intmax_t cwid, cht; + + if (b->mainControl == NULL) { + *width = 0; + *height = 0; + return; + } + + // first do margins + left = b->marginLeft; + top = b->marginTop; + right = b->marginRight; + bottom = b->marginBottom; + uiBinTranslateMargins(uiBin(b), &left, &top, &right, &bottom, d); + *width = left + right; + *height = top + bottom; + + // then do the control + uiControlPreferredSize(b->mainControl, d, &cwid, &cht); + *width += cwid; + *height += cht; +} + +static void binSysFunc(uiControl *c, uiControlSysFuncParams *p) +{ + struct bin *b = (struct bin *) c; + + if (b->mainControl != NULL) + uiControlSysFunc(b->mainControl, p); +} + +static void binResizeChildren(uiContainer *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) +{ + struct bin *b = (struct bin *) c; + intmax_t left, top, right, bottom; + + if (b->mainControl == NULL) + return; + left = b->marginLeft; + top = b->marginTop; + right = b->marginRight; + bottom = b->marginBottom; + uiBinTranslateMargins(uiBin(b), &left, &top, &right, &bottom, d); + x += left; + y += top; + width -= left + right; + height -= top + bottom; + uiControlResize(b->mainControl, x, y, width, height, d); +} + +static void binSetMainControl(uiBin *bb, uiControl *mainControl) +{ + struct bin *b = (struct bin *) bb; + + if (b->mainControl != NULL) + uiControlSetParent(b->mainControl, NULL); + b->mainControl = mainControl; + if (b->mainControl != NULL) + uiControlSetParent(b->mainControl, uiContainer(b)); + uiContainerUpdate(uiContainer(b)); +} + +static void binSetMargins(uiBin *bb, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) +{ + struct bin *b = (struct bin *) bb; + + b->marginLeft = left; + b->marginRight = right; + b->marginTop = top; + b->marginBottom = bottom; + uiContainerUpdate(uiContainer(b)); +} + +uiBin *newBin(void) +{ + struct bin *b; + + b = uiNew(struct bin); + + uiMakeContainer(uiContainer(b)); + + b->baseDestroy = uiControl(b)->Destroy; + uiControl(b)->Destroy = binDestroy; + uiControl(b)->PreferredSize = binPreferredSize; + uiControl(b)->SysFunc = binSysFunc; + + uiContainer(b)->ResizeChildren = binResizeChildren; + + uiBin(b)->SetMainControl = binSetMainControl; + uiBin(b)->SetMargins = binSetMargins; + // these are defined by each OS's bin.c + uiBin(b)->HasOSParent = binHasOSParent; + uiBin(b)->SetOSParent = binSetOSParent; + uiBin(b)->RemoveOSParent = binRemoveOSParent; + uiBin(b)->ResizeRoot = binResizeRoot; + uiBin(b)->TranslateMargins = binTranslateMargins; + + return uiBin(b); +} diff --git a/ui.idl b/ui.idl index 41e76b88..d0cf913d 100644 --- a/ui.idl +++ b/ui.idl @@ -59,6 +59,17 @@ interface Container from Control { }; func MakeContainer(c *Container); +interface Bin from Container { + func SetMainControl(c *Control); + func SetMargins(left intmax_t, top intmax_t, right intmax_t, bottom intmax_t); + // defined by each OS + func HasOSParent(void) int; + func SetOSParent(parent uintptr_t); + func RemoveOSParent(void); + func ResizeRoot(x intmax_t, y intmax_t, width intmax_t, height intmax_t); + func TranslateMargins(left *intmax_t, top *intmax_t, right *intmax_t, bottom *intmax_t, d *Sizing); +}; + interface Window from Control { func Title(void) *char; func SetTitle(title *const char); diff --git a/uipriv.h b/uipriv.h index 17493d9d..67618536 100644 --- a/uipriv.h +++ b/uipriv.h @@ -10,10 +10,12 @@ extern void uiFree(void *); extern void complain(const char *, ...); -extern uiContainer *newBin(void); -extern void binSetMainControl(uiContainer *, uiControl *); -extern void binSetMargins(uiContainer *, intmax_t, intmax_t, intmax_t, intmax_t); -extern void binSetParent(uiContainer *, uintptr_t); +extern uiBin *newBin(void); +extern int binHasOSParent(uiBin *); +extern void binSetOSParent(uiBin *, uintptr_t); +extern void binRemoveOSParent(uiBin *); +extern void binResizeRoot(uiBin *, intmax_t, intmax_t, intmax_t, intmax_t); +extern void binTranslateMargins(uiBin *, intmax_t *, intmax_t *, intmax_t *, intmax_t *, uiSizing *); // array.c struct ptrArray { diff --git a/windows/bin.c b/windows/bin.c index 9e69a0f5..afd95778 100644 --- a/windows/bin.c +++ b/windows/bin.c @@ -1,126 +1,42 @@ // 27 april 2015 #include "uipriv_windows.h" -struct bin { - uiContainer c; - void (*baseDestroy)(uiControl *); - uiControl *mainControl; - intmax_t marginLeft; - intmax_t marginTop; - intmax_t marginRight; - intmax_t marginBottom; -}; - -static void binDestroy(uiControl *c) +int binHasOSParent(uiBin *b) { - struct bin *b = (struct bin *) c; HWND hwnd; - // ensure clean removal by making sure the bin has no OS parent hwnd = (HWND) uiControlHandle(uiControl(b)); - if (GetAncestor(hwnd, GA_PARENT) != initialParent) - complain("attempt to destroy bin %p while it has an OS parent", b); - // don't chain up to base here; we need to destroy children ourselves first - if (b->mainControl != NULL) { - uiControlSetParent(b->mainControl, NULL); - uiControlDestroy(b->mainControl); - } - // NOW we can chain up to base - (*(b->baseDestroy))(uiControl(b)); - uiFree(b); + return GetAncestor(hwnd, GA_PARENT) != initialParent; } -static void binPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) +void binSetOSParent(uiBin *b, uintptr_t osParent) { - struct bin *b = (struct bin *) c; - intmax_t marginX, marginY; + HWND hwnd; + HWND parent = (HWND) osParent; - if (b->mainControl == NULL) { - *width = 0; - *height = 0; - return; - } - uiControlPreferredSize(b->mainControl, d, width, height); - marginX = uiWindowsDlgUnitsToX(b->marginLeft, d->Sys->BaseX) + uiWindowsDlgUnitsToX(b->marginRight, d->Sys->BaseX); - marginY = uiWindowsDlgUnitsToY(b->marginTop, d->Sys->BaseY) + uiWindowsDlgUnitsToY(b->marginBottom, d->Sys->BaseY); - *width += marginX; - *height += marginY; + hwnd = (HWND) uiControlHandle(uiControl(b)); + if (SetParent(hwnd, parent) == 0) + logLastError("error setting bin OS parent in binSetOSParent()"); } -static void binSysFunc(uiControl *c, uiControlSysFuncParams *p) +void binRemoveOSParent(uiBin *b) { - struct bin *b = (struct bin *) c; - - if (b->mainControl != NULL) - uiControlSysFunc(b->mainControl, p); + binSetOSParent(b, (uintptr_t) initialParent); } -static void binResizeChildren(uiContainer *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) +void binResizeRoot(uiBin *b, intmax_t x, intmax_t y, intmax_t width, intmax_t height) { - struct bin *b = (struct bin *) c; - intmax_t marginLeft, marginTop; + HWND hwnd; - if (b->mainControl == NULL) - return; - marginLeft = uiWindowsDlgUnitsToX(b->marginLeft, d->Sys->BaseX); - marginTop = uiWindowsDlgUnitsToY(b->marginTop, d->Sys->BaseY); - x += marginLeft; - y += marginTop; - width -= marginLeft + uiWindowsDlgUnitsToX(b->marginRight, d->Sys->BaseX); - height -= marginTop + uiWindowsDlgUnitsToY(b->marginBottom, d->Sys->BaseY); - uiControlResize(b->mainControl, x, y, width, height, d); -} - -uiContainer *newBin(void) -{ - struct bin *b; - - b = uiNew(struct bin); - - uiMakeContainer(uiContainer(b)); - - b->baseDestroy = uiControl(b)->Destroy; - uiControl(b)->Destroy = binDestroy; - uiControl(b)->PreferredSize = binPreferredSize; - uiControl(b)->SysFunc = binSysFunc; - - uiContainer(b)->ResizeChildren = binResizeChildren; - - return uiContainer(b); -} - -void binSetMainControl(uiContainer *c, uiControl *mainControl) -{ - struct bin *b = (struct bin *) c; - - if (b->mainControl != NULL) - uiControlSetParent(b->mainControl, NULL); - b->mainControl = mainControl; - if (b->mainControl != NULL) - uiControlSetParent(b->mainControl, uiContainer(b)); + hwnd = (HWND) uiControlHandle(uiControl(b)); + moveWindow(hwnd, x, y, width, height); uiContainerUpdate(uiContainer(b)); } -void binSetMargins(uiContainer *c, intmax_t left, intmax_t top, intmax_t right, intmax_t bottom) +void binTranslateMargins(uiBin *b, intmax_t *left, intmax_t *top, intmax_t *right, intmax_t *bottom, uiSizing *d) { - struct bin *b = (struct bin *) c; - - b->marginLeft = left; - b->marginRight = right; - b->marginTop = top; - b->marginBottom = bottom; - uiContainerUpdate(uiContainer(b)); -} - -void binSetParent(uiContainer *c, uintptr_t osParent) -{ - struct bin *b = (struct bin *) c; - HWND hwnd; - HWND newParent = (HWND) osParent; - - hwnd = (HWND) uiControlHandle(uiControl(b)); - if (newParent == NULL) - newParent = initialParent; - if (SetParent(hwnd, newParent) == 0) - logLastError("error changing bin's parent in binSetParent()"); + *left = uiWindowsDlgUnitsToX(*left, d->Sys->BaseX); + *top = uiWindowsDlgUnitsToY(*top, d->Sys->BaseY); + *right = uiWindowsDlgUnitsToX(*right, d->Sys->BaseX); + *bottom = uiWindowsDlgUnitsToY(*bottom, d->Sys->BaseY); }