diff --git a/new_editor/include/XCEditor/Foundation/UIEditorTextLayout.h b/new_editor/include/XCEditor/Foundation/UIEditorTextLayout.h new file mode 100644 index 00000000..ebb3c92f --- /dev/null +++ b/new_editor/include/XCEditor/Foundation/UIEditorTextLayout.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include +#include + +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(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 diff --git a/new_editor/include/XCEditor/Menu/UIEditorMenuBar.h b/new_editor/include/XCEditor/Menu/UIEditorMenuBar.h index c87e3f5f..66cb2533 100644 --- a/new_editor/include/XCEditor/Menu/UIEditorMenuBar.h +++ b/new_editor/include/XCEditor/Menu/UIEditorMenuBar.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -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 = {}); diff --git a/new_editor/include/XCEditor/Menu/UIEditorMenuPopup.h b/new_editor/include/XCEditor/Menu/UIEditorMenuPopup.h index 27afddb0..5bc1ee3f 100644 --- a/new_editor/include/XCEditor/Menu/UIEditorMenuPopup.h +++ b/new_editor/include/XCEditor/Menu/UIEditorMenuPopup.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -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& items, const UIEditorMenuPopupMetrics& metrics = {}); diff --git a/new_editor/include/XCEditor/Shell/UIEditorStatusBar.h b/new_editor/include/XCEditor/Shell/UIEditorStatusBar.h index 6985e140..89b8d39f 100644 --- a/new_editor/include/XCEditor/Shell/UIEditorStatusBar.h +++ b/new_editor/include/XCEditor/Shell/UIEditorStatusBar.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -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 = {}); diff --git a/new_editor/include/XCEditor/Viewport/UIEditorViewportShell.h b/new_editor/include/XCEditor/Viewport/UIEditorViewportShell.h index 631513d4..63950202 100644 --- a/new_editor/include/XCEditor/Viewport/UIEditorViewportShell.h +++ b/new_editor/include/XCEditor/Viewport/UIEditorViewportShell.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -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, diff --git a/new_editor/include/XCEditor/Viewport/UIEditorViewportSlot.h b/new_editor/include/XCEditor/Viewport/UIEditorViewportSlot.h index 5e5b231a..8c000559 100644 --- a/new_editor/include/XCEditor/Viewport/UIEditorViewportSlot.h +++ b/new_editor/include/XCEditor/Viewport/UIEditorViewportSlot.h @@ -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 = {}); diff --git a/new_editor/include/XCEditor/Workspace/UIEditorWorkspaceCompose.h b/new_editor/include/XCEditor/Workspace/UIEditorWorkspaceCompose.h index c60e7dec..08b2d07c 100644 --- a/new_editor/include/XCEditor/Workspace/UIEditorWorkspaceCompose.h +++ b/new_editor/include/XCEditor/Workspace/UIEditorWorkspaceCompose.h @@ -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& presentations, - const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {}); + const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {}, + const UIEditorTextMeasurer* textMeasurer = nullptr); UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest( const ::XCEngine::UI::UIRect& bounds, diff --git a/new_editor/src/Menu/UIEditorMenuBar.cpp b/new_editor/src/Menu/UIEditorMenuBar.cpp index 03ee9710..435c5fa9 100644 --- a/new_editor/src/Menu/UIEditorMenuBar.cpp +++ b/new_editor/src/Menu/UIEditorMenuBar.cpp @@ -1,5 +1,7 @@ #include +#include + #include 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(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( diff --git a/new_editor/src/Menu/UIEditorMenuPopup.cpp b/new_editor/src/Menu/UIEditorMenuPopup.cpp index 02fd4fbd..bcd5e77e 100644 --- a/new_editor/src/Menu/UIEditorMenuPopup.cpp +++ b/new_editor/src/Menu/UIEditorMenuPopup.cpp @@ -1,5 +1,7 @@ #include +#include + #include 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(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& 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 - diff --git a/new_editor/src/Shell/ShellInteractionInternal.h b/new_editor/src/Shell/ShellInteractionInternal.h index 16ad09d7..509651cd 100644 --- a/new_editor/src/Shell/ShellInteractionInternal.h +++ b/new_editor/src/Shell/ShellInteractionInternal.h @@ -20,6 +20,7 @@ struct RequestHit { struct BuildRequestOutput { UIEditorShellInteractionRequest request = {}; + UIEditorShellInteractionModel resolvedModel = {}; bool hadInvalidPopupState = false; }; diff --git a/new_editor/src/Shell/UIEditorShellInteraction.cpp b/new_editor/src/Shell/UIEditorShellInteraction.cpp index 8d698f8a..5b568f44 100644 --- a/new_editor/src/Shell/UIEditorShellInteraction.cpp +++ b/new_editor/src/Shell/UIEditorShellInteraction.cpp @@ -166,10 +166,10 @@ std::vector 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 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 BuildMeasuredStatusSegments( + const std::vector& segments, + const UIEditorShellInteractionServices& services, + const Widgets::UIEditorStatusBarMetrics& metrics) { + std::vector 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; } diff --git a/new_editor/src/Shell/UIEditorStatusBar.cpp b/new_editor/src/Shell/UIEditorStatusBar.cpp index 3cd1a6ed..2dfd5780 100644 --- a/new_editor/src/Shell/UIEditorStatusBar.cpp +++ b/new_editor/src/Shell/UIEditorStatusBar.cpp @@ -1,5 +1,7 @@ #include +#include + #include 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(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); } } diff --git a/new_editor/src/Viewport/UIEditorViewportShell.cpp b/new_editor/src/Viewport/UIEditorViewportShell.cpp index a392ed2b..1c6a0bbb 100644 --- a/new_editor/src/Viewport/UIEditorViewportShell.cpp +++ b/new_editor/src/Viewport/UIEditorViewportShell.cpp @@ -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, diff --git a/new_editor/src/Viewport/UIEditorViewportSlot.cpp b/new_editor/src/Viewport/UIEditorViewportSlot.cpp index f9fb914f..ee001699 100644 --- a/new_editor/src/Viewport/UIEditorViewportSlot.cpp +++ b/new_editor/src/Viewport/UIEditorViewportSlot.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include @@ -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(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); } } diff --git a/new_editor/src/Workspace/UIEditorWorkspaceCompose.cpp b/new_editor/src/Workspace/UIEditorWorkspaceCompose.cpp index 8a4c9503..04ec450e 100644 --- a/new_editor/src/Workspace/UIEditorWorkspaceCompose.cpp +++ b/new_editor/src/Workspace/UIEditorWorkspaceCompose.cpp @@ -147,7 +147,8 @@ UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest( const Widgets::UIEditorDockHostLayout& dockHostLayout, const UIEditorPanelRegistry& panelRegistry, const std::vector& 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)); diff --git a/new_editor/src/Workspace/UIEditorWorkspaceInteraction.cpp b/new_editor/src/Workspace/UIEditorWorkspaceInteraction.cpp index 63c691d7..1b999aef 100644 --- a/new_editor/src/Workspace/UIEditorWorkspaceInteraction.cpp +++ b/new_editor/src/Workspace/UIEditorWorkspaceInteraction.cpp @@ -81,7 +81,8 @@ UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction( frame.dockHostFrame.layout, controller.GetPanelRegistry(), model.workspacePresentations, - viewportMetrics); + viewportMetrics, + textMeasurer); const UIEditorPanelContentHostFrame previewContentHostFrame = BuildUIEditorPanelContentHostFrame( previewRequest.contentHostRequest,