Česky
Kamil Dudka

GED 2006 (C++)

File detail

Name:Downloadcommand.cc [Download]
Location: ged2006 > src
Size:7.1 KB
Last modification:2007-08-29 02:16

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