/*
GameEngine and Editor
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Component Type Editor View
#include "ComponentTypeEditorView.h"
#include "IconsFontAwesome5.h"
#include "IUiSystem.h"
#include "SchemaEdit.h"
#include "imgui.h"
#include <algorithm>
namespace GameEngine {
ComponentTypeEditorView::ComponentTypeEditorView(const ApplicationFramework::IApplication& app,
const EcsSystem& entityComponentSystem)
: m_application(app)
, m_entityComponentSystem(entityComponentSystem)
{
}
void ComponentTypeEditorView::AddShowMenuItem()
{
ImGui::MenuItem("Show Component Type Editor", NULL, &m_open);
}
static
void ShowFieldTypes(GameRuntime::Schema* schema, GameRuntime::VariableDescription* vars, int count, int iconFontIndex)
{
for (int i = 0; i < count; ++i)
{
auto& var = vars[i];
if (var.variableType == GameRuntime::VariableTypeEnum::E_Struct)
{
if (ImGui::TreeNodeEx(ConvertRuntimeString(schema, var.name).c_str(), ImGuiTreeNodeFlags_DefaultOpen | ImGuiTreeNodeFlags_SpanFullWidth))
{
ShowFieldTypes(schema, schema->variables->variables + var.structDescription.variableDescriptionTableOffset, var.structDescription.numberOfFields, iconFontIndex);
ImGui::TreePop();
}
}
else
{
std::string entName = ConvertRuntimeString(schema, var.name);
entName += "##" + std::to_string((size_t)&var);
const char* varTypes[] = {
"E_Void", "E_Bool", "E_Enum", "E_String", "E_Number", "E_EncodedNumber", "E_Color", "E_Entity", "E_Asset" // , "E_Struct", "E_Component"
};
//ImGui::NewLine();
ImGui::PushItemWidth(100);
//IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
//IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true!
//IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
//IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
//ImGui::InputText(entName.c_str());
ImGui::Combo(entName.c_str(), (int*)&var.variableType, varTypes, IM_ARRAYSIZE(varTypes));
ImGui::SameLine(200);
const char* strLens[] = { "32", "64", "128", "256", "512" };
int strLensCount[] = { 32, 64, 128, 256, 512 };
//int tmpMaxCharacterCount = 0;
//while (var.stringDescription.maximumCharacterCount < )
const char* numTypes[] = {
"E_UInt8", "E_UInt16", "E_UInt32", "E_UInt64", "E_Int8", "E_Int16", "E_Int32", "E_Int64", "E_Float32", "E_Float64", "E_Angle", "E_Ratio"
};
const char* colorTypes[] = {
"E_RGB32", "E_RGBA32"
};
switch (var.variableType)
{
case GameRuntime::VariableTypeEnum::E_Enum:
// Enter list of name values
break;
case GameRuntime::VariableTypeEnum::E_String:
ImGui::Combo("String length", (int*)&var.stringDescription.maximumCharacterCount, strLens, IM_ARRAYSIZE(strLens));
break;
case GameRuntime::VariableTypeEnum::E_Number:
ImGui::Combo("Number type", (int*)&var.numberDescription.numberType, numTypes, IM_ARRAYSIZE(numTypes));
break;
//case GameRuntime::E_EncodedNumber:
// break;
case GameRuntime::VariableTypeEnum::E_Color:
ImGui::Combo("Color type", (int*)&var.colorDescription.colorType, colorTypes, IM_ARRAYSIZE(colorTypes));
break;
default:
break;
}
ImGui::PushItemWidth(10);
// ImGui::Button(("X##" + std::to_string((size_t)&var)).c_str());
// TODO : still need to work on these:
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[iconFontIndex]);
ImGui::SameLine(360);
ImGui::Button((ICON_FA_CARET_DOWN "##" + entName).c_str());
ImGui::SameLine(375);
ImGui::Button((ICON_FA_CARET_UP "##" + entName).c_str());
ImGui::SameLine(390);
ImGui::Button((ICON_FA_GRIP_VERTICAL "##" + entName).c_str());
ImGui::SameLine(405);
ImGui::Button((/*ICON_FA_CLOSE*/ "X" "##" + entName).c_str());
ImGui::PopFont();
//ImGui::Selectable(std::to_string((size_t)&var).c_str());
if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
{
int n_next = i + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
if (n_next >= 0 && n_next < count)
{
auto varCopy = var;
vars[i] = vars[n_next];
vars[n_next] = varCopy;
ImGui::ResetMouseDragDelta();
}
}
ImGui::PopItemWidth();
ImGui::PopItemWidth();
//ImGui::NewLine();
//ImGui::Spacing();
}
}
}
void ComponentTypeEditorView::Update()
{
if (!m_open)
return;
if (ImGui::Begin("Component Editor", &m_open))
{
StringList compTypes = m_entityComponentSystem.AllComponentTypeNames();
compTypes.insert(compTypes.begin(), "*New*");
ImGui::Text("Component:");
ImGui::Separator();
static int item_current_idx = 0; // Here we store our selection data as an index.
if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 10.7 * ImGui::GetTextLineHeightWithSpacing())))
{
for (int n = 0; n < compTypes.size(); n++)
{
const bool is_selected = (item_current_idx == n);
if (ImGui::Selectable(compTypes[n].c_str(), is_selected))
item_current_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndListBox();
}
ImGui::Separator();
ImGui::Text("Layout:");
std::string selectedComponent = compTypes[item_current_idx];
auto componentTypeId = m_entityComponentSystem.FindComponentTypeByName(selectedComponent);
ImGui::Text("Selected Index: %i", item_current_idx);
ImGui::Text("Selected Component: %s", selectedComponent.c_str());
ImGui::Text("Selected ComponentId: %lu", componentTypeId);
if (componentTypeId != -1ULL)
{
auto schema = m_entityComponentSystem.GetSchema();
auto& compRef = m_entityComponentSystem.GetComponentType(componentTypeId);
//if (ImGui::CollapsingHeader(compRef.name.c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
auto* vars = schema->variables->variables + compRef.fields.variableDescriptionTableOffset;
ShowFieldTypes(schema, vars, compRef.fields.numberOfFields, m_application.UiSystem()->IconFontIndex());
}
}
ImGui::Separator();
static int clicked = 0;
if (ImGui::Button("Add Field"))
clicked++;
if (clicked & 1)
{
ImGui::Begin("Fields", &m_open);
StringList compTypes = m_entityComponentSystem.AllComponentTypeNames();
std::vector<const char*> compTypesCStr;
for (auto& ct : compTypes)
compTypesCStr.emplace_back(ct.c_str());
static int item_current = 0;
ImGui::SameLine();
if (ImGui::ListBox(" ", &item_current, compTypesCStr.data(), compTypesCStr.size(), 10))
{
clicked++;
std::string compTypeSelected = compTypes[item_current];
auto compTypeId = m_entityComponentSystem.FindComponentTypeByName(compTypeSelected);
printf(" component selected: %s id: %lu\n", compTypeSelected.c_str(), compTypeId);
}
ImGui::End();
}
}
ImGui::End();
}
void ComponentTypeEditorView::Initialize()
{
}
void ComponentTypeEditorView::Shutdown()
{
}
void ComponentTypeEditorView::Show()
{
}
} // GameEngine namespace