Merge pull request #79 from SHADE-DP/SP3-6-c-scripting

Added Undo-Redo support for Script Inspectors
This commit is contained in:
XiaoQiDigipen 2022-10-02 02:47:47 +08:00 committed by GitHub
commit 39302bc7f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 290 additions and 33 deletions

View File

@ -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

View File

@ -27,6 +27,11 @@ namespace SHADE
}
}
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
{
undoStack.push(commandPtr);
}
void SHCommandManager::UndoCommand()
{
if (undoStack.empty())

View File

@ -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();

View File

@ -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()

View File

@ -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 */

View File

@ -31,6 +31,7 @@ project "SHADE_Managed"
"%{IncludeDir.imnodes}",
"%{IncludeDir.yamlcpp}",
"%{IncludeDir.RTTR}/include",
"%{IncludeDir.dotnet}\\include",
"%{wks.location}/SHADE_Engine/src"
}

View File

@ -3,7 +3,7 @@
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 27, 2022
\brief Contains the definition of the functions for the ScriptStore managed
\brief Contains the definition of the functions for the Editor managed
static class.
Note: This file is written in C++17/CLI.
@ -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)); \
} \
} \
@ -105,26 +113,43 @@ namespace SHADE
SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector")
}
void Editor::RenderScriptAddButton(Entity entity)
{
// Get list of Scripts
auto scriptTypes = ScriptStore::GetAvailableScriptList();
void Editor::RenderScriptAddButton(Entity entity)
{
// Get list of Scripts
auto scriptTypes = ScriptStore::GetAvailableScriptList();
// Define pop up
if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD))
{
for each (Type ^ type in scriptTypes)
{
if (SHEditorUI::Selectable(Convert::ToNative(type->Name)))
{
// Add the script
ScriptStore::AddScriptViaName(entity, type->Name);
}
}
// Define pop up
if (SHEditorUI::BeginMenu("Add Script", ICON_MD_LIBRARY_ADD))
{
for each (Type ^ type in scriptTypes)
{
if (SHEditorUI::Selectable(Convert::ToNative(type->Name)))
{
// Add the script
ScriptStore::AddScriptViaName(entity, type->Name);
}
}
SHEditorUI::EndMenu();
}
}
SHEditorUI::EndMenu();
}
}
/*---------------------------------------------------------------------------------*/
/* 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>()));
}
}

View File

@ -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
{
@ -36,15 +37,26 @@ namespace SHADE
/// rendering code.
/// </summary>
/// <param name="entity">The Entity to render the Scripts of.</param>
static void RenderScriptsInInspector(Entity entity);
/// <summary>
/// Renders a dropdown button that allows for the addition of PlushieScripts
/// onto the specified Entity.
/// </summary>
/// <param name="entity">The Entity to add PlushieScripts to.</param>
static void RenderScriptAddButton(Entity entity);
static void RenderScriptsInInspector(Entity entity);
/// <summary>
/// Renders a dropdown button that allows for the addition of PlushieScripts
/// onto the specified Entity.
/// </summary>
/// <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;
private:
/*-----------------------------------------------------------------------------*/
/* 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);
};
}

View File

@ -0,0 +1,69 @@
/************************************************************************************//*!
\file UndoRedoStack.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 29, 2022
\brief Contains the definition of the functions for the UndoRedoStack managed
class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "UndoRedoStack.hxx"
// External Dependencies
#include "Editor/SHEditorUI.h"
// Project Headers
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 >= 0 && latestActionIndex < commandStack->Count - 1)
{
commandStack->RemoveRange(latestActionIndex, commandStack->Count - latestActionIndex);
}
// Add the command
commandStack->Add(command);
// 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;
}
}

View File

@ -0,0 +1,75 @@
/************************************************************************************//*!
\file UndoRedoStack.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Sep 29, 2022
\brief Contains the definition of the managed UndoRedoStack class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
namespace SHADE
{
/// <summary>
/// Class that is able to store a stack of actions that can be done and redone.
/// </summary>
private ref class UndoRedoStack sealed
{
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Command for the stack that represents a data modification.
/// </summary>
value struct Command
{
public:
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:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
int latestActionIndex = -1;
System::Collections::Generic::List<Command>^ commandStack = gcnew System::Collections::Generic::List<Command>();
};
}