Refactor XCUI editor module layout

This commit is contained in:
2026-04-10 00:41:28 +08:00
parent 4b47764f26
commit 02a0e626fe
263 changed files with 12396 additions and 7592 deletions

View File

@@ -0,0 +1,188 @@
#pragma once
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
#include <XCEditor/Shell/UIEditorWorkspaceModel.h>
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
#include <XCEditor/Shell/UIEditorPanelFrame.h>
#include <XCEditor/Collections/UIEditorTabStrip.h>
#include <XCEngine/UI/Layout/UISplitterLayout.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor::Widgets {
enum class UIEditorDockHostHitTargetKind : std::uint8_t {
None = 0,
SplitterHandle,
TabStripBackground,
Tab,
TabCloseButton,
PanelHeader,
PanelBody,
PanelFooter,
PanelCloseButton
};
struct UIEditorDockHostHitTarget {
UIEditorDockHostHitTargetKind kind = UIEditorDockHostHitTargetKind::None;
std::string nodeId = {};
std::string panelId = {};
std::size_t index = UIEditorTabStripInvalidIndex;
};
struct UIEditorDockHostTabStripVisualState {
std::string nodeId = {};
UIEditorTabStripState state = {};
};
struct UIEditorDockHostState {
bool focused = false;
UIEditorDockHostHitTarget hoveredTarget = {};
std::string activeSplitterNodeId = {};
std::vector<UIEditorDockHostTabStripVisualState> tabStripStates = {};
};
struct UIEditorDockHostMetrics {
::XCEngine::UI::Layout::UISplitterMetrics splitterMetrics =
::XCEngine::UI::Layout::UISplitterMetrics{ 10.0f, 18.0f };
UIEditorTabStripMetrics tabStripMetrics = {};
UIEditorPanelFrameMetrics panelFrameMetrics = {};
::XCEngine::UI::UISize minimumStandalonePanelBodySize =
::XCEngine::UI::UISize(180.0f, 140.0f);
::XCEngine::UI::UISize minimumTabContentBodySize =
::XCEngine::UI::UISize(260.0f, 180.0f);
float splitterHandleRounding = 4.0f;
float placeholderLineGap = 22.0f;
};
struct UIEditorDockHostPalette {
UIEditorTabStripPalette tabStripPalette = {};
UIEditorPanelFramePalette panelFramePalette = {};
::XCEngine::UI::UIColor splitterColor =
::XCEngine::UI::UIColor(0.22f, 0.23f, 0.25f, 1.0f);
::XCEngine::UI::UIColor splitterHoveredColor =
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
::XCEngine::UI::UIColor splitterActiveColor =
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
::XCEngine::UI::UIColor placeholderTitleColor =
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
::XCEngine::UI::UIColor placeholderTextColor =
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
::XCEngine::UI::UIColor placeholderMutedColor =
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
};
struct UIEditorDockHostTabItemLayout {
std::string panelId = {};
std::string title = {};
bool closable = true;
bool active = false;
};
struct UIEditorDockHostSplitterLayout {
std::string nodeId = {};
UIEditorWorkspaceSplitAxis axis = UIEditorWorkspaceSplitAxis::Horizontal;
::XCEngine::UI::UIRect bounds = {};
::XCEngine::UI::UIRect handleHitRect = {};
::XCEngine::UI::Layout::UISplitterConstraints constraints = {};
::XCEngine::UI::Layout::UISplitterMetrics metrics = {};
::XCEngine::UI::Layout::UISplitterLayoutResult splitterLayout = {};
bool hovered = false;
bool active = false;
};
struct UIEditorDockHostPanelLayout {
std::string nodeId = {};
std::string panelId = {};
std::string title = {};
bool active = false;
UIEditorPanelFrameState frameState = {};
UIEditorPanelFrameLayout frameLayout = {};
};
struct UIEditorDockHostTabStackLayout {
std::string nodeId = {};
std::string selectedPanelId = {};
::XCEngine::UI::UIRect bounds = {};
std::vector<UIEditorDockHostTabItemLayout> items = {};
UIEditorTabStripState tabStripState = {};
UIEditorTabStripLayout tabStripLayout = {};
UIEditorPanelFrameState contentFrameState = {};
UIEditorPanelFrameLayout contentFrameLayout = {};
};
struct UIEditorDockHostLayout {
::XCEngine::UI::UIRect bounds = {};
std::vector<UIEditorDockHostSplitterLayout> splitters = {};
std::vector<UIEditorDockHostPanelLayout> panels = {};
std::vector<UIEditorDockHostTabStackLayout> tabStacks = {};
};
// Allows higher-level compose to own panel body presentation while DockHost
// keeps drawing the surrounding chrome/frame.
struct UIEditorDockHostForegroundOptions {
std::vector<std::string> externalBodyPanelIds = {};
};
const UIEditorDockHostSplitterLayout* FindUIEditorDockHostSplitterLayout(
const UIEditorDockHostLayout& layout,
std::string_view nodeId);
UIEditorDockHostLayout BuildUIEditorDockHostLayout(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorDockHostState& state = {},
const UIEditorDockHostMetrics& metrics = {});
UIEditorDockHostHitTarget HitTestUIEditorDockHost(
const UIEditorDockHostLayout& layout,
const ::XCEngine::UI::UIPoint& point);
void AppendUIEditorDockHostBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorDockHostLayout& layout,
const UIEditorDockHostPalette& palette = {},
const UIEditorDockHostMetrics& metrics = {});
void AppendUIEditorDockHostForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorDockHostLayout& layout,
const UIEditorDockHostForegroundOptions& options = {},
const UIEditorDockHostPalette& palette = {},
const UIEditorDockHostMetrics& metrics = {});
void AppendUIEditorDockHostForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorDockHostLayout& layout,
const UIEditorDockHostPalette& palette,
const UIEditorDockHostMetrics& metrics = {});
void AppendUIEditorDockHost(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorDockHostState& state = {},
const UIEditorDockHostForegroundOptions& foregroundOptions = {},
const UIEditorDockHostPalette& palette = {},
const UIEditorDockHostMetrics& metrics = {});
void AppendUIEditorDockHost(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorDockHostState& state,
const UIEditorDockHostPalette& palette,
const UIEditorDockHostMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,53 @@
#pragma once
#include <XCEditor/Collections/UIEditorTabStripInteraction.h>
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
#include <XCEditor/Shell/UIEditorDockHost.h>
#include <XCEngine/UI/DrawData.h>
#include <XCEngine/UI/Widgets/UISplitterInteraction.h>
#include <string>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorDockHostTabStripInteractionEntry {
std::string nodeId = {};
UIEditorTabStripInteractionState state = {};
};
struct UIEditorDockHostInteractionState {
Widgets::UIEditorDockHostState dockHostState = {};
::XCEngine::UI::Widgets::UISplitterDragState splitterDragState = {};
std::vector<UIEditorDockHostTabStripInteractionEntry> tabStripInteractions = {};
::XCEngine::UI::UIPoint pointerPosition = {};
bool hasPointerPosition = false;
};
struct UIEditorDockHostInteractionResult {
bool consumed = false;
bool commandExecuted = false;
bool layoutChanged = false;
bool requestPointerCapture = false;
bool releasePointerCapture = false;
Widgets::UIEditorDockHostHitTarget hitTarget = {};
std::string activeSplitterNodeId = {};
UIEditorWorkspaceCommandResult commandResult = {};
UIEditorWorkspaceLayoutOperationResult layoutResult = {};
};
struct UIEditorDockHostInteractionFrame {
Widgets::UIEditorDockHostLayout layout = {};
UIEditorDockHostInteractionResult result = {};
bool focused = false;
};
UIEditorDockHostInteractionFrame UpdateUIEditorDockHostInteraction(
UIEditorDockHostInteractionState& state,
UIEditorWorkspaceController& controller,
const ::XCEngine::UI::UIRect& bounds,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorDockHostMetrics& metrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,120 @@
#pragma once
#include <XCEngine/UI/DrawData.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
namespace XCEngine::UI::Editor::Widgets {
inline constexpr std::size_t UIEditorMenuBarInvalidIndex =
static_cast<std::size_t>(-1);
struct UIEditorMenuBarItem {
std::string menuId = {};
std::string label = {};
bool enabled = true;
float desiredLabelWidth = 0.0f;
};
struct UIEditorMenuBarState {
std::size_t openIndex = UIEditorMenuBarInvalidIndex;
std::size_t hoveredIndex = UIEditorMenuBarInvalidIndex;
bool focused = false;
};
struct UIEditorMenuBarMetrics {
float barHeight = 34.0f;
float horizontalInset = 10.0f;
float verticalInset = 4.0f;
float buttonGap = 6.0f;
float buttonPaddingX = 14.0f;
float estimatedGlyphWidth = 7.0f;
float labelInsetY = -1.0f;
float barCornerRounding = 8.0f;
float buttonCornerRounding = 6.0f;
float baseBorderThickness = 1.0f;
float focusedBorderThickness = 2.0f;
float openBorderThickness = 1.5f;
};
struct UIEditorMenuBarPalette {
::XCEngine::UI::UIColor barColor =
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.19f, 1.0f);
::XCEngine::UI::UIColor buttonColor =
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
::XCEngine::UI::UIColor buttonHoveredColor =
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
::XCEngine::UI::UIColor buttonOpenColor =
::XCEngine::UI::UIColor(0.33f, 0.35f, 0.38f, 1.0f);
::XCEngine::UI::UIColor borderColor =
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
::XCEngine::UI::UIColor focusedBorderColor =
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
::XCEngine::UI::UIColor openBorderColor =
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
::XCEngine::UI::UIColor textPrimary =
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
::XCEngine::UI::UIColor textMuted =
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
::XCEngine::UI::UIColor textDisabled =
::XCEngine::UI::UIColor(0.54f, 0.55f, 0.58f, 1.0f);
};
struct UIEditorMenuBarLayout {
::XCEngine::UI::UIRect bounds = {};
::XCEngine::UI::UIRect contentRect = {};
std::vector<::XCEngine::UI::UIRect> buttonRects = {};
};
enum class UIEditorMenuBarHitTargetKind : std::uint8_t {
None = 0,
BarBackground,
Button
};
struct UIEditorMenuBarHitTarget {
UIEditorMenuBarHitTargetKind kind = UIEditorMenuBarHitTargetKind::None;
std::size_t index = UIEditorMenuBarInvalidIndex;
};
float ResolveUIEditorMenuBarDesiredButtonWidth(
const UIEditorMenuBarItem& item,
const UIEditorMenuBarMetrics& metrics = {});
UIEditorMenuBarLayout BuildUIEditorMenuBarLayout(
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorMenuBarItem>& items,
const UIEditorMenuBarMetrics& metrics = {});
UIEditorMenuBarHitTarget HitTestUIEditorMenuBar(
const UIEditorMenuBarLayout& layout,
const ::XCEngine::UI::UIPoint& point);
void AppendUIEditorMenuBarBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorMenuBarLayout& layout,
const std::vector<UIEditorMenuBarItem>& items,
const UIEditorMenuBarState& state,
const UIEditorMenuBarPalette& palette = {},
const UIEditorMenuBarMetrics& metrics = {});
void AppendUIEditorMenuBarForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorMenuBarLayout& layout,
const std::vector<UIEditorMenuBarItem>& items,
const UIEditorMenuBarState& state,
const UIEditorMenuBarPalette& palette = {},
const UIEditorMenuBarMetrics& metrics = {});
void AppendUIEditorMenuBar(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorMenuBarItem>& items,
const UIEditorMenuBarState& state,
const UIEditorMenuBarPalette& palette = {},
const UIEditorMenuBarMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,116 @@
#pragma once
#include <XCEditor/Foundation/UIEditorCommandDispatcher.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
class UIEditorShortcutManager;
enum class UIEditorMenuItemKind : std::uint8_t {
Command = 0,
Separator,
Submenu
};
enum class UIEditorMenuCheckedStateSource : std::uint8_t {
None = 0,
PanelOpen,
PanelVisible,
PanelActive
};
struct UIEditorMenuCheckedStateBinding {
UIEditorMenuCheckedStateSource source = UIEditorMenuCheckedStateSource::None;
std::string panelId = {};
};
struct UIEditorMenuItemDescriptor {
UIEditorMenuItemKind kind = UIEditorMenuItemKind::Command;
std::string itemId = {};
std::string label = {};
std::string commandId = {};
UIEditorMenuCheckedStateBinding checkedState = {};
std::vector<UIEditorMenuItemDescriptor> children = {};
};
struct UIEditorMenuDescriptor {
std::string menuId = {};
std::string label = {};
std::vector<UIEditorMenuItemDescriptor> items = {};
};
struct UIEditorMenuModel {
std::vector<UIEditorMenuDescriptor> menus = {};
};
enum class UIEditorMenuModelValidationCode : std::uint8_t {
None = 0,
InvalidCommandRegistry,
EmptyMenuId,
EmptyMenuLabel,
DuplicateMenuId,
EmptyCommandId,
UnknownCommandId,
MissingItemLabel,
CommandItemHasChildren,
SubmenuMissingLabel,
SubmenuEmptyChildren,
SubmenuHasCommandId,
SeparatorHasCommandId,
SeparatorHasChildren,
UnexpectedCheckedState,
MissingCheckedStatePanelId
};
struct UIEditorMenuModelValidationResult {
UIEditorMenuModelValidationCode code = UIEditorMenuModelValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorMenuModelValidationCode::None;
}
};
struct UIEditorResolvedMenuItem {
UIEditorMenuItemKind kind = UIEditorMenuItemKind::Command;
std::string itemId = {};
std::string label = {};
std::string commandId = {};
std::string commandDisplayName = {};
std::string shortcutText = {};
bool enabled = true;
bool checked = false;
UIEditorWorkspaceCommandStatus previewStatus =
UIEditorWorkspaceCommandStatus::Rejected;
std::string message = {};
std::vector<UIEditorResolvedMenuItem> children = {};
};
struct UIEditorResolvedMenuDescriptor {
std::string menuId = {};
std::string label = {};
std::vector<UIEditorResolvedMenuItem> items = {};
};
struct UIEditorResolvedMenuModel {
std::vector<UIEditorResolvedMenuDescriptor> menus = {};
};
std::string_view GetUIEditorMenuItemKindName(UIEditorMenuItemKind kind);
UIEditorMenuModelValidationResult ValidateUIEditorMenuModel(
const UIEditorMenuModel& model,
const UIEditorCommandRegistry& commandRegistry);
UIEditorResolvedMenuModel BuildUIEditorResolvedMenuModel(
const UIEditorMenuModel& model,
const UIEditorCommandDispatcher& commandDispatcher,
const UIEditorWorkspaceController& controller,
const UIEditorShortcutManager* shortcutManager = nullptr);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,136 @@
#pragma once
#include <XCEditor/Shell/UIEditorMenuModel.h>
#include <XCEngine/UI/DrawData.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor::Widgets {
inline constexpr std::size_t UIEditorMenuPopupInvalidIndex =
static_cast<std::size_t>(-1);
struct UIEditorMenuPopupItem {
std::string itemId = {};
::XCEngine::UI::Editor::UIEditorMenuItemKind kind =
::XCEngine::UI::Editor::UIEditorMenuItemKind::Command;
std::string label = {};
std::string shortcutText = {};
bool enabled = true;
bool checked = false;
bool hasSubmenu = false;
float desiredLabelWidth = 0.0f;
float desiredShortcutWidth = 0.0f;
};
struct UIEditorMenuPopupState {
std::size_t hoveredIndex = UIEditorMenuPopupInvalidIndex;
std::size_t submenuOpenIndex = UIEditorMenuPopupInvalidIndex;
bool focused = false;
};
struct UIEditorMenuPopupMetrics {
float contentPaddingX = 6.0f;
float contentPaddingY = 6.0f;
float itemHeight = 28.0f;
float separatorHeight = 9.0f;
float checkColumnWidth = 18.0f;
float shortcutGap = 20.0f;
float submenuIndicatorWidth = 14.0f;
float rowCornerRounding = 5.0f;
float popupCornerRounding = 8.0f;
float labelInsetX = 14.0f;
float labelInsetY = -1.0f;
float labelFontSize = 13.0f;
float shortcutInsetRight = 24.0f;
float estimatedGlyphWidth = 7.0f;
float glyphFontSize = 12.0f;
float separatorThickness = 1.0f;
float borderThickness = 1.0f;
};
struct UIEditorMenuPopupPalette {
::XCEngine::UI::UIColor popupColor =
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.17f, 1.0f);
::XCEngine::UI::UIColor borderColor =
::XCEngine::UI::UIColor(0.31f, 0.31f, 0.31f, 1.0f);
::XCEngine::UI::UIColor itemHoverColor =
::XCEngine::UI::UIColor(0.28f, 0.28f, 0.28f, 1.0f);
::XCEngine::UI::UIColor itemOpenColor =
::XCEngine::UI::UIColor(0.34f, 0.34f, 0.34f, 1.0f);
::XCEngine::UI::UIColor separatorColor =
::XCEngine::UI::UIColor(0.32f, 0.32f, 0.32f, 1.0f);
::XCEngine::UI::UIColor textPrimary =
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
::XCEngine::UI::UIColor textMuted =
::XCEngine::UI::UIColor(0.76f, 0.76f, 0.76f, 1.0f);
::XCEngine::UI::UIColor textDisabled =
::XCEngine::UI::UIColor(0.50f, 0.50f, 0.50f, 1.0f);
::XCEngine::UI::UIColor glyphColor =
::XCEngine::UI::UIColor(0.90f, 0.90f, 0.90f, 1.0f);
};
struct UIEditorMenuPopupLayout {
::XCEngine::UI::UIRect popupRect = {};
::XCEngine::UI::UIRect contentRect = {};
std::vector<::XCEngine::UI::UIRect> itemRects = {};
};
enum class UIEditorMenuPopupHitTargetKind : std::uint8_t {
None = 0,
PopupSurface,
Item
};
struct UIEditorMenuPopupHitTarget {
UIEditorMenuPopupHitTargetKind kind = UIEditorMenuPopupHitTargetKind::None;
std::size_t index = UIEditorMenuPopupInvalidIndex;
};
float ResolveUIEditorMenuPopupDesiredWidth(
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupMetrics& metrics = {});
float MeasureUIEditorMenuPopupHeight(
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupMetrics& metrics = {});
UIEditorMenuPopupLayout BuildUIEditorMenuPopupLayout(
const ::XCEngine::UI::UIRect& popupRect,
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupMetrics& metrics = {});
UIEditorMenuPopupHitTarget HitTestUIEditorMenuPopup(
const UIEditorMenuPopupLayout& layout,
const std::vector<UIEditorMenuPopupItem>& items,
const ::XCEngine::UI::UIPoint& point);
void AppendUIEditorMenuPopupBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorMenuPopupLayout& layout,
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupState& state,
const UIEditorMenuPopupPalette& palette = {},
const UIEditorMenuPopupMetrics& metrics = {});
void AppendUIEditorMenuPopupForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorMenuPopupLayout& layout,
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupState& state,
const UIEditorMenuPopupPalette& palette = {},
const UIEditorMenuPopupMetrics& metrics = {});
void AppendUIEditorMenuPopup(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& popupRect,
const std::vector<UIEditorMenuPopupItem>& items,
const UIEditorMenuPopupState& state,
const UIEditorMenuPopupPalette& palette = {},
const UIEditorMenuPopupMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,106 @@
#pragma once
#include <XCEngine/UI/Input/UIInputPath.h>
#include <XCEngine/UI/Widgets/UIPopupOverlayModel.h>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorMenuPopupState {
std::string popupId = {};
std::string menuId = {};
std::string itemId = {};
[[nodiscard]] bool IsRootPopup() const {
return itemId.empty();
}
};
struct UIEditorMenuSessionMutationResult {
bool changed = false;
std::string openRootMenuId = {};
std::string openedPopupId = {};
std::vector<std::string> closedPopupIds = {};
::XCEngine::UI::Widgets::UIPopupDismissReason dismissReason =
::XCEngine::UI::Widgets::UIPopupDismissReason::None;
[[nodiscard]] bool HasOpenMenu() const {
return !openRootMenuId.empty();
}
};
class UIEditorMenuSession {
public:
const ::XCEngine::UI::Widgets::UIPopupOverlayModel& GetPopupOverlayModel() const {
return m_popupOverlayModel;
}
const std::vector<UIEditorMenuPopupState>& GetPopupStates() const {
return m_popupStates;
}
const std::vector<std::string>& GetOpenSubmenuItemIds() const {
return m_openSubmenuItemIds;
}
std::string_view GetOpenRootMenuId() const {
return m_openRootMenuId;
}
[[nodiscard]] bool HasOpenMenu() const {
return !m_openRootMenuId.empty();
}
[[nodiscard]] bool IsMenuOpen(std::string_view menuId) const {
return !m_openRootMenuId.empty() && m_openRootMenuId == menuId;
}
[[nodiscard]] bool IsPopupOpen(std::string_view popupId) const;
const UIEditorMenuPopupState* FindPopupState(std::string_view popupId) const;
void Reset();
UIEditorMenuSessionMutationResult OpenRootMenu(
std::string_view menuId,
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
UIEditorMenuSessionMutationResult OpenMenuBarRoot(
std::string_view menuId,
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
UIEditorMenuSessionMutationResult HoverMenuBarRoot(
std::string_view menuId,
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
UIEditorMenuSessionMutationResult HoverSubmenu(
std::string_view itemId,
::XCEngine::UI::Widgets::UIPopupOverlayEntry entry);
UIEditorMenuSessionMutationResult CloseAll(
::XCEngine::UI::Widgets::UIPopupDismissReason dismissReason =
::XCEngine::UI::Widgets::UIPopupDismissReason::Programmatic);
UIEditorMenuSessionMutationResult DismissFromEscape();
UIEditorMenuSessionMutationResult DismissFromPointerDown(
const UIInputPath& hitPath);
UIEditorMenuSessionMutationResult DismissFromFocusLoss(
const UIInputPath& focusedPath);
private:
UIEditorMenuSessionMutationResult BuildResult(
const ::XCEngine::UI::Widgets::UIPopupOverlayMutationResult& mutation) const;
void RemoveClosedPopupStates(const std::vector<std::string>& closedPopupIds);
void RebuildDerivedState();
std::string m_openRootMenuId = {};
::XCEngine::UI::Widgets::UIPopupOverlayModel m_popupOverlayModel = {};
std::vector<UIEditorMenuPopupState> m_popupStates = {};
std::vector<std::string> m_openSubmenuItemIds = {};
};
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,88 @@
#pragma once
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
#include <XCEditor/Shell/UIEditorDockHost.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
enum class UIEditorPanelContentHostEventKind : std::uint8_t {
Mounted = 0,
Unmounted,
BoundsChanged
};
std::string_view GetUIEditorPanelContentHostEventKindName(
UIEditorPanelContentHostEventKind kind);
bool IsUIEditorPanelPresentationExternallyHosted(UIEditorPanelPresentationKind kind);
struct UIEditorPanelContentHostBinding {
std::string panelId = {};
UIEditorPanelPresentationKind kind = UIEditorPanelPresentationKind::Placeholder;
};
struct UIEditorPanelContentHostMountRequest {
std::string panelId = {};
UIEditorPanelPresentationKind kind = UIEditorPanelPresentationKind::Placeholder;
::XCEngine::UI::UIRect bounds = {};
};
struct UIEditorPanelContentHostRequest {
std::vector<UIEditorPanelContentHostMountRequest> mountRequests = {};
};
struct UIEditorPanelContentHostPanelState {
std::string panelId = {};
UIEditorPanelPresentationKind kind = UIEditorPanelPresentationKind::Placeholder;
bool mounted = false;
::XCEngine::UI::UIRect bounds = {};
};
struct UIEditorPanelContentHostState {
std::vector<UIEditorPanelContentHostPanelState> panelStates = {};
};
struct UIEditorPanelContentHostEvent {
UIEditorPanelContentHostEventKind kind = UIEditorPanelContentHostEventKind::Mounted;
std::string panelId = {};
UIEditorPanelPresentationKind presentationKind = UIEditorPanelPresentationKind::Placeholder;
::XCEngine::UI::UIRect bounds = {};
};
struct UIEditorPanelContentHostFrame {
std::vector<UIEditorPanelContentHostPanelState> panelStates = {};
std::vector<UIEditorPanelContentHostEvent> events = {};
};
const UIEditorPanelContentHostMountRequest* FindUIEditorPanelContentHostMountRequest(
const UIEditorPanelContentHostRequest& request,
std::string_view panelId);
const UIEditorPanelContentHostPanelState* FindUIEditorPanelContentHostPanelState(
const UIEditorPanelContentHostState& state,
std::string_view panelId);
const UIEditorPanelContentHostPanelState* FindUIEditorPanelContentHostPanelState(
const UIEditorPanelContentHostFrame& frame,
std::string_view panelId);
UIEditorPanelContentHostRequest ResolveUIEditorPanelContentHostRequest(
const Widgets::UIEditorDockHostLayout& dockHostLayout,
const UIEditorPanelRegistry& panelRegistry,
const std::vector<UIEditorPanelContentHostBinding>& bindings);
UIEditorPanelContentHostFrame UpdateUIEditorPanelContentHost(
UIEditorPanelContentHostState& state,
const UIEditorPanelContentHostRequest& request,
const UIEditorPanelRegistry& panelRegistry,
const std::vector<UIEditorPanelContentHostBinding>& bindings);
std::vector<std::string> CollectMountedUIEditorPanelContentHostPanelIds(
const UIEditorPanelContentHostFrame& frame);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,160 @@
#pragma once
#include <XCEngine/UI/DrawData.h>
#include <cstdint>
#include <string_view>
namespace XCEngine::UI::Editor::Widgets {
enum class UIEditorPanelFrameAction : std::uint8_t {
None = 0,
Pin,
Close
};
enum class UIEditorPanelFrameHitTarget : std::uint8_t {
None = 0,
Header,
Body,
Footer,
PinButton,
CloseButton
};
struct UIEditorPanelFrameState {
bool active = false;
bool hovered = false;
bool focused = false;
bool pinned = false;
bool closable = true;
bool pinnable = true;
bool showFooter = false;
bool pinHovered = false;
bool closeHovered = false;
};
struct UIEditorPanelFrameText {
std::string_view title = {};
std::string_view subtitle = {};
std::string_view footer = {};
};
struct UIEditorPanelFrameMetrics {
float cornerRounding = 8.0f;
float headerHeight = 36.0f;
float footerHeight = 24.0f;
float contentPadding = 12.0f;
float titleInsetX = 14.0f;
float titleInsetY = 9.0f;
float subtitleInsetY = 22.0f;
float footerInsetX = 14.0f;
float footerInsetY = 6.0f;
float actionButtonExtent = 18.0f;
float actionInsetX = 12.0f;
float actionGap = 6.0f;
float baseBorderThickness = 1.0f;
float hoveredBorderThickness = 1.25f;
float activeBorderThickness = 1.5f;
float focusedBorderThickness = 2.0f;
};
struct UIEditorPanelFramePalette {
::XCEngine::UI::UIColor surfaceColor =
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
::XCEngine::UI::UIColor headerColor =
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.19f, 1.0f);
::XCEngine::UI::UIColor footerColor =
::XCEngine::UI::UIColor(0.17f, 0.17f, 0.18f, 1.0f);
::XCEngine::UI::UIColor borderColor =
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
::XCEngine::UI::UIColor hoveredBorderColor =
::XCEngine::UI::UIColor(0.39f, 0.41f, 0.43f, 1.0f);
::XCEngine::UI::UIColor activeBorderColor =
::XCEngine::UI::UIColor(0.50f, 0.52f, 0.56f, 1.0f);
::XCEngine::UI::UIColor focusedBorderColor =
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
::XCEngine::UI::UIColor textPrimary =
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
::XCEngine::UI::UIColor textSecondary =
::XCEngine::UI::UIColor(0.70f, 0.72f, 0.74f, 1.0f);
::XCEngine::UI::UIColor textMuted =
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
::XCEngine::UI::UIColor actionButtonColor =
::XCEngine::UI::UIColor(0.21f, 0.22f, 0.24f, 1.0f);
::XCEngine::UI::UIColor actionButtonHoveredColor =
::XCEngine::UI::UIColor(0.27f, 0.28f, 0.30f, 1.0f);
::XCEngine::UI::UIColor actionButtonSelectedColor =
::XCEngine::UI::UIColor(0.33f, 0.35f, 0.38f, 1.0f);
::XCEngine::UI::UIColor actionButtonBorderColor =
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
::XCEngine::UI::UIColor actionGlyphColor =
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
};
struct UIEditorPanelFrameLayout {
::XCEngine::UI::UIRect frameRect = {};
::XCEngine::UI::UIRect headerRect = {};
::XCEngine::UI::UIRect bodyRect = {};
::XCEngine::UI::UIRect footerRect = {};
::XCEngine::UI::UIRect pinButtonRect = {};
::XCEngine::UI::UIRect closeButtonRect = {};
bool hasFooter = false;
bool showPinButton = false;
bool showCloseButton = false;
};
bool IsUIEditorPanelFramePointInside(
const ::XCEngine::UI::UIRect& rect,
const ::XCEngine::UI::UIPoint& point);
bool IsUIEditorPanelFramePinButtonVisible(const UIEditorPanelFrameState& state);
bool IsUIEditorPanelFrameCloseButtonVisible(const UIEditorPanelFrameState& state);
UIEditorPanelFrameLayout BuildUIEditorPanelFrameLayout(
const ::XCEngine::UI::UIRect& frameRect,
const UIEditorPanelFrameState& state,
const UIEditorPanelFrameMetrics& metrics = {});
::XCEngine::UI::UIColor ResolveUIEditorPanelFrameBorderColor(
const UIEditorPanelFrameState& state,
const UIEditorPanelFramePalette& palette = {});
float ResolveUIEditorPanelFrameBorderThickness(
const UIEditorPanelFrameState& state,
const UIEditorPanelFrameMetrics& metrics = {});
UIEditorPanelFrameAction HitTestUIEditorPanelFrameAction(
const UIEditorPanelFrameLayout& layout,
const UIEditorPanelFrameState& state,
const ::XCEngine::UI::UIPoint& point);
UIEditorPanelFrameHitTarget HitTestUIEditorPanelFrame(
const UIEditorPanelFrameLayout& layout,
const UIEditorPanelFrameState& state,
const ::XCEngine::UI::UIPoint& point);
void AppendUIEditorPanelFrameBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorPanelFrameLayout& layout,
const UIEditorPanelFrameState& state,
const UIEditorPanelFramePalette& palette = {},
const UIEditorPanelFrameMetrics& metrics = {});
void AppendUIEditorPanelFrameForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorPanelFrameLayout& layout,
const UIEditorPanelFrameState& state,
const UIEditorPanelFrameText& text,
const UIEditorPanelFramePalette& palette = {},
const UIEditorPanelFrameMetrics& metrics = {});
void AppendUIEditorPanelFrame(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& frameRect,
const UIEditorPanelFrameState& state,
const UIEditorPanelFrameText& text,
const UIEditorPanelFramePalette& palette = {},
const UIEditorPanelFrameMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,68 @@
#pragma once
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
enum class UIEditorPanelHostLifecycleEventKind : std::uint8_t {
Attached = 0,
Detached,
Shown,
Hidden,
Activated,
Deactivated,
FocusGained,
FocusLost
};
std::string_view GetUIEditorPanelHostLifecycleEventKindName(
UIEditorPanelHostLifecycleEventKind kind);
struct UIEditorPanelHostState {
std::string panelId = {};
bool attached = false;
bool visible = false;
bool active = false;
bool focused = false;
};
struct UIEditorPanelHostLifecycleEvent {
UIEditorPanelHostLifecycleEventKind kind = UIEditorPanelHostLifecycleEventKind::Attached;
std::string panelId = {};
};
struct UIEditorPanelHostLifecycleState {
std::vector<UIEditorPanelHostState> panelStates = {};
};
struct UIEditorPanelHostLifecycleRequest {
std::string focusedPanelId = {};
};
struct UIEditorPanelHostLifecycleFrame {
std::vector<UIEditorPanelHostState> panelStates = {};
std::vector<UIEditorPanelHostLifecycleEvent> events = {};
};
const UIEditorPanelHostState* FindUIEditorPanelHostState(
const UIEditorPanelHostLifecycleState& state,
std::string_view panelId);
const UIEditorPanelHostState* FindUIEditorPanelHostState(
const UIEditorPanelHostLifecycleFrame& frame,
std::string_view panelId);
UIEditorPanelHostLifecycleFrame UpdateUIEditorPanelHostLifecycle(
UIEditorPanelHostLifecycleState& state,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorPanelHostLifecycleRequest& request = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,54 @@
#pragma once
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
enum class UIEditorPanelPresentationKind : std::uint8_t {
Placeholder = 0,
ViewportShell,
HostedContent
};
struct UIEditorPanelDescriptor {
std::string panelId = {};
std::string defaultTitle = {};
UIEditorPanelPresentationKind presentationKind = UIEditorPanelPresentationKind::Placeholder;
bool placeholder = true;
bool canHide = true;
bool canClose = true;
};
struct UIEditorPanelRegistry {
std::vector<UIEditorPanelDescriptor> panels = {};
};
enum class UIEditorPanelRegistryValidationCode : std::uint8_t {
None = 0,
EmptyPanelId,
EmptyDefaultTitle,
DuplicatePanelId
};
struct UIEditorPanelRegistryValidationResult {
UIEditorPanelRegistryValidationCode code = UIEditorPanelRegistryValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorPanelRegistryValidationCode::None;
}
};
UIEditorPanelRegistry BuildDefaultEditorShellPanelRegistry();
const UIEditorPanelDescriptor* FindUIEditorPanelDescriptor(
const UIEditorPanelRegistry& registry,
std::string_view panelId);
UIEditorPanelRegistryValidationResult ValidateUIEditorPanelRegistry(
const UIEditorPanelRegistry& registry);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,97 @@
#pragma once
#include <XCEditor/Shell/UIEditorWorkspaceCompose.h>
#include <XCEditor/Shell/UIEditorMenuBar.h>
#include <XCEditor/Shell/UIEditorStatusBar.h>
namespace XCEngine::UI::Editor {
struct UIEditorShellComposeModel {
std::vector<Widgets::UIEditorMenuBarItem> menuBarItems = {};
std::vector<Widgets::UIEditorStatusBarSegment> statusSegments = {};
std::vector<UIEditorWorkspacePanelPresentationModel> workspacePresentations = {};
};
struct UIEditorShellComposeState {
Widgets::UIEditorMenuBarState menuBarState = {};
UIEditorWorkspaceComposeState workspaceState = {};
Widgets::UIEditorStatusBarState statusBarState = {};
};
struct UIEditorShellComposeMetrics {
float outerPadding = 12.0f;
float sectionGap = 8.0f;
float surfaceCornerRounding = 10.0f;
Widgets::UIEditorMenuBarMetrics menuBarMetrics = {};
Widgets::UIEditorDockHostMetrics dockHostMetrics = {};
Widgets::UIEditorViewportSlotMetrics viewportMetrics = {};
Widgets::UIEditorStatusBarMetrics statusBarMetrics = {};
};
struct UIEditorShellComposePalette {
::XCEngine::UI::UIColor surfaceColor =
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
::XCEngine::UI::UIColor surfaceBorderColor =
::XCEngine::UI::UIColor(0.27f, 0.27f, 0.27f, 1.0f);
Widgets::UIEditorMenuBarPalette menuBarPalette = {};
Widgets::UIEditorDockHostPalette dockHostPalette = {};
Widgets::UIEditorViewportSlotPalette viewportPalette = {};
Widgets::UIEditorStatusBarPalette statusBarPalette = {};
};
struct UIEditorShellComposeLayout {
::XCEngine::UI::UIRect bounds = {};
::XCEngine::UI::UIRect contentRect = {};
::XCEngine::UI::UIRect menuBarRect = {};
::XCEngine::UI::UIRect workspaceRect = {};
::XCEngine::UI::UIRect statusBarRect = {};
Widgets::UIEditorMenuBarLayout menuBarLayout = {};
Widgets::UIEditorStatusBarLayout statusBarLayout = {};
};
struct UIEditorShellComposeRequest {
UIEditorShellComposeLayout layout = {};
UIEditorWorkspaceComposeRequest workspaceRequest = {};
};
struct UIEditorShellComposeFrame {
UIEditorShellComposeLayout layout = {};
UIEditorWorkspaceComposeFrame workspaceFrame = {};
};
UIEditorShellComposeLayout BuildUIEditorShellComposeLayout(
const ::XCEngine::UI::UIRect& bounds,
const std::vector<Widgets::UIEditorMenuBarItem>& menuBarItems,
const std::vector<Widgets::UIEditorStatusBarSegment>& statusSegments,
const UIEditorShellComposeMetrics& metrics = {});
UIEditorShellComposeRequest ResolveUIEditorShellComposeRequest(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorShellComposeModel& model,
const Widgets::UIEditorDockHostState& dockHostState = {},
const UIEditorShellComposeState& state = {},
const UIEditorShellComposeMetrics& metrics = {});
UIEditorShellComposeFrame UpdateUIEditorShellCompose(
UIEditorShellComposeState& state,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const UIEditorShellComposeModel& model,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorDockHostState& dockHostState = {},
const UIEditorShellComposeMetrics& metrics = {});
void AppendUIEditorShellCompose(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorShellComposeFrame& frame,
const UIEditorShellComposeModel& model,
const UIEditorShellComposeState& state,
const UIEditorShellComposePalette& palette = {},
const UIEditorShellComposeMetrics& metrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,189 @@
#pragma once
#include <XCEditor/Shell/UIEditorMenuModel.h>
#include <XCEditor/Shell/UIEditorMenuSession.h>
#include <XCEditor/Shell/UIEditorShellCompose.h>
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
#include <XCEditor/Shell/UIEditorWorkspaceInteraction.h>
#include <XCEditor/Shell/UIEditorMenuPopup.h>
#include <XCEngine/UI/DrawData.h>
#include <string>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorShellInteractionDefinition {
UIEditorMenuModel menuModel = {};
std::vector<Widgets::UIEditorStatusBarSegment> statusSegments = {};
std::vector<UIEditorWorkspacePanelPresentationModel> workspacePresentations = {};
};
struct UIEditorShellInteractionModel {
UIEditorResolvedMenuModel resolvedMenuModel = {};
std::vector<Widgets::UIEditorStatusBarSegment> statusSegments = {};
std::vector<UIEditorWorkspacePanelPresentationModel> workspacePresentations = {};
};
struct UIEditorShellInteractionState {
UIEditorShellComposeState composeState = {};
UIEditorMenuSession menuSession = {};
UIEditorWorkspaceInteractionState workspaceInteractionState = {};
::XCEngine::UI::UIPoint pointerPosition = {};
bool focused = false;
bool hasPointerPosition = false;
};
struct UIEditorShellInteractionMetrics {
UIEditorShellComposeMetrics shellMetrics = {};
Widgets::UIEditorMenuPopupMetrics popupMetrics = {};
};
struct UIEditorShellInteractionPalette {
UIEditorShellComposePalette shellPalette = {};
Widgets::UIEditorMenuPopupPalette popupPalette = {};
};
struct UIEditorShellInteractionServices {
const UIEditorCommandDispatcher* commandDispatcher = nullptr;
const UIEditorShortcutManager* shortcutManager = nullptr;
};
struct UIEditorShellInteractionMenuButtonRequest {
std::string menuId = {};
std::string label = {};
std::string popupId = {};
::XCEngine::UI::UIRect rect = {};
::XCEngine::UI::UIInputPath path = {};
bool enabled = true;
};
struct UIEditorShellInteractionPopupItemRequest {
std::string popupId = {};
std::string menuId = {};
std::string itemId = {};
std::string label = {};
std::string commandId = {};
std::string childPopupId = {};
::XCEngine::UI::UIRect rect = {};
::XCEngine::UI::UIInputPath path = {};
UIEditorMenuItemKind kind = UIEditorMenuItemKind::Command;
bool enabled = false;
bool checked = false;
bool hasSubmenu = false;
};
struct UIEditorShellInteractionPopupRequest {
std::string popupId = {};
std::string menuId = {};
std::string sourceItemId = {};
::XCEngine::UI::Widgets::UIPopupOverlayEntry overlayEntry = {};
::XCEngine::UI::Widgets::UIPopupPlacementResult placement = {};
Widgets::UIEditorMenuPopupLayout layout = {};
std::vector<UIEditorResolvedMenuItem> resolvedItems = {};
std::vector<Widgets::UIEditorMenuPopupItem> widgetItems = {};
std::vector<UIEditorShellInteractionPopupItemRequest> itemRequests = {};
};
struct UIEditorShellInteractionRequest {
UIEditorShellComposeRequest shellRequest = {};
std::vector<Widgets::UIEditorMenuBarItem> menuBarItems = {};
std::vector<UIEditorShellInteractionMenuButtonRequest> menuButtons = {};
std::vector<UIEditorShellInteractionPopupRequest> popupRequests = {};
};
struct UIEditorShellInteractionResult {
bool consumed = false;
bool menuModal = false;
bool workspaceInputSuppressed = false;
bool requestPointerCapture = false;
bool releasePointerCapture = false;
bool viewportInteractionChanged = false;
bool commandTriggered = false;
bool commandDispatched = false;
std::string menuId = {};
std::string popupId = {};
std::string itemId = {};
std::string commandId = {};
std::string viewportPanelId = {};
UIEditorViewportInputBridgeFrame viewportInputFrame = {};
UIEditorMenuSessionMutationResult menuMutation = {};
UIEditorCommandDispatchResult commandDispatchResult = {};
UIEditorWorkspaceInteractionResult workspaceResult = {};
};
struct UIEditorShellInteractionPopupFrame {
std::string popupId = {};
Widgets::UIEditorMenuPopupState popupState = {};
};
struct UIEditorShellInteractionFrame {
UIEditorShellInteractionModel model = {};
UIEditorShellInteractionRequest request = {};
UIEditorShellComposeFrame shellFrame = {};
UIEditorWorkspaceInteractionFrame workspaceInteractionFrame = {};
std::vector<UIEditorShellInteractionPopupFrame> popupFrames = {};
UIEditorShellInteractionResult result = {};
std::string openRootMenuId = {};
std::string hoveredMenuId = {};
std::string hoveredPopupId = {};
std::string hoveredItemId = {};
bool focused = false;
};
UIEditorShellInteractionModel ResolveUIEditorShellInteractionModel(
const UIEditorWorkspaceController& controller,
const UIEditorShellInteractionDefinition& definition,
const UIEditorShellInteractionServices& services = {});
UIEditorShellInteractionRequest ResolveUIEditorShellInteractionRequest(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorWorkspaceController& controller,
const UIEditorShellInteractionModel& model,
const UIEditorShellInteractionState& state = {},
const UIEditorShellInteractionMetrics& metrics = {},
const UIEditorShellInteractionServices& services = {});
UIEditorShellInteractionFrame UpdateUIEditorShellInteraction(
UIEditorShellInteractionState& state,
UIEditorWorkspaceController& controller,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorShellInteractionModel& model,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const UIEditorShellInteractionServices& services = {},
const UIEditorShellInteractionMetrics& metrics = {});
UIEditorShellInteractionRequest ResolveUIEditorShellInteractionRequest(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorWorkspaceController& controller,
const UIEditorShellInteractionDefinition& definition,
const UIEditorShellInteractionState& state = {},
const UIEditorShellInteractionMetrics& metrics = {},
const UIEditorShellInteractionServices& services = {});
UIEditorShellInteractionFrame UpdateUIEditorShellInteraction(
UIEditorShellInteractionState& state,
UIEditorWorkspaceController& controller,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorShellInteractionDefinition& definition,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const UIEditorShellInteractionServices& services = {},
const UIEditorShellInteractionMetrics& metrics = {});
void AppendUIEditorShellInteraction(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorShellInteractionFrame& frame,
const UIEditorShellInteractionModel& model,
const UIEditorShellInteractionState& state,
const UIEditorShellInteractionPalette& palette = {},
const UIEditorShellInteractionMetrics& metrics = {});
void AppendUIEditorShellInteraction(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorShellInteractionFrame& frame,
const UIEditorShellInteractionState& state,
const UIEditorShellInteractionPalette& palette = {},
const UIEditorShellInteractionMetrics& metrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,144 @@
#pragma once
#include <XCEngine/UI/DrawData.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor::Widgets {
inline constexpr std::size_t UIEditorStatusBarInvalidIndex =
static_cast<std::size_t>(-1);
enum class UIEditorStatusBarSlot : std::uint8_t {
Leading = 0,
Trailing
};
enum class UIEditorStatusBarTextTone : std::uint8_t {
Primary = 0,
Muted,
Accent
};
enum class UIEditorStatusBarHitTargetKind : std::uint8_t {
None = 0,
Background,
Segment,
Separator
};
struct UIEditorStatusBarSegment {
std::string segmentId = {};
std::string label = {};
UIEditorStatusBarSlot slot = UIEditorStatusBarSlot::Leading;
UIEditorStatusBarTextTone tone = UIEditorStatusBarTextTone::Primary;
bool interactive = true;
bool showSeparator = false;
float desiredWidth = 0.0f;
};
struct UIEditorStatusBarState {
std::size_t hoveredIndex = UIEditorStatusBarInvalidIndex;
std::size_t activeIndex = UIEditorStatusBarInvalidIndex;
bool focused = false;
};
struct UIEditorStatusBarMetrics {
float barHeight = 28.0f;
float outerPaddingX = 10.0f;
float segmentPaddingX = 10.0f;
float segmentPaddingY = 6.0f;
float segmentGap = 4.0f;
float separatorWidth = 1.0f;
float separatorInsetY = 6.0f;
float slotGapMin = 18.0f;
float cornerRounding = 8.0f;
float estimatedGlyphWidth = 7.0f;
float borderThickness = 1.0f;
float focusedBorderThickness = 2.0f;
};
struct UIEditorStatusBarPalette {
::XCEngine::UI::UIColor surfaceColor =
::XCEngine::UI::UIColor(0.15f, 0.15f, 0.16f, 1.0f);
::XCEngine::UI::UIColor borderColor =
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.34f, 1.0f);
::XCEngine::UI::UIColor focusedBorderColor =
::XCEngine::UI::UIColor(0.78f, 0.80f, 0.84f, 1.0f);
::XCEngine::UI::UIColor segmentColor =
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.21f, 1.0f);
::XCEngine::UI::UIColor segmentHoveredColor =
::XCEngine::UI::UIColor(0.24f, 0.26f, 0.28f, 1.0f);
::XCEngine::UI::UIColor segmentActiveColor =
::XCEngine::UI::UIColor(0.30f, 0.32f, 0.35f, 1.0f);
::XCEngine::UI::UIColor segmentBorderColor =
::XCEngine::UI::UIColor(0.42f, 0.44f, 0.47f, 1.0f);
::XCEngine::UI::UIColor separatorColor =
::XCEngine::UI::UIColor(0.32f, 0.34f, 0.36f, 1.0f);
::XCEngine::UI::UIColor textPrimary =
::XCEngine::UI::UIColor(0.93f, 0.94f, 0.96f, 1.0f);
::XCEngine::UI::UIColor textMuted =
::XCEngine::UI::UIColor(0.58f, 0.59f, 0.62f, 1.0f);
::XCEngine::UI::UIColor textAccent =
::XCEngine::UI::UIColor(0.82f, 0.86f, 0.93f, 1.0f);
};
struct UIEditorStatusBarLayout {
::XCEngine::UI::UIRect bounds = {};
::XCEngine::UI::UIRect leadingSlotRect = {};
::XCEngine::UI::UIRect trailingSlotRect = {};
std::vector<::XCEngine::UI::UIRect> segmentRects = {};
std::vector<::XCEngine::UI::UIRect> separatorRects = {};
};
struct UIEditorStatusBarHitTarget {
UIEditorStatusBarHitTargetKind kind = UIEditorStatusBarHitTargetKind::None;
std::size_t index = UIEditorStatusBarInvalidIndex;
};
float ResolveUIEditorStatusBarDesiredSegmentWidth(
const UIEditorStatusBarSegment& segment,
const UIEditorStatusBarMetrics& metrics = {});
UIEditorStatusBarLayout BuildUIEditorStatusBarLayout(
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorStatusBarSegment>& segments,
const UIEditorStatusBarMetrics& metrics = {});
UIEditorStatusBarHitTarget HitTestUIEditorStatusBar(
const UIEditorStatusBarLayout& layout,
const ::XCEngine::UI::UIPoint& point);
::XCEngine::UI::UIColor ResolveUIEditorStatusBarTextColor(
UIEditorStatusBarTextTone tone,
const UIEditorStatusBarPalette& palette = {});
void AppendUIEditorStatusBarBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorStatusBarLayout& layout,
const std::vector<UIEditorStatusBarSegment>& segments,
const UIEditorStatusBarState& state,
const UIEditorStatusBarPalette& palette = {},
const UIEditorStatusBarMetrics& metrics = {});
void AppendUIEditorStatusBarForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorStatusBarLayout& layout,
const std::vector<UIEditorStatusBarSegment>& segments,
const UIEditorStatusBarState& state,
const UIEditorStatusBarPalette& palette = {},
const UIEditorStatusBarMetrics& metrics = {});
void AppendUIEditorStatusBar(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const std::vector<UIEditorStatusBarSegment>& segments,
const UIEditorStatusBarState& state,
const UIEditorStatusBarPalette& palette = {},
const UIEditorStatusBarMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,67 @@
#pragma once
#include <XCEngine/UI/Types.h>
#include <cstdint>
#include <unordered_set>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorViewportInputBridgeConfig {
bool focusOnPointerDownInside = true;
bool clearFocusOnPointerDownOutside = true;
bool capturePointerOnPointerDownInside = true;
};
struct UIEditorViewportInputBridgeState {
bool hovered = false;
bool focused = false;
bool captured = false;
::XCEngine::UI::UIPointerButton captureButton = ::XCEngine::UI::UIPointerButton::None;
::XCEngine::UI::UIPoint lastScreenPointerPosition = {};
::XCEngine::UI::UIPoint lastLocalPointerPosition = {};
bool hasPointerPosition = false;
::XCEngine::UI::UIInputModifiers modifiers = {};
std::unordered_set<std::int32_t> pressedKeys = {};
std::uint8_t pointerButtonsDownMask = 0;
};
struct UIEditorViewportInputBridgeFrame {
bool hovered = false;
bool focused = false;
bool captured = false;
bool pointerInside = false;
bool pointerMoved = false;
bool pointerPressedInside = false;
bool pointerReleasedInside = false;
bool focusGained = false;
bool focusLost = false;
bool captureStarted = false;
bool captureEnded = false;
::XCEngine::UI::UIPointerButton changedPointerButton = ::XCEngine::UI::UIPointerButton::None;
::XCEngine::UI::UIPoint screenPointerPosition = {};
::XCEngine::UI::UIPoint localPointerPosition = {};
::XCEngine::UI::UIPoint pointerDelta = {};
float wheelDelta = 0.0f;
::XCEngine::UI::UIInputModifiers modifiers = {};
std::vector<std::int32_t> pressedKeyCodes = {};
std::vector<std::int32_t> releasedKeyCodes = {};
std::vector<std::uint32_t> characters = {};
};
bool IsUIEditorViewportInputBridgeKeyDown(
const UIEditorViewportInputBridgeState& state,
std::int32_t keyCode);
bool IsUIEditorViewportInputBridgePointerButtonDown(
const UIEditorViewportInputBridgeState& state,
::XCEngine::UI::UIPointerButton button);
UIEditorViewportInputBridgeFrame UpdateUIEditorViewportInputBridge(
UIEditorViewportInputBridgeState& state,
const ::XCEngine::UI::UIRect& inputRect,
const std::vector<::XCEngine::UI::UIInputEvent>& events,
const UIEditorViewportInputBridgeConfig& config = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,57 @@
#pragma once
#include <XCEditor/Shell/UIEditorViewportInputBridge.h>
#include <XCEditor/Shell/UIEditorViewportSlot.h>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorViewportShellVisualState {
std::size_t hoveredToolIndex = Widgets::UIEditorViewportSlotInvalidIndex;
std::size_t activeToolIndex = Widgets::UIEditorViewportSlotInvalidIndex;
Widgets::UIEditorStatusBarState statusBarState = {};
};
struct UIEditorViewportShellSpec {
Widgets::UIEditorViewportSlotChrome chrome = {};
std::vector<Widgets::UIEditorViewportSlotToolItem> toolItems = {};
std::vector<Widgets::UIEditorStatusBarSegment> statusSegments = {};
UIEditorViewportInputBridgeConfig inputBridgeConfig = {};
UIEditorViewportShellVisualState visualState = {};
};
struct UIEditorViewportShellModel {
UIEditorViewportShellSpec spec = {};
Widgets::UIEditorViewportSlotFrame frame = {};
};
struct UIEditorViewportShellRequest {
Widgets::UIEditorViewportSlotLayout slotLayout = {};
::XCEngine::UI::UISize requestedViewportSize = {};
};
struct UIEditorViewportShellState {
UIEditorViewportInputBridgeState inputBridgeState = {};
};
struct UIEditorViewportShellFrame {
Widgets::UIEditorViewportSlotLayout slotLayout = {};
Widgets::UIEditorViewportSlotState slotState = {};
UIEditorViewportInputBridgeFrame inputFrame = {};
::XCEngine::UI::UISize requestedViewportSize = {};
};
UIEditorViewportShellRequest ResolveUIEditorViewportShellRequest(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorViewportShellSpec& spec,
const Widgets::UIEditorViewportSlotMetrics& metrics = {});
UIEditorViewportShellFrame UpdateUIEditorViewportShell(
UIEditorViewportShellState& state,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorViewportShellModel& model,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorViewportSlotMetrics& metrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,203 @@
#pragma once
#include <XCEngine/UI/DrawData.h>
#include <XCEditor/Shell/UIEditorStatusBar.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor::Widgets {
inline constexpr std::size_t UIEditorViewportSlotInvalidIndex =
static_cast<std::size_t>(-1);
enum class UIEditorViewportSlotToolSlot : std::uint8_t {
Leading = 0,
Trailing
};
enum class UIEditorViewportSlotHitTargetKind : std::uint8_t {
None = 0,
TopBar,
Title,
ToolItem,
Surface,
BottomBar,
StatusSegment,
StatusSeparator
};
struct UIEditorViewportSlotFrame {
::XCEngine::UI::UITextureHandle texture = {};
::XCEngine::UI::UISize requestedSize = {};
::XCEngine::UI::UISize presentedSize = {};
bool hasTexture = false;
std::string statusText = {};
};
struct UIEditorViewportSlotChrome {
std::string_view title = {};
std::string_view subtitle = {};
bool showTopBar = true;
bool showBottomBar = true;
float topBarHeight = 40.0f;
float bottomBarHeight = 28.0f;
};
struct UIEditorViewportSlotToolItem {
std::string itemId = {};
std::string label = {};
UIEditorViewportSlotToolSlot slot = UIEditorViewportSlotToolSlot::Trailing;
bool enabled = true;
bool selected = false;
float desiredWidth = 0.0f;
};
struct UIEditorViewportSlotState {
bool focused = false;
bool surfaceHovered = false;
bool surfaceActive = false;
bool inputCaptured = false;
std::size_t hoveredToolIndex = UIEditorViewportSlotInvalidIndex;
std::size_t activeToolIndex = UIEditorViewportSlotInvalidIndex;
UIEditorStatusBarState statusBarState = {};
};
struct UIEditorViewportSlotMetrics {
float cornerRounding = 10.0f;
float outerBorderThickness = 1.0f;
float focusedBorderThickness = 1.5f;
float topBarPaddingX = 12.0f;
float topBarPaddingY = 7.0f;
float toolPaddingX = 10.0f;
float toolGap = 6.0f;
float toolCornerRounding = 6.0f;
float titleGap = 10.0f;
float titleInsetY = 10.0f;
float subtitleInsetY = 25.0f;
float estimatedGlyphWidth = 7.0f;
float surfaceInset = 0.0f;
float surfaceBorderThickness = 1.0f;
float focusedSurfaceBorderThickness = 1.5f;
};
struct UIEditorViewportSlotPalette {
::XCEngine::UI::UIColor frameColor =
::XCEngine::UI::UIColor(0.14f, 0.14f, 0.14f, 1.0f);
::XCEngine::UI::UIColor topBarColor =
::XCEngine::UI::UIColor(0.18f, 0.18f, 0.18f, 1.0f);
::XCEngine::UI::UIColor surfaceColor =
::XCEngine::UI::UIColor(0.10f, 0.10f, 0.10f, 1.0f);
::XCEngine::UI::UIColor surfaceHoverOverlayColor =
::XCEngine::UI::UIColor(0.22f, 0.22f, 0.22f, 0.24f);
::XCEngine::UI::UIColor surfaceActiveOverlayColor =
::XCEngine::UI::UIColor(0.34f, 0.34f, 0.34f, 0.18f);
::XCEngine::UI::UIColor captureOverlayColor =
::XCEngine::UI::UIColor(0.70f, 0.70f, 0.70f, 0.10f);
::XCEngine::UI::UIColor borderColor =
::XCEngine::UI::UIColor(0.28f, 0.28f, 0.28f, 1.0f);
::XCEngine::UI::UIColor focusedBorderColor =
::XCEngine::UI::UIColor(0.84f, 0.84f, 0.84f, 1.0f);
::XCEngine::UI::UIColor surfaceBorderColor =
::XCEngine::UI::UIColor(0.22f, 0.22f, 0.22f, 1.0f);
::XCEngine::UI::UIColor surfaceHoveredBorderColor =
::XCEngine::UI::UIColor(0.44f, 0.44f, 0.44f, 1.0f);
::XCEngine::UI::UIColor surfaceActiveBorderColor =
::XCEngine::UI::UIColor(0.64f, 0.64f, 0.64f, 1.0f);
::XCEngine::UI::UIColor surfaceCapturedBorderColor =
::XCEngine::UI::UIColor(0.86f, 0.86f, 0.86f, 1.0f);
::XCEngine::UI::UIColor toolColor =
::XCEngine::UI::UIColor(0.24f, 0.24f, 0.24f, 1.0f);
::XCEngine::UI::UIColor toolHoveredColor =
::XCEngine::UI::UIColor(0.31f, 0.31f, 0.31f, 1.0f);
::XCEngine::UI::UIColor toolSelectedColor =
::XCEngine::UI::UIColor(0.39f, 0.39f, 0.39f, 1.0f);
::XCEngine::UI::UIColor toolDisabledColor =
::XCEngine::UI::UIColor(0.19f, 0.19f, 0.19f, 1.0f);
::XCEngine::UI::UIColor toolBorderColor =
::XCEngine::UI::UIColor(0.40f, 0.40f, 0.40f, 1.0f);
::XCEngine::UI::UIColor textPrimary =
::XCEngine::UI::UIColor(0.94f, 0.94f, 0.94f, 1.0f);
::XCEngine::UI::UIColor textSecondary =
::XCEngine::UI::UIColor(0.76f, 0.76f, 0.76f, 1.0f);
::XCEngine::UI::UIColor textMuted =
::XCEngine::UI::UIColor(0.62f, 0.62f, 0.62f, 1.0f);
::XCEngine::UI::UIColor imageTint =
::XCEngine::UI::UIColor(1.0f, 1.0f, 1.0f, 1.0f);
UIEditorStatusBarPalette statusBarPalette = {};
};
struct UIEditorViewportSlotLayout {
::XCEngine::UI::UIRect bounds = {};
::XCEngine::UI::UIRect topBarRect = {};
::XCEngine::UI::UIRect titleRect = {};
::XCEngine::UI::UIRect subtitleRect = {};
::XCEngine::UI::UIRect toolbarLeadingRect = {};
::XCEngine::UI::UIRect toolbarTrailingRect = {};
::XCEngine::UI::UIRect surfaceRect = {};
::XCEngine::UI::UIRect textureRect = {};
::XCEngine::UI::UIRect inputRect = {};
::XCEngine::UI::UIRect bottomBarRect = {};
std::vector<::XCEngine::UI::UIRect> toolItemRects = {};
UIEditorStatusBarLayout statusBarLayout = {};
::XCEngine::UI::UISize requestedSurfaceSize = {};
bool hasTopBar = false;
bool hasBottomBar = false;
};
struct UIEditorViewportSlotHitTarget {
UIEditorViewportSlotHitTargetKind kind = UIEditorViewportSlotHitTargetKind::None;
std::size_t index = UIEditorViewportSlotInvalidIndex;
};
float ResolveUIEditorViewportSlotDesiredToolWidth(
const UIEditorViewportSlotToolItem& item,
const UIEditorViewportSlotMetrics& metrics = {});
UIEditorViewportSlotLayout BuildUIEditorViewportSlotLayout(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorViewportSlotChrome& chrome,
const UIEditorViewportSlotFrame& frame,
const std::vector<UIEditorViewportSlotToolItem>& toolItems,
const std::vector<UIEditorStatusBarSegment>& statusSegments,
const UIEditorViewportSlotMetrics& metrics = {});
UIEditorViewportSlotHitTarget HitTestUIEditorViewportSlot(
const UIEditorViewportSlotLayout& layout,
const ::XCEngine::UI::UIPoint& point);
void AppendUIEditorViewportSlotBackground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorViewportSlotLayout& layout,
const std::vector<UIEditorViewportSlotToolItem>& toolItems,
const std::vector<UIEditorStatusBarSegment>& statusSegments,
const UIEditorViewportSlotState& state,
const UIEditorViewportSlotPalette& palette = {},
const UIEditorViewportSlotMetrics& metrics = {});
void AppendUIEditorViewportSlotForeground(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorViewportSlotLayout& layout,
const UIEditorViewportSlotChrome& chrome,
const UIEditorViewportSlotFrame& frame,
const std::vector<UIEditorViewportSlotToolItem>& toolItems,
const std::vector<UIEditorStatusBarSegment>& statusSegments,
const UIEditorViewportSlotState& state,
const UIEditorViewportSlotPalette& palette = {},
const UIEditorViewportSlotMetrics& metrics = {});
void AppendUIEditorViewportSlot(
::XCEngine::UI::UIDrawList& drawList,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorViewportSlotChrome& chrome,
const UIEditorViewportSlotFrame& frame,
const std::vector<UIEditorViewportSlotToolItem>& toolItems,
const std::vector<UIEditorStatusBarSegment>& statusSegments,
const UIEditorViewportSlotState& state,
const UIEditorViewportSlotPalette& palette = {},
const UIEditorViewportSlotMetrics& metrics = {});
} // namespace XCEngine::UI::Editor::Widgets

