Fix editor host resize and dock splitter behavior
This commit is contained in:
@@ -25,13 +25,14 @@ void AppendMinimizeGlyph(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const UIColor& color,
|
||||
float thickness,
|
||||
float insetX,
|
||||
float insetY) {
|
||||
const float y = rect.y + rect.height - insetY;
|
||||
float thickness) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float halfWidth = (std::max)(4.0f, rect.height * 0.22f);
|
||||
const float y = centerY + rect.height * 0.12f;
|
||||
drawList.AddLine(
|
||||
UIPoint(rect.x + insetX, y),
|
||||
UIPoint(rect.x + rect.width - insetX, y),
|
||||
UIPoint(centerX - halfWidth, y),
|
||||
UIPoint(centerX + halfWidth, y),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
@@ -40,15 +41,16 @@ void AppendMaximizeGlyph(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const UIColor& color,
|
||||
float thickness,
|
||||
float insetX,
|
||||
float insetY) {
|
||||
float thickness) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float halfExtent = (std::max)(4.0f, rect.height * 0.20f);
|
||||
drawList.AddRectOutline(
|
||||
UIRect(
|
||||
rect.x + insetX,
|
||||
rect.y + insetY,
|
||||
(std::max)(0.0f, rect.width - insetX * 2.0f),
|
||||
(std::max)(0.0f, rect.height - insetY * 2.0f)),
|
||||
centerX - halfExtent,
|
||||
centerY - halfExtent,
|
||||
halfExtent * 2.0f,
|
||||
halfExtent * 2.0f),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
@@ -57,26 +59,25 @@ void AppendRestoreGlyph(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const UIColor& color,
|
||||
float thickness,
|
||||
float insetX,
|
||||
float insetY) {
|
||||
const float width = (std::max)(0.0f, rect.width - insetX * 2.0f);
|
||||
const float height = (std::max)(0.0f, rect.height - insetY * 2.0f);
|
||||
const float offset = 3.0f;
|
||||
float thickness) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float halfExtent = (std::max)(4.0f, rect.height * 0.18f);
|
||||
const float offset = 2.0f;
|
||||
drawList.AddRectOutline(
|
||||
UIRect(
|
||||
rect.x + insetX + offset,
|
||||
rect.y + insetY,
|
||||
(std::max)(0.0f, width - offset),
|
||||
(std::max)(0.0f, height - offset)),
|
||||
centerX - halfExtent + offset,
|
||||
centerY - halfExtent - offset,
|
||||
halfExtent * 2.0f,
|
||||
halfExtent * 2.0f),
|
||||
color,
|
||||
thickness);
|
||||
drawList.AddRectOutline(
|
||||
UIRect(
|
||||
rect.x + insetX,
|
||||
rect.y + insetY + offset,
|
||||
(std::max)(0.0f, width - offset),
|
||||
(std::max)(0.0f, height - offset)),
|
||||
centerX - halfExtent - offset,
|
||||
centerY - halfExtent + offset,
|
||||
halfExtent * 2.0f,
|
||||
halfExtent * 2.0f),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
@@ -85,17 +86,19 @@ void AppendCloseGlyph(
|
||||
UIDrawList& drawList,
|
||||
const UIRect& rect,
|
||||
const UIColor& color,
|
||||
float thickness,
|
||||
float insetX,
|
||||
float insetY) {
|
||||
float thickness) {
|
||||
const float centerX = rect.x + rect.width * 0.5f;
|
||||
const float centerY = rect.y + rect.height * 0.5f;
|
||||
const float halfWidth = (std::max)(4.0f, rect.height * 0.20f);
|
||||
const float halfHeight = halfWidth;
|
||||
drawList.AddLine(
|
||||
UIPoint(rect.x + insetX, rect.y + insetY),
|
||||
UIPoint(rect.x + rect.width - insetX, rect.y + rect.height - insetY),
|
||||
UIPoint(centerX - halfWidth, centerY - halfHeight),
|
||||
UIPoint(centerX + halfWidth, centerY + halfHeight),
|
||||
color,
|
||||
thickness);
|
||||
drawList.AddLine(
|
||||
UIPoint(rect.x + rect.width - insetX, rect.y + insetY),
|
||||
UIPoint(rect.x + insetX, rect.y + rect.height - insetY),
|
||||
UIPoint(centerX + halfWidth, centerY - halfHeight),
|
||||
UIPoint(centerX - halfWidth, centerY + halfHeight),
|
||||
color,
|
||||
thickness);
|
||||
}
|
||||
@@ -152,6 +155,58 @@ int QuerySystemMetricForDpi(int index, UINT dpi) {
|
||||
return GetSystemMetrics(index);
|
||||
}
|
||||
|
||||
bool IsWindowAlignedToMonitorWorkArea(HWND hwnd) {
|
||||
if (hwnd == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT windowRect = {};
|
||||
if (!GetWindowRect(hwnd, &windowRect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (monitor == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MONITORINFO monitorInfo = {};
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (!GetMonitorInfoW(monitor, &monitorInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RECT& workArea = monitorInfo.rcWork;
|
||||
return windowRect.left == workArea.left &&
|
||||
windowRect.top == workArea.top &&
|
||||
windowRect.right == workArea.right &&
|
||||
windowRect.bottom == workArea.bottom;
|
||||
}
|
||||
|
||||
void ApplyDwmBoolWindowAttribute(HWND hwnd, DWORD attribute, BOOL value) {
|
||||
if (hwnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
using DwmSetWindowAttributeFn = HRESULT(WINAPI*)(HWND, DWORD, LPCVOID, DWORD);
|
||||
static const auto setWindowAttribute = []() -> DwmSetWindowAttributeFn {
|
||||
HMODULE dwmapi = GetModuleHandleW(L"dwmapi.dll");
|
||||
if (dwmapi == nullptr) {
|
||||
dwmapi = LoadLibraryW(L"dwmapi.dll");
|
||||
}
|
||||
if (dwmapi == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<DwmSetWindowAttributeFn>(
|
||||
GetProcAddress(dwmapi, "DwmSetWindowAttribute"));
|
||||
}();
|
||||
|
||||
if (setWindowAttribute != nullptr) {
|
||||
setWindowAttribute(hwnd, attribute, &value, sizeof(value));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BorderlessWindowChromeLayout BuildBorderlessWindowChromeLayout(
|
||||
@@ -232,9 +287,7 @@ void AppendBorderlessWindowChrome(
|
||||
drawList,
|
||||
button.rect,
|
||||
iconColor,
|
||||
metrics.iconThickness,
|
||||
metrics.iconInsetX,
|
||||
metrics.iconInsetY);
|
||||
metrics.iconThickness);
|
||||
break;
|
||||
case BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
|
||||
if (maximized) {
|
||||
@@ -242,17 +295,13 @@ void AppendBorderlessWindowChrome(
|
||||
drawList,
|
||||
button.rect,
|
||||
iconColor,
|
||||
metrics.iconThickness,
|
||||
metrics.iconInsetX,
|
||||
metrics.iconInsetY);
|
||||
metrics.iconThickness);
|
||||
} else {
|
||||
AppendMaximizeGlyph(
|
||||
drawList,
|
||||
button.rect,
|
||||
iconColor,
|
||||
metrics.iconThickness,
|
||||
metrics.iconInsetX,
|
||||
metrics.iconInsetY);
|
||||
metrics.iconThickness);
|
||||
}
|
||||
break;
|
||||
case BorderlessWindowChromeHitTarget::CloseButton:
|
||||
@@ -260,9 +309,7 @@ void AppendBorderlessWindowChrome(
|
||||
drawList,
|
||||
button.rect,
|
||||
iconColor,
|
||||
metrics.iconThickness,
|
||||
metrics.iconInsetX,
|
||||
metrics.iconInsetY);
|
||||
metrics.iconThickness);
|
||||
break;
|
||||
case BorderlessWindowChromeHitTarget::DragRegion:
|
||||
case BorderlessWindowChromeHitTarget::None:
|
||||
@@ -290,38 +337,66 @@ void EnableBorderlessWindowShadow(HWND hwnd) {
|
||||
GetProcAddress(dwmapi, "DwmExtendFrameIntoClientArea"));
|
||||
}();
|
||||
if (extendFrameIntoClientArea != nullptr) {
|
||||
const MARGINS margins = { 1, 1, 1, 1 };
|
||||
const bool maximized = IsZoomed(hwnd) || IsWindowAlignedToMonitorWorkArea(hwnd);
|
||||
const MARGINS margins = maximized
|
||||
? MARGINS{ 0, 0, 0, 0 }
|
||||
: MARGINS{ 1, 1, 1, 1 };
|
||||
extendFrameIntoClientArea(hwnd, &margins);
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshBorderlessWindowDwmDecorations(HWND hwnd) {
|
||||
if (hwnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Borderless host cannot participate in compositor-driven minimize/maximize
|
||||
// transitions without Windows stretching the last presented client frame.
|
||||
// Disable those transitions for this window, then refresh the shadow state.
|
||||
ApplyDwmBoolWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, TRUE);
|
||||
EnableBorderlessWindowShadow(hwnd);
|
||||
}
|
||||
|
||||
bool HandleBorderlessWindowGetMinMaxInfo(HWND hwnd, LPARAM lParam) {
|
||||
if (hwnd == nullptr || lParam == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* minMaxInfo = reinterpret_cast<MINMAXINFO*>(lParam);
|
||||
if (minMaxInfo == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (monitor == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MONITORINFO monitorInfo = {};
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (!GetMonitorInfoW(monitor, &monitorInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RECT& workArea = monitorInfo.rcWork;
|
||||
const RECT& monitorArea = monitorInfo.rcMonitor;
|
||||
minMaxInfo->ptMaxPosition.x = workArea.left - monitorArea.left;
|
||||
minMaxInfo->ptMaxPosition.y = workArea.top - monitorArea.top;
|
||||
minMaxInfo->ptMaxSize.x = workArea.right - workArea.left;
|
||||
minMaxInfo->ptMaxSize.y = workArea.bottom - workArea.top;
|
||||
minMaxInfo->ptMaxTrackSize = minMaxInfo->ptMaxSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
LRESULT HandleBorderlessWindowNcCalcSize(
|
||||
HWND hwnd,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam,
|
||||
UINT dpi) {
|
||||
if (wParam == FALSE || lParam == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
|
||||
if (params == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IsZoomed(hwnd)) {
|
||||
const int frameX =
|
||||
QuerySystemMetricForDpi(SM_CXFRAME, dpi) +
|
||||
QuerySystemMetricForDpi(SM_CXPADDEDBORDER, dpi);
|
||||
const int frameY =
|
||||
QuerySystemMetricForDpi(SM_CYFRAME, dpi) +
|
||||
QuerySystemMetricForDpi(SM_CXPADDEDBORDER, dpi);
|
||||
params->rgrc[0].left += frameX;
|
||||
params->rgrc[0].right -= frameX;
|
||||
params->rgrc[0].top += frameY;
|
||||
params->rgrc[0].bottom -= frameY;
|
||||
}
|
||||
|
||||
(void)hwnd;
|
||||
(void)wParam;
|
||||
(void)lParam;
|
||||
(void)dpi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user