Torque3D/Engine/source/util/undo.h
marauder2k7 efbe5e90f5 virtuals removed
virtuals removed and replaced with override where necessary, clang-tidy to the rescue.
2024-03-18 18:13:00 +00:00

252 lines
7.2 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#ifndef _UNDO_H_
#define _UNDO_H_
#ifndef _SIMOBJECT_H_
#include "console/simObject.h"
#endif
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _ENGINEAPI_H_
#include "console/engineAPI.h"
#endif
class UndoManager;
///
class UndoAction : public SimObject
{
friend class UndoManager;
protected:
// The manager this was added to.
UndoManager* mUndoManager;
public:
/// A brief description of the action, for display in menus and the like.
// not private because we're exposing it to the console.
String mActionName;
// Required in all ConsoleObject subclasses.
typedef SimObject Parent;
DECLARE_CONOBJECT(UndoAction);
static void initPersistFields();
/// Create a new action, assigning it a name for display in menus et cetera.
UndoAction(const UTF8 *actionName = " ");
virtual ~UndoAction();
/// Implement these methods to perform your specific undo & redo tasks.
virtual void undo() { };
virtual void redo() { };
/// Adds the action to the undo stack of the default UndoManager, or the provided manager.
void addToManager(UndoManager* theMan = NULL);
};
/// An undo action that is comprised of other undo actions.
class CompoundUndoAction : public UndoAction
{
friend class UndoManager;
protected:
Vector< UndoAction* > mChildren;
public:
typedef UndoAction Parent;
CompoundUndoAction( const UTF8 *actionName = " " );
virtual ~CompoundUndoAction();
DECLARE_CONOBJECT(CompoundUndoAction);
virtual void addAction( UndoAction *action );
void undo() override;
void redo() override;
void onDeleteNotify( SimObject* object ) override;
U32 getNumChildren() const { return mChildren.size(); }
};
///
class UndoManager : public SimObject
{
private:
/// Default number of undo & redo levels.
const static U32 kDefaultNumLevels = 100;
/// The stacks of undo & redo actions. They will be capped at size mNumLevels.
Vector<UndoAction*> mUndoStack;
Vector<UndoAction*> mRedoStack;
/// Stack for assembling compound actions.
Vector< CompoundUndoAction* > mCompoundStack;
/// Deletes all the UndoActions in a stack, then clears it.
void clearStack(Vector<UndoAction*> &stack);
/// Clamps a Vector to mNumLevels entries.
void clampStack(Vector<UndoAction*> &stack);
/// Run the removal logic on the action.
void doRemove( UndoAction* action, bool noDelete );
public:
/// Number of undo & redo levels.
// not private because we're exposing it to the console.
U32 mNumLevels;
// Required in all ConsoleObject subclasses.
typedef SimObject Parent;
DECLARE_CONOBJECT(UndoManager);
static void initPersistFields();
/// Constructor. If levels = 0, we use the default number of undo levels.
UndoManager(U32 levels = kDefaultNumLevels);
/// Destructor. deletes and clears the undo & redo stacks.
~UndoManager();
/// Accessor to the default undo manager singleton. Creates one if needed.
static UndoManager& getDefaultManager();
/// Undo last action, and put it on the redo stack.
void undo();
/// Redo the last action, and put it on the undo stack.
void redo();
/// Clears the undo and redo stacks.
void clearAll();
/// Returns the printable name of the top actions on the undo & redo stacks.
const char* getNextUndoName();
const char* getNextRedoName();
S32 getUndoCount();
S32 getRedoCount();
const char* getUndoName(S32 index);
const char* getRedoName(S32 index);
UndoAction* getUndoAction(S32 index);
UndoAction* getRedoAction(S32 index);
/// Add an action to the top of the undo stack, and clear the redo stack.
void addAction(UndoAction* action);
void removeAction(UndoAction* action, bool noDelete = false);
/// @name Compound Actions
///
/// The compound action stack allows to redirect undos to a CompoundUndoAction
/// and thus assemble multi-operation undos directly through the UndoManager.
/// When the bottom-most CompoundUndoAction is popped off the stack, the compound
/// will be moved onto the undo stack.
///
/// @{
/// Push a compound action called "name" onto the compound stack. While the
/// compound stack is not empty, all undos that are queued on the undo manager will
/// go to the topmost compound instead of the undo stack.
CompoundUndoAction* pushCompound( const String& name );
/// Pop the topmost compound off the compound stack and add it to the undo manager.
/// If the compound stack is still not empty, the compound will be added to the next
/// lower compound on the stack. Otherwise it will be recorded as a regular undo.
void popCompound( bool discard = false );
/// Return the current nesting depth of the compound stack.
U32 getCompoundStackDepth() const { return mCompoundStack.size(); }
/// @}
};
/// Script Undo Action Creation
///
/// Undo actions can be created in script like this:
///
/// ...
/// %undo = new UndoScriptAction() { class = SampleUndo; actionName = "Sample Undo"; };
/// %undo.addToManager(UndoManager);
/// ...
///
/// function SampleUndo::undo()
/// {
/// ...
/// }
///
/// function SampleUndo::redo()
/// {
/// ...
/// }
///
class UndoScriptAction : public UndoAction
{
public:
typedef UndoAction Parent;
UndoScriptAction() : UndoAction()
{
}
void undo() override { Con::executef(this, "undo"); };
void redo() override { Con::executef(this, "redo"); }
bool onAdd() override
{
// Let Parent Do Work.
if(!Parent::onAdd())
return false;
// Notify Script.
if(isMethod("onAdd"))
Con::executef(this, "onAdd");
// Return Success.
return true;
};
void onRemove() override
{
if (mUndoManager)
mUndoManager->removeAction((UndoAction*)this, true);
// notify script
if(isMethod("onRemove"))
Con::executef(this, "onRemove");
Parent::onRemove();
}
DECLARE_CONOBJECT(UndoScriptAction);
};
#endif // _UNDO_H_