1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-18 17:40:48 +02:00

First draft of undo/redo. Can move objects and undo new object placement.

Signed-off-by: Tomasz Zieliński <tomaszzielinskijedenzwielu@gmail.com>
This commit is contained in:
Tomasz Zieliński 2022-09-05 18:27:09 +02:00
parent d1471fb3ed
commit 81ec08b55e
7 changed files with 152 additions and 14 deletions

View File

@ -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<void(bool, bool)> 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()

View File

@ -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<CMapOperation> && operation); /// Client code does not need to call this method.
//poor man's signal
void setUndoCallback(std::function<void(bool, bool)> functor);
private:
typedef std::list<std::unique_ptr<CMapOperation> > TStack;
@ -155,6 +160,9 @@ private:
TStack undoStack;
TStack redoStack;
int undoRedoLimit;
void onUndoRedo();
std::function<void(bool allowUndo, bool allowRedo)> 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

View File

@ -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);
}

View File

@ -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);

View File

@ -51,7 +51,7 @@
<x>0</x>
<y>0</y>
<width>1024</width>
<height>22</height>
<height>18</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -70,7 +70,15 @@
<addaction name="actionMapSettings"/>
<addaction name="actionPlayers_settings"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
<addaction name="actionUndo"/>
<addaction name="actionRedo"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuMap"/>
</widget>
<widget class="QToolBar" name="toolBar">
@ -647,7 +655,7 @@
<x>0</x>
<y>0</y>
<width>128</width>
<height>271</height>
<height>356</height>
</rect>
</property>
<property name="sizePolicy">
@ -690,7 +698,7 @@
<x>0</x>
<y>0</y>
<width>128</width>
<height>271</height>
<height>356</height>
</rect>
</property>
<property name="sizePolicy">
@ -709,7 +717,7 @@
<x>0</x>
<y>0</y>
<width>128</width>
<height>271</height>
<height>356</height>
</rect>
</property>
<property name="sizePolicy">
@ -823,6 +831,37 @@
<string>Players settings</string>
</property>
</action>
<action name="actionUndo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Undo</string>
</property>
<property name="iconText">
<string>Undo</string>
</property>
<property name="shortcut">
<string>Ctrl+Z</string>
</property>
<property name="shortcutVisibleInContextMenu">
<bool>true</bool>
</property>
</action>
<action name="actionRedo">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Redo</string>
</property>
<property name="shortcut">
<string>Ctrl+Y</string>
</property>
<property name="shortcutVisibleInContextMenu">
<bool>true</bool>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
@ -833,4 +872,8 @@
</customwidgets>
<resources/>
<connections/>
<slots>
<signal>enableUndo(bool)</signal>
<signal>enableRedo(bool)</signal>
</slots>
</ui>

View File

@ -46,6 +46,13 @@ void MapController::setMap(std::unique_ptr<CMap> 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();
}

View File

@ -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<CMap> _map;