From a3f183b6e89dd0cde9db1175e1844e9dbb9a21b0 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 19 May 2015 12:32:14 -0400 Subject: [PATCH] Started implementing uiSpinbox on Windows. --- redo/test/page2.c | 2 +- redo/ui.idl | 2 +- redo/windows/GNUmakeinc.mk | 1 + redo/windows/spinbox.c | 105 +++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 redo/windows/spinbox.c diff --git a/redo/test/page2.c b/redo/test/page2.c index 560d0b2b..43e41267 100644 --- a/redo/test/page2.c +++ b/redo/test/page2.c @@ -106,7 +106,7 @@ uiBox *makePage2(void) button = uiNewButton(moveOutText); uiButtonOnClicked(button, movePage1, NULL); uiBoxAppend(hbox, uiControl(button), 0); - uiBoxAppend(hbox, uiControl(uiNewSpinbox()), 0); + uiBoxAppend(hbox, uiControl(uiNewSpinbox()), 1); uiBoxAppend(page2, uiControl(hbox), 0); moveBack = 0; diff --git a/redo/ui.idl b/redo/ui.idl index 4f2951a3..1fc94fec 100644 --- a/redo/ui.idl +++ b/redo/ui.idl @@ -143,7 +143,7 @@ func NewGroup(text *const char) *Group; interface Spinbox from Control { }; -func NewSpinbox(void); +func NewSpinbox(void) *Spinbox; interface Menu { func AppendItem(name *const char) *MenuItem; diff --git a/redo/windows/GNUmakeinc.mk b/redo/windows/GNUmakeinc.mk index 9136323a..e70db6f7 100644 --- a/redo/windows/GNUmakeinc.mk +++ b/redo/windows/GNUmakeinc.mk @@ -15,6 +15,7 @@ osCFILES = \ windows/menu.c \ windows/parent.c \ windows/resize.c \ + windows/spinbox.c \ windows/tab.c \ windows/text.c \ windows/util.c \ diff --git a/redo/windows/spinbox.c b/redo/windows/spinbox.c new file mode 100644 index 00000000..4095f07c --- /dev/null +++ b/redo/windows/spinbox.c @@ -0,0 +1,105 @@ +// 8 april 2015 +#include "uipriv_windows.h" + +struct spinbox { + uiSpinbox s; + HWND hwnd; + HWND updown; + void (*baseResize)(uiControl *, intmax_t, intmax_t, intmax_t, intmax_t, uiSizing *); +}; + +static BOOL onWM_COMMAND(uiControl *c, WORD code, LRESULT *lResult) +{ + return FALSE; +} + +static BOOL onWM_NOTIFY(uiControl *c, NMHDR *nm, LRESULT *lResult) +{ + return FALSE; +} + +static void onDestroy(void *data) +{ + struct spinbox *s = (struct spinbox *) data; + + uiFree(s); +} + +// from http://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing +#define entryWidth 107 /* this is actually the shorter progress bar width, but Microsoft only indicates as wide as necessary */ +#define entryHeight 14 + +static void spinboxPreferredSize(uiControl *c, uiSizing *d, intmax_t *width, intmax_t *height) +{ + *width = uiWindowsDlgUnitsToX(entryWidth, d->Sys->BaseX); + *height = uiWindowsDlgUnitsToY(entryHeight, d->Sys->BaseY); +} + +// an up-down control will only properly position itself the first time +// stupidly, there are no messages to force a size calculation, nor can I seem to reset the buddy window to force a new position +// alas, we have to make a new up/down control each time :( +// TODO will we need to store a copy of the current position and range for this? +static void recreateUpDown(struct spinbox *s) +{ + HWND parent; + + parent = GetAncestor(s->hwnd, GA_PARENT); + if (s->updown != NULL) + if (DestroyWindow(s->updown) == 0) + logLastError("error destroying old updown in recreateUpDown()"); + s->updown = CreateWindowExW(0, + UPDOWN_CLASSW, L"", + // no WS_VISIBLE; we set visibility ourselves + WS_CHILD | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_HOTTRACK | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, + // this is important; it's necessary for autosizing to work + 0, 0, 0, 0, + parent, NULL, hInstance, NULL); + if (s->updown == NULL) + logLastError("error creating updown in recreateUpDown()"); + SendMessageW(s->updown, UDM_SETBUDDY, (WPARAM) (s->hwnd), 0); + // TODO + SendMessageW(s->updown, UDM_SETRANGE32, 0, 100); + SendMessageW(s->updown, UDM_SETPOS32, 0, 0); + if (uiControlContainerVisible(uiControl(s))) + ShowWindow(s->updown, SW_SHOW); +} + +static void spinboxResize(uiControl *c, intmax_t x, intmax_t y, intmax_t width, intmax_t height, uiSizing *d) +{ + struct spinbox *s = (struct spinbox *) c; + + (*(s->baseResize))(uiControl(s), x, y, width, height, d); + recreateUpDown(s); +} + +uiSpinbox *uiNewSpinbox(void) +{ + struct spinbox *s; + uiWindowsMakeControlParams p; + + s = uiNew(struct spinbox); + uiTyped(s)->Type = uiTypeSpinbox(); + + p.dwExStyle = WS_EX_CLIENTEDGE; + p.lpClassName = L"edit"; + p.lpWindowName = L""; + p.dwStyle = ES_AUTOHSCROLL | ES_LEFT | ES_NOHIDESEL | ES_NUMBER | WS_TABSTOP; + p.hInstance = hInstance; + p.lpParam = NULL; + p.useStandardControlFont = TRUE; + p.onWM_COMMAND = onWM_COMMAND; + p.onWM_NOTIFY = onWM_NOTIFY; + p.onDestroy = onDestroy; + p.onDestroyData = s; + uiWindowsMakeControl(uiControl(s), &p); + + s->hwnd = (HWND) uiControlHandle(uiControl(s)); + + recreateUpDown(s); + + uiControl(s)->PreferredSize = spinboxPreferredSize; + s->baseResize = uiControl(s)->Resize; + uiControl(s)->Resize = spinboxResize; + + return uiSpinbox(s); +}