View File

@@ -0,0 +1,107 @@
#pragma once
#include <XCEditor/Shell/UIEditorPanelContentHost.h>
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
#include <XCEditor/Shell/UIEditorViewportShell.h>
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
#include <XCEditor/Shell/UIEditorDockHost.h>
#include <XCEngine/UI/DrawData.h>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorWorkspacePanelPresentationModel {
std::string panelId = {};
UIEditorPanelPresentationKind kind = UIEditorPanelPresentationKind::Placeholder;
UIEditorViewportShellModel viewportShellModel = {};
};
struct UIEditorWorkspacePanelPresentationState {
std::string panelId = {};
UIEditorViewportShellState viewportShellState = {};
};
struct UIEditorWorkspaceComposeState {
UIEditorPanelContentHostState contentHostState = {};
std::vector<UIEditorWorkspacePanelPresentationState> panelStates = {};
};
struct UIEditorWorkspaceViewportComposeRequest {
std::string panelId = {};
::XCEngine::UI::UIRect bounds = {};
UIEditorViewportShellRequest viewportShellRequest = {};
};
struct UIEditorWorkspaceComposeRequest {
Widgets::UIEditorDockHostLayout dockHostLayout = {};
UIEditorPanelContentHostRequest contentHostRequest = {};
std::vector<UIEditorWorkspaceViewportComposeRequest> viewportRequests = {};
};
struct UIEditorWorkspaceViewportComposeFrame {
std::string panelId = {};
::XCEngine::UI::UIRect bounds = {};
UIEditorViewportShellModel viewportShellModel = {};
UIEditorViewportShellFrame viewportShellFrame = {};
};
struct UIEditorWorkspaceComposeFrame {
Widgets::UIEditorDockHostLayout dockHostLayout = {};
UIEditorPanelContentHostFrame contentHostFrame = {};
std::vector<UIEditorWorkspaceViewportComposeFrame> viewportFrames = {};
};
const UIEditorWorkspacePanelPresentationModel* FindUIEditorWorkspacePanelPresentationModel(
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
std::string_view panelId);
const UIEditorWorkspacePanelPresentationState* FindUIEditorWorkspacePanelPresentationState(
const UIEditorWorkspaceComposeState& state,
std::string_view panelId);
const UIEditorWorkspaceViewportComposeRequest* FindUIEditorWorkspaceViewportPresentationRequest(
const UIEditorWorkspaceComposeRequest& request,
std::string_view panelId);
const UIEditorWorkspaceViewportComposeFrame* FindUIEditorWorkspaceViewportPresentationFrame(
const UIEditorWorkspaceComposeFrame& frame,
std::string_view panelId);
UIEditorWorkspaceComposeRequest ResolveUIEditorWorkspaceComposeRequest(
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
const Widgets::UIEditorDockHostState& dockHostState = {},
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
UIEditorWorkspaceComposeFrame UpdateUIEditorWorkspaceCompose(
UIEditorWorkspaceComposeState& state,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session,
const std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorDockHostState& dockHostState = {},
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
std::vector<std::string> CollectUIEditorWorkspaceComposeExternalBodyPanelIds(
const UIEditorWorkspaceComposeFrame& frame);
void AppendUIEditorWorkspaceCompose(
::XCEngine::UI::UIDrawList& drawList,
const UIEditorWorkspaceComposeFrame& frame,
const Widgets::UIEditorDockHostPalette& dockHostPalette = {},
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
const Widgets::UIEditorViewportSlotPalette& viewportPalette = {},
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,141 @@
#pragma once
#include <XCEditor/Shell/UIEditorWorkspaceLayoutPersistence.h>
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
enum class UIEditorWorkspaceCommandKind : std::uint8_t {
OpenPanel = 0,
ClosePanel,
ShowPanel,
HidePanel,
ActivatePanel,
ResetWorkspace
};
enum class UIEditorWorkspaceCommandStatus : std::uint8_t {
Changed = 0,
NoOp,
Rejected
};
struct UIEditorWorkspaceCommand {
UIEditorWorkspaceCommandKind kind = UIEditorWorkspaceCommandKind::ActivatePanel;
std::string panelId = {};
};
struct UIEditorWorkspaceCommandResult {
UIEditorWorkspaceCommandKind kind = UIEditorWorkspaceCommandKind::ActivatePanel;
UIEditorWorkspaceCommandStatus status = UIEditorWorkspaceCommandStatus::Rejected;
std::string panelId = {};
std::string message = {};
std::string activePanelId = {};
std::vector<std::string> visiblePanelIds = {};
};
enum class UIEditorWorkspaceControllerValidationCode : std::uint8_t {
None = 0,
InvalidPanelRegistry,
InvalidWorkspace,
InvalidWorkspaceSession
};
struct UIEditorWorkspaceControllerValidationResult {
UIEditorWorkspaceControllerValidationCode code =
UIEditorWorkspaceControllerValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorWorkspaceControllerValidationCode::None;
}
};
std::string_view GetUIEditorWorkspaceCommandKindName(UIEditorWorkspaceCommandKind kind);
std::string_view GetUIEditorWorkspaceCommandStatusName(UIEditorWorkspaceCommandStatus status);
enum class UIEditorWorkspaceLayoutOperationStatus : std::uint8_t {
Changed = 0,
NoOp,
Rejected
};
struct UIEditorWorkspaceLayoutOperationResult {
UIEditorWorkspaceLayoutOperationStatus status =
UIEditorWorkspaceLayoutOperationStatus::Rejected;
std::string message = {};
std::string activePanelId = {};
std::vector<std::string> visiblePanelIds = {};
};
std::string_view GetUIEditorWorkspaceLayoutOperationStatusName(
UIEditorWorkspaceLayoutOperationStatus status);
class UIEditorWorkspaceController {
public:
UIEditorWorkspaceController() = default;
UIEditorWorkspaceController(
UIEditorPanelRegistry panelRegistry,
UIEditorWorkspaceModel workspace,
UIEditorWorkspaceSession session);
const UIEditorPanelRegistry& GetPanelRegistry() const {
return m_panelRegistry;
}
const UIEditorWorkspaceModel& GetWorkspace() const {
return m_workspace;
}
const UIEditorWorkspaceSession& GetSession() const {
return m_session;
}
UIEditorWorkspaceControllerValidationResult ValidateState() const;
UIEditorWorkspaceLayoutSnapshot CaptureLayoutSnapshot() const;
UIEditorWorkspaceLayoutOperationResult RestoreLayoutSnapshot(
const UIEditorWorkspaceLayoutSnapshot& snapshot);
UIEditorWorkspaceLayoutOperationResult RestoreSerializedLayout(
std::string_view serializedLayout);
UIEditorWorkspaceLayoutOperationResult SetSplitRatio(
std::string_view nodeId,
float splitRatio);
UIEditorWorkspaceCommandResult Dispatch(const UIEditorWorkspaceCommand& command);
private:
UIEditorWorkspaceCommandResult BuildResult(
const UIEditorWorkspaceCommand& command,
UIEditorWorkspaceCommandStatus status,
std::string message) const;
UIEditorWorkspaceCommandResult FinalizeMutation(
const UIEditorWorkspaceCommand& command,
bool changed,
std::string changedMessage,
std::string unexpectedFailureMessage,
const UIEditorWorkspaceModel& previousWorkspace,
const UIEditorWorkspaceSession& previousSession);
UIEditorWorkspaceLayoutOperationResult BuildLayoutOperationResult(
UIEditorWorkspaceLayoutOperationStatus status,
std::string message) const;
const UIEditorPanelDescriptor* FindPanelDescriptor(std::string_view panelId) const;
UIEditorPanelRegistry m_panelRegistry = {};
UIEditorWorkspaceModel m_baselineWorkspace = {};
UIEditorWorkspaceSession m_baselineSession = {};
UIEditorWorkspaceModel m_workspace = {};
UIEditorWorkspaceSession m_session = {};
};
UIEditorWorkspaceController BuildDefaultUIEditorWorkspaceController(
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,47 @@
#pragma once
#include <XCEditor/Shell/UIEditorDockHostInteraction.h>
#include <XCEditor/Shell/UIEditorWorkspaceCompose.h>
#include <XCEngine/UI/Types.h>
#include <string>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorWorkspaceInteractionModel {
std::vector<UIEditorWorkspacePanelPresentationModel> workspacePresentations = {};
};
struct UIEditorWorkspaceInteractionState {
UIEditorDockHostInteractionState dockHostInteractionState = {};
UIEditorWorkspaceComposeState composeState = {};
};
struct UIEditorWorkspaceInteractionResult {
bool consumed = false;
bool requestPointerCapture = false;
bool releasePointerCapture = false;
bool viewportInteractionChanged = false;
std::string viewportPanelId = {};
UIEditorViewportInputBridgeFrame viewportInputFrame = {};
UIEditorDockHostInteractionResult dockHostResult = {};
};
struct UIEditorWorkspaceInteractionFrame {
UIEditorDockHostInteractionFrame dockHostFrame = {};
UIEditorWorkspaceComposeFrame composeFrame = {};
UIEditorWorkspaceInteractionResult result = {};
};
UIEditorWorkspaceInteractionFrame UpdateUIEditorWorkspaceInteraction(
UIEditorWorkspaceInteractionState& state,
UIEditorWorkspaceController& controller,
const ::XCEngine::UI::UIRect& bounds,
const UIEditorWorkspaceInteractionModel& model,
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
const Widgets::UIEditorDockHostMetrics& dockHostMetrics = {},
const Widgets::UIEditorViewportSlotMetrics& viewportMetrics = {});
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,55 @@
#pragma once
#include <XCEditor/Shell/UIEditorWorkspaceSession.h>
#include <cstdint>
#include <string>
#include <string_view>
namespace XCEngine::UI::Editor {
struct UIEditorWorkspaceLayoutSnapshot {
UIEditorWorkspaceModel workspace = {};
UIEditorWorkspaceSession session = {};
};
enum class UIEditorWorkspaceLayoutLoadCode : std::uint8_t {
None = 0,
InvalidPanelRegistry,
EmptyInput,
InvalidHeader,
UnsupportedVersion,
MissingActiveRecord,
UnexpectedEndOfInput,
InvalidNodeRecord,
InvalidSessionRecord,
InvalidWorkspace,
InvalidWorkspaceSession
};
struct UIEditorWorkspaceLayoutLoadResult {
UIEditorWorkspaceLayoutLoadCode code = UIEditorWorkspaceLayoutLoadCode::None;
std::string message = {};
UIEditorWorkspaceLayoutSnapshot snapshot = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorWorkspaceLayoutLoadCode::None;
}
};
UIEditorWorkspaceLayoutSnapshot BuildUIEditorWorkspaceLayoutSnapshot(
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session);
bool AreUIEditorWorkspaceLayoutSnapshotsEquivalent(
const UIEditorWorkspaceLayoutSnapshot& lhs,
const UIEditorWorkspaceLayoutSnapshot& rhs);
std::string SerializeUIEditorWorkspaceLayoutSnapshot(
const UIEditorWorkspaceLayoutSnapshot& snapshot);
UIEditorWorkspaceLayoutLoadResult DeserializeUIEditorWorkspaceLayoutSnapshot(
const UIEditorPanelRegistry& panelRegistry,
std::string_view serializedLayout);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,127 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
enum class UIEditorWorkspaceNodeKind : std::uint8_t {
Panel = 0,
TabStack,
Split
};
enum class UIEditorWorkspaceSplitAxis : std::uint8_t {
Horizontal = 0,
Vertical
};
struct UIEditorWorkspacePanelState {
std::string panelId = {};
std::string title = {};
bool placeholder = false;
};
struct UIEditorWorkspaceNode {
UIEditorWorkspaceNodeKind kind = UIEditorWorkspaceNodeKind::Panel;
std::string nodeId = {};
UIEditorWorkspaceSplitAxis splitAxis = UIEditorWorkspaceSplitAxis::Horizontal;
float splitRatio = 0.5f;
std::size_t selectedTabIndex = 0u;
UIEditorWorkspacePanelState panel = {};
std::vector<UIEditorWorkspaceNode> children = {};
};
struct UIEditorWorkspaceModel {
UIEditorWorkspaceNode root = {};
std::string activePanelId = {};
};
enum class UIEditorWorkspaceValidationCode : std::uint8_t {
None = 0,
EmptyNodeId,
InvalidSplitChildCount,
InvalidSplitRatio,
EmptyTabStack,
InvalidSelectedTabIndex,
NonPanelTabChild,
EmptyPanelId,
EmptyPanelTitle,
DuplicatePanelId,
InvalidActivePanelId
};
struct UIEditorWorkspaceValidationResult {
UIEditorWorkspaceValidationCode code = UIEditorWorkspaceValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorWorkspaceValidationCode::None;
}
};
struct UIEditorWorkspaceVisiblePanel {
std::string panelId = {};
std::string title = {};
bool active = false;
bool placeholder = false;
};
UIEditorWorkspaceModel BuildDefaultEditorShellWorkspaceModel();
UIEditorWorkspaceNode BuildUIEditorWorkspacePanel(
std::string nodeId,
std::string panelId,
std::string title,
bool placeholder = false);
UIEditorWorkspaceNode BuildUIEditorWorkspaceTabStack(
std::string nodeId,
std::vector<UIEditorWorkspaceNode> panels,
std::size_t selectedTabIndex = 0u);
UIEditorWorkspaceNode BuildUIEditorWorkspaceSplit(
std::string nodeId,
UIEditorWorkspaceSplitAxis axis,
float splitRatio,
UIEditorWorkspaceNode primary,
UIEditorWorkspaceNode secondary);
UIEditorWorkspaceValidationResult ValidateUIEditorWorkspace(
const UIEditorWorkspaceModel& workspace);
std::vector<UIEditorWorkspaceVisiblePanel> CollectUIEditorWorkspaceVisiblePanels(
const UIEditorWorkspaceModel& workspace);
bool ContainsUIEditorWorkspacePanel(
const UIEditorWorkspaceModel& workspace,
std::string_view panelId);
const UIEditorWorkspaceNode* FindUIEditorWorkspaceNode(
const UIEditorWorkspaceModel& workspace,
std::string_view nodeId);
bool AreUIEditorWorkspaceNodesEquivalent(
const UIEditorWorkspaceNode& lhs,
const UIEditorWorkspaceNode& rhs);
bool AreUIEditorWorkspaceModelsEquivalent(
const UIEditorWorkspaceModel& lhs,
const UIEditorWorkspaceModel& rhs);
const UIEditorWorkspacePanelState* FindUIEditorWorkspaceActivePanel(
const UIEditorWorkspaceModel& workspace);
bool TryActivateUIEditorWorkspacePanel(
UIEditorWorkspaceModel& workspace,
std::string_view panelId);
bool TrySetUIEditorWorkspaceSplitRatio(
UIEditorWorkspaceModel& workspace,
std::string_view nodeId,
float splitRatio);
} // namespace XCEngine::UI::Editor

