From 6243e3c459dffd9c6c7f9f72c2bc4d9ab176044c Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 20 Dec 2023 18:39:19 +0100 Subject: [PATCH] Syntax highlighting of entity paths and instance paths --- Cargo.lock | 2 + crates/re_data_ui/src/item_ui.rs | 14 +++-- crates/re_ui/Cargo.toml | 3 + crates/re_ui/src/lib.rs | 2 + crates/re_ui/src/syntax_highlighting.rs | 64 ++++++++++++++++++++++ crates/re_viewer/src/ui/selection_panel.rs | 9 ++- 6 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 crates/re_ui/src/syntax_highlighting.rs diff --git a/Cargo.lock b/Cargo.lock index 3d7cf382acae..d52519d25a44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5272,7 +5272,9 @@ dependencies = [ "egui_extras", "egui_tiles", "parking_lot 0.12.1", + "re_entity_db", "re_log", + "re_log_types", "serde", "serde_json", "strum", diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index cc8c25a63c91..f1c3582a0999 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -2,9 +2,9 @@ //! //! TODO(andreas): This is not a `data_ui`, can this go somewhere else, shouldn't be in `re_data_ui`. -use egui::Ui; use re_entity_db::{EntityTree, InstancePath}; use re_log_types::{ComponentPath, EntityPath, TimeInt, Timeline}; +use re_ui::SyntaxHighlighting; use re_viewer_context::{ DataQueryId, HoverHighlight, Item, Selection, SpaceViewId, UiVerbosity, ViewerContext, }; @@ -49,7 +49,7 @@ pub fn entity_path_button( ui, space_view_id, &InstancePath::entity_splat(entity_path.clone()), - entity_path.to_string(), + entity_path.syntax_highlighted(ui.style()), ) } @@ -82,7 +82,7 @@ pub fn instance_path_button( ui, space_view_id, instance_path, - instance_path.to_string(), + instance_path.syntax_highlighted(ui.style()), ) } @@ -351,14 +351,18 @@ pub fn select_hovered_on_click( /// Displays the "hover card" (i.e. big tooltip) for an instance or an entity. /// /// The entity hover card is displayed the provided instance path is a splat. -pub fn instance_hover_card_ui(ui: &mut Ui, ctx: &ViewerContext<'_>, instance_path: &InstancePath) { +pub fn instance_hover_card_ui( + ui: &mut egui::Ui, + ctx: &ViewerContext<'_>, + instance_path: &InstancePath, +) { let subtype_string = if instance_path.instance_key.is_splat() { "Entity" } else { "Entity Instance" }; ui.strong(subtype_string); - ui.label(format!("Path: {instance_path}")); + ui.label(instance_path.syntax_highlighted(ui.style())); // TODO(emilk): give data_ui an alternate "everything on this timeline" query? // Then we can move the size view into `data_ui`. diff --git a/crates/re_ui/Cargo.toml b/crates/re_ui/Cargo.toml index 31b89ffc24fd..5087c77ccbcc 100644 --- a/crates/re_ui/Cargo.toml +++ b/crates/re_ui/Cargo.toml @@ -26,6 +26,9 @@ all-features = true default = [] [dependencies] +re_entity_db.workspace = true # syntax-highlighting for InstancePath. TODO(emilk): move InstancePath +re_log_types.workspace = true # syntax-highlighting for EntityPath + egui_commonmark.workspace = true egui_extras.workspace = true egui.workspace = true diff --git a/crates/re_ui/src/lib.rs b/crates/re_ui/src/lib.rs index f5be9530ccd8..79c13c0b1a3c 100644 --- a/crates/re_ui/src/lib.rs +++ b/crates/re_ui/src/lib.rs @@ -8,6 +8,7 @@ pub mod icons; mod layout_job_builder; pub mod list_item; pub mod modal; +mod syntax_highlighting; pub mod toasts; mod toggle_switch; @@ -16,6 +17,7 @@ pub use command_palette::CommandPalette; pub use design_tokens::DesignTokens; pub use icons::Icon; pub use layout_job_builder::LayoutJobBuilder; +pub use syntax_highlighting::SyntaxHighlighting; pub use toggle_switch::toggle_switch; // --------------------------------------------------------------------------- diff --git a/crates/re_ui/src/syntax_highlighting.rs b/crates/re_ui/src/syntax_highlighting.rs new file mode 100644 index 000000000000..673803578c12 --- /dev/null +++ b/crates/re_ui/src/syntax_highlighting.rs @@ -0,0 +1,64 @@ +use re_entity_db::InstancePath; +use re_log_types::{EntityPath, EntityPathPart}; + +use egui::{text::LayoutJob, Color32, Style, TextFormat}; + +pub trait SyntaxHighlighting { + fn syntax_highlighted(&self, style: &Style) -> LayoutJob { + let mut job = LayoutJob::default(); + self.syntax_highlight_into(style, &mut job); + job + } + + fn syntax_highlight_into(&self, style: &Style, job: &mut LayoutJob); +} + +fn text_format(style: &Style) -> TextFormat { + TextFormat { + font_id: egui::TextStyle::Body.resolve(style), + + // This color be replaced with appropriate color based on widget, + // and whether the widget is hovered, etc + color: Color32::PLACEHOLDER, + + ..Default::default() + } +} + +fn faint_text_format(style: &Style) -> TextFormat { + TextFormat { + color: Color32::WHITE, + + ..text_format(style) + } +} + +impl SyntaxHighlighting for EntityPathPart { + fn syntax_highlight_into(&self, style: &Style, job: &mut LayoutJob) { + job.append(&self.ui_string(), 0.0, 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)); + + for (i, part) in self.iter().enumerate() { + if i != 0 { + job.append("/", 0.0, faint_text_format(style)); + } + part.syntax_highlight_into(style, job); + } + } +} + +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)); + } + } +} diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index 97153c922a7f..70fa2973553f 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -13,6 +13,7 @@ use re_types::{ }; use re_ui::list_item::ListItem; use re_ui::ReUi; +use re_ui::SyntaxHighlighting as _; use re_viewer_context::{ gpu_bridge::colormap_dropdown_button_ui, HoverHighlight, Item, SpaceViewClass, SpaceViewClassIdentifier, SpaceViewId, SystemCommand, SystemCommandSender as _, UiVerbosity, @@ -353,12 +354,14 @@ fn what_is_selected_ui( "Entity instance" }; + let name = instance_path.syntax_highlighted(ui.style()); + 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, ui, - instance_path.to_string().as_str(), + name, None, &format!( "{typ} '{instance_path}' as shown in Space View {:?}", @@ -375,7 +378,7 @@ fn what_is_selected_ui( item_title_ui( ctx.re_ui, ui, - instance_path.to_string().as_str(), + name, None, &format!("{typ} '{instance_path}'"), ); @@ -409,7 +412,7 @@ fn what_is_selected_ui( fn item_title_ui( re_ui: &re_ui::ReUi, ui: &mut egui::Ui, - name: &str, + name: impl Into, icon: Option<&re_ui::Icon>, hover: &str, ) -> egui::Response {