Add scene viewport move gizmo workflow

This commit is contained in:
2026-03-29 16:18:13 +08:00
parent 2651bad080
commit 0ea1cb29e6
11 changed files with 749 additions and 13 deletions

View File

@@ -1,5 +1,6 @@
#include "Actions/ActionRouting.h"
#include "Core/IEditorContext.h"
#include "Core/ISceneManager.h"
#include "Core/ISelectionManager.h"
#include "SceneViewPanel.h"
#include "Viewport/SceneViewportOverlayRenderer.h"
@@ -11,10 +12,38 @@
namespace XCEngine {
namespace Editor {
namespace {
SceneViewportMoveGizmoContext BuildMoveGizmoContext(
IEditorContext& context,
const SceneViewportOverlayData& overlay,
const ViewportPanelContentResult& content,
const ImVec2& mousePosition) {
SceneViewportMoveGizmoContext gizmoContext = {};
gizmoContext.overlay = overlay;
gizmoContext.viewportSize = Math::Vector2(content.availableSize.x, content.availableSize.y);
gizmoContext.mousePosition = Math::Vector2(
mousePosition.x - content.itemMin.x,
mousePosition.y - content.itemMin.y);
if (context.GetSelectionManager().GetSelectionCount() == 1) {
const uint64_t selectedEntity = context.GetSelectionManager().GetSelectedEntity();
if (selectedEntity != 0) {
gizmoContext.selectedObject = context.GetSceneManager().GetEntity(selectedEntity);
}
}
return gizmoContext;
}
} // namespace
SceneViewPanel::SceneViewPanel() : Panel("Scene") {}
void SceneViewPanel::Render() {
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
UI::PanelWindowScope panel(m_name.c_str());
ImGui::PopStyleVar();
if (!panel.IsOpen()) {
return;
}
@@ -22,21 +51,55 @@ void SceneViewPanel::Render() {
const ViewportPanelContentResult content = RenderViewportPanelContent(*m_context, EditorViewportKind::Scene);
if (IViewportHostService* viewportHostService = m_context->GetViewportHostService()) {
const ImGuiIO& io = ImGui::GetIO();
const bool selectClick =
const bool hasInteractiveViewport = content.hasViewportArea && content.frame.hasTexture;
SceneViewportOverlayData overlay = {};
SceneViewportMoveGizmoContext moveGizmoContext = {};
if (hasInteractiveViewport) {
overlay = viewportHostService->GetSceneViewOverlayData();
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
if (m_moveGizmo.IsActive() &&
(moveGizmoContext.selectedObject == nullptr ||
m_context->GetSelectionManager().GetSelectedEntity() != m_moveGizmo.GetActiveEntityId())) {
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
}
m_moveGizmo.Update(moveGizmoContext);
} else if (m_moveGizmo.IsActive()) {
m_moveGizmo.CancelDrag(&m_context->GetUndoManager());
}
const bool beginMoveGizmo =
hasInteractiveViewport &&
content.hovered &&
content.frame.hasTexture &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
!m_lookDragging &&
!m_panDragging;
!m_panDragging &&
m_moveGizmo.IsHoveringHandle();
const bool selectClick =
hasInteractiveViewport &&
content.hovered &&
ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
!m_lookDragging &&
!m_panDragging &&
!m_moveGizmo.IsHoveringHandle() &&
!m_moveGizmo.IsActive();
const bool beginLookDrag =
content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Right);
content.hovered &&
!m_moveGizmo.IsActive() &&
ImGui::IsMouseClicked(ImGuiMouseButton_Right);
const bool beginPanDrag =
content.hovered && ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
content.hovered &&
!m_moveGizmo.IsActive() &&
ImGui::IsMouseClicked(ImGuiMouseButton_Middle);
if (selectClick || beginLookDrag || beginPanDrag) {
if (beginMoveGizmo || selectClick || beginLookDrag || beginPanDrag) {
ImGui::SetWindowFocus();
}
if (beginMoveGizmo) {
m_moveGizmo.TryBeginDrag(moveGizmoContext, m_context->GetUndoManager());
}
if (selectClick) {
const ImVec2 localMousePosition(
io.MousePos.x - content.itemMin.x,
@@ -52,6 +115,14 @@ void SceneViewPanel::Render() {
}
}
if (m_moveGizmo.IsActive()) {
if (ImGui::IsMouseDown(ImGuiMouseButton_Left)) {
m_moveGizmo.UpdateDrag(moveGizmoContext);
} else {
m_moveGizmo.EndDrag(m_context->GetUndoManager());
}
}
if (beginLookDrag) {
m_lookDragging = true;
m_lastLookDragDelta = ImVec2(0.0f, 0.0f);
@@ -70,7 +141,7 @@ void SceneViewPanel::Render() {
m_lastPanDragDelta = ImVec2(0.0f, 0.0f);
}
if (m_lookDragging || m_panDragging) {
if (m_lookDragging || m_panDragging || m_moveGizmo.IsActive()) {
ImGui::SetNextFrameWantCaptureMouse(true);
}
if (m_lookDragging) {
@@ -126,13 +197,16 @@ void SceneViewPanel::Render() {
viewportHostService->UpdateSceneViewInput(*m_context, input);
if (content.hasViewportArea && content.frame.hasTexture) {
const SceneViewportOverlayData overlay = viewportHostService->GetSceneViewOverlayData();
overlay = viewportHostService->GetSceneViewOverlayData();
moveGizmoContext = BuildMoveGizmoContext(*m_context, overlay, content, io.MousePos);
m_moveGizmo.Update(moveGizmoContext);
DrawSceneViewportOverlay(
ImGui::GetWindowDrawList(),
overlay,
content.itemMin,
content.itemMax,
content.availableSize);
content.availableSize,
&m_moveGizmo.GetDrawData());
}
}