From 45766c5e80b328c270f75d01654eac44e4c23117 Mon Sep 17 00:00:00 2001 From: Clement Rey Date: Fri, 16 Feb 2024 17:40:38 +0100 Subject: [PATCH 1/2] clickable parts --- crates/re_data_ui/src/item_ui.rs | 71 ++++++++++++++++++++++ crates/re_ui/src/syntax_highlighting.rs | 14 +++-- crates/re_viewer/src/ui/selection_panel.rs | 33 +++++----- 3 files changed, 96 insertions(+), 22 deletions(-) diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index d10ded43239f..7dde295d461c 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -57,6 +57,35 @@ 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| { + 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 +148,48 @@ 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| { + 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..c63f327aada2 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -13,7 +13,6 @@ 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_viewer_context::{ blueprint_timepoint_for_writes, gpu_bridge::colormap_dropdown_button_ui, ContainerId, DataQueryId, HoverHighlight, Item, SpaceViewClass, SpaceViewClassIdentifier, SpaceViewId, @@ -416,20 +415,23 @@ fn what_is_selected_ui( "Entity instance" }; - let name = instance_path.syntax_highlighted(ui.style()); + let (query, store) = + guess_query_and_store_for_selected_entity(ctx, &instance_path.entity_path); if let Some(space_view_id) = space_view_id { if let Some(space_view) = viewport.space_view(space_view_id) { - item_title_ui( - ctx.re_ui, + item_ui::instance_path_parts_buttons( + ctx, + &query, + store, ui, - name, - None, - &format!( - "{typ} '{instance_path}' as shown in Space View {:?}", - space_view.display_name - ), - ); + Some(*space_view_id), + instance_path, + ) + .on_hover_text(format!( + "{typ} '{instance_path}' as shown in Space View {:?}", + space_view.display_name + )); ui.horizontal(|ui| { ui.label("in"); @@ -437,13 +439,8 @@ fn what_is_selected_ui( }); } } else { - item_title_ui( - ctx.re_ui, - ui, - name, - None, - &format!("{typ} '{instance_path}'"), - ); + item_ui::instance_path_parts_buttons(ctx, &query, store, ui, None, instance_path) + .on_hover_text(format!("{typ} '{instance_path}'")); list_existing_data_blueprints(ui, ctx, &instance_path.entity_path, viewport); } From 20ff5fb6a3b03e5aac404dcd31bd16546dc3a11c Mon Sep 17 00:00:00 2001 From: Antoine Beyeler Date: Mon, 19 Feb 2024 16:00:34 +0100 Subject: [PATCH 2/2] - Restored title - added path to parent entity in the top-level context - removed redundant blueprint section for non-splat instance - adjusted spacing in `{instance|entity_path}_parts_button` --- crates/re_data_ui/src/item_ui.rs | 4 + crates/re_viewer/src/ui/selection_panel.rs | 88 +++++++++++++--------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index 7dde295d461c..2964697633ad 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -67,6 +67,8 @@ pub fn entity_path_parts_buttons( 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()); @@ -158,6 +160,8 @@ pub fn instance_path_parts_buttons( 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()); diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index c63f327aada2..2963a5097195 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -12,7 +12,7 @@ use re_types::{ }; use re_types_core::components::InstanceKey; use re_ui::list_item::ListItem; -use re_ui::ReUi; +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, @@ -409,29 +409,50 @@ 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) { - item_ui::instance_path_parts_buttons( - ctx, - &query, - store, + item_title_ui( + ctx.re_ui, ui, - Some(*space_view_id), - instance_path, - ) - .on_hover_text(format!( - "{typ} '{instance_path}' as shown in Space View {:?}", - space_view.display_name - )); + name, + None, + &format!( + "{typ} '{instance_path}' as shown in Space View {:?}", + space_view.display_name + ), + ); + + 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"); @@ -439,8 +460,20 @@ fn what_is_selected_ui( }); } } else { - item_ui::instance_path_parts_buttons(ctx, &query, store, ui, None, instance_path) - .on_hover_text(format!("{typ} '{instance_path}'")); + item_title_ui( + ctx.re_ui, + ui, + name, + None, + &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); } @@ -761,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, } } @@ -912,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;