GED 2006 (C++)
File detail
Source code
/*
* File: command.cc - Command abstraction and command history
* Project: GED - bitmap editor (ICP)
* Author: Kamil Dudka, xdudka00
* Team: xdudka00, xfilak01, xhefka00, xhradi08
* Created: 2006-03-10
*/
#include <iostream>
#include <string>
#include <list>
#include "gedconf.h"
#include "pluginsupport.h"
#include "draw.h"
#include "command.h"
typedef std::list<Cmd *>::iterator TCmdIterator;
typedef std::list<Cmd *>::const_iterator TCmdConstIterator;
using std::string;
const char *MacroCmd::szCmdName = "MacroCmd";
/*
* Save undo bitmap for selected area
*/
void SlowUndoSelectCmd::exec ()
{
_sa= _fb.select ();
_fbUndo.size (_sa.size);
for (int y=0; y< _sa.size.height; y++)
for (int x=0; x< _sa.size.width; x++)
_fbUndo [y][x] = _fb [y + _sa.at.y][x + _sa.at.x];
}
/*
* Restore selected area from undo bitmap
*/
void SlowUndoSelectCmd::unExec ()
{
for (int y=0; y< _sa.size.height; y++)
for (int x=0; x< _sa.size.width; x++)
_fb [y + _sa.at.y][x + _sa.at.x] = _fbUndo [y][x];
}
/*
* Read macro command from configuration file
* macName: macro name
*/
MacroCmd::MacroCmd (FrameBuffer *pFB, std::string macName):
Cmd (pFB), _macName (macName)
{
CommandVector srcList= GedConf::ptr()->getCommands (macName);
for (
CommandVector::iterator i= srcList.begin();
i!= srcList.end();
i++)
addFromConf (*i);
}
/*
* Save macro command to configuration file
*/
void MacroCmd::save ()
{
for (TCmdIterator i= _cmdList.begin(); i!= _cmdList.end(); i++)
addToConf (*i);
}
/*
* Add command to MacroCmd from CommandVector item
*/
void MacroCmd::addFromConf (GedMacroCommand &cmd)
{
if (cmd.getName() == string(BrushCmd::szCmdName)) {
// TOOL_BRUSH
operator<< (new BrushCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(LineCmd::szCmdName)) {
// TOOL_LINE
operator<< (new LineCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(RectCmd::szCmdName)) {
// TOOL_RECT
operator<< (new RectCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(CircleCmd::szCmdName)) {
// TOOL_CIRCLE
operator<< (new CircleCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(EllipseCmd::szCmdName)) {
// TOOL_ELLIPSE
operator<< (new EllipseCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(TextCmd::szCmdName)) {
// TOOL_TEXT
operator<< (new TextCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(SelectCmd::szCmdName)) {
// TOOL_SELECT
operator<< (new SelectCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(GrayScaleCmd::szCmdName)) {
// Built-in filter "Grayscale"
operator<< (new GrayScaleCmd (&_fb, cmd.getParam ()));
}
else if (cmd.getName() == string(InvertCmd::szCmdName)) {
// Built-in filter "Invert"
operator<< (new InvertCmd (&_fb, cmd.getParam ()));
}
else {
// Create plugin command
operator<< (new PluginCmd (&_fb, cmd.getName(), cmd.getParam()));
}
}
/*
* Add command to configuration file
*/
void MacroCmd::addToConf (Cmd *pCmd)
{
const std::string strName = pCmd->name();
const std::string strArgs = pCmd->args();
if (strName == MacroCmd::szCmdName) {
// Nested macro
std::cerr << "Nested macro: " << strArgs << "\n";
if (strName == _macName)
// Avoid direct macro recursion
return;
// Add nested macro
MacroCmd *nestedMac = new MacroCmd (&_fb, strArgs);
nestedMac->name (_macName);
nestedMac->save ();
delete nestedMac;
return;
}
// Command
GedConf::ptr()->addMacro (_macName.c_str(), strName.c_str(), strArgs.c_str());
#ifndef NDEBUG
std::cerr << "Added Cmd \'" << strName << "\' to macro \'" << _macName << "\'\n";
#endif
}
/*
* Add command to MacroCommand
*/
MacroCmd &MacroCmd::operator<< (Cmd *pCmd)
{
_cmdList.push_back (pCmd);
return *this;
}
/*
* Execute macro command
*/
void MacroCmd::exec ()
{
for (_crashPoint= _cmdList.begin(); _crashPoint!= _cmdList.end(); _crashPoint++)
(*_crashPoint) -> exec();
}
/*
* Revert macro execution (for undo)
*/
void MacroCmd::unExec ()
{
if (_cmdList.begin() == _crashPoint)
// empty macro
return;
for (_crashPoint--; _crashPoint!=_cmdList.begin(); _crashPoint--)
(*_crashPoint) -> unExec();
(*_cmdList.begin()) -> unExec();
}
/*
* execute PluginCmd (and save undo)
*/
void PluginCmd::exec()
{
// save undo
SlowUndoCmd::exec();
// call plugin
PluginList::ptr()->callByName (_fb, _pluginName, _pluginArgs);
}
/*
* Initialize history list
*/
CmdHistory::CmdHistory ():
_now (_histList.begin ()),
_iMacroOffset (0),
_iLastSave (0),
_bSavePointLost (false),
_bMacroLoading (false)
{
}
/*
* Destroy history list
*/
CmdHistory::~CmdHistory () {
// Delete all commands
for (_now = _histList.begin(); _now!= _histList.end(); _now ++)
delete *_now;
}
/*
* Put command to history list
*/
CmdHistory &CmdHistory::operator<< (Cmd *pCmd) {
if (_now!= _histList.end() && _iLastSave > undoAvailable ())
// impossible to revert changes
_bSavePointLost = true;
// Delete undo till _now
for (TCmdIterator i=_now; i!= _histList.end(); i++)
delete *i;
_histList.erase (_now, _histList.end());
// Insert command
_histList.push_back (pCmd);
_now = _histList.end();
return *this;
}
/*
* return true if undo is possible
*/
bool CmdHistory::canUndo () const {
//return !_bMacroLoading && _now != _histList.begin ();
return
_now!= _histList.begin() &&
(!_bMacroLoading || _iMacroOffset < undoAvailable());
}
/*
* return true if redo is possible
*/
bool CmdHistory::canRedo () const {
//return !_bMacroLoading && _now != _histList.end ();
return _now != _histList.end ();
}
/*
* Count cmd list items between "start" and "end"
*/
int CmdHistory::undoAvailable () const {
int count=0;
for (TCmdConstIterator i=_histList.begin(); i!=_now; i++)
count++;
return count;
}
/*
* return true if image has changed since last saving
*/
bool CmdHistory::needSave ()
{
if (_bSavePointLost)
return true;
return _iLastSave != undoAvailable ();
}
/*
* This method may be called on user save action
*/
void CmdHistory::setSaved ()
{
_bSavePointLost = false;
_iLastSave = undoAvailable ();
}
/*
* Cancel last operation
*/
void CmdHistory::rollBack ()
{
if (_now != _histList.end ())
// out of range
throw ErrUnderflow ();
_now --;
delete *_now;
_histList.erase (_now);
_now = _histList.end();
}
/*
* Undo command
*/
void CmdHistory::undo () {
if (!canUndo ())
// out of range
throw ErrUnderflow ();
_now --;
(*_now) -> unExec();
}
/*
* Redo command
*/
void CmdHistory::redo () {
if (!canRedo ())
// out of range
throw ErrUnderflow ();
(*_now) -> exec();
_now ++;
}
/*
* Start macro recording
*/
void CmdHistory::startMacro () {
_iMacroOffset = undoAvailable ();
_bMacroLoading = true;
}
/*
* Build macro command
*/
MacroCmd *CmdHistory::createMacroCmd () {
if (_iMacroOffset > undoAvailable())
throw ErrUnderflow ();
TCmdIterator pos = _histList.begin();
// create macro command
MacroCmd *macro = new MacroCmd ( &((*pos)->_fb) );
// jump to _iMacroOffset
for (int i=0; i<_iMacroOffset; i++)
pos++;
// add commands between _iMacroOffset nad _now
for (; pos!=_now; pos++)
*macro << *pos;
_bMacroLoading = false;
return macro;
}