diff --git a/BeefLibs/Beefy2D/src/BFApp.bf b/BeefLibs/Beefy2D/src/BFApp.bf index 0d931ac8..20835a1b 100644 --- a/BeefLibs/Beefy2D/src/BFApp.bf +++ b/BeefLibs/Beefy2D/src/BFApp.bf @@ -81,6 +81,9 @@ namespace Beefy [StdCall, CLink] static extern void BFApp_GetWorkspaceRect(out int32 x, out int32 y, out int32 width, out int32 height); + [StdCall, CLink] + static extern void BFApp_GetWorkspaceRectFrom(int32 x, int32 y, int32 width, int32 height, out int32 outX, out int32 outY, out int32 outWidth, out int32 outHeight); + [StdCall, CLink] static extern void BFApp_Create(); @@ -447,6 +450,19 @@ namespace Beefy height = heightOut; } + public void GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, out int outX, out int outY, out int outWidth, out int outHeight) + { + int32 xOut; + int32 yOut; + int32 widthOut; + int32 heightOut; + BFApp_GetWorkspaceRectFrom((.)fromX, (.)fromY, (.)fromWidth, (.)fromHeight, out xOut, out yOut, out widthOut, out heightOut); + outX = xOut; + outY = yOut; + outWidth = widthOut; + outHeight = heightOut; + } + public bool HasModalDialogs() { for (var window in mWindows) diff --git a/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf b/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf index 58f0bc9e..66c68f20 100644 --- a/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf +++ b/BeefLibs/Beefy2D/src/theme/dark/DarkTooltip.bf @@ -51,7 +51,7 @@ namespace Beefy.theme.dark mText = new String(text); mAllowResize = allowResize; - BFApp.sApp.GetWorkspaceRect(var workspaceX, var workspaceY, var workspaceWidth, var workspaceHeight); + BFApp.sApp.GetWorkspaceRectFrom((.)x, (.)y, 0, 0, var workspaceX, var workspaceY, var workspaceWidth, var workspaceHeight); float maxWidth = workspaceWidth - GS!(32); FontMetrics fontMetrics = .(); diff --git a/BeefLibs/Beefy2D/src/widgets/Menu.bf b/BeefLibs/Beefy2D/src/widgets/Menu.bf index f751c532..06047529 100644 --- a/BeefLibs/Beefy2D/src/widgets/Menu.bf +++ b/BeefLibs/Beefy2D/src/widgets/Menu.bf @@ -178,7 +178,7 @@ namespace Beefy.widgets base.Resize(x, y, width, height); } - public virtual void CalcContainerSize(MenuContainer menuContainer, bool allowScrollable, ref float screenX, ref float screenY, out float width, out float height) + public virtual void CalcContainerSize(float x, float y, MenuContainer menuContainer, bool allowScrollable, ref float screenX, ref float screenY, out float width, out float height) { Rect menuRect = menuContainer.CalcRectFromContent(); width = Math.Min(mMaxContainerWidth, Math.Max(mMinContainerWidth, menuRect.mWidth)); @@ -188,7 +188,7 @@ namespace Beefy.widgets int workspaceY; int workspaceWidth; int workspaceHeight; - BFApp.sApp.GetWorkspaceRect(out workspaceX, out workspaceY, out workspaceWidth, out workspaceHeight); + BFApp.sApp.GetWorkspaceRectFrom((.)x, (.)y, 0, 0, out workspaceX, out workspaceY, out workspaceWidth, out workspaceHeight); float maxY = workspaceY + workspaceHeight; @@ -250,13 +250,14 @@ namespace Beefy.widgets float screenX; float screenY; relativeWidget.SelfToRootTranslate(0, curY, out screenX, out screenY); + screenX += relativeWidget.mWidgetWindow.mClientX; screenY += relativeWidget.mWidgetWindow.mClientY; int wsX; int wsY; int wsWidth; int wsHeight; - BFApp.sApp.GetWorkspaceRect(out wsX, out wsY, out wsWidth, out wsHeight); + BFApp.sApp.GetWorkspaceRectFrom((.)screenX, (.)screenY, 0, 0, out wsX, out wsY, out wsWidth, out wsHeight); float spaceLeft = (wsY + wsHeight) - (screenY); if (spaceLeft < minHeight) { @@ -299,7 +300,10 @@ namespace Beefy.widgets float screenWidth; float screenHeight; - CalcContainerSize(menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight); + CalcContainerSize(screenX, screenY, menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight); + + screenWidth = Math.Max(screenWidth, 32); + screenHeight = Math.Max(screenHeight, 32); WidgetWindow parentWindow = (relativeWidget != null) ? relativeWidget.mWidgetWindow : null; curWidgetWindow = new WidgetWindow(parentWindow, @@ -332,7 +336,7 @@ namespace Beefy.widgets float screenWidth; float screenHeight; - CalcContainerSize(menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight); + CalcContainerSize(x, y, menuContainer, allowScrollable, ref screenX, ref screenY, out screenWidth, out screenHeight); curWidgetWindow.Resize((int32)(screenX), (int32)(screenY), (int32)screenWidth, (int32)screenHeight); diff --git a/BeefySysLib/BFApp.h b/BeefySysLib/BFApp.h index 26a8536d..3728ed4c 100644 --- a/BeefySysLib/BFApp.h +++ b/BeefySysLib/BFApp.h @@ -88,6 +88,7 @@ public: virtual void SetCursor(int cursor); virtual void GetDesktopResolution(int& width, int& height) = 0; virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height) = 0; + virtual void GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) { GetWorkspaceRect(outX, outY, outWidth, outHeight); } virtual BFWindow* CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) = 0; virtual void RemoveWindow(BFWindow* window); diff --git a/BeefySysLib/BeefySysLib.cpp b/BeefySysLib/BeefySysLib.cpp index 328a2240..3e6bea08 100644 --- a/BeefySysLib/BeefySysLib.cpp +++ b/BeefySysLib/BeefySysLib.cpp @@ -79,6 +79,11 @@ BF_EXPORT void BF_CALLTYPE BFApp_GetWorkspaceRect(int& x, int& y, int& width, in gBFApp->GetWorkspaceRect(x, y, width, height); } +BF_EXPORT void BF_CALLTYPE BFApp_GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) +{ + gBFApp->GetWorkspaceRectFrom(fromX, fromY, fromWidth, fromHeight, outX, outY, outWidth, outHeight); +} + BF_EXPORT void BF_CALLTYPE BFApp_Create() { new PlatformBFApp(); diff --git a/BeefySysLib/platform/win/WinBFApp.cpp b/BeefySysLib/platform/win/WinBFApp.cpp index b1b4e2aa..ef600cc5 100644 --- a/BeefySysLib/platform/win/WinBFApp.cpp +++ b/BeefySysLib/platform/win/WinBFApp.cpp @@ -43,6 +43,38 @@ static BOOL CALLBACK BFEnumResNameProc( return FALSE; } +struct AdjustedMonRect +{ + int mMonCount; + int mX; + int mY; + int mWidth; + int mHeight; +}; + +static BOOL ClipToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg) +{ + AdjustedMonRect* outRect = (AdjustedMonRect*)userArg; + + MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + if (::GetMonitorInfo(mon, &monitorInfo) == 0) + return TRUE; + + outRect->mMonCount++; + + if (outRect->mX < monitorInfo.rcWork.left) + outRect->mX = monitorInfo.rcWork.left; + else if (outRect->mX + outRect->mWidth >= monitorInfo.rcWork.right) + outRect->mX = BF_MAX((int)monitorInfo.rcWork.left, monitorInfo.rcWork.right - outRect->mWidth); + + if (outRect->mY < monitorInfo.rcWork.top) + outRect->mY = monitorInfo.rcWork.top; + else if (outRect->mY + outRect->mHeight >= monitorInfo.rcWork.bottom) + outRect->mY = BF_MAX((int)monitorInfo.rcWork.top, monitorInfo.rcWork.bottom - outRect->mHeight); + + return TRUE; +} + WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) { HINSTANCE hInstance = GetModuleHandle(NULL); @@ -128,18 +160,16 @@ WinBFWindow::WinBFWindow(BFWindow* parent, const StringImpl& title, int x, int y if (windowFlags & BFWINDOW_POPUP_POSITION) { - RECT desktopRect; - ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL); + AdjustedMonRect adjustRect = { 0, x, y, width, height }; + RECT wantRect = { x, y, x + width, y + height }; - if (x < desktopRect.left) - x = desktopRect.left; - else if (x + width >= desktopRect.right) - x = BF_MAX((int)desktopRect.left, desktopRect.right - width); - - if (y < desktopRect.top) - y = desktopRect.top; - else if (y + height >= desktopRect.bottom) - y = BF_MAX((int)desktopRect.top, desktopRect.bottom - height); + EnumDisplayMonitors(NULL, &wantRect, ClipToMonitor, (LPARAM)&adjustRect); + if (adjustRect.mMonCount == 0) + EnumDisplayMonitors(NULL, NULL, ClipToMonitor, (LPARAM)&adjustRect); + x = adjustRect.mX; + y = adjustRect.mY; + width = adjustRect.mWidth; + height = adjustRect.mHeight; } mFlags = windowFlags; @@ -1128,26 +1158,70 @@ void WinBFApp::GetDesktopResolution(int& width, int& height) height = ::GetSystemMetrics(SM_CYSCREEN); } -void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height) +static BOOL InflateRectToMonitor(HMONITOR mon, HDC hdc, LPRECT monRect, LPARAM userArg) { - RECT desktopRect; + AdjustedMonRect* inflatedRect = (AdjustedMonRect*)userArg; - if (::GetSystemMetrics(SM_CMONITORS) > 1) + MONITORINFO monitorInfo = { sizeof(MONITORINFO) }; + if (::GetMonitorInfo(mon, &monitorInfo) == 0) + return TRUE; + + inflatedRect->mMonCount++; + if (inflatedRect->mMonCount == 1) { - desktopRect.left = ::GetSystemMetrics(SM_XVIRTUALSCREEN); - desktopRect.right = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); - desktopRect.top = ::GetSystemMetrics(SM_YVIRTUALSCREEN); - desktopRect.bottom = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); + inflatedRect->mX = monitorInfo.rcWork.left; + inflatedRect->mY = monitorInfo.rcWork.top; + inflatedRect->mWidth = monitorInfo.rcWork.right - monitorInfo.rcWork.left; + inflatedRect->mHeight = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; } else { - ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &desktopRect, NULL); + int minLeft = BF_MIN(inflatedRect->mX, monitorInfo.rcWork.left); + int minTop = BF_MIN(inflatedRect->mY, monitorInfo.rcWork.top); + int maxRight = BF_MAX(inflatedRect->mX + inflatedRect->mWidth, monitorInfo.rcWork.right); + int maxBottom = BF_MAX(inflatedRect->mY + inflatedRect->mHeight, monitorInfo.rcWork.bottom); + + inflatedRect->mX = minLeft; + inflatedRect->mY = minTop; + inflatedRect->mWidth = maxRight - minLeft; + inflatedRect->mHeight = maxBottom - minTop; } - x = desktopRect.left; - y = desktopRect.top; - width = desktopRect.right - desktopRect.left; - height = desktopRect.bottom - desktopRect.top; + return TRUE; +} + +void WinBFApp::GetWorkspaceRect(int& x, int& y, int& width, int& height) +{ + AdjustedMonRect inflateRect = { 0 }; + + EnumDisplayMonitors(NULL, NULL, InflateRectToMonitor, (LPARAM)&inflateRect); + x = inflateRect.mX; + y = inflateRect.mY; + width = inflateRect.mWidth; + height = inflateRect.mHeight; +} + +void WinBFApp::GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int & outX, int & outY, int & outWidth, int & outHeight) +{ + AdjustedMonRect inflateRect = { 0 }; + + RECT wantRect; + wantRect.left = fromX; + wantRect.top = fromY; + wantRect.right = fromX + BF_MAX(fromWidth, 1); + wantRect.bottom = fromY + BF_MAX(fromHeight, 1); + EnumDisplayMonitors(NULL, &wantRect, InflateRectToMonitor, (LPARAM)&inflateRect); + + if (inflateRect.mMonCount == 0) + { + GetWorkspaceRect(outX, outY, outWidth, outHeight); + return; + } + + outX = inflateRect.mX; + outY = inflateRect.mY; + outWidth = inflateRect.mWidth; + outHeight = inflateRect.mHeight; } BFWindow* WinBFApp::CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) diff --git a/BeefySysLib/platform/win/WinBFApp.h b/BeefySysLib/platform/win/WinBFApp.h index 71087a42..9cd8b3d5 100644 --- a/BeefySysLib/platform/win/WinBFApp.h +++ b/BeefySysLib/platform/win/WinBFApp.h @@ -105,8 +105,9 @@ public: virtual void Init() override; virtual void Run() override; - virtual void GetDesktopResolution(int& width, int& height); - virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height); + virtual void GetDesktopResolution(int& width, int& height) override; + virtual void GetWorkspaceRect(int& x, int& y, int& width, int& height) override; + virtual void GetWorkspaceRectFrom(int fromX, int fromY, int fromWidth, int fromHeight, int& outX, int& outY, int& outWidth, int& outHeight) override; virtual BFWindow* CreateNewWindow(BFWindow* parent, const StringImpl& title, int x, int y, int width, int height, int windowFlags) override; virtual DrawLayer* CreateDrawLayer(BFWindow* window); diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 1b6315f8..2db79030 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -10572,7 +10572,7 @@ namespace IDE // { BFWindow.Flags flags = .Border | .ThickFrame | .Resizable | .SysMenu | - .Caption | .Minimize | .Maximize | .QuitOnClose | .Menu; + .Caption | .Minimize | .Maximize | .QuitOnClose | .Menu | .PopupPosition; if (mRunningTestScript) flags |= .NoActivate;