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

@@ -158,6 +158,7 @@ target_link_libraries(XCUIEditorHost PUBLIC
if(XCENGINE_BUILD_XCUI_EDITOR_APP)
add_executable(XCUIEditorApp WIN32
app/EditorApp.rc
app/main.cpp
app/Application.cpp
app/Commands/ProductEditorHostCommandBridge.cpp

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() {

View File

@@ -130,6 +130,7 @@ private:
std::vector<::XCEngine::UI::UIInputEvent> m_pendingInputEvents = {};
bool m_trackingMouseLeave = false;
bool m_renderReady = false;
::XCEngine::UI::UITextureHandle m_titleBarLogoIcon = {};
::XCEngine::UI::Editor::Host::BorderlessWindowChromeState m_borderlessWindowChromeState = {};
::XCEngine::UI::Editor::Host::HostRuntimeState m_hostRuntime = {};
};

View File

@@ -0,0 +1,9 @@
#include "EditorResources.h"
IDI_APP_ICON ICON "../resources/Icons/logo.ico"
IDI_APP_ICON_SMALL ICON "../resources/Icons/logo_icon.ico"
IDR_PNG_FOLDER_ICON PNG "../resources/Icons/folder_icon.png"
IDR_PNG_GAMEOBJECT_ICON PNG "../resources/Icons/gameobject_icon.png"
IDR_PNG_SCENE_ICON PNG "../resources/Icons/scene_icon.png"
IDR_PNG_LOGO PNG "../resources/Icons/logo.png"
IDR_PNG_LOGO_ICON PNG "../resources/Icons/logo_icon.png"

View File

@@ -0,0 +1,9 @@
#pragma once
#define IDI_APP_ICON 101
#define IDI_APP_ICON_SMALL 102
#define IDR_PNG_FOLDER_ICON 201
#define IDR_PNG_GAMEOBJECT_ICON 202
#define IDR_PNG_SCENE_ICON 203
#define IDR_PNG_LOGO 204
#define IDR_PNG_LOGO_ICON 205

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

View File

@@ -28,15 +28,15 @@ struct BorderlessWindowChromeMetrics {
struct BorderlessWindowChromePalette {
::XCEngine::UI::UIColor buttonHoverColor =
::XCEngine::UI::UIColor(0.88f, 0.88f, 0.88f, 1.0f);
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
::XCEngine::UI::UIColor buttonPressedColor =
::XCEngine::UI::UIColor(0.78f, 0.78f, 0.78f, 1.0f);
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
::XCEngine::UI::UIColor closeButtonHoverColor =
::XCEngine::UI::UIColor(0.91f, 0.31f, 0.24f, 1.0f);
::XCEngine::UI::UIColor closeButtonPressedColor =
::XCEngine::UI::UIColor(0.78f, 0.22f, 0.18f, 1.0f);
::XCEngine::UI::UIColor iconColor =
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
::XCEngine::UI::UIColor closeIconHoverColor =
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
};

View File

@@ -4,6 +4,7 @@
#include <array>
#include <cmath>
#include <filesystem>
#include <limits>
#include <memory>
namespace XCEngine::UI::Editor::Host {
@@ -380,6 +381,29 @@ bool NativeRenderer::LoadTextureFromFile(
return true;
}
bool NativeRenderer::LoadTextureFromMemory(
const std::uint8_t* data,
std::size_t size,
::XCEngine::UI::UITextureHandle& outTexture,
std::string& outError) {
outError.clear();
ReleaseTexture(outTexture);
auto texture = std::make_unique<NativeTextureResource>();
if (!DecodeTextureMemory(data, size, *texture, outError)) {
outTexture = {};
return false;
}
outTexture.nativeHandle = reinterpret_cast<std::uintptr_t>(texture.get());
outTexture.width = texture->width;
outTexture.height = texture->height;
outTexture.kind = ::XCEngine::UI::UITextureHandleKind::DescriptorHandle;
m_liveTextures.insert(texture.get());
texture.release();
return true;
}
void NativeRenderer::ReleaseTexture(::XCEngine::UI::UITextureHandle& texture) {
if (!texture.IsValid()) {
texture = {};
@@ -742,15 +766,80 @@ bool NativeRenderer::DecodeTextureFile(
return false;
}
return DecodeTextureFrame(*frame.Get(), outTexture, outError);
}
bool NativeRenderer::DecodeTextureMemory(
const std::uint8_t* data,
std::size_t size,
NativeTextureResource& outTexture,
std::string& outError) {
outError.clear();
if (data == nullptr || size == 0u) {
outError = "DecodeTextureMemory rejected an empty image payload.";
return false;
}
if (size > static_cast<std::size_t>((std::numeric_limits<DWORD>::max)())) {
outError = "DecodeTextureMemory payload exceeds WIC stream limits.";
return false;
}
if (!EnsureWicFactory(outError)) {
return false;
}
Microsoft::WRL::ComPtr<IWICStream> stream;
HRESULT hr = m_wicFactory->CreateStream(stream.ReleaseAndGetAddressOf());
if (FAILED(hr) || !stream) {
outError = HrToString("IWICImagingFactory::CreateStream", hr);
return false;
}
hr = stream->InitializeFromMemory(
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(data)),
static_cast<DWORD>(size));
if (FAILED(hr)) {
outError = HrToString("IWICStream::InitializeFromMemory", hr);
return false;
}
Microsoft::WRL::ComPtr<IWICBitmapDecoder> decoder;
hr = m_wicFactory->CreateDecoderFromStream(
stream.Get(),
nullptr,
WICDecodeMetadataCacheOnLoad,
decoder.ReleaseAndGetAddressOf());
if (FAILED(hr) || !decoder) {
outError = HrToString("IWICImagingFactory::CreateDecoderFromStream", hr);
return false;
}
Microsoft::WRL::ComPtr<IWICBitmapFrameDecode> frame;
hr = decoder->GetFrame(0u, frame.ReleaseAndGetAddressOf());
if (FAILED(hr) || !frame) {
outError = HrToString("IWICBitmapDecoder::GetFrame", hr);
return false;
}
return DecodeTextureFrame(*frame.Get(), outTexture, outError);
}
bool NativeRenderer::DecodeTextureFrame(
IWICBitmapSource& source,
NativeTextureResource& outTexture,
std::string& outError) {
outError.clear();
Microsoft::WRL::ComPtr<IWICFormatConverter> converter;
hr = m_wicFactory->CreateFormatConverter(converter.ReleaseAndGetAddressOf());
HRESULT hr = m_wicFactory->CreateFormatConverter(converter.ReleaseAndGetAddressOf());
if (FAILED(hr) || !converter) {
outError = HrToString("IWICImagingFactory::CreateFormatConverter", hr);
return false;
}
hr = converter->Initialize(
frame.Get(),
&source,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
nullptr,

View File

@@ -48,6 +48,11 @@ public:
const std::filesystem::path& path,
::XCEngine::UI::UITextureHandle& outTexture,
std::string& outError);
bool LoadTextureFromMemory(
const std::uint8_t* data,
std::size_t size,
::XCEngine::UI::UITextureHandle& outTexture,
std::string& outError);
void ReleaseTexture(::XCEngine::UI::UITextureHandle& texture);
float MeasureTextWidth(
const ::XCEngine::UI::Editor::UIEditorTextMeasureRequest& request) const override;
@@ -82,6 +87,15 @@ private:
const std::filesystem::path& path,
NativeTextureResource& outTexture,
std::string& outError);
bool DecodeTextureMemory(
const std::uint8_t* data,
std::size_t size,
NativeTextureResource& outTexture,
std::string& outError);
bool DecodeTextureFrame(
IWICBitmapSource& source,
NativeTextureResource& outTexture,
std::string& outError);
bool ResolveTextureBitmap(
ID2D1RenderTarget& renderTarget,
NativeTextureResource& texture,

View File

@@ -4,6 +4,13 @@
namespace XCEngine::UI::Editor::Host {
namespace {
constexpr UINT kMessageNcUaDrawCaption = 0x00AEu;
constexpr UINT kMessageNcUaDrawFrame = 0x00AFu;
} // namespace
void TryEnableNonClientDpiScaling(HWND hwnd) {
if (hwnd == nullptr) {
return;
@@ -82,6 +89,20 @@ bool WindowMessageDispatcher::TryDispatch(
return true;
}
return false;
case WM_NCHITTEST:
if (application.IsBorderlessWindowEnabled()) {
outResult = HTCLIENT;
return true;
}
return false;
case WM_NCPAINT:
case kMessageNcUaDrawCaption:
case kMessageNcUaDrawFrame:
if (application.IsBorderlessWindowEnabled()) {
outResult = 0;
return true;
}
return false;
case WM_SYSCOMMAND:
if (application.HandleBorderlessWindowSystemCommand(wParam)) {
outResult = 0;

View File

@@ -1,4 +1,5 @@
#include "ProductBuiltInIcons.h"
#include "EditorResources.h"
#include <sstream>
@@ -20,31 +21,96 @@ void AppendLoadError(
stream << label << ": " << error;
}
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;
}
void LoadEmbeddedPngTexture(
Host::NativeRenderer& renderer,
UINT resourceId,
std::string_view label,
::XCEngine::UI::UITextureHandle& outTexture,
std::ostringstream& errorStream) {
const std::uint8_t* bytes = nullptr;
std::size_t byteCount = 0u;
std::string error = {};
if (!LoadEmbeddedPngBytes(resourceId, bytes, byteCount, error)) {
AppendLoadError(errorStream, label, error);
return;
}
error.clear();
if (!renderer.LoadTextureFromMemory(bytes, byteCount, outTexture, error)) {
AppendLoadError(errorStream, label, error);
}
}
} // namespace
void ProductBuiltInIcons::Initialize(
Host::NativeRenderer& renderer,
const std::filesystem::path& repoRoot) {
void ProductBuiltInIcons::Initialize(Host::NativeRenderer& renderer) {
Shutdown();
m_renderer = &renderer;
m_repoRoot = repoRoot.lexically_normal();
std::ostringstream errorStream = {};
std::string error = {};
if (!m_renderer->LoadTextureFromFile(ResolveFolderIconPath(), m_folderIcon, error)) {
AppendLoadError(errorStream, "folder_icon.png", error);
}
error.clear();
if (!m_renderer->LoadTextureFromFile(ResolveGameObjectIconPath(), m_gameObjectIcon, error)) {
AppendLoadError(errorStream, "gameobject_icon.png", error);
}
error.clear();
if (!m_renderer->LoadTextureFromFile(ResolveSceneIconPath(), m_sceneIcon, error)) {
AppendLoadError(errorStream, "scene_icon.png", error);
}
LoadEmbeddedPngTexture(
renderer,
IDR_PNG_FOLDER_ICON,
"folder_icon.png",
m_folderIcon,
errorStream);
LoadEmbeddedPngTexture(
renderer,
IDR_PNG_GAMEOBJECT_ICON,
"gameobject_icon.png",
m_gameObjectIcon,
errorStream);
LoadEmbeddedPngTexture(
renderer,
IDR_PNG_SCENE_ICON,
"scene_icon.png",
m_sceneIcon,
errorStream);
m_lastError = errorStream.str();
}
@@ -57,7 +123,6 @@ void ProductBuiltInIcons::Shutdown() {
}
m_renderer = nullptr;
m_repoRoot.clear();
m_lastError.clear();
}
@@ -79,16 +144,4 @@ const std::string& ProductBuiltInIcons::GetLastError() const {
return m_lastError;
}
std::filesystem::path ProductBuiltInIcons::ResolveFolderIconPath() const {
return (m_repoRoot / "editor/resources/Icons/folder_icon.png").lexically_normal();
}
std::filesystem::path ProductBuiltInIcons::ResolveGameObjectIconPath() const {
return (m_repoRoot / "editor/resources/Icons/gameobject_icon.png").lexically_normal();
}
std::filesystem::path ProductBuiltInIcons::ResolveSceneIconPath() const {
return (m_repoRoot / "editor/resources/Icons/scene_icon.png").lexically_normal();
}
} // namespace XCEngine::UI::Editor::App

View File

@@ -5,7 +5,6 @@
#include <XCEngine/UI/Types.h>
#include <cstdint>
#include <filesystem>
#include <string>
namespace XCEngine::UI::Editor::App {
@@ -18,21 +17,14 @@ enum class ProductBuiltInIconKind : std::uint8_t {
class ProductBuiltInIcons {
public:
void Initialize(
Host::NativeRenderer& renderer,
const std::filesystem::path& repoRoot);
void Initialize(Host::NativeRenderer& renderer);
void Shutdown();
const ::XCEngine::UI::UITextureHandle& Resolve(ProductBuiltInIconKind kind) const;
const std::string& GetLastError() const;
private:
std::filesystem::path ResolveFolderIconPath() const;
std::filesystem::path ResolveGameObjectIconPath() const;
std::filesystem::path ResolveSceneIconPath() const;
Host::NativeRenderer* m_renderer = nullptr;
std::filesystem::path m_repoRoot = {};
::XCEngine::UI::UITextureHandle m_folderIcon = {};
::XCEngine::UI::UITextureHandle m_gameObjectIcon = {};
::XCEngine::UI::UITextureHandle m_sceneIcon = {};

View File

@@ -19,9 +19,9 @@ constexpr float kPadding = 8.0f;
constexpr float kLineHeight = 18.0f;
constexpr float kFontSize = 11.0f;
constexpr UIColor kSurfaceColor(0.205f, 0.205f, 0.205f, 1.0f);
constexpr UIColor kTextColor(0.840f, 0.840f, 0.840f, 1.0f);
constexpr UIColor kChannelColor(0.640f, 0.640f, 0.640f, 1.0f);
constexpr UIColor kSurfaceColor(0.10f, 0.10f, 0.10f, 1.0f);
constexpr UIColor kTextColor(0.860f, 0.860f, 0.860f, 1.0f);
constexpr UIColor kChannelColor(0.660f, 0.660f, 0.660f, 1.0f);
constexpr UIColor kEmptyColor(0.580f, 0.580f, 0.580f, 1.0f);
float ResolveTextTop(float rectY, float rectHeight, float fontSize) {

View File

@@ -24,13 +24,13 @@ constexpr float kSubtitleFontSize = 11.0f;
constexpr float kSectionTitleFontSize = 11.0f;
constexpr float kRowFontSize = 11.0f;
constexpr UIColor kSurfaceColor(0.205f, 0.205f, 0.205f, 1.0f);
constexpr UIColor kSectionHeaderColor(0.225f, 0.225f, 0.225f, 1.0f);
constexpr UIColor kSectionBodyColor(0.215f, 0.215f, 0.215f, 1.0f);
constexpr UIColor kTitleColor(0.910f, 0.910f, 0.910f, 1.0f);
constexpr UIColor kSubtitleColor(0.650f, 0.650f, 0.650f, 1.0f);
constexpr UIColor kLabelColor(0.700f, 0.700f, 0.700f, 1.0f);
constexpr UIColor kValueColor(0.860f, 0.860f, 0.860f, 1.0f);
constexpr UIColor kSurfaceColor(0.10f, 0.10f, 0.10f, 1.0f);
constexpr UIColor kSectionHeaderColor(0.12f, 0.12f, 0.12f, 1.0f);
constexpr UIColor kSectionBodyColor(0.11f, 0.11f, 0.11f, 1.0f);
constexpr UIColor kTitleColor(0.930f, 0.930f, 0.930f, 1.0f);
constexpr UIColor kSubtitleColor(0.640f, 0.640f, 0.640f, 1.0f);
constexpr UIColor kLabelColor(0.720f, 0.720f, 0.720f, 1.0f);
constexpr UIColor kValueColor(0.880f, 0.880f, 0.880f, 1.0f);
float ResolveTextTop(float rectY, float rectHeight, float fontSize) {
const float lineHeight = fontSize * 1.6f;

View File

@@ -52,17 +52,17 @@ constexpr float kGridPreviewHeight = 54.0f;
constexpr float kHeaderFontSize = 12.0f;
constexpr float kTileLabelFontSize = 11.0f;
constexpr UIColor kSurfaceColor(0.200f, 0.200f, 0.200f, 1.0f);
constexpr UIColor kPaneColor(0.205f, 0.205f, 0.205f, 1.0f);
constexpr UIColor kHeaderColor(0.215f, 0.215f, 0.215f, 1.0f);
constexpr UIColor kTextPrimary(0.830f, 0.830f, 0.830f, 1.0f);
constexpr UIColor kTextStrong(0.910f, 0.910f, 0.910f, 1.0f);
constexpr UIColor kTextMuted(0.560f, 0.560f, 0.560f, 1.0f);
constexpr UIColor kTileHoverColor(0.245f, 0.245f, 0.245f, 1.0f);
constexpr UIColor kTileSelectedColor(0.300f, 0.300f, 0.300f, 1.0f);
constexpr UIColor kTilePreviewFillColor(0.700f, 0.700f, 0.700f, 1.0f);
constexpr UIColor kTilePreviewShadeColor(0.610f, 0.610f, 0.610f, 1.0f);
constexpr UIColor kTilePreviewOutlineColor(0.860f, 0.860f, 0.860f, 0.35f);
constexpr UIColor kSurfaceColor(0.10f, 0.10f, 0.10f, 1.0f);
constexpr UIColor kPaneColor(0.11f, 0.11f, 0.11f, 1.0f);
constexpr UIColor kHeaderColor(0.12f, 0.12f, 0.12f, 1.0f);
constexpr UIColor kTextPrimary(0.840f, 0.840f, 0.840f, 1.0f);
constexpr UIColor kTextStrong(0.930f, 0.930f, 0.930f, 1.0f);
constexpr UIColor kTextMuted(0.580f, 0.580f, 0.580f, 1.0f);
constexpr UIColor kTileHoverColor(0.14f, 0.14f, 0.14f, 1.0f);
constexpr UIColor kTileSelectedColor(0.17f, 0.17f, 0.17f, 1.0f);
constexpr UIColor kTilePreviewFillColor(0.20f, 0.20f, 0.20f, 1.0f);
constexpr UIColor kTilePreviewShadeColor(0.15f, 0.15f, 0.15f, 1.0f);
constexpr UIColor kTilePreviewOutlineColor(0.920f, 0.920f, 0.920f, 0.25f);
bool ContainsPoint(const UIRect& rect, const UIPoint& point) {
return point.x >= rect.x &&

View File

@@ -4,11 +4,11 @@
namespace XCEngine::UI::Editor::App {
inline constexpr ::XCEngine::UI::UIColor kProductTreeSurfaceColor(0.205f, 0.205f, 0.205f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeHoverColor(0.245f, 0.245f, 0.245f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeSelectedColor(0.300f, 0.300f, 0.300f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeDisclosureColor(0.560f, 0.560f, 0.560f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeTextColor(0.830f, 0.830f, 0.830f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeSurfaceColor(0.10f, 0.10f, 0.10f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeHoverColor(0.13f, 0.13f, 0.13f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeSelectedColor(0.16f, 0.16f, 0.16f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeDisclosureColor(0.620f, 0.620f, 0.620f, 1.0f);
inline constexpr ::XCEngine::UI::UIColor kProductTreeTextColor(0.900f, 0.900f, 0.900f, 1.0f);
inline Widgets::UIEditorTreeViewMetrics BuildProductTreeViewMetrics() {
Widgets::UIEditorTreeViewMetrics metrics = {};

View File

@@ -220,7 +220,7 @@ std::vector<UIInputEvent> FilterHostedContentInputEventsForShellOwnership(
void ProductEditorWorkspace::Initialize(
const std::filesystem::path& repoRoot,
Host::NativeRenderer& renderer) {
m_builtInIcons.Initialize(renderer, repoRoot);
m_builtInIcons.Initialize(renderer);
m_hierarchyPanel.SetBuiltInIcons(&m_builtInIcons);
m_projectPanel.SetBuiltInIcons(&m_builtInIcons);
m_projectPanel.SetTextMeasurer(&renderer);

View File

@@ -30,7 +30,7 @@ struct UIEditorMenuBarMetrics {
float horizontalInset = 0.0f;
float verticalInset = 2.0f;
float buttonGap = 1.0f;
float buttonPaddingX = 4.0f;
float buttonPaddingX = 7.0f;
float labelFontSize = 13.0f;
float estimatedGlyphWidth = 6.5f;
float labelInsetY = -1.5f;

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

View File

@@ -4,12 +4,208 @@ namespace XCEngine::UI::Editor {
namespace {
using ::XCEngine::UI::UIColor;
template <typename TValue>
const TValue& GetDefaultValue() {
static const TValue value = {};
return value;
}
Widgets::UIEditorMenuBarPalette BuildMenuBarPalette() {
Widgets::UIEditorMenuBarPalette palette = {};
palette.barColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.buttonColor = UIColor(0.0f, 0.0f, 0.0f, 0.0f);
palette.buttonHoveredColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.buttonOpenColor = UIColor(0.17f, 0.17f, 0.17f, 1.0f);
palette.borderColor = UIColor(0.0f, 0.0f, 0.0f, 0.0f);
palette.focusedBorderColor = UIColor(0.0f, 0.0f, 0.0f, 0.0f);
palette.openBorderColor = UIColor(0.0f, 0.0f, 0.0f, 0.0f);
palette.textPrimary = UIColor(0.93f, 0.93f, 0.93f, 1.0f);
palette.textMuted = UIColor(0.72f, 0.72f, 0.72f, 1.0f);
palette.textDisabled = UIColor(0.45f, 0.45f, 0.45f, 1.0f);
return palette;
}
Widgets::UIEditorMenuPopupPalette BuildMenuPopupPalette() {
Widgets::UIEditorMenuPopupPalette palette = {};
palette.popupColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.itemHoverColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.itemOpenColor = UIColor(0.17f, 0.17f, 0.17f, 1.0f);
palette.separatorColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.textPrimary = UIColor(0.93f, 0.93f, 0.93f, 1.0f);
palette.textMuted = UIColor(0.68f, 0.68f, 0.68f, 1.0f);
palette.textDisabled = UIColor(0.45f, 0.45f, 0.45f, 1.0f);
palette.glyphColor = UIColor(0.90f, 0.90f, 0.90f, 1.0f);
return palette;
}
Widgets::UIEditorListViewPalette BuildListViewPalette() {
Widgets::UIEditorListViewPalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.rowHoverColor = UIColor(0.13f, 0.13f, 0.13f, 1.0f);
palette.rowSelectedColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.rowSelectedFocusedColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.primaryTextColor = UIColor(0.93f, 0.93f, 0.93f, 1.0f);
palette.secondaryTextColor = UIColor(0.67f, 0.67f, 0.67f, 1.0f);
return palette;
}
Widgets::UIEditorTreeViewPalette BuildTreeViewPalette() {
Widgets::UIEditorTreeViewPalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.rowHoverColor = UIColor(0.13f, 0.13f, 0.13f, 1.0f);
palette.rowSelectedColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.rowSelectedFocusedColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.disclosureColor = UIColor(0.62f, 0.62f, 0.62f, 1.0f);
palette.textColor = UIColor(0.92f, 0.92f, 0.92f, 1.0f);
return palette;
}
Widgets::UIEditorScrollViewPalette BuildScrollViewPalette() {
Widgets::UIEditorScrollViewPalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.scrollbarTrackColor = UIColor(0.08f, 0.08f, 0.08f, 1.0f);
palette.scrollbarThumbColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.scrollbarThumbHoverColor = UIColor(0.17f, 0.17f, 0.17f, 1.0f);
palette.scrollbarThumbActiveColor = UIColor(0.20f, 0.20f, 0.20f, 1.0f);
return palette;
}
Widgets::UIEditorTabStripPalette BuildTabStripPalette() {
Widgets::UIEditorTabStripPalette palette = {};
palette.stripBackgroundColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.headerBackgroundColor = UIColor(0.11f, 0.11f, 0.11f, 1.0f);
palette.contentBackgroundColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.stripBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.headerContentSeparatorColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.tabColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.tabHoveredColor = UIColor(0.15f, 0.15f, 0.15f, 1.0f);
palette.tabSelectedColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.tabBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.tabHoveredBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.tabSelectedBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.textPrimary = UIColor(0.92f, 0.92f, 0.92f, 1.0f);
palette.textSecondary = UIColor(0.72f, 0.72f, 0.72f, 1.0f);
palette.textMuted = UIColor(0.58f, 0.58f, 0.58f, 1.0f);
palette.closeButtonColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.closeButtonHoveredColor = UIColor(0.15f, 0.15f, 0.15f, 1.0f);
palette.closeButtonBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.closeGlyphColor = UIColor(0.85f, 0.85f, 0.85f, 1.0f);
palette.reorderPreviewColor = UIColor(0.92f, 0.92f, 0.92f, 0.90f);
return palette;
}
Widgets::UIEditorStatusBarPalette BuildStatusBarPalette() {
Widgets::UIEditorStatusBarPalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.segmentColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.segmentHoveredColor = UIColor(0.15f, 0.15f, 0.15f, 1.0f);
palette.segmentActiveColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.segmentBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.separatorColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.textPrimary = UIColor(0.90f, 0.90f, 0.90f, 1.0f);
palette.textMuted = UIColor(0.64f, 0.64f, 0.64f, 1.0f);
palette.textAccent = UIColor(0.94f, 0.94f, 0.94f, 1.0f);
return palette;
}
Widgets::UIEditorPanelFramePalette BuildPanelFramePalette() {
Widgets::UIEditorPanelFramePalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.headerColor = UIColor(0.11f, 0.11f, 0.11f, 1.0f);
palette.footerColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.hoveredBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.activeBorderColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.focusedBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.textPrimary = UIColor(0.92f, 0.92f, 0.92f, 1.0f);
palette.textSecondary = UIColor(0.68f, 0.68f, 0.68f, 1.0f);
palette.textMuted = UIColor(0.58f, 0.58f, 0.58f, 1.0f);
palette.actionButtonColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.actionButtonHoveredColor = UIColor(0.15f, 0.15f, 0.15f, 1.0f);
palette.actionButtonSelectedColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.actionButtonBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.actionGlyphColor = UIColor(0.84f, 0.84f, 0.84f, 1.0f);
return palette;
}
Widgets::UIEditorDockHostPalette BuildDockHostPalette() {
Widgets::UIEditorDockHostPalette palette = {};
palette.tabStripPalette = BuildTabStripPalette();
palette.panelFramePalette = BuildPanelFramePalette();
palette.splitterColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.splitterHoveredColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.splitterActiveColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.placeholderTitleColor = UIColor(0.92f, 0.92f, 0.92f, 1.0f);
palette.placeholderTextColor = UIColor(0.70f, 0.70f, 0.70f, 1.0f);
palette.placeholderMutedColor = UIColor(0.58f, 0.58f, 0.58f, 1.0f);
palette.dropPreviewFillColor = UIColor(0.92f, 0.92f, 0.92f, 0.08f);
palette.dropPreviewBorderColor = UIColor(0.96f, 0.96f, 0.96f, 0.70f);
return palette;
}
Widgets::UIEditorViewportSlotPalette BuildViewportSlotPalette() {
Widgets::UIEditorViewportSlotPalette palette = {};
palette.frameColor = UIColor(0.09f, 0.09f, 0.09f, 1.0f);
palette.topBarColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.surfaceColor = UIColor(0.08f, 0.08f, 0.08f, 1.0f);
palette.surfaceHoverOverlayColor = UIColor(0.18f, 0.18f, 0.18f, 0.12f);
palette.surfaceActiveOverlayColor = UIColor(0.22f, 0.22f, 0.22f, 0.10f);
palette.captureOverlayColor = UIColor(0.92f, 0.92f, 0.92f, 0.06f);
palette.borderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.focusedBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.surfaceBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.surfaceHoveredBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.surfaceActiveBorderColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.surfaceCapturedBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.toolColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.toolHoveredColor = UIColor(0.15f, 0.15f, 0.15f, 1.0f);
palette.toolSelectedColor = UIColor(0.18f, 0.18f, 0.18f, 1.0f);
palette.toolDisabledColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.toolBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.textPrimary = UIColor(0.92f, 0.92f, 0.92f, 1.0f);
palette.textSecondary = UIColor(0.68f, 0.68f, 0.68f, 1.0f);
palette.textMuted = UIColor(0.58f, 0.58f, 0.58f, 1.0f);
palette.imageTint = UIColor(1.0f, 1.0f, 1.0f, 1.0f);
palette.statusBarPalette = BuildStatusBarPalette();
return palette;
}
UIEditorShellComposePalette BuildShellComposePalette() {
UIEditorShellComposePalette palette = {};
palette.surfaceColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.surfaceBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.menuBarPalette = BuildMenuBarPalette();
palette.toolbarPalette.barColor = UIColor(0.10f, 0.10f, 0.10f, 1.0f);
palette.toolbarPalette.groupColor = UIColor(0.11f, 0.11f, 0.11f, 1.0f);
palette.toolbarPalette.groupBorderColor = UIColor(0.14f, 0.14f, 0.14f, 1.0f);
palette.toolbarPalette.buttonColor = UIColor(0.12f, 0.12f, 0.12f, 1.0f);
palette.toolbarPalette.buttonBorderColor = UIColor(0.16f, 0.16f, 0.16f, 1.0f);
palette.toolbarPalette.iconColor = UIColor(0.88f, 0.88f, 0.88f, 1.0f);
palette.dockHostPalette = BuildDockHostPalette();
palette.viewportPalette = BuildViewportSlotPalette();
palette.statusBarPalette = BuildStatusBarPalette();
return palette;
}
UIEditorShellInteractionPalette BuildShellInteractionPalette() {
UIEditorShellInteractionPalette palette = {};
palette.shellPalette = BuildShellComposePalette();
palette.popupPalette = BuildMenuPopupPalette();
return palette;
}
#define XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(Name, Type) \
const Type& ResolveUIEditor##Name() { \
return GetDefaultValue<Type>(); \
@@ -38,32 +234,80 @@ XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ObjectFieldPalette, Widgets::UIEditorObjectF
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(AssetFieldMetrics, Widgets::UIEditorAssetFieldMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(AssetFieldPalette, Widgets::UIEditorAssetFieldPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(MenuPopupMetrics, Widgets::UIEditorMenuPopupMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(MenuPopupPalette, Widgets::UIEditorMenuPopupPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ListViewMetrics, Widgets::UIEditorListViewMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ListViewPalette, Widgets::UIEditorListViewPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(TreeViewMetrics, Widgets::UIEditorTreeViewMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(TreeViewPalette, Widgets::UIEditorTreeViewPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ScrollViewMetrics, Widgets::UIEditorScrollViewMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ScrollViewPalette, Widgets::UIEditorScrollViewPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(TabStripMetrics, Widgets::UIEditorTabStripMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(TabStripPalette, Widgets::UIEditorTabStripPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(MenuBarMetrics, Widgets::UIEditorMenuBarMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(MenuBarPalette, Widgets::UIEditorMenuBarPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(StatusBarMetrics, Widgets::UIEditorStatusBarMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(StatusBarPalette, Widgets::UIEditorStatusBarPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(PanelFrameMetrics, Widgets::UIEditorPanelFrameMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(PanelFramePalette, Widgets::UIEditorPanelFramePalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(DockHostMetrics, Widgets::UIEditorDockHostMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(DockHostPalette, Widgets::UIEditorDockHostPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ViewportSlotMetrics, Widgets::UIEditorViewportSlotMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ViewportSlotPalette, Widgets::UIEditorViewportSlotPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ShellComposeMetrics, UIEditorShellComposeMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ShellComposePalette, UIEditorShellComposePalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ShellInteractionMetrics, UIEditorShellInteractionMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(ShellInteractionPalette, UIEditorShellInteractionPalette)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(PropertyGridMetrics, Widgets::UIEditorPropertyGridMetrics)
XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS(PropertyGridPalette, Widgets::UIEditorPropertyGridPalette)
const Widgets::UIEditorMenuPopupPalette& ResolveUIEditorMenuPopupPalette() {
static const Widgets::UIEditorMenuPopupPalette palette = BuildMenuPopupPalette();
return palette;
}
const Widgets::UIEditorListViewPalette& ResolveUIEditorListViewPalette() {
static const Widgets::UIEditorListViewPalette palette = BuildListViewPalette();
return palette;
}
const Widgets::UIEditorTreeViewPalette& ResolveUIEditorTreeViewPalette() {
static const Widgets::UIEditorTreeViewPalette palette = BuildTreeViewPalette();
return palette;
}
const Widgets::UIEditorScrollViewPalette& ResolveUIEditorScrollViewPalette() {
static const Widgets::UIEditorScrollViewPalette palette = BuildScrollViewPalette();
return palette;
}
const Widgets::UIEditorTabStripPalette& ResolveUIEditorTabStripPalette() {
static const Widgets::UIEditorTabStripPalette palette = BuildTabStripPalette();
return palette;
}
const Widgets::UIEditorMenuBarPalette& ResolveUIEditorMenuBarPalette() {
static const Widgets::UIEditorMenuBarPalette palette = BuildMenuBarPalette();
return palette;
}
const Widgets::UIEditorStatusBarPalette& ResolveUIEditorStatusBarPalette() {
static const Widgets::UIEditorStatusBarPalette palette = BuildStatusBarPalette();
return palette;
}
const Widgets::UIEditorPanelFramePalette& ResolveUIEditorPanelFramePalette() {
static const Widgets::UIEditorPanelFramePalette palette = BuildPanelFramePalette();
return palette;
}
const Widgets::UIEditorDockHostPalette& ResolveUIEditorDockHostPalette() {
static const Widgets::UIEditorDockHostPalette palette = BuildDockHostPalette();
return palette;
}
const Widgets::UIEditorViewportSlotPalette& ResolveUIEditorViewportSlotPalette() {
static const Widgets::UIEditorViewportSlotPalette palette = BuildViewportSlotPalette();
return palette;
}
const UIEditorShellComposePalette& ResolveUIEditorShellComposePalette() {
static const UIEditorShellComposePalette palette = BuildShellComposePalette();
return palette;
}
const UIEditorShellInteractionPalette& ResolveUIEditorShellInteractionPalette() {
static const UIEditorShellInteractionPalette palette = BuildShellInteractionPalette();
return palette;
}
#undef XCUIEDITOR_DEFINE_DEFAULT_ACCESSORS
} // namespace XCEngine::UI::Editor

View File

@@ -18,7 +18,39 @@ bool AreEqual(float lhs, float rhs) {
} // namespace
const UIEditorInspectorFieldStyleTokens& GetUIEditorInspectorFieldStyleTokens() {
static const UIEditorInspectorFieldStyleTokens kTokens = {};
static const UIEditorInspectorFieldStyleTokens kTokens = [] {
UIEditorInspectorFieldStyleTokens tokens = {};
tokens.rowHoverColor = ::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
tokens.rowActiveColor = ::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
tokens.labelColor = ::XCEngine::UI::UIColor(0.78f, 0.78f, 0.78f, 1.0f);
tokens.valueColor = ::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
tokens.readOnlyValueColor = ::XCEngine::UI::UIColor(0.60f, 0.60f, 0.60f, 1.0f);
tokens.controlColor = ::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
tokens.controlHoverColor = ::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
tokens.controlEditingColor = ::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
tokens.controlReadOnlyColor = ::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
tokens.controlBorderColor = ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
tokens.controlFocusedBorderColor = ::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
tokens.prefixColor = ::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
tokens.prefixBorderColor = ::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
tokens.popupColor = ::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
tokens.popupBorderColor = ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
tokens.popupHeaderColor = ::XCEngine::UI::UIColor(0.11f, 0.11f, 0.11f, 1.0f);
tokens.popupTitleColor = ::XCEngine::UI::UIColor(0.93f, 0.93f, 0.93f, 1.0f);
tokens.popupTextColor = ::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
tokens.popupTextMutedColor = ::XCEngine::UI::UIColor(0.68f, 0.68f, 0.68f, 1.0f);
tokens.previewBorderColor = ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
tokens.previewBaseColor = ::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
tokens.checkerLightColor = ::XCEngine::UI::UIColor(0.26f, 0.26f, 0.26f, 1.0f);
tokens.checkerDarkColor = ::XCEngine::UI::UIColor(0.16f, 0.16f, 0.16f, 1.0f);
tokens.sliderBorderColor = ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
tokens.numericBoxColor = ::XCEngine::UI::UIColor(0.12f, 0.12f, 0.12f, 1.0f);
tokens.numericBoxBorderColor = ::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
tokens.numericBoxTextColor = ::XCEngine::UI::UIColor(0.92f, 0.92f, 0.92f, 1.0f);
tokens.closeButtonHoverColor = ::XCEngine::UI::UIColor(0.15f, 0.15f, 0.15f, 1.0f);
tokens.closeGlyphColor = ::XCEngine::UI::UIColor(0.85f, 0.85f, 0.85f, 1.0f);
return tokens;
}();
return kTokens;
}