1#ifndef ENTT_TOOLS_DAVEY_HPP
2#define ENTT_TOOLS_DAVEY_HPP
9#include "../entity/mixin.hpp"
10#include "../entity/registry.hpp"
11#include "../entity/sparse_set.hpp"
12#include "../entity/storage.hpp"
13#include "../locator/locator.hpp"
14#include "../meta/container.hpp"
15#include "../meta/context.hpp"
16#include "../meta/meta.hpp"
17#include "../meta/pointer.hpp"
18#include "../meta/resolve.hpp"
25template<
typename Entity,
typename OnEntity>
26static void present_element(
const meta_any &obj, OnEntity on_entity) {
27 for([[maybe_unused]]
const auto [
id, data]: obj.type().data()) {
28 const auto elem = data.get(obj);
29 const char *label = data.name() ? data.name() : std::string{data.type().info().name()}.data();
31 if(
auto type = data.type(); type.info() == type_id<const char *>()) {
32 ImGui::Text(
"%s: %s", label, elem.template cast<const char *>());
33 }
else if(type.info() == type_id<std::string>()) {
34 ImGui::Text(
"%s: %s", label, elem.template cast<const std::string &>().data());
35 }
else if(type.info() == type_id<Entity>()) {
36 if(
const auto entt = elem.template cast<Entity>(); entt == null) {
37 ImGui::Text(
"%s: %s", label,
"null");
39 on_entity(label, entt);
41 }
else if(type.is_enum()) {
42 const char *as_string =
nullptr;
44 for(
auto [
id, curr]: type.data()) {
45 if(curr.get({}) == elem) {
46 as_string = curr.name();
52 ImGui::Text(
"%s: %s", label, as_string);
54 ImGui::Text(
"%s: %zu", label, elem.template allow_cast<std::uint64_t>().template cast<std::uint64_t>());
56 }
else if(type.is_arithmetic()) {
57 if(type.info() == type_id<bool>()) {
58 std::stringstream buffer{};
59 buffer << std::boolalpha << elem.template cast<bool>();
60 ImGui::Text(
"%s: %s", label, buffer.str().data());
61 }
else if(type.info() == type_id<char>()) {
62 ImGui::Text(
"%s: %c", label, elem.template cast<char>());
63 }
else if(type.is_integral()) {
64 ImGui::Text(
"%s: %zu", label, elem.template allow_cast<std::uint64_t>().template cast<std::uint64_t>());
66 ImGui::Text(
"%s: %f", label, elem.template allow_cast<double>().template cast<double>());
68 }
else if(type.is_pointer_like()) {
69 if(
auto deref = *obj; deref) {
70 if(ImGui::TreeNode(label)) {
71 present_element<Entity>(*obj, on_entity);
75 ImGui::Text(
"%s: %s", label,
"null");
77 }
else if(type.is_sequence_container()) {
78 if(ImGui::TreeNode(label)) {
79 meta_sequence_container
view = elem.as_sequence_container();
81 for(std::size_t pos{}, last =
view.size(); pos < last; ++pos) {
82 ImGui::PushID(
static_cast<int>(pos));
84 if(ImGui::TreeNode(label,
"%zu", pos)) {
85 present_element<Entity>(view[pos], on_entity);
94 }
else if(type.is_associative_container()) {
95 if(ImGui::TreeNode(label)) {
96 meta_associative_container
view = elem.as_associative_container();
97 auto it =
view.begin();
99 for(std::size_t pos{}, last =
view.size(); pos < last; ++pos, ++it) {
100 ImGui::PushID(
static_cast<int>(pos));
102 if(ImGui::TreeNode(label,
"%zu", pos)) {
103 const auto [key, value] = *it;
105 if(ImGui::TreeNode(
"key")) {
106 present_element<Entity>(key, on_entity);
110 if(ImGui::TreeNode(
"value")) {
111 present_element<Entity>(value, on_entity);
123 }
else if(type.is_class()) {
124 if(ImGui::TreeNode(label)) {
125 present_element<Entity>(elem, on_entity);
129 const std::string underlying_type{data.type().info().name()};
130 ImGui::Text(
"%s: %s", label, underlying_type.data());
135template<
typename Entity,
typename Allocator>
136static void present_storage(
const meta_ctx &ctx,
const basic_sparse_set<Entity, Allocator> &storage) {
138 for(
auto entt: storage) {
139 ImGui::PushID(
static_cast<int>(
to_entity(entt)));
142 if(
const auto obj = type.from_void(
storage.
value(entt)); obj) {
143 present_element<
typename std::decay_t<
decltype(
storage)>::entity_type>(obj, [](
const char *name,
const Entity entt) {
154 for(
auto entt: storage) {
160template<
typename Entity,
typename It>
161static void present_entity(
const meta_ctx &ctx,
const Entity entt,
const It from,
const It to) {
162 for(
auto it = from; it != to; ++it) {
165 const char *label = type.name() ? type.name() : std::string{
storage.
info().
name()}.data();
167 if(ImGui::TreeNode(&
storage.
info(),
"%s", label)) {
168 if(
const auto obj = type.from_void(
storage.
value(entt)); obj) {
169 present_element<Entity>(obj, [&ctx, from, to](
const char *name,
const Entity other) {
171 present_entity<Entity>(ctx, other, from, to);
181 ImGui::Text(
"%s", name.data());
187template<
typename... Get,
typename... Exclude, std::size_t... Index>
188static void present_view(
const meta_ctx &ctx,
const basic_view<get_t<Get...>, exclude_t<Exclude...>> &view, std::index_sequence<Index...>) {
189 using view_type =
basic_view<get_t<Get...>, exclude_t<Exclude...>>;
190 const std::array<
const typename view_type::common_type *,
sizeof...(Index)> range{
view.template storage<Index>()...};
192 for(
auto tup:
view.each()) {
193 const auto entt = std::get<0>(tup);
194 ImGui::PushID(
static_cast<int>(
to_entity(entt)));
197 for(
const auto *storage: range) {
199 const char *label = type.name() ? type.name() : std::string{
storage->
info().
name()}.data();
201 if(ImGui::TreeNode(&
storage->
info(),
"%s", label)) {
202 if(
const auto obj = type.from_void(
storage->
value(entt)); obj) {
203 present_element<typename view_type::entity_type>(obj, [](
const char *name,
const typename view_type::entity_type entt) {
212 ImGui::Text(
"%s", name.data());
234template<
typename Type,
typename Entity,
typename Allocator>
236 internal::present_storage(ctx,
storage);
246template<
typename Type,
typename Entity,
typename Allocator>
258template<
typename... Get,
typename... Exclude>
260 internal::present_view(ctx,
view, std::index_sequence_for<Get...>{});
269template<
typename... Get,
typename... Exclude>
281template<
typename Entity,
typename Allocator>
283 ImGui::BeginTabBar(
"#tabs");
285 if(ImGui::BeginTabItem(
"Entity")) {
290 const auto range =
registry.storage();
291 internal::present_entity(ctx,
entt, range.begin(), range.end());
301 if(ImGui::BeginTabItem(
"Storage")) {
304 const char *label = type.name() ? type.name() : std::string{
storage.info().name()}.data();
306 if(ImGui::TreeNode(&
storage.info(),
"%s (%zu)", label,
storage.size())) {
307 internal::present_storage(ctx,
storage);
324template<
typename Entity,
typename Allocator>
Fast and reliable entity-component system.
bool contains(const entity_type entt) const noexcept
Checks if a sparse set contains an entity.
const void * value(const entity_type entt) const noexcept
Returns the element assigned to an entity, if any.
const type_info & info() const noexcept
Returns a type info object for the value type, if any.
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
constexpr entt_traits< Entity >::entity_type to_entity(const Entity value) noexcept
Returns the entity part once converted to the underlying type.
basic_view< type_list_transform_t< Get, storage_for >, type_list_transform_t< Exclude, storage_for > > view
Alias declaration for the most common use case.
constexpr entt_traits< Entity >::version_type to_version(const Entity value) noexcept
Returns the version part once converted to the underlying type.
void davey(const meta_ctx &ctx, const basic_storage< Type, Entity, Allocator > &storage)
ImGui-based introspection tool for storage types.
meta_type resolve() noexcept
Returns the meta type associated with a given type.
basic_registry<> registry
Alias declaration for the most common use case.
constexpr entt_traits< Entity >::entity_type to_integral(const Entity value) noexcept
Converts an entity to its underlying type.
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
basic_storage< Type > storage
Alias declaration for the most common use case.
Alias for exclusion lists.
Alias for lists of observed elements.
constexpr std::string_view name() const noexcept
Type name.