Skip to content

Commit

Permalink
Allow selection of entitites directly in the plot space view (#4959)
Browse files Browse the repository at this point in the history
### What

* depends on emilk/egui#3920
* Fixes #4952
* Closes #4828


Wires up the new plot item ids to our hover/selection mechanism.
Moved a utility method from item_ui to ViewerContext since I didn't want
to take a dependency on `re_data_ui` here (and this method had a todo
about being in the wrong spot anyways 😄 )



https://github.com/rerun-io/rerun/assets/1220815/1ef61a4f-7e13-4661-90c6-fa53ea008823



DRAFT: Uses unpublished egui version!


### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
* Using newly built examples:
[app.rerun.io](https://app.rerun.io/pr/4959/index.html)
* Using examples from latest `main` build:
[app.rerun.io](https://app.rerun.io/pr/4959/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[app.rerun.io](https://app.rerun.io/pr/4959/index.html?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG

- [PR Build Summary](https://build.rerun.io/pr/4959)
- [Docs
preview](https://rerun.io/preview/f3f871cc9d2504b9c12a445787116a69af91f47f/docs)
<!--DOCS-PREVIEW-->
- [Examples
preview](https://rerun.io/preview/f3f871cc9d2504b9c12a445787116a69af91f47f/examples)
<!--EXAMPLES-PREVIEW-->
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)
  • Loading branch information
Wumpf authored Jan 31, 2024
1 parent d60c233 commit ffe8a10
Show file tree
Hide file tree
Showing 16 changed files with 134 additions and 88 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "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" }
Expand Down
37 changes: 2 additions & 35 deletions crates/re_data_ui/src/item_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, SpaceViewId, UiVerbosity, ViewerContext,
};

use super::DataUi;
Expand Down Expand Up @@ -331,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 {
Expand All @@ -341,38 +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<Selection>,
) {
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);
}
}
}

/// 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.
Expand Down
31 changes: 27 additions & 4 deletions crates/re_space_view_bar_chart/src/space_view_class.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -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<N: Into<f64>>(
ent_path: &EntityPath,
values: impl Iterator<Item = N>,
Expand Down Expand Up @@ -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(())
Expand Down
14 changes: 7 additions & 7 deletions crates/re_space_view_spatial/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ScreenshotMode>) {
_response: &egui::Response,
) -> Option<ScreenshotMode> {
#[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);
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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)
}
Expand Down
3 changes: 1 addition & 2 deletions crates/re_space_view_spatial/src/ui_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
3 changes: 1 addition & 2 deletions crates/re_space_view_spatial/src/ui_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
26 changes: 23 additions & 3 deletions crates/re_space_view_time_series/src/space_view_class.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use egui::ahash::HashSet;
use egui::ahash::{HashMap, HashSet};
use egui_plot::{Legend, Line, Plot, PlotPoint, Points};

use re_data_store::TimeType;
Expand Down Expand Up @@ -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: _,
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();
Expand All @@ -376,19 +379,23 @@ impl SpaceViewClass for TimeSeriesSpaceView {
.collect::<Vec<_>>();

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 => {}
Expand Down Expand Up @@ -418,6 +425,19 @@ impl SpaceViewClass for TimeSeriesSpaceView {
})
.map(|x| transform.position_from_point(&PlotPoint::new(x, 0.0)).x);

// Interact with the plot items (lines, scatters, etc.)
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(mut 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())
Expand Down
Loading

0 comments on commit ffe8a10

Please sign in to comment.