#include "timer.h"
-class DebugScopeTimer
-{
-Timer m_timer;
-const char* m_operation;
+class DebugScopeTimer {
+ Timer m_timer;
+ const char *m_operation;
public:
-DebugScopeTimer( const char* operation )
- : m_operation( operation ){
- m_timer.start();
-}
-~DebugScopeTimer(){
- unsigned int elapsed = m_timer.elapsed_msec();
- if ( elapsed > 0 ) {
- globalOutputStream() << m_operation << ": " << elapsed << " msec\n";
- }
-}
+ DebugScopeTimer(const char *operation)
+ : m_operation(operation)
+ {
+ m_timer.start();
+ }
+
+ ~DebugScopeTimer()
+ {
+ unsigned int elapsed = m_timer.elapsed_msec();
+ if (elapsed > 0) {
+ globalOutputStream() << m_operation << ": " << elapsed << " msec\n";
+ }
+ }
};
-class RadiantUndoSystem : public UndoSystem
-{
-UINT_CONSTANT( MAX_UNDO_LEVELS, 1024 );
+class RadiantUndoSystem : public UndoSystem {
+ UINT_CONSTANT(MAX_UNDO_LEVELS, 1024);
+
+ class Snapshot {
+ class StateApplicator {
+ public:
+ Undoable *m_undoable;
+ private:
+ UndoMemento *m_data;
+ public:
+
+ StateApplicator(Undoable *undoable, UndoMemento *data)
+ : m_undoable(undoable), m_data(data)
+ {
+ }
+
+ void restore()
+ {
+ m_undoable->importState(m_data);
+ }
+
+ void release()
+ {
+ m_data->release();
+ }
+ };
+
+ typedef std::list<StateApplicator> states_t;
+ states_t m_states;
+
+ public:
+ bool empty() const
+ {
+ return m_states.empty();
+ }
+
+ std::size_t size() const
+ {
+ return m_states.size();
+ }
+
+ void save(Undoable *undoable)
+ {
+ m_states.push_front(StateApplicator(undoable, undoable->exportState()));
+ }
+
+ void restore()
+ {
+ for (states_t::iterator i = m_states.begin(); i != m_states.end(); ++i) {
+ (*i).restore();
+ }
+ }
+
+ void release()
+ {
+ for (states_t::iterator i = m_states.begin(); i != m_states.end(); ++i) {
+ (*i).release();
+ }
+ }
+ };
+
+ struct Operation {
+ Snapshot m_snapshot;
+ CopiedString m_command;
+
+ Operation(const char *command)
+ : m_command(command)
+ {
+ }
+
+ ~Operation()
+ {
+ m_snapshot.release();
+ }
+ };
+
+
+ class UndoStack {
+//! Note: using std::list instead of vector/deque, to avoid copying of undos
+ typedef std::list<Operation *> Operations;
+
+ Operations m_stack;
+ Operation *m_pending;
+
+ public:
+ UndoStack() : m_pending(0)
+ {
+ }
+
+ ~UndoStack()
+ {
+ clear();
+ }
+
+ bool empty() const
+ {
+ return m_stack.empty();
+ }
+
+ std::size_t size() const
+ {
+ return m_stack.size();
+ }
+
+ Operation *back()
+ {
+ return m_stack.back();
+ }
+
+ const Operation *back() const
+ {
+ return m_stack.back();
+ }
+
+ Operation *front()
+ {
+ return m_stack.front();
+ }
+
+ const Operation *front() const
+ {
+ return m_stack.front();
+ }
+
+ void pop_front()
+ {
+ delete m_stack.front();
+ m_stack.pop_front();
+ }
+
+ void pop_back()
+ {
+ delete m_stack.back();
+ m_stack.pop_back();
+ }
+
+ void clear()
+ {
+ if (!m_stack.empty()) {
+ for (Operations::iterator i = m_stack.begin(); i != m_stack.end(); ++i) {
+ delete *i;
+ }
+ m_stack.clear();
+ }
+ }
+
+ void start(const char *command)
+ {
+ if (m_pending != 0) {
+ delete m_pending;
+ }
+ m_pending = new Operation(command);
+ }
+
+ bool finish(const char *command)
+ {
+ if (m_pending != 0) {
+ delete m_pending;
+ m_pending = 0;
+ return false;
+ } else {
+ ASSERT_MESSAGE(!m_stack.empty(), "undo stack empty");
+ m_stack.back()->m_command = command;
+ return true;
+ }
+ }
+
+ void save(Undoable *undoable)
+ {
+ if (m_pending != 0) {
+ m_stack.push_back(m_pending);
+ m_pending = 0;
+ }
+ back()->m_snapshot.save(undoable);
+ }
+ };
+
+ UndoStack m_undo_stack;
+ UndoStack m_redo_stack;
+
+ class UndoStackFiller : public UndoObserver {
+ UndoStack *m_stack;
+ public:
+
+ UndoStackFiller()
+ : m_stack(0)
+ {
+ }
+
+ void save(Undoable *undoable)
+ {
+ ASSERT_NOTNULL(undoable);
+
+ if (m_stack != 0) {
+ m_stack->save(undoable);
+ m_stack = 0;
+ }
+ }
+
+ void setStack(UndoStack *stack)
+ {
+ m_stack = stack;
+ }
+ };
+
+ typedef std::map<Undoable *, UndoStackFiller> undoables_t;
+ undoables_t m_undoables;
+
+ void mark_undoables(UndoStack *stack)
+ {
+ for (undoables_t::iterator i = m_undoables.begin(); i != m_undoables.end(); ++i) {
+ (*i).second.setStack(stack);
+ }
+ }
-class Snapshot
-{
-class StateApplicator
-{
-public:
-Undoable* m_undoable;
-private:
-UndoMemento* m_data;
+ std::size_t m_undo_levels;
+
+ typedef std::set<UndoTracker *> Trackers;
+ Trackers m_trackers;
public:
+ RadiantUndoSystem()
+ : m_undo_levels(64)
+ {
+ }
-StateApplicator( Undoable* undoable, UndoMemento* data )
- : m_undoable( undoable ), m_data( data ){
-}
-void restore(){
- m_undoable->importState( m_data );
-}
-void release(){
- m_data->release();
-}
-};
+ ~RadiantUndoSystem()
+ {
+ clear();
+ }
-typedef std::list<StateApplicator> states_t;
-states_t m_states;
+ UndoObserver *observer(Undoable *undoable)
+ {
+ ASSERT_NOTNULL(undoable);
-public:
-bool empty() const {
- return m_states.empty();
-}
-std::size_t size() const {
- return m_states.size();
-}
-void save( Undoable* undoable ){
- m_states.push_front( StateApplicator( undoable, undoable->exportState() ) );
-}
-void restore(){
- for ( states_t::iterator i = m_states.begin(); i != m_states.end(); ++i )
- {
- ( *i ).restore();
- }
-}
-void release(){
- for ( states_t::iterator i = m_states.begin(); i != m_states.end(); ++i )
- {
- ( *i ).release();
- }
-}
-};
+ return &m_undoables[undoable];
+ }
-struct Operation
-{
- Snapshot m_snapshot;
- CopiedString m_command;
-
- Operation( const char* command )
- : m_command( command ){
- }
- ~Operation(){
- m_snapshot.release();
- }
-};
+ void release(Undoable *undoable)
+ {
+ ASSERT_NOTNULL(undoable);
+ m_undoables.erase(undoable);
+ }
-class UndoStack
-{
-//! Note: using std::list instead of vector/deque, to avoid copying of undos
-typedef std::list<Operation*> Operations;
+ void setLevels(std::size_t levels)
+ {
+ if (levels > MAX_UNDO_LEVELS()) {
+ levels = MAX_UNDO_LEVELS();
+ }
-Operations m_stack;
-Operation* m_pending;
+ while (m_undo_stack.size() > levels) {
+ m_undo_stack.pop_front();
+ }
+ m_undo_levels = levels;
+ }
-public:
-UndoStack() : m_pending( 0 ){
-}
-~UndoStack(){
- clear();
-}
-bool empty() const {
- return m_stack.empty();
-}
-std::size_t size() const {
- return m_stack.size();
-}
-Operation* back(){
- return m_stack.back();
-}
-const Operation* back() const {
- return m_stack.back();
-}
-Operation* front(){
- return m_stack.front();
-}
-const Operation* front() const {
- return m_stack.front();
-}
-void pop_front(){
- delete m_stack.front();
- m_stack.pop_front();
-}
-void pop_back(){
- delete m_stack.back();
- m_stack.pop_back();
-}
-void clear(){
- if ( !m_stack.empty() ) {
- for ( Operations::iterator i = m_stack.begin(); i != m_stack.end(); ++i )
- {
- delete *i;
- }
- m_stack.clear();
- }
-}
-void start( const char* command ){
- if ( m_pending != 0 ) {
- delete m_pending;
- }
- m_pending = new Operation( command );
-}
-bool finish( const char* command ){
- if ( m_pending != 0 ) {
- delete m_pending;
- m_pending = 0;
- return false;
- }
- else
- {
- ASSERT_MESSAGE( !m_stack.empty(), "undo stack empty" );
- m_stack.back()->m_command = command;
- return true;
- }
-}
-void save( Undoable* undoable ){
- if ( m_pending != 0 ) {
- m_stack.push_back( m_pending );
- m_pending = 0;
- }
- back()->m_snapshot.save( undoable );
-}
-};
+ std::size_t getLevels() const
+ {
+ return m_undo_levels;
+ }
-UndoStack m_undo_stack;
-UndoStack m_redo_stack;
+ std::size_t size() const
+ {
+ return m_undo_stack.size();
+ }
-class UndoStackFiller : public UndoObserver
-{
-UndoStack* m_stack;
-public:
+ void startUndo()
+ {
+ m_undo_stack.start("unnamedCommand");
+ mark_undoables(&m_undo_stack);
+ }
-UndoStackFiller()
- : m_stack( 0 ){
-}
-void save( Undoable* undoable ){
- ASSERT_NOTNULL( undoable );
+ bool finishUndo(const char *command)
+ {
+ bool changed = m_undo_stack.finish(command);
+ mark_undoables(0);
+ return changed;
+ }
- if ( m_stack != 0 ) {
- m_stack->save( undoable );
- m_stack = 0;
- }
-}
-void setStack( UndoStack* stack ){
- m_stack = stack;
-}
-};
+ void startRedo()
+ {
+ m_redo_stack.start("unnamedCommand");
+ mark_undoables(&m_redo_stack);
+ }
-typedef std::map<Undoable*, UndoStackFiller> undoables_t;
-undoables_t m_undoables;
+ bool finishRedo(const char *command)
+ {
+ bool changed = m_redo_stack.finish(command);
+ mark_undoables(0);
+ return changed;
+ }
-void mark_undoables( UndoStack* stack ){
- for ( undoables_t::iterator i = m_undoables.begin(); i != m_undoables.end(); ++i )
- {
- ( *i ).second.setStack( stack );
- }
-}
+ void start()
+ {
+ m_redo_stack.clear();
+ if (m_undo_stack.size() == m_undo_levels) {
+ m_undo_stack.pop_front();
+ }
+ startUndo();
+ trackersBegin();
+ }
-std::size_t m_undo_levels;
+ void finish(const char *command)
+ {
+ if (finishUndo(command)) {
+ globalOutputStream() << command << '\n';
+ }
+ }
-typedef std::set<UndoTracker*> Trackers;
-Trackers m_trackers;
-public:
-RadiantUndoSystem()
- : m_undo_levels( 64 ){
-}
-~RadiantUndoSystem(){
- clear();
-}
-UndoObserver* observer( Undoable* undoable ){
- ASSERT_NOTNULL( undoable );
+ void undo()
+ {
+ if (m_undo_stack.empty()) {
+ globalOutputStream() << "Undo: no undo available\n";
+ } else {
+ Operation *operation = m_undo_stack.back();
+ globalOutputStream() << "Undo: " << operation->m_command.c_str() << "\n";
+
+ startRedo();
+ trackersUndo();
+ operation->m_snapshot.restore();
+ finishRedo(operation->m_command.c_str());
+ m_undo_stack.pop_back();
+ }
+ }
- return &m_undoables[undoable];
-}
-void release( Undoable* undoable ){
- ASSERT_NOTNULL( undoable );
+ void redo()
+ {
+ if (m_redo_stack.empty()) {
+ globalOutputStream() << "Redo: no redo available\n";
+ } else {
+ Operation *operation = m_redo_stack.back();
+ globalOutputStream() << "Redo: " << operation->m_command.c_str() << "\n";
+
+ startUndo();
+ trackersRedo();
+ operation->m_snapshot.restore();
+ finishUndo(operation->m_command.c_str());
+ m_redo_stack.pop_back();
+ }
+ }
- m_undoables.erase( undoable );
-}
-void setLevels( std::size_t levels ){
- if ( levels > MAX_UNDO_LEVELS() ) {
- levels = MAX_UNDO_LEVELS();
- }
-
- while ( m_undo_stack.size() > levels )
- {
- m_undo_stack.pop_front();
- }
- m_undo_levels = levels;
-}
-std::size_t getLevels() const {
- return m_undo_levels;
-}
-std::size_t size() const {
- return m_undo_stack.size();
-}
-void startUndo(){
- m_undo_stack.start( "unnamedCommand" );
- mark_undoables( &m_undo_stack );
-}
-bool finishUndo( const char* command ){
- bool changed = m_undo_stack.finish( command );
- mark_undoables( 0 );
- return changed;
-}
-void startRedo(){
- m_redo_stack.start( "unnamedCommand" );
- mark_undoables( &m_redo_stack );
-}
-bool finishRedo( const char* command ){
- bool changed = m_redo_stack.finish( command );
- mark_undoables( 0 );
- return changed;
-}
-void start(){
- m_redo_stack.clear();
- if ( m_undo_stack.size() == m_undo_levels ) {
- m_undo_stack.pop_front();
- }
- startUndo();
- trackersBegin();
-}
-void finish( const char* command ){
- if ( finishUndo( command ) ) {
- globalOutputStream() << command << '\n';
- }
-}
-void undo(){
- if ( m_undo_stack.empty() ) {
- globalOutputStream() << "Undo: no undo available\n";
- }
- else
- {
- Operation* operation = m_undo_stack.back();
- globalOutputStream() << "Undo: " << operation->m_command.c_str() << "\n";
-
- startRedo();
- trackersUndo();
- operation->m_snapshot.restore();
- finishRedo( operation->m_command.c_str() );
- m_undo_stack.pop_back();
- }
-}
-void redo(){
- if ( m_redo_stack.empty() ) {
- globalOutputStream() << "Redo: no redo available\n";
- }
- else
- {
- Operation* operation = m_redo_stack.back();
- globalOutputStream() << "Redo: " << operation->m_command.c_str() << "\n";
-
- startUndo();
- trackersRedo();
- operation->m_snapshot.restore();
- finishUndo( operation->m_command.c_str() );
- m_redo_stack.pop_back();
- }
-}
-void clear(){
- mark_undoables( 0 );
- m_undo_stack.clear();
- m_redo_stack.clear();
- trackersClear();
-}
-void trackerAttach( UndoTracker& tracker ){
- ASSERT_MESSAGE( m_trackers.find( &tracker ) == m_trackers.end(), "undo tracker already attached" );
- m_trackers.insert( &tracker );
-}
-void trackerDetach( UndoTracker& tracker ){
- ASSERT_MESSAGE( m_trackers.find( &tracker ) != m_trackers.end(), "undo tracker cannot be detached" );
- m_trackers.erase( &tracker );
-}
-void trackersClear() const {
- for ( Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i )
- {
- ( *i )->clear();
- }
-}
-void trackersBegin() const {
- for ( Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i )
- {
- ( *i )->begin();
- }
-}
-void trackersUndo() const {
- for ( Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i )
- {
- ( *i )->undo();
- }
-}
-void trackersRedo() const {
- for ( Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i )
- {
- ( *i )->redo();
- }
-}
-};
+ void clear()
+ {
+ mark_undoables(0);
+ m_undo_stack.clear();
+ m_redo_stack.clear();
+ trackersClear();
+ }
+
+ void trackerAttach(UndoTracker &tracker)
+ {
+ ASSERT_MESSAGE(m_trackers.find(&tracker) == m_trackers.end(), "undo tracker already attached");
+ m_trackers.insert(&tracker);
+ }
+
+ void trackerDetach(UndoTracker &tracker)
+ {
+ ASSERT_MESSAGE(m_trackers.find(&tracker) != m_trackers.end(), "undo tracker cannot be detached");
+ m_trackers.erase(&tracker);
+ }
+ void trackersClear() const
+ {
+ for (Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i) {
+ (*i)->clear();
+ }
+ }
+
+ void trackersBegin() const
+ {
+ for (Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i) {
+ (*i)->begin();
+ }
+ }
+
+ void trackersUndo() const
+ {
+ for (Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i) {
+ (*i)->undo();
+ }
+ }
+
+ void trackersRedo() const
+ {
+ for (Trackers::const_iterator i = m_trackers.begin(); i != m_trackers.end(); ++i) {
+ (*i)->redo();
+ }
+ }
+};
-void UndoLevels_importString( RadiantUndoSystem& undo, const char* value ){
- int levels;
- PropertyImpl<int, const char *>::Import( levels, value );
- undo.setLevels( levels );
+void UndoLevels_importString(RadiantUndoSystem &undo, const char *value)
+{
+ int levels;
+ PropertyImpl<int, const char *>::Import(levels, value);
+ undo.setLevels(levels);
}
-typedef ReferenceCaller<RadiantUndoSystem, void(const char*), UndoLevels_importString> UndoLevelsImportStringCaller;
-void UndoLevels_exportString( const RadiantUndoSystem& undo, const Callback<void(const char *)> & importer ){
- PropertyImpl<int, const char *>::Export( static_cast<int>( undo.getLevels() ), importer );
+
+typedef ReferenceCaller<RadiantUndoSystem, void(const char *), UndoLevels_importString> UndoLevelsImportStringCaller;
+
+void UndoLevels_exportString(const RadiantUndoSystem &undo, const Callback<void(const char *)> &importer)
+{
+ PropertyImpl<int, const char *>::Export(static_cast<int>( undo.getLevels()), importer);
}
-typedef ConstReferenceCaller<RadiantUndoSystem, void(const Callback<void(const char *)> &), UndoLevels_exportString> UndoLevelsExportStringCaller;
+
+typedef ConstReferenceCaller<RadiantUndoSystem, void(
+ const Callback<void(const char *)> &), UndoLevels_exportString> UndoLevelsExportStringCaller;
#include "generic/callback.h"
struct UndoLevels {
- static void Export(const RadiantUndoSystem &self, const Callback<void(int)> &returnz) {
+ static void Export(const RadiantUndoSystem &self, const Callback<void(int)> &returnz)
+ {
returnz(static_cast<int>(self.getLevels()));
}
- static void Import(RadiantUndoSystem &self, int value) {
+ static void Import(RadiantUndoSystem &self, int value)
+ {
self.setLevels(value);
}
};
-void Undo_constructPreferences( RadiantUndoSystem& undo, PreferencesPage& page ){
+void Undo_constructPreferences(RadiantUndoSystem &undo, PreferencesPage &page)
+{
page.appendSpinner("Undo Queue Size", 64, 0, 1024, make_property<UndoLevels>(undo));
}
-void Undo_constructPage( RadiantUndoSystem& undo, PreferenceGroup& group ){
- PreferencesPage page( group.createPage( "Undo", "Undo Queue Settings" ) );
- Undo_constructPreferences( undo, page );
-}
-void Undo_registerPreferencesPage( RadiantUndoSystem& undo ){
- PreferencesDialog_addSettingsPage( ReferenceCaller<RadiantUndoSystem, void(PreferenceGroup&), Undo_constructPage>( undo ) );
+
+void Undo_constructPage(RadiantUndoSystem &undo, PreferenceGroup &group)
+{
+ PreferencesPage page(group.createPage("Undo", "Undo Queue Settings"));
+ Undo_constructPreferences(undo, page);
}
-class UndoSystemDependencies : public GlobalPreferenceSystemModuleRef
+void Undo_registerPreferencesPage(RadiantUndoSystem &undo)
{
+ PreferencesDialog_addSettingsPage(
+ ReferenceCaller<RadiantUndoSystem, void(PreferenceGroup &), Undo_constructPage>(undo));
+}
+
+class UndoSystemDependencies : public GlobalPreferenceSystemModuleRef {
};
-class UndoSystemAPI
-{
-RadiantUndoSystem m_undosystem;
+class UndoSystemAPI {
+ RadiantUndoSystem m_undosystem;
public:
-typedef UndoSystem Type;
-STRING_CONSTANT( Name, "*" );
+ typedef UndoSystem Type;
-UndoSystemAPI(){
- GlobalPreferenceSystem().registerPreference("UndoLevels", make_property_string<UndoLevels>(m_undosystem));
+ STRING_CONSTANT(Name, "*");
- Undo_registerPreferencesPage( m_undosystem );
-}
-UndoSystem* getTable(){
- return &m_undosystem;
-}
+ UndoSystemAPI()
+ {
+ GlobalPreferenceSystem().registerPreference("UndoLevels", make_property_string<UndoLevels>(m_undosystem));
+
+ Undo_registerPreferencesPage(m_undosystem);
+ }
+
+ UndoSystem *getTable()
+ {
+ return &m_undosystem;
+ }
};
#include "modulesystem/singletonmodule.h"
typedef SingletonModule<UndoSystemAPI, UndoSystemDependencies> UndoSystemModule;
typedef Static<UndoSystemModule> StaticUndoSystemModule;
-StaticRegisterModule staticRegisterUndoSystem( StaticUndoSystemModule::instance() );
+StaticRegisterModule staticRegisterUndoSystem(StaticUndoSystemModule::instance());
+class undoable_test : public Undoable {
+ struct state_type : public UndoMemento {
+ state_type() : test_data(0)
+ {
+ }
+ state_type(const state_type &other) : UndoMemento(other), test_data(other.test_data)
+ {
+ }
+ void release()
+ {
+ delete this;
+ }
+ int test_data;
+ };
+ state_type m_state;
+ UndoObserver *m_observer;
+public:
+ undoable_test()
+ : m_observer(GlobalUndoSystem().observer(this))
+ {
+ }
+ ~undoable_test()
+ {
+ GlobalUndoSystem().release(this);
+ }
+ UndoMemento *exportState() const
+ {
+ return new state_type(m_state);
+ }
+ void importState(const UndoMemento *state)
+ {
+ ASSERT_NOTNULL(state);
-class undoable_test : public Undoable
-{
-struct state_type : public UndoMemento
-{
- state_type() : test_data( 0 ){
- }
- state_type( const state_type& other ) : UndoMemento( other ), test_data( other.test_data ){
- }
- void release(){
- delete this;
- }
-
- int test_data;
-};
-state_type m_state;
-UndoObserver* m_observer;
-public:
-undoable_test()
- : m_observer( GlobalUndoSystem().observer( this ) ){
-}
-~undoable_test(){
- GlobalUndoSystem().release( this );
-}
-UndoMemento* exportState() const {
- return new state_type( m_state );
-}
-void importState( const UndoMemento* state ){
- ASSERT_NOTNULL( state );
-
- m_observer->save( this );
- m_state = *( static_cast<const state_type*>( state ) );
-}
+ m_observer->save(this);
+ m_state = *(static_cast<const state_type *>( state ));
+ }
-void mutate( unsigned int data ){
- m_observer->save( this );
- m_state.test_data = data;
-}
+ void mutate(unsigned int data)
+ {
+ m_observer->save(this);
+ m_state.test_data = data;
+ }
};
#if 0
{
public:
TestUndo(){
- undoable_test test;
- GlobalUndoSystem().begin( "bleh" );
- test.mutate( 3 );
- GlobalUndoSystem().begin( "blah" );
- test.mutate( 4 );
- GlobalUndoSystem().undo();
- GlobalUndoSystem().undo();
- GlobalUndoSystem().redo();
- GlobalUndoSystem().redo();
+ undoable_test test;
+ GlobalUndoSystem().begin( "bleh" );
+ test.mutate( 3 );
+ GlobalUndoSystem().begin( "blah" );
+ test.mutate( 4 );
+ GlobalUndoSystem().undo();
+ GlobalUndoSystem().undo();
+ GlobalUndoSystem().redo();
+ GlobalUndoSystem().redo();
}
};