From ed5aa597adeae3889a79599f0d25b1e39f4517b0 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Mon, 23 Jun 2025 18:04:53 +0200 Subject: [PATCH] feat(editor): undoing movement/transformations --- core/src/partassembly.cpp | 14 ++++++++++++++ core/src/partassembly.h | 9 +++++++++ editor/mainglwidget.cpp | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/core/src/partassembly.cpp b/core/src/partassembly.cpp index 5fe7114..96518e4 100644 --- a/core/src/partassembly.cpp +++ b/core/src/partassembly.cpp @@ -117,4 +117,18 @@ void PartAssembly::Scale(Vector3 newSize, bool scaleUp) { } _bounds = _bounds * factor; +} + +std::vector PartAssembly::GetCurrentTransforms() { + std::vector transforms; + + for (auto part : parts) { + PartTransformState t; + t.part = part; + t.cframe = part->cframe; + t.size = part->size; + transforms.push_back(t); + } + + return transforms; } \ No newline at end of file diff --git a/core/src/partassembly.h b/core/src/partassembly.h index 81ca398..d0eee58 100644 --- a/core/src/partassembly.h +++ b/core/src/partassembly.h @@ -8,6 +8,12 @@ class Part; class Instance; class Selection; +struct PartTransformState { + std::shared_ptr part; + Vector3 size; + CFrame cframe; +}; + class PartAssembly { CFrame _assemblyOrigin; Vector3 _bounds; @@ -25,6 +31,9 @@ public: inline Vector3 size() { return _size; }; inline bool multipleSelected() { return parts.size() > 1; } + // Gets the current transform state of all the parts in the assembly + std::vector GetCurrentTransforms(); + // Transforms the assembly such that newOrigin is now this assembly's new assemblyOrigin void SetOrigin(CFrame newOrigin); diff --git a/editor/mainglwidget.cpp b/editor/mainglwidget.cpp index 210154f..b82bd22 100755 --- a/editor/mainglwidget.cpp +++ b/editor/mainglwidget.cpp @@ -21,6 +21,7 @@ #include "rendering/renderer.h" #include "rendering/shader.h" #include "datatypes/variant.h" +#include "undohistory.h" #define PI 3.14159 #define M_mainWindow dynamic_cast(window()) @@ -120,6 +121,8 @@ CFrame snapCFrame(CFrame frame) { return CFrame(frame.Position(), frame.Position() + closestVec1, closestVec2); } +std::vector initialTransforms; + bool tryMouseContextMenu = false; bool isMouseDragging = false; std::weak_ptr draggingObject; @@ -359,6 +362,7 @@ void MainGLWidget::mouseMoveEvent(QMouseEvent* evt) { } void MainGLWidget::mousePressEvent(QMouseEvent* evt) { + initialTransforms = {}; tryMouseContextMenu = evt->button() == Qt::RightButton; switch(evt->button()) { // Camera drag @@ -377,6 +381,8 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) { startPoint = glm::vec2(evt->pos().x(), evt->pos().y()); initialAssembly = PartAssembly::FromSelection(gDataModel->GetService()); initialFrame = initialAssembly.assemblyOrigin(); + initialTransforms = PartAssembly::FromSelection(gDataModel->GetService()).GetCurrentTransforms(); + printf("%ld\n", initialTransforms.size()); isMouseDragging = true; draggingHandle = handle; startLinearTransform(evt); @@ -430,6 +436,7 @@ void MainGLWidget::mousePressEvent(QMouseEvent* evt) { //part.selected = true; isMouseDragging = true; draggingObject = part; + initialTransforms = PartAssembly::FromSelection({part}).GetCurrentTransforms(); if (evt->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier)) { auto sel = selection->Get(); if (std::find(sel.begin(), sel.end(), selObject) == sel.end()) @@ -455,6 +462,17 @@ void MainGLWidget::mouseReleaseEvent(QMouseEvent* evt) { draggingObject = {}; draggingHandle = std::nullopt; + if (!initialTransforms.empty()) { + UndoState historyState; + + for (auto t : initialTransforms) { + historyState.push_back(UndoStatePropertyChanged { t.part, "CFrame", t.cframe, t.part->cframe }); + historyState.push_back(UndoStatePropertyChanged { t.part, "Size", t.size, t.part->size }); + } + + M_mainWindow->undoManager.PushState(historyState); + } + // Open context menu if (tryMouseContextMenu) contextMenu.exec(QCursor::pos()); @@ -505,6 +523,7 @@ void MainGLWidget::keyPressEvent(QKeyEvent* evt) { })); gWorkspace()->SyncPartPhysics(lastPart); lastPart->name = "Part" + std::to_string(partId++); + M_mainWindow->undoManager.PushState({ UndoStateInstanceCreated { lastPart, gWorkspace() } }); } }