#include "inspect.hpp" #include "compat/assert.hpp" #include "compat/defs.hpp" #include "entity/accessor.hpp" #include "imgui-raii.hpp" #include #include #include #include #include #include #include namespace floormat { namespace { String label_left(StringView label) { float width = ImGui::CalcItemWidth(), x = ImGui::GetCursorPosX(); ImGui::Text("%s", label.data()); ImGui::SameLine(); ImGui::SetCursorPosX(x + width*.5f + ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SetNextItemWidth(-1); return ""_s.join(StringIterable({ "##"_s, label })); } template struct is_magnum_vector_ final : std::false_type {}; template struct is_magnum_vector_> : std::true_type {}; template struct is_magnum_vector_> : std::true_type {}; template struct is_magnum_vector_> : std::true_type {}; template struct is_magnum_vector_> : std::true_type {}; template constexpr bool is_magnum_vector = is_magnum_vector_::value; template struct IGDT_; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template<> struct IGDT_ : std::integral_constant {}; template constexpr auto IGDT = IGDT_::value; using namespace imgui; using namespace entities; template void do_inspect_field(void* datum, const erased_accessor& accessor, field_repr repr) { fm_assert(accessor.check_field_name()); bool should_disable; switch (accessor.is_enabled(datum)) { using enum field_status; case hidden: return; case readonly: should_disable = true; break; case enabled: should_disable = false; break; } should_disable = should_disable || !accessor.can_write(); [[maybe_unused]] auto disabler = begin_disabled(should_disable); bool ret = false; const auto label = label_left(accessor.field_name); T value{}; accessor.read_fun(datum, accessor.reader, &value); auto orig = value; if constexpr (!is_magnum_vector) { auto [min, max] = accessor.get_range(datum).convert(); constexpr auto igdt = IGDT; switch (repr) { case field_repr::input: ret = ImGui::InputScalar(label.data(), igdt, &value); break; case field_repr::slider: ret = ImGui::SliderScalar(label.data(), igdt, &value, &min, &max); break; case field_repr::drag: ret = ImGui::DragScalar(label.data(), igdt, &value, 1, &min, &max); break; } value = std::clamp(value, min, max); } else { auto [min, max] = accessor.get_range(datum).convert(); constexpr auto igdt = IGDT; switch (repr) { case field_repr::input: ret = ImGui::InputScalarN(label.data(), igdt, &value, T::Size); break; case field_repr::drag: fm_warn_once("can't use imgui input drag mode for vector type"); [[fallthrough]]; case field_repr::slider: ret = ImGui::SliderScalarN(label.data(), igdt, &value, T::Size, &min, &max); break; } for (std::size_t i = 0; i < T::Size; i++) value[i] = std::clamp(value[i], min[i], max[i]); } ImGui::NewLine(); if (ret && !should_disable && value != orig) if (accessor.is_enabled(datum) >= field_status::enabled && accessor.can_write()) accessor.write_fun(datum, accessor.writer, &value); } } // namespace #define MAKE_SPEC(type, repr) \ template<> void inspect_field(void* datum, const erased_accessor& accessor) { \ do_inspect_field(datum, accessor, (repr)); \ } #define MAKE_SPEC_REPR(type, repr) \ template<> void inspect_field>(void* datum, const erased_accessor& accessor) { \ do_inspect_field(datum, accessor, (repr)); \ } #define MAKE_SPEC_REPRS(type) \ MAKE_SPEC_REPR(type, field_repr::input) \ MAKE_SPEC_REPR(type, field_repr::slider) \ MAKE_SPEC_REPR(type, field_repr::drag) \ MAKE_SPEC(type, field_repr::input) #define MAKE_SPEC_REPRS2(type) \ MAKE_SPEC_REPRS(Math::Vector2) \ MAKE_SPEC_REPRS(Math::Vector3) \ MAKE_SPEC_REPRS(Math::Vector4) \ MAKE_SPEC_REPRS(type) MAKE_SPEC_REPRS2(std::uint8_t) MAKE_SPEC_REPRS2(std::int8_t) MAKE_SPEC_REPRS2(std::uint16_t) MAKE_SPEC_REPRS2(std::int16_t) MAKE_SPEC_REPRS2(std::uint32_t) MAKE_SPEC_REPRS2(std::int32_t) } // namespace floormat