From c3777da0f45c9557a8b514a90ab85198cdd7c4a2 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 15 Jun 2016 21:55:42 -0400 Subject: [PATCH] And added the new uiWindow methods on Windows. --- README.md | 1 + windows/window.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/README.md b/README.md index 1aea4549..86a83fa7 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ This README is being written.
* **15 June 2016** * Added `uiFormDelete()`; thanks to @emersion. + * Added `uiWindowPosition()`, `uiWindowSetPosition()`, `uiWindowCenter()`, and `uiWindowOnPositionChanged()`, methods for manipulating uiWindow position. * **14 June 2016** * uiDarwinControl now has a `ChildVisibilityChanged()` method and a corresponding `NotifyVisibilityChanged()` function that is called by the default show/hide handlers. This is used to make visibility changes work on OS X; uiBox, uiForm, and uiGrid all respect these now. diff --git a/windows/window.cpp b/windows/window.cpp index 411cb86e..f753d93c 100644 --- a/windows/window.cpp +++ b/windows/window.cpp @@ -14,6 +14,9 @@ struct uiWindow { void *onClosingData; int margined; BOOL hasMenubar; + void (*onPositionChanged)(uiWindow *, void *); + void *onPositionChangedData; + BOOL changingPosition; }; // from https://msdn.microsoft.com/en-us/library/windows/desktop/dn742486.aspx#sizingandspacing @@ -87,6 +90,10 @@ static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARA runMenuEvent(LOWORD(wParam), uiWindow(w)); return 0; case WM_WINDOWPOSCHANGED: + if ((wp->flags & SWP_NOMOVE) == 0) + if (!w->changingPosition) + (*(w->onPositionChanged))(w, w->onPositionChangedData); + // and continue anyway if ((wp->flags & SWP_NOSIZE) != 0) break; windowRelayout(w); @@ -138,6 +145,11 @@ static int defaultOnClosing(uiWindow *w, void *data) return 0; } +static void defaultOnPositionChanged(uiWindow *w, void *data) +{ + // do nothing +} + static std::map windows; static void uiWindowDestroy(uiControl *c) @@ -277,6 +289,74 @@ void uiWindowSetTitle(uiWindow *w, const char *title) // don't queue resize; the caption isn't part of what affects layout and sizing of the client area (it'll be ellipsized if too long) } +void uiWindowPosition(uiWindow *w, int *x, int *y) +{ + RECT r; + + uiWindowsEnsureGetWindowRect(w->hwnd, &r); + *x = r.left; + *y = r.top; +} + +void uiWindowSetPosition(uiWindow *w, int x, int y) +{ + w->changingPosition = TRUE; + if (SetWindowPos(w->hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER) == 0) + logLastError(L"error moving window"); + w->changingPosition = FALSE; +} + +// this is used for both fullscreening and centering +// see also https://blogs.msdn.microsoft.com/oldnewthing/20100412-00/?p=14353 and https://blogs.msdn.microsoft.com/oldnewthing/20050505-04/?p=35703 +static void windowMonitorRect(HWND hwnd, RECT *r) +{ + HMONITOR monitor; + MONITORINFO mi; + + monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + ZeroMemory(&mi, sizeof (MONITORINFO)); + mi.cbSize = sizeof (MONITORINFO); + if (GetMonitorInfoW(monitor, &mi) == 0) { + logLastError(L"error getting window monitor rect"); + // default to SM_CXSCREEN x SM_CYSCREEN to be safe + r->left = 0; + r->top = 0; + r->right = GetSystemMetrics(SM_CXSCREEN); + r->bottom = GetSystemMetrics(SM_CYSCREEN); + return; + } + *r = mi.rcMonitor; +} + +// TODO use the work rect instead? +void uiWindowCenter(uiWindow *w) +{ + RECT wr, mr; + int x, y; + LONG wwid, mwid; + LONG wht, mht; + + uiWindowsEnsureGetWindowRect(w->hwnd, &wr); + windowMonitorRect(w->hwnd, &mr); + wwid = wr.right - wr.left; + mwid = mr.right - mr.left; + x = (mwid - wwid) / 2; + wht = wr.bottom - wr.top; + mht = mr.bottom - mr.top; + y = (mht - wht) / 2; + // y is now evenly divided, however https://msdn.microsoft.com/en-us/library/windows/desktop/dn742502(v=vs.85).aspx says that 45% should go above and 55% should go below + // so just move 5% of the way up + // TODO is this correct? + y -= y / 20; + uiWindowSetPosition(w, x, y); +} + +void uiWindowOnPositionChanged(uiWindow *w, void (*f)(uiWindow *, void *), void *data) +{ + w->onPositionChanged = f; + w->onPositionChangedData = data; +} + void uiWindowOnClosing(uiWindow *w, int (*f)(uiWindow *, void *), void *data) { w->onClosing = f; @@ -373,6 +453,7 @@ uiWindow *uiNewWindow(const char *title, int width, int height, int hasMenubar) setClientSize(w, width, height, hasMenubarBOOL, style, exstyle); uiWindowOnClosing(w, defaultOnClosing, NULL); + uiWindowOnPositionChanged(w, defaultOnPositionChanged, NULL); windows[w] = true; return w;