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,4 +1,5 @@
#include "Application.h"
#include "EditorResources.h"
#include <Host/WindowMessageDispatcher.h>
@@ -42,7 +43,7 @@ constexpr float kBaseDpiScale = 96.0f;
constexpr float kBorderlessTitleBarHeightDips = 28.0f;
constexpr float kBorderlessTitleBarFontSize = 12.0f;
constexpr DWORD kBorderlessWindowStyle =
WS_POPUP | WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
WS_POPUP | WS_THICKFRAME;
bool ResolveVerboseRuntimeTraceEnabled() {
wchar_t buffer[8] = {};
@@ -53,6 +54,64 @@ bool ResolveVerboseRuntimeTraceEnabled() {
return length > 0u && buffer[0] != L'0';
}
bool LoadEmbeddedPngBytes(
UINT resourceId,
const std::uint8_t*& outData,
std::size_t& outSize,
std::string& outError) {
outData = nullptr;
outSize = 0u;
outError.clear();
HMODULE module = GetModuleHandleW(nullptr);
if (module == nullptr) {
outError = "GetModuleHandleW(nullptr) returned null.";
return false;
}
HRSRC resource = FindResourceW(module, MAKEINTRESOURCEW(resourceId), L"PNG");
if (resource == nullptr) {
outError = "FindResourceW failed.";
return false;
}
HGLOBAL resourceData = LoadResource(module, resource);
if (resourceData == nullptr) {
outError = "LoadResource failed.";
return false;
}
const DWORD resourceSize = SizeofResource(module, resource);
if (resourceSize == 0u) {
outError = "SizeofResource returned zero.";
return false;
}
const void* lockedBytes = LockResource(resourceData);
if (lockedBytes == nullptr) {
outError = "LockResource failed.";
return false;
}
outData = reinterpret_cast<const std::uint8_t*>(lockedBytes);
outSize = static_cast<std::size_t>(resourceSize);
return true;
}
bool LoadEmbeddedPngTexture(
Host::NativeRenderer& renderer,
UINT resourceId,
::XCEngine::UI::UITextureHandle& outTexture,
std::string& outError) {
const std::uint8_t* bytes = nullptr;
std::size_t byteCount = 0u;
if (!LoadEmbeddedPngBytes(resourceId, bytes, byteCount, outError)) {
return false;
}
return renderer.LoadTextureFromMemory(bytes, byteCount, outTexture, outError);
}
UINT QuerySystemDpi() {
HDC screenDc = GetDC(nullptr);
if (screenDc == nullptr) {
@@ -415,6 +474,22 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
windowClass.lpfnWndProc = &Application::WndProc;
windowClass.hInstance = hInstance;
windowClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
windowClass.hIcon = static_cast<HICON>(
LoadImageW(
hInstance,
MAKEINTRESOURCEW(IDI_APP_ICON),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE));
windowClass.hIconSm = static_cast<HICON>(
LoadImageW(
hInstance,
MAKEINTRESOURCEW(IDI_APP_ICON_SMALL),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR));
windowClass.lpszClassName = kWindowClassName;
m_windowClassAtom = RegisterClassExW(&windowClass);
if (m_windowClassAtom == 0) {
@@ -439,6 +514,12 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
LogRuntimeTrace("app", "window creation failed");
return false;
}
if (windowClass.hIcon != nullptr) {
SendMessageW(m_hwnd, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(windowClass.hIcon));
}
if (windowClass.hIconSm != nullptr) {
SendMessageW(m_hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast<LPARAM>(windowClass.hIconSm));
}
Host::RefreshBorderlessWindowDwmDecorations(m_hwnd);
m_hostRuntime.Reset();
m_hostRuntime.SetWindowDpi(QueryWindowDpi(m_hwnd));
@@ -477,6 +558,10 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
m_editorWorkspace.AttachViewportWindowRenderer(m_windowRenderer);
m_editorWorkspace.SetViewportSurfacePresentationEnabled(
attachResult.hasViewportSurfacePresentation);
std::string titleBarLogoError = {};
if (!LoadEmbeddedPngTexture(m_renderer, IDR_PNG_LOGO_ICON, m_titleBarLogoIcon, titleBarLogoError)) {
LogRuntimeTrace("icons", "titlebar logo_icon.png: " + titleBarLogoError);
}
if (!m_editorWorkspace.GetBuiltInIconError().empty()) {
LogRuntimeTrace("icons", m_editorWorkspace.GetBuiltInIconError());
}
@@ -507,6 +592,7 @@ void Application::Shutdown() {
m_autoScreenshot.Shutdown();
m_editorWorkspace.Shutdown();
m_renderer.ReleaseTexture(m_titleBarLogoIcon);
m_windowRenderLoop.Detach();
m_windowRenderer.Shutdown();
m_renderer.Shutdown();
@@ -1114,23 +1200,36 @@ void Application::AppendBorderlessWindowChrome(
const Host::BorderlessWindowChromeLayout layout =
ResolveBorderlessWindowChromeLayout(clientWidthDips);
const float iconExtent = 16.0f;
const float iconInsetLeft = 8.0f;
const float iconTextGap = 8.0f;
const float iconX = layout.titleBarRect.x + iconInsetLeft;
const float iconY =
layout.titleBarRect.y +
(std::max)(0.0f, (layout.titleBarRect.height - iconExtent) * 0.5f);
drawList.AddFilledRect(
layout.titleBarRect,
UIColor(0.97f, 0.97f, 0.97f, 1.0f));
UIColor(0.10f, 0.10f, 0.10f, 1.0f));
drawList.AddLine(
UIPoint(layout.titleBarRect.x, layout.titleBarRect.y + layout.titleBarRect.height),
UIPoint(
layout.titleBarRect.x + layout.titleBarRect.width,
layout.titleBarRect.y + layout.titleBarRect.height),
UIColor(0.78f, 0.78f, 0.78f, 1.0f),
UIColor(0.14f, 0.14f, 0.14f, 1.0f),
1.0f);
if (m_titleBarLogoIcon.IsValid()) {
drawList.AddImage(
UIRect(iconX, iconY, iconExtent, iconExtent),
m_titleBarLogoIcon,
UIColor(1.0f, 1.0f, 1.0f, 1.0f));
}
drawList.AddText(
UIPoint(
12.0f,
iconX + (m_titleBarLogoIcon.IsValid() ? (iconExtent + iconTextGap) : 4.0f),
layout.titleBarRect.y +
(std::max)(0.0f, (layout.titleBarRect.height - kBorderlessTitleBarFontSize) * 0.5f - 1.0f)),
kWindowTitleText,
UIColor(0.12f, 0.12f, 0.12f, 1.0f),
UIColor(0.92f, 0.92f, 0.92f, 1.0f),
kBorderlessTitleBarFontSize);
Host::AppendBorderlessWindowChrome(
drawList,
@@ -1306,11 +1405,23 @@ std::string Application::DescribeInputEvents(
}
void Application::OnResize(UINT width, UINT height) {
bool matchesPredictedClientSize = false;
UINT predictedWidth = 0u;
UINT predictedHeight = 0u;
if (m_hostRuntime.TryGetPredictedClientPixelSize(predictedWidth, predictedHeight)) {
matchesPredictedClientSize =
predictedWidth == width &&
predictedHeight == height;
}
m_hostRuntime.ClearPredictedClientPixelSize();
if (IsBorderlessWindowEnabled() && m_hwnd != nullptr) {
Host::RefreshBorderlessWindowDwmDecorations(m_hwnd);
}
ApplyWindowResize(width, height);
if (!matchesPredictedClientSize) {
ApplyWindowResize(width, height);
}
}
void Application::OnEnterSizeMove() {