Hierarchy QOL
Undo/Redo Parent Child Shift select Undo/Redo create entity
This commit is contained in:
parent
7fc417e35a
commit
ec6772657f
|
@ -24,6 +24,7 @@ namespace SHADE
|
||||||
class SHCommand : SHBaseCommand
|
class SHCommand : SHBaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using SHCommandPtr = std::unique_ptr<T>;
|
||||||
typedef std::function<void(T const&)> SetterFunction;
|
typedef std::function<void(T const&)> SetterFunction;
|
||||||
|
|
||||||
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)
|
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace SHADE
|
||||||
SHCommandManager::CommandStack SHCommandManager::undoStack{};
|
SHCommandManager::CommandStack SHCommandManager::undoStack{};
|
||||||
SHCommandManager::CommandStack SHCommandManager::redoStack{};
|
SHCommandManager::CommandStack SHCommandManager::redoStack{};
|
||||||
|
|
||||||
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue)
|
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
|
||||||
{
|
{
|
||||||
redoStack = CommandStack();
|
redoStack = CommandStack();
|
||||||
commandPtr->Execute();
|
commandPtr->Execute();
|
||||||
|
@ -27,9 +27,9 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHCommandManager::RegisterCommand(CommandPtr commandPtr)
|
void SHCommandManager::RegisterCommand(BaseCommandPtr commandPtr)
|
||||||
{
|
{
|
||||||
undoStack.push(commandPtr);
|
undoStack.push(commandPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHCommandManager::UndoCommand()
|
void SHCommandManager::UndoCommand()
|
||||||
|
|
|
@ -19,11 +19,13 @@ namespace SHADE
|
||||||
//#==============================================================#
|
//#==============================================================#
|
||||||
//|| Type Aliases ||
|
//|| Type Aliases ||
|
||||||
//#==============================================================#
|
//#==============================================================#
|
||||||
using CommandPtr = std::shared_ptr<SHBaseCommand>;
|
using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
|
||||||
using CommandStack = std::stack<CommandPtr>;
|
template<typename T>
|
||||||
|
using SHCommandPtr = std::shared_ptr<SHCommand<T>>;
|
||||||
|
using CommandStack = std::stack<BaseCommandPtr>;
|
||||||
|
|
||||||
static void PerformCommand(CommandPtr commandPtr, bool const& overrideValue = false);
|
static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
|
||||||
static void RegisterCommand(CommandPtr commandPtr);
|
static void RegisterCommand(BaseCommandPtr commandPtr);
|
||||||
static void UndoCommand();
|
static void UndoCommand();
|
||||||
static void RedoCommand();
|
static void RedoCommand();
|
||||||
static std::size_t GetUndoStackSize();
|
static std::size_t GetUndoStackSize();
|
||||||
|
|
|
@ -50,6 +50,7 @@ namespace SHADE
|
||||||
if(const auto root = sceneGraph.GetRoot())
|
if(const auto root = sceneGraph.GetRoot())
|
||||||
{
|
{
|
||||||
auto const& children = root->GetChildren();
|
auto const& children = root->GetChildren();
|
||||||
|
|
||||||
for (const auto child : children)
|
for (const auto child : children)
|
||||||
{
|
{
|
||||||
RecursivelyDrawEntityNode(child);
|
RecursivelyDrawEntityNode(child);
|
||||||
|
@ -102,7 +103,7 @@ namespace SHADE
|
||||||
}
|
}
|
||||||
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
|
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
|
||||||
{
|
{
|
||||||
SHEntityManager::CreateEntity();
|
SHCommandManager::PerformCommand(std::make_shared<SHCreateEntityCommand>());
|
||||||
}
|
}
|
||||||
if (ImGui::IsItemHovered())
|
if (ImGui::IsItemHovered())
|
||||||
{
|
{
|
||||||
|
@ -142,13 +143,24 @@ namespace SHADE
|
||||||
|
|
||||||
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
|
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
|
||||||
//Draw Node
|
//Draw Node
|
||||||
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", EntityHandleGenerator::GetIndex(eid), entity->name.c_str());
|
bool isNodeOpen = ImGui::TreeNodeEx(reinterpret_cast<void*>(entity), nodeFlags, "%u: %s", SHEntityManager::GetEntityIndex(eid), entity->name.c_str());
|
||||||
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
|
const ImRect nodeRect = ImRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
|
||||||
|
|
||||||
//Check For Begin Drag
|
//Check For Begin Drag
|
||||||
if (SHDragDrop::BeginSource())
|
if (SHDragDrop::BeginSource())
|
||||||
{
|
{
|
||||||
ImGui::Text("Moving EID: %zu", eid);
|
std::string moveLabel = "Moving EID: ";
|
||||||
|
if(!isSelected)
|
||||||
|
editor->selectedEntities.push_back(eid);
|
||||||
|
for(int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
|
||||||
|
{
|
||||||
|
moveLabel.append(std::to_string(editor->selectedEntities[i]));
|
||||||
|
if(i + 1 < static_cast<int>(editor->selectedEntities.size()))
|
||||||
|
{
|
||||||
|
moveLabel.append(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Text(moveLabel.c_str());
|
||||||
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
|
SHDragDrop::SetPayload<std::vector<EntityID>>(DRAG_EID, &editor->selectedEntities);
|
||||||
SHDragDrop::EndSource();
|
SHDragDrop::EndSource();
|
||||||
}
|
}
|
||||||
|
@ -156,14 +168,7 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
|
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
|
||||||
{
|
{
|
||||||
std::vector<EntityID> const droppedEIDs = *eidPayload;
|
ParentSelectedEntities(eid);
|
||||||
for(auto const& dropEID : droppedEIDs)
|
|
||||||
{
|
|
||||||
if(!sceneGraph.GetChild(dropEID, eid))
|
|
||||||
sceneGraph.SetParent(dropEID, eid);
|
|
||||||
}
|
|
||||||
//if(!sceneGraph.GetChild(dropEID, eid))
|
|
||||||
// sceneGraph.SetParent(dropEID, eid); //Set dropEID parent to eid (belonging to current Node)
|
|
||||||
SHDragDrop::EndTarget();
|
SHDragDrop::EndTarget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,7 +188,7 @@ namespace SHADE
|
||||||
|
|
||||||
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
|
if((currentNode->GetParent() != sceneGraph.GetRoot()) && ImGui::Selectable(std::format("{} Unparent Selected", ICON_MD_NORTH_WEST).data()))
|
||||||
{
|
{
|
||||||
sceneGraph.SetParent(currentNode->GetEntityID(), nullptr);
|
ParentSelectedEntities(MAX_EID);
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
@ -195,7 +200,15 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
if (!isSelected)
|
if (!isSelected)
|
||||||
{
|
{
|
||||||
if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
if(ImGui::IsKeyDown(ImGuiKey_LeftShift))
|
||||||
|
{
|
||||||
|
if(editor->selectedEntities.size() >= 1)
|
||||||
|
{
|
||||||
|
SelectRangeOfEntities(editor->selectedEntities[0], eid);
|
||||||
|
}
|
||||||
|
else editor->selectedEntities.clear();
|
||||||
|
}
|
||||||
|
else if (!ImGui::IsKeyDown(ImGuiKey_LeftCtrl))
|
||||||
editor->selectedEntities.clear();
|
editor->selectedEntities.clear();
|
||||||
editor->selectedEntities.push_back(eid);
|
editor->selectedEntities.push_back(eid);
|
||||||
}//if not selected
|
}//if not selected
|
||||||
|
@ -242,4 +255,90 @@ namespace SHADE
|
||||||
{
|
{
|
||||||
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
|
SHEntityManager::CreateEntity(MAX_EID, "DefaultChild", parentEID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SHHierarchyPanel::ParentSelectedEntities(EntityID parentEID) const noexcept
|
||||||
|
{
|
||||||
|
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||||
|
auto const editor = SHSystemManager::GetSystem<SHEditor>();
|
||||||
|
SHEntityParentCommand::EntityParentData entityParentData;
|
||||||
|
std::vector<EntityID> parentedEIDS;
|
||||||
|
for(auto const& eid : editor->selectedEntities)
|
||||||
|
{
|
||||||
|
if(sceneGraph.GetChild(eid, parentEID) == nullptr)
|
||||||
|
{
|
||||||
|
parentedEIDS.push_back(eid);
|
||||||
|
if(auto parent = sceneGraph.GetParent(eid))
|
||||||
|
entityParentData[eid].oldParentEID = parent->GetEntityID();
|
||||||
|
entityParentData[eid].newParentEID = parentEID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SHCommandManager::PerformCommand(std::make_shared<SHEntityParentCommand>(parentedEIDS, entityParentData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHHierarchyPanel::SelectRangeOfEntities(EntityID beginEID, EntityID endEID)
|
||||||
|
{
|
||||||
|
bool startSelecting = false; bool endSelecting = false;
|
||||||
|
auto const editor = SHSystemManager::GetSystem<SHEditor>();
|
||||||
|
editor->selectedEntities.clear();
|
||||||
|
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||||
|
sceneGraph.Traverse([&](SHSceneNode* nodePtr)
|
||||||
|
{
|
||||||
|
auto eid = nodePtr->GetEntityID();
|
||||||
|
if(!startSelecting)
|
||||||
|
{
|
||||||
|
if(eid == beginEID || eid == endEID)
|
||||||
|
{
|
||||||
|
startSelecting = true;
|
||||||
|
editor->selectedEntities.push_back(eid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!endSelecting)
|
||||||
|
{
|
||||||
|
editor->selectedEntities.push_back(eid);
|
||||||
|
if(eid == endEID || eid == beginEID)
|
||||||
|
{
|
||||||
|
endSelecting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHCreateEntityCommand::Execute()
|
||||||
|
{
|
||||||
|
EntityID newEID = SHEntityManager::CreateEntity(eid);
|
||||||
|
if(eid == MAX_EID)
|
||||||
|
eid = newEID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHCreateEntityCommand::Undo()
|
||||||
|
{
|
||||||
|
SHEntityManager::DestroyEntity(eid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHEntityParentCommand::Execute()
|
||||||
|
{
|
||||||
|
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||||
|
for(auto const& eid : entities)
|
||||||
|
{
|
||||||
|
if(entityParentData[eid].newParentEID == MAX_EID)
|
||||||
|
sceneGraph.SetParent(eid, nullptr);
|
||||||
|
else
|
||||||
|
sceneGraph.SetParent(eid, entityParentData[eid].newParentEID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHEntityParentCommand::Undo()
|
||||||
|
{
|
||||||
|
auto const& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
|
||||||
|
for(auto const& eid : entities)
|
||||||
|
{
|
||||||
|
if(entityParentData[eid].oldParentEID == MAX_EID)
|
||||||
|
sceneGraph.SetParent(eid, nullptr);
|
||||||
|
else
|
||||||
|
sceneGraph.SetParent(eid, entityParentData[eid].oldParentEID);
|
||||||
|
}
|
||||||
|
}
|
||||||
}//namespace SHADE
|
}//namespace SHADE
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "ECS_Base/SHECSMacros.h"
|
#include "ECS_Base/SHECSMacros.h"
|
||||||
#include "Editor/EditorWindow/SHEditorWindow.h"
|
#include "Editor/EditorWindow/SHEditorWindow.h"
|
||||||
|
#include "Editor/Command/SHCommand.hpp"
|
||||||
namespace SHADE
|
namespace SHADE
|
||||||
{
|
{
|
||||||
class SHSceneNode;
|
class SHSceneNode;
|
||||||
|
@ -28,8 +28,40 @@ namespace SHADE
|
||||||
void DrawMenuBar() const noexcept;
|
void DrawMenuBar() const noexcept;
|
||||||
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
|
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
|
||||||
void CreateChildEntity(EntityID parentEID) const noexcept;
|
void CreateChildEntity(EntityID parentEID) const noexcept;
|
||||||
|
void ParentSelectedEntities(EntityID parentEID) const noexcept;
|
||||||
|
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
|
||||||
std::string filter;
|
std::string filter;
|
||||||
bool isAnyNodeSelected = false;
|
bool isAnyNodeSelected = false;
|
||||||
EntityID scrollTo = MAX_EID;
|
EntityID scrollTo = MAX_EID;
|
||||||
};//class SHHierarchyPanel
|
};//class SHHierarchyPanel
|
||||||
|
|
||||||
|
//Might move to a different file
|
||||||
|
class SHCreateEntityCommand final : public SHBaseCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Execute() override;
|
||||||
|
void Undo() override;
|
||||||
|
private:
|
||||||
|
EntityID eid = MAX_EID;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SHEntityParentCommand final : public SHBaseCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Data
|
||||||
|
{
|
||||||
|
EntityID oldParentEID = MAX_EID;
|
||||||
|
EntityID newParentEID = MAX_EID;
|
||||||
|
};
|
||||||
|
using EntityParentData = std::unordered_map<EntityID, Data>;
|
||||||
|
|
||||||
|
SHEntityParentCommand(std::vector<EntityID> entityIDs, EntityParentData inEntityParentData):entities(entityIDs),entityParentData(inEntityParentData){}
|
||||||
|
|
||||||
|
void Execute() override;
|
||||||
|
void Undo() override;
|
||||||
|
private:
|
||||||
|
std::vector<EntityID> entities;
|
||||||
|
std::unordered_map<EntityID, Data> entityParentData;
|
||||||
|
};
|
||||||
|
|
||||||
}//namespace SHADE
|
}//namespace SHADE
|
||||||
|
|
Loading…
Reference in New Issue