Refine new editor shell host and embedded icons

This commit is contained in:
2026-04-14 14:41:45 +08:00
parent 4ee1bcc599
commit 91c62c6b14
27 changed files with 768 additions and 124 deletions

View File

@@ -1,6 +1,7 @@
#include "BorderlessWindowChrome.h"
#include <algorithm>
#include <cmath>
#include <dwmapi.h>
namespace XCEngine::UI::Editor::Host {
@@ -12,6 +13,12 @@ using ::XCEngine::UI::UIDrawList;
using ::XCEngine::UI::UIPoint;
using ::XCEngine::UI::UIRect;
constexpr UIColor kTransparentColor(0.0f, 0.0f, 0.0f, 0.0f);
float ResolveGlyphBoxSize(const UIRect& rect, float ratio, float minSize) {
return (std::max)(minSize, static_cast<float>(std::round(rect.height * ratio)));
}
bool IsPointInsideRect(const UIRect& rect, const UIPoint& point) {
return rect.width > 0.0f &&
rect.height > 0.0f &&
@@ -28,8 +35,8 @@ void AppendMinimizeGlyph(
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;
const float halfWidth = ResolveGlyphBoxSize(rect, 0.38f, 10.0f) * 0.5f;
const float y = centerY;
drawList.AddLine(
UIPoint(centerX - halfWidth, y),
UIPoint(centerX + halfWidth, y),
@@ -44,15 +51,16 @@ void AppendMaximizeGlyph(
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(
centerX - halfExtent,
centerY - halfExtent,
halfExtent * 2.0f,
halfExtent * 2.0f),
color,
thickness);
const float boxSize = ResolveGlyphBoxSize(rect, 0.32f, 9.0f);
const float halfExtent = boxSize * 0.5f;
const float left = centerX - halfExtent;
const float top = centerY - halfExtent;
const float right = left + boxSize;
const float bottom = top + boxSize;
drawList.AddLine(UIPoint(left, top), UIPoint(right, top), color, thickness);
drawList.AddLine(UIPoint(left, top), UIPoint(left, bottom), color, thickness);
drawList.AddLine(UIPoint(right, top), UIPoint(right, bottom), color, thickness);
drawList.AddLine(UIPoint(left, bottom), UIPoint(right, bottom), color, thickness);
}
void AppendRestoreGlyph(
@@ -62,24 +70,30 @@ void AppendRestoreGlyph(
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(
centerX - halfExtent + offset,
centerY - halfExtent - offset,
halfExtent * 2.0f,
halfExtent * 2.0f),
color,
thickness);
drawList.AddRectOutline(
UIRect(
centerX - halfExtent - offset,
centerY - halfExtent + offset,
halfExtent * 2.0f,
halfExtent * 2.0f),
color,
thickness);
const float boxSize = ResolveGlyphBoxSize(rect, 0.29f, 8.0f);
const float halfExtent = boxSize * 0.5f;
const float offset = 1.0f;
const float backLeft = centerX - halfExtent + offset;
const float backTop = centerY - halfExtent - offset;
const float backRight = backLeft + boxSize;
const float backBottom = backTop + boxSize;
const float frontLeft = centerX - halfExtent - offset;
const float frontTop = centerY - halfExtent + offset;
const float frontRight = frontLeft + boxSize;
const float frontBottom = frontTop + boxSize;
// Only draw the exposed segments of the back window.
drawList.AddLine(UIPoint(backLeft, backTop), UIPoint(backRight, backTop), color, thickness);
drawList.AddLine(UIPoint(backLeft, backTop), UIPoint(backLeft, frontTop), color, thickness);
drawList.AddLine(UIPoint(backRight, backTop), UIPoint(backRight, backBottom), color, thickness);
drawList.AddLine(UIPoint(frontRight, backBottom), UIPoint(backRight, backBottom), color, thickness);
drawList.AddLine(UIPoint(frontLeft, frontTop), UIPoint(frontRight, frontTop), color, thickness);
drawList.AddLine(UIPoint(frontLeft, frontTop), UIPoint(frontLeft, frontBottom), color, thickness);
drawList.AddLine(UIPoint(frontRight, frontTop), UIPoint(frontRight, frontBottom), color, thickness);
drawList.AddLine(UIPoint(frontLeft, frontBottom), UIPoint(frontRight, frontBottom), color, thickness);
}
void AppendCloseGlyph(
@@ -89,7 +103,7 @@ void AppendCloseGlyph(
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 halfWidth = ResolveGlyphBoxSize(rect, 0.29f, 8.0f) * 0.5f;
const float halfHeight = halfWidth;
drawList.AddLine(
UIPoint(centerX - halfWidth, centerY - halfHeight),
@@ -116,7 +130,7 @@ void AppendCloseGlyph(
if (hovered) {
return palette.closeButtonHoverColor;
}
return {};
return kTransparentColor;
}
if (pressed) {
@@ -125,7 +139,7 @@ void AppendCloseGlyph(
if (hovered) {
return palette.buttonHoverColor;
}
return {};
return kTransparentColor;
}
::XCEngine::UI::UIColor ResolveIconColor(
@@ -207,6 +221,54 @@ void ApplyDwmBoolWindowAttribute(HWND hwnd, DWORD attribute, BOOL value) {
}
}
void ApplyDwmColorWindowAttribute(HWND hwnd, DWORD attribute, COLORREF 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));
}
}
void ApplyDwmIntWindowAttribute(HWND hwnd, DWORD attribute, int 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(
@@ -353,7 +415,13 @@ void RefreshBorderlessWindowDwmDecorations(HWND hwnd) {
// 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.
ApplyDwmIntWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, DWMNCRP_DISABLED);
ApplyDwmBoolWindowAttribute(hwnd, DWMWA_ALLOW_NCPAINT, FALSE);
ApplyDwmBoolWindowAttribute(hwnd, DWMWA_TRANSITIONS_FORCEDISABLED, TRUE);
ApplyDwmBoolWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, TRUE);
ApplyDwmColorWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, RGB(26, 26, 26));
ApplyDwmColorWindowAttribute(hwnd, DWMWA_TEXT_COLOR, RGB(235, 235, 235));
ApplyDwmColorWindowAttribute(hwnd, DWMWA_BORDER_COLOR, RGB(26, 26, 26));
EnableBorderlessWindowShadow(hwnd);
}