diff --git a/redo/ui_windows.h b/redo/ui_windows.h index adc63a33..8b0f177a 100644 --- a/redo/ui_windows.h +++ b/redo/ui_windows.h @@ -46,6 +46,8 @@ struct uiSizingSys { // Use these in your preferredSize() implementation with baseX and baseY. #define uiWindowsDlgUnitsToX(dlg, baseX) MulDiv((dlg), baseX, 4) #define uiWindowsDlgUnitsToY(dlg, baseY) MulDiv((dlg), baseY, 8) +// Use this as your control's GetSizing() implementation. +extern void uiWindowsGetSizing(uiControl *, uiSizing *); // and use this if you need the text of the window width _UI_EXTERN intmax_t uiWindowsWindowTextWidth(HWND hwnd); diff --git a/redo/windows/control.c b/redo/windows/control.c index e701575e..9a12c0a0 100644 --- a/redo/windows/control.c +++ b/redo/windows/control.c @@ -68,7 +68,7 @@ static void singleQueueResize(uiControl *c) static void singleGetSIzing(uiControl *c, uiSizing *d) { - // TODO + uiWindowsGetSizing(c, d); } static void singleComputeChildSize(uiControl *c, intmax_t *x, intmax_t *y, intmax_t *width, intmax_t *height, uiSizing *d) diff --git a/redo/windows/resize.c b/redo/windows/resize.c index e54e3b6b..8d946dd2 100644 --- a/redo/windows/resize.c +++ b/redo/windows/resize.c @@ -59,3 +59,44 @@ void moveAndReorderWindow(HWND hwnd, HWND insertAfter, intmax_t x, intmax_t y, i if (SetWindowPos(hwnd, insertAfter, x, y, width, height, swpflags) == 0) logLastError("error moving and reordering window in moveAndReorderWindow()"); } + +// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx +// this X value is really only for buttons but I don't see a better one :/ +#define winXPadding 4 +#define winYPadding 4 + +void uiWindowsGetSizing(uiControl *c, uiSizing *d) +{ + HWND hwnd; + HDC dc; + HFONT prevfont; + TEXTMETRICW tm; + SIZE size; + + hwnd = (HWND) uiControlHandle(c); + + dc = GetDC(c->hwnd); + if (dc == NULL) + logLastError("error getting DC in uiWindowsGetSizing()"); + prevfont = (HFONT) SelectObject(dc, hMessageFont); + if (prevfont == NULL) + logLastError("error loading control font into device context in uiWindowsGetSizing()"); + + ZeroMemory(&tm, sizeof (TEXTMETRICW)); + if (GetTextMetricsW(dc, &tm) == 0) + logLastError("error getting text metrics in uiWindowsGetSizing()"); + if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) + logLastError("error getting text extent point in uiWindowsGetSizing()"); + + d->Sys->BaseX = (int) ((size.cx / 26 + 1) / 2); + d->Sys->BaseY = (int) tm.tmHeight; + d->Sys->InternalLeading = tm.tmInternalLeading; + + if (SelectObject(dc, prevfont) != hMessageFont) + logLastError("error restoring previous font into device context in uiWindowsGetSizing()"); + if (ReleaseDC(c->hwnd, dc) == 0) + logLastError("error releasing DC in uiWindowsGetSizing()"); + + d->XPadding = uiWindowsDlgUnitsToX(winXPadding, sys.BaseX); + d->YPadding = uiWindowsDlgUnitsToY(winYPadding, sys.BaseY); +} diff --git a/redo/windows/window.c b/redo/windows/window.c index a0d86105..4f1d7805 100644 --- a/redo/windows/window.c +++ b/redo/windows/window.c @@ -134,7 +134,7 @@ static void windowQueueResize(uiControl *c) static void windowGetSizing(uiControl *c, uiSizing *d) { - // TODO + uiWindowsGetSizing(c, d); } // from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing diff --git a/windows/container.c b/windows/container.c index 9f66e38b..35fb6b73 100644 --- a/windows/container.c +++ b/windows/container.c @@ -1,161 +1,6 @@ // 26 april 2015 #include "uipriv_windows.h" -#define containerClass L"libui_uiContainerClass" - -HWND initialParent; - -struct container { - HWND hwnd; - uiContainer *parent; - int hidden; - HBRUSH brush; -}; - -static HWND realParent(HWND hwnd) -{ - HWND parent; - int class; - - parent = hwnd; - for (;;) { - parent = GetAncestor(parent, GA_PARENT); - // skip groupboxes; they're (supposed to be) transparent - // skip uiContainers; they don't draw anything - class = windowClassOf(parent, L"button", containerClass, NULL); - if (class != 0 && class != 1) - break; - } - return parent; -} - -struct parentDraw { - HDC cdc; - HBITMAP bitmap; - HBITMAP prevbitmap; -}; - -static void parentDraw(HDC dc, HWND parent, struct parentDraw *pd) -{ - RECT r; - - if (GetClientRect(parent, &r) == 0) - logLastError("error getting parent's client rect in parentDraw()"); - pd->cdc = CreateCompatibleDC(dc); - if (pd->cdc == NULL) - logLastError("error creating compatible DC in parentDraw()"); - pd->bitmap = CreateCompatibleBitmap(dc, r.right - r.left, r.bottom - r.top); - if (pd->bitmap == NULL) - logLastError("error creating compatible bitmap in parentDraw()"); - pd->prevbitmap = SelectObject(pd->cdc, pd->bitmap); - if (pd->prevbitmap == NULL) - logLastError("error selecting bitmap into compatible DC in parentDraw()"); - SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) (pd->cdc), PRF_CLIENT); -} - -static void endParentDraw(struct parentDraw *pd) -{ - if (SelectObject(pd->cdc, pd->prevbitmap) != pd->bitmap) - logLastError("error selecting previous bitmap back into compatible DC in endParentDraw()"); - if (DeleteObject(pd->bitmap) == 0) - logLastError("error deleting compatible bitmap in endParentDraw()"); - if (DeleteDC(pd->cdc) == 0) - logLastError("error deleting compatible DC in endParentDraw()"); -} - -// see http://www.codeproject.com/Articles/5978/Correctly-drawn-themed-dialogs-in-WinXP -static HBRUSH getControlBackgroundBrush(HWND hwnd, HDC dc) -{ - HWND parent; - RECT hwndScreenRect; - struct parentDraw pd; - HBRUSH brush; - - parent = realParent(hwnd); - - parentDraw(dc, parent, &pd); - brush = CreatePatternBrush(pd.bitmap); - if (brush == NULL) - logLastError("error creating pattern brush in getControlBackgroundBrush()"); - endParentDraw(&pd); - - // now figure out where the control is relative to the parent so we can align the brush properly - if (GetWindowRect(hwnd, &hwndScreenRect) == 0) - logLastError("error getting control window rect in getControlBackgroundBrush()"); - // this will be in screen coordinates; convert to parent coordinates - mapWindowRect(NULL, parent, &hwndScreenRect); - if (SetBrushOrgEx(dc, -hwndScreenRect.left, -hwndScreenRect.top, NULL) == 0) - logLastError("error setting brush origin in getControlBackgroundBrush()"); - - return brush; -} - -static void paintContainerBackground(HWND hwnd, HDC dc, RECT *paintRect) -{ - HWND parent; - RECT paintRectParent; - struct parentDraw pd; - - parent = realParent(hwnd); - parentDraw(dc, parent, &pd); - - paintRectParent = *paintRect; - mapWindowRect(hwnd, parent, &paintRectParent); - if (BitBlt(dc, paintRect->left, paintRect->top, paintRect->right - paintRect->left, paintRect->bottom - paintRect->top, - pd.cdc, paintRectParent.left, paintRectParent.top, - SRCCOPY) == 0) - logLastError("error drawing parent background over uiContainer in paintContainerBackground()"); - - endParentDraw(&pd); -} - -// from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing and https://msdn.microsoft.com/en-us/library/windows/desktop/bb226818%28v=vs.85%29.aspx -// this X value is really only for buttons but I don't see a better one :/ -#define winXPadding 4 -#define winYPadding 4 - -// abort the resize if something fails and we don't have what we need to do a resize -static HRESULT resize(uiContainer *cc, RECT *r) -{ - struct container *c = (struct container *) (uiControl(cc)->Internal); - uiSizing d; - uiSizingSys sys; - HDC dc; - HFONT prevfont; - TEXTMETRICW tm; - SIZE size; - - dc = GetDC(c->hwnd); - if (dc == NULL) - return logLastError("error getting DC in resize()"); - prevfont = (HFONT) SelectObject(dc, hMessageFont); - if (prevfont == NULL) - return logLastError("error loading control font into device context in resize()"); - - ZeroMemory(&tm, sizeof (TEXTMETRICW)); - if (GetTextMetricsW(dc, &tm) == 0) - return logLastError("error getting text metrics in resize()"); - if (GetTextExtentPoint32W(dc, L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &size) == 0) - return logLastError("error getting text extent point in resize()"); - - sys.BaseX = (int) ((size.cx / 26 + 1) / 2); - sys.BaseY = (int) tm.tmHeight; - sys.InternalLeading = tm.tmInternalLeading; - - if (SelectObject(dc, prevfont) != hMessageFont) - return logLastError("error restoring previous font into device context in resize()"); - if (ReleaseDC(c->hwnd, dc) == 0) - return logLastError("error releasing DC in resize()"); - - // the first control gets the topmost z-order and thus the first tab stop - sys.InsertAfter = HWND_TOP; - - d.XPadding = uiWindowsDlgUnitsToX(winXPadding, sys.BaseX); - d.YPadding = uiWindowsDlgUnitsToY(winYPadding, sys.BaseY); - d.Sys = &sys; - uiContainerResizeChildren(cc, r->left, r->top, r->right - r->left, r->bottom - r->top, &d); - return S_OK; -} static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { @@ -177,35 +22,9 @@ static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LP // instead, we simply check if c == NULL again later switch (uMsg) { - // these must always be run, even on the initial parent - // why? http://blogs.msdn.com/b/oldnewthing/archive/2010/03/16/9979112.aspx - case WM_COMMAND: - // bounce back to the control in question - // except if to the initial parent, in which case act as if the message was ignored - control = (HWND) lParam; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgCOMMAND, wParam, lParam); - break; // fall through to DefWindowProcW() - case WM_NOTIFY: - // same as WM_COMMAND - control = nm->hwndFrom; - if (control != NULL && IsChild(initialParent, control) == 0) - return SendMessageW(control, msgNOTIFY, wParam, lParam); - break; // these are only run if c is not NULL - case WM_CTLCOLORSTATIC: - case WM_CTLCOLORBTN: - if (cc == NULL) - break; - c = (struct container *) (uiControl(cc)->Internal); - if (c->brush != NULL) - if (DeleteObject(c->brush) == 0) - logLastError("error deleting old background brush in containerWndProc()"); - if (SetBkMode((HDC) wParam, TRANSPARENT) == 0) - logLastError("error setting transparent background mode to controls in containerWndProc()"); - c->brush = getControlBackgroundBrush((HWND) lParam, (HDC) wParam); - return (LRESULT) (c->brush); + case WM_PAINT: if (cc == NULL) break; @@ -242,60 +61,11 @@ static LRESULT CALLBACK containerWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LP logLastError("error queueing redraw after resize in containerWndProc()"); return 0; - // and this is run only on the initial parent - // this ensures that all end session handling is done in one place and only once - case WM_QUERYENDSESSION: - case msgConsoleEndSession: - if (cc != NULL) - break; - // TODO block handler - if (shouldQuit()) { - uiQuit(); - return TRUE; - } - return FALSE; } return DefWindowProcW(hwnd, uMsg, wParam, lParam); } -const char *initContainer(HICON hDefaultIcon, HCURSOR hDefaultCursor) -{ - WNDCLASSW wc; - - ZeroMemory(&wc, sizeof (WNDCLASSW)); - wc.lpszClassName = containerClass; - wc.lpfnWndProc = containerWndProc; - wc.hInstance = hInstance; - wc.hIcon = hDefaultIcon; - wc.hCursor = hDefaultCursor; - wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1); - if (RegisterClassW(&wc) == 0) - return "registering uiContainer window class"; - - initialParent = CreateWindowExW(0, - containerClass, L"", - WS_OVERLAPPEDWINDOW, - 0, 0, - 100, 100, - NULL, NULL, hInstance, NULL); - if (initialParent == NULL) - return "creating initial parent window"; - - // just to be safe, disable the initial parent so it can't be interacted with accidentally - // if this causes issues for our controls, we can remove it - EnableWindow(initialParent, FALSE); - return NULL; -} - -void uninitContainer(void) -{ - if (DestroyWindow(initialParent) == 0) - logLastError("error destroying initial parent in uninitContainer()"); - if (UnregisterClassW(containerClass, hInstance) == 0) - logLastError("error unregistering uiContainer window class in uninitContainer()"); -} - // subclasses override this and call back here when all children are destroyed static void containerDestroy(uiControl *cc) {