Fixed lists undo not working
This commit is contained in:
parent
2d2cc532a5
commit
543c199b03
|
@ -180,6 +180,7 @@ namespace SHADE
|
|||
|
||||
SHEditorUI::Text(Convert::ToNative(field->Name));
|
||||
SHEditorUI::SameLine();
|
||||
|
||||
SHEditorUI::Button("+");
|
||||
|
||||
SHEditorUI::Indent();
|
||||
|
@ -187,9 +188,11 @@ namespace SHADE
|
|||
{
|
||||
SHEditorUI::PushID(i);
|
||||
System::Object^ obj = iList[i];
|
||||
System::Object^ oldObj = iList[i];
|
||||
if (renderFieldEditor(std::to_string(i), obj, rangeAttrib))
|
||||
{
|
||||
iList[i] = obj;
|
||||
registerUndoListChangeAction(listType, iList, i, obj, oldObj);
|
||||
}
|
||||
SHEditorUI::SameLine();
|
||||
SHEditorUI::Button("-");
|
||||
|
@ -281,24 +284,26 @@ namespace SHADE
|
|||
|
||||
bool Editor::renderFieldEditor(const std::string& fieldName, System::Object^% object, RangeAttribute^ rangeAttrib)
|
||||
{
|
||||
const bool MODIFIED_PRIMITIVE =
|
||||
renderFieldEditor<int , Int16 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , Int32 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , Int64 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , UInt16 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , UInt32 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , UInt64 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , Byte >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<bool , bool >(fieldName, object, SHEditorUI::InputCheckbox, nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<float , float >(fieldName, object, SHEditorUI::InputFloat , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<double , double >(fieldName, object, SHEditorUI::InputDouble , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<SHVec2 , Vector2 >(fieldName, object, SHEditorUI::InputVec2 , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<SHVec3 , Vector3 >(fieldName, object, SHEditorUI::InputVec3 , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<uint32_t , GameObject >(fieldName, object, nullptr , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<std::string, System::String^>(fieldName, object, nullptr , nullptr, rangeAttrib) ||
|
||||
renderFieldEditor<int , System::Enum >(fieldName, object, nullptr , nullptr, rangeAttrib);
|
||||
bool modified;
|
||||
|
||||
return MODIFIED_PRIMITIVE;
|
||||
const bool RENDERED =
|
||||
renderFieldEditor<int , Int16 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , Int32 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , Int64 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , UInt16 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , UInt32 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , UInt64 >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , Byte >(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<bool , bool >(fieldName, object, SHEditorUI::InputCheckbox, nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<float , float >(fieldName, object, SHEditorUI::InputFloat , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<double , double >(fieldName, object, SHEditorUI::InputDouble , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<SHVec2 , Vector2 >(fieldName, object, SHEditorUI::InputVec2 , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<SHVec3 , Vector3 >(fieldName, object, SHEditorUI::InputVec3 , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<uint32_t , GameObject >(fieldName, object, nullptr , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<std::string, System::String^>(fieldName, object, nullptr , nullptr, rangeAttrib, modified) ||
|
||||
renderFieldEditor<int , System::Enum >(fieldName, object, nullptr , nullptr, rangeAttrib, modified);
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool Editor::renderEnumEditor(const std::string& fieldName, System::Object^% object, bool* isHovered)
|
||||
|
@ -345,6 +350,33 @@ namespace SHADE
|
|||
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
|
||||
}
|
||||
|
||||
void Editor::registerUndoListChangeAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData)
|
||||
{
|
||||
if (list == nullptr)
|
||||
return;
|
||||
|
||||
actionStack.Add(gcnew ListElementChangeCommand(list, index, newData, oldData));
|
||||
|
||||
// Inform the C++ Undo-Redo stack
|
||||
SHCommandManager::RegisterCommand(std::reinterpret_pointer_cast<SHBaseCommand>(std::make_shared<SHCLICommand>()));
|
||||
}
|
||||
|
||||
void Editor::registerUndoListAddAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data)
|
||||
{
|
||||
if (list == nullptr)
|
||||
return;
|
||||
|
||||
actionStack.Add(gcnew ListElementAddCommand(list, index, data));
|
||||
}
|
||||
|
||||
void Editor::registerUndoListRemoveAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data)
|
||||
{
|
||||
if (list == nullptr)
|
||||
return;
|
||||
|
||||
actionStack.Add(gcnew ListElementRemoveCommand(list, index, data));
|
||||
}
|
||||
|
||||
generic<typename Attribute>
|
||||
Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field)
|
||||
{
|
||||
|
|
|
@ -80,13 +80,15 @@ namespace SHADE
|
|||
}
|
||||
|
||||
template<typename NativeType, typename ManagedType>
|
||||
bool Editor::renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib)
|
||||
bool Editor::renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib, bool& modified)
|
||||
{
|
||||
modified = false;
|
||||
|
||||
if constexpr (std::is_same_v<ManagedType, System::Enum>)
|
||||
{
|
||||
if (object->GetType()->IsSubclassOf(Enum::typeid))
|
||||
{
|
||||
renderEnumEditor(fieldName, object, isHovered);
|
||||
modified = renderEnumEditor(fieldName, object, isHovered);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +101,7 @@ namespace SHADE
|
|||
if (renderFieldEditorInternal<NativeType, ManagedType>(fieldName, managedValPtr, fieldEditor, isHovered, rangeAttrib))
|
||||
{
|
||||
object = managedVal;
|
||||
modified = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -90,7 +90,49 @@ namespace SHADE
|
|||
/// The object that contains the data of the field to render.
|
||||
/// </param>
|
||||
static void renderFieldInInspector(System::Reflection::FieldInfo^ field, System::Object^ object);
|
||||
/// <summary>
|
||||
/// Renders a raw editor for a single value.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to render.</param>
|
||||
/// <param name="object">Tracking reference to the object to modify.</param>
|
||||
/// <param name="rangeAttrib">
|
||||
/// If specified, will be used to constrain values.
|
||||
/// </param>
|
||||
/// <returns>True if the value was modified.</returns>
|
||||
static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, RangeAttribute^ rangeAttrib);
|
||||
/// <summary>
|
||||
/// Renders a ImGui field editor based on the type of parameters specified if the
|
||||
/// type matches.
|
||||
/// </summary>
|
||||
/// <typeparam name="NativeType">Native type of the field.</typeparam>
|
||||
/// <typeparam name="ManagedType">Managed type of the field.</typeparam>
|
||||
/// <param name="fieldName">Label to use for the field editor.</param>
|
||||
/// <param name="managedVal">
|
||||
/// Tracking reference for the managed variable to modify.
|
||||
/// </param>
|
||||
/// <param name="fieldEditor">ImGui field editor function to use.</param>
|
||||
/// <param name="isHovered">
|
||||
/// Pointer to a bool that stores if the field editor was hovered over.
|
||||
/// </param>
|
||||
/// <param name="rangeAttrib">
|
||||
/// If provided and the type supports it, the field will be rendered with a
|
||||
/// slider instead.
|
||||
/// </param>
|
||||
/// <param name="modified"></param>
|
||||
/// <returns>True if the field was rendered..</returns>
|
||||
template<typename NativeType, typename ManagedType>
|
||||
static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib, bool& modified);
|
||||
/// <summary>
|
||||
/// Renders a raw editor for a single enum value.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field to render.</param>
|
||||
/// <param name="object">
|
||||
/// Tracking reference to the object to modify. Must be an enum.
|
||||
/// </param>
|
||||
/// <param name="isHovered">
|
||||
/// Pointer to a bool that stores if the field editor was hovered over.
|
||||
/// </param>
|
||||
/// <returns>True if the value was modified.</returns>
|
||||
static bool renderEnumEditor(const std::string& fieldName, System::Object^% object, bool* isHovered);
|
||||
/// <summary>
|
||||
/// Checks if the specified field is of the specified native and managed type
|
||||
|
@ -128,26 +170,6 @@ namespace SHADE
|
|||
/// <returns>True if the field is modified.</returns>
|
||||
template<typename NativeType, typename ManagedType>
|
||||
static bool renderFieldEditorInternal(const std::string& fieldName, interior_ptr<ManagedType> managedValPtr, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib);
|
||||
/// <summary>
|
||||
/// Renders a ImGui field editor based on the type of parameters specified.
|
||||
/// </summary>
|
||||
/// <typeparam name="NativeType">Native type of the field.</typeparam>
|
||||
/// <typeparam name="ManagedType">Managed type of the field.</typeparam>
|
||||
/// <param name="fieldName">Label to use for the field editor.</param>
|
||||
/// <param name="managedVal">
|
||||
/// Tracking reference for the managed variable to modify.
|
||||
/// </param>
|
||||
/// <param name="fieldEditor">ImGui field editor function to use.</param>
|
||||
/// <param name="isHovered">
|
||||
/// Pointer to a bool that stores if the field editor was hovered over.
|
||||
/// </param>
|
||||
/// <param name="rangeAttrib">
|
||||
/// If provided and the type supports it, the field will be rendered with a
|
||||
/// slider instead.
|
||||
/// </param>
|
||||
/// <returns>True if the field is modified.</returns>
|
||||
template<typename NativeType, typename ManagedType>
|
||||
static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc<NativeType> fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib);
|
||||
|
||||
/// <summary>
|
||||
/// Renders a context menu when right clicked for the scripts
|
||||
|
@ -164,6 +186,9 @@ namespace SHADE
|
|||
/// <param name="newData">New data to set.</param>
|
||||
/// <param name="oldData">Data that was overriden.</param>
|
||||
static void registerUndoAction(System::Object^ object, System::Reflection::FieldInfo^ field, System::Object^ newData, System::Object^ oldData);
|
||||
static void registerUndoListChangeAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData);
|
||||
static void registerUndoListAddAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data);
|
||||
static void registerUndoListRemoveAction(System::Type^ type, System::Collections::IList^ list, int index, System::Object^ data);
|
||||
/// <summary>
|
||||
/// Checks if a specific field has the specified attribute
|
||||
/// </summary>
|
||||
|
|
|
@ -132,10 +132,9 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementChangeCommand - Constructor */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
ListElementChangeCommand<T>::ListElementChangeCommand(System::Collections::Generic::List<T>^ list, int index, T newData, T oldData)
|
||||
ListElementChangeCommand::ListElementChangeCommand(System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData)
|
||||
: list { list }
|
||||
, index{ index }
|
||||
, index { index }
|
||||
, newData { newData }
|
||||
, oldData { oldData }
|
||||
{}
|
||||
|
@ -143,10 +142,9 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementChangeCommand - ICommand Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
bool ListElementChangeCommand<T>::Execute()
|
||||
bool ListElementChangeCommand::Execute()
|
||||
{
|
||||
if (list && index < System::Linq::Enumerable::Count(list))
|
||||
if (list && index < list->Count)
|
||||
{
|
||||
list[index] = newData;
|
||||
return true;
|
||||
|
@ -155,10 +153,9 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementChangeCommand<T>::Unexceute()
|
||||
bool ListElementChangeCommand::Unexceute()
|
||||
{
|
||||
if (list && index < System::Linq::Enumerable::Count(list))
|
||||
if (list && index < list->Count)
|
||||
{
|
||||
list[index] = oldData;
|
||||
return true;
|
||||
|
@ -166,11 +163,9 @@ namespace SHADE
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementChangeCommand<T>::Merge(ICommand^ command)
|
||||
bool ListElementChangeCommand::Merge(ICommand^ command)
|
||||
{
|
||||
ListElementChangeCommand<T>^ otherCommand = safe_cast<ListElementChangeCommand<T>^>(command);
|
||||
ListElementChangeCommand^ otherCommand = safe_cast<ListElementChangeCommand^>(command);
|
||||
if (otherCommand == nullptr)
|
||||
{
|
||||
Debug::LogWarning("[Field Change Command] Attempted to merge two incompatible commands!");
|
||||
|
@ -187,8 +182,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementAddCommand - ICommand Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
ListElementAddCommand<T>::ListElementAddCommand(System::Collections::Generic::List<T>^ list, int addIndex, T data)
|
||||
ListElementAddCommand::ListElementAddCommand(System::Collections::IList^ list, int addIndex, System::Object^ data)
|
||||
: list { list }
|
||||
, addIndex { addIndex }
|
||||
, data { data }
|
||||
|
@ -197,8 +191,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementAddCommand - ICommand Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
bool ListElementAddCommand<T>::Execute()
|
||||
bool ListElementAddCommand::Execute()
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
|
@ -209,10 +202,9 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementAddCommand<T>::Unexceute()
|
||||
bool ListElementAddCommand::Unexceute()
|
||||
{
|
||||
if (list && addIndex < System::Linq::Enumerable::Count(list))
|
||||
if (list && addIndex < list->Count)
|
||||
{
|
||||
list->RemoveAt(addIndex);
|
||||
return true;
|
||||
|
@ -221,8 +213,7 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementAddCommand<T>::Merge(ICommand^)
|
||||
bool ListElementAddCommand::Merge(ICommand^)
|
||||
{
|
||||
// Not allowed
|
||||
return false;
|
||||
|
@ -231,8 +222,7 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementRemoveCommand - ICommand Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
ListElementRemoveCommand<T>::ListElementRemoveCommand(System::Collections::Generic::List<T>^ list, int removeIndex, T data)
|
||||
ListElementRemoveCommand::ListElementRemoveCommand(System::Collections::IList^ list, int removeIndex, System::Object^ data)
|
||||
: list { list }
|
||||
, removeIndex { removeIndex }
|
||||
, data { data }
|
||||
|
@ -241,10 +231,9 @@ namespace SHADE
|
|||
/*---------------------------------------------------------------------------------*/
|
||||
/* ListElementRemoveCommand - ICommand Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
generic<typename T>
|
||||
bool ListElementRemoveCommand<T>::Execute()
|
||||
bool ListElementRemoveCommand::Execute()
|
||||
{
|
||||
if (list && removeIndex < System::Linq::Enumerable::Count(list))
|
||||
if (list && removeIndex < list->Count)
|
||||
{
|
||||
list->RemoveAt(removeIndex);
|
||||
return true;
|
||||
|
@ -253,8 +242,7 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementRemoveCommand<T>::Unexceute()
|
||||
bool ListElementRemoveCommand::Unexceute()
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
|
@ -265,8 +253,7 @@ namespace SHADE
|
|||
return false;
|
||||
}
|
||||
|
||||
generic<typename T>
|
||||
bool ListElementRemoveCommand<T>::Merge(ICommand^)
|
||||
bool ListElementRemoveCommand::Merge(ICommand^)
|
||||
{
|
||||
// Not allowed
|
||||
return false;
|
||||
|
|
|
@ -55,53 +55,51 @@ namespace SHADE
|
|||
System::Object^ oldData;
|
||||
};
|
||||
|
||||
generic<typename T>
|
||||
|
||||
private ref class ListElementChangeCommand sealed : public ICommand
|
||||
{
|
||||
public:
|
||||
ListElementChangeCommand(System::Collections::Generic::List<T>^ list, int index, T newData, T oldData);
|
||||
ListElementChangeCommand(System::Collections::IList^ list, int index, System::Object^ newData, System::Object^ oldData);
|
||||
|
||||
bool Execute() override;
|
||||
bool Unexceute() override;
|
||||
bool Merge(ICommand^ command) override;
|
||||
|
||||
private:
|
||||
System::Collections::Generic::List<T>^ list;
|
||||
System::Collections::IList^ list;
|
||||
int index;
|
||||
T newData;
|
||||
T oldData;
|
||||
System::Object^ newData;
|
||||
System::Object^ oldData;
|
||||
};
|
||||
|
||||
generic<typename T>
|
||||
private ref class ListElementAddCommand sealed : public ICommand
|
||||
{
|
||||
public:
|
||||
ListElementAddCommand(System::Collections::Generic::List<T>^ list, int addIndex, T data);
|
||||
ListElementAddCommand(System::Collections::IList^ list, int addIndex, System::Object^ data);
|
||||
|
||||
bool Execute() override;
|
||||
bool Unexceute() override;
|
||||
bool Merge(ICommand^ command) override;
|
||||
|
||||
private:
|
||||
System::Collections::Generic::List<T>^ list;
|
||||
System::Collections::IList^ list;
|
||||
int addIndex; // New index of the added element
|
||||
T data;
|
||||
System::Object^ data;
|
||||
};
|
||||
|
||||
generic<typename T>
|
||||
private ref class ListElementRemoveCommand sealed : public ICommand
|
||||
{
|
||||
public:
|
||||
ListElementRemoveCommand(System::Collections::Generic::List<T>^ list, int removeIndex, T data);
|
||||
ListElementRemoveCommand(System::Collections::IList^ list, int removeIndex, System::Object^ data);
|
||||
|
||||
bool Execute() override;
|
||||
bool Unexceute() override;
|
||||
bool Merge(ICommand^ command) override;
|
||||
|
||||
private:
|
||||
System::Collections::Generic::List<T>^ list;
|
||||
System::Collections::IList^ list;
|
||||
int removeIndex; // Index of the element to remove at
|
||||
T data;
|
||||
System::Object^ data;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in New Issue