new_editor: unify shared UI text measurement semantics
This commit is contained in:
39
new_editor/include/XCEditor/Foundation/UIEditorTextLayout.h
Normal file
39
new_editor/include/XCEditor/Foundation/UIEditorTextLayout.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
|
||||
inline float ClampUIEditorNonNegative(float value) {
|
||||
return (std::max)(value, 0.0f);
|
||||
}
|
||||
|
||||
inline float EstimateUIEditorSimpleTextWidth(
|
||||
std::string_view text,
|
||||
float estimatedGlyphWidth) {
|
||||
return static_cast<float>(text.size()) * ClampUIEditorNonNegative(estimatedGlyphWidth);
|
||||
}
|
||||
|
||||
inline float ResolveUIEditorMeasuredTextWidth(
|
||||
std::string_view text,
|
||||
float measuredWidth,
|
||||
float fontSize,
|
||||
float estimatedGlyphWidth,
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr) {
|
||||
if (measuredWidth > 0.0f) {
|
||||
return measuredWidth;
|
||||
}
|
||||
|
||||
if (textMeasurer != nullptr &&
|
||||
!text.empty() &&
|
||||
fontSize > 0.0f) {
|
||||
return textMeasurer->MeasureTextWidth(UIEditorTextMeasureRequest { text, fontSize });
|
||||
}
|
||||
|
||||
return EstimateUIEditorSimpleTextWidth(text, estimatedGlyphWidth);
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <cstddef>
|
||||
@@ -16,7 +18,8 @@ struct UIEditorMenuBarItem {
|
||||
std::string menuId = {};
|
||||
std::string label = {};
|
||||
bool enabled = true;
|
||||
float desiredLabelWidth = 0.0f;
|
||||
// Pure measured label width. Button padding is applied only in layout.
|
||||
float measuredLabelWidth = 0.0f;
|
||||
};
|
||||
|
||||
struct UIEditorMenuBarState {
|
||||
@@ -81,6 +84,11 @@ struct UIEditorMenuBarHitTarget {
|
||||
std::size_t index = UIEditorMenuBarInvalidIndex;
|
||||
};
|
||||
|
||||
float ResolveUIEditorMenuBarMeasuredLabelWidth(
|
||||
const UIEditorMenuBarItem& item,
|
||||
const UIEditorMenuBarMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
float ResolveUIEditorMenuBarDesiredButtonWidth(
|
||||
const UIEditorMenuBarItem& item,
|
||||
const UIEditorMenuBarMetrics& metrics = {});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
#include <XCEditor/Menu/UIEditorMenuModel.h>
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
@@ -23,8 +24,9 @@ struct UIEditorMenuPopupItem {
|
||||
bool enabled = true;
|
||||
bool checked = false;
|
||||
bool hasSubmenu = false;
|
||||
float desiredLabelWidth = 0.0f;
|
||||
float desiredShortcutWidth = 0.0f;
|
||||
// Pure measured text widths. Row/popup sizing is derived from them locally.
|
||||
float measuredLabelWidth = 0.0f;
|
||||
float measuredShortcutWidth = 0.0f;
|
||||
};
|
||||
|
||||
struct UIEditorMenuPopupState {
|
||||
@@ -91,6 +93,16 @@ struct UIEditorMenuPopupHitTarget {
|
||||
std::size_t index = UIEditorMenuPopupInvalidIndex;
|
||||
};
|
||||
|
||||
float ResolveUIEditorMenuPopupMeasuredLabelWidth(
|
||||
const UIEditorMenuPopupItem& item,
|
||||
const UIEditorMenuPopupMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
float ResolveUIEditorMenuPopupMeasuredShortcutWidth(
|
||||
const UIEditorMenuPopupItem& item,
|
||||
const UIEditorMenuPopupMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
float ResolveUIEditorMenuPopupDesiredWidth(
|
||||
const std::vector<UIEditorMenuPopupItem>& items,
|
||||
const UIEditorMenuPopupMetrics& metrics = {});
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <cstddef>
|
||||
@@ -38,7 +40,8 @@ struct UIEditorStatusBarSegment {
|
||||
UIEditorStatusBarTextTone tone = UIEditorStatusBarTextTone::Primary;
|
||||
bool interactive = true;
|
||||
bool showSeparator = false;
|
||||
float desiredWidth = 0.0f;
|
||||
// Pure measured label width. Segment padding is applied only in layout.
|
||||
float measuredLabelWidth = 0.0f;
|
||||
};
|
||||
|
||||
struct UIEditorStatusBarState {
|
||||
@@ -57,6 +60,8 @@ struct UIEditorStatusBarMetrics {
|
||||
float separatorInsetY = 5.0f;
|
||||
float slotGapMin = 18.0f;
|
||||
float cornerRounding = 0.0f;
|
||||
float labelFontSize = 12.0f;
|
||||
float labelInsetY = 0.0f;
|
||||
float estimatedGlyphWidth = 6.5f;
|
||||
float borderThickness = 1.0f;
|
||||
float focusedBorderThickness = 1.0f;
|
||||
@@ -100,6 +105,11 @@ struct UIEditorStatusBarHitTarget {
|
||||
std::size_t index = UIEditorStatusBarInvalidIndex;
|
||||
};
|
||||
|
||||
float ResolveUIEditorStatusBarMeasuredLabelWidth(
|
||||
const UIEditorStatusBarSegment& segment,
|
||||
const UIEditorStatusBarMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
float ResolveUIEditorStatusBarDesiredSegmentWidth(
|
||||
const UIEditorStatusBarSegment& segment,
|
||||
const UIEditorStatusBarMetrics& metrics = {});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextMeasurement.h>
|
||||
#include <XCEditor/Viewport/UIEditorViewportInputBridge.h>
|
||||
#include <XCEditor/Viewport/UIEditorViewportSlot.h>
|
||||
|
||||
@@ -42,6 +43,11 @@ struct UIEditorViewportShellFrame {
|
||||
::XCEngine::UI::UISize requestedViewportSize = {};
|
||||
};
|
||||
|
||||
UIEditorViewportShellModel ResolveUIEditorViewportShellMeasuredModel(
|
||||
const UIEditorViewportShellModel& model,
|
||||
const Widgets::UIEditorViewportSlotMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
UIEditorViewportShellRequest ResolveUIEditorViewportShellRequest(
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorViewportShellSpec& spec,
|
||||
|
||||
@@ -53,7 +53,8 @@ struct UIEditorViewportSlotToolItem {
|
||||
UIEditorViewportSlotToolSlot slot = UIEditorViewportSlotToolSlot::Trailing;
|
||||
bool enabled = true;
|
||||
bool selected = false;
|
||||
float desiredWidth = 0.0f;
|
||||
// Pure measured tool-label width. Tool button padding is applied only in layout.
|
||||
float measuredLabelWidth = 0.0f;
|
||||
};
|
||||
|
||||
struct UIEditorViewportSlotState {
|
||||
@@ -75,13 +76,18 @@ struct UIEditorViewportSlotMetrics {
|
||||
float toolPaddingX = 8.0f;
|
||||
float toolGap = 4.0f;
|
||||
float toolCornerRounding = 2.0f;
|
||||
float toolLabelFontSize = 11.0f;
|
||||
float toolLabelInsetY = 3.0f;
|
||||
float titleGap = 6.0f;
|
||||
float titleFontSize = 13.0f;
|
||||
float titleInsetY = 5.0f;
|
||||
float subtitleFontSize = 10.0f;
|
||||
float subtitleInsetY = 14.0f;
|
||||
float estimatedGlyphWidth = 6.5f;
|
||||
float surfaceInset = 0.0f;
|
||||
float surfaceBorderThickness = 1.0f;
|
||||
float focusedSurfaceBorderThickness = 1.0f;
|
||||
UIEditorStatusBarMetrics statusBarMetrics = {};
|
||||
};
|
||||
|
||||
struct UIEditorViewportSlotPalette {
|
||||
@@ -157,6 +163,11 @@ struct UIEditorViewportSlotForegroundAppendOptions {
|
||||
bool includeSurfaceTexture = true;
|
||||
};
|
||||
|
||||
float ResolveUIEditorViewportSlotMeasuredToolLabelWidth(
|
||||
const UIEditorViewportSlotToolItem& item,
|
||||
const UIEditorViewportSlotMetrics& metrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
float ResolveUIEditorViewportSlotDesiredToolWidth(
|
||||
const UIEditorViewportSlotToolItem& item,
|
||||
const UIEditorViewportSlotMetrics& metrics = {});
|
||||
|
||||
@@ -35,6 +35,7 @@ struct UIEditorWorkspaceComposeState {
|
||||
struct UIEditorWorkspaceViewportComposeRequest {
|
||||
std::string panelId = {};
|
||||
::XCEngine::UI::UIRect bounds = {};
|
||||
UIEditorViewportShellModel viewportShellModel = {};
|
||||
UIEditorViewportShellRequest viewportShellRequest = {};
|
||||
};
|
||||
|
||||
@@ -82,7 +83,8 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
||||
const Widgets::UIEditorDockHostLayout& dockHostLayout,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
||||
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
|
||||
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {},
|
||||
const UIEditorTextMeasurer* textMeasurer = nullptr);
|
||||
|
||||
UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <XCEditor/Menu/UIEditorMenuBar.h>
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
@@ -26,16 +28,6 @@ bool IsVisibleColor(const UIColor& color) {
|
||||
return color.a > 0.0f;
|
||||
}
|
||||
|
||||
float ResolveEstimatedLabelWidth(
|
||||
const UIEditorMenuBarItem& item,
|
||||
const UIEditorMenuBarMetrics& metrics) {
|
||||
if (item.desiredLabelWidth > 0.0f) {
|
||||
return item.desiredLabelWidth;
|
||||
}
|
||||
|
||||
return static_cast<float>(item.label.size()) * ClampNonNegative(metrics.estimatedGlyphWidth);
|
||||
}
|
||||
|
||||
float ResolveLabelTop(const UIRect& rect, const UIEditorMenuBarMetrics& metrics) {
|
||||
return rect.y +
|
||||
(std::max)(0.0f, (rect.height - ClampNonNegative(metrics.labelFontSize)) * 0.5f) +
|
||||
@@ -99,10 +91,23 @@ float ResolveButtonBorderThickness(
|
||||
|
||||
} // namespace
|
||||
|
||||
float ResolveUIEditorMenuBarMeasuredLabelWidth(
|
||||
const UIEditorMenuBarItem& item,
|
||||
const UIEditorMenuBarMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
return ResolveUIEditorMeasuredTextWidth(
|
||||
item.label,
|
||||
item.measuredLabelWidth,
|
||||
metrics.labelFontSize,
|
||||
metrics.estimatedGlyphWidth,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
float ResolveUIEditorMenuBarDesiredButtonWidth(
|
||||
const UIEditorMenuBarItem& item,
|
||||
const UIEditorMenuBarMetrics& metrics) {
|
||||
return ResolveEstimatedLabelWidth(item, metrics) + ClampNonNegative(metrics.buttonPaddingX) * 2.0f;
|
||||
return ResolveUIEditorMenuBarMeasuredLabelWidth(item, metrics) +
|
||||
ClampNonNegative(metrics.buttonPaddingX) * 2.0f;
|
||||
}
|
||||
|
||||
UIEditorMenuBarLayout BuildUIEditorMenuBarLayout(
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <XCEditor/Menu/UIEditorMenuPopup.h>
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
@@ -23,14 +25,6 @@ bool IsPointInsideRect(const UIRect& rect, const UIPoint& point) {
|
||||
point.y <= rect.y + rect.height;
|
||||
}
|
||||
|
||||
float ResolveEstimatedWidth(float explicitWidth, std::string_view text, float glyphWidth) {
|
||||
if (explicitWidth > 0.0f) {
|
||||
return explicitWidth;
|
||||
}
|
||||
|
||||
return static_cast<float>(text.size()) * glyphWidth;
|
||||
}
|
||||
|
||||
bool IsInteractiveItem(const UIEditorMenuPopupItem& item) {
|
||||
return item.kind != UIEditorMenuItemKind::Separator;
|
||||
}
|
||||
@@ -49,6 +43,30 @@ bool IsHighlighted(const UIEditorMenuPopupState& state, std::size_t index) {
|
||||
|
||||
} // namespace
|
||||
|
||||
float ResolveUIEditorMenuPopupMeasuredLabelWidth(
|
||||
const UIEditorMenuPopupItem& item,
|
||||
const UIEditorMenuPopupMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
return ResolveUIEditorMeasuredTextWidth(
|
||||
item.label,
|
||||
item.measuredLabelWidth,
|
||||
metrics.labelFontSize,
|
||||
metrics.estimatedGlyphWidth,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
float ResolveUIEditorMenuPopupMeasuredShortcutWidth(
|
||||
const UIEditorMenuPopupItem& item,
|
||||
const UIEditorMenuPopupMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
return ResolveUIEditorMeasuredTextWidth(
|
||||
item.shortcutText,
|
||||
item.measuredShortcutWidth,
|
||||
metrics.labelFontSize,
|
||||
metrics.estimatedGlyphWidth,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
float ResolveUIEditorMenuPopupDesiredWidth(
|
||||
const std::vector<UIEditorMenuPopupItem>& items,
|
||||
const UIEditorMenuPopupMetrics& metrics) {
|
||||
@@ -59,14 +77,11 @@ float ResolveUIEditorMenuPopupDesiredWidth(
|
||||
}
|
||||
|
||||
const float labelWidth =
|
||||
ResolveEstimatedWidth(item.desiredLabelWidth, item.label, metrics.estimatedGlyphWidth);
|
||||
ResolveUIEditorMenuPopupMeasuredLabelWidth(item, metrics);
|
||||
const float shortcutWidth =
|
||||
item.shortcutText.empty()
|
||||
? 0.0f
|
||||
: ResolveEstimatedWidth(
|
||||
item.desiredShortcutWidth,
|
||||
item.shortcutText,
|
||||
metrics.estimatedGlyphWidth);
|
||||
: ResolveUIEditorMenuPopupMeasuredShortcutWidth(item, metrics);
|
||||
const float submenuWidth =
|
||||
item.hasSubmenu ? ClampNonNegative(metrics.submenuIndicatorWidth) : 0.0f;
|
||||
const float rowWidth =
|
||||
@@ -225,10 +240,7 @@ void AppendUIEditorMenuPopupForeground(
|
||||
float labelClipWidth = (std::max)(labelRight - labelLeft, 0.0f);
|
||||
if (!item.shortcutText.empty()) {
|
||||
const float shortcutWidth =
|
||||
ResolveEstimatedWidth(
|
||||
item.desiredShortcutWidth,
|
||||
item.shortcutText,
|
||||
metrics.estimatedGlyphWidth);
|
||||
ResolveUIEditorMenuPopupMeasuredShortcutWidth(item, metrics);
|
||||
labelClipWidth = (std::max)(
|
||||
labelClipWidth - shortcutWidth - ClampNonNegative(metrics.shortcutGap),
|
||||
0.0f);
|
||||
@@ -249,10 +261,7 @@ void AppendUIEditorMenuPopupForeground(
|
||||
|
||||
if (!item.shortcutText.empty()) {
|
||||
const float shortcutWidth =
|
||||
ResolveEstimatedWidth(
|
||||
item.desiredShortcutWidth,
|
||||
item.shortcutText,
|
||||
metrics.estimatedGlyphWidth);
|
||||
ResolveUIEditorMenuPopupMeasuredShortcutWidth(item, metrics);
|
||||
const float shortcutLeft = rect.x + rect.width -
|
||||
ClampNonNegative(metrics.shortcutInsetRight) -
|
||||
shortcutWidth -
|
||||
|
||||
@@ -20,6 +20,7 @@ struct RequestHit {
|
||||
|
||||
struct BuildRequestOutput {
|
||||
UIEditorShellInteractionRequest request = {};
|
||||
UIEditorShellInteractionModel resolvedModel = {};
|
||||
bool hadInvalidPopupState = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -166,10 +166,10 @@ std::vector<Widgets::UIEditorMenuBarItem> BuildMenuBarItems(
|
||||
item.menuId = menu.menuId;
|
||||
item.label = menu.label;
|
||||
item.enabled = !menu.items.empty();
|
||||
if (services.textMeasurer != nullptr && !item.label.empty()) {
|
||||
item.desiredLabelWidth = services.textMeasurer->MeasureTextWidth(
|
||||
UIEditorTextMeasureRequest { item.label, metrics.labelFontSize });
|
||||
}
|
||||
item.measuredLabelWidth = Widgets::ResolveUIEditorMenuBarMeasuredLabelWidth(
|
||||
item,
|
||||
metrics,
|
||||
services.textMeasurer);
|
||||
items.push_back(std::move(item));
|
||||
}
|
||||
|
||||
@@ -204,27 +204,35 @@ std::vector<Widgets::UIEditorMenuPopupItem> BuildPopupWidgetItems(
|
||||
widgetItem.checked = item.checked;
|
||||
widgetItem.hasSubmenu =
|
||||
item.kind == UIEditorMenuItemKind::Submenu && !item.children.empty();
|
||||
if (services.textMeasurer != nullptr) {
|
||||
if (!widgetItem.label.empty()) {
|
||||
widgetItem.desiredLabelWidth = services.textMeasurer->MeasureTextWidth(
|
||||
UIEditorTextMeasureRequest {
|
||||
widgetItem.label,
|
||||
metrics.labelFontSize });
|
||||
}
|
||||
if (!widgetItem.shortcutText.empty()) {
|
||||
widgetItem.desiredShortcutWidth =
|
||||
services.textMeasurer->MeasureTextWidth(
|
||||
UIEditorTextMeasureRequest {
|
||||
widgetItem.shortcutText,
|
||||
metrics.labelFontSize });
|
||||
}
|
||||
}
|
||||
widgetItem.measuredLabelWidth = Widgets::ResolveUIEditorMenuPopupMeasuredLabelWidth(
|
||||
widgetItem,
|
||||
metrics,
|
||||
services.textMeasurer);
|
||||
widgetItem.measuredShortcutWidth =
|
||||
Widgets::ResolveUIEditorMenuPopupMeasuredShortcutWidth(
|
||||
widgetItem,
|
||||
metrics,
|
||||
services.textMeasurer);
|
||||
widgetItems.push_back(std::move(widgetItem));
|
||||
}
|
||||
|
||||
return widgetItems;
|
||||
}
|
||||
|
||||
std::vector<Widgets::UIEditorStatusBarSegment> BuildMeasuredStatusSegments(
|
||||
const std::vector<Widgets::UIEditorStatusBarSegment>& segments,
|
||||
const UIEditorShellInteractionServices& services,
|
||||
const Widgets::UIEditorStatusBarMetrics& metrics) {
|
||||
std::vector<Widgets::UIEditorStatusBarSegment> measuredSegments = segments;
|
||||
for (Widgets::UIEditorStatusBarSegment& segment : measuredSegments) {
|
||||
segment.measuredLabelWidth = Widgets::ResolveUIEditorStatusBarMeasuredLabelWidth(
|
||||
segment,
|
||||
metrics,
|
||||
services.textMeasurer);
|
||||
}
|
||||
return measuredSegments;
|
||||
}
|
||||
|
||||
bool HasMeaningfulInteractionResult(
|
||||
const UIEditorShellInteractionResult& result) {
|
||||
return result.consumed ||
|
||||
@@ -253,6 +261,11 @@ BuildRequestOutput BuildRequest(
|
||||
const UIEditorShellInteractionMetrics& metrics,
|
||||
const UIEditorShellInteractionServices& services) {
|
||||
BuildRequestOutput output = {};
|
||||
output.resolvedModel = model;
|
||||
output.resolvedModel.statusSegments = BuildMeasuredStatusSegments(
|
||||
model.statusSegments,
|
||||
services,
|
||||
metrics.shellMetrics.statusBarMetrics);
|
||||
UIEditorShellInteractionRequest& request = output.request;
|
||||
request.menuBarItems = BuildMenuBarItems(
|
||||
model.resolvedMenuModel,
|
||||
@@ -260,7 +273,7 @@ BuildRequestOutput BuildRequest(
|
||||
metrics.shellMetrics.menuBarMetrics);
|
||||
|
||||
const UIEditorShellComposeModel shellModel =
|
||||
BuildShellComposeModel(model, request.menuBarItems);
|
||||
BuildShellComposeModel(output.resolvedModel, request.menuBarItems);
|
||||
request.shellRequest = ResolveUIEditorShellComposeRequest(
|
||||
bounds,
|
||||
shellModel,
|
||||
@@ -785,7 +798,7 @@ UIEditorShellInteractionFrame UpdateUIEditorShellInteraction(
|
||||
interactionResult.workspaceResult.viewportInputFrame;
|
||||
interactionResult.consumed =
|
||||
interactionResult.consumed || interactionResult.workspaceResult.consumed;
|
||||
frame.model = model;
|
||||
frame.model = requestBuild.resolvedModel;
|
||||
frame.result = std::move(interactionResult);
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <XCEditor/Shell/UIEditorStatusBar.h>
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor::Widgets {
|
||||
@@ -45,19 +47,35 @@ float ResolveSegmentCornerRounding(const UIEditorStatusBarMetrics& metrics) {
|
||||
return (std::max)(metrics.cornerRounding - 2.0f, 0.0f);
|
||||
}
|
||||
|
||||
float ResolveLabelTop(
|
||||
const UIRect& rect,
|
||||
const UIEditorStatusBarMetrics& metrics) {
|
||||
return rect.y +
|
||||
(std::max)(0.0f, (rect.height - ClampNonNegative(metrics.labelFontSize)) * 0.5f) +
|
||||
metrics.labelInsetY;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
float ResolveUIEditorStatusBarMeasuredLabelWidth(
|
||||
const UIEditorStatusBarSegment& segment,
|
||||
const UIEditorStatusBarMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
return ResolveUIEditorMeasuredTextWidth(
|
||||
segment.label,
|
||||
segment.measuredLabelWidth,
|
||||
metrics.labelFontSize,
|
||||
metrics.estimatedGlyphWidth,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
float ResolveUIEditorStatusBarDesiredSegmentWidth(
|
||||
const UIEditorStatusBarSegment& segment,
|
||||
const UIEditorStatusBarMetrics& metrics) {
|
||||
if (segment.desiredWidth > 0.0f) {
|
||||
return segment.desiredWidth;
|
||||
}
|
||||
|
||||
return segment.label.empty()
|
||||
? metrics.segmentPaddingX * 2.0f
|
||||
: metrics.segmentPaddingX * 2.0f +
|
||||
static_cast<float>(segment.label.size()) * metrics.estimatedGlyphWidth;
|
||||
ResolveUIEditorStatusBarMeasuredLabelWidth(segment, metrics);
|
||||
}
|
||||
|
||||
UIEditorStatusBarLayout BuildUIEditorStatusBarLayout(
|
||||
@@ -260,10 +278,10 @@ void AppendUIEditorStatusBarForeground(
|
||||
drawList.AddText(
|
||||
UIPoint(
|
||||
layout.segmentRects[index].x + metrics.segmentPaddingX,
|
||||
layout.segmentRects[index].y + metrics.segmentPaddingY),
|
||||
ResolveLabelTop(layout.segmentRects[index], metrics)),
|
||||
segments[index].label,
|
||||
ResolveUIEditorStatusBarTextColor(segments[index].tone, palette),
|
||||
12.0f);
|
||||
metrics.labelFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,28 @@ UIEditorViewportSlotState BuildViewportShellSlotState(
|
||||
|
||||
} // namespace
|
||||
|
||||
UIEditorViewportShellModel ResolveUIEditorViewportShellMeasuredModel(
|
||||
const UIEditorViewportShellModel& model,
|
||||
const Widgets::UIEditorViewportSlotMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
UIEditorViewportShellModel measuredModel = model;
|
||||
for (Widgets::UIEditorViewportSlotToolItem& toolItem : measuredModel.spec.toolItems) {
|
||||
toolItem.measuredLabelWidth = Widgets::ResolveUIEditorViewportSlotMeasuredToolLabelWidth(
|
||||
toolItem,
|
||||
metrics,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
for (Widgets::UIEditorStatusBarSegment& segment : measuredModel.spec.statusSegments) {
|
||||
segment.measuredLabelWidth = Widgets::ResolveUIEditorStatusBarMeasuredLabelWidth(
|
||||
segment,
|
||||
metrics.statusBarMetrics,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
return measuredModel;
|
||||
}
|
||||
|
||||
UIEditorViewportShellRequest ResolveUIEditorViewportShellRequest(
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const UIEditorViewportShellSpec& spec,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <XCEditor/Viewport/UIEditorViewportSlot.h>
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorTextLayout.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
@@ -95,19 +97,34 @@ float ResolveSurfaceBorderThickness(
|
||||
return metrics.surfaceBorderThickness;
|
||||
}
|
||||
|
||||
float ResolveCenteredTextTop(
|
||||
const UIRect& rect,
|
||||
float fontSize,
|
||||
float insetY) {
|
||||
return rect.y + (std::max)(0.0f, (rect.height - fontSize) * 0.5f) + insetY;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
float ResolveUIEditorViewportSlotMeasuredToolLabelWidth(
|
||||
const UIEditorViewportSlotToolItem& item,
|
||||
const UIEditorViewportSlotMetrics& metrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
return ResolveUIEditorMeasuredTextWidth(
|
||||
item.label,
|
||||
item.measuredLabelWidth,
|
||||
metrics.toolLabelFontSize,
|
||||
metrics.estimatedGlyphWidth,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
float ResolveUIEditorViewportSlotDesiredToolWidth(
|
||||
const UIEditorViewportSlotToolItem& item,
|
||||
const UIEditorViewportSlotMetrics& metrics) {
|
||||
if (item.desiredWidth > 0.0f) {
|
||||
return item.desiredWidth;
|
||||
}
|
||||
|
||||
return item.label.empty()
|
||||
? metrics.toolPaddingX * 2.0f
|
||||
: metrics.toolPaddingX * 2.0f +
|
||||
static_cast<float>(item.label.size()) * metrics.estimatedGlyphWidth;
|
||||
ResolveUIEditorViewportSlotMeasuredToolLabelWidth(item, metrics);
|
||||
}
|
||||
|
||||
UIEditorViewportSlotLayout BuildUIEditorViewportSlotLayout(
|
||||
@@ -154,7 +171,10 @@ UIEditorViewportSlotLayout BuildUIEditorViewportSlotLayout(
|
||||
layout.bounds.width,
|
||||
bottomBarHeight);
|
||||
layout.statusBarLayout =
|
||||
BuildUIEditorStatusBarLayout(layout.bottomBarRect, statusSegments);
|
||||
BuildUIEditorStatusBarLayout(
|
||||
layout.bottomBarRect,
|
||||
statusSegments,
|
||||
metrics.statusBarMetrics);
|
||||
}
|
||||
|
||||
const float surfaceTop = layout.hasTopBar
|
||||
@@ -359,7 +379,8 @@ void AppendUIEditorViewportSlotBackground(
|
||||
layout.statusBarLayout,
|
||||
statusSegments,
|
||||
state.statusBarState,
|
||||
palette.statusBarPalette);
|
||||
palette.statusBarPalette,
|
||||
metrics.statusBarMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,18 +398,28 @@ void AppendUIEditorViewportSlotForeground(
|
||||
if (layout.hasTopBar) {
|
||||
if (!chrome.title.empty()) {
|
||||
drawList.AddText(
|
||||
UIPoint(layout.titleRect.x, layout.topBarRect.y + metrics.titleInsetY),
|
||||
UIPoint(
|
||||
layout.titleRect.x,
|
||||
ResolveCenteredTextTop(
|
||||
layout.topBarRect,
|
||||
metrics.titleFontSize,
|
||||
metrics.titleInsetY)),
|
||||
chrome.title,
|
||||
palette.textPrimary,
|
||||
13.0f);
|
||||
metrics.titleFontSize);
|
||||
}
|
||||
|
||||
if (!chrome.subtitle.empty()) {
|
||||
drawList.AddText(
|
||||
UIPoint(layout.subtitleRect.x, layout.topBarRect.y + metrics.subtitleInsetY),
|
||||
UIPoint(
|
||||
layout.subtitleRect.x,
|
||||
ResolveCenteredTextTop(
|
||||
layout.topBarRect,
|
||||
metrics.subtitleFontSize,
|
||||
metrics.subtitleInsetY)),
|
||||
chrome.subtitle,
|
||||
palette.textSecondary,
|
||||
10.0f);
|
||||
metrics.subtitleFontSize);
|
||||
}
|
||||
|
||||
for (std::size_t index = 0u; index < toolItems.size(); ++index) {
|
||||
@@ -399,10 +430,13 @@ void AppendUIEditorViewportSlotForeground(
|
||||
drawList.AddText(
|
||||
UIPoint(
|
||||
layout.toolItemRects[index].x + metrics.toolPaddingX,
|
||||
layout.toolItemRects[index].y + 3.0f),
|
||||
ResolveCenteredTextTop(
|
||||
layout.toolItemRects[index],
|
||||
metrics.toolLabelFontSize,
|
||||
metrics.toolLabelInsetY)),
|
||||
toolItems[index].label,
|
||||
toolItems[index].enabled ? palette.textPrimary : palette.textMuted,
|
||||
11.0f);
|
||||
metrics.toolLabelFontSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +452,8 @@ void AppendUIEditorViewportSlotForeground(
|
||||
layout.statusBarLayout,
|
||||
statusSegments,
|
||||
state.statusBarState,
|
||||
palette.statusBarPalette);
|
||||
palette.statusBarPalette,
|
||||
metrics.statusBarMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,8 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
||||
const Widgets::UIEditorDockHostLayout& dockHostLayout,
|
||||
const UIEditorPanelRegistry& panelRegistry,
|
||||
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
||||
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics) {
|
||||
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics,
|
||||
const UIEditorTextMeasurer* textMeasurer) {
|
||||
UIEditorWorkspaceComposeRequest request = {};
|
||||
request.dockHostLayout = dockHostLayout;
|
||||
request.contentHostRequest = ResolveUIEditorPanelContentHostRequest(
|
||||
@@ -171,9 +172,13 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
||||
UIEditorWorkspaceViewportComposeRequest viewportRequest = {};
|
||||
viewportRequest.panelId = mountRequest.panelId;
|
||||
viewportRequest.bounds = mountRequest.bounds;
|
||||
viewportRequest.viewportShellModel = ResolveUIEditorViewportShellMeasuredModel(
|
||||
presentation->viewportShellModel,
|
||||
viewportMetrics,
|
||||
textMeasurer);
|
||||
viewportRequest.viewportShellRequest = ResolveUIEditorViewportShellRequest(
|
||||
mountRequest.bounds,
|
||||
presentation->viewportShellModel.spec,
|
||||
viewportRequest.viewportShellModel.spec,
|
||||
viewportMetrics);
|
||||
request.viewportRequests.push_back(std::move(viewportRequest));
|
||||
}
|
||||
@@ -203,7 +208,8 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
|
||||
dockHostLayout,
|
||||
panelRegistry,
|
||||
presentations,
|
||||
viewportMetrics);
|
||||
viewportMetrics,
|
||||
textMeasurer);
|
||||
}
|
||||
|
||||
UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
||||
@@ -240,7 +246,7 @@ UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
||||
UIEditorWorkspaceViewportComposeFrame viewportFrame = {};
|
||||
viewportFrame.panelId = presentation.panelId;
|
||||
viewportFrame.bounds = viewportRequest->bounds;
|
||||
viewportFrame.viewportShellModel = presentation.viewportShellModel;
|
||||
viewportFrame.viewportShellModel = viewportRequest->viewportShellModel;
|
||||
UIEditorViewportInputBridgeRequest inputRequest = {};
|
||||
if (inputOwner != nullptr) {
|
||||
inputRequest.focusMode = UIEditorViewportInputBridgeFocusMode::External;
|
||||
@@ -250,7 +256,7 @@ UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
|
||||
viewportFrame.viewportShellFrame = UpdateUIEditorViewportShell(
|
||||
panelState.viewportShellState,
|
||||
viewportRequest->viewportShellRequest,
|
||||
presentation.viewportShellModel,
|
||||
viewportFrame.viewportShellModel,
|
||||
inputEvents,
|
||||
inputRequest);
|
||||
frame.viewportFrames.push_back(std::move(viewportFrame));
|
||||
|
||||
@@ -81,7 +81,8 @@ UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
|
||||
frame.dockHostFrame.layout,
|
||||
controller.GetPanelRegistry(),
|
||||
model.workspacePresentations,
|
||||
viewportMetrics);
|
||||
viewportMetrics,
|
||||
textMeasurer);
|
||||
const UIEditorPanelContentHostFrame previewContentHostFrame =
|
||||
BuildUIEditorPanelContentHostFrame(
|
||||
previewRequest.contentHostRequest,
|
||||
|
||||
Reference in New Issue
Block a user