Files
Nuake-custom/Nuake/Source/Nuake/UI/WidgetDrawer.h
2025-04-03 21:26:54 -04:00

269 lines
6.8 KiB
C++

#pragma once
#include "Nuake/Core/Object/Object.h"
#include <entt/entt.hpp>
#include <imgui/imgui.h>
#include <functional>
#include <unordered_map>
namespace Nuake
{
using DrawWidgetTypeFn = std::function<void(entt::meta_data& fieldMeta, entt::meta_any& instance)>;
class WidgetDrawer
{
public:
WidgetDrawer()
{
RegisterDefaulWidgets();
}
~WidgetDrawer() = default;
static WidgetDrawer& Get()
{
static WidgetDrawer instance;
return instance;
}
void RegisterDefaulWidgets()
{
auto& drawer = Get();
drawer.RegisterTypeDrawer<float, &WidgetDrawer::DrawFloat>(&drawer);
drawer.RegisterTypeDrawer<bool, &WidgetDrawer::DrawBool>(&drawer);
drawer.RegisterTypeDrawer<std::string, &WidgetDrawer::DrawString>(&drawer);
drawer.RegisterTypeDrawer<Vector2, &WidgetDrawer::DrawVector2>(&drawer);
drawer.RegisterTypeDrawer<Vector3, &WidgetDrawer::DrawVector3>(&drawer);
drawer.RegisterTypeDrawer<DynamicItemList, &WidgetDrawer::DrawDynamicItemList>(&drawer);
}
void DrawFloat(entt::meta_data& type, entt::meta_any& instance)
{
float stepSize = 1.f;
if (auto prop = type.prop(HashedFieldPropName::FloatStep))
stepSize = *prop.value().try_cast<float>();
float min = 0.f;
if (auto prop = type.prop(HashedFieldPropName::FloatMin))
min = *prop.value().try_cast<float>();
float max = 0.f;
if (auto prop = type.prop(HashedFieldPropName::FloatMax))
max = *prop.value().try_cast<float>();
auto propDisplayName = type.prop(HashedName::DisplayName);
const char* displayName = *propDisplayName.value().try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = type.get(instance);
float* floatPtr = fieldVal.try_cast<float>();
if (floatPtr != nullptr)
{
float floatProxy = *floatPtr;
const std::string controlId = std::string("##") + displayName;
if (ImGui::DragFloat(controlId.c_str(), &floatProxy, stepSize, min, max))
{
type.set(instance, floatProxy);
}
}
else
{
ImGui::Text("ERR");
}
}
}
void DrawBool(entt::meta_data& type, entt::meta_any& instance)
{
auto prop = type.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = type.get(instance);
bool* boolPtr = fieldVal.try_cast<bool>();
if (boolPtr != nullptr)
{
bool boolProxy = *boolPtr;
std::string controlId = std::string("##") + displayName;
if (ImGui::Checkbox(controlId.c_str(), &boolProxy))
{
type.set(instance, boolProxy);
}
}
else
{
ImGui::Text("ERR");
}
}
}
void DrawString(entt::meta_data& type, entt::meta_any& instance)
{
auto prop = type.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = type.get(instance);
std::string* fieldValPtr = fieldVal.try_cast<std::string>();
if (fieldValPtr != nullptr)
{
std::string fieldValProxy = *fieldValPtr;
std::string controlId = std::string("##") + displayName;
ImGui::InputText(controlId.c_str(), &fieldValProxy);
if (fieldValProxy != *fieldValPtr)
{
type.set(instance, fieldValProxy);
}
}
else
{
ImGui::Text("ERR");
}
}
}
void DrawVector2(entt::meta_data& field, entt::meta_any& component)
{
auto prop = field.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
Vector2* vec2Ptr = fieldVal.try_cast<Vector2>();
std::string controlId = std::string("##") + displayName;
ImGui::PushID(controlId.c_str());
if (ImGuiHelper::DrawVec2(controlId, vec2Ptr, 0.5f, 100.0, 0.01f))
{
field.set(component, *vec2Ptr);
Engine::GetProject()->IsDirty = true;
}
ImGui::PopID();
}
}
void DrawVector3(entt::meta_data& field, entt::meta_any& component)
{
auto prop = field.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
Vector3* vec3Ptr = fieldVal.try_cast<Vector3>();
std::string controlId = std::string("##") + displayName;
ImGui::PushID(controlId.c_str());
if (ImGuiHelper::DrawVec3(controlId, vec3Ptr, 0.5f, 100.0, 0.01f))
{
field.set(component, *vec3Ptr);
Engine::GetProject()->IsDirty = true;
}
ImGui::PopID();
}
}
void DrawDynamicItemList(entt::meta_data& field, entt::meta_any& component)
{
auto propDisplayName = field.prop(HashedName::DisplayName);
const char* displayName = *propDisplayName.value().try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
auto fieldValPtr = fieldVal.try_cast<DynamicItemList>();
if (fieldValPtr == nullptr)
{
ImGui::Text("ERR");
}
const auto& items = fieldValPtr->items;
const int index = fieldValPtr->index;
// Check first to see if we are within the bounds
std::string selectedStr = "";
if (index >= 0 || index < items.size())
{
selectedStr = items[index];
}
std::string controlName = std::string("##") + displayName;
if (ImGui::BeginCombo(controlName.c_str(), selectedStr.c_str()))
{
for (int i = 0; i < items.size(); i++)
{
bool isSelected = (index == i);
std::string name = items[i];
if (name.empty())
{
name = "Empty";
}
if (ImGui::Selectable(name.c_str(), isSelected))
{
field.set(component, i);
}
if (isSelected)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
}
void DrawWidget(entt::meta_data& dataType, entt::meta_any& instance)
{
entt::id_type dataId = dataType.type().id();
if (WidgetTypeDrawers.contains(dataId))
{
auto& drawerFn = WidgetTypeDrawers[dataId];
drawerFn(dataType, instance);
}
else
{
ImGui::Text("ERR");
}
}
template<class T, auto Func, class O>
void RegisterTypeDrawer(O* o)
{
WidgetTypeDrawers[entt::type_id<T>().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2);
}
private:
std::unordered_map<entt::id_type, DrawWidgetTypeFn> WidgetTypeDrawers;
};
}