View File

@@ -0,0 +1,98 @@
#pragma once
#include <XCEditor/Shell/UIEditorPanelRegistry.h>
#include <XCEditor/Shell/UIEditorWorkspaceModel.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::UI::Editor {
struct UIEditorPanelSessionState {
std::string panelId = {};
bool open = true;
bool visible = true;
};
struct UIEditorWorkspaceSession {
std::vector<UIEditorPanelSessionState> panelStates = {};
};
enum class UIEditorWorkspaceSessionValidationCode : std::uint8_t {
None = 0,
MissingPanelState,
UnknownPanelId,
DuplicatePanelId,
ClosedPanelVisible,
NonHideablePanelHidden,
NonCloseablePanelClosed,
InvalidActivePanelId
};
struct UIEditorWorkspaceSessionValidationResult {
UIEditorWorkspaceSessionValidationCode code = UIEditorWorkspaceSessionValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorWorkspaceSessionValidationCode::None;
}
};
UIEditorWorkspaceSession BuildDefaultUIEditorWorkspaceSession(
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace);
const UIEditorPanelSessionState* FindUIEditorPanelSessionState(
const UIEditorWorkspaceSession& session,
std::string_view panelId);
UIEditorWorkspaceSessionValidationResult ValidateUIEditorWorkspaceSession(
const UIEditorPanelRegistry& panelRegistry,
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session);
bool AreUIEditorWorkspaceSessionsEquivalent(
const UIEditorWorkspaceSession& lhs,
const UIEditorWorkspaceSession& rhs);
std::vector<UIEditorWorkspaceVisiblePanel> CollectUIEditorWorkspaceVisiblePanels(
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session);
const UIEditorWorkspacePanelState* FindUIEditorWorkspaceActivePanel(
const UIEditorWorkspaceModel& workspace,
const UIEditorWorkspaceSession& session);
bool TryOpenUIEditorWorkspacePanel(
const UIEditorPanelRegistry& panelRegistry,
UIEditorWorkspaceModel& workspace,
UIEditorWorkspaceSession& session,
std::string_view panelId);
bool TryCloseUIEditorWorkspacePanel(
const UIEditorPanelRegistry& panelRegistry,
UIEditorWorkspaceModel& workspace,
UIEditorWorkspaceSession& session,
std::string_view panelId);
bool TryShowUIEditorWorkspacePanel(
const UIEditorPanelRegistry& panelRegistry,
UIEditorWorkspaceModel& workspace,
UIEditorWorkspaceSession& session,
std::string_view panelId);
bool TryHideUIEditorWorkspacePanel(
const UIEditorPanelRegistry& panelRegistry,
UIEditorWorkspaceModel& workspace,
UIEditorWorkspaceSession& session,
std::string_view panelId);
bool TryActivateUIEditorWorkspacePanel(
const UIEditorPanelRegistry& panelRegistry,
UIEditorWorkspaceModel& workspace,
UIEditorWorkspaceSession& session,
std::string_view panelId);
} // namespace XCEngine::UI::Editor