fix(new_editor/window): move detached root tab into title bar
This commit is contained in:
@@ -2,20 +2,107 @@
|
||||
#include "Platform/Win32/EditorWindowConstants.h"
|
||||
#include "Platform/Win32/EditorWindowStyle.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||||
#include <XCEditor/Panels/UIEditorPanelRegistry.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
#include <XCEngine/UI/Layout/UITabStripLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string_view>
|
||||
|
||||
#include <windowsx.h>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
using namespace EditorWindowSupport;
|
||||
using ::XCEngine::UI::Layout::MeasureUITabStripHeaderWidth;
|
||||
using ::XCEngine::UI::UIColor;
|
||||
using ::XCEngine::UI::UIDrawList;
|
||||
using ::XCEngine::UI::UIPoint;
|
||||
using ::XCEngine::UI::UIRect;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr float kTitleBarLogoExtent = 16.0f;
|
||||
constexpr float kTitleBarLogoInsetLeft = 8.0f;
|
||||
constexpr float kTitleBarLogoTextGap = 8.0f;
|
||||
std::string ResolveDetachedTitleTabText(const EditorWindow& window) {
|
||||
const auto& workspaceController = window.GetWorkspaceController();
|
||||
const std::string_view activePanelId = workspaceController.GetWorkspace().activePanelId;
|
||||
if (!activePanelId.empty()) {
|
||||
if (const UIEditorPanelDescriptor* descriptor =
|
||||
FindUIEditorPanelDescriptor(
|
||||
workspaceController.GetPanelRegistry(),
|
||||
activePanelId);
|
||||
descriptor != nullptr &&
|
||||
!descriptor->defaultTitle.empty()) {
|
||||
return descriptor->defaultTitle;
|
||||
}
|
||||
}
|
||||
|
||||
return std::string("Panel");
|
||||
}
|
||||
|
||||
float ResolveDetachedTabWidth(std::string_view text) {
|
||||
const Widgets::UIEditorTabStripMetrics& metrics = ResolveUIEditorTabStripMetrics();
|
||||
Widgets::UIEditorTabStripItem item = {};
|
||||
item.title = std::string(text);
|
||||
const float desiredLabelWidth =
|
||||
Widgets::ResolveUIEditorTabStripDesiredHeaderLabelWidth(item, metrics);
|
||||
return MeasureUITabStripHeaderWidth(desiredLabelWidth, metrics.layoutMetrics);
|
||||
}
|
||||
|
||||
bool IsRootPanelVisible(
|
||||
const UIEditorWorkspaceController& controller,
|
||||
std::string_view panelId) {
|
||||
const UIEditorPanelSessionState* panelState =
|
||||
FindUIEditorPanelSessionState(controller.GetSession(), panelId);
|
||||
return panelState != nullptr && panelState->open && panelState->visible;
|
||||
}
|
||||
|
||||
bool HasSingleVisibleRootTab(const UIEditorWorkspaceController& controller) {
|
||||
const UIEditorWorkspaceNode& root = controller.GetWorkspace().root;
|
||||
if (root.kind != UIEditorWorkspaceNodeKind::TabStack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t visiblePanelCount = 0u;
|
||||
for (const UIEditorWorkspaceNode& child : root.children) {
|
||||
if (child.kind != UIEditorWorkspaceNodeKind::Panel ||
|
||||
!IsRootPanelVisible(controller, child.panel.panelId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++visiblePanelCount;
|
||||
if (visiblePanelCount > 1u) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return visiblePanelCount == 1u;
|
||||
}
|
||||
|
||||
UIRect BuildDetachedTitleLogoRect(const Host::BorderlessWindowChromeLayout& layout) {
|
||||
const float availableLeft = layout.titleBarRect.x;
|
||||
const float availableRight = layout.minimizeButtonRect.x;
|
||||
const float centeredX = std::floor(
|
||||
layout.titleBarRect.x + layout.titleBarRect.width * 0.5f - kTitleBarLogoExtent * 0.5f);
|
||||
const float clampedX = (std::max)(
|
||||
availableLeft,
|
||||
(std::min)(centeredX, availableRight - kTitleBarLogoExtent));
|
||||
const float logoY =
|
||||
layout.titleBarRect.y +
|
||||
(std::max)(0.0f, (layout.titleBarRect.height - kTitleBarLogoExtent) * 0.5f);
|
||||
return UIRect(clampedX, logoY, kTitleBarLogoExtent, kTitleBarLogoExtent);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool EditorWindow::ShouldUseDetachedTitleBarTabStrip() const {
|
||||
return !m_window.primary && HasSingleVisibleRootTab(m_composition.workspaceController);
|
||||
}
|
||||
|
||||
Host::BorderlessWindowChromeHitTarget EditorWindow::HitTestBorderlessWindowChrome(
|
||||
LPARAM lParam) const {
|
||||
if (!IsBorderlessWindowEnabled() || m_window.hwnd == nullptr) {
|
||||
@@ -38,9 +125,14 @@ Host::BorderlessWindowChromeHitTarget EditorWindow::HitTestBorderlessWindowChrom
|
||||
|
||||
Host::BorderlessWindowChromeLayout EditorWindow::ResolveBorderlessWindowChromeLayout(
|
||||
float clientWidthDips) const {
|
||||
float leadingOccupiedRight = 0.0f;
|
||||
if (ShouldUseDetachedTitleBarTabStrip()) {
|
||||
leadingOccupiedRight = ResolveDetachedTabWidth(ResolveDetachedTitleTabText(*this));
|
||||
}
|
||||
|
||||
return Host::BuildBorderlessWindowChromeLayout(
|
||||
UIRect(0.0f, 0.0f, clientWidthDips, kBorderlessTitleBarHeightDips),
|
||||
0.0f);
|
||||
leadingOccupiedRight);
|
||||
}
|
||||
|
||||
void EditorWindow::AppendBorderlessWindowChrome(
|
||||
@@ -52,40 +144,54 @@ void EditorWindow::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, kShellSurfaceColor);
|
||||
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),
|
||||
kShellBorderColor,
|
||||
1.0f);
|
||||
if (m_render.titleBarLogoIcon.IsValid()) {
|
||||
drawList.AddImage(
|
||||
UIRect(iconX, iconY, iconExtent, iconExtent),
|
||||
m_render.titleBarLogoIcon,
|
||||
UIColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
const bool useDetachedTitleBarTabStrip = ShouldUseDetachedTitleBarTabStrip();
|
||||
if (!useDetachedTitleBarTabStrip) {
|
||||
drawList.AddFilledRect(layout.titleBarRect, kShellSurfaceColor);
|
||||
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),
|
||||
kShellBorderColor,
|
||||
1.0f);
|
||||
}
|
||||
|
||||
const std::string& titleText =
|
||||
m_window.titleText.empty() ? std::string("XCEngine Editor") : m_window.titleText;
|
||||
drawList.AddText(
|
||||
UIPoint(
|
||||
iconX + (m_render.titleBarLogoIcon.IsValid() ? (iconExtent + iconTextGap) : 4.0f),
|
||||
if (!m_window.primary) {
|
||||
if (m_render.titleBarLogoIcon.IsValid()) {
|
||||
drawList.AddImage(
|
||||
BuildDetachedTitleLogoRect(layout),
|
||||
m_render.titleBarLogoIcon,
|
||||
UIColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
} else {
|
||||
const float iconX = layout.titleBarRect.x + kTitleBarLogoInsetLeft;
|
||||
const float iconY =
|
||||
layout.titleBarRect.y +
|
||||
(std::max)(
|
||||
0.0f,
|
||||
(layout.titleBarRect.height - kBorderlessTitleBarFontSize) * 0.5f - 1.0f)),
|
||||
titleText,
|
||||
kShellTextColor,
|
||||
kBorderlessTitleBarFontSize);
|
||||
(std::max)(0.0f, (layout.titleBarRect.height - kTitleBarLogoExtent) * 0.5f);
|
||||
if (m_render.titleBarLogoIcon.IsValid()) {
|
||||
drawList.AddImage(
|
||||
UIRect(iconX, iconY, kTitleBarLogoExtent, kTitleBarLogoExtent),
|
||||
m_render.titleBarLogoIcon,
|
||||
UIColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
}
|
||||
|
||||
const std::string& titleText =
|
||||
m_window.titleText.empty() ? std::string("XCEngine Editor") : m_window.titleText;
|
||||
drawList.AddText(
|
||||
UIPoint(
|
||||
iconX +
|
||||
(m_render.titleBarLogoIcon.IsValid()
|
||||
? (kTitleBarLogoExtent + kTitleBarLogoTextGap)
|
||||
: 4.0f),
|
||||
layout.titleBarRect.y +
|
||||
(std::max)(
|
||||
0.0f,
|
||||
(layout.titleBarRect.height - kBorderlessTitleBarFontSize) * 0.5f - 1.0f)),
|
||||
titleText,
|
||||
kShellTextColor,
|
||||
kBorderlessTitleBarFontSize);
|
||||
}
|
||||
|
||||
Host::AppendBorderlessWindowChrome(
|
||||
drawList,
|
||||
layout,
|
||||
|
||||
Reference in New Issue
Block a user