feat(xcui): add editor command and menu foundations

This commit is contained in:
2026-04-06 18:05:34 +08:00
parent 4afeb19d25
commit f912e81ade
29 changed files with 3581 additions and 61 deletions

View File

@@ -0,0 +1,73 @@
#pragma once
#include <XCNewEditor/Editor/UIEditorCommandRegistry.h>
#include <cstdint>
#include <string>
#include <string_view>
namespace XCEngine::NewEditor {
enum class UIEditorCommandEvaluationCode : std::uint8_t {
None = 0,
InvalidCommandRegistry,
UnknownCommandId,
MissingActivePanel
};
struct UIEditorCommandEvaluationResult {
UIEditorCommandEvaluationCode code = UIEditorCommandEvaluationCode::None;
bool executable = false;
std::string commandId = {};
std::string displayName = {};
UIEditorWorkspaceCommand workspaceCommand = {};
UIEditorWorkspaceCommandResult previewResult = {};
std::string message = {};
[[nodiscard]] bool IsExecutable() const {
return executable;
}
};
enum class UIEditorCommandDispatchStatus : std::uint8_t {
Dispatched = 0,
Rejected
};
struct UIEditorCommandDispatchResult {
UIEditorCommandDispatchStatus status = UIEditorCommandDispatchStatus::Rejected;
bool commandExecuted = false;
std::string commandId = {};
std::string displayName = {};
UIEditorWorkspaceCommand workspaceCommand = {};
UIEditorWorkspaceCommandResult commandResult = {};
std::string message = {};
};
std::string_view GetUIEditorCommandDispatchStatusName(
UIEditorCommandDispatchStatus status);
class UIEditorCommandDispatcher {
public:
UIEditorCommandDispatcher() = default;
explicit UIEditorCommandDispatcher(UIEditorCommandRegistry commandRegistry);
const UIEditorCommandRegistry& GetCommandRegistry() const {
return m_commandRegistry;
}
UIEditorCommandRegistryValidationResult ValidateConfiguration() const;
UIEditorCommandEvaluationResult Evaluate(
std::string_view commandId,
const UIEditorWorkspaceController& controller) const;
UIEditorCommandDispatchResult Dispatch(
std::string_view commandId,
UIEditorWorkspaceController& controller) const;
private:
UIEditorCommandRegistry m_commandRegistry = {};
};
} // namespace XCEngine::NewEditor

View File

@@ -0,0 +1,63 @@
#pragma once
#include <XCNewEditor/Editor/UIEditorWorkspaceController.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::NewEditor {
enum class UIEditorCommandPanelSource : std::uint8_t {
None = 0,
FixedPanelId,
ActivePanel
};
struct UIEditorWorkspaceCommandDescriptor {
UIEditorWorkspaceCommandKind kind = UIEditorWorkspaceCommandKind::ActivatePanel;
UIEditorCommandPanelSource panelSource = UIEditorCommandPanelSource::FixedPanelId;
std::string panelId = {};
};
struct UIEditorCommandDescriptor {
std::string commandId = {};
std::string displayName = {};
UIEditorWorkspaceCommandDescriptor workspaceCommand = {};
};
struct UIEditorCommandRegistry {
std::vector<UIEditorCommandDescriptor> commands = {};
};
enum class UIEditorCommandRegistryValidationCode : std::uint8_t {
None = 0,
EmptyCommandId,
EmptyDisplayName,
DuplicateCommandId,
MissingPanelSource,
MissingFixedPanelId,
UnexpectedPanelSource
};
struct UIEditorCommandRegistryValidationResult {
UIEditorCommandRegistryValidationCode code =
UIEditorCommandRegistryValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorCommandRegistryValidationCode::None;
}
};
std::string_view GetUIEditorCommandPanelSourceName(UIEditorCommandPanelSource source);
const UIEditorCommandDescriptor* FindUIEditorCommandDescriptor(
const UIEditorCommandRegistry& registry,
std::string_view commandId);
UIEditorCommandRegistryValidationResult ValidateUIEditorCommandRegistry(
const UIEditorCommandRegistry& registry);
} // namespace XCEngine::NewEditor

