Editor keyboard shortcuts:
Ctrl+S to save the currently selected entity file (iterates to the base parent) Ctrl+N to create a new empty entity under the selection Ctrl+O to import an entity file Del to delete an entity
This commit is contained in:
@@ -11,6 +11,9 @@ struct KeyDown : Event
|
||||
{
|
||||
/** GLFW key code */
|
||||
int KeyCode;
|
||||
bool ModCtrl;
|
||||
bool ModAlt;
|
||||
bool ModShift;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ struct KeyUp : Event
|
||||
{
|
||||
/** GLFW key code */
|
||||
int KeyCode;
|
||||
bool ModCtrl;
|
||||
bool ModAlt;
|
||||
bool ModShift;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <imgui/imgui_internal.h>
|
||||
#include <nativefiledialog/nfd.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include "../Common.h"
|
||||
#include "../GLM.h"
|
||||
#include <glm/gtx/common.hpp>
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "../Core/EntityWrapper.h"
|
||||
#include "../Core/ResourceManager.h"
|
||||
#include "../Core/EPause.h"
|
||||
#include "../Core/EKeyDown.h"
|
||||
#include "../Rendering/Texture.h"
|
||||
|
||||
class EditorGUI
|
||||
@@ -33,6 +35,7 @@ public:
|
||||
void Draw();
|
||||
|
||||
void SelectEntity(EntityWrapper entity);
|
||||
void SetDirty(EntityWrapper entity);
|
||||
|
||||
// Called when an entity is selected in the entity tree
|
||||
typedef std::function<void(EntityWrapper)> OnEntitySelectedCallback_t;
|
||||
@@ -75,15 +78,23 @@ private:
|
||||
World* m_World;
|
||||
EventBroker* m_EventBroker;
|
||||
|
||||
struct EntityFileInfo
|
||||
{
|
||||
boost::filesystem::path Path;
|
||||
bool Dirty = false;
|
||||
};
|
||||
|
||||
// Config variables
|
||||
const boost::filesystem::path m_DefaultEntityPath = boost::filesystem::path("Schema") / boost::filesystem::path("Entities");
|
||||
|
||||
// State variables
|
||||
// State
|
||||
EntityWrapper m_CurrentSelection = EntityWrapper::Invalid;
|
||||
std::unordered_map<EntityWrapper, boost::filesystem::path> m_EntityFiles;
|
||||
std::unordered_map<EntityWrapper, EntityFileInfo> m_EntityFiles;
|
||||
EntityWrapper m_CurrentlyDragging = EntityWrapper::Invalid;
|
||||
std::string m_LastErrorMessage;
|
||||
WidgetMode m_CurrentWidgetMode = WidgetMode::Translate;
|
||||
std::set<std::string> m_ModalsToOpen;
|
||||
std::map<std::string, boost::any> m_ModalData;
|
||||
|
||||
// Callbacks
|
||||
OnEntitySelectedCallback_t m_OnEntitySelected = nullptr;
|
||||
@@ -97,11 +108,16 @@ private:
|
||||
OnComponentDelete_t m_OnComponentDelete = nullptr;
|
||||
OnWidgetMode_t m_OnWidgetMode = nullptr;
|
||||
|
||||
// Events
|
||||
EventRelay<EditorGUI, Events::KeyDown> m_EKeyDown;
|
||||
bool OnKeyDown(const Events::KeyDown& e);
|
||||
|
||||
// Utility functions
|
||||
boost::filesystem::path fileOpenDialog();
|
||||
boost::filesystem::path fileSaveDialog();
|
||||
const std::string formatEntityName(EntityWrapper entity);
|
||||
GLuint tryLoadTexture(std::string filePath);
|
||||
void openModal(const std::string& modal);
|
||||
|
||||
// Entity file handling methods
|
||||
void entityImport(World* world);
|
||||
@@ -118,15 +134,15 @@ private:
|
||||
bool drawEntityNode(EntityWrapper entity);
|
||||
void drawComponents(EntityWrapper entity);
|
||||
bool drawComponentNode(EntityWrapper entity, const ComponentInfo& componentType);
|
||||
void drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field);
|
||||
void drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field);
|
||||
bool drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
bool drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field);
|
||||
void drawModals();
|
||||
|
||||
// Custom UI elements
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
<Entity name="X">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="0" Y="1" Z="0"/>
|
||||
<Type>
|
||||
<Rotate/>
|
||||
</Type>
|
||||
@@ -25,7 +24,6 @@
|
||||
<Entity name="Y">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="1" Y="0" Z="0"/>
|
||||
<Type>
|
||||
<Rotate/>
|
||||
</Type>
|
||||
@@ -41,7 +39,6 @@
|
||||
<Entity name="Z">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="1" Y="1" Z="0"/>
|
||||
<Type>
|
||||
<Rotate/>
|
||||
</Type>
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
<Entity name="X">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="1" Y="0" Z="0"/>
|
||||
<Axis X="1" Y="0" Z="0"/>
|
||||
</c:EditorWidget>
|
||||
<c:Model>
|
||||
@@ -25,7 +24,6 @@
|
||||
<Entity name="Y">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="0" Y="1" Z="0"/>
|
||||
<Axis X="0" Y="1" Z="0"/>
|
||||
</c:EditorWidget>
|
||||
<c:Model>
|
||||
@@ -38,7 +36,6 @@
|
||||
<Entity name="Z">
|
||||
<Components>
|
||||
<c:EditorWidget>
|
||||
<MouseAxis X="0" Y="0" Z="1"/>
|
||||
<Axis X="0" Y="0" Z="1"/>
|
||||
</c:EditorWidget>
|
||||
<c:Model>
|
||||
|
||||
@@ -10,7 +10,11 @@ bool EntityWrapper::HasComponent(const std::string& componentName)
|
||||
|
||||
EntityWrapper EntityWrapper::Parent()
|
||||
{
|
||||
return EntityWrapper(World, World->GetParent(ID));
|
||||
if (this->World == nullptr || this->ID == EntityID_Invalid) {
|
||||
return EntityWrapper::Invalid;
|
||||
} else {
|
||||
return EntityWrapper(this->World, this->World->GetParent(this->ID));
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityWrapper::Valid()
|
||||
|
||||
@@ -34,10 +34,16 @@ void InputManager::Update(double dt)
|
||||
if (m_CurrentKeyState[i]) {
|
||||
Events::KeyDown e;
|
||||
e.KeyCode = i;
|
||||
e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL);
|
||||
e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT);
|
||||
e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT);
|
||||
m_EventBroker->Publish(e);
|
||||
} else {
|
||||
Events::KeyUp e;
|
||||
e.KeyCode = i;
|
||||
e.ModCtrl = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_CONTROL) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_CONTROL);
|
||||
e.ModAlt = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_ALT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_ALT);
|
||||
e.ModShift = glfwGetKey(m_GLFWWindow, GLFW_KEY_LEFT_SHIFT) || glfwGetKey(m_GLFWWindow, GLFW_KEY_RIGHT_SHIFT);
|
||||
m_EventBroker->Publish(e);
|
||||
}
|
||||
}
|
||||
|
||||
+149
-44
@@ -4,7 +4,7 @@ EditorGUI::EditorGUI(World* world, EventBroker* eventBroker)
|
||||
: m_World(world)
|
||||
, m_EventBroker(eventBroker)
|
||||
{
|
||||
|
||||
EVENT_SUBSCRIBE_MEMBER(m_EKeyDown, &EditorGUI::OnKeyDown);
|
||||
}
|
||||
|
||||
void EditorGUI::Draw()
|
||||
@@ -14,6 +14,7 @@ void EditorGUI::Draw()
|
||||
drawTools();
|
||||
drawEntities(m_World);
|
||||
drawComponents(m_CurrentSelection);
|
||||
drawModals();
|
||||
}
|
||||
|
||||
void EditorGUI::SelectEntity(EntityWrapper entity)
|
||||
@@ -111,6 +112,7 @@ void EditorGUI::drawEntities(World* world)
|
||||
if (m_CurrentSelection.Valid()) {
|
||||
if (m_OnEntityChangeName != nullptr) {
|
||||
m_OnEntityChangeName(m_CurrentSelection, std::string(buffer));
|
||||
SetDirty(m_CurrentSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,8 +122,6 @@ void EditorGUI::drawEntities(World* world)
|
||||
|
||||
drawEntitiesRecursive(world, EntityID_Invalid);
|
||||
|
||||
// Draw any potential modals before ending this scope
|
||||
drawModals();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
@@ -167,10 +167,10 @@ bool EditorGUI::drawEntityNode(EntityWrapper entity)
|
||||
ImGui::Text(formatEntityName(entity).c_str());
|
||||
ImGui::End();
|
||||
}
|
||||
} else if (m_CurrentlyDragging == entity) {
|
||||
}/* else if (m_CurrentlyDragging == entity) {
|
||||
LOG_DEBUG("Stopped dragging %i", entity.ID);
|
||||
m_CurrentlyDragging = EntityWrapper::Invalid;
|
||||
}
|
||||
}*/
|
||||
// Entity context menu
|
||||
std::string contextMenuUniqueID = std::string("EntityContextMenu") + std::to_string(entity.ID);
|
||||
if (hovered && ImGui::IsMouseClicked(1)) {
|
||||
@@ -190,7 +190,6 @@ bool EditorGUI::drawEntityNode(EntityWrapper entity)
|
||||
if (ImGui::MenuItem("Move to root")) {
|
||||
entityChangeParent(entity, EntityWrapper::Invalid);
|
||||
}
|
||||
drawModals();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
@@ -242,6 +241,7 @@ void EditorGUI::drawComponents(EntityWrapper entity)
|
||||
if (m_OnComponentAttach != nullptr) {
|
||||
std::string chosenComponentType(componentTypes.at(selectedItem));
|
||||
m_OnComponentAttach(entity, chosenComponentType);
|
||||
SetDirty(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,7 +287,10 @@ bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci)
|
||||
const ComponentInfo::Field_t& field = kv.second;
|
||||
|
||||
// Draw the field widget based on its type
|
||||
drawComponentField(component, field);
|
||||
bool dirty = drawComponentField(component, field);
|
||||
if (dirty) {
|
||||
SetDirty(entity);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// Draw field name
|
||||
ImGui::Text(fieldName.c_str());
|
||||
@@ -305,70 +308,76 @@ bool EditorGUI::drawComponentNode(EntityWrapper entity, const ComponentInfo& ci)
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field)
|
||||
bool EditorGUI::drawComponentField(ComponentWrapper& c, const ComponentInfo::Field_t& field)
|
||||
{
|
||||
// Push an unique widget id so different components with fields with equal names are still counted as different
|
||||
ImGui::PushID((c.Info.Name + field.Name).c_str());
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
if (field.Type == "Vector") {
|
||||
drawComponentField_Vector(c, field);
|
||||
dirty = drawComponentField_Vector(c, field);
|
||||
} else if (field.Type == "Color") {
|
||||
drawComponentField_Color(c, field);
|
||||
dirty = drawComponentField_Color(c, field);
|
||||
//} else if (field.Type == "Quaternion") {
|
||||
} else if (field.Type == "int") {
|
||||
drawComponentField_int(c, field);
|
||||
dirty = drawComponentField_int(c, field);
|
||||
} else if (field.Type == "enum") {
|
||||
drawComponentField_enum(c, field);
|
||||
dirty = drawComponentField_enum(c, field);
|
||||
} else if (field.Type == "float") {
|
||||
drawComponentField_float(c, field);
|
||||
dirty = drawComponentField_float(c, field);
|
||||
} else if (field.Type == "double") {
|
||||
drawComponentField_double(c, field);
|
||||
dirty = drawComponentField_double(c, field);
|
||||
} else if (field.Type == "bool") {
|
||||
drawComponentField_bool(c, field);
|
||||
dirty = drawComponentField_bool(c, field);
|
||||
} else if (field.Type == "string") {
|
||||
drawComponentField_string(c, field);
|
||||
dirty = drawComponentField_string(c, field);
|
||||
} else {
|
||||
ImGui::TextDisabled(field.Type.c_str());
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_Vector(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<glm::vec3>(field.Name);
|
||||
if (field.Name == "Scale") {
|
||||
// Limit scale values to a minimum of 0
|
||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
||||
return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, 0.f, std::numeric_limits<float>::max());
|
||||
} else if (field.Name == "Orientation") {
|
||||
// Make orentations have a period of 2*Pi
|
||||
glm::vec3 tempVal = glm::fmod(val, glm::vec3(glm::two_pi<float>()));
|
||||
if (ImGui::SliderFloat3("", glm::value_ptr(tempVal), 0.f, glm::two_pi<float>())) {
|
||||
val = tempVal;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
||||
return ImGui::DragFloat3("", glm::value_ptr(val), 0.1f, std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max());
|
||||
}
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_Color(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<glm::vec4>(field.Name);
|
||||
ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
||||
return ImGui::ColorEdit4("", glm::value_ptr(val), true);
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_int(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<int>(field.Name);
|
||||
ImGui::InputInt("", &val);
|
||||
return ImGui::InputInt("", &val);
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_enum(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto fieldEnumDefIt = c.Info.Meta->FieldEnumDefinitions.find(field.Name);
|
||||
if (fieldEnumDefIt == c.Info.Meta->FieldEnumDefinitions.end()) {
|
||||
drawComponentField_int(c, field);
|
||||
return;
|
||||
return drawComponentField_int(c, field);
|
||||
}
|
||||
|
||||
auto& val = c.Field<int>(field.Name);
|
||||
@@ -386,30 +395,36 @@ void EditorGUI::drawComponentField_enum(ComponentWrapper &c, const ComponentInfo
|
||||
}
|
||||
if (ImGui::Combo("", &selectedItem, enumKeys.str().c_str())) {
|
||||
val = enumValues.at(selectedItem);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_float(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<float>(field.Name);
|
||||
ImGui::InputFloat("", &val, 0.01f, 1.f);
|
||||
return ImGui::InputFloat("", &val, 0.01f, 1.f);
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_double(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
float tempVal = static_cast<float>(c.Field<double>(field.Name));
|
||||
if (ImGui::InputFloat("", &tempVal, 0.01f, 1.f)) {
|
||||
c.SetField(field.Name, static_cast<double>(tempVal));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_bool(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<bool>(field.Name);
|
||||
ImGui::Checkbox("", &val);
|
||||
return ImGui::Checkbox("", &val);
|
||||
}
|
||||
|
||||
void EditorGUI::drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
bool EditorGUI::drawComponentField_string(ComponentWrapper &c, const ComponentInfo::Field_t &field)
|
||||
{
|
||||
auto& val = c.Field<std::string>(field.Name);
|
||||
char tempString[1024]; // Let's just hope this is an sufficiently large buffer for strings :)
|
||||
@@ -418,12 +433,20 @@ void EditorGUI::drawComponentField_string(ComponentWrapper &c, const ComponentIn
|
||||
memcpy(tempString, val.c_str(), std::min(val.length() + 1, sizeof(tempString) - 1));
|
||||
if (ImGui::InputText("", tempString, sizeof(tempString))) {
|
||||
val = std::string(tempString);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// TODO: Handle drag and drop of files
|
||||
}
|
||||
|
||||
void EditorGUI::drawModals()
|
||||
{
|
||||
for (auto& modal : m_ModalsToOpen) {
|
||||
ImGui::OpenPopup(modal.c_str());
|
||||
}
|
||||
m_ModalsToOpen.clear();
|
||||
|
||||
if (ImGui::BeginPopupModal("Import failed", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("Entity import failed. Check console for more information.\n\n");
|
||||
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 120);
|
||||
@@ -441,6 +464,26 @@ void EditorGUI::drawModals()
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("Confirm deletion", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
if (m_ModalData.count("Confirm deletion") == 0) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::Text("Are you sure you want to delete entity \"%s\"?", formatEntityName(m_CurrentSelection).c_str());
|
||||
ImGui::ItemSize(ImVec2(5.f, 0.f));
|
||||
ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() - 2*60);
|
||||
if (ImGui::Button("Delete (Del)", ImVec2(60, 0))) {
|
||||
entityDelete(boost::any_cast<EntityWrapper>(m_ModalData.at("Confirm deletion")));
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", ImVec2(60, 0))) {
|
||||
m_ModalData.erase("Confirm deletion");
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorGUI::createDeleteButton(const std::string& componentType)
|
||||
@@ -492,6 +535,35 @@ void EditorGUI::createWidgetToolButton(WidgetMode mode)
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorGUI::OnKeyDown(const Events::KeyDown& e)
|
||||
{
|
||||
if (e.ModCtrl && e.KeyCode == GLFW_KEY_S) {
|
||||
if (m_CurrentSelection.Valid()) {
|
||||
EntityWrapper baseParent = m_CurrentSelection;
|
||||
while (baseParent.Parent().Valid()) {
|
||||
baseParent = baseParent.Parent();
|
||||
}
|
||||
entitySave(baseParent);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.ModCtrl && e.KeyCode == GLFW_KEY_N) {
|
||||
entityCreate(m_World, m_CurrentSelection);
|
||||
}
|
||||
|
||||
if (e.ModCtrl && e.KeyCode == GLFW_KEY_O) {
|
||||
entityImport(m_World);
|
||||
}
|
||||
|
||||
if (e.KeyCode == GLFW_KEY_DELETE) {
|
||||
if (m_CurrentSelection.Valid()) {
|
||||
entityDelete(m_CurrentSelection);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::filesystem::path EditorGUI::fileOpenDialog()
|
||||
{
|
||||
namespace bfs = boost::filesystem;
|
||||
@@ -540,7 +612,10 @@ const std::string EditorGUI::formatEntityName(EntityWrapper entity)
|
||||
}
|
||||
|
||||
if (m_EntityFiles.count(entity) == 1) {
|
||||
name << " (" << m_EntityFiles.at(entity).filename().string() << ")";
|
||||
name << " (" << m_EntityFiles.at(entity).Path.filename().string() << ")";
|
||||
if (m_EntityFiles.at(entity).Dirty) {
|
||||
name << "*";
|
||||
}
|
||||
}
|
||||
|
||||
return name.str();
|
||||
@@ -555,6 +630,22 @@ GLuint EditorGUI::tryLoadTexture(std::string filePath)
|
||||
return texture;
|
||||
}
|
||||
|
||||
void EditorGUI::openModal(const std::string& modal)
|
||||
{
|
||||
m_ModalsToOpen.insert(modal);
|
||||
}
|
||||
|
||||
void EditorGUI::SetDirty(EntityWrapper entity)
|
||||
{
|
||||
EntityWrapper baseParent = entity;
|
||||
while (baseParent.Parent().Valid()) {
|
||||
baseParent = baseParent.Parent();
|
||||
}
|
||||
if (m_EntityFiles.find(baseParent) != m_EntityFiles.end()) {
|
||||
m_EntityFiles.at(baseParent).Dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorGUI::entityImport(World* world)
|
||||
{
|
||||
boost::filesystem::path filePath = fileOpenDialog();
|
||||
@@ -564,10 +655,10 @@ void EditorGUI::entityImport(World* world)
|
||||
|
||||
EntityWrapper entity = m_OnEntityImport(EntityWrapper(world, EntityID_Invalid), filePath);
|
||||
if (entity.Valid()) {
|
||||
m_EntityFiles[entity] = filePath;
|
||||
m_EntityFiles[entity].Path = filePath;
|
||||
SelectEntity(entity);
|
||||
} else {
|
||||
ImGui::OpenPopup("Import failed");
|
||||
openModal("Import failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +666,7 @@ void EditorGUI::entitySave(EntityWrapper entity, bool saveAs /* = false */)
|
||||
{
|
||||
boost::filesystem::path filePath;
|
||||
if (!saveAs && m_EntityFiles.count(entity) == 1) {
|
||||
filePath = m_EntityFiles.at(entity);
|
||||
filePath = m_EntityFiles.at(entity).Path;
|
||||
} else {
|
||||
filePath = fileSaveDialog();
|
||||
}
|
||||
@@ -586,10 +677,11 @@ void EditorGUI::entitySave(EntityWrapper entity, bool saveAs /* = false */)
|
||||
|
||||
try {
|
||||
m_OnEntitySave(entity, filePath);
|
||||
m_EntityFiles[entity] = filePath;
|
||||
m_EntityFiles[entity].Path = filePath;
|
||||
m_EntityFiles[entity].Dirty = false;
|
||||
} catch (const std::exception& e) {
|
||||
m_LastErrorMessage = e.what();
|
||||
ImGui::OpenPopup("Save failed");
|
||||
openModal("Save failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,12 +699,24 @@ void EditorGUI::entityCreate(World* world, EntityWrapper parent)
|
||||
|
||||
void EditorGUI::entityDelete(EntityWrapper entity)
|
||||
{
|
||||
if (m_OnEntityDelete != nullptr) {
|
||||
m_OnEntityDelete(entity);
|
||||
m_EntityFiles.erase(entity);
|
||||
}
|
||||
if (!m_CurrentSelection.Valid()) {
|
||||
SelectEntity(EntityWrapper::Invalid);
|
||||
std::string modalName = "Confirm deletion";
|
||||
|
||||
if (m_ModalData.count(modalName) == 0) {
|
||||
m_ModalData[modalName] = entity;
|
||||
openModal(modalName);
|
||||
} else {
|
||||
if (boost::any_cast<EntityWrapper>(m_ModalData[modalName]) == entity) {
|
||||
EntityWrapper parent = entity.Parent();
|
||||
if (m_OnEntityDelete != nullptr) {
|
||||
SetDirty(entity);
|
||||
m_OnEntityDelete(entity);
|
||||
m_EntityFiles.erase(entity);
|
||||
}
|
||||
if (!m_CurrentSelection.Valid()) {
|
||||
SelectEntity(parent);
|
||||
}
|
||||
}
|
||||
m_ModalData.erase(modalName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,6 +727,7 @@ void EditorGUI::entityChangeParent(EntityWrapper entity, EntityWrapper parent)
|
||||
}
|
||||
|
||||
if (m_OnEntityChangeParent != nullptr) {
|
||||
SetDirty(entity);
|
||||
m_OnEntityChangeParent(entity, parent);
|
||||
LOG_DEBUG("Changed parent of %i to %i", entity.ID, parent.ID);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ EditorSystem::~EditorSystem()
|
||||
|
||||
void EditorSystem::Update(double dt)
|
||||
{
|
||||
m_EventBroker->Process<EditorGUI>();
|
||||
m_EditorGUI->Draw();
|
||||
m_EditorStats->Draw(dt);
|
||||
|
||||
@@ -87,27 +88,37 @@ EntityWrapper EditorSystem::OnEntityCreate(EntityWrapper parent)
|
||||
|
||||
void EditorSystem::OnEntityDelete(EntityWrapper entity)
|
||||
{
|
||||
entity.World->DeleteEntity(entity.ID);
|
||||
if (entity.Valid()) {
|
||||
entity.World->DeleteEntity(entity.ID);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::OnEntityChangeParent(EntityWrapper entity, EntityWrapper parent)
|
||||
{
|
||||
entity.World->SetParent(entity.ID, parent.ID);
|
||||
if (entity.Valid()) {
|
||||
entity.World->SetParent(entity.ID, parent.ID);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::OnEntityChangeName(EntityWrapper entity, const std::string& name)
|
||||
{
|
||||
entity.World->SetName(entity.ID, name);
|
||||
if (entity.Valid()) {
|
||||
entity.World->SetName(entity.ID, name);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::OnComponentAttach(EntityWrapper entity, const std::string& componentType)
|
||||
{
|
||||
entity.World->AttachComponent(entity.ID, componentType);
|
||||
if (entity.Valid()) {
|
||||
entity.World->AttachComponent(entity.ID, componentType);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorSystem::OnComponentDelete(EntityWrapper entity, const std::string& componentType)
|
||||
{
|
||||
entity.World->DeleteComponent(entity.ID, componentType);
|
||||
if (entity.Valid()) {
|
||||
entity.World->DeleteComponent(entity.ID, componentType);
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorSystem::OnMouseRelease(const Events::MouseRelease& e)
|
||||
@@ -126,6 +137,7 @@ bool EditorSystem::OnWidgetDelta(const Events::WidgetDelta& e)
|
||||
{
|
||||
if (m_CurrentSelection.Valid()) {
|
||||
(glm::vec3&)m_CurrentSelection["Transform"]["Position"] += glm::inverse(Transform::AbsoluteOrientation(m_CurrentSelection.World, m_CurrentSelection.ID)) * e.Translation;
|
||||
m_EditorGUI->SetDirty(m_CurrentSelection);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user