Base work on reimplementing editor GUI
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
#ifndef EditorGUI_h__
|
||||
#define EditorGUI_h__
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui/imgui_internal.h>
|
||||
#include <nativefiledialog/nfd.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "../Common.h"
|
||||
|
||||
#include "../Core/EventBroker.h"
|
||||
#include "../Core/World.h"
|
||||
#include "../Core/EntityWrapper.h"
|
||||
|
||||
class EditorGUI
|
||||
{
|
||||
public:
|
||||
EditorGUI(EventBroker* eventBroker)
|
||||
: m_EventBroker(eventBroker)
|
||||
{ }
|
||||
|
||||
void Draw(World* world);
|
||||
|
||||
void SelectEntity(EntityWrapper entity);
|
||||
|
||||
// Called when an entity is selected in the entity tree
|
||||
typedef std::function<void(EntityWrapper)> OnEntitySelectedCallback_t;
|
||||
void SetEntitySelectedCallback(OnEntitySelectedCallback_t f) { m_OnEntitySelected = f; }
|
||||
// Called when the user means to import an entity file.
|
||||
// Expects an EntityWrapper of the newly created entity in return.
|
||||
typedef std::function<EntityWrapper(boost::filesystem::path)> OnEntityImport_t;
|
||||
void SetEntityImportCallback(OnEntityImport_t f) { m_OnEntityImport = f; }
|
||||
// Called when the user means to save an entity to file.
|
||||
// Expects a bool indicating whether the save was successful or not in return.
|
||||
typedef std::function<bool(EntityWrapper, boost::filesystem::path)> OnEntitySave_t;
|
||||
void SetEntitySaveCallback(OnEntitySave_t f) { m_OnEntitySave = f; }
|
||||
// Called when the user means to create a new entity.
|
||||
// @param EntityWrapper The parent of the entity to be created
|
||||
// @return EntityWrapper The newly created entity
|
||||
typedef std::function<EntityWrapper(EntityWrapper)> OnEntityCreate_t;
|
||||
void SetEntityCreateCallback(OnEntityCreate_t f) { m_OnEntityCreate = f; }
|
||||
// Called when the user means to delete an entity.
|
||||
typedef std::function<void(EntityWrapper)> OnEntityDelete_t;
|
||||
void SetEntityCreateCallback(OnEntityDelete_t f) { m_OnEntityDelete = f; }
|
||||
|
||||
private:
|
||||
EventBroker* m_EventBroker;
|
||||
|
||||
// State variables
|
||||
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
|
||||
|
||||
// Callbacks
|
||||
OnEntitySelectedCallback_t m_OnEntitySelected = nullptr;
|
||||
OnEntityImport_t m_OnEntityImport = nullptr;
|
||||
OnEntitySave_t m_OnEntitySave = nullptr;
|
||||
OnEntityCreate_t m_OnEntityCreate = nullptr;
|
||||
OnEntityDelete_t m_OnEntityDelete = nullptr;
|
||||
|
||||
void drawMenu();
|
||||
void drawEntities(World* world);
|
||||
void drawEntitiesRecursive(World* world, EntityID parent);
|
||||
bool drawEntityNode(EntityWrapper entity);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "../Core/ResourceManager.h"
|
||||
#include "../Core/EntityFilePreprocessor.h"
|
||||
#include "../Core/EntityFileParser.h"
|
||||
#include "EditorGUI.h"
|
||||
|
||||
class EditorSystem : public ImpureSystem
|
||||
{
|
||||
@@ -23,8 +24,10 @@ private:
|
||||
World* m_EditorWorld;
|
||||
SystemPipeline* m_EditorWorldSystemPipeline;
|
||||
Camera* m_EditorCamera;
|
||||
|
||||
EntityWrapper m_Widget = EntityWrapper::Invalid;
|
||||
EntityWrapper m_Camera = EntityWrapper::Invalid;
|
||||
DebugCameraInputController<EditorSystem>* m_DebugCameraInputController;
|
||||
EditorGUI* m_EditorGUI;
|
||||
|
||||
void OnEntitySelected(EntityWrapper entity);
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
#include <imgui/imgui.h>
|
||||
#include <nativefiledialog/nfd.h>
|
||||
|
||||
class EditorUI
|
||||
{
|
||||
public:
|
||||
EditorUI();
|
||||
};
|
||||
@@ -13,7 +13,7 @@
|
||||
<Entity>
|
||||
<Components>
|
||||
<c:Transform>
|
||||
<Position X="0" Y="-0"/>
|
||||
<Position X="0" Y="0" Z="-2"/>
|
||||
<Scale X="1" Y="1" Z="1"/>
|
||||
</c:Transform>
|
||||
<c:Camera>
|
||||
@@ -23,5 +23,6 @@
|
||||
</c:Model>
|
||||
</Components>
|
||||
</Entity>
|
||||
<EntityRef file="Schema/Entities/EditorWidget.xml"/>
|
||||
</Children>
|
||||
</Entity>
|
||||
|
||||
@@ -38,9 +38,7 @@
|
||||
<xs:element ref="Entity" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="EntityRef" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:attribute name="file" type="xs:string" minOccurs="0"/>
|
||||
</xs:all>
|
||||
<xs:attribute name="file" type="xs:string" minOccurs="0"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
#include "Editor/EditorGUI.h"
|
||||
|
||||
void EditorGUI::Draw(World* world)
|
||||
{
|
||||
drawMenu();
|
||||
drawEntities(world);
|
||||
}
|
||||
|
||||
void EditorGUI::SelectEntity(EntityWrapper entity)
|
||||
{
|
||||
m_CurrentSelection = entity;
|
||||
if (m_OnEntitySelected != nullptr) {
|
||||
m_OnEntitySelected(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorGUI::drawMenu()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EditorGUI::drawEntities(World* world)
|
||||
{
|
||||
if (!ImGui::Begin("Entities")) {
|
||||
return;
|
||||
}
|
||||
|
||||
drawEntitiesRecursive(world, EntityID_Invalid);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void EditorGUI::drawEntitiesRecursive(World* world, EntityID parent)
|
||||
{
|
||||
auto entityChildren = world->GetEntityChildren();
|
||||
auto range = entityChildren.equal_range(parent);
|
||||
for (auto it = range.first; it != range.second; it++) {
|
||||
if (EditorGUI::drawEntityNode(EntityWrapper(world, it->second))) {
|
||||
drawEntitiesRecursive(world, it->second);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorGUI::drawEntityNode(EntityWrapper entity)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
float width = ImGui::GetContentRegionAvailWidth();
|
||||
ImRect bb(pos + ImVec2(20, 0), pos + ImVec2(width, 13));
|
||||
auto window = ImGui::GetCurrentWindow();
|
||||
if (m_CurrentSelection == entity) {
|
||||
const ImU32 col = window->Color(ImGuiCol_HeaderActive);
|
||||
window->DrawList->AddRectFilled(bb.Min, bb.Max, col);
|
||||
}
|
||||
ImGuiID id = window->GetID((std::string("#SelectButton") + std::to_string(entity)).c_str());
|
||||
bool hovered = false;
|
||||
bool held = false;
|
||||
if (ImGui::ButtonBehavior(bb, id, &hovered, &held)) {
|
||||
SelectEntity(entity);
|
||||
}
|
||||
//if (held) {
|
||||
// ImVec2 entityDragDelta = ImGui::GetMouseDragDelta(0);
|
||||
// if (std::abs(entityDragDelta.x) > 0 && std::abs(entityDragDelta.y) > 0) {
|
||||
// if (m_UIDraggingEntity == EntityID_Invalid) {
|
||||
// m_UIDraggingEntity = entity;
|
||||
// LOG_DEBUG("Started drag of entity %i", m_UIDraggingEntity);
|
||||
// }
|
||||
// ImGui::SetNextWindowPos(ImGui::GetIO().MousePos + ImVec2(20, 0));
|
||||
// ImGui::Begin("Change parent", nullptr, ImVec2(0, 0), 0.3f, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoSavedSettings);
|
||||
// ImGui::Text("#%i", m_UIDraggingEntity);
|
||||
// ImGui::End();
|
||||
// }
|
||||
//}
|
||||
|
||||
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Once);
|
||||
std::string nodeTitle;
|
||||
const std::string& entityName = entity.World->GetName(entity);
|
||||
if (!entityName.empty()) {
|
||||
nodeTitle = entityName;
|
||||
} else {
|
||||
nodeTitle = std::string("#") + std::to_string(entity.ID);
|
||||
}
|
||||
if (ImGui::TreeNode(nodeTitle.c_str())) {
|
||||
//if (m_UIDraggingEntity != EntityID_Invalid && ImGui::IsItemHoveredRect() && ImGui::IsMouseReleased(0)) {
|
||||
// LOG_DEBUG("Changed parent of %i to %i", m_UIDraggingEntity, entity);
|
||||
// changeParent(m_UIDraggingEntity, entity);
|
||||
// m_UIDraggingEntity = EntityID_Invalid;
|
||||
//}
|
||||
|
||||
if (ImGui::BeginPopupContextItem("item context menu")) {
|
||||
if (ImGui::Button("Add")) {
|
||||
if (m_OnEntityCreate != nullptr) {
|
||||
EntityWrapper newEntity = m_OnEntityCreate(EntityWrapper(entity.World, EntityID_Invalid));
|
||||
ImGui::CloseCurrentPopup();
|
||||
SelectEntity(newEntity);
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Delete")) {
|
||||
if (m_OnEntityDelete != nullptr) {
|
||||
m_OnEntityDelete(entity);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
if (!m_CurrentSelection.Valid()) {
|
||||
SelectEntity(EntityWrapper::Invalid);
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer, Render
|
||||
m_EditorWorld->AttachComponent(m_Camera.ID, "Camera");
|
||||
m_DebugCameraInputController = new DebugCameraInputController<EditorSystem>(m_EventBroker, -1);
|
||||
|
||||
m_EditorGUI = new EditorGUI(m_EventBroker);
|
||||
m_EditorGUI->SetEntitySelectedCallback(std::bind(&EditorSystem::OnEntitySelected, this, std::placeholders::_1));
|
||||
|
||||
Events::SetCamera e;
|
||||
e.CameraEntity = m_Camera;
|
||||
m_EventBroker->Publish(e);
|
||||
@@ -31,6 +34,7 @@ EditorSystem::EditorSystem(EventBroker* eventBroker, IRenderer* renderer, Render
|
||||
|
||||
EditorSystem::~EditorSystem()
|
||||
{
|
||||
delete m_EditorGUI;
|
||||
delete m_DebugCameraInputController;
|
||||
delete m_EditorWorldSystemPipeline;
|
||||
delete m_EditorWorld;
|
||||
@@ -40,7 +44,14 @@ void EditorSystem::Update(World* world, double dt)
|
||||
{
|
||||
m_EditorWorldSystemPipeline->Update(m_EditorWorld, dt);
|
||||
|
||||
m_EditorGUI->Draw(world);
|
||||
|
||||
m_DebugCameraInputController->Update(dt);
|
||||
m_Camera["Transform"]["Position"] = m_DebugCameraInputController->Position();
|
||||
m_Camera["Transform"]["Orientation"] = glm::eulerAngles(m_DebugCameraInputController->Orientation());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::OnEntitySelected(EntityWrapper entity)
|
||||
{
|
||||
m_Widget["Transform"]["Position"] = Transform::AbsolutePosition(entity.World, entity.ID);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user