View File

@@ -0,0 +1,116 @@
#pragma once
#include <XCNewEditor/Editor/UIEditorCommandDispatcher.h>
#include <cstdint>
#include <string>
#include <string_view>
#include <vector>
namespace XCEngine::NewEditor {
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::NewEditor

View File

@@ -0,0 +1,100 @@
#pragma once
#include <XCNewEditor/Editor/UIEditorCommandDispatcher.h>
#include <XCEngine/UI/Input/UIShortcutRegistry.h>
#include <cstdint>
#include <string>
#include <string_view>
namespace XCEngine::NewEditor {
enum class UIEditorShortcutManagerValidationCode : std::uint8_t {
None = 0,
InvalidCommandRegistry,
EmptyBindingCommandId,
UnknownCommandId,
MissingScopedOwnerId,
EmptyShortcutKey,
ConflictingBinding
};
struct UIEditorShortcutManagerValidationResult {
UIEditorShortcutManagerValidationCode code =
UIEditorShortcutManagerValidationCode::None;
std::string message = {};
[[nodiscard]] bool IsValid() const {
return code == UIEditorShortcutManagerValidationCode::None;
}
};
enum class UIEditorShortcutDispatchStatus : std::uint8_t {
NoMatch = 0,
Suppressed,
Dispatched,
Rejected
};
struct UIEditorShortcutDispatchResult {
UIEditorShortcutDispatchStatus status = UIEditorShortcutDispatchStatus::NoMatch;
bool matched = false;
bool commandExecuted = false;
std::string commandId = {};
std::string commandDisplayName = {};
std::string message = {};
XCEngine::UI::UIShortcutScope shortcutScope =
XCEngine::UI::UIShortcutScope::Global;
XCEngine::UI::UIElementId shortcutOwnerId = 0;
UIEditorWorkspaceCommandResult commandResult = {};
};
std::string_view GetUIEditorShortcutDispatchStatusName(
UIEditorShortcutDispatchStatus status);
class UIEditorShortcutManager {
public:
UIEditorShortcutManager() = default;
explicit UIEditorShortcutManager(UIEditorCommandRegistry commandRegistry);
const UIEditorCommandDispatcher& GetCommandDispatcher() const {
return m_commandDispatcher;
}
const UIEditorCommandRegistry& GetCommandRegistry() const {
return m_commandDispatcher.GetCommandRegistry();
}
const XCEngine::UI::UIShortcutRegistry& GetShortcutRegistry() const {
return m_shortcutRegistry;
}
std::uint64_t RegisterBinding(const XCEngine::UI::UIShortcutBinding& binding);
bool UnregisterBinding(std::uint64_t bindingId);
void ClearBindings();
UIEditorShortcutManagerValidationResult ValidateConfiguration() const;
std::string GetPreferredShortcutText(std::string_view commandId) const;
UIEditorShortcutDispatchResult Dispatch(
const XCEngine::UI::UIInputEvent& event,
const XCEngine::UI::UIShortcutContext& shortcutContext,
UIEditorWorkspaceController& controller) const;
private:
UIEditorShortcutDispatchResult BuildDispatchResult(
UIEditorShortcutDispatchStatus status,
std::string commandId,
std::string commandDisplayName,
std::string message,
const XCEngine::UI::UIShortcutMatch* match = nullptr) const;
const XCEngine::UI::UIShortcutBinding* FindPreferredBinding(
std::string_view commandId) const;
UIEditorCommandDispatcher m_commandDispatcher = {};
XCEngine::UI::UIShortcutRegistry m_shortcutRegistry = {};
};
} // namespace XCEngine::NewEditor