Skip to content

Commit 2fef06c

Browse files
authored
Show different entity categories in different tabs (#35)
* Add entity-centric tabs * Make `ObjectListEntry` a struct * Restore resource names * Restore internal observer TODO * Include one-shot system in `inspector_window` example
1 parent dc5c340 commit 2fef06c

File tree

6 files changed

+167
-143
lines changed

6 files changed

+167
-143
lines changed

examples/inspector_window.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ fn main() {
2626
let mut name_registry = app.world_mut().resource_mut::<NameResolutionRegistry>();
2727
name_registry.register_name_defining_type::<Chaff>(0);
2828

29+
// Register a one-shot system to be shown in the inspector
30+
let one_shot_system_id = app.world_mut().register_system(example_one_shot_system);
31+
app.world_mut()
32+
.entity_mut(one_shot_system_id.entity())
33+
.insert(Name::new("Example One-Shot System"));
34+
2935
app.run();
3036
}
3137

@@ -83,6 +89,7 @@ The inspector window shows:
8389
- Entity list with component counts and memory usage
8490
- Components tab with reflected values
8591
- Relationships tab showing parent/child hierarchy
92+
- One-Shot systems tab showing registered systems
8693
- Click entities in the Relationships tab to navigate"
8794
.to_string();
8895

@@ -125,3 +132,8 @@ fn fluctuating_entity_counts(
125132
commands.entity(marked_for_death).despawn();
126133
}
127134
}
135+
136+
/// One-shot system registered just to be shown in the inspector.
137+
fn example_one_shot_system() {
138+
info!("This is an example one-shot system.");
139+
}

src/entity_name_resolution/mod.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use bevy::core_pipeline::Skybox;
44
use bevy::ecs::component::ComponentId;
5+
use bevy::ecs::resource::IsResource;
56
use bevy::ecs::system::SystemIdMarker;
67
use bevy::light::{Atmosphere, FogVolume, IrradianceVolume, SunDisk};
78
use bevy::pbr::Lightmap;
@@ -84,6 +85,34 @@ pub fn resolve_name(
8485
return None;
8586
};
8687

88+
let is_resource = component_data.iter().any(|comp_inspection| {
89+
metadata_map
90+
.get(&comp_inspection.component_id)
91+
.and_then(|meta| meta.type_id)
92+
== Some(TypeId::of::<IsResource>())
93+
});
94+
95+
if is_resource {
96+
let mut resource_names = component_data
97+
.iter()
98+
.filter_map(|inspection| {
99+
let type_id = metadata_map
100+
.get(&inspection.component_id)
101+
.and_then(|meta| meta.type_id);
102+
if type_id == Some(TypeId::of::<IsResource>()) {
103+
None
104+
} else {
105+
Some(inspection.name.shortname().to_string())
106+
}
107+
})
108+
.collect::<Vec<String>>();
109+
110+
if !resource_names.is_empty() {
111+
resource_names.sort();
112+
return Some(EntityName::generated(&resource_names.join(" | ")));
113+
}
114+
}
115+
87116
let mut name_resolution_priorities = component_data
88117
.iter()
89118
.filter_map(|comp_inspection| {

src/gui/panels/detail_panel.rs

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::entity_name_resolution::EntityName;
2020
use crate::extension_methods::WorldInspectionExtensionTrait;
2121
use crate::gui::config::InspectorConfig;
2222
use crate::gui::semantic_names::SemanticFieldNames;
23-
use crate::gui::state::{DetailTab, InspectableObject, InspectorCache, InspectorState};
23+
use crate::gui::state::{DetailTab, InspectorCache, InspectorState};
2424
use crate::gui::widgets::drag_value::{DragValue, DragValueDragState, FieldPath, FieldPathSegment};
2525
use crate::inspection::component_inspection::{
2626
ComponentDetailLevel, ComponentInspectionSettings, ComponentMetadataMap,
@@ -66,7 +66,7 @@ fn on_hierarchy_node_click(
6666
nodes: Query<&HierarchyNode>,
6767
) {
6868
if let Ok(node) = nodes.get(activate.entity) {
69-
state.selected_object = Some(InspectableObject::Entity(node.0));
69+
state.selected_object = Some(node.0);
7070
}
7171
}
7272

@@ -131,29 +131,14 @@ pub fn sync_detail_panel(world: &mut World) {
131131
};
132132

133133
// Check if entity still exists
134-
match selected_object {
135-
InspectableObject::Entity(entity) => {
136-
if !world.entities().contains(entity) {
137-
spawn_error_message(
138-
world,
139-
content_entity,
140-
&config,
141-
"Selected entity no longer exists",
142-
);
143-
return;
144-
}
145-
}
146-
InspectableObject::Resource(id) => {
147-
if !world.contains_resource_by_id(id) {
148-
spawn_error_message(
149-
world,
150-
content_entity,
151-
&config,
152-
"Selected resource no longer exists",
153-
);
154-
return;
155-
}
156-
}
134+
if !world.entities().contains(selected_object) {
135+
spawn_error_message(
136+
world,
137+
content_entity,
138+
&config,
139+
"Selected entity no longer exists",
140+
);
141+
return;
157142
}
158143

159144
// Ensure we have a metadata map - take it out to avoid borrow conflicts
@@ -171,32 +156,16 @@ pub fn sync_detail_panel(world: &mut World) {
171156
// Render based on active tab
172157
match active_tab {
173158
DetailTab::Components => {
174-
let InspectableObject::Entity(selected_entity) = selected_object else {
175-
warn_once!(
176-
"Components tab selected for non-entity object: {:?}",
177-
selected_object
178-
);
179-
return;
180-
};
181-
182159
if let Some(ref mut mm) = metadata_map {
183-
spawn_components_tab_exclusive(world, content_entity, selected_entity, mm, &config);
160+
spawn_components_tab_exclusive(world, content_entity, selected_object, mm, &config);
184161
}
185162
}
186163
DetailTab::Relationships => {
187-
let InspectableObject::Entity(selected_entity) = selected_object else {
188-
warn_once!(
189-
"Relationships tab selected for non-entity object: {:?}",
190-
selected_object
191-
);
192-
return;
193-
};
194-
195164
if let Some(ref mm) = metadata_map {
196165
spawn_relationships_tab_exclusive(
197166
world,
198167
content_entity,
199-
selected_entity,
168+
selected_object,
200169
mm,
201170
&config,
202171
);

0 commit comments

Comments
 (0)