From e599f40664abbb56093640d501b051cf92e94852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sun, 13 Feb 2022 00:28:17 +0100 Subject: [PATCH] editor: undo/redo improvements; also added cut to Ctrl+X; --- Editor/CameraWindow.cpp | 8 ++ Editor/Editor.cpp | 158 ++++++++++++++++++---------------- Editor/Editor.h | 7 +- Editor/EmitterWindow.cpp | 9 ++ Editor/EnvProbeWindow.cpp | 9 ++ Editor/ForceFieldWindow.cpp | 9 ++ Editor/HairParticleWindow.cpp | 9 ++ Editor/LightWindow.cpp | 9 ++ Editor/MaterialWindow.cpp | 9 ++ Editor/MeshWindow.cpp | 8 ++ Editor/SoundWindow.cpp | 9 ++ Editor/TransformWindow.cpp | 9 ++ 12 files changed, 177 insertions(+), 76 deletions(-) diff --git a/Editor/CameraWindow.cpp b/Editor/CameraWindow.cpp index 446d56478..8abd65520 100644 --- a/Editor/CameraWindow.cpp +++ b/Editor/CameraWindow.cpp @@ -185,8 +185,16 @@ void CameraWindow::Create(EditorComponent* editor) TransformComponent& transform = *scene.transforms.GetComponent(entity); transform.MatrixTransform(camera.InvView); + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); }); diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index f3035f461..a8633ddf0 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -757,9 +757,7 @@ void EditorComponent::Load() nameWnd.SetEntity(INVALID_ENTITY); RefreshSceneGraphView(); - - history.clear(); - historyPos = -1; + ResetHistory(); }); GetGUI().AddWidget(&clearButton); @@ -787,6 +785,7 @@ void EditorComponent::Load() ss += "Undo: Ctrl + Z\n"; ss += "Redo: Ctrl + Y\n"; ss += "Copy: Ctrl + C\n"; + ss += "Cut: Ctrl + X\n"; ss += "Paste: Ctrl + V\n"; ss += "Delete: DELETE button\n"; ss += "Place Instances: Ctrl + Shift + Left mouse click (place clipboard onto clicked surface)\n"; @@ -805,6 +804,7 @@ void EditorComponent::Load() helpLabel.Create("HelpLabel"); helpLabel.SetText(ss); helpLabel.SetVisible(false); + helpLabel.SetColor(wi::Color(113, 183, 214, 100), wi::gui::WIDGETSTATE::IDLE); GetGUI().AddWidget(&helpLabel); } @@ -851,6 +851,9 @@ void EditorComponent::Load() sceneGraphView.Create("Scene graph view"); sceneGraphView.OnSelect([this](wi::gui::EventArgs args) { + if (args.iValue < 0) + return; + wi::Archive& archive = AdvanceHistory(); archive << HISTORYOP_SELECTION; // record PREVIOUS selection state... @@ -1007,6 +1010,8 @@ void EditorComponent::Update(float dt) } } + bool deleting = wi::input::Press(wi::input::KEYBOARD_BUTTON_DELETE); + // Camera control: XMFLOAT4 currentMouse = wi::input::GetPointer(); if (!wi::backlog::isActive() && !GetGUI().HasFocus()) @@ -1428,8 +1433,8 @@ void EditorComponent::Update(float dt) { selectAll = true; } - // Copy - if (wi::input::Press((wi::input::BUTTON)'C')) + // Copy/Cut + if (wi::input::Press((wi::input::BUTTON)'C') || wi::input::Press((wi::input::BUTTON)'X')) { auto& prevSel = translator.selectedEntitiesNonRecursive; @@ -1440,6 +1445,11 @@ void EditorComponent::Update(float dt) { scene.Entity_Serialize(clipboard, seri, x); } + + if (wi::input::Press((wi::input::BUTTON)'X')) + { + deleting = true; + } } // Paste if (wi::input::Press((wi::input::BUTTON)'V')) @@ -1464,12 +1474,7 @@ void EditorComponent::Update(float dt) } RecordSelection(archive); - - archive << addedEntities; - for (auto& x : addedEntities) - { - scene.Entity_Serialize(archive, seri, x); - } + RecordAddedEntity(archive, addedEntities); RefreshSceneGraphView(); } @@ -1489,17 +1494,11 @@ void EditorComponent::Update(float dt) wi::scene::PickResult picked; picked.entity = scene.Entity_Duplicate(x); AddSelected(picked); - addedEntities.push_back(x); + addedEntities.push_back(picked.entity); } RecordSelection(archive); - - EntitySerializer seri; - archive << addedEntities; - for (auto& x : prevSel) - { - scene.Entity_Serialize(archive, seri, x); - } + RecordAddedEntity(archive, addedEntities); RefreshSceneGraphView(); } @@ -1526,13 +1525,10 @@ void EditorComponent::Update(float dt) wi::Archive& archive = AdvanceHistory(); archive << HISTORYOP_ADD; + // because selection didn't change here, we record same selection state twice, it's not a bug: RecordSelection(archive); RecordSelection(archive); - archive << addedEntities; - for (auto& x : addedEntities) - { - scene.Entity_Serialize(archive, seri, x); - } + RecordAddedEntity(archive, addedEntities); RefreshSceneGraphView(); } @@ -1554,9 +1550,8 @@ void EditorComponent::Update(float dt) } - // Delete - if (wi::input::Press(wi::input::KEYBOARD_BUTTON_DELETE)) + if (deleting) { wi::Archive& archive = AdvanceHistory(); archive << HISTORYOP_DELETE; @@ -2401,6 +2396,7 @@ bool EditorComponent::IsSelected(Entity entity) const } return false; } + void EditorComponent::RecordSelection(wi::Archive& archive) const { archive << translator.selected.size(); @@ -2413,6 +2409,22 @@ void EditorComponent::RecordSelection(wi::Archive& archive) const archive << x.distance; } } +void EditorComponent::RecordAddedEntity(wi::Archive& archive, wi::ecs::Entity entity) const +{ + const wi::vector entities = { entity }; + RecordAddedEntity(archive, entities); +} +void EditorComponent::RecordAddedEntity(wi::Archive& archive, const wi::vector& entities) const +{ + Scene& scene = GetScene(); + EntitySerializer seri; + + archive << entities; + for (auto& x : entities) + { + scene.Entity_Serialize(archive, seri, x); + } +} void EditorComponent::ResetHistory() { @@ -2470,6 +2482,51 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) translator.PostTranslate(); } break; + case HISTORYOP_SELECTION: + { + // Read selections states from archive: + + wi::vector selectedBEFORE; + size_t selectionCountBEFORE; + archive >> selectionCountBEFORE; + for (size_t i = 0; i < selectionCountBEFORE; ++i) + { + wi::scene::PickResult sel; + archive >> sel.entity; + archive >> sel.position; + archive >> sel.normal; + archive >> sel.subsetIndex; + archive >> sel.distance; + + selectedBEFORE.push_back(sel); + } + + wi::vector selectedAFTER; + size_t selectionCountAFTER; + archive >> selectionCountAFTER; + for (size_t i = 0; i < selectionCountAFTER; ++i) + { + wi::scene::PickResult sel; + archive >> sel.entity; + archive >> sel.position; + archive >> sel.normal; + archive >> sel.subsetIndex; + archive >> sel.distance; + + selectedAFTER.push_back(sel); + } + + // Restore proper selection state: + if (undo) + { + translator.selected = selectedBEFORE; + } + else + { + translator.selected = selectedAFTER; + } + } + break; case HISTORYOP_ADD: { // Read selections states from archive: @@ -2572,59 +2629,12 @@ void EditorComponent::ConsumeHistoryOperation(bool undo) } break; - case HISTORYOP_SELECTION: - { - // Read selections states from archive: - - wi::vector selectedBEFORE; - size_t selectionCountBEFORE; - archive >> selectionCountBEFORE; - for (size_t i = 0; i < selectionCountBEFORE; ++i) - { - wi::scene::PickResult sel; - archive >> sel.entity; - archive >> sel.position; - archive >> sel.normal; - archive >> sel.subsetIndex; - archive >> sel.distance; - - selectedBEFORE.push_back(sel); - } - - wi::vector selectedAFTER; - size_t selectionCountAFTER; - archive >> selectionCountAFTER; - for (size_t i = 0; i < selectionCountAFTER; ++i) - { - wi::scene::PickResult sel; - archive >> sel.entity; - archive >> sel.position; - archive >> sel.normal; - archive >> sel.subsetIndex; - archive >> sel.distance; - - selectedAFTER.push_back(sel); - } - - - // Restore proper selection state: - if (undo) - { - translator.selected = selectedBEFORE; - } - else - { - translator.selected = selectedAFTER; - } - } - break; case HISTORYOP_PAINTTOOL: paintToolWnd.ConsumeHistoryOperation(archive, undo); break; case HISTORYOP_NONE: - assert(0); - break; default: + assert(0); break; } diff --git a/Editor/Editor.h b/Editor/Editor.h index 02c795695..84af0bcc3 100644 --- a/Editor/Editor.h +++ b/Editor/Editor.h @@ -153,7 +153,6 @@ public: void AddSelected(wi::ecs::Entity entity); void AddSelected(const wi::scene::PickResult& picked); bool IsSelected(wi::ecs::Entity entity) const; - void RecordSelection(wi::Archive& archive) const; wi::Archive clipboard; @@ -163,13 +162,17 @@ public: enum HistoryOperationType { HISTORYOP_TRANSLATOR, + HISTORYOP_SELECTION, HISTORYOP_ADD, HISTORYOP_DELETE, - HISTORYOP_SELECTION, HISTORYOP_PAINTTOOL, HISTORYOP_NONE }; + void RecordSelection(wi::Archive& archive) const; + void RecordAddedEntity(wi::Archive& archive, wi::ecs::Entity entity) const; + void RecordAddedEntity(wi::Archive& archive, const wi::vector& entities) const; + void ResetHistory(); wi::Archive& AdvanceHistory(); void ConsumeHistoryOperation(bool undo); diff --git a/Editor/EmitterWindow.cpp b/Editor/EmitterWindow.cpp index 2208940d1..82cbf520c 100644 --- a/Editor/EmitterWindow.cpp +++ b/Editor/EmitterWindow.cpp @@ -38,8 +38,17 @@ void EmitterWindow::Create(EditorComponent* editor) addButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); Entity entity = scene.Entity_CreateEmitter("editorEmitter"); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); }); diff --git a/Editor/EnvProbeWindow.cpp b/Editor/EnvProbeWindow.cpp index 53ffeb355..8bbac511f 100644 --- a/Editor/EnvProbeWindow.cpp +++ b/Editor/EnvProbeWindow.cpp @@ -31,8 +31,17 @@ void EnvProbeWindow::Create(EditorComponent* editor) XMFLOAT3 pos; XMStoreFloat3(&pos, XMVectorAdd(wi::scene::GetCamera().GetEye(), wi::scene::GetCamera().GetAt() * 4)); Entity entity = wi::scene::GetScene().Entity_CreateEnvironmentProbe("editorProbe", pos); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); }); diff --git a/Editor/ForceFieldWindow.cpp b/Editor/ForceFieldWindow.cpp index 1488edb2c..81a4e9dc4 100644 --- a/Editor/ForceFieldWindow.cpp +++ b/Editor/ForceFieldWindow.cpp @@ -36,8 +36,17 @@ void ForceFieldWindow::Create(EditorComponent* editor) assert(0); break; } + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); } diff --git a/Editor/HairParticleWindow.cpp b/Editor/HairParticleWindow.cpp index b787a08da..036e0abda 100644 --- a/Editor/HairParticleWindow.cpp +++ b/Editor/HairParticleWindow.cpp @@ -22,8 +22,17 @@ void HairParticleWindow::Create(EditorComponent* editor) addButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); Entity entity = scene.Entity_CreateHair("editorHair"); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); }); diff --git a/Editor/LightWindow.cpp b/Editor/LightWindow.cpp index 0995c8bc8..9f98d653e 100644 --- a/Editor/LightWindow.cpp +++ b/Editor/LightWindow.cpp @@ -168,8 +168,17 @@ void LightWindow::Create(EditorComponent* editor) if (light != nullptr) { light->type = (LightComponent::LightType)typeSelectorComboBox.GetSelected(); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); } diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index 17f5d9063..838119040 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -452,9 +452,18 @@ void MaterialWindow::Create(EditorComponent* editor) newMaterialButton.OnClick([=](wi::gui::EventArgs args) { Scene& scene = wi::scene::GetScene(); Entity entity = scene.Entity_CreateMaterial("editorMaterial"); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); editor->RefreshSceneGraphView(); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + SetEntity(entity); }); AddWidget(&newMaterialButton); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 444ddbabe..80fe5afbe 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -551,12 +551,20 @@ void MeshWindow::Create(EditorComponent* editor) mesh->ComputeNormals(MeshComponent::COMPUTE_NORMALS_SMOOTH_FAST); }; generate_mesh(128, 128); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); editor->ClearSelected(); wi::scene::PickResult pick; pick.entity = entity; pick.subsetIndex = 0; editor->AddSelected(pick); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + SetEntity(object.meshID, pick.subsetIndex); diff --git a/Editor/SoundWindow.cpp b/Editor/SoundWindow.cpp index c3708bf1e..66993a548 100644 --- a/Editor/SoundWindow.cpp +++ b/Editor/SoundWindow.cpp @@ -70,8 +70,17 @@ void SoundWindow::Create(EditorComponent* editor) wi::helper::FileDialog(params, [=](std::string fileName) { wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) { Entity entity = GetScene().Entity_CreateSound("editorSound", fileName); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); }); diff --git a/Editor/TransformWindow.cpp b/Editor/TransformWindow.cpp index 11ca17744..4378934b9 100644 --- a/Editor/TransformWindow.cpp +++ b/Editor/TransformWindow.cpp @@ -24,8 +24,17 @@ void TransformWindow::Create(EditorComponent* editor) createButton.OnClick([=](wi::gui::EventArgs args) { Entity entity = CreateEntity(); wi::scene::GetScene().transforms.Create(entity); + + wi::Archive& archive = editor->AdvanceHistory(); + archive << EditorComponent::HISTORYOP_ADD; + editor->RecordSelection(archive); + editor->ClearSelected(); editor->AddSelected(entity); + + editor->RecordSelection(archive); + editor->RecordAddedEntity(archive, entity); + editor->RefreshSceneGraphView(); SetEntity(entity); });