406 lines
13 KiB
C++
406 lines
13 KiB
C++
#include "EditorContext.h"
|
|
#include "EditorShellAssetBuilder.h"
|
|
#include "Engine/EditorSceneBackendFactory.h"
|
|
#include "Scene/EditorSceneRuntime.h"
|
|
#include "Panels/EditorPanelIds.h"
|
|
#include "Viewport/EditorViewportRuntimeServices.h"
|
|
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
|
#include <sstream>
|
|
#include <utility>
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
using ::XCEngine::UI::Editor::UIEditorWorkspacePanelPresentationModel;
|
|
using ::XCEngine::UI::Editor::AppendUIEditorRuntimeTrace;
|
|
|
|
std::string ComposeStatusText(
|
|
std::string_view status,
|
|
std::string_view message) {
|
|
if (status.empty()) {
|
|
return std::string(message);
|
|
}
|
|
|
|
if (message.empty()) {
|
|
return std::string(status);
|
|
}
|
|
|
|
return std::string(status) + ": " + std::string(message);
|
|
}
|
|
|
|
UIEditorWorkspacePanelPresentationModel* FindMutablePresentation(
|
|
std::vector<UIEditorWorkspacePanelPresentationModel>& presentations,
|
|
std::string_view panelId) {
|
|
for (UIEditorWorkspacePanelPresentationModel& presentation : presentations) {
|
|
if (presentation.panelId == panelId) {
|
|
return &presentation;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool EditorContext::Initialize(
|
|
const EditorRuntimePaths& runtimePaths,
|
|
EditorSceneBackendFactory& sceneBackendFactory) {
|
|
m_valid = false;
|
|
m_validationMessage.clear();
|
|
AppendUIEditorRuntimeTrace("startup", "EditorContext::Initialize begin");
|
|
m_shellAsset = BuildEditorApplicationShellAsset(runtimePaths);
|
|
AppendUIEditorRuntimeTrace("startup", "BuildEditorApplicationShellAsset complete");
|
|
m_shellValidation = ValidateEditorShellAsset(m_shellAsset);
|
|
AppendUIEditorRuntimeTrace(
|
|
"startup",
|
|
std::string("ValidateEditorShellAsset complete valid=") +
|
|
(m_shellValidation.IsValid() ? "1" : "0"));
|
|
if (!m_shellValidation.IsValid()) {
|
|
m_validationMessage = m_shellValidation.message;
|
|
return false;
|
|
}
|
|
|
|
m_session = {};
|
|
m_session.workspaceRoot = runtimePaths.workspaceRoot;
|
|
m_session.projectRoot = runtimePaths.projectRoot;
|
|
m_selectionService = {};
|
|
m_projectRuntime.Reset();
|
|
AppendUIEditorRuntimeTrace("startup", "EditorProjectRuntime::Initialize begin");
|
|
m_projectRuntime.Initialize(runtimePaths.projectRoot);
|
|
AppendUIEditorRuntimeTrace("startup", "EditorProjectRuntime::Initialize end");
|
|
m_projectRuntime.BindSelectionService(&m_selectionService);
|
|
m_sceneRuntime.SetBackend(sceneBackendFactory.CreateSceneBackend());
|
|
AppendUIEditorRuntimeTrace("startup", "EditorSceneRuntime::Initialize begin");
|
|
const EditorStartupSceneResult startupScene =
|
|
m_sceneRuntime.Initialize(m_session.projectRoot);
|
|
if (!startupScene.ready) {
|
|
m_validationMessage = "Editor scene runtime failed to initialize.";
|
|
AppendUIEditorRuntimeTrace("startup", m_validationMessage);
|
|
return false;
|
|
}
|
|
AppendUIEditorRuntimeTrace("startup", "EditorSceneRuntime::Initialize end");
|
|
m_sceneRuntime.BindSelectionService(&m_selectionService);
|
|
m_runtimeCoordinator.Initialize(
|
|
m_session,
|
|
m_sceneRuntime,
|
|
m_projectRuntime,
|
|
runtimePaths,
|
|
startupScene);
|
|
ResetEditorColorPickerToolState(m_colorPickerToolState);
|
|
ResetEditorUtilityWindowRequestState(m_utilityWindowRequestState);
|
|
SyncSessionFromSelectionService();
|
|
m_textMeasurer = nullptr;
|
|
m_lastStatus.clear();
|
|
m_lastMessage.clear();
|
|
SetReadyStatus();
|
|
m_valid = true;
|
|
AppendUIEditorRuntimeTrace("startup", "EditorContext::Initialize end");
|
|
return true;
|
|
}
|
|
|
|
void EditorContext::AttachTextMeasurer(
|
|
const UIEditorTextMeasurer& textMeasurer) {
|
|
m_textMeasurer = &textMeasurer;
|
|
}
|
|
|
|
void EditorContext::SetSystemInteractionHost(
|
|
::XCEngine::UI::Editor::System::SystemInteractionService* systemInteractionHost) {
|
|
m_systemInteractionHost = systemInteractionHost;
|
|
}
|
|
|
|
void EditorContext::TickEditorRuntime() {
|
|
m_runtimeCoordinator.TickFrame();
|
|
}
|
|
|
|
bool EditorContext::IsValid() const {
|
|
return m_valid;
|
|
}
|
|
|
|
const std::string& EditorContext::GetValidationMessage() const {
|
|
return m_validationMessage;
|
|
}
|
|
|
|
const EditorShellAsset& EditorContext::GetShellAsset() const {
|
|
return m_shellAsset;
|
|
}
|
|
|
|
const EditorSession& EditorContext::GetSession() const {
|
|
return m_session;
|
|
}
|
|
|
|
EditorProjectRuntime& EditorContext::GetProjectRuntime() {
|
|
return m_projectRuntime;
|
|
}
|
|
|
|
const EditorProjectRuntime& EditorContext::GetProjectRuntime() const {
|
|
return m_projectRuntime;
|
|
}
|
|
|
|
EditorSceneRuntime& EditorContext::GetSceneRuntime() {
|
|
return m_sceneRuntime;
|
|
}
|
|
|
|
const EditorSceneRuntime& EditorContext::GetSceneRuntime() const {
|
|
return m_sceneRuntime;
|
|
}
|
|
|
|
EditorRuntimeCoordinator& EditorContext::GetRuntimeCoordinator() {
|
|
return m_runtimeCoordinator;
|
|
}
|
|
|
|
const EditorRuntimeCoordinator& EditorContext::GetRuntimeCoordinator() const {
|
|
return m_runtimeCoordinator;
|
|
}
|
|
|
|
EditorColorPickerToolState& EditorContext::GetColorPickerToolState() {
|
|
return m_colorPickerToolState;
|
|
}
|
|
|
|
const EditorColorPickerToolState& EditorContext::GetColorPickerToolState() const {
|
|
return m_colorPickerToolState;
|
|
}
|
|
|
|
void EditorContext::RequestOpenUtilityWindow(EditorUtilityWindowKind kind) {
|
|
RequestEditorUtilityWindow(m_utilityWindowRequestState, kind);
|
|
}
|
|
|
|
std::optional<EditorUtilityWindowKind> EditorContext::ConsumeOpenUtilityWindowRequest() {
|
|
return ConsumeEditorUtilityWindowRequest(m_utilityWindowRequestState);
|
|
}
|
|
|
|
void EditorContext::SetSelection(EditorSelectionState selection) {
|
|
m_selectionService.SetSelection(std::move(selection));
|
|
SyncSessionFromSelectionService();
|
|
}
|
|
|
|
void EditorContext::ClearSelection() {
|
|
m_selectionService.ClearSelection();
|
|
SyncSessionFromSelectionService();
|
|
}
|
|
|
|
void EditorContext::SyncSessionFromSelectionService() {
|
|
m_session.selection = m_selectionService.GetSelection();
|
|
}
|
|
|
|
UIEditorWorkspaceController EditorContext::BuildWorkspaceController() const {
|
|
return UIEditorWorkspaceController(
|
|
m_shellAsset.panelRegistry,
|
|
m_shellAsset.workspace,
|
|
m_shellAsset.workspaceSession);
|
|
}
|
|
|
|
const UIEditorTextMeasurer* EditorContext::GetTextMeasurer() const {
|
|
return m_textMeasurer;
|
|
}
|
|
|
|
bool EditorContext::RequestOpenSceneAsset(const std::filesystem::path& scenePath) {
|
|
const bool opened = m_runtimeCoordinator.RequestOpenSceneAsset(scenePath);
|
|
SetStatus(
|
|
"Scene",
|
|
opened
|
|
? m_runtimeCoordinator.GetLastMessage()
|
|
: m_runtimeCoordinator.GetLastMessage().empty()
|
|
? std::string("Failed to open scene asset.")
|
|
: m_runtimeCoordinator.GetLastMessage());
|
|
SyncSessionFromSelectionService();
|
|
return opened;
|
|
}
|
|
|
|
UIEditorShellInteractionDefinition EditorContext::BuildShellDefinition(
|
|
const UIEditorWorkspaceController& workspaceController,
|
|
std::string_view captureText,
|
|
EditorShellVariant variant) const {
|
|
UIEditorShellInteractionDefinition definition =
|
|
BuildEditorApplicationShellInteractionDefinition(
|
|
m_shellAsset,
|
|
workspaceController,
|
|
ComposeStatusText(m_lastStatus, m_lastMessage),
|
|
captureText,
|
|
variant);
|
|
|
|
if (UIEditorWorkspacePanelPresentationModel* scenePresentation =
|
|
FindMutablePresentation(definition.workspacePresentations, kScenePanelId);
|
|
scenePresentation != nullptr) {
|
|
scenePresentation->viewportShellModel.spec.chrome.showTopBar = true;
|
|
scenePresentation->viewportShellModel.spec.chrome.topBarHeight = 24.0f;
|
|
scenePresentation->viewportShellModel.spec.chrome.title = {};
|
|
scenePresentation->viewportShellModel.spec.chrome.subtitle = {};
|
|
scenePresentation->viewportShellModel.spec.toolItems.clear();
|
|
scenePresentation->viewportShellModel.spec.visualState.hoveredToolIndex =
|
|
Widgets::UIEditorViewportSlotInvalidIndex;
|
|
scenePresentation->viewportShellModel.spec.visualState.activeToolIndex =
|
|
Widgets::UIEditorViewportSlotInvalidIndex;
|
|
}
|
|
|
|
return definition;
|
|
}
|
|
|
|
std::string EditorContext::DescribeWorkspaceState(
|
|
const UIEditorWorkspaceController& workspaceController,
|
|
const UIEditorShellInteractionState& interactionState) const {
|
|
std::ostringstream stream = {};
|
|
stream << "active=" << workspaceController.GetWorkspace().activePanelId;
|
|
const auto visiblePanels =
|
|
CollectUIEditorWorkspaceVisiblePanels(
|
|
workspaceController.GetWorkspace(),
|
|
workspaceController.GetSession());
|
|
stream << " visible=[";
|
|
for (std::size_t index = 0; index < visiblePanels.size(); ++index) {
|
|
if (index > 0u) {
|
|
stream << ',';
|
|
}
|
|
stream << visiblePanels[index].panelId;
|
|
}
|
|
stream << ']';
|
|
|
|
const auto& dockState =
|
|
interactionState.workspaceInteractionState.dockHostInteractionState;
|
|
stream << " dragNode=" << dockState.activeTabDragNodeId;
|
|
stream << " dragPanel=" << dockState.activeTabDragPanelId;
|
|
if (dockState.dockHostState.dropPreview.visible) {
|
|
stream << " dropTarget=" << dockState.dockHostState.dropPreview.targetNodeId;
|
|
}
|
|
return stream.str();
|
|
}
|
|
|
|
std::vector<WorkspaceTraceEntry> EditorContext::SyncWorkspacePanelFrameEvents(
|
|
const std::vector<EditorWorkspacePanelFrameEvent>& panelEvents) {
|
|
return SyncWorkspacePanelEvents(panelEvents);
|
|
}
|
|
|
|
void EditorContext::SyncSceneViewportRenderRequest(
|
|
EditorSceneViewportRuntime& sceneViewportRuntime) {
|
|
(void)sceneViewportRuntime;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|
|
namespace XCEngine::UI::Editor::App {
|
|
|
|
namespace {
|
|
|
|
constexpr std::size_t kMaxConsoleEntries = 256u;
|
|
|
|
std::string ResolveViewportStatusMessage(
|
|
const UIEditorShellInteractionResult& result) {
|
|
if (result.viewportInputFrame.captureStarted) {
|
|
return "Viewport capture started.";
|
|
}
|
|
if (result.viewportInputFrame.captureEnded) {
|
|
return "Viewport capture ended.";
|
|
}
|
|
if (result.viewportInputFrame.focusGained) {
|
|
return "Viewport focused.";
|
|
}
|
|
if (result.viewportInputFrame.focusLost) {
|
|
return "Viewport focus lost.";
|
|
}
|
|
if (result.viewportInputFrame.pointerPressedInside) {
|
|
return "Viewport pointer down.";
|
|
}
|
|
if (result.viewportInputFrame.pointerReleasedInside) {
|
|
return "Viewport pointer up.";
|
|
}
|
|
if (result.viewportInputFrame.pointerMoved) {
|
|
return "Viewport pointer move.";
|
|
}
|
|
if (result.viewportInputFrame.wheelDelta != 0.0f) {
|
|
return "Viewport wheel.";
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void EditorContext::SetReadyStatus() {
|
|
SetStatus("Ready", "Application shell loaded.");
|
|
}
|
|
|
|
void EditorContext::SetStatus(
|
|
std::string status,
|
|
std::string message) {
|
|
if (m_lastStatus != status || m_lastMessage != message) {
|
|
AppendConsoleEntry(status, message);
|
|
}
|
|
m_lastStatus = std::move(status);
|
|
m_lastMessage = std::move(message);
|
|
}
|
|
|
|
void EditorContext::UpdateStatusFromShellResult(
|
|
const UIEditorWorkspaceController& workspaceController,
|
|
const UIEditorShellInteractionResult& result) {
|
|
(void)workspaceController;
|
|
|
|
if (result.commandDispatched) {
|
|
SetStatus(
|
|
std::string(GetUIEditorCommandDispatchStatusName(result.commandDispatchResult.status)),
|
|
result.commandDispatchResult.message.empty()
|
|
? result.commandDispatchResult.displayName
|
|
: result.commandDispatchResult.message);
|
|
return;
|
|
}
|
|
|
|
if (result.workspaceResult.dockHostResult.layoutChanged) {
|
|
SetStatus("Layout", result.workspaceResult.dockHostResult.layoutResult.message);
|
|
return;
|
|
}
|
|
|
|
if (result.workspaceResult.dockHostResult.commandExecuted) {
|
|
SetStatus("Workspace", result.workspaceResult.dockHostResult.commandResult.message);
|
|
return;
|
|
}
|
|
|
|
if (!result.viewportPanelId.empty()) {
|
|
std::string message = ResolveViewportStatusMessage(result);
|
|
if (!message.empty()) {
|
|
SetStatus(result.viewportPanelId, std::move(message));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!result.menuMutation.changed) {
|
|
return;
|
|
}
|
|
|
|
if (!result.itemId.empty() && !result.menuMutation.openedPopupId.empty()) {
|
|
SetStatus("Menu", result.itemId + " opened child popup.");
|
|
} else if (!result.menuId.empty() && !result.menuMutation.openedPopupId.empty()) {
|
|
SetStatus("Menu", result.menuId + " opened.");
|
|
} else {
|
|
SetStatus("Menu", "Popup chain dismissed.");
|
|
}
|
|
}
|
|
|
|
void EditorContext::AppendConsoleEntry(
|
|
std::string channel,
|
|
std::string message) {
|
|
EditorConsoleEntry entry = {};
|
|
entry.channel = std::move(channel);
|
|
entry.message = std::move(message);
|
|
m_session.consoleEntries.push_back(std::move(entry));
|
|
if (m_session.consoleEntries.size() > kMaxConsoleEntries) {
|
|
m_session.consoleEntries.erase(m_session.consoleEntries.begin());
|
|
}
|
|
}
|
|
|
|
std::vector<WorkspaceTraceEntry> EditorContext::SyncWorkspacePanelEvents(
|
|
const std::vector<EditorWorkspacePanelFrameEvent>& panelEvents) {
|
|
std::vector<WorkspaceTraceEntry> entries = {};
|
|
SyncSessionFromSelectionService();
|
|
|
|
for (const EditorWorkspacePanelFrameEvent& event : panelEvents) {
|
|
SetStatus(event.status, event.message);
|
|
entries.push_back(WorkspaceTraceEntry{
|
|
.channel = event.traceChannel,
|
|
.message = event.message,
|
|
});
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
} // namespace XCEngine::UI::Editor::App
|
|
|