From d37f3bf575be86f7a2ae19917614da4e033836bf Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 29 Jan 2024 19:00:12 +0100 Subject: [PATCH 1/5] wired up egui_plots update to selecting entities from plots --- Cargo.lock | 21 ++++++------ Cargo.toml | 14 ++++---- crates/re_data_ui/src/item_ui.rs | 29 ++-------------- .../src/space_view_class.rs | 26 ++++++++++++-- .../src/visualizer_system.rs | 15 ++++++-- .../re_viewer_context/src/viewer_context.rs | 34 ++++++++++++++++++- 6 files changed, 88 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0224c5f84af2..f7922094481c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1559,7 +1559,7 @@ checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecolor" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "bytemuck", "serde", @@ -1568,7 +1568,7 @@ dependencies = [ [[package]] name = "eframe" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "bytemuck", "cocoa", @@ -1593,7 +1593,6 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "web-time", "wgpu", "winapi", "winit", @@ -1602,7 +1601,7 @@ dependencies = [ [[package]] name = "egui" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "accesskit", "ahash", @@ -1618,7 +1617,7 @@ dependencies = [ [[package]] name = "egui-wgpu" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "bytemuck", "egui", @@ -1635,7 +1634,7 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "accesskit_winit", "arboard", @@ -1664,7 +1663,7 @@ dependencies = [ [[package]] name = "egui_extras" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "egui", "ehttp", @@ -1679,7 +1678,7 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "bytemuck", "egui", @@ -1696,7 +1695,7 @@ dependencies = [ [[package]] name = "egui_plot" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "egui", ] @@ -1739,7 +1738,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "emath" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "bytemuck", "serde", @@ -1840,7 +1839,7 @@ dependencies = [ [[package]] name = "epaint" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=ab39420c2933d2e402999043375b64e7cf0ee9ed#ab39420c2933d2e402999043375b64e7cf0ee9ed" +source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" dependencies = [ "ab_glyph", "ahash", diff --git a/Cargo.toml b/Cargo.toml index 1927bbb002fc..416122ddf3ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -277,13 +277,13 @@ debug = true # As a last resport, patch with a commit to our own repository. # ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk. -ecolor = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -eframe = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -egui = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -egui_extras = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -egui_plot = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 -emath = { git = "https://github.com/emilk/egui.git", rev = "ab39420c2933d2e402999043375b64e7cf0ee9ed" } # egui master 2024-01-29 +ecolor = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +eframe = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +egui = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +egui_extras = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +egui_plot = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +emath = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 # Useful while developing: # ecolor = { path = "../../egui/crates/ecolor" } diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index dd4dfa353155..8ef34e51ee8e 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -6,8 +6,7 @@ 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, SystemCommandSender, UiVerbosity, - ViewerContext, + DataQueryId, HoverHighlight, Item, Selection, SpaceViewId, UiVerbosity, ViewerContext, }; use super::DataUi; @@ -347,30 +346,8 @@ pub fn select_hovered_on_click( response: &egui::Response, selection: impl Into, ) { - re_tracing::profile_function!(); - - let mut selection = selection.into(); - selection.resolve_mono_instance_path_items(ctx); - let selection_state = ctx.selection_state(); - - if response.hovered() { - selection_state.set_hovered(selection.clone()); - } - - if response.double_clicked() { - if let Some((item, _)) = selection.first() { - ctx.command_sender - .send_system(re_viewer_context::SystemCommand::SetFocus(item.clone())); - } - } - - if response.clicked() { - if response.ctx.input(|i| i.modifiers.command) { - selection_state.toggle_selection(selection); - } else { - selection_state.set_selection(selection); - } - } + // TODO: inline everywhere. + ctx.select_hovered_on_click(response, selection); } /// Displays the "hover card" (i.e. big tooltip) for an instance or an entity. diff --git a/crates/re_space_view_time_series/src/space_view_class.rs b/crates/re_space_view_time_series/src/space_view_class.rs index 0d8e61df3546..4ecd71fc4faa 100644 --- a/crates/re_space_view_time_series/src/space_view_class.rs +++ b/crates/re_space_view_time_series/src/space_view_class.rs @@ -1,4 +1,4 @@ -use egui::ahash::HashSet; +use egui::ahash::{HashMap, HashSet}; use egui_plot::{Legend, Line, Plot, Points}; use re_data_store::TimeType; @@ -353,10 +353,13 @@ impl SpaceViewClass for TimeSeriesSpaceView { plot = plot.x_grid_spacer(move |spacer| ns_grid_spacer(canvas_size, &spacer)); } + let mut plot_item_id_to_entity_path = HashMap::default(); + let egui_plot::PlotResponse { inner: time_x, response, transform, + hovered_plot_item, } = plot.show(ui, |plot_ui| { if plot_ui.response().secondary_clicked() { let mut time_ctrl_write = ctx.rec_cfg.time_ctrl.write(); @@ -376,19 +379,23 @@ impl SpaceViewClass for TimeSeriesSpaceView { .collect::>(); let color = line.color; + let id = egui::Id::new(line.entity_path.hash()); + plot_item_id_to_entity_path.insert(id, line.entity_path.clone()); match line.kind { PlotSeriesKind::Continuous => plot_ui.line( Line::new(points) .name(&line.label) .color(color) - .width(line.width), + .width(line.width) + .id(id), ), PlotSeriesKind::Scatter => plot_ui.points( Points::new(points) .name(&line.label) .color(color) - .radius(line.width), + .radius(line.width) + .id(id), ), // Break up the chart. At some point we might want something fancier. PlotSeriesKind::Clear => {} @@ -418,6 +425,19 @@ impl SpaceViewClass for TimeSeriesSpaceView { .map(|x| plot_ui.screen_from_plot([x, 0.0].into()).x) }); + // Interact with the plot items (lines, scatters, etc.) + if let Some(hovered_plot_item) = hovered_plot_item { + if let Some(entity_path) = plot_item_id_to_entity_path.get(&hovered_plot_item) { + ctx.select_hovered_on_click( + &response, + re_viewer_context::Item::InstancePath( + Some(query.space_view_id), + entity_path.clone().into(), + ), + ); + } + } + if let Some(time_x) = time_x { let interact_radius = ui.style().interaction.resize_grab_radius_side; let line_rect = egui::Rect::from_x_y_ranges(time_x..=time_x, response.rect.y_range()) diff --git a/crates/re_space_view_time_series/src/visualizer_system.rs b/crates/re_space_view_time_series/src/visualizer_system.rs index 9fc79cc11eaa..6c7fdfd86087 100644 --- a/crates/re_space_view_time_series/src/visualizer_system.rs +++ b/crates/re_space_view_time_series/src/visualizer_system.rs @@ -1,5 +1,5 @@ use re_data_store::TimeRange; -use re_log_types::{StoreKind, TimeInt}; +use re_log_types::{EntityPath, StoreKind, TimeInt}; use re_query_cache::{MaybeCachedComponentData, QueryError}; use re_types::{ archetypes::TimeSeriesScalar, @@ -60,6 +60,7 @@ pub struct PlotSeries { pub width: f32, pub kind: PlotSeriesKind, pub points: Vec<(i64, f64)>, + pub entity_path: EntityPath, } /// A scene for a time series plot, with everything needed to render it. @@ -384,9 +385,10 @@ impl TimeSeriesSystem { width: 2.0 * points[0].attrs.radius, kind: PlotSeriesKind::Scatter, points: vec![(points[0].time, points[0].value)], + entity_path: data_result.entity_path.clone(), }); } else { - self.add_line_segments(&line_label, points); + self.add_line_segments(&line_label, points, &data_result.entity_path); } } @@ -398,7 +400,12 @@ impl TimeSeriesSystem { // A line segment is a continuous run of points with identical attributes: each time // we notice a change in attributes, we need a new line segment. #[inline(never)] // Better callstacks on crashes - fn add_line_segments(&mut self, line_label: &str, points: Vec) { + fn add_line_segments( + &mut self, + line_label: &str, + points: Vec, + entity_path: &EntityPath, + ) { re_tracing::profile_function!(); let num_points = points.len(); @@ -409,6 +416,7 @@ impl TimeSeriesSystem { width: 2.0 * attrs.radius, points: Vec::with_capacity(num_points), kind: attrs.kind, + entity_path: entity_path.clone(), }; for (i, p) in points.into_iter().enumerate() { @@ -429,6 +437,7 @@ impl TimeSeriesSystem { width: 2.0 * attrs.radius, kind: attrs.kind, points: Vec::with_capacity(num_points - i), + entity_path: entity_path.clone(), }, ); diff --git a/crates/re_viewer_context/src/viewer_context.rs b/crates/re_viewer_context/src/viewer_context.rs index 5c7584b9eb51..ece85da42ba5 100644 --- a/crates/re_viewer_context/src/viewer_context.rs +++ b/crates/re_viewer_context/src/viewer_context.rs @@ -7,7 +7,7 @@ use re_entity_db::entity_db::EntityDb; use crate::{ query_context::DataQueryResult, AppOptions, ApplicableEntities, ApplicationSelectionState, Caches, CommandSender, ComponentUiRegistry, DataQueryId, IndicatedEntities, PerVisualizer, - Selection, SpaceViewClassRegistry, StoreContext, TimeControl, + Selection, SpaceViewClassRegistry, StoreContext, SystemCommandSender as _, TimeControl, }; /// Common things needed by many parts of the viewer. @@ -91,6 +91,38 @@ impl<'a> ViewerContext<'a> { pub fn current_query(&self) -> re_data_store::LatestAtQuery { self.rec_cfg.time_ctrl.read().current_query() } + + /// Set hover/select/focus for a given selection based on an egui response. + pub fn select_hovered_on_click( + &self, + response: &egui::Response, + selection: impl Into, + ) { + re_tracing::profile_function!(); + + let mut selection = selection.into(); + selection.resolve_mono_instance_path_items(self); + let selection_state = self.selection_state(); + + if response.hovered() { + selection_state.set_hovered(selection.clone()); + } + + if response.double_clicked() { + if let Some((item, _)) = selection.first() { + self.command_sender + .send_system(crate::SystemCommand::SetFocus(item.clone())); + } + } + + if response.clicked() { + if response.ctx.input(|i| i.modifiers.command) { + selection_state.toggle_selection(selection); + } else { + selection_state.set_selection(selection); + } + } + } } // ---------------------------------------------------------------------------- From 4f95ba2db3e2443d07bb50dd4905ae8d5cf7cce3 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 30 Jan 2024 10:50:54 +0100 Subject: [PATCH 2/5] replace item_ui::select_hovered_on_click wit ctx.select_hovered_on_click --- crates/re_data_ui/src/item_ui.rs | 14 ++------------ crates/re_space_view_spatial/src/ui.rs | 2 +- crates/re_time_panel/src/lib.rs | 5 ++--- crates/re_viewer/src/ui/selection_panel.rs | 2 +- crates/re_viewport/src/viewport.rs | 4 ++-- crates/re_viewport/src/viewport_blueprint_ui.rs | 7 +++---- .../src/color_coordinates_space_view.rs | 3 +-- 7 files changed, 12 insertions(+), 25 deletions(-) diff --git a/crates/re_data_ui/src/item_ui.rs b/crates/re_data_ui/src/item_ui.rs index 8ef34e51ee8e..e22330569ee4 100644 --- a/crates/re_data_ui/src/item_ui.rs +++ b/crates/re_data_ui/src/item_ui.rs @@ -6,7 +6,7 @@ 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, + DataQueryId, HoverHighlight, Item, SpaceViewId, UiVerbosity, ViewerContext, }; use super::DataUi; @@ -330,7 +330,7 @@ pub fn cursor_interact_with_selectable( let is_item_hovered = ctx.selection_state().highlight_for_ui_element(&item) == HoverHighlight::Hovered; - select_hovered_on_click(ctx, &response, item); + ctx.select_hovered_on_click(&response, item); // TODO(andreas): How to deal with shift click for selecting ranges? if is_item_hovered { @@ -340,16 +340,6 @@ pub fn cursor_interact_with_selectable( } } -// TODO(andreas): Move elsewhere, this is not directly part of the item_ui. -pub fn select_hovered_on_click( - ctx: &ViewerContext<'_>, - response: &egui::Response, - selection: impl Into, -) { - // TODO: inline everywhere. - ctx.select_hovered_on_click(response, selection); -} - /// 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. diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 4029b5979a5b..e252613c8116 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -661,7 +661,7 @@ pub fn picking( }); }; - item_ui::select_hovered_on_click(ctx, &response, re_viewer_context::Selection(hovered_items)); + ctx.select_hovered_on_click( &response, re_viewer_context::Selection(hovered_items)); Ok(response) } diff --git a/crates/re_time_panel/src/lib.rs b/crates/re_time_panel/src/lib.rs index 6b8ef70b0e73..2e764d29503d 100644 --- a/crates/re_time_panel/src/lib.rs +++ b/crates/re_time_panel/src/lib.rs @@ -13,7 +13,6 @@ mod time_selection_ui; use egui::emath::Rangef; use egui::{pos2, Color32, CursorIcon, NumExt, Painter, PointerButton, Rect, Shape, Ui, Vec2}; -use re_data_ui::item_ui; use re_entity_db::{EntityTree, InstancePath, TimeHistogram}; use re_log_types::{ external::re_types_core::ComponentName, ComponentPath, EntityPath, EntityPathPart, TimeInt, @@ -602,7 +601,7 @@ impl TimePanel { ); }); - item_ui::select_hovered_on_click(ctx, &response, item.to_item()); + ctx.select_hovered_on_click(&response, item.to_item()); let is_closed = body_response.is_none(); let response_rect = response.rect; @@ -713,7 +712,7 @@ impl TimePanel { ui.set_clip_rect(clip_rect_save); - re_data_ui::item_ui::select_hovered_on_click(ctx, &response, item.to_item()); + ctx.select_hovered_on_click(&response, item.to_item()); let response_rect = response.rect; diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index 3b0986d83215..600af6bbaaff 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -764,7 +764,7 @@ fn show_list_item_for_container_child( let response = list_item.show(ui); - item_ui::select_hovered_on_click(ctx, &response, std::iter::once(item)); + ctx.select_hovered_on_click(&response, std::iter::once(item)); if remove_contents { viewport.blueprint.mark_user_interaction(ctx); diff --git a/crates/re_viewport/src/viewport.rs b/crates/re_viewport/src/viewport.rs index c73e4953ab26..3b0ca0da5c17 100644 --- a/crates/re_viewport/src/viewport.rs +++ b/crates/re_viewport/src/viewport.rs @@ -8,7 +8,6 @@ use ahash::HashMap; use egui_tiles::Behavior as _; use once_cell::sync::Lazy; -use re_data_ui::item_ui; use re_entity_db::EntityPropertyMap; use re_ui::{Icon, ReUi}; @@ -580,7 +579,8 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { } if let Some(egui_tiles::Tile::Pane(space_view_id)) = tiles.get(tile_id) { - item_ui::select_hovered_on_click(self.ctx, &response, Item::SpaceView(*space_view_id)); + self.ctx + .select_hovered_on_click(&response, Item::SpaceView(*space_view_id)); } response diff --git a/crates/re_viewport/src/viewport_blueprint_ui.rs b/crates/re_viewport/src/viewport_blueprint_ui.rs index 2b1b01bbeb0d..1350ef95dd76 100644 --- a/crates/re_viewport/src/viewport_blueprint_ui.rs +++ b/crates/re_viewport/src/viewport_blueprint_ui.rs @@ -1,7 +1,6 @@ use egui::{Response, Ui}; use itertools::Itertools; -use re_data_ui::item_ui; use re_entity_db::InstancePath; use re_log_types::{EntityPath, EntityPathRule}; use re_space_view::DataQueryBlueprint; @@ -110,7 +109,7 @@ impl Viewport<'_, '_> { }) .item_response; - item_ui::select_hovered_on_click(ctx, &response, item); + ctx.select_hovered_on_click(&response, item); if remove { self.blueprint.mark_user_interaction(ctx); @@ -207,7 +206,7 @@ impl Viewport<'_, '_> { self.blueprint.focus_tab(space_view.id); } - item_ui::select_hovered_on_click(ctx, &response, item); + ctx.select_hovered_on_click(&response, item); if visibility_changed { if self.blueprint.auto_layout { @@ -402,7 +401,7 @@ impl Viewport<'_, '_> { }; data_result.save_override(Some(properties), ctx); - item_ui::select_hovered_on_click(ctx, &response, item); + ctx.select_hovered_on_click(&response, item); } } diff --git a/examples/rust/custom_space_view/src/color_coordinates_space_view.rs b/examples/rust/custom_space_view/src/color_coordinates_space_view.rs index 306ad497e3b7..4de90457c8e4 100644 --- a/examples/rust/custom_space_view/src/color_coordinates_space_view.rs +++ b/examples/rust/custom_space_view/src/color_coordinates_space_view.rs @@ -277,8 +277,7 @@ fn color_space_ui( ctx.entity_db.store(), ); }); - item_ui::select_hovered_on_click( - ctx, + ctx.select_hovered_on_click( &interact, Item::InstancePath(Some(query.space_view_id), instance), ); From a6c43a4e778c05133600eed9111c270692ff9f43 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 30 Jan 2024 16:12:54 +0100 Subject: [PATCH 3/5] latest upstream egui --- Cargo.lock | 21 +++++++++++---------- Cargo.toml | 14 +++++++------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7922094481c..2ed4ede6e8ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1559,7 +1559,7 @@ checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" [[package]] name = "ecolor" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "bytemuck", "serde", @@ -1568,7 +1568,7 @@ dependencies = [ [[package]] name = "eframe" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "bytemuck", "cocoa", @@ -1593,6 +1593,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "web-time", "wgpu", "winapi", "winit", @@ -1601,7 +1602,7 @@ dependencies = [ [[package]] name = "egui" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "accesskit", "ahash", @@ -1617,7 +1618,7 @@ dependencies = [ [[package]] name = "egui-wgpu" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "bytemuck", "egui", @@ -1634,7 +1635,7 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "accesskit_winit", "arboard", @@ -1663,7 +1664,7 @@ dependencies = [ [[package]] name = "egui_extras" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "egui", "ehttp", @@ -1678,7 +1679,7 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "bytemuck", "egui", @@ -1695,7 +1696,7 @@ dependencies = [ [[package]] name = "egui_plot" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "egui", ] @@ -1738,7 +1739,7 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "emath" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "bytemuck", "serde", @@ -1839,7 +1840,7 @@ dependencies = [ [[package]] name = "epaint" version = "0.25.0" -source = "git+https://github.com/emilk/egui.git?rev=37aa3973a2046e38c502f9fdb941c76fbd7a5f84#37aa3973a2046e38c502f9fdb941c76fbd7a5f84" +source = "git+https://github.com/emilk/egui.git?rev=ca513ce241c6511275e92b05b2953c38fa6086e1#ca513ce241c6511275e92b05b2953c38fa6086e1" dependencies = [ "ab_glyph", "ahash", diff --git a/Cargo.toml b/Cargo.toml index 416122ddf3ac..a2e0cc21a4ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -277,13 +277,13 @@ debug = true # As a last resport, patch with a commit to our own repository. # ALWAYS document what PR the commit hash is part of, or when it was merged into the upstream trunk. -ecolor = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -eframe = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -egui = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -egui_extras = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -egui_plot = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 -emath = { git = "https://github.com/emilk/egui.git", rev = "37aa3973a2046e38c502f9fdb941c76fbd7a5f84" } # egui TODO: 2024-01-29 +ecolor = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +eframe = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +egui = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +egui_extras = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +egui_plot = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +egui-wgpu = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 +emath = { git = "https://github.com/emilk/egui.git", rev = "ca513ce241c6511275e92b05b2953c38fa6086e1" } # egui Ids on plot items. 2024-01-30 # Useful while developing: # ecolor = { path = "../../egui/crates/ecolor" } From 1afc771a49eeb46dfcbc4a104f3575f89dd5f48d Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 30 Jan 2024 16:24:35 +0100 Subject: [PATCH 4/5] fixups for latest egui, allow selecting entities in bar chart plot --- .../src/space_view_class.rs | 31 ++++++++++++++++--- crates/re_space_view_spatial/src/ui.rs | 14 ++++----- crates/re_space_view_spatial/src/ui_2d.rs | 3 +- crates/re_space_view_spatial/src/ui_3d.rs | 3 +- .../src/space_view_class.rs | 20 ++++++------ .../re_viewer/src/ui/selection_history_ui.rs | 4 +-- 6 files changed, 48 insertions(+), 27 deletions(-) diff --git a/crates/re_space_view_bar_chart/src/space_view_class.rs b/crates/re_space_view_bar_chart/src/space_view_class.rs index a3f4fc6acf3f..cddf02cbeb09 100644 --- a/crates/re_space_view_bar_chart/src/space_view_class.rs +++ b/crates/re_space_view_bar_chart/src/space_view_class.rs @@ -1,4 +1,4 @@ -use egui::util::hash; +use egui::{ahash::HashMap, util::hash}; use re_entity_db::{EditableAutoValue, EntityProperties, LegendCorner}; use re_log_types::EntityPath; use re_space_view::{controls, suggest_space_view_for_each_entity}; @@ -132,11 +132,11 @@ impl SpaceViewClass for BarChartSpaceView { fn ui( &self, - _ctx: &ViewerContext<'_>, + ctx: &ViewerContext<'_>, ui: &mut egui::Ui, _state: &mut Self::State, root_entity_properties: &EntityProperties, - _query: &ViewQuery<'_>, + query: &ViewQuery<'_>, system_output: re_viewer_context::SystemExecutionOutput, ) -> Result<(), SpaceViewSystemExecutionError> { use egui_plot::{Bar, BarChart, Legend, Plot}; @@ -164,7 +164,13 @@ impl SpaceViewClass for BarChartSpaceView { ); } - plot.show(ui, |plot_ui| { + let mut plot_item_id_to_entity_path = HashMap::default(); + + let egui_plot::PlotResponse { + response, + hovered_plot_item, + .. + } = plot.show(ui, |plot_ui| { fn create_bar_chart>( ent_path: &EntityPath, values: impl Iterator, @@ -251,9 +257,26 @@ impl SpaceViewClass for BarChartSpaceView { } }; + let id = egui::Id::new(ent_path.hash()); + plot_item_id_to_entity_path.insert(id, ent_path.clone()); + let chart = chart.id(id); + plot_ui.bar_chart(chart); } }); + + // Interact with the plot items. + if let Some(entity_path) = hovered_plot_item + .and_then(|hovered_plot_item| plot_item_id_to_entity_path.get(&hovered_plot_item)) + { + ctx.select_hovered_on_click( + &response, + re_viewer_context::Item::InstancePath( + Some(query.space_view_id), + entity_path.clone().into(), + ), + ); + } }); Ok(()) diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index e252613c8116..f95e168086f1 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -393,13 +393,13 @@ pub fn outline_config(gui_ctx: &egui::Context) -> OutlineConfig { pub fn screenshot_context_menu( _ctx: &ViewerContext<'_>, - response: egui::Response, -) -> (egui::Response, Option) { + response: &egui::Response, +) -> Option { #[cfg(not(target_arch = "wasm32"))] { if _ctx.app_options.experimental_space_view_screenshots { let mut take_screenshot = None; - let response = response.context_menu(|ui| { + response.context_menu(|ui| { ui.style_mut().wrap = Some(false); if ui.button("Save screenshot to disk").clicked() { take_screenshot = Some(ScreenshotMode::SaveAndCopyToClipboard); @@ -409,14 +409,14 @@ pub fn screenshot_context_menu( ui.close_menu(); } }); - (response, take_screenshot) + take_screenshot } else { - (response, None) + None } } #[cfg(target_arch = "wasm32")] { - (response, None) + None } } @@ -661,7 +661,7 @@ pub fn picking( }); }; - ctx.select_hovered_on_click( &response, re_viewer_context::Selection(hovered_items)); + ctx.select_hovered_on_click(&response, re_viewer_context::Selection(hovered_items)); Ok(response) } diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index 1696838a1008..5978d0afa09c 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -355,8 +355,7 @@ pub fn view_2d( // ------------------------------------------------------------------------ // Screenshot context menu. - let (_, screenshot_mode) = screenshot_context_menu(ctx, response); - if let Some(mode) = screenshot_mode { + if let Some(mode) = screenshot_context_menu(ctx, &response) { view_builder .schedule_screenshot(ctx.render_ctx, query.space_view_id.gpu_readback_id(), mode) .ok(); diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 90fe399e6c5f..dbe604b725ee 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -581,8 +581,7 @@ pub fn view_3d( } // Screenshot context menu. - let (_, screenshot_mode) = screenshot_context_menu(ctx, response); - if let Some(mode) = screenshot_mode { + if let Some(mode) = screenshot_context_menu(ctx, &response) { view_builder .schedule_screenshot(ctx.render_ctx, query.space_view_id.gpu_readback_id(), mode) .ok(); diff --git a/crates/re_space_view_time_series/src/space_view_class.rs b/crates/re_space_view_time_series/src/space_view_class.rs index 4ecd71fc4faa..7933ea5a2d3c 100644 --- a/crates/re_space_view_time_series/src/space_view_class.rs +++ b/crates/re_space_view_time_series/src/space_view_class.rs @@ -426,16 +426,16 @@ impl SpaceViewClass for TimeSeriesSpaceView { }); // Interact with the plot items (lines, scatters, etc.) - if let Some(hovered_plot_item) = hovered_plot_item { - if let Some(entity_path) = plot_item_id_to_entity_path.get(&hovered_plot_item) { - ctx.select_hovered_on_click( - &response, - re_viewer_context::Item::InstancePath( - Some(query.space_view_id), - entity_path.clone().into(), - ), - ); - } + if let Some(entity_path) = hovered_plot_item + .and_then(|hovered_plot_item| plot_item_id_to_entity_path.get(&hovered_plot_item)) + { + ctx.select_hovered_on_click( + &response, + re_viewer_context::Item::InstancePath( + Some(query.space_view_id), + entity_path.clone().into(), + ), + ); } if let Some(time_x) = time_x { diff --git a/crates/re_viewer/src/ui/selection_history_ui.rs b/crates/re_viewer/src/ui/selection_history_ui.rs index c9a23305b9ba..dc0e3df1d660 100644 --- a/crates/re_viewer/src/ui/selection_history_ui.rs +++ b/crates/re_viewer/src/ui/selection_history_ui.rs @@ -43,7 +43,7 @@ impl SelectionHistoryUi { )); let mut return_current = false; - let response = response.context_menu(|ui| { + response.context_menu(|ui| { // undo: newest on top, oldest on bottom let cur = history.current; for i in (0..history.current).rev() { @@ -93,7 +93,7 @@ impl SelectionHistoryUi { )); let mut return_current = false; - let response = response.context_menu(|ui| { + response.context_menu(|ui| { // redo: oldest on top, most recent on bottom let cur = history.current; for i in (history.current + 1)..history.stack.len() { From f3f871cc9d2504b9c12a445787116a69af91f47f Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Tue, 30 Jan 2024 16:57:54 +0100 Subject: [PATCH 5/5] web warning fix --- crates/re_space_view_spatial/src/ui.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index f95e168086f1..f5f4c25b8914 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -393,13 +393,13 @@ pub fn outline_config(gui_ctx: &egui::Context) -> OutlineConfig { pub fn screenshot_context_menu( _ctx: &ViewerContext<'_>, - response: &egui::Response, + _response: &egui::Response, ) -> Option { #[cfg(not(target_arch = "wasm32"))] { if _ctx.app_options.experimental_space_view_screenshots { let mut take_screenshot = None; - response.context_menu(|ui| { + _response.context_menu(|ui| { ui.style_mut().wrap = Some(false); if ui.button("Save screenshot to disk").clicked() { take_screenshot = Some(ScreenshotMode::SaveAndCopyToClipboard);