From 2c9908bceae8b5ebf3dc6b7ddbf854a1f0d8db61 Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Fri, 2 Jan 2026 19:24:12 +0300 Subject: [PATCH] Added grid undo actions --- src/DrawingProgram/Tools/GridModifyTool.cpp | 2 +- src/GridManager.cpp | 117 +++++++++++++++++++- src/GridManager.hpp | 1 + src/WorldUndoManager.cpp | 29 ++++- src/WorldUndoManager.hpp | 3 +- 5 files changed, 141 insertions(+), 11 deletions(-) diff --git a/src/DrawingProgram/Tools/GridModifyTool.cpp b/src/DrawingProgram/Tools/GridModifyTool.cpp index 9dfef71..409a5a3 100644 --- a/src/DrawingProgram/Tools/GridModifyTool.cpp +++ b/src/DrawingProgram/Tools/GridModifyTool.cpp @@ -190,5 +190,5 @@ void GridModifyTool::draw(SkCanvas* canvas, const DrawData& drawData) { void GridModifyTool::switch_tool(DrawingProgramToolType newTool) { NetworkingObjects::NetObjTemporaryPtr gLock = grid.lock(); if(gLock) - drawP.world.delayedUpdateObjectManager.send_update_to_all(gLock, true); + drawP.world.gridMan.finalize_grid_modify(gLock, oldGrid); } diff --git a/src/GridManager.cpp b/src/GridManager.cpp index b7da80f..b19e813 100644 --- a/src/GridManager.cpp +++ b/src/GridManager.cpp @@ -1,6 +1,7 @@ #include "GridManager.hpp" #include "World.hpp" #include "MainProgram.hpp" +#include "WorldUndoManager.hpp" #include GridManager::GridManager(World& w): @@ -17,13 +18,123 @@ void GridManager::add_default_grid(const std::string& newName) { g.color = color_mul_alpha(convert_vec4(world.canvasTheme.get_tool_front_color()), 0.4f); g.size = world.drawData.cam.c.inverseScale * WorldScalar(WorldGrid::GRID_UNIT_PIXEL_SIZE); g.offset = world.drawData.cam.c.pos + world.drawData.cam.c.dir_from_space(world.main.window.size.cast() * 0.5f); - grids->emplace_back_direct(grids, g); + auto it = grids->emplace_back_direct(grids, g); + + class AddGridWorldUndoAction : public WorldUndoAction { + public: + AddGridWorldUndoAction(const WorldGrid& initGridData, WorldUndoManager::UndoObjectID initUndoID): + gridData(initGridData), + undoID(initUndoID) + {} + bool undo(WorldUndoManager& undoMan) override { + std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); + if(!toEraseID.has_value()) + return false; + auto& gridList = undoMan.world.gridMan.grids; + gridList->erase(gridList, gridList->get(toEraseID.value())); + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); + if(toInsertID.has_value()) + return false; + auto& gridList = undoMan.world.gridMan.grids; + auto insertedIt = gridList->emplace_back_direct(gridList, gridData); + undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); + return true; + } + void scale_up(const WorldScalar& scaleAmount) override { + gridData.scale_up(scaleAmount); + } + ~AddGridWorldUndoAction() {} + + WorldGrid gridData; + WorldUndoManager::UndoObjectID undoID; + }; + + world.undo.push(std::make_unique(g, world.undo.get_undoid_from_netid(it->obj.get_net_id()))); } } void GridManager::remove_grid(uint32_t indexToRemove) { - if(grids) - grids->erase(grids, grids->at(indexToRemove)); + if(grids) { + class EraseGridWorldUndoAction : public WorldUndoAction { + public: + EraseGridWorldUndoAction(const WorldGrid& initGridData, WorldUndoManager::UndoObjectID initUndoID): + gridData(initGridData), + undoID(initUndoID) + {} + bool undo(WorldUndoManager& undoMan) override { + std::optional toInsertID = undoMan.get_netid_from_undoid(undoID); + if(toInsertID.has_value()) + return false; + auto& gridList = undoMan.world.gridMan.grids; + auto insertedIt = gridList->emplace_back_direct(gridList, gridData); + undoMan.register_new_netid_to_existing_undoid(undoID, insertedIt->obj.get_net_id()); + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::optional toEraseID = undoMan.get_netid_from_undoid(undoID); + if(!toEraseID.has_value()) + return false; + auto& gridList = undoMan.world.gridMan.grids; + gridList->erase(gridList, gridList->get(toEraseID.value())); + return true; + } + void scale_up(const WorldScalar& scaleAmount) override { + gridData.scale_up(scaleAmount); + } + ~EraseGridWorldUndoAction() {} + + WorldGrid gridData; + WorldUndoManager::UndoObjectID undoID; + }; + + auto it = grids->at(indexToRemove); + world.undo.push(std::make_unique(*it->obj, world.undo.get_undoid_from_netid(it->obj.get_net_id()))); + grids->erase(grids, it); + } +} + +void GridManager::finalize_grid_modify(const NetworkingObjects::NetObjTemporaryPtr& wGrid, const WorldGrid& oldGridData) { + class ModifyGridWorldUndoAction : public WorldUndoAction { + public: + ModifyGridWorldUndoAction(const WorldGrid& initGridDataOld, const WorldGrid& initGridDataNew, WorldUndoManager::UndoObjectID initUndoID): + gridDataOld(initGridDataOld), + gridDataNew(initGridDataNew), + undoID(initUndoID) + {} + bool undo(WorldUndoManager& undoMan) override { + std::optional toModifyID = undoMan.get_netid_from_undoid(undoID); + if(!toModifyID.has_value()) + return false; + auto gridPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toModifyID.value()); + *gridPtr = gridDataOld; + undoMan.world.delayedUpdateObjectManager.send_update_to_all(gridPtr, true); + return true; + } + bool redo(WorldUndoManager& undoMan) override { + std::optional toModifyID = undoMan.get_netid_from_undoid(undoID); + if(!toModifyID.has_value()) + return false; + auto gridPtr = undoMan.world.netObjMan.get_obj_temporary_ref_from_id(toModifyID.value()); + *gridPtr = gridDataNew; + undoMan.world.delayedUpdateObjectManager.send_update_to_all(gridPtr, true); + return true; + } + void scale_up(const WorldScalar& scaleAmount) override { + gridDataOld.scale_up(scaleAmount); + gridDataNew.scale_up(scaleAmount); + } + ~ModifyGridWorldUndoAction() {} + + WorldGrid gridDataOld; + WorldGrid gridDataNew; + WorldUndoManager::UndoObjectID undoID; + }; + + world.undo.push(std::make_unique(oldGridData, *wGrid, world.undo.get_undoid_from_netid(wGrid.get_net_id()))); + world.delayedUpdateObjectManager.send_update_to_all(wGrid, true); } void GridManager::draw_back(SkCanvas* canvas, const DrawData& drawData) { diff --git a/src/GridManager.hpp b/src/GridManager.hpp index 96de7f9..691eded 100644 --- a/src/GridManager.hpp +++ b/src/GridManager.hpp @@ -34,6 +34,7 @@ class GridManager { void scale_up(const WorldScalar& scaleUpAmount); void save_file(cereal::PortableBinaryOutputArchive& a) const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); + void finalize_grid_modify(const NetworkingObjects::NetObjTemporaryPtr& wGrid, const WorldGrid& oldGridData); NetworkingObjects::NetObjOwnerPtr> grids; World& world; diff --git a/src/WorldUndoManager.cpp b/src/WorldUndoManager.cpp index 815ad4e..8e125ab 100644 --- a/src/WorldUndoManager.cpp +++ b/src/WorldUndoManager.cpp @@ -71,7 +71,7 @@ void WorldUndoManager::reassign_netid(const NetworkingObjects::NetObjID& oldNetO if(netIDtoUndoIDIterator != netIDToUndoID.end()) { UndoObjectID undoID = netIDtoUndoIDIterator->second; netIDToUndoID.erase(netIDtoUndoIDIterator); - netIDToUndoID.emplace(newNetObjID, undoID); + netIDToUndoID[newNetObjID] = undoID; undoIDToNetID[undoID] = newNetObjID; } } @@ -92,11 +92,28 @@ void WorldUndoManager::remove_by_undoid(UndoObjectID undoID) { } } -WorldUndoManager::UndoObjectID WorldUndoManager::register_new_netobj(const NetworkingObjects::NetObjID& netObjID) { - ++lastUndoObjectID; - undoIDToNetID[lastUndoObjectID] = netObjID; - netIDToUndoID[netObjID] = lastUndoObjectID; - return lastUndoObjectID; +WorldUndoManager::UndoObjectID WorldUndoManager::get_undoid_from_netid(const NetworkingObjects::NetObjID& netObjID) { + auto it = netIDToUndoID.find(netObjID); + if(it == netIDToUndoID.end()) { + ++lastUndoObjectID; + undoIDToNetID[lastUndoObjectID] = netObjID; + netIDToUndoID[netObjID] = lastUndoObjectID; + return lastUndoObjectID; + } + return it->second; +} + +void WorldUndoManager::register_new_netid_to_existing_undoid(UndoObjectID existingUndoID, const NetworkingObjects::NetObjID& netObjID) { + auto undoIDToNetIDIterator = undoIDToNetID.find(existingUndoID); + if(undoIDToNetIDIterator != undoIDToNetID.end()) { + netIDToUndoID.erase(undoIDToNetIDIterator->second); + undoIDToNetIDIterator->second = netObjID; + netIDToUndoID[netObjID] = existingUndoID; + } + else { + netIDToUndoID[netObjID] = existingUndoID; + undoIDToNetID[existingUndoID] = netObjID; + } } std::optional WorldUndoManager::get_netid_from_undoid(UndoObjectID undoID) { diff --git a/src/WorldUndoManager.hpp b/src/WorldUndoManager.hpp index bb42e54..80449f8 100644 --- a/src/WorldUndoManager.hpp +++ b/src/WorldUndoManager.hpp @@ -31,7 +31,8 @@ class WorldUndoManager { void reassign_netid(const NetworkingObjects::NetObjID& oldNetObjID, const NetworkingObjects::NetObjID& newNetObjID); void remove_by_netid(const NetworkingObjects::NetObjID& netObjID); void remove_by_undoid(UndoObjectID undoID); - UndoObjectID register_new_netobj(const NetworkingObjects::NetObjID& netObjID); + UndoObjectID get_undoid_from_netid(const NetworkingObjects::NetObjID& netObjID); + void register_new_netid_to_existing_undoid(UndoObjectID existingUndoID, const NetworkingObjects::NetObjID& netObjID); std::optional get_netid_from_undoid(UndoObjectID undoID); World& world;