LumixEngine/src/editor/property_grid.cpp
2017-04-27 20:01:26 +02:00

757 lines
21 KiB
C++

#include "property_grid.h"
#include "asset_browser.h"
#include "editor/prefab_system.h"
#include "editor/studio_app.h"
#include "editor/world_editor.h"
#include "engine/blob.h"
#include "engine/engine.h"
#include "engine/iplugin.h"
#include "engine/iproperty_descriptor.h"
#include "engine/math_utils.h"
#include "engine/prefab.h"
#include "engine/property_register.h"
#include "engine/resource.h"
#include "engine/serializer.h"
#include "engine/vec.h"
#include "imgui/imgui.h"
#include "utils.h"
#include <cmath>
#include <cstdlib>
PropertyGrid::PropertyGrid(StudioApp& app)
: m_app(app)
, m_is_opened(true)
, m_editor(*app.getWorldEditor())
, m_plugins(app.getWorldEditor()->getAllocator())
{
m_particle_emitter_updating = true;
m_particle_emitter_timescale = 1.0f;
m_component_filter[0] = '\0';
}
PropertyGrid::~PropertyGrid()
{
for (auto* i : m_plugins)
{
LUMIX_DELETE(m_editor.getAllocator(), i);
}
}
void PropertyGrid::showProperty(Lumix::IPropertyDescriptor& desc,
int index,
const Lumix::Array<Lumix::Entity>& entities,
Lumix::ComponentType cmp_type)
{
if (desc.getType() == Lumix::IPropertyDescriptor::BLOB) return;
Lumix::OutputBlob stream(m_editor.getAllocator());
Lumix::ComponentUID first_entity_cmp;
first_entity_cmp.type = cmp_type;
first_entity_cmp.scene = m_editor.getUniverse()->getScene(cmp_type);
first_entity_cmp.entity = entities[0];
first_entity_cmp.handle = first_entity_cmp.scene->getComponent(entities[0], cmp_type);
desc.get(first_entity_cmp, index, stream);
Lumix::InputBlob tmp(stream);
Lumix::StaticString<100> desc_name(desc.getName(), "###", (Lumix::u64)&desc);
switch (desc.getType())
{
case Lumix::IPropertyDescriptor::DECIMAL:
{
float f;
tmp.read(f);
auto& d = static_cast<Lumix::INumericPropertyDescriptor<float>&>(desc);
if (d.isInRadians()) f = Lumix::Math::radiansToDegrees(f);
if ((d.getMax() - d.getMin()) / d.getStep() <= 100)
{
if (ImGui::SliderFloat(desc_name, &f, d.getMin(), d.getMax()))
{
if (d.isInRadians()) f = Lumix::Math::degreesToRadians(f);
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &f, sizeof(f));
}
}
else
{
if (ImGui::DragFloat(desc_name, &f, d.getStep(), d.getMin(), d.getMax()))
{
if (d.isInRadians()) f = Lumix::Math::degreesToRadians(f);
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &f, sizeof(f));
}
}
break;
}
case Lumix::IPropertyDescriptor::INTEGER:
{
int i;
tmp.read(i);
auto& d = static_cast<Lumix::INumericPropertyDescriptor<int>&>(desc);
if (ImGui::DragInt(desc_name, &i, (float)d.getStep(), d.getMin(), d.getMax()))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &i, sizeof(i));
}
break;
}
case Lumix::IPropertyDescriptor::UNSIGNED_INTEGER:
{
unsigned int ui;
tmp.read(ui);
int i = (int)ui;
if (ImGui::DragInt(desc_name, &i))
{
ui = (unsigned int)i;
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &ui, sizeof(ui));
}
break;
}
case Lumix::IPropertyDescriptor::BOOL:
{
bool b;
tmp.read(b);
if (ImGui::Checkbox(desc_name, &b))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &b, sizeof(b));
}
break;
}
case Lumix::IPropertyDescriptor::COLOR:
{
Lumix::Vec3 v;
tmp.read(v);
if (ImGui::ColorEdit3(desc_name, &v.x))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
if (ImGui::BeginPopupContextItem(Lumix::StaticString<50>(desc_name, "pu")))
{
if (ImGui::ColorPicker(&v.x, false))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
ImGui::EndPopup();
}
break;
}
case Lumix::IPropertyDescriptor::VEC2:
{
Lumix::Vec2 v;
tmp.read(v);
if (desc.isInRadians())
{
v.x = Lumix::Math::radiansToDegrees(v.x);
v.y = Lumix::Math::radiansToDegrees(v.y);
}
if (ImGui::DragFloat2(desc_name, &v.x))
{
if (desc.isInRadians())
{
v.x = Lumix::Math::degreesToRadians(v.x);
v.y = Lumix::Math::degreesToRadians(v.y);
}
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
break;
}
case Lumix::IPropertyDescriptor::INT2:
{
Lumix::Int2 v;
tmp.read(v);
if (ImGui::DragInt2(desc_name, &v.x))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
break;
}
case Lumix::IPropertyDescriptor::VEC3:
{
Lumix::Vec3 v;
tmp.read(v);
if (desc.isInRadians()) v = Lumix::Math::radiansToDegrees(v);
if (ImGui::DragFloat3(desc_name, &v.x))
{
if (desc.isInRadians()) v = Lumix::Math::degreesToRadians(v);
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
break;
}
case Lumix::IPropertyDescriptor::VEC4:
{
Lumix::Vec4 v;
tmp.read(v);
if (ImGui::DragFloat4(desc_name, &v.x))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &v, sizeof(v));
}
break;
}
case Lumix::IPropertyDescriptor::RESOURCE:
{
char buf[1024];
Lumix::copyString(buf, (const char*)stream.getData());
auto& resource_descriptor = static_cast<Lumix::IResourcePropertyDescriptor&>(desc);
Lumix::ResourceType rm_type = resource_descriptor.getResourceType();
if (m_app.getAssetBrowser()->resourceInput(
desc.getName(), Lumix::StaticString<20>("", (Lumix::u64)&desc), buf, sizeof(buf), rm_type))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), buf, Lumix::stringLength(buf) + 1);
}
break;
}
case Lumix::IPropertyDescriptor::STRING:
case Lumix::IPropertyDescriptor::FILE:
{
char buf[1024];
Lumix::copyString(buf, (const char*)stream.getData());
if (ImGui::InputText(desc_name, buf, sizeof(buf)))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), buf, Lumix::stringLength(buf) + 1);
}
break;
}
case Lumix::IPropertyDescriptor::ARRAY:
showArrayProperty(entities, cmp_type, static_cast<Lumix::IArrayDescriptor&>(desc));
break;
case Lumix::IPropertyDescriptor::SAMPLED_FUNCTION:
showSampledFunctionProperty(entities, cmp_type, static_cast<Lumix::ISampledFunctionDescriptor&>(desc));
break;
case Lumix::IPropertyDescriptor::ENTITY:
showEntityProperty(entities, cmp_type, index, static_cast<Lumix::IEnumPropertyDescriptor&>(desc));
break;
case Lumix::IPropertyDescriptor::ENUM:
showEnumProperty(entities, cmp_type, index, static_cast<Lumix::IEnumPropertyDescriptor&>(desc));
break;
case Lumix::IPropertyDescriptor::BLOB:
default:
ASSERT(false);
break;
}
}
void PropertyGrid::showEntityProperty(const Lumix::Array<Lumix::Entity>& entities,
Lumix::ComponentType cmp_type,
int index,
Lumix::IPropertyDescriptor& desc)
{
Lumix::OutputBlob blob(m_editor.getAllocator());
Lumix::ComponentUID cmp;
cmp.scene = m_editor.getUniverse()->getScene(cmp_type);
cmp.type = cmp_type;
cmp.entity = entities[0];
cmp.handle = cmp.scene->getComponent(cmp.entity, cmp.type);
desc.get(cmp, index, blob);
Lumix::Entity entity = *(Lumix::Entity*)blob.getData();
char buf[128];
getEntityListDisplayName(m_editor, buf, Lumix::lengthOf(buf), entity);
ImGui::LabelText(desc.getName(), "%s", buf);
ImGui::SameLine();
ImGui::PushID(desc.getName());
if (ImGui::Button("...")) ImGui::OpenPopup(desc.getName());
Lumix::Universe& universe = *m_editor.getUniverse();
if (ImGui::BeginPopup(desc.getName()))
{
for (auto i = universe.getFirstEntity(); isValid(i); i = universe.getNextEntity(i))
{
getEntityListDisplayName(m_editor, buf, Lumix::lengthOf(buf), i);
if (ImGui::Selectable(buf))
{
m_editor.setProperty(cmp_type, index, desc, &entities[0], entities.size(), &i, sizeof(i));
}
}
ImGui::EndPopup();
}
ImGui::PopID();
}
void PropertyGrid::showEnumProperty(const Lumix::Array<Lumix::Entity>& entities,
Lumix::ComponentType cmp_type,
int index,
Lumix::IEnumPropertyDescriptor& desc)
{
if(entities.size() > 1)
{
ImGui::LabelText(desc.getName(), "Multi-object editing not supported.");
return;
}
Lumix::ComponentUID cmp;
cmp.type = cmp_type;
cmp.entity = entities[0];
cmp.scene = m_editor.getUniverse()->getScene(cmp_type);
cmp.handle = cmp.scene->getComponent(cmp.entity, cmp.type);
Lumix::OutputBlob blob(m_editor.getAllocator());
desc.get(cmp, index, blob);
int value = *(int*)blob.getData();
int count = desc.getEnumCount(cmp.scene, cmp.handle);
struct Data
{
Lumix::IEnumPropertyDescriptor* descriptor;
Lumix::ComponentHandle cmp;
Lumix::IScene* scene;
};
auto getter = [](void* data, int index, const char** out) -> bool {
auto* combo_data = static_cast<Data*>(data);
*out = combo_data->descriptor->getEnumItemName(combo_data->scene, combo_data->cmp, index);
if (!*out)
{
static char buf[100];
combo_data->descriptor->getEnumItemName(
combo_data->scene, combo_data->cmp, index, buf, Lumix::lengthOf(buf));
*out = buf;
}
return true;
};
Data data;
data.cmp = cmp.handle;
data.scene = cmp.scene;
data.descriptor = &desc;
if (ImGui::Combo(desc.getName(), &value, getter, &data, count))
{
m_editor.setProperty(cmp.type, index, desc, &cmp.entity, 1, &value, sizeof(value));
}
}
void PropertyGrid::showSampledFunctionProperty(const Lumix::Array<Lumix::Entity>& entities,
Lumix::ComponentType cmp_type,
Lumix::ISampledFunctionDescriptor& desc)
{
static const int MIN_COUNT = 6;
Lumix::OutputBlob blob(m_editor.getAllocator());
Lumix::ComponentUID cmp;
cmp.type = cmp_type;
cmp.entity = entities[0];
cmp.scene = m_editor.getUniverse()->getScene(cmp_type);
cmp.handle = cmp.scene->getComponent(cmp.entity, cmp.type);
desc.get(cmp, -1, blob);
int count;
Lumix::InputBlob input(blob);
input.read(count);
Lumix::Vec2* f = (Lumix::Vec2*)input.skip(sizeof(Lumix::Vec2) * count);
auto editor = ImGui::BeginCurveEditor(desc.getName());
if (editor.valid)
{
bool changed = false;
changed |= ImGui::CurveSegment((ImVec2*)(f + 1), editor);
for (int i = 1; i < count - 3; i += 3)
{
changed |= ImGui::CurveSegment((ImVec2*)(f + i), editor);
if (changed)
{
f[i + 3].x = Lumix::Math::maximum(f[i].x + 0.001f, f[i + 3].x);
if (i + 3 < count)
{
f[i + 3].x = Lumix::Math::minimum(f[i + 6].x - 0.001f, f[i + 3].x);
}
}
if (ImGui::IsItemActive() && ImGui::IsMouseDoubleClicked(0)
&& count > MIN_COUNT && i + 3 < count - 2)
{
for (int j = i + 2; j < count - 3; ++j)
{
f[j] = f[j + 3];
}
count -= 3;
*(int*)blob.getData() = count;
changed = true;
}
}
f[count - 2].x = 1;
f[1].x = 0;
ImGui::EndCurveEditor(editor);
if (ImGui::IsItemActive() && ImGui::IsMouseDoubleClicked(0))
{
auto mp = ImGui::GetMousePos();
mp.x -= editor.inner_bb_min.x - 1;
mp.y -= editor.inner_bb_min.y - 1;
mp.x /= (editor.inner_bb_max.x - editor.inner_bb_min.x);
mp.y /= (editor.inner_bb_max.y - editor.inner_bb_min.y);
mp.y = 1 - mp.y;
blob.write(ImVec2(-0.2f, 0));
blob.write(mp);
blob.write(ImVec2(0.2f, 0));
count += 3;
*(int*)blob.getData() = count;
f = (Lumix::Vec2*)((int*)blob.getData() + 1);
changed = true;
auto compare = [](const void* a, const void* b) -> int
{
float fa = ((const float*)a)[2];
float fb = ((const float*)b)[2];
return fa < fb ? -1 : (fa > fb) ? 1 : 0;
};
qsort(f, count / 3, 3 * sizeof(f[0]), compare);
}
if (changed)
{
for (int i = 2; i < count - 3; i += 3)
{
auto prev_p = ((Lumix::Vec2*)f)[i - 1];
auto next_p = ((Lumix::Vec2*)f)[i + 2];
auto& tangent = ((Lumix::Vec2*)f)[i];
auto& tangent2 = ((Lumix::Vec2*)f)[i + 1];
float half = 0.5f * (next_p.x - prev_p.x);
tangent = tangent.normalized() * half;
tangent2 = tangent2.normalized() * half;
}
f[0].x = 0;
f[count - 1].x = desc.getMaxX();
m_editor.setProperty(cmp_type, -1, desc, &entities[0], entities.size(), blob.getData(), blob.getPos());
}
}
}
void PropertyGrid::showArrayProperty(const Lumix::Array<Lumix::Entity>& entities,
Lumix::ComponentType cmp_type,
Lumix::IArrayDescriptor& desc)
{
Lumix::ComponentUID cmp;
cmp.type = cmp_type;
cmp.scene = m_editor.getUniverse()->getScene(cmp_type);
cmp.entity = entities[0];
cmp.handle = cmp.scene->getComponent(cmp.entity, cmp.type);
Lumix::StaticString<100> desc_name(desc.getName(), "###", (Lumix::u64)&desc);
if (!ImGui::CollapsingHeader(desc_name, nullptr, ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_DefaultOpen)) return;
if (entities.size() > 1)
{
ImGui::Text("Multi-object editing not supported.");
return;
}
int count = desc.getCount(cmp);
if (desc.canAdd() && ImGui::Button("Add"))
{
m_editor.addArrayPropertyItem(cmp, desc);
}
count = desc.getCount(cmp);
for (int i = 0; i < count; ++i)
{
char tmp[10];
Lumix::toCString(i, tmp, sizeof(tmp));
ImGui::PushID(i);
if (!desc.canRemove() || ImGui::TreeNode(tmp))
{
if (desc.canRemove() && ImGui::Button("Remove"))
{
m_editor.removeArrayPropertyItem(cmp, i, desc);
--i;
count = desc.getCount(cmp);
ImGui::TreePop();
ImGui::PopID();
continue;
}
for (int j = 0; j < desc.getChildren().size(); ++j)
{
auto* child = desc.getChildren()[j];
showProperty(*child, i, entities, cmp_type);
}
if (desc.canRemove()) ImGui::TreePop();
}
ImGui::PopID();
}
}
void PropertyGrid::showComponentProperties(const Lumix::Array<Lumix::Entity>& entities, Lumix::ComponentType cmp_type)
{
ImGuiTreeNodeFlags flags =
ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_AllowOverlapMode;
bool is_opened = ImGui::CollapsingHeader(m_app.getComponentTypeName(cmp_type), nullptr, flags);
ImGui::PushID(cmp_type.index);
float w = ImGui::GetContentRegionAvailWidth();
ImGui::SameLine(w - 45);
if (ImGui::Button("Remove"))
{
m_editor.destroyComponent(&entities[0], entities.size(), cmp_type);
ImGui::PopID();
return;
}
if (!is_opened)
{
ImGui::PopID();
return;
}
auto& descs = Lumix::PropertyRegister::getDescriptors(cmp_type);
for (auto* desc : descs)
{
showProperty(*desc, -1, entities, cmp_type);
}
if (entities.size() == 1)
{
Lumix::ComponentUID cmp;
cmp.type = cmp_type;
cmp.scene = m_editor.getUniverse()->getScene(cmp.type);
cmp.entity = entities[0];
cmp.handle = cmp.scene->getComponent(cmp.entity, cmp.type);
for (auto* i : m_plugins)
{
i->onGUI(*this, cmp);
}
}
ImGui::PopID();
}
bool PropertyGrid::entityInput(const char* label, const char* str_id, Lumix::Entity& entity) const
{
const auto& style = ImGui::GetStyle();
float item_w = ImGui::CalcItemWidth();
ImGui::PushItemWidth(
item_w - ImGui::CalcTextSize("...").x - style.FramePadding.x * 2 - style.ItemSpacing.x);
char buf[50];
getEntityListDisplayName(m_editor, buf, sizeof(buf), entity);
ImGui::LabelText("", "%s", buf);
ImGui::SameLine();
Lumix::StaticString<30> popup_name("pu", str_id);
if (ImGui::Button(Lumix::StaticString<30>("...###br", str_id)))
{
ImGui::OpenPopup(popup_name);
}
if (ImGui::IsItemHoveredRect())
{
if (ImGui::IsMouseReleased(0) && m_app.getDragData().type == StudioApp::DragData::ENTITY)
{
entity = *(Lumix::Entity*)m_app.getDragData().data;
return true;
}
}
ImGui::SameLine();
ImGui::Text("%s", label);
ImGui::PopItemWidth();
if (ImGui::BeginPopup(popup_name))
{
if (isValid(entity))
{
if (ImGui::Button("Select current")) m_editor.selectEntities(&entity, 1);
ImGui::SameLine();
if (ImGui::Button("Empty"))
{
entity = Lumix::INVALID_ENTITY;
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
return true;
}
}
Lumix::Universe* universe = m_editor.getUniverse();
static int current_item;
if (ImGui::ListBoxHeader("Entities"))
{
for (auto i = universe->getFirstEntity(); isValid(i); i = universe->getNextEntity(i))
{
getEntityListDisplayName(m_editor, buf, Lumix::lengthOf(buf), i);
if (ImGui::Selectable(buf))
{
ImGui::ListBoxFooter();
entity = i;
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
return true;
}
}
ImGui::ListBoxFooter();
}
ImGui::EndPopup();
}
return false;
}
void PropertyGrid::showCoreProperties(const Lumix::Array<Lumix::Entity>& entities)
{
if (entities.size() == 1)
{
Lumix::PrefabSystem& prefab_system = m_editor.getPrefabSystem();
Lumix::PrefabResource* prefab = prefab_system.getPrefabResource(entities[0]);
if (prefab)
{
ImGui::SameLine();
if (ImGui::Button("Save prefab"))
{
prefab_system.savePrefab(prefab->getPath());
}
}
char name[256];
ImGui::LabelText("ID", "%d", entities[0].index);
Lumix::EntityGUID guid = m_editor.getEntityGUID(entities[0]);
if (guid == Lumix::INVALID_ENTITY_GUID)
{
ImGui::LabelText("GUID", "%s", "runtime");
}
else
{
char guid_str[32];
Lumix::toCString(guid.value, guid_str, Lumix::lengthOf(guid_str));
ImGui::LabelText("GUID", "%s", guid_str);
}
Lumix::Entity parent = m_editor.getUniverse()->getParent(entities[0]);
if (isValid(parent))
{
getEntityListDisplayName(m_editor, name, Lumix::lengthOf(name), parent);
ImGui::LabelText("Parent", "%s", name);
Lumix::Transform tr = m_editor.getUniverse()->getLocalTransform(entities[0]);
Lumix::Vec3 old_pos = tr.pos;
if (ImGui::DragFloat3("Local position", &tr.pos.x))
{
Lumix::WorldEditor::Coordinate coord;
if (tr.pos.x != old_pos.x) coord = Lumix::WorldEditor::Coordinate::X;
if (tr.pos.y != old_pos.y) coord = Lumix::WorldEditor::Coordinate::Y;
if (tr.pos.z != old_pos.z) coord = Lumix::WorldEditor::Coordinate::Z;
m_editor.setEntitiesLocalCoordinate(&entities[0], entities.size(), (&tr.pos.x)[(int)coord], coord);
}
}
const char* tmp = m_editor.getUniverse()->getEntityName(entities[0]);
Lumix::copyString(name, tmp);
if (ImGui::InputText("Name", name, sizeof(name))) m_editor.setEntityName(entities[0], name);
}
else
{
ImGui::LabelText("ID", "%s", "Multiple objects");
ImGui::LabelText("Name", "%s", "Multi-object editing not supported.");
}
Lumix::Vec3 pos = m_editor.getUniverse()->getPosition(entities[0]);
Lumix::Vec3 old_pos = pos;
if (ImGui::DragFloat3("Position", &pos.x))
{
Lumix::WorldEditor::Coordinate coord;
if (pos.x != old_pos.x) coord = Lumix::WorldEditor::Coordinate::X;
if (pos.y != old_pos.y) coord = Lumix::WorldEditor::Coordinate::Y;
if (pos.z != old_pos.z) coord = Lumix::WorldEditor::Coordinate::Z;
m_editor.setEntitiesCoordinate(&entities[0], entities.size(), (&pos.x)[(int)coord], coord);
}
Lumix::Universe* universe = m_editor.getUniverse();
Lumix::Quat rot = universe->getRotation(entities[0]);
Lumix::Vec3 old_euler = rot.toEuler();
Lumix::Vec3 euler = Lumix::Math::radiansToDegrees(old_euler);
if (ImGui::DragFloat3("Rotation", &euler.x))
{
if (euler.x <= -90.0f || euler.x >= 90.0f) euler.y = 0;
euler.x = Lumix::Math::degreesToRadians(Lumix::Math::clamp(euler.x, -90.0f, 90.0f));
euler.y = Lumix::Math::degreesToRadians(fmodf(euler.y + 180, 360.0f) - 180);
euler.z = Lumix::Math::degreesToRadians(fmodf(euler.z + 180, 360.0f) - 180);
rot.fromEuler(euler);
Lumix::Array<Lumix::Quat> rots(m_editor.getAllocator());
for (Lumix::Entity entity : entities)
{
Lumix::Vec3 tmp = universe->getRotation(entity).toEuler();
if (fabs(euler.x - old_euler.x) > 0.01f) tmp.x = euler.x;
if (fabs(euler.y - old_euler.y) > 0.01f) tmp.y = euler.y;
if (fabs(euler.z - old_euler.z) > 0.01f) tmp.z = euler.z;
rots.emplace().fromEuler(tmp);
}
m_editor.setEntitiesRotations(&entities[0], &rots[0], entities.size());
}
float scale = m_editor.getUniverse()->getScale(entities[0]);
if (ImGui::DragFloat("Scale", &scale, 0.1f))
{
m_editor.setEntitiesScale(&entities[0], entities.size(), scale);
}
}
static void showAddComponentNode(const StudioApp::AddCmpTreeNode* node, const char* filter)
{
if (!node) return;
if (filter[0])
{
if (!node->plugin) showAddComponentNode(node->child, filter);
else if (Lumix::stristr(node->plugin->getLabel(), filter)) node->plugin->onGUI(false, true);
showAddComponentNode(node->next, filter);
return;
}
if (node->plugin)
{
node->plugin->onGUI(false, false);
showAddComponentNode(node->next, filter);
return;
}
const char* last = Lumix::reverseFind(node->label, nullptr, '/');
if (ImGui::BeginMenu(last ? last + 1 : node->label))
{
showAddComponentNode(node->child, filter);
ImGui::EndMenu();
}
showAddComponentNode(node->next, filter);
}
void PropertyGrid::onGUI()
{
auto& ents = m_editor.getSelectedEntities();
if (ImGui::BeginDock("Properties", &m_is_opened) && !ents.empty())
{
if (ImGui::Button("Add component"))
{
ImGui::OpenPopup("AddComponentPopup");
}
if (ImGui::BeginPopup("AddComponentPopup"))
{
ImGui::FilterInput("Filter", m_component_filter, sizeof(m_component_filter));
showAddComponentNode(m_app.getAddComponentTreeRoot().child, m_component_filter);
ImGui::EndPopup();
}
showCoreProperties(ents);
Lumix::Universe& universe = *m_editor.getUniverse();
for (Lumix::ComponentUID cmp = universe.getFirstComponent(ents[0]); cmp.isValid();
cmp = universe.getNextComponent(cmp))
{
showComponentProperties(ents, cmp.type);
}
}
ImGui::EndDock();
}