Add Editor Features - Transform Gizmo #105
|
@ -24,6 +24,7 @@ namespace SHADE
|
|||
class SHCommand : SHBaseCommand
|
||||
{
|
||||
public:
|
||||
using SHCommandPtr = std::unique_ptr<T>;
|
||||
typedef std::function<void(T const&)> SetterFunction;
|
||||
|
||||
SHCommand(T const& oldVal, T const& value, SetterFunction setFnc)
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace SHADE
|
|||
SHCommandManager::CommandStack SHCommandManager::undoStack{};
|
||||
SHCommandManager::CommandStack SHCommandManager::redoStack{};
|
||||
|
||||
void SHCommandManager::PerformCommand(CommandPtr commandPtr, bool const& overrideValue)
|
||||
void SHCommandManager::PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue)
|
||||
{
|
||||
redoStack = CommandStack();
|
||||
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()
|
||||
|
|
|
@ -19,11 +19,13 @@ namespace SHADE
|
|||
//#==============================================================#
|
||||
//|| Type Aliases ||
|
||||
//#==============================================================#
|
||||
using CommandPtr = std::shared_ptr<SHBaseCommand>;
|
||||
using CommandStack = std::stack<CommandPtr>;
|
||||
using BaseCommandPtr = std::shared_ptr<SHBaseCommand>;
|
||||
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 RegisterCommand(CommandPtr commandPtr);
|
||||
static void PerformCommand(BaseCommandPtr commandPtr, bool const& overrideValue = false);
|
||||
static void RegisterCommand(BaseCommandPtr commandPtr);
|
||||
static void UndoCommand();
|
||||
static void RedoCommand();
|
||||
static std::size_t GetUndoStackSize();
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace SHADE
|
|||
if(const auto root = sceneGraph.GetRoot())
|
||||
{
|
||||
auto const& children = root->GetChildren();
|
||||
|
||||
for (const auto child : children)
|
||||
{
|
||||
RecursivelyDrawEntityNode(child);
|
||||
|
@ -102,7 +103,7 @@ namespace SHADE
|
|||
}
|
||||
if (ImGui::SmallButton(ICON_MD_ADD_CIRCLE))
|
||||
{
|
||||
SHEntityManager::CreateEntity();
|
||||
SHCommandManager::PerformCommand(std::make_shared<SHCreateEntityCommand>());
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
|
@ -142,13 +143,24 @@ namespace SHADE
|
|||
|
||||
auto* entity = SHEntityManager::GetEntityByID(currentNode->GetEntityID());
|
||||
//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());
|
||||
|
||||
//Check For Begin Drag
|
||||
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::EndSource();
|
||||
}
|
||||
|
@ -156,14 +168,7 @@ namespace SHADE
|
|||
{
|
||||
if (const std::vector<EntityID>* eidPayload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(DRAG_EID)) //If payload is valid
|
||||
{
|
||||
std::vector<EntityID> const droppedEIDs = *eidPayload;
|
||||
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)
|
||||
ParentSelectedEntities(eid);
|
||||
SHDragDrop::EndTarget();
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +188,7 @@ namespace SHADE
|
|||
|
||||
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();
|
||||
}
|
||||
|
@ -195,7 +200,15 @@ namespace SHADE
|
|||
{
|
||||
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.push_back(eid);
|
||||
}//if not selected
|
||||
|
@ -242,4 +255,90 @@ namespace SHADE
|
|||
{
|
||||
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
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "imgui_internal.h"
|
||||
#include "ECS_Base/SHECSMacros.h"
|
||||
#include "Editor/EditorWindow/SHEditorWindow.h"
|
||||
|
||||
#include "Editor/Command/SHCommand.hpp"
|
||||
namespace SHADE
|
||||
{
|
||||
class SHSceneNode;
|
||||
|
@ -28,8 +28,40 @@ namespace SHADE
|
|||
void DrawMenuBar() const noexcept;
|
||||
ImRect RecursivelyDrawEntityNode(SHSceneNode*);
|
||||
void CreateChildEntity(EntityID parentEID) const noexcept;
|
||||
void ParentSelectedEntities(EntityID parentEID) const noexcept;
|
||||
void SelectRangeOfEntities(EntityID beginEID, EntityID EndEID);
|
||||
std::string filter;
|
||||
bool isAnyNodeSelected = false;
|
||||
EntityID scrollTo = MAX_EID;
|
||||
};//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
|
||||
|
|
Loading…
Reference in New Issue