diff --git a/redo/windows/group.c b/redo/windows/group.c new file mode 100644 index 00000000..592b67ac --- /dev/null +++ b/redo/windows/group.c @@ -0,0 +1,143 @@ +// 16 may 2015 +#include "uipriv_windows.h" + +struct uiGroup { + uiWindowsControl c; + HWND hwnd; + struct child *child; + int margined; +}; + +static void onDestroy(uiGroup *); + +uiWindowsDefineControlWithOnDestroy( + uiGroup, // type name + uiGroupType, // type function + onDestroy(this); // on destroy +) + +static void onDestroy(uiGroup *g) +{ + if (g->child != NULL) + childDestroy(g->child); +} + +// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing +#define groupXMargin 6 +#define groupYMarginTop 11 /* note this value /includes the groupbox label */ +#define groupYMarginBottom 7 + +// unfortunately because the client area of a groupbox includes the frame and caption text, we have to apply some margins ourselves, even if we don't want "any" +// these were deduced by hand based on the standard DLU conversions; the X and Y top margins are the width and height, respectively, of one character cell +// they can be fine-tuned later +#define groupUnmarginedXMargin 4 +#define groupUnmarginedYMarginTop 8 +#define groupUnmarginedYMarginBottom 3 + +static void minimumSize(uiControl *c, uiWindowsSizing *d, intmax_t *width, intmax_t *height) +{ + uiGroup *g = uiGroup(c); + + *width = 0; + *height = 0; + if (g->child != NULL) + childMinimumSize(g->child, d, width, height); + if (g->margined) { + *width += 2 * uiWindowsDlgUnitsToX(groupXMargin, d->BaseX); + *height += uiWindowsDlgUnitsToY(groupYMarginTop, d->BaseY) + uiWindowsDlgUnitsToY(groupYMarginBottom, d->BaseY); + } else { + *width += 2 * uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->BaseX); + *height += uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->BaseY) + uiWindowsDlgUnitsToY(groupUnmarginedYMarginBottom, d->BaseY); + } +} + +static void groupRelayout(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height) +{ + struct group *g = (struct group *) c; + uiSizing *d; + + // TODO + (*(g->baseResize))(uiControl(g), x, y, width, height, d); + + if (g->child == NULL) + return; + + d = uiWindowsGetSizing(g->hwnd); + if (g->margined) { + x += uiWindowsDlgUnitsToX(groupXMargin, d->BaseX); + y += uiWindowsDlgUnitsToY(groupYMarginTop, d->BaseY); + width -= 2 * uiWindowsDlgUnitsToX(groupXMargin, d->BaseX); + height -= uiWindowsDlgUnitsToY(groupYMarginTop, d->BaseY) + uiWindowsDlgUnitsToY(groupYMarginBottom, d->BaseY); + } else { + x += uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->BaseX); + y += uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->BaseY); + width -= 2 * uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->BaseX); + height -= uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->BaseY) + uiWindowsDlgUnitsToY(groupUnmarginedYMarginBottom, d->BaseY); + } + uiWindowsFreeSizing(d); + childRelayout(g->child, x, y, width, height); +} + +static void groupContainerUpdateState(uiControl *c) +{ + uiGroup *g = uiGroup(c); + + if (g->child != NULL) + childUpdateState(g->child); +} + +char *uiGroupTitle(uiGroup *g) +{ + return uiWindowsUtilText(g->hwnd); +} + +void uiGroupSetTitle(uiGroup *g, const char *text) +{ + uiWindowsUtilSetText(g->hwnd, text); + // changing the text might necessitate a change in the groupbox's size + uiControlQueueResize(uiControl(g)); +} + +void uiGroupSetChild(uiGroup *g, uiControl *child) +{ + if (g->child != NULL) + childRemove(g->child); + g->child = newChild(child, uiControl(g), g->hwnd); + if (g->child != NULL) + uiControlQueueResize(g->child); +} + +int uiGroupMargined(uiGroup *g) +{ + return g->margined; +} + +void uiGroupSetMargined(uiGroup *g, int margined) +{ + g->margined = margined; + uiControlQueueResize(uiControl(g)); +} + +uiGroup *uiNewGroup(const char *text) +{ + uiGroup *g; + WCHAR *wtext; + + g = (uiGroup *) uiNewControl(uiGroupType()); + + wtext = toUTF16(text); + g->hwnd = uiWindowsUtilCreateControlHWND(WS_EX_CONTROLPARENT, + L"button", wtext, + BS_GROUPBOX, + hInstance, NULL, + TRUE); + uiFree(wtext); + + // TODO subclass uiGroup to call parent.c functions + + uiWindowsFinishNewControl(g, uiGroup); + uiControl(g)->Resize = groupRelayout; + uiControl(g)->ContainerUpdateState = groupContainerUpdateState; + + return g; +} diff --git a/windows/parent.c b/redo/windows/parent.c similarity index 95% rename from windows/parent.c rename to redo/windows/parent.c index df91bd72..78d2270a 100644 --- a/windows/parent.c +++ b/redo/windows/parent.c @@ -1,7 +1,8 @@ // 26 april 2015 #include "uipriv_windows.h" -// This contains code used by all OS controls that contain other controls. It also contains the container drawing code. +// This contains code used by all uiControls that contain other controls. +// It also contains the code to draw the background of a container.c container, as that is a variant of the WM_CTLCOLORxxx handler code. static HBRUSH parentBrush = NULL; diff --git a/windows/group.c b/windows/group.c deleted file mode 100644 index f8a39dac..00000000 --- a/windows/group.c +++ /dev/null @@ -1,171 +0,0 @@ -// 16 may 2015 -#include "uipriv_windows.h" - -struct group { - uiGroup g; - HWND hwnd; - uiControl *child; - void (*baseCommitDestroy)(uiControl *); - int margined; - void (*baseResize)(uiControl *, intmax_t, intmax_t, intmax_t, intmax_t, uiSizing *); -}; - -uiDefineControlType(uiGroup, uiTypeGroup, struct group) - -static void groupCommitDestroy(uiControl *c) -{ - struct group *g = (struct group *) c; - - if (g->child != NULL) { - uiControlSetParent(g->child, NULL); - uiControlDestroy(g->child); - } - (*(g->baseCommitDestroy))(uiControl(g)); -} - -static uintptr_t groupHandle(uiControl *c) -{ - struct group *g = (struct group *) c; - - return (uintptr_t) (g->hwnd); -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing -#define groupXMargin 6 -#define groupYMarginTop 11 /* note this value /includes the groupbox label */ -#define groupYMarginBottom 7 - -// unfortunately because the client area of a groupbox includes the frame and caption text, we have to apply some margins ourselves, even if we don't want "any" -// these were deduced by hand based on the standard DLU conversions; the X and Y top margins are the width and height, respectively, of one character cell -// they can be fine-tuned later -#define groupUnmarginedXMargin 4 -#define groupUnmarginedYMarginTop 8 -#define groupUnmarginedYMarginBottom 3 - -static void groupPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) -{ - struct group *g = (struct group *) c; - - *width = 0; - *height = 0; - if (g->child != NULL) - uiControlPreferredSize(g->child, d, width, height); - if (g->margined) { - *width += 2 * uiWindowsDlgUnitsToX(groupXMargin, d->Sys->BaseX); - *height += uiWindowsDlgUnitsToY(groupYMarginTop, d->Sys->BaseY) + uiWindowsDlgUnitsToY(groupYMarginBottom, d->Sys->BaseY); - } else { - *width += 2 * uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->Sys->BaseX); - *height += uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->Sys->BaseY) + uiWindowsDlgUnitsToY(groupUnmarginedYMarginBottom, d->Sys->BaseY); - } -} - -static void groupResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) -{ - struct group *g = (struct group *) c; - uiSizing *dchild; - - (*(g->baseResize))(uiControl(g), x, y, width, height, d); - - if (g->child == NULL) - return; - - if (g->margined) { - x += uiWindowsDlgUnitsToX(groupXMargin, d->Sys->BaseX); - y += uiWindowsDlgUnitsToY(groupYMarginTop, d->Sys->BaseY); - width -= 2 * uiWindowsDlgUnitsToX(groupXMargin, d->Sys->BaseX); - height -= uiWindowsDlgUnitsToY(groupYMarginTop, d->Sys->BaseY) + uiWindowsDlgUnitsToY(groupYMarginBottom, d->Sys->BaseY); - } else { - x += uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->Sys->BaseX); - y += uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->Sys->BaseY); - width -= 2 * uiWindowsDlgUnitsToX(groupUnmarginedXMargin, d->Sys->BaseX); - height -= uiWindowsDlgUnitsToY(groupUnmarginedYMarginTop, d->Sys->BaseY) + uiWindowsDlgUnitsToY(groupUnmarginedYMarginBottom, d->Sys->BaseY); - } - - dchild = uiControlSizing(uiControl(g)); - uiControlResize(g->child, x, y, width, height, dchild); - uiFreeSizing(dchild); -} - -static void groupContainerUpdateState(uiControl *c) -{ - struct group *g = (struct group *) c; - - if (g->child != NULL) - uiControlUpdateState(g->child); -} - -static char *groupTitle(uiGroup *gg) -{ - struct group *g = (struct group *) gg; - - return uiWindowsUtilText(g->hwnd); -} - -static void groupSetTitle(uiGroup *gg, const char *text) -{ - struct group *g = (struct group *) gg; - - uiWindowsUtilSetText(g->hwnd, text); - // changing the text might necessitate a change in the groupbox's size - uiControlQueueResize(uiControl(g)); -} - -static void groupSetChild(uiGroup *gg, uiControl *child) -{ - struct group *g = (struct group *) gg; - - if (g->child != NULL) - uiControlSetParent(g->child, NULL); - g->child = child; - if (g->child != NULL) { - uiControlSetParent(g->child, uiControl(g)); - uiControlQueueResize(g->child); - } -} - -static int groupMargined(uiGroup *gg) -{ - struct group *g = (struct group *) gg; - - return g->margined; -} - -static void groupSetMargined(uiGroup *gg, int margined) -{ - struct group *g = (struct group *) gg; - - g->margined = margined; - uiControlQueueResize(uiControl(g)); -} - -uiGroup *uiNewGroup(const char *text) -{ - struct group *g; - WCHAR *wtext; - - g = (struct group *) uiWindowsNewSingleHWNDControl(uiTypeGroup()); - - wtext = toUTF16(text); - g->hwnd = uiWindowsUtilCreateControlHWND(WS_EX_CONTROLPARENT, - L"button", wtext, - BS_GROUPBOX, - hInstance, NULL, - TRUE); - uiFree(wtext); - - uiControl(g)->Handle = groupHandle; - uiControl(g)->PreferredSize = groupPreferredSize; - g->baseResize = uiControl(g)->Resize; - uiControl(g)->Resize = groupResize; - g->baseCommitDestroy = uiControl(g)->CommitDestroy; - uiControl(g)->CommitDestroy = groupCommitDestroy; - uiControl(g)->ContainerUpdateState = groupContainerUpdateState; - - uiGroup(g)->Title = groupTitle; - uiGroup(g)->SetTitle = groupSetTitle; - uiGroup(g)->SetChild = groupSetChild; - uiGroup(g)->Margined = groupMargined; - uiGroup(g)->SetMargined = groupSetMargined; - - return uiGroup(g); -}