diff --git a/Commands.cpp b/Commands.cpp
new file mode 100644
index 0000000..6958b67
--- /dev/null
+++ b/Commands.cpp
@@ -0,0 +1,98 @@
+
+#include "Commands.h"
+
+AddShapesCommand::AddShapesCommand(MainWindow *mainWindow, uid mappingId, QUndoCommand *parent):
+ QUndoCommand(parent)
+{
+ m_mainWindow = mainWindow;
+ m_mappingId = mappingId;
+}
+
+void AddShapesCommand::undo()
+{
+ m_mappingPtr = m_mainWindow->getMappingManager().getMappingById(m_mappingId);
+ m_mainWindow->deleteMapping(m_mappingId);
+}
+
+void AddShapesCommand::redo()
+{
+ if(m_mappingPtr != NULL)
+ {
+ uint currentId = m_mainWindow->getMappingManager().addMapping(m_mappingPtr);
+ m_mainWindow->addMappingItem(currentId);
+ }
+}
+
+
+MoveVertexCommand::MoveVertexCommand(MapperGLCanvas *mapperGLCanvas, int activeVertex, const QPointF &point, QUndoCommand *parent) :
+ QUndoCommand(parent)
+{
+ m_mapperGLCanvas = mapperGLCanvas;
+ m_shape = m_mapperGLCanvas->getCurrentShape();
+ m_activeVertex = activeVertex;
+ vertexPosition = point;
+}
+
+void MoveVertexCommand::undo()
+{
+ m_shape->setVertex(m_activeVertex, vertexPosition);
+ m_mapperGLCanvas->update();
+ emit m_mapperGLCanvas->shapeChanged(m_mapperGLCanvas->getCurrentShape());
+}
+
+void MoveVertexCommand::redo()
+{
+ m_shape->setVertex(m_activeVertex, vertexPosition);
+ m_mapperGLCanvas->update();
+ emit m_mapperGLCanvas->shapeChanged(m_mapperGLCanvas->getCurrentShape());
+}
+
+
+MoveShapesCommand::MoveShapesCommand(MapperGLCanvas *mapperGLCanvas, QMouseEvent *event, const QPointF &point, QUndoCommand *parent) :
+ QUndoCommand(parent)
+{
+ m_mapperGLCanvas = mapperGLCanvas;
+ m_shape = m_mapperGLCanvas->getCurrentShape();
+ m_event = event;
+ newPosition = point;
+}
+
+void MoveShapesCommand::undo()
+{
+ m_shape->translate(oldPosition.x(), oldPosition.y());
+ m_mapperGLCanvas->update();
+ emit m_mapperGLCanvas->shapeChanged(m_mapperGLCanvas->getCurrentShape());
+}
+
+void MoveShapesCommand::redo()
+{
+ m_shape->translate(m_event->x() - newPosition.x(), m_event->y() - newPosition.y());
+ m_mapperGLCanvas->update();
+ emit m_mapperGLCanvas->shapeChanged(m_mapperGLCanvas->getCurrentShape());
+
+ oldPosition.setX(newPosition.x() - m_event->x());
+ oldPosition.setY(newPosition.y() - m_event->y());
+}
+
+
+DeleteMappingCommand::DeleteMappingCommand(MainWindow *mainWindow, uid mappingId, QUndoCommand *parent) :
+ QUndoCommand(parent)
+{
+ m_mainWindow = mainWindow;
+ m_mappingId = mappingId;
+}
+
+void DeleteMappingCommand::undo()
+{
+ if(m_mappingPtr != NULL)
+ {
+ uint currentId = m_mainWindow->getMappingManager().addMapping(m_mappingPtr);
+ m_mainWindow->addMappingItem(currentId);
+ }
+}
+
+void DeleteMappingCommand::redo()
+{
+ m_mappingPtr = m_mainWindow->getMappingManager().getMappingById(m_mappingId);
+ m_mainWindow->deleteMapping(m_mappingId);
+}
diff --git a/Commands.h b/Commands.h
new file mode 100644
index 0000000..7c8d155
--- /dev/null
+++ b/Commands.h
@@ -0,0 +1,85 @@
+/*
+ * Commands.h
+ *
+ * (c) 2014 Sofian Audry -- info(@)sofianaudry(.)com
+ * (c) 2014 Alexandre Quessy -- alexandre(@)quessy(.)net
+ * (c) 2014 Dame Diongue -- baydamd(@)gmail(.)com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef COMMANDS_H_
+#define COMMANDS_H_
+
+#include
+#include "MainWindow.h"
+#include "MapperGLCanvas.h"
+
+class AddShapesCommand : public QUndoCommand
+{
+public:
+ AddShapesCommand(MainWindow *mainWindow, uid mappingId, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ MainWindow *m_mainWindow;
+ Mapping::ptr m_mappingPtr;
+ uid m_mappingId;
+
+};
+
+class MoveVertexCommand : public QUndoCommand
+{
+public:
+ MoveVertexCommand(MapperGLCanvas *mapperGLCanvas, int activeVertex, const QPointF &point, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ MapperGLCanvas *m_mapperGLCanvas;
+ Shape *m_shape;
+ int m_activeVertex;
+ QPointF vertexPosition;
+
+};
+
+class MoveShapesCommand : public QUndoCommand
+{
+public:
+ MoveShapesCommand(MapperGLCanvas *mapperGLCanvas, QMouseEvent *event, const QPointF &point, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ MapperGLCanvas *m_mapperGLCanvas;
+ Shape *m_shape;
+ QMouseEvent *m_event;
+ QPointF newPosition, oldPosition;
+};
+
+class DeleteMappingCommand : public QUndoCommand
+{
+public:
+ DeleteMappingCommand(MainWindow *mainWindow, uid mappingId, QUndoCommand *parent = 0);
+ void undo();
+ void redo();
+
+private:
+ MainWindow *m_mainWindow;
+ Mapping::ptr m_mappingPtr;
+ uid m_mappingId;
+};
+
+#endif /* COMMANDS_H_ */
diff --git a/MainWindow.cpp b/MainWindow.cpp
index 3dbbf69..8ff8e25 100644
--- a/MainWindow.cpp
+++ b/MainWindow.cpp
@@ -19,6 +19,7 @@
*/
#include "MainWindow.h"
+#include "Commands.h"
#include "ProjectWriter.h"
#include "ProjectReader.h"
#include
@@ -26,7 +27,6 @@
MainWindow::MainWindow()
{
-
// Create model.
if (Media::hasVideoSupport())
std::cout << "Video support: yes" << std::endl;
@@ -53,8 +53,6 @@ MainWindow::MainWindow()
createContextMenu();
createToolBars();
createStatusBar();
- updateRecentFileActions();
- updateRecentVideoActions();
// Load settings.
readSettings();
@@ -288,38 +286,43 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event)
if (keyEvent->modifiers() == Qt::CTRL)
{
switch (keyEvent->key()) {
+<<<<<<< HEAD
case Qt::Key_F:
if (outputWindow->windowState() != Qt::WindowFullScreen)
outputWindow->setFullScreen(true);
+=======
+ case Qt::Key_F:
+ outputWindow->setFullScreen(true);
+>>>>>>> feature-undo-commands
break;
- case Qt::Key_N:
+ case Qt::Key_N:
newFile();
break;
- case Qt::Key_O:
+ case Qt::Key_O:
open();
break;
- case Qt::Key_S:
+ case Qt::Key_S:
save();
break;
- case Qt::Key_Q:
+ case Qt::Key_Q:
close();
break;
- case Qt::Key_Delete:
+ case Qt::Key_Delete:
deleteItem();
break;
- case Qt::Key_M:
+ case Qt::Key_M:
addMesh();
break;
- case Qt::Key_T:
+ case Qt::Key_T:
addTriangle();
break;
- case Qt::Key_E:
+ case Qt::Key_E:
addEllipse();
break;
- case Qt::Key_D:
+ case Qt::Key_D:
outputWindow->setVisible(true);
break;
- case Qt::Key_P:
+ case Qt::Key_P:
if (_isPlaying)
{
pause();
@@ -329,11 +332,18 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event)
play();
}
break;
- case Qt::Key_R:
+ case Qt::Key_R:
rewind();
break;
+ case Qt::Key_Z:
+ undoStack->undo();
+ break;
}
}
+ else if (keyEvent->matches(QKeySequence::Redo))
+ {
+ undoStack->redo();
+ }
else if (keyEvent->key() == Qt::Key_Escape)
{
outputWindow->setFullScreen(false);
@@ -368,6 +378,7 @@ void MainWindow::newFile()
{
clearWindow();
setCurrentFile("");
+ undoStack->clear();
}
// Restart video playback. XXX Hack
@@ -524,6 +535,9 @@ void MainWindow::addMesh()
Mapping::ptr mapping(mappingPtr);
uint mappingId = mappingManager->addMapping(mapping);
addMappingItem(mappingId);
+
+ // Implement undoStack Commands
+ undoStack->push(new AddShapesCommand(this, mappingId));
}
void MainWindow::addTriangle()
@@ -557,6 +571,9 @@ void MainWindow::addTriangle()
Mapping::ptr mapping(mappingPtr);
uint mappingId = mappingManager->addMapping(mapping);
addMappingItem(mappingId);
+
+ // Implement undoStack Commands
+ undoStack->push(new AddShapesCommand(this, mappingId));
}
void MainWindow::addEllipse()
@@ -590,6 +607,9 @@ void MainWindow::addEllipse()
Mapping::ptr mapping(mappingPtr);
uint mappingId = mappingManager->addMapping(mapping);
addMappingItem(mappingId);
+
+ // Implement undoStack Commands
+ undoStack->push(new AddShapesCommand(this, mappingId));
}
void MainWindow::play()
@@ -676,7 +696,7 @@ void MainWindow::deleteItem()
if (isMappingTabSelected) //currentSelectedItem->listWidget() == mappingList)
{
// Delete mapping.
- deleteMapping( getItemId(*mappingList->currentItem()) );
+ undoStack->push(new DeleteMappingCommand(this, getItemId(*mappingList->currentItem())));
//currentSelectedItem = NULL;
}
else if (isPaintTabSelected) //currentSelectedItem->listWidget() == paintList)
@@ -1146,6 +1166,9 @@ void MainWindow::createLayout()
void MainWindow::createActions()
{
+ // UndoStack
+ undoStack = new QUndoStack(this);
+
// New.
newAction = new QAction(tr("&New"), this);
newAction->setIcon(QIcon(":/new"));
@@ -1194,11 +1217,15 @@ void MainWindow::createActions()
connect(recentVideoActions[i], SIGNAL(triggered()), this, SLOT(openRecentVideo()));
}
- // Clear action
+ // Clear recent video list action
clearRecentFileActions = new QAction(this);
clearRecentFileActions->setVisible(true);
connect(clearRecentFileActions, SIGNAL(triggered()), this, SLOT(clearRecentFileList()));
+ // Empty list of recent video action
+ emptyRecentVideos = new QAction(tr("No Videos"), this);
+ emptyRecentVideos->setEnabled(false);
+
// Import video.
importVideoAction = new QAction(tr("&Import media source file..."), this);
@@ -1247,6 +1274,18 @@ void MainWindow::createActions()
// connect(pasteAction, SIGNAL(triggered()), spreadsheet, SLOT(paste()));
//
+ // Undo action
+ undoAction = undoStack->createUndoAction(this, tr("&Undo"));
+ undoAction->setShortcut(QKeySequence::Undo);
+ undoAction->setIconVisibleInMenu(false);
+ undoAction->setShortcutContext(Qt::ApplicationShortcut);
+
+ //Redo action
+ redoAction = undoStack->createRedoAction(this, tr("&Redo"));
+ redoAction->setShortcut(QKeySequence::Redo);
+ redoAction->setIconVisibleInMenu(false);
+ redoAction->setShortcutContext(Qt::ApplicationShortcut);
+
// About.
aboutAction = new QAction(tr("&About"), this);
aboutAction->setStatusTip(tr("Show the application's About box"));
@@ -1438,6 +1477,7 @@ void MainWindow::createMenus()
// Recent import video
recentVideoMenu = fileMenu->addMenu(tr("Recents video"));
+ recentVideoMenu->addAction(emptyRecentVideos);
for (int i = 0; i < MaxRecentVideo; ++i)
recentVideoMenu->addAction(recentVideoActions[i]);
@@ -1448,6 +1488,8 @@ void MainWindow::createMenus()
// Edit.
editMenu = menuBar->addMenu(tr("&Edit"));
+ editMenu->addAction(undoAction);
+ editMenu->addAction(redoAction);
// editMenu->addAction(cutAction);
// editMenu->addAction(copyAction);
// editMenu->addAction(pasteAction);
@@ -1497,7 +1539,7 @@ void MainWindow::createContextMenu()
// spreadsheet->addAction(cutAction);
// spreadsheet->addAction(copyAction);
// spreadsheet->addAction(pasteAction);
-// spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);
+ // spreadsheet->setContextMenuPolicy(Qt::ActionsContextMenu);
}
void MainWindow::createToolBars()
@@ -1599,6 +1641,7 @@ void MainWindow::readSettings()
}
config_osc_receive_port = settings.value("osc_receive_port", 12345).toInt();
+ // Update Recent files and video
updateRecentFileActions();
updateRecentVideoActions();
}
@@ -1769,9 +1812,9 @@ void MainWindow::updateRecentFileActions()
void MainWindow::updateRecentVideoActions()
{
recentVideos = settings.value("recentVideos").toStringList();
- int numRecentVidoes = qMin(recentVideos.size(), int(MaxRecentVideo));
+ int numRecentVideos = qMin(recentVideos.size(), int(MaxRecentVideo));
- for (int i = 0; i < numRecentVidoes; ++i)
+ for (int i = 0; i < numRecentVideos; ++i)
{
QString text = tr("&%1 %2")
.arg(i + 1)
@@ -1781,14 +1824,12 @@ void MainWindow::updateRecentVideoActions()
recentVideoActions[i]->setVisible(true);
}
- for (int j = numRecentVidoes; j < MaxRecentVideo; ++j)
+ for (int j = numRecentVideos; j < MaxRecentVideo; ++j)
recentVideoActions[j]->setVisible(false);
- if (numRecentVidoes <= 0)
+ if (numRecentVideos > 0)
{
- QAction *noVideos = new QAction(tr("No Videos"), this);
- noVideos->setEnabled(false);
- recentVideoMenu->addAction(noVideos);
+ emptyRecentVideos->setVisible(false);
}
}
diff --git a/MainWindow.h b/MainWindow.h
index a99770a..5b70ebf 100644
--- a/MainWindow.h
+++ b/MainWindow.h
@@ -22,6 +22,9 @@
#define MAIN_WINDOW_H_
#include
+#if QT_VERSION >= 0x050000
+ #include
+#endif
#include
#include
#include
@@ -262,6 +265,8 @@ private:
QAction *saveAction;
QAction *saveAsAction;
QAction *exitAction;
+ QAction *undoAction;
+ QAction *redoAction;
// QAction *cutAction;
// QAction *copyAction;
// QAction *pasteAction;
@@ -269,6 +274,7 @@ private:
QAction *preferencesAction;
QAction *aboutAction;
QAction *clearRecentFileActions;
+ QAction *emptyRecentVideos;
QAction *addMeshAction;
QAction *addTriangleAction;
@@ -352,6 +358,11 @@ private:
PreferencesDialog* _preferences_dialog;
+ // UndoStack
+ QUndoStack *undoStack;
+
+
+
public:
// Accessor/mutators for the view. ///////////////////////////////////////////////////////////////////
MappingManager& getMappingManager() { return *mappingManager; }
@@ -366,6 +377,9 @@ public:
void removeCurrentPaint();
void removeCurrentMapping();
+ // Use the same undoStack for whole program
+ QUndoStack* getUndoStack() const { return undoStack; }
+
void startFullScreen();
bool setOscPort(QString portNumber);
bool setOscPort(int portNumber);
diff --git a/MapperGLCanvas.cpp b/MapperGLCanvas.cpp
index 72346e9..9723200 100644
--- a/MapperGLCanvas.cpp
+++ b/MapperGLCanvas.cpp
@@ -21,6 +21,7 @@
#include "MapperGLCanvas.h"
#include "MainWindow.h"
+#include "Commands.h"
MapperGLCanvas::MapperGLCanvas(MainWindow* mainWindow, QWidget* parent, const QGLWidget * shareWidget)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent, shareWidget),
@@ -188,6 +189,9 @@ void MapperGLCanvas::mouseReleaseEvent(QMouseEvent* event)
void MapperGLCanvas::mouseMoveEvent(QMouseEvent* event)
{
+ // Prepare to store commands
+ undoStack = getMainWindow()->getUndoStack();
+
if (_mousePressedOnVertex)
{
// std::cout << "Move event " << std::endl;
@@ -202,10 +206,9 @@ void MapperGLCanvas::mouseMoveEvent(QMouseEvent* event)
// Stick to vertices.
if (stickyVertices())
glueVertex(shape, &p);
- shape->setVertex(_activeVertex, p);
- update();
- emit shapeChanged(getCurrentShape());
+ // Enable to Undo and Redo when mouse move the position of vertices
+ undoStack->push(new MoveVertexCommand(this, _activeVertex, p));
}
}
else if (_shapeGrabbed)
@@ -217,9 +220,7 @@ void MapperGLCanvas::mouseMoveEvent(QMouseEvent* event)
{
if (!_shapeFirstGrab)
{
- shape->translate(event->x() - prevMousePosition.x(), event->y() - prevMousePosition.y());
- update();
- emit shapeChanged(getCurrentShape());
+ undoStack->push(new MoveShapesCommand(this, event, prevMousePosition));
}
else
_shapeFirstGrab = false;
@@ -232,6 +233,9 @@ void MapperGLCanvas::mouseMoveEvent(QMouseEvent* event)
void MapperGLCanvas::keyPressEvent(QKeyEvent* event)
{
+ // Prepare to store commands
+ undoStack = getMainWindow()->getUndoStack();
+
// Checks if the key has been handled by this function or needs to be deferred to superclass.
bool handledKey = false;
@@ -264,13 +268,18 @@ void MapperGLCanvas::keyPressEvent(QKeyEvent* event)
p.rx()--;
break;
default:
- handledKey = false;
+ if (event->matches(QKeySequence::Undo))
+ undoStack->undo();
+
+ else if (event->matches(QKeySequence::Redo))
+ undoStack->redo();
+ else
+ handledKey = false;
break;
}
// TODO: this will always be called even if no arrow key has been pressed (small performance issue).
- shape->setVertex(_activeVertex, p);
- update();
- emit shapeChanged(getCurrentShape());
+ // Enable to Undo and Redo when arrow keys move the position of vertices
+ undoStack->push(new MoveVertexCommand(this, _activeVertex, p));
}
// Defer unhandled keys to parent.
diff --git a/MapperGLCanvas.h b/MapperGLCanvas.h
index ca8ef24..9576638 100644
--- a/MapperGLCanvas.h
+++ b/MapperGLCanvas.h
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
@@ -141,6 +142,9 @@ private:
// True iff we want vertices to stick to each other.
bool _stickyVertices;
+ // Pointer to MainWindow UndoStack
+ QUndoStack *undoStack;
+
signals:
void shapeChanged(Shape*);
void imageChanged();
diff --git a/main.cpp b/main.cpp
index 490a27c..c68aedc 100644
--- a/main.cpp
+++ b/main.cpp
@@ -4,7 +4,6 @@
#include
#include
-#include
#include
#if USING_QT_5
#include
diff --git a/mapmap.pro b/mapmap.pro
index b85f270..b5a323c 100644
--- a/mapmap.pro
+++ b/mapmap.pro
@@ -2,10 +2,12 @@ CONFIG += qt debug
TEMPLATE = app
VERSION = 0.2.1
TARGET = mapmap
-QT += gui opengl xml widgets
+QT += gui opengl xml
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
DEFINES += UNICODE QT_THREAD_SUPPORT QT_CORE_LIB QT_GUI_LIB
HEADERS = \
+ Commands.h \
DestinationGLCanvas.h \
MM.h \
MainApplication.h \
@@ -30,6 +32,7 @@ HEADERS = \
Util.h
SOURCES = \
+ Commands.cpp \
DestinationGLCanvas.cpp \
MM.cpp \
MainApplication.cpp \