6#include "entt/core/any.hpp"
11#include "imgui/imgui.h"
12#include "imgui/imgui_internal.h"
26#include <unordered_map>
38 auto base_inspector_type = entt::resolve<inspector>();
40 for(
auto& inspector_type : inspector_types)
43 if(inspected_type_var)
46 inspector_type.invoke(
"create_and_register"_hs, {}, inspected_type_var, entt::forward_as_meta(
type_map));
61 return debug_view > 0;
69 const entt::meta_any& old_var,
70 const entt::meta_any& new_var,
71 const entt::meta_custom& custom)
73 std::function<void()> on_success =
nullptr;
80 on_success = [
entity = override_ctx.
entity, component_type_name, component_type_pretty_name, prop_path]()
104 end_prefab_inspection();
106 auto prefab_root = find_prefab_root_entity(e);
114 prefab_root_entity = prefab_root;
118 is_path_overridden_callback =
119 [comp_copy = *prefab_comp, entity_copy = e](
const hpp::uuid& entity_uuid,
120 const std::string& component_path)
122 return comp_copy.has_override(entity_uuid, component_path);
126 auto entity_uuid = get_entity_prefab_uuid(e);
128 set_entity_uuid(entity_uuid);
148 if(!is_active || !prefab_root_entity)
157 auto entity_uuid = path_context.get_entity_uuid();
159 if(exists_in_prefab(prefab_scene,
162 path_context.get_component_type_name(),
163 path_context.get_current_path()))
166 std::string component_path = path_context.get_current_path_with_component_type();
168 std::string pretty_component_path = pretty_path_context.get_current_path_with_component_type();
170 prefab_comp->add_override(entity_uuid, component_path, pretty_component_path);
171 prefab_comp->changed =
true;
212 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
213 ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
226 ImGui::PopStyleColor(2);
246 auto current_entity =
entity;
249 while(current_entity)
253 return current_entity;
263 current_entity = transform->get_parent();
357 const entt::meta_type& component_type,
358 const std::string& property_path)
367 const std::string& component_type_name,
368 const std::string& component_pretty_type_name,
369 const std::string& property_path)
388 auto type = entt::resolve(entt::hashed_string(component_type_name.c_str()));
389 std::string current_path = component_type_name;
390 std::string current_pretty_path = component_pretty_type_name;
392 for(
auto& token : tokens)
394 auto prop =
type.data(entt::hashed_string(token.c_str()));
395 auto prop_type = prop.type();
397 current_path +=
"/" + token;
403 prefab_comp->add_override(entity_uuid, current_path, current_pretty_path);
408 if(component_type_name ==
"transform_component")
410 auto property_path_global =
string_utils::replace(property_path,
"global_transform",
"local_transform");
412 if(property_path_global != property_path)
428 if(entity_uuid.is_nil())
433 prefab_comp->remove_entity(entity_uuid);
440 hpp::uuid entity_uuid,
441 const std::string& component_type,
442 const std::string& property_path) ->
bool
449 if(entity_uuid.is_nil())
454 auto etype = entt::resolve(entt::hashed_string(component_type.c_str()));
459 auto method = etype.func(
"component_exists"_hs);
465 struct prefab_version_t
470 entt::handle instance;
471 auto view = cache_scene.registry->view<
prefab_component, prefab_version_t>();
473 [&](
auto e,
auto&& comp,
auto&&
version)
477 instance = cache_scene.create_handle(e);
482 cache_scene.unload();
483 instance = cache_scene.instantiate(
prefab);
484 instance.emplace<prefab_version_t>(
prefab.version());
493 auto result = method.invoke({},
entity);
495 bool exists = result.cast<
bool>();
501 if(etype == entt::resolve<script_component>())
507 if(tokens.size() > 1 && tokens[0] ==
"script_components")
509 auto script_name = tokens[1];
510 return script_comp->has_script_components(script_name);
557 if(predicate_meta.try_cast<
bool>())
559 auto pred = predicate_meta.cast<
bool>();
574 auto prop_var = prop.get(
object);
577 auto prop_old_var = prop.get(
object);
580 auto prop_type = prop_var.type();
583 bool is_array = prop_type.is_sequence_container();
584 bool is_associative_container = prop_type.is_associative_container();
585 bool is_container = is_array || is_associative_container;
586 bool is_enum = prop_type.is_enum();
604 prop_inspector->before_inspect(prop);
616 result |=
inspect_array(ctx, prop_var, prop_proxy, prop, info, prop.custom());
618 else if(is_associative_container)
625 result |=
inspect_enum(ctx, prop_var, prop_proxy, info);
631 result |=
inspect_var(ctx, prop_var, prop_proxy, info, prop.custom());
633 else if(!is_flattable)
635 ImGui::AlignTextToFramePadding();
636 ImGui::SetNextItemOpen(
true, ImGuiCond_Appearing);
638 bool open = ImGui::TreeNode(pretty_name.c_str());
642 ImGui::TreePush(pretty_name.c_str());
644 result |=
inspect_var(ctx, prop_var, prop_proxy, info, prop.custom());
652 ImGui::PushID(pretty_name.c_str());
654 result |=
inspect_var(ctx, prop_var, prop_proxy, info, prop.custom());
661 if(result.changed && !is_readonly)
663 prop.set(
object, prop_var);
664 add_property_action(ctx, override_ctx, result, prop_proxy, prop_old_var, prop_var, prop.custom());
673 prop_inspector->after_inspect(prop);
676 override_ctx.pop_segment();
684 const entt::meta_data& prop,
698 const std::string&
name,
703 auto view = var.as_sequence_container();
706 auto int_size =
static_cast<int>(
size);
715 bool resizeable = view.resize(
size);
718 ImGuiInputTextFlags flags = 0;
721 bool readonly = info.read_only || !resizeable;
726 flags |= ImGuiInputTextFlags_ReadOnly;
731 if(ImGui::InputInt(
"##array", &int_size, step, step_fast, flags))
733 int_size = std::max(readonly_count, int_size);
735 if(view.resize(
static_cast<std::size_t
>(int_size)))
737 size =
static_cast<std::size_t
>(int_size);
738 result.changed =
true;
740 result.edit_finished =
true;
744 ImGui::DrawItemActivityOutline();
751 ImGui::TreePush(
"array");
753 int index_to_remove = -1;
754 for(std::size_t i = 0; i <
size; ++i)
756 auto value = view[i];
757 std::string element =
"Element ";
758 element += std::to_string(i);
762 auto item_info = info;
763 item_info.read_only |= readonly_count > 0;
767 auto pos_before = ImGui::GetCursorPos();
784 value_proxy.
impl->get_name = [var_proxy, element]()
786 auto name = var_proxy.impl->get_name();
791 return fmt::format(
"{}/{}",
name, element);
793 value_proxy.
impl->getter = [parent_proxy = var_proxy, i](entt::meta_any& result)
796 if(parent_proxy.impl->getter(var) && var)
798 auto view = var.as_sequence_container();
799 if(view.size() >
static_cast<std::size_t
>(i))
801 auto value = view[i];
808 value_proxy.
impl->setter = [parent_proxy = var_proxy, i](
meta_any_proxy& proxy,
const entt::meta_any& value, uint64_t execution_count)
mutable
811 if(parent_proxy.impl->getter(var) && var)
813 auto view = var.as_sequence_container();
814 if(view.size() >
static_cast<std::size_t
>(i))
817 auto it = view.begin();
818 std::advance(it,
static_cast<std::ptrdiff_t
>(i));
824 view.insert(it, value);
827 return parent_proxy.impl->setter(parent_proxy, var, execution_count);
834 result |=
inspect_var(ctx, value, value_proxy, item_info, custom);
845 auto pos_after = ImGui::GetCursorPos();
852 if(!item_info.read_only && !resizeable)
854 ImGui::SetCursorPos(pos_before);
857 ImGui::AlignTextToFramePadding();
858 if(ImGui::Button(
ICON_MDI_DELETE, ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing())))
862 ImGui::SetItemTooltipEx(
"Remove element.");
864 ImGui::SetCursorPos(pos_after);
869 if(index_to_remove != -1)
871 auto it = view.begin();
872 std::advance(it, index_to_remove);
874 result.changed =
true;
875 result.edit_finished =
true;
881 ImGui::RenderFrameEx(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
889 const entt::meta_data& prop,
893 auto view = var.as_associative_container();
895 auto int_size =
static_cast<int>(
size);
988 if(!edited.allow_cast<int64_t>())
992 auto current_value = edited.cast<int64_t>();
997 auto type = var.type();
1002 std::string pretty_name;
1006 std::vector<enum_value> names;
1007 for(
auto kvp :
type.data())
1009 const auto& data = kvp.second;
1012 auto value = data.get(var);
1014 int64_t value64 = 0;
1015 if(value.allow_cast<int64_t>())
1017 value64 = value.cast<int64_t>();
1023 names.emplace_back(enum_value{
name, pretty_name, value64});
1025 if(value64 == current_value)
1032 if(current_idx >=
static_cast<int>(names.size()))
1041 ImGui::LabelText(
"##enum",
"%s", names[current_idx].pretty_name.c_str());
1045 int listbox_item_size =
static_cast<int>(names.size());
1047 ImGuiComboFlags flags = 0;
1049 if(ImGui::BeginCombo(
"##enum", names[current_idx].pretty_name.c_str(), flags))
1051 for(
int n = 0; n < listbox_item_size; n++)
1053 const bool is_selected = (current_idx == n);
1055 if(ImGui::Selectable(names[n].pretty_name.c_str(), is_selected))
1058 result.changed =
true;
1059 result.edit_finished |=
true;
1061 edited = names[n].value;
1063 if(edited.allow_cast(var.type()))
1065 var = std::move(edited);
1069 ImGui::DrawItemActivityOutline();
1072 ImGui::SetItemDefaultFocus();
1077 ImGui::DrawItemActivityOutline();
1084 entt::meta_any& var,
1091 auto type = var.type();
1094 derived_var_proxy.
impl->get_name = [parent_proxy = var_proxy]()
1096 return parent_proxy.impl->get_name();
1098 derived_var_proxy.
impl->getter = [parent_proxy = var_proxy](entt::meta_any& result)
1100 if(parent_proxy.impl->getter(result) && result)
1107 derived_var_proxy.
impl->setter = [parent_proxy = var_proxy](
meta_any_proxy& proxy,
const entt::meta_any& value, uint64_t execution_count)
mutable
1110 if(proxy.impl->getter(var) && var)
1113 return parent_proxy.impl->setter(parent_proxy, var, execution_count);
1118 entt::meta_any old_var;
1119 if(info.is_copyable)
1131 result |=
inspector->inspect(ctx, var, derived_var_proxy, info, custom);
1133 else if(
type.is_enum())
1135 result |=
inspect_enum(ctx, var, derived_var_proxy, info);
1143 if(result.changed && info.is_property)
1156 entt::meta_any& var,
1158 const entt::meta_type&
type,
1162 auto properties =
type.data();
1165 if(properties.begin() == properties.end())
1172 if(
type.is_sequence_container())
1174 result |=
inspect_array(ctx, var, var_proxy,
"",
"", info, custom);
1179 std::vector<std::pair<std::string, std::vector<entt::meta_data>>> grouped_props;
1180 for(
auto kvp : properties)
1182 const auto& prop = kvp.second;
1187 auto it = std::find_if(grouped_props.begin(),
1188 grouped_props.end(),
1191 return kv.first == group;
1194 if(it == grouped_props.end())
1197 grouped_props.emplace_back(group, std::vector<entt::meta_data>{prop});
1202 it->second.emplace_back(prop);
1206 for(
auto& kvp : grouped_props)
1208 auto& props = kvp.second;
1210 const auto& group_name = kvp.first;
1212 if(group_name.empty())
1214 for(
auto&& prop : props)
1224 ImGui::AlignTextToFramePadding();
1225 ImGui::SetNextItemOpen(
true, ImGuiCond_Appearing);
1226 if(ImGui::TreeNode(kvp.first.c_str()))
1228 ImGui::TreePush(kvp.first.c_str());
1230 for(
auto& prop : props)
1249 entt::meta_any& var,
1255 for(
auto base : var.type().base())
Manages ImGui layout for property inspection in the editor.
void set_data(const entt::meta_data &prop, bool columns=true)
Updates layout data from meta property.
void pop_layout()
Cleans up ImGui state (IDs, tables, tree nodes)
auto push_tree_layout(ImGuiTreeNodeFlags flags=0) -> bool
Creates a collapsible tree node layout for nested properties.
void push_segment(const std::string &segment)
Push a new path segment onto the context stack.
void set_component_type(const std::string &type)
Set the component type for this context.
auto get_component_type_name() const -> std::string
Get the component type name.
void pop_segment()
Pop the last path segment from the context stack.
void set_entity_uuid(const hpp::uuid &entity_uuid)
Set the entity UUID for nested entity tracking.
auto get_current_path() const -> std::string
Get the current full property path.
Class that contains core data for audio listeners. There can only be one instance of it per scene.
void PushFont(Font::Enum _font)
void PushReadonly(bool _enabled)
auto get_derived_types(const meta_type &t) -> std::vector< meta_type >
auto get_pretty_name(const meta_type &t) -> std::string
auto as_derived(meta_any &obj) -> bool
auto get_attribute_as< std::string >(const meta_custom &custom, const char *name) -> std::string
auto get_attribute_as(const meta_custom &custom, const char *name) -> T
auto get_attribute(const meta_custom &custom, const char *name) -> const meta_any &
std::function< bool(const meta_any &)> property_predicate_t
auto get_name(const meta_type &t) -> std::string
Provides utilities for inspecting and converting sequence-related types to strings.
auto tokenize(const std::string &str, const std::string &delimiters) -> string_tokens_t
auto replace(const std::string &str, const std::string &search, const std::string &replace) -> std::string
auto inspect_property(rtti::context &ctx, entt::meta_any &object, const meta_any_proxy &var_proxy, const entt::meta_data &prop) -> inspect_result
void pop_debug_view()
Pops debug view mode (decreases debug view counter)
auto make_property_proxy(const meta_any_proxy &var_proxy, const entt::meta_data &prop) -> meta_any_proxy
auto is_property_readonly(const entt::meta_any &object, const entt::meta_data &prop) -> bool
auto is_property_visible(const entt::meta_any &object, const entt::meta_data &prop) -> bool
void add_property_action(rtti::context &ctx, prefab_override_context &override_ctx, inspect_result &result, const meta_any_proxy &var_proxy, const entt::meta_any &old_var, const entt::meta_any &new_var, const entt::meta_custom &custom)
auto inspect_associative_container(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const entt::meta_data &prop, const var_info &info, const entt::meta_custom &custom) -> inspect_result
Inspects associative containers like maps and sets.
auto inspect_var_properties_impl(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const entt::meta_type &type, const var_info &info, const entt::meta_custom &custom) -> inspect_result
auto inspect_var_properties(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const var_info &info, const entt::meta_custom &custom) -> inspect_result
Inspects all properties of a complex object recursively.
void push_debug_view()
Pushes debug view mode (increases debug view counter)
auto is_debug_view() -> bool
Checks if currently in debug view mode.
auto get_inspector(rtti::context &ctx, const entt::meta_type &type) -> std::shared_ptr< inspector >
auto inspect_array(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const entt::meta_data &prop, const var_info &info, const entt::meta_custom &custom) -> inspect_result
Inspects array-like containers with add/remove functionality.
auto inspect_enum(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const var_info &info) -> inspect_result
Inspects enumeration types with dropdown selection.
auto is_property_flattable(const entt::meta_any &object, const entt::meta_data &prop) -> bool
auto inspect_var(rtti::context &ctx, entt::meta_any &var, const meta_any_proxy &var_proxy, const var_info &info, const entt::meta_custom &custom) -> inspect_result
Main entry point for inspecting any variable with automatic type resolution.
Represents a handle to an asset, providing access and management functions.
void do_action(const std::string &name, const std::function< void()> &action)
static auto context() -> rtti::context &
Result of an inspection operation indicating what changes occurred.
bool change_recorded
Whether the change was recorded for undo/redo system.
Registry for managing type-specific inspector instances.
inspector_registry()
Constructor that auto-discovers and registers all inspector types.
std::unordered_map< entt::id_type, std::shared_ptr< inspector > > type_map
Map from type ID to inspector instance for fast lookup.
Component that holds a reference to a prefab asset and tracks property overrides.
Component that provides a unique identifier (UUID) for a prefab.
hpp::uuid id
The unique identifier for the entity.
Global context for tracking prefab override changes during inspection.
void end_prefab_inspection()
End prefab inspection context and clean up state.
entt::handle prefab_root_entity
The prefab root entity that contains the prefab_component.
static auto exists_in_prefab(scene &cache_scene, const asset_handle< prefab > &prefab, hpp::uuid entity_uuid, const std::string &component_type, const std::string &property_path) -> bool
Checks if a property exists in the original prefab.
void set_entity_uuid(const hpp::uuid &uuid)
Sets the entity UUID for both path contexts.
property_path_context pretty_path_context
Current property path context for human-readable paths.
entt::handle entity
The specific entity currently being inspected.
auto is_path_overridden() const -> bool
Check if the current property path is already overridden.
static void mark_property_as_changed(entt::handle entity, const entt::meta_type &component_type, const std::string &property_path)
Marks a specific property as changed using component type.
static void mark_transform_global_as_changed(entt::handle entity, bool position, bool rotation, bool scale, bool skew)
static auto find_prefab_root_entity(entt::handle entity) -> entt::handle
Finds the prefab root entity by traversing up the parent hierarchy.
static void mark_material_as_changed(entt::handle entity)
Marks material as changed in prefab override system.
static void mark_text_area_as_changed(entt::handle entity)
Marks text area as changed in prefab override system.
property_path_context path_context
Current property path context for serialization paths.
void set_component_type(const std::string &type, const std::string &pretty_type)
Sets the component type for both path contexts.
auto record_override() -> bool
Record a property override when a change is detected.
static void mark_entity_as_removed(entt::handle entity)
Marks an entity as removed from the prefab instance.
bool is_active
Whether we're currently inspecting a prefab instance.
void push_segment(const std::string &segment, const std::string &pretty_segment)
Pushes a new path segment onto both contexts and applies override styling.
static void mark_active_as_changed(entt::handle entity)
Marks entity active state as changed in prefab override system.
static void mark_transform_as_changed(entt::handle entity, bool position, bool rotation, bool scale, bool skew)
Marks transform properties as changed in prefab override system.
void pop_segment()
Pops the last path segment and removes override styling if needed.
static auto get_entity_prefab_uuid(entt::handle entity) -> hpp::uuid
Gets the prefab UUID of an entity from its prefab_id_component.
auto begin_prefab_inspection(entt::handle entity) -> bool
Initialize context for inspecting a prefab instance.
Represents a generic prefab with a buffer for serialized data.
Represents a scene in the ACE framework, managing entities and their relationships.
static auto find_entity_by_prefab_uuid(entt::handle root_entity, const hpp::uuid &target_uuid) -> entt::handle
Finds an entity by UUID in the scene.
Metadata about a variable being inspected.
bool is_property
Whether this is a property that can be overridden in prefabs.
bool read_only
Whether the variable should be displayed as read-only.