Browse Source

Add undoable command test

- Add UndoableCommand base class
 - Add CommandManager that handles undoing
 - Add test to main ofxPiMapper files
master
Krisjanis Rijnieks 10 years ago
parent
commit
df840a293c
  1. 28
      example/example.xcodeproj/project.pbxproj
  2. 42
      src/Commands/BaseCommand.h
  3. 9
      src/Commands/Command.h
  4. 27
      src/Commands/CommandManager.cpp
  5. 23
      src/Commands/CommandManager.h
  6. 7
      src/Commands/TestCommand.cpp
  7. 16
      src/Commands/TestCommand.h
  8. 21
      src/Commands/TestUndoCommand.cpp
  9. 27
      src/Commands/TestUndoCommand.h
  10. 25
      src/ofxPiMapper.cpp
  11. 37
      src/ofxPiMapper.h

28
example/example.xcodeproj/project.pbxproj

@ -63,6 +63,9 @@
39C1248119F187D5005DF557 /* TextureEditor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C1247A19F187D5005DF557 /* TextureEditor.cpp */; };
39C1248819F1EB75005DF557 /* SurfaceManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C1248319F1EB75005DF557 /* SurfaceManager.cpp */; };
39C1248919F1EB75005DF557 /* SurfaceManagerGui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C1248519F1EB75005DF557 /* SurfaceManagerGui.cpp */; };
39C787BD1AC2111B00691393 /* CommandManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C787BC1AC2111B00691393 /* CommandManager.cpp */; };
39C787C11AC2BBAE00691393 /* TestUndoCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39C787BF1AC2BBAE00691393 /* TestUndoCommand.cpp */; };
39FDD9EE1AC00EAE00262205 /* TestCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 39FDD9EC1AC00EAE00262205 /* TestCommand.cpp */; };
BBAB23CB13894F3D00AA2426 /* GLUT.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = BBAB23BE13894E4700AA2426 /* GLUT.framework */; };
E4328149138ABC9F0047C5CB /* openFrameworksDebug.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E4328148138ABC890047C5CB /* openFrameworksDebug.a */; };
E45BE97B0E8CC7DD009D7055 /* AGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E45BE9710E8CC7DD009D7055 /* AGL.framework */; };
@ -246,6 +249,13 @@
39C1248519F1EB75005DF557 /* SurfaceManagerGui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SurfaceManagerGui.cpp; sourceTree = "<group>"; };
39C1248619F1EB75005DF557 /* SurfaceManagerGui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceManagerGui.h; sourceTree = "<group>"; };
39C1248719F1EB75005DF557 /* SurfaceType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SurfaceType.h; sourceTree = "<group>"; };
39C787BB1AC20D2400691393 /* CommandManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandManager.h; path = Commands/CommandManager.h; sourceTree = "<group>"; };
39C787BC1AC2111B00691393 /* CommandManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandManager.cpp; path = Commands/CommandManager.cpp; sourceTree = "<group>"; };
39C787BF1AC2BBAE00691393 /* TestUndoCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestUndoCommand.cpp; path = Commands/TestUndoCommand.cpp; sourceTree = "<group>"; };
39C787C01AC2BBAE00691393 /* TestUndoCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestUndoCommand.h; path = Commands/TestUndoCommand.h; sourceTree = "<group>"; };
39FDD9EA1AC007BF00262205 /* BaseCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BaseCommand.h; path = Commands/BaseCommand.h; sourceTree = "<group>"; };
39FDD9EC1AC00EAE00262205 /* TestCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TestCommand.cpp; path = Commands/TestCommand.cpp; sourceTree = "<group>"; };
39FDD9ED1AC00EAE00262205 /* TestCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestCommand.h; path = Commands/TestCommand.h; sourceTree = "<group>"; };
BBAB23BE13894E4700AA2426 /* GLUT.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLUT.framework; path = ../../../libs/glut/lib/osx/GLUT.framework; sourceTree = "<group>"; };
E4328143138ABC890047C5CB /* openFrameworksLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = openFrameworksLib.xcodeproj; path = ../../../libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj; sourceTree = SOURCE_ROOT; };
E45BE9710E8CC7DD009D7055 /* AGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AGL.framework; path = /System/Library/Frameworks/AGL.framework; sourceTree = "<absolute>"; };
@ -364,6 +374,7 @@
396E8A2F190FEDD900705899 /* src */ = {
isa = PBXGroup;
children = (
39FDD9E81AC0076200262205 /* Commands */,
39C1246D19F187D5005DF557 /* UserInterface */,
39C1246219F0AB96005DF557 /* Surfaces */,
39C1245619F086A9005DF557 /* Sources */,
@ -628,6 +639,20 @@
path = UserInterface;
sourceTree = "<group>";
};
39FDD9E81AC0076200262205 /* Commands */ = {
isa = PBXGroup;
children = (
39FDD9EA1AC007BF00262205 /* BaseCommand.h */,
39C787BB1AC20D2400691393 /* CommandManager.h */,
39C787BC1AC2111B00691393 /* CommandManager.cpp */,
39FDD9ED1AC00EAE00262205 /* TestCommand.h */,
39FDD9EC1AC00EAE00262205 /* TestCommand.cpp */,
39C787C01AC2BBAE00691393 /* TestUndoCommand.h */,
39C787BF1AC2BBAE00691393 /* TestUndoCommand.cpp */,
);
name = Commands;
sourceTree = "<group>";
};
BB4B014C10F69532006C3DED /* addons */ = {
isa = PBXGroup;
children = (
@ -807,6 +832,7 @@
buildActionMask = 2147483647;
files = (
3933D5D819BB87BD000ACA55 /* ofxSlider.cpp in Sources */,
39C787BD1AC2111B00691393 /* CommandManager.cpp in Sources */,
39C1247E19F187D5005DF557 /* ProjectionEditor.cpp in Sources */,
39C1244619EE9589005DF557 /* RecursiveDirectoryIteratorStategies.cpp in Sources */,
39C1243A19EE9589005DF557 /* Compression.cpp in Sources */,
@ -823,7 +849,9 @@
397EFC7F1A08FE720009286E /* FboSource.cpp in Sources */,
E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */,
39C1244719EE9589005DF557 /* RegexPathFilter.cpp in Sources */,
39C787C11AC2BBAE00691393 /* TestUndoCommand.cpp in Sources */,
39C1247C19F187D5005DF557 /* BaseJoint.cpp in Sources */,
39FDD9EE1AC00EAE00262205 /* TestCommand.cpp in Sources */,
39C1245219EE95DD005DF557 /* MediaServer.cpp in Sources */,
39C1243D19EE9589005DF557 /* DirectoryUtils.cpp in Sources */,
39264843192224F90008A7F5 /* tinyxmlparser.cpp in Sources */,

42
src/Commands/BaseCommand.h

@ -0,0 +1,42 @@
// Command base class for separating ofxPiMapper available commands from the core.
// Created by Krisjanis Rijnieks 2015-03-23
// Good example
// http://gameprogrammingpatterns.com/command.html
#pragma once
namespace ofx{
namespace piMapper{
// Base class for all commands
class BaseCommand{
public:
virtual ~BaseCommand(){};
virtual void execute() = 0;
virtual bool isUndoable(){return false;}
protected:
BaseCommand(){};
};
// Base class for all undoable commands
class BaseUndoableCommand : public BaseCommand{
public:
virtual void undo() = 0;
virtual bool isUndoable(){return true;}
protected:
BaseUndoableCommand(){};
};
} // namespace piMapper
} // namespace ofx
// Ideas for command classes
// SelectSurfaceCommand
// MoveSurfaceCommand
// SelectSourceMapCommand
// MoveSourceMapCommand

9
src/Commands/Command.h

@ -1,9 +0,0 @@
// Command base class for separating ofxPiMapper available commands from the core.
// Created by Krisjanis Rijnieks 2015-03-23
#pragma once
class Command{
public:
virtual void execute() = 0;
};

27
src/Commands/CommandManager.cpp

@ -0,0 +1,27 @@
#include "CommandManager.h"
namespace ofx{
namespace piMapper{
void CommandManager::executeCommand(BaseCommand * cmd){
cmd->execute();
if (cmd->isUndoable()){
commandStack.push_back(static_cast<BaseUndoableCommand *>(cmd));
}
}
void CommandManager::undo(){
if (commandStack.size() > 0){
BaseUndoableCommand * cmd = commandStack.back();
cmd->undo();
// Delete last command for now
// TODO: Enable redo func and that means we do not destroy last command,
// we move the stack pointer instead.
delete commandStack.back();
commandStack.pop_back();
}
}
} // namespace piMapper
} // namespace ofx

23
src/Commands/CommandManager.h

@ -0,0 +1,23 @@
// CommandManager class to keep a stack of commands for undo functionality
// Created by Krisjanis Rijnieks 2015-03-24
#pragma once
#import <deque>
#import "BaseCommand.h"
namespace ofx{
namespace piMapper{
class CommandManager{
public:
void executeCommand(BaseCommand * cmd);
void undo();
private:
std::deque<BaseUndoableCommand *> commandStack;
};
} // namespace piMapper
} // namespace ofx

7
src/Commands/TestCommand.cpp

@ -1,5 +1,8 @@
# include "TestCommand.h"
namespace ofx{
namespace piMapper{
TestCommand::TestCommand(ofxPiMapper * a){
_application = a;
}
@ -8,3 +11,7 @@ void TestCommand::execute(){
string name = "Hugo";
_application->testCommand(name);
}
} // namespace piMapper
} // namespace ofx

16
src/Commands/TestCommand.h

@ -5,17 +5,23 @@
#pragma once
#include "ofxPiMapper.h"
#include "Command.h"
#include "BaseCommand.h"
class ofxPiMapper;
class TestCommand : public Command{
namespace ofx{
namespace piMapper{
class TestCommand : public BaseCommand{
public:
TestCommand(ofxPiMapper * a);
~TestCommand();
virtual void execute();
void execute();
private:
ofxPiMapper * _application;
};
} // namespace piMapper
} // namespace ofx

21
src/Commands/TestUndoCommand.cpp

@ -0,0 +1,21 @@
#include "TestUndoCommand.h"
namespace ofx{
namespace piMapper{
TestUndoCommand::TestUndoCommand(ofxPiMapper * a){
_application = a;
}
void TestUndoCommand::execute(){
increase = 2;
_application->testUndoableCommand(increase);
}
void TestUndoCommand::undo(){
_application->testUndoableCommand(-increase);
}
} // namespace piMapper
} // namespace ofx

27
src/Commands/TestUndoCommand.h

@ -0,0 +1,27 @@
// Created by Krisjanis Rijnieks 2015-03-25
#pragma once
#include "ofxPiMapper.h"
#include "BaseCommand.h"
class ofxPiMapper;
namespace ofx{
namespace piMapper{
class TestUndoCommand : public BaseUndoableCommand{
public:
TestUndoCommand(ofxPiMapper * a);
void execute();
void undo();
private:
ofxPiMapper * _application;
int increase;
};
} // namespace piMapper
} // namespace ofx

25
src/ofxPiMapper.cpp

@ -1,8 +1,6 @@
#include "ofxPiMapper.h"
ofxPiMapper::ofxPiMapper():
bShowInfo(false),
isSetUp(false){
ofxPiMapper::ofxPiMapper(): bShowInfo(false), isSetUp(false){
ofAddListener(ofEvents().keyPressed, this, &ofxPiMapper::keyPressed);
}
@ -33,9 +31,8 @@ void ofxPiMapper::setup() {
ofLogNotice("ofxPiMapper") << "Done setting up";
// Initialize TestCommand
ofxPiMapper * app = this;
aTestCommand = new TestCommand(app);
// Initialize undo test vars
undoTestValue = 0;
}
void ofxPiMapper::draw(){
@ -66,12 +63,15 @@ void ofxPiMapper::draw() {
ofColor(255, 255, 255, 200));
}
ofDrawBitmapStringHighlight(ofToString(undoTestValue), 200, 200);
} // draw
void ofxPiMapper::keyPressed(ofKeyEventArgs &args){
ofLogNotice("ofxPiMapper") << "Key pressed: " << static_cast<char>(args.key);
switch (args.key) {
case '1':
gui.setMode(ofx::piMapper::GuiMode::NONE);
break;
@ -103,8 +103,15 @@ void ofxPiMapper::keyPressed(ofKeyEventArgs &args) {
surfaceManager.removeSelectedSurface();
break;
// TODO: Remove the following case when Command test done.
case '9':
commandManager.executeCommand(new ofx::piMapper::TestUndoCommand((ofxPiMapper *)this));
break;
case '0':
aTestCommand->execute();
commandManager.executeCommand(new ofx::piMapper::TestCommand((ofxPiMapper *)this));
break;
case 'u':
// undo
commandManager.undo();
break;
default:
break;
@ -171,3 +178,7 @@ ofx::piMapper::SurfaceManager& ofxPiMapper::getSurfaceManager() {
void ofxPiMapper::testCommand(string name){
ofLogNotice("ofxPiMapper", name);
}
void ofxPiMapper::testUndoableCommand(int increase){
undoTestValue += increase;
}

37
src/ofxPiMapper.h

@ -8,6 +8,9 @@
*
* Author: Krisjanis Rijnieks */
// On using prefixes like m or p (mMemberVariable, pMyPointer)
// http://stackoverflow.com/questions/1228161/why-use-prefixes-on-member-variables-in-c-classes
#pragma once
#include "ofMain.h"
@ -16,32 +19,30 @@
#include "MediaServer.h"
#include "FboSource.h"
#include "Command.h"
#include "BaseCommand.h"
#include "TestCommand.h" // TODO: Remove this line when done testing
#include "TestUndoCommand.h"
#include "CommandManager.h"
#define PIMAPPER_DEF_SURFACES_XML_FILE "defaultSurfaces.xml"
#define PIMAPPER_USER_SURFACES_XML_FILE "surfaces.xml"
class ofxPiMapper{
public:
// These are here for adding and removing listeners on
// contruction and deconstruction
public:
ofxPiMapper();
~ofxPiMapper();
// These are here to adapt to the openFrameworks ways
void setup();
void draw(); // Called manually to make custom layering possible
void draw();
void keyPressed(ofKeyEventArgs& args);
// Use this to add custom FBO source
void addFboSource(ofx::piMapper::FboSource& fboSource);
/* Discussion:
* Maybe it makes more sense to use create prefix instead of add
* in addTriangleSurface and so on, so we get createTriangleSurface.
* TODO: Copy/move these methods to SurfaceManager (not sure) */
// Discussion:
// Maybe it makes more sense to use create prefix instead of add
// in addTriangleSurface and so on, so we get createTriangleSurface.
// TODO: Copy/move these methods to SurfaceManager (not sure)
void addTriangleSurface();
void addQuadSurface();
@ -49,15 +50,17 @@ public:
void showInfo() { bShowInfo = true; };
void hideInfo() { bShowInfo = false; };
/* Discussion:
* Maybe these should be static as this would allow to access them
* from anywhere within ofxPiMapper. */
// Discussion:
// Maybe these should be static as this would allow to access them
// from anywhere within ofxPiMapper.
ofx::piMapper::MediaServer& getMediaServer();
ofx::piMapper::SurfaceManager& getSurfaceManager();
// Test first steps of the Command design pattern implementation.
void testCommand(string name);
Command * aTestCommand;
void testUndoableCommand(int increase);
int undoTestValue;
ofx::piMapper::CommandManager commandManager;
private:
bool isSetUp;
@ -65,7 +68,7 @@ private:
ofx::piMapper::MediaServer mediaServer;
ofx::piMapper::SurfaceManager surfaceManager;
/* Discussion: Here now the GUI points only to surface manager,
* maybe it should be as a separate layer? */
// Discussion: Here now the GUI points only to surface manager,
// maybe it should be as a separate layer?
ofx::piMapper::SurfaceManagerGui gui;
};
Loading…
Cancel
Save