feat(new_editor): add project panel and polish dock chrome

This commit is contained in:
2026-04-11 20:20:30 +08:00
parent 030230eb1f
commit 0a015b52ca
12 changed files with 1455 additions and 52 deletions

View File

@@ -41,6 +41,45 @@ constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Edit
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));
}
@@ -289,6 +328,27 @@ std::string DescribeInputEventType(const UIInputEvent& event) {
}
}
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) {
@@ -339,6 +399,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
m_shellServices.commandDispatcher = &m_shortcutManager.GetCommandDispatcher();
m_shellServices.shortcutManager = &m_shortcutManager;
m_shellServices.textMeasurer = &m_renderer;
m_projectPanel.Initialize(ResolveRepoRootPath());
m_lastStatus = "Ready";
m_lastMessage = "Old editor shell baseline loaded.";
LogRuntimeTrace("app", "workspace initialized: " + DescribeWorkspaceState());
@@ -385,6 +446,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
LogRuntimeTrace("app", "renderer initialization failed");
return false;
}
m_projectPanel.SetTextMeasurer(&m_renderer);
ShowWindow(m_hwnd, nCmdShow);
UpdateWindow(m_hwnd);
@@ -448,6 +510,11 @@ void Application::RenderFrame() {
const UIEditorShellInteractionDefinition definition = BuildShellDefinition();
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",
@@ -459,10 +526,10 @@ void Application::RenderFrame() {
m_workspaceController,
UIRect(0.0f, 0.0f, width, height),
definition,
frameEvents,
shellEvents,
m_shellServices,
metrics);
if (!frameEvents.empty() ||
if (!shellEvents.empty() ||
m_shellFrame.result.workspaceResult.dockHostResult.layoutChanged ||
m_shellFrame.result.workspaceResult.dockHostResult.commandExecuted) {
std::ostringstream frameTrace = {};
@@ -482,13 +549,24 @@ void Application::RenderFrame() {
}
ApplyHostCaptureRequests(m_shellFrame.result);
UpdateLastStatus(m_shellFrame.result);
m_projectPanel.Update(
m_shellFrame.workspaceInteractionFrame.composeFrame.contentHostFrame,
hostedContentEvents,
!m_shellFrame.result.workspaceInputSuppressed,
m_workspaceController.GetWorkspace().activePanelId == "project");
ApplyHostedContentCaptureRequests();
ApplyCurrentCursor();
AppendUIEditorShellInteraction(
const UIEditorShellComposeModel shellComposeModel =
BuildShellComposeModelFromFrame(m_shellFrame);
AppendUIEditorShellCompose(
drawList,
m_shellFrame,
m_shellInteractionState,
palette,
metrics);
m_shellFrame.shellFrame,
shellComposeModel,
m_shellInteractionState.composeState,
palette.shellPalette,
metrics.shellMetrics);
m_projectPanel.Append(drawList);
AppendShellPopups(drawList, m_shellFrame, palette, metrics);
} else {
drawList.AddText(
UIPoint(28.0f, 28.0f),
@@ -522,6 +600,14 @@ float Application::PixelsToDips(float pixels) const {
}
LPCWSTR Application::ResolveCurrentCursorResource() const {
switch (m_projectPanel.GetCursorKind()) {
case App::ProductProjectPanel::CursorKind::ResizeEW:
return IDC_SIZEWE;
case App::ProductProjectPanel::CursorKind::Arrow:
default:
break;
}
switch (Widgets::ResolveUIEditorDockHostCursorKind(
m_shellFrame.workspaceInteractionFrame.dockHostFrame.layout)) {
case Widgets::UIEditorDockHostCursorKind::ResizeEW:
@@ -639,7 +725,19 @@ void Application::ApplyHostCaptureRequests(const UIEditorShellInteractionResult&
}
}
bool Application::HasInteractiveCaptureState() const {
void Application::ApplyHostedContentCaptureRequests() {
if (m_projectPanel.WantsHostPointerCapture() && GetCapture() != m_hwnd) {
SetCapture(m_hwnd);
}
if (m_projectPanel.WantsHostPointerRelease() &&
GetCapture() == m_hwnd &&
!HasShellInteractiveCaptureState()) {
ReleaseCapture();
}
}
bool Application::HasShellInteractiveCaptureState() const {
if (m_shellInteractionState.workspaceInteractionState.dockHostInteractionState.splitterDragState.active) {
return true;
}
@@ -657,6 +755,10 @@ bool Application::HasInteractiveCaptureState() const {
return false;
}
bool Application::HasInteractiveCaptureState() const {
return HasShellInteractiveCaptureState() || m_projectPanel.HasActivePointerCapture();
}
UIEditorShellInteractionDefinition Application::BuildShellDefinition() const {
std::string statusText = m_lastStatus;
if (!m_lastMessage.empty()) {