Skip to content

Instantly share code, notes, and snippets.

@sfpgmr
Created November 6, 2022 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfpgmr/d98d1293d70f037c5f713fd81250f7f5 to your computer and use it in GitHub Desktop.
Save sfpgmr/d98d1293d70f037c5f713fd81250f7f5 to your computer and use it in GitHub Desktop.
#pragma once
/** @file
* @brief undo redo command class
* @author S.F. (Satoshi Fujiwara)
*/
#include <stack>
namespace sf {
namespace model {
struct command_manager;
struct command_interface
{
virtual ~command_interface(){};
virtual const bool can_undo() const throw() = 0;
virtual const bool can_redo() const throw() = 0;
virtual const bool is_terminate() const throw() = 0;
virtual void undo() = 0;
virtual void redo() = 0;
virtual void execute() = 0;
virtual const std::wstring& name() const throw() = 0;
};
struct abstract_command : public command_interface
{
abstract_command(const bool terminate)
: m_terminate(terminate){}
abstract_command(const abstract_command& src)
: m_terminate(src.m_terminate) {}
virtual ~abstract_command(){};
virtual const bool is_terminate() const throw() {return m_terminate;}
virtual void execute() {redo();}
virtual const std::wstring& name() const throw() = 0;
protected:
bool m_terminate;
};
struct command : public abstract_command
{
typedef boost::function<void () > func_type;
command(const std::wstring& command_name,const func_type& exec_func,const func_type& undo_func,const bool term = true)
: abstract_command(term),m_name(command_name),m_undo_func(undo_func),m_exec_func(exec_func),m_terminate(term)
{
//m_undo_func = undo_func;
//m_exec_func = exec_func;
//m_terminate = term;
};
command(const std::wstring& command_name,const func_type& exec_func,const bool term = true)
: abstract_command(term),m_name(command_name),m_exec_func(exec_func),m_terminate(term)
{
//m_exec_func = exec_func;
//m_terminate = term;
};
~command(){};
const bool can_undo() const throw()
{
return !m_undo_func.empty();
};
const bool can_redo() const throw()
{
return !m_exec_func.empty();
};
const bool is_terminate() const throw() { return m_terminate;};
void undo(){m_undo_func();};
void redo(){m_exec_func();};
void execute(){m_exec_func();};
const std::wstring& name() const throw() {return m_name;}
private:
func_type m_undo_func;
func_type m_exec_func;
bool m_terminate;
std::wstring m_name;
static void null_func(){};
};
struct command_manager
{
typedef boost::function<void (command_manager&)> changed_evt_func;
typedef boost::ptr_deque<sf::model::command_interface> container_type;
command_manager(){};
~command_manager(){};
void add(command_interface* exec_command)
{
if(exec_command->can_undo())
{
m_redo.clear();
m_undo.push_front(exec_command);
m_func(*this);
}
}
void undo()
{
bool term_ = false;
while(!term_ && !m_undo.empty())
{
// (_T("undo() size: %d \n"),m_undo.size());
m_undo.front().undo();
term_ = m_undo.front().is_terminate();
m_redo.push_front(m_undo.pop_front().release());
// m_undo.pop_front();
}
if(!m_func.empty())
{
m_func(*this);
}
}
void redo()
{
bool term_ = false;
while(!term_ && !m_redo.empty())
{
m_redo.front().redo();
term_ = m_redo.front().is_terminate();
m_undo.push_front(m_redo.pop_front().release());
// m_redo.pop_front();
}
if(!m_func.empty())
{
m_func(*this);
}
}
void clear()
{
m_undo.clear();
m_redo.clear();
if(!m_func.empty())
{
m_func(*this);
}
}
const container_type& undo_buf() const throw() {return m_undo;}
const container_type& redo_buf() const throw() {return m_redo;}
const bool is_undo(){return !m_undo.empty();};
const bool is_redo(){return !m_undo.empty();};
void event_func(const changed_evt_func& func){m_func = func;};
private:
changed_evt_func m_func;
container_type m_undo;
container_type m_redo;
};
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment