From 81ec08b55e623fcf69faa31489ad2349c0b6bd8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Mon, 5 Sep 2022 18:27:09 +0200 Subject: [PATCH] First draft of undo/redo. Can move objects and undo new object placement. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz ZieliƄski --- lib/mapping/CMapEditManager.cpp | 38 ++++++++++++++++++------ lib/mapping/CMapEditManager.h | 13 +++++++-- mapeditor/mainwindow.cpp | 31 ++++++++++++++++++++ mapeditor/mainwindow.h | 6 ++++ mapeditor/mainwindow.ui | 51 ++++++++++++++++++++++++++++++--- mapeditor/mapcontroller.cpp | 23 +++++++++++++++ mapeditor/mapcontroller.h | 4 +++ 7 files changed, 152 insertions(+), 14 deletions(-) diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index d2ad1fd3b..9e5dcf59e 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -155,14 +155,17 @@ MapRect CMapOperation::extendTileAroundSafely(const int3 & centerPos) const } -CMapUndoManager::CMapUndoManager() : undoRedoLimit(10) +CMapUndoManager::CMapUndoManager() : + undoRedoLimit(10), + undoCallback([](bool, bool) {}) { - + //TODO: unlimited undo } void CMapUndoManager::undo() { doOperation(undoStack, redoStack, true); + } void CMapUndoManager::redo() @@ -174,6 +177,7 @@ void CMapUndoManager::clearAll() { undoStack.clear(); redoStack.clear(); + onUndoRedo(); } int CMapUndoManager::getUndoRedoLimit() const @@ -219,6 +223,7 @@ void CMapUndoManager::doOperation(TStack & fromStack, TStack & toStack, bool doU } toStack.push_front(std::move(operation)); fromStack.pop_front(); + onUndoRedo(); } const CMapOperation * CMapUndoManager::peek(const TStack & stack) const @@ -227,6 +232,18 @@ const CMapOperation * CMapUndoManager::peek(const TStack & stack) const return stack.front().get(); } +void CMapUndoManager::onUndoRedo() +{ + //true if there's anything on the stack + undoCallback((bool)peekUndo(), (bool)peekRedo()); +} + +void CMapUndoManager::setUndoCallback(std::function functor) +{ + undoCallback = functor; + onUndoRedo(); //inform immediately +} + CMapEditManager::CMapEditManager(CMap * map) : map(map), terrainSel(map), objectSel(map) { @@ -322,6 +339,7 @@ void CComposedOperation::undo() void CComposedOperation::redo() { + //TODO: double-chekcif the order is correct for(auto & operation : operations) { operation->redo(); @@ -1070,7 +1088,7 @@ void CInsertObjectOperation::execute() void CInsertObjectOperation::undo() { - //TODO + map->removeObject(obj); } void CInsertObjectOperation::redo() @@ -1083,20 +1101,24 @@ std::string CInsertObjectOperation::getLabel() const return "Insert Object"; } -CMoveObjectOperation::CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position) - : CMapOperation(map), obj(obj), pos(position) +CMoveObjectOperation::CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & targetPosition) + : CMapOperation(map), + obj(obj), + initialPos(obj->pos), + targetPos(targetPosition) { - } void CMoveObjectOperation::execute() { - map->moveObject(obj, pos); + map->moveObject(obj, targetPos); + logGlobal->debug("Moved object %s to position %s", obj->instanceName, targetPos.toString()); } void CMoveObjectOperation::undo() { - //TODO + map->moveObject(obj, initialPos); + logGlobal->debug("Moved object %s back to position %s", obj->instanceName, initialPos.toString()); } void CMoveObjectOperation::redo() diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index a500c413e..5cebfdc91 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -138,6 +138,8 @@ public: /// The undo redo limit is a number which says how many undo/redo items can be saved. The default /// value is 10. If the value is 0, no undo/redo history will be maintained. + + /// FIXME: unlimited undo please int getUndoRedoLimit() const; void setUndoRedoLimit(int value); @@ -146,6 +148,9 @@ public: void addOperation(std::unique_ptr && operation); /// Client code does not need to call this method. + //poor man's signal + void setUndoCallback(std::function functor); + private: typedef std::list > TStack; @@ -155,6 +160,9 @@ private: TStack undoStack; TStack redoStack; int undoRedoLimit; + + void onUndoRedo(); + std::function undoCallback; }; /// The map edit manager provides functionality for drawing terrain and placing @@ -425,7 +433,7 @@ private: class CMoveObjectOperation : public CMapOperation { public: - CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position); + CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & targetPosition); void execute() override; void undo() override; @@ -434,7 +442,8 @@ public: private: CGObjectInstance * obj; - int3 pos; + int3 initialPos; + int3 targetPos; }; /// The CRemoveObjectOperation class removes object from the map diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp index 9079c6b81..4193ab234 100644 --- a/mapeditor/mainwindow.cpp +++ b/mapeditor/mainwindow.cpp @@ -554,6 +554,28 @@ void MainWindow::on_actionLevel_triggered() } } +void MainWindow::on_actionUndo_triggered() +{ + QString str("Undo clicked"); + statusBar()->showMessage(str, 1000); + + if (controller.map()) + { + controller.undo(); + } +} + +void MainWindow::on_actionRedo_triggered() +{ + QString str("Redo clicked"); + statusBar()->showMessage(str, 1000); + + if (controller.map()) + { + controller.redo(); + } +} + void MainWindow::on_actionPass_triggered(bool checked) { if(controller.map()) @@ -769,3 +791,12 @@ void MainWindow::on_actionPlayers_settings_triggered() mapSettingsDialog->setModal(true); } +void MainWindow::enableUndo(bool enable) +{ + ui->actionUndo->setEnabled(enable); +} + +void MainWindow::enableRedo(bool enable) +{ + ui->actionRedo->setEnabled(enable); +} \ No newline at end of file diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h index 242719702..2cc3bb5c3 100644 --- a/mapeditor/mainwindow.h +++ b/mapeditor/mainwindow.h @@ -48,6 +48,10 @@ private slots: void on_actionLevel_triggered(); void on_actionSave_triggered(); + + void on_actionUndo_triggered(); + + void on_actionRedo_triggered(); void on_actionPass_triggered(bool checked); @@ -84,6 +88,8 @@ public slots: void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected); void loadInspector(CGObjectInstance * obj); void mapChanged(); + void enableUndo(bool enable); + void enableRedo(bool enable); private: void preparePreview(const QModelIndex &index, bool createNew); diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui index db084e180..a34bcdc82 100644 --- a/mapeditor/mainwindow.ui +++ b/mapeditor/mainwindow.ui @@ -51,7 +51,7 @@ 0 0 1024 - 22 + 18 @@ -70,7 +70,15 @@ + + + Edit + + + + + @@ -647,7 +655,7 @@ 0 0 128 - 271 + 356 @@ -690,7 +698,7 @@ 0 0 128 - 271 + 356 @@ -709,7 +717,7 @@ 0 0 128 - 271 + 356 @@ -823,6 +831,37 @@ Players settings + + + false + + + Undo + + + Undo + + + Ctrl+Z + + + true + + + + + false + + + Redo + + + Ctrl+Y + + + true + + @@ -833,4 +872,8 @@ + + enableUndo(bool) + enableRedo(bool) + diff --git a/mapeditor/mapcontroller.cpp b/mapeditor/mapcontroller.cpp index afcb768fd..f695f8830 100644 --- a/mapeditor/mapcontroller.cpp +++ b/mapeditor/mapcontroller.cpp @@ -46,6 +46,13 @@ void MapController::setMap(std::unique_ptr cmap) _scenes[1].reset(new MapScene(1)); resetMapHandler(); sceneForceUpdate(); + + _map->getEditManager()->getUndoManager().setUndoCallback([this](bool allowUndo, bool allowRedo) + { + main->enableUndo(allowUndo); + main->enableRedo(allowRedo); + } + ); } void MapController::sceneForceUpdate() @@ -211,3 +218,19 @@ void MapController::commitObjectCreate(int level) main->mapChanged(); } + +void MapController::undo() +{ + _map->getEditManager()->getUndoManager().undo(); + resetMapHandler(); + sceneForceUpdate(); + main->mapChanged(); +} + +void MapController::redo() +{ + _map->getEditManager()->getUndoManager().redo(); + resetMapHandler(); + sceneForceUpdate(); + main->mapChanged(); +} \ No newline at end of file diff --git a/mapeditor/mapcontroller.h b/mapeditor/mapcontroller.h index a89b6b377..ecc04b644 100644 --- a/mapeditor/mapcontroller.h +++ b/mapeditor/mapcontroller.h @@ -27,6 +27,7 @@ public: void sceneForceUpdate(int level); void commitTerrainChange(int level, const Terrain & terrain); + void commitObjectErase(const CGObjectInstance* obj); void commitObjectErase(int level); void commitObstacleFill(int level); void commitChangeWithoutRedraw(); @@ -36,6 +37,9 @@ public: bool discardObject(int level) const; void createObject(int level, CGObjectInstance * obj) const; + + void undo(); + void redo(); private: std::unique_ptr _map;