diff --git a/SHADE_Managed/src/Editor/Editor.cxx b/SHADE_Managed/src/Editor/Editor.cxx index 7648e2aa..d1672929 100644 --- a/SHADE_Managed/src/Editor/Editor.cxx +++ b/SHADE_Managed/src/Editor/Editor.cxx @@ -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(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputCheckbox, nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputFloat , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputDouble , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputVec2 , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, SHEditorUI::InputVec3 , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, nullptr , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, nullptr , nullptr, rangeAttrib) || - renderFieldEditor(fieldName, object, nullptr , nullptr, rangeAttrib); + bool modified; - return MODIFIED_PRIMITIVE; + const bool RENDERED = + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputInt , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputCheckbox, nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputFloat , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputDouble , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputVec2 , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, SHEditorUI::InputVec3 , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, nullptr , nullptr, rangeAttrib, modified) || + renderFieldEditor(fieldName, object, nullptr , nullptr, rangeAttrib, modified) || + renderFieldEditor(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(std::make_shared())); } + 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(std::make_shared())); + } + + 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 Attribute Editor::hasAttribute(System::Reflection::FieldInfo^ field) { diff --git a/SHADE_Managed/src/Editor/Editor.h++ b/SHADE_Managed/src/Editor/Editor.h++ index 009160ce..a186d7ea 100644 --- a/SHADE_Managed/src/Editor/Editor.h++ +++ b/SHADE_Managed/src/Editor/Editor.h++ @@ -80,13 +80,15 @@ namespace SHADE } template - bool Editor::renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib) + bool Editor::renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib, bool& modified) { + modified = false; + if constexpr (std::is_same_v) { 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(fieldName, managedValPtr, fieldEditor, isHovered, rangeAttrib)) { object = managedVal; + modified = true; return true; } return false; diff --git a/SHADE_Managed/src/Editor/Editor.hxx b/SHADE_Managed/src/Editor/Editor.hxx index 54ab128d..64c445e5 100644 --- a/SHADE_Managed/src/Editor/Editor.hxx +++ b/SHADE_Managed/src/Editor/Editor.hxx @@ -90,7 +90,49 @@ namespace SHADE /// The object that contains the data of the field to render. /// static void renderFieldInInspector(System::Reflection::FieldInfo^ field, System::Object^ object); + /// + /// Renders a raw editor for a single value. + /// + /// The name of the field to render. + /// Tracking reference to the object to modify. + /// + /// If specified, will be used to constrain values. + /// + /// True if the value was modified. static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, RangeAttribute^ rangeAttrib); + /// + /// Renders a ImGui field editor based on the type of parameters specified if the + /// type matches. + /// + /// Native type of the field. + /// Managed type of the field. + /// Label to use for the field editor. + /// + /// Tracking reference for the managed variable to modify. + /// + /// ImGui field editor function to use. + /// + /// Pointer to a bool that stores if the field editor was hovered over. + /// + /// + /// If provided and the type supports it, the field will be rendered with a + /// slider instead. + /// + /// + /// True if the field was rendered.. + template + static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib, bool& modified); + /// + /// Renders a raw editor for a single enum value. + /// + /// The name of the field to render. + /// + /// Tracking reference to the object to modify. Must be an enum. + /// + /// + /// Pointer to a bool that stores if the field editor was hovered over. + /// + /// True if the value was modified. static bool renderEnumEditor(const std::string& fieldName, System::Object^% object, bool* isHovered); /// /// Checks if the specified field is of the specified native and managed type @@ -128,26 +170,6 @@ namespace SHADE /// True if the field is modified. template static bool renderFieldEditorInternal(const std::string& fieldName, interior_ptr managedValPtr, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib); - /// - /// Renders a ImGui field editor based on the type of parameters specified. - /// - /// Native type of the field. - /// Managed type of the field. - /// Label to use for the field editor. - /// - /// Tracking reference for the managed variable to modify. - /// - /// ImGui field editor function to use. - /// - /// Pointer to a bool that stores if the field editor was hovered over. - /// - /// - /// If provided and the type supports it, the field will be rendered with a - /// slider instead. - /// - /// True if the field is modified. - template - static bool renderFieldEditor(const std::string& fieldName, System::Object^% object, EditorFieldFunc fieldEditor, bool* isHovered, RangeAttribute^ rangeAttrib); /// /// Renders a context menu when right clicked for the scripts @@ -164,6 +186,9 @@ namespace SHADE /// New data to set. /// Data that was overriden. 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); /// /// Checks if a specific field has the specified attribute /// diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.cxx b/SHADE_Managed/src/Editor/UndoRedoStack.cxx index 10ef822c..789d285d 100644 --- a/SHADE_Managed/src/Editor/UndoRedoStack.cxx +++ b/SHADE_Managed/src/Editor/UndoRedoStack.cxx @@ -132,10 +132,9 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* ListElementChangeCommand - Constructor */ /*---------------------------------------------------------------------------------*/ - generic - ListElementChangeCommand::ListElementChangeCommand(System::Collections::Generic::List^ 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 - bool ListElementChangeCommand::Execute() + bool ListElementChangeCommand::Execute() { - if (list && index < System::Linq::Enumerable::Count(list)) + if (list && index < list->Count) { list[index] = newData; return true; @@ -154,11 +152,10 @@ namespace SHADE return false; } - - generic - bool ListElementChangeCommand::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 - bool ListElementChangeCommand::Merge(ICommand^ command) + bool ListElementChangeCommand::Merge(ICommand^ command) { - ListElementChangeCommand^ otherCommand = safe_cast^>(command); + ListElementChangeCommand^ otherCommand = safe_cast(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 - ListElementAddCommand::ListElementAddCommand(System::Collections::Generic::List^ 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 - bool ListElementAddCommand::Execute() + bool ListElementAddCommand::Execute() { if (list) { @@ -209,10 +202,9 @@ namespace SHADE return false; } - generic - bool ListElementAddCommand::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 - bool ListElementAddCommand::Merge(ICommand^) + bool ListElementAddCommand::Merge(ICommand^) { // Not allowed return false; @@ -231,8 +222,7 @@ namespace SHADE /*---------------------------------------------------------------------------------*/ /* ListElementRemoveCommand - ICommand Functions */ /*---------------------------------------------------------------------------------*/ - generic - ListElementRemoveCommand::ListElementRemoveCommand(System::Collections::Generic::List^ 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 - bool ListElementRemoveCommand::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 - bool ListElementRemoveCommand::Unexceute() + bool ListElementRemoveCommand::Unexceute() { if (list) { @@ -265,8 +253,7 @@ namespace SHADE return false; } - generic - bool ListElementRemoveCommand::Merge(ICommand^) + bool ListElementRemoveCommand::Merge(ICommand^) { // Not allowed return false; diff --git a/SHADE_Managed/src/Editor/UndoRedoStack.hxx b/SHADE_Managed/src/Editor/UndoRedoStack.hxx index ed9a625a..dea458bc 100644 --- a/SHADE_Managed/src/Editor/UndoRedoStack.hxx +++ b/SHADE_Managed/src/Editor/UndoRedoStack.hxx @@ -55,53 +55,51 @@ namespace SHADE System::Object^ oldData; }; - generic + private ref class ListElementChangeCommand sealed : public ICommand { public: - ListElementChangeCommand(System::Collections::Generic::List^ 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^ list; + System::Collections::IList^ list; int index; - T newData; - T oldData; + System::Object^ newData; + System::Object^ oldData; }; - generic private ref class ListElementAddCommand sealed : public ICommand { public: - ListElementAddCommand(System::Collections::Generic::List^ 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^ list; + System::Collections::IList^ list; int addIndex; // New index of the added element - T data; + System::Object^ data; }; - generic private ref class ListElementRemoveCommand sealed : public ICommand { public: - ListElementRemoveCommand(System::Collections::Generic::List^ 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^ list; + System::Collections::IList^ list; int removeIndex; // Index of the element to remove at - T data; + System::Object^ data; }; ///