mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-22 22:13:35 +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:
parent
d1471fb3ed
commit
81ec08b55e
@ -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()
|
void CMapUndoManager::undo()
|
||||||
{
|
{
|
||||||
doOperation(undoStack, redoStack, true);
|
doOperation(undoStack, redoStack, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapUndoManager::redo()
|
void CMapUndoManager::redo()
|
||||||
@ -174,6 +177,7 @@ void CMapUndoManager::clearAll()
|
|||||||
{
|
{
|
||||||
undoStack.clear();
|
undoStack.clear();
|
||||||
redoStack.clear();
|
redoStack.clear();
|
||||||
|
onUndoRedo();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CMapUndoManager::getUndoRedoLimit() const
|
int CMapUndoManager::getUndoRedoLimit() const
|
||||||
@ -219,6 +223,7 @@ void CMapUndoManager::doOperation(TStack & fromStack, TStack & toStack, bool doU
|
|||||||
}
|
}
|
||||||
toStack.push_front(std::move(operation));
|
toStack.push_front(std::move(operation));
|
||||||
fromStack.pop_front();
|
fromStack.pop_front();
|
||||||
|
onUndoRedo();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CMapOperation * CMapUndoManager::peek(const TStack & stack) const
|
const CMapOperation * CMapUndoManager::peek(const TStack & stack) const
|
||||||
@ -227,6 +232,18 @@ const CMapOperation * CMapUndoManager::peek(const TStack & stack) const
|
|||||||
return stack.front().get();
|
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)
|
CMapEditManager::CMapEditManager(CMap * map)
|
||||||
: map(map), terrainSel(map), objectSel(map)
|
: map(map), terrainSel(map), objectSel(map)
|
||||||
{
|
{
|
||||||
@ -322,6 +339,7 @@ void CComposedOperation::undo()
|
|||||||
|
|
||||||
void CComposedOperation::redo()
|
void CComposedOperation::redo()
|
||||||
{
|
{
|
||||||
|
//TODO: double-chekcif the order is correct
|
||||||
for(auto & operation : operations)
|
for(auto & operation : operations)
|
||||||
{
|
{
|
||||||
operation->redo();
|
operation->redo();
|
||||||
@ -1070,7 +1088,7 @@ void CInsertObjectOperation::execute()
|
|||||||
|
|
||||||
void CInsertObjectOperation::undo()
|
void CInsertObjectOperation::undo()
|
||||||
{
|
{
|
||||||
//TODO
|
map->removeObject(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CInsertObjectOperation::redo()
|
void CInsertObjectOperation::redo()
|
||||||
@ -1083,20 +1101,24 @@ std::string CInsertObjectOperation::getLabel() const
|
|||||||
return "Insert Object";
|
return "Insert Object";
|
||||||
}
|
}
|
||||||
|
|
||||||
CMoveObjectOperation::CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position)
|
CMoveObjectOperation::CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & targetPosition)
|
||||||
: CMapOperation(map), obj(obj), pos(position)
|
: CMapOperation(map),
|
||||||
|
obj(obj),
|
||||||
|
initialPos(obj->pos),
|
||||||
|
targetPos(targetPosition)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMoveObjectOperation::execute()
|
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()
|
void CMoveObjectOperation::undo()
|
||||||
{
|
{
|
||||||
//TODO
|
map->moveObject(obj, initialPos);
|
||||||
|
logGlobal->debug("Moved object %s back to position %s", obj->instanceName, initialPos.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMoveObjectOperation::redo()
|
void CMoveObjectOperation::redo()
|
||||||
|
@ -138,6 +138,8 @@ public:
|
|||||||
|
|
||||||
/// The undo redo limit is a number which says how many undo/redo items can be saved. The default
|
/// 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.
|
/// value is 10. If the value is 0, no undo/redo history will be maintained.
|
||||||
|
|
||||||
|
/// FIXME: unlimited undo please
|
||||||
int getUndoRedoLimit() const;
|
int getUndoRedoLimit() const;
|
||||||
void setUndoRedoLimit(int value);
|
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.
|
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:
|
private:
|
||||||
typedef std::list<std::unique_ptr<CMapOperation> > TStack;
|
typedef std::list<std::unique_ptr<CMapOperation> > TStack;
|
||||||
|
|
||||||
@ -155,6 +160,9 @@ private:
|
|||||||
TStack undoStack;
|
TStack undoStack;
|
||||||
TStack redoStack;
|
TStack redoStack;
|
||||||
int undoRedoLimit;
|
int undoRedoLimit;
|
||||||
|
|
||||||
|
void onUndoRedo();
|
||||||
|
std::function<void(bool allowUndo, bool allowRedo)> undoCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The map edit manager provides functionality for drawing terrain and placing
|
/// The map edit manager provides functionality for drawing terrain and placing
|
||||||
@ -425,7 +433,7 @@ private:
|
|||||||
class CMoveObjectOperation : public CMapOperation
|
class CMoveObjectOperation : public CMapOperation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position);
|
CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & targetPosition);
|
||||||
|
|
||||||
void execute() override;
|
void execute() override;
|
||||||
void undo() override;
|
void undo() override;
|
||||||
@ -434,7 +442,8 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
CGObjectInstance * obj;
|
CGObjectInstance * obj;
|
||||||
int3 pos;
|
int3 initialPos;
|
||||||
|
int3 targetPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The CRemoveObjectOperation class removes object from the map
|
/// The CRemoveObjectOperation class removes object from the map
|
||||||
|
@ -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)
|
void MainWindow::on_actionPass_triggered(bool checked)
|
||||||
{
|
{
|
||||||
if(controller.map())
|
if(controller.map())
|
||||||
@ -769,3 +791,12 @@ void MainWindow::on_actionPlayers_settings_triggered()
|
|||||||
mapSettingsDialog->setModal(true);
|
mapSettingsDialog->setModal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::enableUndo(bool enable)
|
||||||
|
{
|
||||||
|
ui->actionUndo->setEnabled(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::enableRedo(bool enable)
|
||||||
|
{
|
||||||
|
ui->actionRedo->setEnabled(enable);
|
||||||
|
}
|
@ -48,6 +48,10 @@ private slots:
|
|||||||
void on_actionLevel_triggered();
|
void on_actionLevel_triggered();
|
||||||
|
|
||||||
void on_actionSave_triggered();
|
void on_actionSave_triggered();
|
||||||
|
|
||||||
|
void on_actionUndo_triggered();
|
||||||
|
|
||||||
|
void on_actionRedo_triggered();
|
||||||
|
|
||||||
void on_actionPass_triggered(bool checked);
|
void on_actionPass_triggered(bool checked);
|
||||||
|
|
||||||
@ -84,6 +88,8 @@ public slots:
|
|||||||
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);
|
void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected);
|
||||||
void loadInspector(CGObjectInstance * obj);
|
void loadInspector(CGObjectInstance * obj);
|
||||||
void mapChanged();
|
void mapChanged();
|
||||||
|
void enableUndo(bool enable);
|
||||||
|
void enableRedo(bool enable);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void preparePreview(const QModelIndex &index, bool createNew);
|
void preparePreview(const QModelIndex &index, bool createNew);
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1024</width>
|
<width>1024</width>
|
||||||
<height>22</height>
|
<height>18</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
@ -70,7 +70,15 @@
|
|||||||
<addaction name="actionMapSettings"/>
|
<addaction name="actionMapSettings"/>
|
||||||
<addaction name="actionPlayers_settings"/>
|
<addaction name="actionPlayers_settings"/>
|
||||||
</widget>
|
</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="menuFile"/>
|
||||||
|
<addaction name="menuEdit"/>
|
||||||
<addaction name="menuMap"/>
|
<addaction name="menuMap"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QToolBar" name="toolBar">
|
<widget class="QToolBar" name="toolBar">
|
||||||
@ -647,7 +655,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>128</width>
|
<width>128</width>
|
||||||
<height>271</height>
|
<height>356</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -690,7 +698,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>128</width>
|
<width>128</width>
|
||||||
<height>271</height>
|
<height>356</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -709,7 +717,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>128</width>
|
<width>128</width>
|
||||||
<height>271</height>
|
<height>356</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -823,6 +831,37 @@
|
|||||||
<string>Players settings</string>
|
<string>Players settings</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</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>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
@ -833,4 +872,8 @@
|
|||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
<slots>
|
||||||
|
<signal>enableUndo(bool)</signal>
|
||||||
|
<signal>enableRedo(bool)</signal>
|
||||||
|
</slots>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -46,6 +46,13 @@ void MapController::setMap(std::unique_ptr<CMap> cmap)
|
|||||||
_scenes[1].reset(new MapScene(1));
|
_scenes[1].reset(new MapScene(1));
|
||||||
resetMapHandler();
|
resetMapHandler();
|
||||||
sceneForceUpdate();
|
sceneForceUpdate();
|
||||||
|
|
||||||
|
_map->getEditManager()->getUndoManager().setUndoCallback([this](bool allowUndo, bool allowRedo)
|
||||||
|
{
|
||||||
|
main->enableUndo(allowUndo);
|
||||||
|
main->enableRedo(allowRedo);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapController::sceneForceUpdate()
|
void MapController::sceneForceUpdate()
|
||||||
@ -211,3 +218,19 @@ void MapController::commitObjectCreate(int level)
|
|||||||
|
|
||||||
main->mapChanged();
|
main->mapChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MapController::undo()
|
||||||
|
{
|
||||||
|
_map->getEditManager()->getUndoManager().undo();
|
||||||
|
resetMapHandler();
|
||||||
|
sceneForceUpdate();
|
||||||
|
main->mapChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapController::redo()
|
||||||
|
{
|
||||||
|
_map->getEditManager()->getUndoManager().redo();
|
||||||
|
resetMapHandler();
|
||||||
|
sceneForceUpdate();
|
||||||
|
main->mapChanged();
|
||||||
|
}
|
@ -27,6 +27,7 @@ public:
|
|||||||
void sceneForceUpdate(int level);
|
void sceneForceUpdate(int level);
|
||||||
|
|
||||||
void commitTerrainChange(int level, const Terrain & terrain);
|
void commitTerrainChange(int level, const Terrain & terrain);
|
||||||
|
void commitObjectErase(const CGObjectInstance* obj);
|
||||||
void commitObjectErase(int level);
|
void commitObjectErase(int level);
|
||||||
void commitObstacleFill(int level);
|
void commitObstacleFill(int level);
|
||||||
void commitChangeWithoutRedraw();
|
void commitChangeWithoutRedraw();
|
||||||
@ -36,6 +37,9 @@ public:
|
|||||||
|
|
||||||
bool discardObject(int level) const;
|
bool discardObject(int level) const;
|
||||||
void createObject(int level, CGObjectInstance * obj) const;
|
void createObject(int level, CGObjectInstance * obj) const;
|
||||||
|
|
||||||
|
void undo();
|
||||||
|
void redo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<CMap> _map;
|
std::unique_ptr<CMap> _map;
|
||||||
|
Loading…
Reference in New Issue
Block a user