Refine new editor shell host and embedded icons
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user