Refactor new editor app context and workspace shell
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
#include "Application.h"
|
||||
|
||||
#include "Shell/ProductShellAsset.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorRuntimeTrace.h>
|
||||
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||||
|
||||
@@ -33,53 +31,12 @@ using ::XCEngine::UI::UIInputEventType;
|
||||
using ::XCEngine::UI::UIPoint;
|
||||
using ::XCEngine::UI::UIPointerButton;
|
||||
using ::XCEngine::UI::UIRect;
|
||||
using App::BuildProductShellAsset;
|
||||
using App::BuildProductShellInteractionDefinition;
|
||||
|
||||
constexpr const wchar_t* kWindowClassName = L"XCEditorShellHost";
|
||||
constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Editor";
|
||||
constexpr UINT kDefaultDpi = 96u;
|
||||
constexpr float kBaseDpiScale = 96.0f;
|
||||
|
||||
UIEditorShellComposeModel BuildShellComposeModelFromFrame(
|
||||
const UIEditorShellInteractionFrame& frame) {
|
||||
UIEditorShellComposeModel model = {};
|
||||
model.menuBarItems = frame.request.menuBarItems;
|
||||
model.toolbarButtons = frame.model.toolbarButtons;
|
||||
model.statusSegments = frame.model.statusSegments;
|
||||
model.workspacePresentations = frame.model.workspacePresentations;
|
||||
return model;
|
||||
}
|
||||
|
||||
void AppendShellPopups(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorShellInteractionFrame& frame,
|
||||
const UIEditorShellInteractionPalette& palette,
|
||||
const UIEditorShellInteractionMetrics& metrics) {
|
||||
const std::size_t popupCount =
|
||||
(std::min)(frame.request.popupRequests.size(), frame.popupFrames.size());
|
||||
for (std::size_t index = 0; index < popupCount; ++index) {
|
||||
const UIEditorShellInteractionPopupRequest& popupRequest =
|
||||
frame.request.popupRequests[index];
|
||||
const UIEditorShellInteractionPopupFrame& popupFrame =
|
||||
frame.popupFrames[index];
|
||||
Widgets::AppendUIEditorMenuPopupBackground(
|
||||
drawList,
|
||||
popupRequest.layout,
|
||||
popupRequest.widgetItems,
|
||||
popupFrame.popupState,
|
||||
palette.popupPalette,
|
||||
metrics.popupMetrics);
|
||||
Widgets::AppendUIEditorMenuPopupForeground(
|
||||
drawList,
|
||||
popupRequest.layout,
|
||||
popupRequest.widgetItems,
|
||||
popupFrame.popupState,
|
||||
palette.popupPalette,
|
||||
metrics.popupMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
Application* GetApplicationFromWindow(HWND hwnd) {
|
||||
return reinterpret_cast<Application*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
|
||||
}
|
||||
@@ -387,27 +344,6 @@ std::string DescribeProjectPanelEvent(const App::ProductProjectPanel::Event& eve
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::vector<UIInputEvent> FilterShellInputEventsForHostedContentCapture(
|
||||
const std::vector<UIInputEvent>& inputEvents) {
|
||||
std::vector<UIInputEvent> filteredEvents = {};
|
||||
filteredEvents.reserve(inputEvents.size());
|
||||
for (const UIInputEvent& event : inputEvents) {
|
||||
switch (event.type) {
|
||||
case UIInputEventType::PointerMove:
|
||||
case UIInputEventType::PointerEnter:
|
||||
case UIInputEventType::PointerLeave:
|
||||
case UIInputEventType::PointerButtonDown:
|
||||
case UIInputEventType::PointerButtonUp:
|
||||
case UIInputEventType::PointerWheel:
|
||||
break;
|
||||
default:
|
||||
filteredEvents.push_back(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filteredEvents;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int Application::Run(HINSTANCE hInstance, int nCmdShow) {
|
||||
@@ -441,28 +377,13 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
|
||||
InitializeUIEditorRuntimeTrace(logRoot);
|
||||
SetUnhandledExceptionFilter(&Application::HandleUnhandledException);
|
||||
LogRuntimeTrace("app", "initialize begin");
|
||||
m_shellAsset = BuildProductShellAsset(repoRoot);
|
||||
m_shellValidation = ValidateEditorShellAsset(m_shellAsset);
|
||||
m_validationMessage = m_shellValidation.message;
|
||||
if (!m_shellValidation.IsValid()) {
|
||||
LogRuntimeTrace("app", "shell asset validation failed: " + m_validationMessage);
|
||||
if (!m_editorContext.Initialize(repoRoot, *this)) {
|
||||
LogRuntimeTrace(
|
||||
"app",
|
||||
"shell asset validation failed: " + m_editorContext.GetValidationMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_workspaceController = UIEditorWorkspaceController(
|
||||
m_shellAsset.panelRegistry,
|
||||
m_shellAsset.workspace,
|
||||
m_shellAsset.workspaceSession);
|
||||
m_shortcutManager = BuildEditorShellShortcutManager(m_shellAsset);
|
||||
m_shortcutManager.SetHostCommandHandler(this);
|
||||
m_shellServices = {};
|
||||
m_shellServices.commandDispatcher = &m_shortcutManager.GetCommandDispatcher();
|
||||
m_shellServices.shortcutManager = &m_shortcutManager;
|
||||
m_shellServices.textMeasurer = &m_renderer;
|
||||
m_lastStatus = "Ready";
|
||||
m_lastMessage = "Old editor shell baseline loaded.";
|
||||
LogRuntimeTrace("app", "workspace initialized: " + DescribeWorkspaceState());
|
||||
|
||||
WNDCLASSEXW windowClass = {};
|
||||
windowClass.cbSize = sizeof(windowClass);
|
||||
windowClass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
@@ -505,24 +426,23 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
|
||||
LogRuntimeTrace("app", "renderer initialization failed");
|
||||
return false;
|
||||
}
|
||||
m_builtInIcons.Initialize(m_renderer, repoRoot);
|
||||
if (!m_builtInIcons.GetLastError().empty()) {
|
||||
LogRuntimeTrace("icons", m_builtInIcons.GetLastError());
|
||||
m_editorContext.AttachTextMeasurer(m_renderer);
|
||||
m_editorWorkspace.Initialize(repoRoot, m_renderer);
|
||||
if (!m_editorWorkspace.GetBuiltInIconError().empty()) {
|
||||
LogRuntimeTrace("icons", m_editorWorkspace.GetBuiltInIconError());
|
||||
}
|
||||
m_hierarchyPanel.SetBuiltInIcons(&m_builtInIcons);
|
||||
m_projectPanel.SetBuiltInIcons(&m_builtInIcons);
|
||||
m_hierarchyPanel.Initialize();
|
||||
m_projectPanel.SetTextMeasurer(&m_renderer);
|
||||
m_projectPanel.Initialize(repoRoot);
|
||||
LogRuntimeTrace(
|
||||
"app",
|
||||
"workspace initialized: " +
|
||||
m_editorContext.DescribeWorkspaceState(m_editorWorkspace.GetShellInteractionState()));
|
||||
|
||||
ShowWindow(m_hwnd, nCmdShow);
|
||||
UpdateWindow(m_hwnd);
|
||||
|
||||
m_autoScreenshot.Initialize(m_shellAsset.captureRootPath);
|
||||
m_autoScreenshot.Initialize(m_editorContext.GetShellAsset().captureRootPath);
|
||||
if (IsAutoCaptureOnStartupEnabled()) {
|
||||
m_autoScreenshot.RequestCapture("startup");
|
||||
m_lastStatus = "Capture";
|
||||
m_lastMessage = "Startup capture requested.";
|
||||
m_editorContext.SetStatus("Capture", "Startup capture requested.");
|
||||
}
|
||||
LogRuntimeTrace("app", "initialize completed");
|
||||
return true;
|
||||
@@ -535,7 +455,7 @@ void Application::Shutdown() {
|
||||
}
|
||||
|
||||
m_autoScreenshot.Shutdown();
|
||||
m_builtInIcons.Shutdown();
|
||||
m_editorWorkspace.Shutdown();
|
||||
m_renderer.Shutdown();
|
||||
|
||||
if (m_hwnd != nullptr && IsWindow(m_hwnd)) {
|
||||
@@ -572,80 +492,50 @@ void Application::RenderFrame() {
|
||||
UIRect(0.0f, 0.0f, width, height),
|
||||
UIColor(0.10f, 0.10f, 0.10f, 1.0f));
|
||||
|
||||
if (m_shellValidation.IsValid()) {
|
||||
const auto& metrics = ResolveUIEditorShellInteractionMetrics();
|
||||
const auto& palette = ResolveUIEditorShellInteractionPalette();
|
||||
const UIEditorShellInteractionDefinition definition = BuildShellDefinition();
|
||||
if (m_editorContext.IsValid()) {
|
||||
std::vector<UIInputEvent> frameEvents = std::move(m_pendingInputEvents);
|
||||
m_pendingInputEvents.clear();
|
||||
const std::vector<UIInputEvent> hostedContentEvents = frameEvents;
|
||||
const std::vector<UIInputEvent> shellEvents =
|
||||
m_projectPanel.HasActivePointerCapture()
|
||||
? FilterShellInputEventsForHostedContentCapture(frameEvents)
|
||||
: frameEvents;
|
||||
if (!frameEvents.empty()) {
|
||||
LogRuntimeTrace(
|
||||
"input",
|
||||
DescribeInputEvents(frameEvents) + " | " + DescribeWorkspaceState());
|
||||
DescribeInputEvents(frameEvents) + " | " +
|
||||
m_editorContext.DescribeWorkspaceState(
|
||||
m_editorWorkspace.GetShellInteractionState()));
|
||||
}
|
||||
|
||||
m_shellFrame = UpdateUIEditorShellInteraction(
|
||||
m_shellInteractionState,
|
||||
m_workspaceController,
|
||||
m_editorWorkspace.Update(
|
||||
m_editorContext,
|
||||
UIRect(0.0f, 0.0f, width, height),
|
||||
definition,
|
||||
shellEvents,
|
||||
m_shellServices,
|
||||
metrics);
|
||||
if (!shellEvents.empty() ||
|
||||
m_shellFrame.result.workspaceResult.dockHostResult.layoutChanged ||
|
||||
m_shellFrame.result.workspaceResult.dockHostResult.commandExecuted) {
|
||||
frameEvents,
|
||||
BuildCaptureStatusText());
|
||||
const UIEditorShellInteractionFrame& shellFrame =
|
||||
m_editorWorkspace.GetShellFrame();
|
||||
if (!frameEvents.empty() ||
|
||||
shellFrame.result.workspaceResult.dockHostResult.layoutChanged ||
|
||||
shellFrame.result.workspaceResult.dockHostResult.commandExecuted) {
|
||||
std::ostringstream frameTrace = {};
|
||||
frameTrace << "result consumed="
|
||||
<< (m_shellFrame.result.consumed ? "true" : "false")
|
||||
<< (shellFrame.result.consumed ? "true" : "false")
|
||||
<< " layoutChanged="
|
||||
<< (m_shellFrame.result.workspaceResult.dockHostResult.layoutChanged ? "true" : "false")
|
||||
<< (shellFrame.result.workspaceResult.dockHostResult.layoutChanged ? "true" : "false")
|
||||
<< " commandExecuted="
|
||||
<< (m_shellFrame.result.workspaceResult.dockHostResult.commandExecuted ? "true" : "false")
|
||||
<< (shellFrame.result.workspaceResult.dockHostResult.commandExecuted ? "true" : "false")
|
||||
<< " active="
|
||||
<< m_workspaceController.GetWorkspace().activePanelId
|
||||
<< m_editorContext.GetWorkspaceController().GetWorkspace().activePanelId
|
||||
<< " message="
|
||||
<< m_shellFrame.result.workspaceResult.dockHostResult.layoutResult.message;
|
||||
<< shellFrame.result.workspaceResult.dockHostResult.layoutResult.message;
|
||||
LogRuntimeTrace(
|
||||
"frame",
|
||||
frameTrace.str());
|
||||
}
|
||||
ApplyHostCaptureRequests(m_shellFrame.result);
|
||||
UpdateLastStatus(m_shellFrame.result);
|
||||
m_hierarchyPanel.Update(
|
||||
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
||||
hostedContentEvents,
|
||||
!m_shellFrame.result.workspaceInputSuppressed,
|
||||
m_workspaceController.GetWorkspace().activePanelId == "hierarchy");
|
||||
m_projectPanel.Update(
|
||||
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
||||
hostedContentEvents,
|
||||
!m_shellFrame.result.workspaceInputSuppressed,
|
||||
m_workspaceController.GetWorkspace().activePanelId == "project");
|
||||
for (const App::ProductProjectPanel::Event& event : m_projectPanel.GetFrameEvents()) {
|
||||
ApplyHostCaptureRequests(shellFrame.result);
|
||||
for (const App::ProductProjectPanel::Event& event : m_editorWorkspace.GetProjectPanelEvents()) {
|
||||
LogRuntimeTrace("project", DescribeProjectPanelEvent(event));
|
||||
m_lastStatus = "Project";
|
||||
m_lastMessage = DescribeProjectPanelEvent(event);
|
||||
m_editorContext.SetStatus("Project", DescribeProjectPanelEvent(event));
|
||||
}
|
||||
ApplyHostedContentCaptureRequests();
|
||||
ApplyCurrentCursor();
|
||||
const UIEditorShellComposeModel shellComposeModel =
|
||||
BuildShellComposeModelFromFrame(m_shellFrame);
|
||||
AppendUIEditorShellCompose(
|
||||
drawList,
|
||||
m_shellFrame.shellFrame,
|
||||
shellComposeModel,
|
||||
m_shellInteractionState.composeState,
|
||||
palette.shellPalette,
|
||||
metrics.shellMetrics);
|
||||
m_hierarchyPanel.Append(drawList);
|
||||
m_projectPanel.Append(drawList);
|
||||
AppendShellPopups(drawList, m_shellFrame, palette, metrics);
|
||||
m_editorWorkspace.Append(drawList);
|
||||
} else {
|
||||
drawList.AddText(
|
||||
UIPoint(28.0f, 28.0f),
|
||||
@@ -654,7 +544,9 @@ void Application::RenderFrame() {
|
||||
16.0f);
|
||||
drawList.AddText(
|
||||
UIPoint(28.0f, 54.0f),
|
||||
m_validationMessage.empty() ? std::string("Unknown validation error.") : m_validationMessage,
|
||||
m_editorContext.GetValidationMessage().empty()
|
||||
? std::string("Unknown validation error.")
|
||||
: m_editorContext.GetValidationMessage(),
|
||||
UIColor(0.72f, 0.72f, 0.72f, 1.0f),
|
||||
12.0f);
|
||||
}
|
||||
@@ -695,7 +587,7 @@ bool Application::IsPointerInsideClientArea() const {
|
||||
}
|
||||
|
||||
LPCWSTR Application::ResolveCurrentCursorResource() const {
|
||||
switch (m_projectPanel.GetCursorKind()) {
|
||||
switch (m_editorWorkspace.GetHostedContentCursorKind()) {
|
||||
case App::ProductProjectPanel::CursorKind::ResizeEW:
|
||||
return IDC_SIZEWE;
|
||||
case App::ProductProjectPanel::CursorKind::Arrow:
|
||||
@@ -703,8 +595,7 @@ LPCWSTR Application::ResolveCurrentCursorResource() const {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Widgets::ResolveUIEditorDockHostCursorKind(
|
||||
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout)) {
|
||||
switch (m_editorWorkspace.GetDockCursorKind()) {
|
||||
case Widgets::UIEditorDockHostCursorKind::ResizeEW:
|
||||
return IDC_SIZEWE;
|
||||
case Widgets::UIEditorDockHostCursorKind::ResizeNS:
|
||||
@@ -735,38 +626,28 @@ UIPoint Application::ConvertClientPixelsToDips(LONG x, LONG y) const {
|
||||
PixelsToDips(static_cast<float>(y)));
|
||||
}
|
||||
|
||||
std::string Application::BuildCaptureStatusText() const {
|
||||
if (m_autoScreenshot.HasPendingCapture()) {
|
||||
return "Shot pending...";
|
||||
}
|
||||
|
||||
if (!m_autoScreenshot.GetLastCaptureError().empty()) {
|
||||
return TruncateText(m_autoScreenshot.GetLastCaptureError(), 38u);
|
||||
}
|
||||
|
||||
if (!m_autoScreenshot.GetLastCaptureSummary().empty()) {
|
||||
return TruncateText(m_autoScreenshot.GetLastCaptureSummary(), 38u);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void Application::LogRuntimeTrace(
|
||||
std::string_view channel,
|
||||
std::string_view message) const {
|
||||
AppendUIEditorRuntimeTrace(channel, message);
|
||||
}
|
||||
|
||||
std::string Application::DescribeWorkspaceState() const {
|
||||
std::ostringstream stream = {};
|
||||
stream << "active=" << m_workspaceController.GetWorkspace().activePanelId;
|
||||
const auto visiblePanels =
|
||||
CollectUIEditorWorkspaceVisiblePanels(
|
||||
m_workspaceController.GetWorkspace(),
|
||||
m_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 =
|
||||
m_shellInteractionState.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::string Application::DescribeInputEvents(
|
||||
const std::vector<UIInputEvent>& events) const {
|
||||
std::ostringstream stream = {};
|
||||
@@ -825,116 +706,19 @@ void Application::ApplyHostCaptureRequests(const UIEditorShellInteractionResult&
|
||||
}
|
||||
|
||||
void Application::ApplyHostedContentCaptureRequests() {
|
||||
if (m_projectPanel.WantsHostPointerCapture() && GetCapture() != m_hwnd) {
|
||||
if (m_editorWorkspace.WantsHostPointerCapture() && GetCapture() != m_hwnd) {
|
||||
SetCapture(m_hwnd);
|
||||
}
|
||||
|
||||
if (m_projectPanel.WantsHostPointerRelease() &&
|
||||
if (m_editorWorkspace.WantsHostPointerRelease() &&
|
||||
GetCapture() == m_hwnd &&
|
||||
!HasShellInteractiveCaptureState()) {
|
||||
!m_editorWorkspace.HasShellInteractiveCapture()) {
|
||||
ReleaseCapture();
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::HasShellInteractiveCaptureState() const {
|
||||
if (m_shellInteractionState.workspaceInteractionState.dockHostInteractionState.splitterDragState.active) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_shellInteractionState.workspaceInteractionState.dockHostInteractionState.activeTabDragNodeId.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& panelState : m_shellInteractionState.workspaceInteractionState.composeState.panelStates) {
|
||||
if (panelState.viewportShellState.inputBridgeState.captured) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Application::HasInteractiveCaptureState() const {
|
||||
return HasShellInteractiveCaptureState() || m_projectPanel.HasActivePointerCapture();
|
||||
}
|
||||
|
||||
UIEditorShellInteractionDefinition Application::BuildShellDefinition() const {
|
||||
std::string statusText = m_lastStatus;
|
||||
if (!m_lastMessage.empty()) {
|
||||
statusText += statusText.empty() ? m_lastMessage : ": " + m_lastMessage;
|
||||
}
|
||||
|
||||
std::string captureText = {};
|
||||
if (m_autoScreenshot.HasPendingCapture()) {
|
||||
captureText = "Shot pending...";
|
||||
} else if (!m_autoScreenshot.GetLastCaptureError().empty()) {
|
||||
captureText = TruncateText(m_autoScreenshot.GetLastCaptureError(), 38u);
|
||||
} else if (!m_autoScreenshot.GetLastCaptureSummary().empty()) {
|
||||
captureText = TruncateText(m_autoScreenshot.GetLastCaptureSummary(), 38u);
|
||||
}
|
||||
|
||||
return BuildProductShellInteractionDefinition(
|
||||
m_shellAsset,
|
||||
m_workspaceController,
|
||||
statusText,
|
||||
captureText);
|
||||
}
|
||||
|
||||
void Application::UpdateLastStatus(const UIEditorShellInteractionResult& result) {
|
||||
if (result.commandDispatched) {
|
||||
m_lastStatus = std::string(GetUIEditorCommandDispatchStatusName(result.commandDispatchResult.status));
|
||||
m_lastMessage = result.commandDispatchResult.message.empty()
|
||||
? result.commandDispatchResult.displayName
|
||||
: result.commandDispatchResult.message;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.workspaceResult.dockHostResult.layoutChanged) {
|
||||
m_lastStatus = "Layout";
|
||||
m_lastMessage = result.workspaceResult.dockHostResult.layoutResult.message;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.workspaceResult.dockHostResult.commandExecuted) {
|
||||
m_lastStatus = "Workspace";
|
||||
m_lastMessage = result.workspaceResult.dockHostResult.commandResult.message;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.viewportPanelId.empty()) {
|
||||
m_lastStatus = result.viewportPanelId;
|
||||
if (result.viewportInputFrame.captureStarted) {
|
||||
m_lastMessage = "Viewport capture started.";
|
||||
} else if (result.viewportInputFrame.captureEnded) {
|
||||
m_lastMessage = "Viewport capture ended.";
|
||||
} else if (result.viewportInputFrame.focusGained) {
|
||||
m_lastMessage = "Viewport focused.";
|
||||
} else if (result.viewportInputFrame.focusLost) {
|
||||
m_lastMessage = "Viewport focus lost.";
|
||||
} else if (result.viewportInputFrame.pointerPressedInside) {
|
||||
m_lastMessage = "Viewport pointer down.";
|
||||
} else if (result.viewportInputFrame.pointerReleasedInside) {
|
||||
m_lastMessage = "Viewport pointer up.";
|
||||
} else if (result.viewportInputFrame.pointerMoved) {
|
||||
m_lastMessage = "Viewport pointer move.";
|
||||
} else if (result.viewportInputFrame.wheelDelta != 0.0f) {
|
||||
m_lastMessage = "Viewport wheel.";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.menuMutation.changed) {
|
||||
if (!result.itemId.empty() && !result.menuMutation.openedPopupId.empty()) {
|
||||
m_lastStatus = "Menu";
|
||||
m_lastMessage = result.itemId + " opened child popup.";
|
||||
} else if (!result.menuId.empty() && !result.menuMutation.openedPopupId.empty()) {
|
||||
m_lastStatus = "Menu";
|
||||
m_lastMessage = result.menuId + " opened.";
|
||||
} else {
|
||||
m_lastStatus = "Menu";
|
||||
m_lastMessage = "Popup chain dismissed.";
|
||||
}
|
||||
}
|
||||
return m_editorWorkspace.HasInteractiveCapture();
|
||||
}
|
||||
|
||||
void Application::QueuePointerEvent(
|
||||
@@ -1082,8 +866,7 @@ UIEditorHostCommandDispatchResult Application::DispatchHostCommand(
|
||||
if (commandId == "help.about") {
|
||||
result.commandExecuted = true;
|
||||
result.message = "About dialog will be wired after modal layer lands.";
|
||||
m_lastStatus = "About";
|
||||
m_lastMessage = result.message;
|
||||
m_editorContext.SetStatus("About", result.message);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,10 @@
|
||||
#include <Host/InputModifierTracker.h>
|
||||
#include <Host/NativeRenderer.h>
|
||||
|
||||
#include "Icons/ProductBuiltInIcons.h"
|
||||
#include "Panels/ProductHierarchyPanel.h"
|
||||
#include "Panels/ProductProjectPanel.h"
|
||||
#include "Core/ProductEditorContext.h"
|
||||
#include "Workspace/ProductEditorWorkspace.h"
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
|
||||
#include <XCEditor/Shell/UIEditorShellAsset.h>
|
||||
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
@@ -53,14 +49,11 @@ private:
|
||||
float GetDpiScale() const;
|
||||
float PixelsToDips(float pixels) const;
|
||||
::XCEngine::UI::UIPoint ConvertClientPixelsToDips(LONG x, LONG y) const;
|
||||
std::string BuildCaptureStatusText() const;
|
||||
void LogRuntimeTrace(std::string_view channel, std::string_view message) const;
|
||||
void ApplyHostCaptureRequests(const UIEditorShellInteractionResult& result);
|
||||
void ApplyHostedContentCaptureRequests();
|
||||
bool HasShellInteractiveCaptureState() const;
|
||||
bool HasInteractiveCaptureState() const;
|
||||
UIEditorShellInteractionDefinition BuildShellDefinition() const;
|
||||
void UpdateLastStatus(const UIEditorShellInteractionResult& result);
|
||||
std::string DescribeWorkspaceState() const;
|
||||
std::string DescribeInputEvents(
|
||||
const std::vector<::XCEngine::UI::UIInputEvent>& events) const;
|
||||
void QueuePointerEvent(
|
||||
@@ -82,21 +75,10 @@ private:
|
||||
::XCEngine::UI::Editor::Host::NativeRenderer m_renderer = {};
|
||||
::XCEngine::UI::Editor::Host::AutoScreenshotController m_autoScreenshot = {};
|
||||
::XCEngine::UI::Editor::Host::InputModifierTracker m_inputModifierTracker = {};
|
||||
EditorShellAsset m_shellAsset = {};
|
||||
EditorShellAssetValidationResult m_shellValidation = {};
|
||||
UIEditorWorkspaceController m_workspaceController = {};
|
||||
UIEditorShortcutManager m_shortcutManager = {};
|
||||
App::ProductBuiltInIcons m_builtInIcons = {};
|
||||
App::ProductHierarchyPanel m_hierarchyPanel = {};
|
||||
App::ProductProjectPanel m_projectPanel = {};
|
||||
UIEditorShellInteractionServices m_shellServices = {};
|
||||
UIEditorShellInteractionState m_shellInteractionState = {};
|
||||
UIEditorShellInteractionFrame m_shellFrame = {};
|
||||
App::ProductEditorContext m_editorContext = {};
|
||||
App::ProductEditorWorkspace m_editorWorkspace = {};
|
||||
std::vector<::XCEngine::UI::UIInputEvent> m_pendingInputEvents = {};
|
||||
bool m_trackingMouseLeave = false;
|
||||
std::string m_validationMessage = {};
|
||||
std::string m_lastStatus = {};
|
||||
std::string m_lastMessage = {};
|
||||
UINT m_windowDpi = 96u;
|
||||
float m_dpiScale = 1.0f;
|
||||
};
|
||||
|
||||
187
new_editor/app/Core/ProductEditorContext.cpp
Normal file
187
new_editor/app/Core/ProductEditorContext.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
#include "ProductEditorContext.h"
|
||||
|
||||
#include "Shell/ProductShellAsset.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::XCEngine::UI::Editor::BuildEditorShellShortcutManager;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ProductEditorContext::Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
UIEditorHostCommandHandler& hostCommandHandler) {
|
||||
m_shellAsset = BuildProductShellAsset(repoRoot);
|
||||
m_shellValidation = ValidateEditorShellAsset(m_shellAsset);
|
||||
if (!m_shellValidation.IsValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_workspaceController = UIEditorWorkspaceController(
|
||||
m_shellAsset.panelRegistry,
|
||||
m_shellAsset.workspace,
|
||||
m_shellAsset.workspaceSession);
|
||||
m_shortcutManager = BuildEditorShellShortcutManager(m_shellAsset);
|
||||
m_shortcutManager.SetHostCommandHandler(&hostCommandHandler);
|
||||
m_shellServices = {};
|
||||
m_shellServices.commandDispatcher = &m_shortcutManager.GetCommandDispatcher();
|
||||
m_shellServices.shortcutManager = &m_shortcutManager;
|
||||
SetReadyStatus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProductEditorContext::AttachTextMeasurer(
|
||||
const UIEditorTextMeasurer& textMeasurer) {
|
||||
m_shellServices.textMeasurer = &textMeasurer;
|
||||
}
|
||||
|
||||
bool ProductEditorContext::IsValid() const {
|
||||
return m_shellValidation.IsValid();
|
||||
}
|
||||
|
||||
const std::string& ProductEditorContext::GetValidationMessage() const {
|
||||
return m_shellValidation.message;
|
||||
}
|
||||
|
||||
const EditorShellAsset& ProductEditorContext::GetShellAsset() const {
|
||||
return m_shellAsset;
|
||||
}
|
||||
|
||||
UIEditorWorkspaceController& ProductEditorContext::GetWorkspaceController() {
|
||||
return m_workspaceController;
|
||||
}
|
||||
|
||||
const UIEditorWorkspaceController& ProductEditorContext::GetWorkspaceController() const {
|
||||
return m_workspaceController;
|
||||
}
|
||||
|
||||
const UIEditorShellInteractionServices& ProductEditorContext::GetShellServices() const {
|
||||
return m_shellServices;
|
||||
}
|
||||
|
||||
UIEditorShellInteractionDefinition ProductEditorContext::BuildShellDefinition(
|
||||
std::string_view captureText) const {
|
||||
return BuildProductShellInteractionDefinition(
|
||||
m_shellAsset,
|
||||
m_workspaceController,
|
||||
ComposeStatusText(m_lastStatus, m_lastMessage),
|
||||
captureText);
|
||||
}
|
||||
|
||||
void ProductEditorContext::SetReadyStatus() {
|
||||
SetStatus("Ready", "Old editor shell baseline loaded.");
|
||||
}
|
||||
|
||||
void ProductEditorContext::SetStatus(
|
||||
std::string status,
|
||||
std::string message) {
|
||||
m_lastStatus = std::move(status);
|
||||
m_lastMessage = std::move(message);
|
||||
}
|
||||
|
||||
void ProductEditorContext::UpdateStatusFromShellResult(
|
||||
const UIEditorShellInteractionResult& result) {
|
||||
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 = {};
|
||||
if (result.viewportInputFrame.captureStarted) {
|
||||
message = "Viewport capture started.";
|
||||
} else if (result.viewportInputFrame.captureEnded) {
|
||||
message = "Viewport capture ended.";
|
||||
} else if (result.viewportInputFrame.focusGained) {
|
||||
message = "Viewport focused.";
|
||||
} else if (result.viewportInputFrame.focusLost) {
|
||||
message = "Viewport focus lost.";
|
||||
} else if (result.viewportInputFrame.pointerPressedInside) {
|
||||
message = "Viewport pointer down.";
|
||||
} else if (result.viewportInputFrame.pointerReleasedInside) {
|
||||
message = "Viewport pointer up.";
|
||||
} else if (result.viewportInputFrame.pointerMoved) {
|
||||
message = "Viewport pointer move.";
|
||||
} else if (result.viewportInputFrame.wheelDelta != 0.0f) {
|
||||
message = "Viewport wheel.";
|
||||
}
|
||||
|
||||
if (!message.empty()) {
|
||||
SetStatus(result.viewportPanelId, std::move(message));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.menuMutation.changed) {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ProductEditorContext::DescribeWorkspaceState(
|
||||
const UIEditorShellInteractionState& interactionState) const {
|
||||
std::ostringstream stream = {};
|
||||
stream << "active=" << m_workspaceController.GetWorkspace().activePanelId;
|
||||
const auto visiblePanels =
|
||||
CollectUIEditorWorkspaceVisiblePanels(
|
||||
m_workspaceController.GetWorkspace(),
|
||||
m_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();
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
55
new_editor/app/Core/ProductEditorContext.h
Normal file
55
new_editor/app/Core/ProductEditorContext.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <XCEditor/Foundation/UIEditorShortcutManager.h>
|
||||
#include <XCEditor/Shell/UIEditorShellAsset.h>
|
||||
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||
#include <XCEditor/Shell/UIEditorWorkspaceController.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace XCEngine::UI::Editor {
|
||||
|
||||
class UIEditorHostCommandHandler;
|
||||
struct UIEditorTextMeasurer;
|
||||
|
||||
} // namespace XCEngine::UI::Editor
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class ProductEditorContext {
|
||||
public:
|
||||
bool Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
UIEditorHostCommandHandler& hostCommandHandler);
|
||||
void AttachTextMeasurer(const UIEditorTextMeasurer& textMeasurer);
|
||||
|
||||
bool IsValid() const;
|
||||
const std::string& GetValidationMessage() const;
|
||||
const EditorShellAsset& GetShellAsset() const;
|
||||
|
||||
UIEditorWorkspaceController& GetWorkspaceController();
|
||||
const UIEditorWorkspaceController& GetWorkspaceController() const;
|
||||
const UIEditorShellInteractionServices& GetShellServices() const;
|
||||
|
||||
UIEditorShellInteractionDefinition BuildShellDefinition(
|
||||
std::string_view captureText) const;
|
||||
|
||||
void SetReadyStatus();
|
||||
void SetStatus(std::string status, std::string message);
|
||||
void UpdateStatusFromShellResult(const UIEditorShellInteractionResult& result);
|
||||
std::string DescribeWorkspaceState(
|
||||
const UIEditorShellInteractionState& interactionState) const;
|
||||
|
||||
private:
|
||||
EditorShellAsset m_shellAsset = {};
|
||||
EditorShellAssetValidationResult m_shellValidation = {};
|
||||
UIEditorWorkspaceController m_workspaceController = {};
|
||||
UIEditorShortcutManager m_shortcutManager = {};
|
||||
UIEditorShellInteractionServices m_shellServices = {};
|
||||
std::string m_lastStatus = {};
|
||||
std::string m_lastMessage = {};
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
210
new_editor/app/Workspace/ProductEditorWorkspace.cpp
Normal file
210
new_editor/app/Workspace/ProductEditorWorkspace.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "ProductEditorWorkspace.h"
|
||||
|
||||
#include <XCEditor/Shell/UIEditorShellCompose.h>
|
||||
#include <XCEditor/Foundation/UIEditorTheme.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
namespace {
|
||||
|
||||
using ::XCEngine::UI::UIColor;
|
||||
using ::XCEngine::UI::UIDrawList;
|
||||
using ::XCEngine::UI::UIInputEvent;
|
||||
using ::XCEngine::UI::UIInputEventType;
|
||||
|
||||
UIEditorShellComposeModel BuildShellComposeModelFromFrame(
|
||||
const UIEditorShellInteractionFrame& frame) {
|
||||
UIEditorShellComposeModel model = {};
|
||||
model.menuBarItems = frame.request.menuBarItems;
|
||||
model.toolbarButtons = frame.model.toolbarButtons;
|
||||
model.statusSegments = frame.model.statusSegments;
|
||||
model.workspacePresentations = frame.model.workspacePresentations;
|
||||
return model;
|
||||
}
|
||||
|
||||
void AppendShellPopups(
|
||||
UIDrawList& drawList,
|
||||
const UIEditorShellInteractionFrame& frame,
|
||||
const UIEditorShellInteractionPalette& palette,
|
||||
const UIEditorShellInteractionMetrics& metrics) {
|
||||
const std::size_t popupCount =
|
||||
(std::min)(frame.request.popupRequests.size(), frame.popupFrames.size());
|
||||
for (std::size_t index = 0; index < popupCount; ++index) {
|
||||
const UIEditorShellInteractionPopupRequest& popupRequest =
|
||||
frame.request.popupRequests[index];
|
||||
const UIEditorShellInteractionPopupFrame& popupFrame =
|
||||
frame.popupFrames[index];
|
||||
Widgets::AppendUIEditorMenuPopupBackground(
|
||||
drawList,
|
||||
popupRequest.layout,
|
||||
popupRequest.widgetItems,
|
||||
popupFrame.popupState,
|
||||
palette.popupPalette,
|
||||
metrics.popupMetrics);
|
||||
Widgets::AppendUIEditorMenuPopupForeground(
|
||||
drawList,
|
||||
popupRequest.layout,
|
||||
popupRequest.widgetItems,
|
||||
popupFrame.popupState,
|
||||
palette.popupPalette,
|
||||
metrics.popupMetrics);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<UIInputEvent> FilterShellInputEventsForHostedContentCapture(
|
||||
const std::vector<UIInputEvent>& inputEvents) {
|
||||
std::vector<UIInputEvent> filteredEvents = {};
|
||||
filteredEvents.reserve(inputEvents.size());
|
||||
for (const UIInputEvent& event : inputEvents) {
|
||||
switch (event.type) {
|
||||
case UIInputEventType::PointerMove:
|
||||
case UIInputEventType::PointerEnter:
|
||||
case UIInputEventType::PointerLeave:
|
||||
case UIInputEventType::PointerButtonDown:
|
||||
case UIInputEventType::PointerButtonUp:
|
||||
case UIInputEventType::PointerWheel:
|
||||
break;
|
||||
default:
|
||||
filteredEvents.push_back(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filteredEvents;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ProductEditorWorkspace::Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
Host::NativeRenderer& renderer) {
|
||||
m_builtInIcons.Initialize(renderer, repoRoot);
|
||||
m_hierarchyPanel.SetBuiltInIcons(&m_builtInIcons);
|
||||
m_projectPanel.SetBuiltInIcons(&m_builtInIcons);
|
||||
m_projectPanel.SetTextMeasurer(&renderer);
|
||||
m_hierarchyPanel.Initialize();
|
||||
m_projectPanel.Initialize(repoRoot);
|
||||
}
|
||||
|
||||
void ProductEditorWorkspace::Shutdown() {
|
||||
m_shellFrame = {};
|
||||
m_shellInteractionState = {};
|
||||
m_builtInIcons.Shutdown();
|
||||
}
|
||||
|
||||
void ProductEditorWorkspace::Update(
|
||||
ProductEditorContext& context,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||
std::string_view captureText) {
|
||||
const auto& metrics = ResolveUIEditorShellInteractionMetrics();
|
||||
const UIEditorShellInteractionDefinition definition =
|
||||
context.BuildShellDefinition(captureText);
|
||||
const std::vector<UIInputEvent> hostedContentEvents = inputEvents;
|
||||
const std::vector<UIInputEvent> shellEvents =
|
||||
HasHostedContentCapture()
|
||||
? FilterShellInputEventsForHostedContentCapture(inputEvents)
|
||||
: inputEvents;
|
||||
|
||||
m_shellFrame = UpdateUIEditorShellInteraction(
|
||||
m_shellInteractionState,
|
||||
context.GetWorkspaceController(),
|
||||
bounds,
|
||||
definition,
|
||||
shellEvents,
|
||||
context.GetShellServices(),
|
||||
metrics);
|
||||
context.UpdateStatusFromShellResult(m_shellFrame.result);
|
||||
|
||||
const std::string& activePanelId =
|
||||
context.GetWorkspaceController().GetWorkspace().activePanelId;
|
||||
m_hierarchyPanel.Update(
|
||||
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
||||
hostedContentEvents,
|
||||
!m_shellFrame.result.workspaceInputSuppressed,
|
||||
activePanelId == "hierarchy");
|
||||
m_projectPanel.Update(
|
||||
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
|
||||
hostedContentEvents,
|
||||
!m_shellFrame.result.workspaceInputSuppressed,
|
||||
activePanelId == "project");
|
||||
}
|
||||
|
||||
void ProductEditorWorkspace::Append(UIDrawList& drawList) const {
|
||||
const auto& metrics = ResolveUIEditorShellInteractionMetrics();
|
||||
const auto& palette = ResolveUIEditorShellInteractionPalette();
|
||||
const UIEditorShellComposeModel shellComposeModel =
|
||||
BuildShellComposeModelFromFrame(m_shellFrame);
|
||||
AppendUIEditorShellCompose(
|
||||
drawList,
|
||||
m_shellFrame.shellFrame,
|
||||
shellComposeModel,
|
||||
m_shellInteractionState.composeState,
|
||||
palette.shellPalette,
|
||||
metrics.shellMetrics);
|
||||
m_hierarchyPanel.Append(drawList);
|
||||
m_projectPanel.Append(drawList);
|
||||
AppendShellPopups(drawList, m_shellFrame, palette, metrics);
|
||||
}
|
||||
|
||||
const UIEditorShellInteractionFrame& ProductEditorWorkspace::GetShellFrame() const {
|
||||
return m_shellFrame;
|
||||
}
|
||||
|
||||
const UIEditorShellInteractionState& ProductEditorWorkspace::GetShellInteractionState() const {
|
||||
return m_shellInteractionState;
|
||||
}
|
||||
|
||||
const std::vector<ProductProjectPanel::Event>& ProductEditorWorkspace::GetProjectPanelEvents() const {
|
||||
return m_projectPanel.GetFrameEvents();
|
||||
}
|
||||
|
||||
const std::string& ProductEditorWorkspace::GetBuiltInIconError() const {
|
||||
return m_builtInIcons.GetLastError();
|
||||
}
|
||||
|
||||
ProductProjectPanel::CursorKind ProductEditorWorkspace::GetHostedContentCursorKind() const {
|
||||
return m_projectPanel.GetCursorKind();
|
||||
}
|
||||
|
||||
Widgets::UIEditorDockHostCursorKind ProductEditorWorkspace::GetDockCursorKind() const {
|
||||
return Widgets::ResolveUIEditorDockHostCursorKind(
|
||||
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout);
|
||||
}
|
||||
|
||||
bool ProductEditorWorkspace::WantsHostPointerCapture() const {
|
||||
return m_projectPanel.WantsHostPointerCapture();
|
||||
}
|
||||
|
||||
bool ProductEditorWorkspace::WantsHostPointerRelease() const {
|
||||
return m_projectPanel.WantsHostPointerRelease();
|
||||
}
|
||||
|
||||
bool ProductEditorWorkspace::HasHostedContentCapture() const {
|
||||
return m_projectPanel.HasActivePointerCapture();
|
||||
}
|
||||
|
||||
bool ProductEditorWorkspace::HasShellInteractiveCapture() const {
|
||||
if (m_shellInteractionState.workspaceInteractionState.dockHostInteractionState.splitterDragState.active) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_shellInteractionState.workspaceInteractionState.dockHostInteractionState.activeTabDragNodeId.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& panelState : m_shellInteractionState.workspaceInteractionState.composeState.panelStates) {
|
||||
if (panelState.viewportShellState.inputBridgeState.captured) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProductEditorWorkspace::HasInteractiveCapture() const {
|
||||
return HasShellInteractiveCapture() || HasHostedContentCapture();
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
55
new_editor/app/Workspace/ProductEditorWorkspace.h
Normal file
55
new_editor/app/Workspace/ProductEditorWorkspace.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "Core/ProductEditorContext.h"
|
||||
#include "Icons/ProductBuiltInIcons.h"
|
||||
#include "Panels/ProductHierarchyPanel.h"
|
||||
#include "Panels/ProductProjectPanel.h"
|
||||
|
||||
#include <Host/NativeRenderer.h>
|
||||
|
||||
#include <XCEditor/Shell/UIEditorShellInteraction.h>
|
||||
|
||||
#include <XCEngine/UI/DrawData.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace XCEngine::UI::Editor::App {
|
||||
|
||||
class ProductEditorWorkspace {
|
||||
public:
|
||||
void Initialize(
|
||||
const std::filesystem::path& repoRoot,
|
||||
Host::NativeRenderer& renderer);
|
||||
void Shutdown();
|
||||
|
||||
void Update(
|
||||
ProductEditorContext& context,
|
||||
const ::XCEngine::UI::UIRect& bounds,
|
||||
const std::vector<::XCEngine::UI::UIInputEvent>& inputEvents,
|
||||
std::string_view captureText);
|
||||
void Append(::XCEngine::UI::UIDrawList& drawList) const;
|
||||
|
||||
const UIEditorShellInteractionFrame& GetShellFrame() const;
|
||||
const UIEditorShellInteractionState& GetShellInteractionState() const;
|
||||
const std::vector<ProductProjectPanel::Event>& GetProjectPanelEvents() const;
|
||||
const std::string& GetBuiltInIconError() const;
|
||||
|
||||
ProductProjectPanel::CursorKind GetHostedContentCursorKind() const;
|
||||
Widgets::UIEditorDockHostCursorKind GetDockCursorKind() const;
|
||||
bool WantsHostPointerCapture() const;
|
||||
bool WantsHostPointerRelease() const;
|
||||
bool HasHostedContentCapture() const;
|
||||
bool HasShellInteractiveCapture() const;
|
||||
bool HasInteractiveCapture() const;
|
||||
|
||||
private:
|
||||
ProductBuiltInIcons m_builtInIcons = {};
|
||||
ProductHierarchyPanel m_hierarchyPanel = {};
|
||||
ProductProjectPanel m_projectPanel = {};
|
||||
UIEditorShellInteractionState m_shellInteractionState = {};
|
||||
UIEditorShellInteractionFrame m_shellFrame = {};
|
||||
};
|
||||
|
||||
} // namespace XCEngine::UI::Editor::App
|
||||
Reference in New Issue
Block a user