Added undo and redo support for script changes in the inspector
This commit is contained in:
parent
1477aaaead
commit
f717b61c88
|
@ -5,9 +5,13 @@
|
|||
//#==============================================================#
|
||||
#include <functional>
|
||||
|
||||
#include "SH_API.h"
|
||||
#include "Scripting/SHScriptEngine.h"
|
||||
#include "ECS_Base/Managers/SHSystemManager.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHBaseCommand
|
||||
class SH_API SHBaseCommand
|
||||
{
|
||||
public:
|
||||
virtual ~SHBaseCommand() = default;
|
||||
|
@ -48,4 +52,20 @@ namespace SHADE
|
|||
T newValue;
|
||||
SetterFunction set;
|
||||
};
|
||||
|
||||
class SH_API SHCLICommand : SHBaseCommand
|
||||
{
|
||||
public:
|
||||
SHCLICommand() = default;
|
||||
void Execute() override
|
||||
{
|
||||
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
|
||||
scriptEngine->RedoScriptInspectorChanges();
|
||||
}
|
||||
void Undo() override
|
||||
{
|
||||
SHScriptEngine* scriptEngine = static_cast<SHScriptEngine*>(SHSystemManager::GetSystem<SHScriptEngine>());
|
||||
scriptEngine->UndoScriptInspectorChanges();
|
||||
}
|
||||
};
|
||||
}//namespace SHADE
|
||||
|
|
|
@ -27,6 +27,11 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
|
||||
{
|
||||
undoStack.push(commandPtr);
|
||||
}
|
||||
|
||||
void SHCommandManager::UndoCommand()
|
||||
{
|
||||
if (undoStack.empty())
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
//|| SHADE Includes ||
|
||||
//#==============================================================#
|
||||
#include "SHCommand.hpp"
|
||||
#include "SH_API.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
class SHCommandManager
|
||||
class SH_API SHCommandManager
|
||||
{
|
||||
public:
|
||||
//#==============================================================#
|
||||
|
@ -22,6 +23,7 @@ namespace SHADE
|
|||
using CommandStack = std::stack<CommandPtr>;
|
||||
|
||||
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
|
||||
static void RegisterCommand(CommandPtr commandPtr);
|
||||
static void UndoCommand();
|
||||
static void RedoCommand();
|
||||
static std::size_t GetUndoStackSize();
|
||||
|
|
|
@ -153,6 +153,16 @@ namespace SHADE
|
|||
csEditorRenderScripts(entity);
|
||||
}
|
||||
|
||||
void SHScriptEngine::UndoScriptInspectorChanges() const
|
||||
{
|
||||
csEditorUndo();
|
||||
}
|
||||
|
||||
void SHScriptEngine::RedoScriptInspectorChanges() const
|
||||
{
|
||||
csEditorRedo();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Static Utility Functions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -400,6 +410,18 @@ namespace SHADE
|
|||
DEFAULT_CSHARP_NAMESPACE + ".Editor",
|
||||
"RenderScriptsInInspector"
|
||||
);
|
||||
csEditorUndo = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".Editor",
|
||||
"Undo"
|
||||
);
|
||||
csEditorRedo = dotNet.GetFunctionPtr<CsFuncPtr>
|
||||
(
|
||||
DEFAULT_CSHARP_LIB_NAME,
|
||||
DEFAULT_CSHARP_NAMESPACE + ".Editor",
|
||||
"Redo"
|
||||
);
|
||||
}
|
||||
|
||||
void SHScriptEngine::registerEvents()
|
||||
|
|
|
@ -171,6 +171,14 @@ namespace SHADE
|
|||
/// </summary>
|
||||
/// <param name="entity">The Entity to render the Scripts of.</param>
|
||||
void RenderScriptsInInspector(EntityID entity) const;
|
||||
/// <summary>
|
||||
/// Performs an undo for script inspector changes if it exists.
|
||||
/// </summary>
|
||||
void UndoScriptInspectorChanges() const;
|
||||
/// <summary>
|
||||
/// Performs a redo for script inspector changes if it exists.
|
||||
/// </summary>
|
||||
void RedoScriptInspectorChanges() const;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Static Utility Functions */
|
||||
|
@ -243,9 +251,8 @@ namespace SHADE
|
|||
CsScriptSerialiseYamlFuncPtr csScriptDeserialiseYaml = nullptr;
|
||||
// - Editor
|
||||
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
|
||||
// Delegates
|
||||
/*ECS::EntityEvent::Delegate onEntityCreate;
|
||||
ECS::EntityEvent::Delegate onEntityDestroy;*/
|
||||
CsFuncPtr csEditorUndo = nullptr;
|
||||
CsFuncPtr csEditorRedo = nullptr;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Event Handler Functions */
|
||||
|
|
|
@ -31,6 +31,7 @@ project "SHADE_Managed"
|
|||
"%{IncludeDir.imnodes}",
|
||||
"%{IncludeDir.yamlcpp}",
|
||||
"%{IncludeDir.RTTR}/include",
|
||||
"%{IncludeDir.dotnet}\\include",
|
||||
"%{wks.location}/SHADE_Engine/src"
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "SHpch.h"
|
||||
// Primary Header
|
||||
#include "Editor/Editor.hxx"
|
||||
// STL Includes
|
||||
#include <memory>
|
||||
// External Dependencies
|
||||
#include "Editor/SHEditorUI.h"
|
||||
// Project Headers
|
||||
|
@ -25,6 +27,8 @@ of DigiPen Institute of Technology is prohibited.
|
|||
#include "Utility/Debug.hxx"
|
||||
#include "Serialisation/ReflectionUtilities.hxx"
|
||||
#include "Editor/IconsMaterialDesign.h"
|
||||
#include "Editor/Command/SHCommandManager.h"
|
||||
#include "Editor/Command/SHCommand.hpp"
|
||||
|
||||
// Using Directives
|
||||
using namespace System;
|
||||
|
@ -48,9 +52,11 @@ using namespace System::Collections::Generic;
|
|||
(field->FieldType == MANAGED_TYPE::typeid) \
|
||||
{ \
|
||||
NATIVE_TYPE val = safe_cast<NATIVE_TYPE>(field->GetValue(object)); \
|
||||
NATIVE_TYPE oldVal = val; \
|
||||
if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \
|
||||
{ \
|
||||
field->SetValue(object, val); \
|
||||
registerUndoAction(object, field, val, oldVal); \
|
||||
} \
|
||||
} \
|
||||
/// <summary>
|
||||
|
@ -69,9 +75,11 @@ using namespace System::Collections::Generic;
|
|||
(field->FieldType == MANAGED_TYPE::typeid) \
|
||||
{ \
|
||||
NATIVE_TYPE val = Convert::ToNative(safe_cast<MANAGED_TYPE>(field->GetValue(object))); \
|
||||
NATIVE_TYPE oldVal = val; \
|
||||
if (SHEditorUI::FUNC(Convert::ToNative(field->Name), val)) \
|
||||
{ \
|
||||
field->SetValue(object, Convert::ToCLI(val)); \
|
||||
registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal)); \
|
||||
} \
|
||||
} \
|
||||
|
||||
|
@ -126,6 +134,23 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* UndoRedoStack Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void Editor::Undo()
|
||||
{
|
||||
SAFE_NATIVE_CALL_BEGIN
|
||||
actionStack.Undo();
|
||||
SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Undo")
|
||||
}
|
||||
|
||||
void Editor::Redo()
|
||||
{
|
||||
SAFE_NATIVE_CALL_BEGIN
|
||||
actionStack.Redo();
|
||||
SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.Redo")
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
@ -192,9 +217,11 @@ namespace SHADE
|
|||
}
|
||||
|
||||
int val = safe_cast<int>(field->GetValue(object));
|
||||
int oldVal = val;
|
||||
if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames))
|
||||
{
|
||||
field->SetValue(object, val);
|
||||
registerUndoAction(object, field, val, oldVal);
|
||||
}
|
||||
}
|
||||
else if RENDER_FIELD_CASTED(Vector2, SHVec2, InputVec2)
|
||||
|
@ -210,9 +237,11 @@ namespace SHADE
|
|||
|
||||
// Actual Field
|
||||
std::string val = Convert::ToNative(stringVal);
|
||||
std::string oldVal = val;
|
||||
if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val))
|
||||
{
|
||||
field->SetValue(object, Convert::ToCLI(val));
|
||||
registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -231,4 +260,18 @@ namespace SHADE
|
|||
}
|
||||
}
|
||||
|
||||
void Editor::registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData)
|
||||
{
|
||||
// Create command and add it into the undo stack
|
||||
UndoRedoStack::Command cmd;
|
||||
cmd.Field = field;
|
||||
cmd.Object = object;
|
||||
cmd.NewData = newData;
|
||||
cmd.OldData = oldData;
|
||||
actionStack.Add(cmd);
|
||||
|
||||
// Inform the C++ Undo-Redo stack
|
||||
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
|
|||
// Project Includes
|
||||
#include "Engine/Entity.hxx"
|
||||
#include "Scripts/Script.hxx"
|
||||
#include "UndoRedoStack.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -44,7 +45,18 @@ namespace SHADE
|
|||
/// <param name="entity">The Entity to add PlushieScripts to.</param>
|
||||
static void RenderScriptAddButton(Entity entity);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* UndoRedoStack Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static void Undo();
|
||||
static void Redo();
|
||||
|
||||
private:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
static UndoRedoStack actionStack;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
|
@ -73,5 +85,6 @@ namespace SHADE
|
|||
/// <param name="entity">The Entity to render the Scripts of.</param>
|
||||
/// <param name="script">The Script to render the inspector for.</param>
|
||||
static void renderScriptContextMenu(Entity entity, Script^ script);
|
||||
static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,28 +22,48 @@ of DigiPen Institute of Technology is prohibited.
|
|||
|
||||
namespace SHADE
|
||||
{
|
||||
bool UndoRedoStack::UndoActionPresent::get()
|
||||
{
|
||||
return commandStack->Count > 0 && latestActionIndex >= 0;
|
||||
}
|
||||
|
||||
bool UndoRedoStack::RedoActionPresent::get()
|
||||
{
|
||||
return latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1;
|
||||
}
|
||||
|
||||
void UndoRedoStack::Add(Command command)
|
||||
{
|
||||
// Erase any other actions ahead of the current action
|
||||
if (latestActionIndex < commandStack->Count - 1)
|
||||
if (latestActionIndex >= 0 && latestActionIndex < commandStack->Count - 1)
|
||||
{
|
||||
commandStack->RemoveRange(latestActionIndex + 1, commandStack->Count - latestActionIndex);
|
||||
commandStack->RemoveRange(latestActionIndex, commandStack->Count - latestActionIndex);
|
||||
}
|
||||
|
||||
// Add the command
|
||||
commandStack->Add(command);
|
||||
|
||||
// Increment latest command
|
||||
++latestActionIndex;
|
||||
// Set the latest command
|
||||
latestActionIndex = commandStack->Count - 1;
|
||||
}
|
||||
|
||||
void UndoRedoStack::Undo()
|
||||
{
|
||||
if (!UndoActionPresent)
|
||||
return;
|
||||
|
||||
Command cmd = commandStack[latestActionIndex];
|
||||
cmd.Field->SetValue(cmd.Object, cmd.OldData);
|
||||
--latestActionIndex;
|
||||
}
|
||||
|
||||
void UndoRedoStack::Redo()
|
||||
{
|
||||
if (!RedoActionPresent)
|
||||
return;
|
||||
|
||||
Command cmd = commandStack[latestActionIndex];
|
||||
cmd.Field->SetValue(cmd.Object, cmd.NewData);
|
||||
++latestActionIndex;
|
||||
}
|
||||
}
|
|
@ -24,18 +24,45 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Command for the stack that represents a data modification.
|
||||
/// </summary>
|
||||
value struct Command
|
||||
{
|
||||
public:
|
||||
System::Action^ UndoAction;
|
||||
System::Action^ RedoAction;
|
||||
System::Object^ Object;
|
||||
System::Reflection::FieldInfo^ Field;
|
||||
System::Object^ NewData;
|
||||
System::Object^ OldData;
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Properties */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// True if there is an undoable action in the stack.
|
||||
/// </summary>
|
||||
property bool UndoActionPresent { bool get(); }
|
||||
/// <summary>
|
||||
/// True if there is a redoable action in the stack.
|
||||
/// </summary>
|
||||
property bool RedoActionPresent { bool get(); }
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Usage Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Adds a command onto the stack.
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
void Add(Command command);
|
||||
/// <summary>
|
||||
/// Undos the last added command if it exists.
|
||||
/// </summary>
|
||||
void Undo();
|
||||
/// <summary>
|
||||
/// Redoes the last undo-ed command if it exists.
|
||||
/// </summary>
|
||||
void Redo();
|
||||
|
||||
private:
|
||||
|
|
Loading…
Reference in New Issue