diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index d10ded43239f..2964697633ad 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -57,6 +57,37 @@ pub fn entity_path_button( ) } +/// Show the different parts of an entity path and make them selectable. +pub fn entity_path_parts_buttons( + ctx: &ViewerContext<'_>, + query: &re_data_store::LatestAtQuery, + store: &re_data_store::DataStore, + ui: &mut egui::Ui, + space_view_id: Option, + entity_path: &EntityPath, +) -> egui::Response { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 4.0; + + let mut accumulated = Vec::new(); + for part in entity_path.iter() { + accumulated.push(part.clone()); + + ui.strong("/"); + entity_path_button_to( + ctx, + query, + store, + ui, + space_view_id, + &accumulated.clone().into(), + part.syntax_highlighted(ui.style()), + ); + } + }) + .response +} + /// Show an entity path and make it selectable. pub fn entity_path_button_to( ctx: &ViewerContext<'_>, @@ -119,6 +150,50 @@ pub fn instance_path_button_to( cursor_interact_with_selectable(ctx, response, item) } +/// Show the different parts of an instance path and make them selectable. +pub fn instance_path_parts_buttons( + ctx: &ViewerContext<'_>, + query: &re_data_store::LatestAtQuery, + store: &re_data_store::DataStore, + ui: &mut egui::Ui, + space_view_id: Option, + instance_path: &InstancePath, +) -> egui::Response { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 4.0; + + let mut accumulated = Vec::new(); + for part in instance_path.entity_path.iter() { + accumulated.push(part.clone()); + + ui.strong("/"); + entity_path_button_to( + ctx, + query, + store, + ui, + space_view_id, + &accumulated.clone().into(), + part.syntax_highlighted(ui.style()), + ); + } + + if !instance_path.instance_key.is_splat() { + ui.strong("/"); + instance_path_button_to( + ctx, + query, + store, + ui, + space_view_id, + instance_path, + instance_path.instance_key.syntax_highlighted(ui.style()), + ); + } + }) + .response +} + fn entity_tree_stats_ui(ui: &mut egui::Ui, timeline: &Timeline, tree: &EntityTree) { use re_format::format_bytes; diff --git a/crates/re_ui/src/syntax_highlighting.rs b/crates/re_ui/src/syntax_highlighting.rs index 673803578c12..63af7fba5f7b 100644 --- a/crates/re_ui/src/syntax_highlighting.rs +++ b/crates/re_ui/src/syntax_highlighting.rs @@ -1,5 +1,5 @@ use re_entity_db::InstancePath; -use re_log_types::{EntityPath, EntityPathPart}; +use re_log_types::{external::re_types_core::components::InstanceKey, EntityPath, EntityPathPart}; use egui::{text::LayoutJob, Color32, Style, TextFormat}; @@ -39,6 +39,14 @@ impl SyntaxHighlighting for EntityPathPart { } } +impl SyntaxHighlighting for InstanceKey { + fn syntax_highlight_into(&self, style: &Style, job: &mut LayoutJob) { + job.append("[", 0.0, faint_text_format(style)); + job.append(&self.to_string(), 0.0, text_format(style)); + job.append("]", 0.0, faint_text_format(style)); + } +} + impl SyntaxHighlighting for EntityPath { fn syntax_highlight_into(&self, style: &Style, job: &mut LayoutJob) { job.append("/", 0.0, faint_text_format(style)); @@ -56,9 +64,7 @@ impl SyntaxHighlighting for InstancePath { fn syntax_highlight_into(&self, style: &Style, job: &mut LayoutJob) { self.entity_path.syntax_highlight_into(style, job); if !self.instance_key.is_splat() { - job.append("[", 0.0, faint_text_format(style)); - job.append(&self.instance_key.to_string(), 0.0, text_format(style)); - job.append("]", 0.0, faint_text_format(style)); + self.instance_key.syntax_highlight_into(style, job); } } } diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index 85a79b68554f..2963a5097195 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -12,8 +12,7 @@ use re_types::{ }; use re_types_core::components::InstanceKey; use re_ui::list_item::ListItem; -use re_ui::ReUi; -use re_ui::SyntaxHighlighting as _; +use re_ui::{ReUi, SyntaxHighlighting as _}; use re_viewer_context::{ blueprint_timepoint_for_writes, gpu_bridge::colormap_dropdown_button_ui, ContainerId, DataQueryId, HoverHighlight, Item, SpaceViewClass, SpaceViewClassIdentifier, SpaceViewId, @@ -410,13 +409,23 @@ fn what_is_selected_ui( } } Item::InstancePath(space_view_id, instance_path) => { - let typ = if instance_path.instance_key.is_splat() { - "Entity" - } else { + let is_instance = !instance_path.instance_key.is_splat(); + + let typ = if is_instance { "Entity instance" + } else { + "Entity" }; + let (query, store) = + guess_query_and_store_for_selected_entity(ctx, &instance_path.entity_path); + let name = instance_path.syntax_highlighted(ui.style()); + let parent = if is_instance { + Some(instance_path.entity_path.clone()) + } else { + instance_path.entity_path.parent() + }; if let Some(space_view_id) = space_view_id { if let Some(space_view) = viewport.space_view(space_view_id) { @@ -431,6 +440,20 @@ fn what_is_selected_ui( ), ); + if let Some(parent) = parent { + ui.horizontal(|ui| { + ui.label("path"); + item_ui::entity_path_parts_buttons( + ctx, + &query, + store, + ui, + Some(*space_view_id), + &parent, + ); + }); + } + ui.horizontal(|ui| { ui.label("in"); space_view_button(ctx, ui, space_view); @@ -445,6 +468,13 @@ fn what_is_selected_ui( &format!("{typ} '{instance_path}'"), ); + if let Some(parent) = parent { + ui.horizontal(|ui| { + ui.label("path"); + item_ui::entity_path_parts_buttons(ctx, &query, store, ui, None, &parent); + }); + } + list_existing_data_blueprints(ui, ctx, &instance_path.entity_path, viewport); } } @@ -764,7 +794,9 @@ fn show_list_item_for_container_child( fn has_blueprint_section(item: &Item) -> bool { match item { Item::ComponentPath(_) | Item::Container(_) => false, - Item::InstancePath(space_view_id, _) => space_view_id.is_some(), + Item::InstancePath(space_view_id, instance_path) => { + space_view_id.is_some() && instance_path.instance_key.is_splat() + } _ => true, } } @@ -915,22 +947,7 @@ fn blueprint_ui_for_instance_path( ) { if let Some(space_view_id) = space_view_id { if let Some(space_view) = viewport.blueprint.space_view(space_view_id) { - if instance_path.instance_key.is_specific() { - let (query, store) = - guess_query_and_store_for_selected_entity(ctx, &instance_path.entity_path); - ui.horizontal(|ui| { - ui.label("Part of"); - item_ui::entity_path_button( - ctx, - &query, - store, - ui, - Some(*space_view_id), - &instance_path.entity_path, - ); - }); - // TODO(emilk): show the values of this specific instance (e.g. point in the point cloud)! - } else { + if instance_path.instance_key.is_splat() { // splat - the whole entity let space_view_class = *space_view.class_identifier(); let entity_path = &instance_path.entity_path;