Fix editor host resize and dock splitter behavior

This commit is contained in:
2026-04-14 03:34:31 +08:00
parent ba91e0f5dd
commit 72d09a1c49
10 changed files with 639 additions and 115 deletions

View File

@@ -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;
}