Skip to content

Commit

Permalink
item selections now are associated with an optional space context
Browse files Browse the repository at this point in the history
  • Loading branch information
Wumpf committed Dec 20, 2023
1 parent 4af4b4e commit c196717
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 300 deletions.
28 changes: 18 additions & 10 deletions crates/re_data_ui/src/item_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use egui::Ui;
use re_data_store::{EntityTree, InstancePath};
use re_log_types::{ComponentPath, EntityPath, TimeInt, Timeline};
use re_viewer_context::{
DataQueryId, HoverHighlight, Item, SpaceViewId, UiVerbosity, ViewerContext,
DataQueryId, HoverHighlight, Item, Selection, SpaceViewId, UiVerbosity, ViewerContext,
};

use super::DataUi;
Expand Down Expand Up @@ -97,7 +97,7 @@ pub fn instance_path_button_to(
let item = Item::InstancePath(space_view_id, instance_path.clone());

let response = ui
.selectable_label(ctx.selection().contains(&item), text)
.selectable_label(ctx.selection().contains_item(&item), text)
.on_hover_ui(|ui| {
instance_hover_card_ui(ui, ctx, instance_path);
});
Expand Down Expand Up @@ -205,7 +205,7 @@ pub fn component_path_button_to(
component_path: &ComponentPath,
) -> egui::Response {
let item = Item::ComponentPath(component_path.clone());
let response = ui.selectable_label(ctx.selection().contains(&item), text);
let response = ui.selectable_label(ctx.selection().contains_item(&item), text);
cursor_interact_with_selectable(ctx, response, item)
}

Expand All @@ -224,7 +224,7 @@ pub fn data_blueprint_group_button_to(
ui,
&re_ui::icons::CONTAINER,
text,
ctx.selection().contains(&item),
ctx.selection().contains_item(&item),
)
.on_hover_text("Group");
cursor_interact_with_selectable(ctx, response, item)
Expand All @@ -242,7 +242,7 @@ pub fn data_blueprint_button_to(
InstancePath::entity_splat(entity_path.clone()),
);
let response = ui
.selectable_label(ctx.selection().contains(&item), text)
.selectable_label(ctx.selection().contains_item(&item), text)
.on_hover_ui(|ui| {
entity_hover_card_ui(ui, ctx, entity_path);
});
Expand Down Expand Up @@ -313,7 +313,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]);
select_hovered_on_click(ctx, &response, item);
// TODO(andreas): How to deal with shift click for selecting ranges?

if is_item_hovered {
Expand All @@ -324,18 +324,26 @@ 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, items: &[Item]) {
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() {
ctx.set_hovered(items.iter());
selection_state.set_hovered(selection.clone());
}

if response.clicked() {
if response.ctx.input(|i| i.modifiers.command) {
ctx.selection_state().toggle_selection(items.to_vec());
selection_state.toggle_selection(selection);
} else {
ctx.selection_state().set_selection(items.iter().cloned());
selection_state.set_selection(selection);
}
}
}
Expand Down
79 changes: 40 additions & 39 deletions crates/re_space_view_spatial/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ use re_space_view::ScreenshotMode;
use re_types::components::{DepthMeter, InstanceKey, TensorData};
use re_types::tensor_data::TensorDataMeaning;
use re_viewer_context::{
resolve_mono_instance_path, HoverHighlight, Item, SelectedSpaceContext, SelectionHighlight,
SpaceViewHighlights, SpaceViewState, SpaceViewSystemExecutionError, TensorDecodeCache,
TensorStatsCache, UiVerbosity, ViewContextCollection, ViewPartCollection, ViewQuery,
ViewerContext,
HoverHighlight, Item, SelectedSpaceContext, SelectionHighlight, SpaceViewHighlights,
SpaceViewState, SpaceViewSystemExecutionError, TensorDecodeCache, TensorStatsCache,
UiVerbosity, ViewContextCollection, ViewPartCollection, ViewQuery, ViewerContext,
};

use super::{eye::Eye, ui_2d::View2DState, ui_3d::View3DState};
Expand Down Expand Up @@ -564,8 +563,6 @@ pub fn picking(
if picked_image_with_coords.is_some() {
// We don't support selecting pixels yet.
instance_path.instance_key = InstanceKey::SPLAT;
} else {
instance_path = resolve_mono_instance_path(&ctx.current_query(), store, &instance_path);
}

hovered_items.push(Item::InstancePath(
Expand Down Expand Up @@ -627,41 +624,45 @@ pub fn picking(
};
}

item_ui::select_hovered_on_click(ctx, &response, &hovered_items);

let hovered_space = match spatial_kind {
SpatialSpaceViewKind::TwoD => SelectedSpaceContext::TwoD {
space_2d: query.space_origin.clone(),
pos: picking_context
.pointer_in_space2d
.extend(depth_at_pointer.unwrap_or(f32::INFINITY)),
},
SpatialSpaceViewKind::ThreeD => {
let hovered_point = picking_result.space_position();
SelectedSpaceContext::ThreeD {
space_3d: query.space_origin.clone(),
pos: hovered_point,
tracked_space_camera: state.state_3d.tracked_camera.clone(),
point_in_space_cameras: parts
.get::<CamerasPart>()?
.space_cameras
.iter()
.map(|cam| {
(
cam.ent_path.clone(),
hovered_point.and_then(|pos| cam.project_onto_2d(pos)),
)
})
.collect(),
// Associate the hovered space with the first item in the hovered item list.
// If we were to add several, space views might render unnecessary additional hints.
// TODO(andreas): Should there be context if no item is hovered at all? There's no usecase for that today it seems.
let mut hovered_items = hovered_items
.into_iter()
.map(|item| (item, None))
.collect::<Vec<_>>();

if let Some((_, context)) = hovered_items.first_mut() {
*context = Some(match spatial_kind {
SpatialSpaceViewKind::TwoD => SelectedSpaceContext::TwoD {
space_2d: query.space_origin.clone(),
pos: picking_context
.pointer_in_space2d
.extend(depth_at_pointer.unwrap_or(f32::INFINITY)),
},
SpatialSpaceViewKind::ThreeD => {
let hovered_point = picking_result.space_position();
SelectedSpaceContext::ThreeD {
space_3d: query.space_origin.clone(),
pos: hovered_point,
tracked_space_camera: state.state_3d.tracked_camera.clone(),
point_in_space_cameras: parts
.get::<CamerasPart>()?
.space_cameras
.iter()
.map(|cam| {
(
cam.ent_path.clone(),
hovered_point.and_then(|pos| cam.project_onto_2d(pos)),
)
})
.collect(),
}
}
}
});
};
ctx.selection_state()
.set_hovered_space_context(hovered_space.clone());
if response.clicked() {
ctx.selection_state()
.set_selected_space_context(hovered_space);
}

item_ui::select_hovered_on_click(ctx, &response, re_viewer_context::Selection(hovered_items));

Ok(response)
}
Expand Down
32 changes: 18 additions & 14 deletions crates/re_space_view_spatial/src/ui_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,20 +370,24 @@ pub fn view_2d(
));

// Make sure to _first_ draw the selected, and *then* the hovered context on top!
painter.extend(show_projections_from_3d_space(
ui,
query.space_origin,
&ui_from_canvas,
ctx.selection_state().selected_space_context(),
ui.style().visuals.selection.bg_fill,
));
painter.extend(show_projections_from_3d_space(
ui,
query.space_origin,
&ui_from_canvas,
ctx.selection_state().hovered_space_context(),
egui::Color32::WHITE,
));
for selected_context in ctx.selection_state().selected_space_context() {
painter.extend(show_projections_from_3d_space(
ui,
query.space_origin,
&ui_from_canvas,
selected_context,
ui.style().visuals.selection.bg_fill,
));
}
if let Some(hovered_context) = ctx.selection_state().hovered_space_context() {
painter.extend(show_projections_from_3d_space(
ui,
query.space_origin,
&ui_from_canvas,
hovered_context,
egui::Color32::WHITE,
));
}

// Add egui driven labels on top of re_renderer content.
painter.extend(label_shapes);
Expand Down
40 changes: 22 additions & 18 deletions crates/re_space_view_spatial/src/ui_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,16 +448,16 @@ pub fn view_3d(
state.state_3d.camera_before_tracked_camera = None;

// While hovering an entity, focuses the camera on it.
if let Some(Item::InstancePath(_, instance_path)) = ctx.hovered().first() {
if let Some((Item::InstancePath(_, instance_path), _)) = ctx.hovered().first() {
if let Some(camera) = find_camera(space_cameras, &instance_path.entity_path) {
state.state_3d.camera_before_tracked_camera =
state.state_3d.orbit_eye.map(|eye| eye.to_eye());
state.state_3d.interpolate_to_eye(camera);
state.state_3d.tracked_camera = Some(instance_path.entity_path.clone());
} else if let SelectedSpaceContext::ThreeD {
} else if let Some(SelectedSpaceContext::ThreeD {
pos: Some(clicked_point),
..
} = ctx.selection_state().hovered_space_context()
}) = ctx.selection_state().hovered_space_context()
{
if let Some(mut new_orbit_eye) = state.state_3d.orbit_eye {
// TODO(andreas): It would be nice if we could focus on the center of the entity rather than the clicked point.
Expand Down Expand Up @@ -499,20 +499,24 @@ pub fn view_3d(
.ok();
}

show_projections_from_2d_space(
&mut line_builder,
space_cameras,
state,
ctx.selection_state().selected_space_context(),
ui.style().visuals.selection.bg_fill,
);
show_projections_from_2d_space(
&mut line_builder,
space_cameras,
state,
ctx.selection_state().hovered_space_context(),
egui::Color32::WHITE,
);
for selected_context in ctx.selection_state().selected_space_context() {
show_projections_from_2d_space(
&mut line_builder,
space_cameras,
state,
selected_context,
ui.style().visuals.selection.bg_fill,
);
}
if let Some(hovered_context) = ctx.selection_state().hovered_space_context() {
show_projections_from_2d_space(
&mut line_builder,
space_cameras,
state,
hovered_context,
egui::Color32::WHITE,
);
}

{
let mut box_batch = line_builder.batch("scene_bbox");
Expand Down Expand Up @@ -692,7 +696,7 @@ fn show_projections_from_2d_space(
}
}
}
_ => {}
SelectedSpaceContext::ThreeD { .. } => {}
}
}

Expand Down
8 changes: 3 additions & 5 deletions crates/re_time_panel/src/data_density_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,10 @@ pub fn data_density_graph_ui(
);

if 0 < num_hovered_messages {
ctx.rec_cfg
.selection_state
.set_hovered(std::iter::once(item.clone()));
ctx.selection_state().set_hovered(item.clone());

if time_area_response.clicked_by(egui::PointerButton::Primary) {
ctx.set_single_selection(item);
ctx.selection_state().set_selection(item.clone());
time_ctrl.set_time(hovered_time_range.min);
time_ctrl.pause();
} else if !ui.ctx().memory(|mem| mem.is_anything_being_dragged()) {
Expand All @@ -503,7 +501,7 @@ pub fn data_density_graph_ui(
}

fn graph_color(ctx: &ViewerContext<'_>, item: &Item, ui: &egui::Ui) -> Color32 {
let is_selected = ctx.selection().contains(item);
let is_selected = ctx.selection().contains_item(item);
if is_selected {
make_brighter(ui.visuals().widgets.active.fg_stroke.color)
} else {
Expand Down
15 changes: 5 additions & 10 deletions crates/re_time_panel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ mod time_selection_ui;

use egui::emath::Rangef;
use egui::{pos2, Color32, CursorIcon, NumExt, Painter, PointerButton, Rect, Shape, Ui, Vec2};
use std::slice;

use re_data_store::{EntityTree, InstancePath, TimeHistogram};
use re_data_ui::item_ui;
Expand Down Expand Up @@ -484,7 +483,7 @@ impl TimePanel {
let default_open = tree.path.len() <= 1 && !tree.is_leaf();

let item = Item::InstancePath(None, InstancePath::entity_splat(tree.path.clone()));
let is_selected = ctx.selection().contains(&item);
let is_selected = ctx.selection().contains_item(&item);
let is_item_hovered =
ctx.selection_state().highlight_for_ui_element(&item) == HoverHighlight::Hovered;

Expand Down Expand Up @@ -517,7 +516,7 @@ impl TimePanel {
let response = response
.on_hover_ui(|ui| re_data_ui::item_ui::entity_hover_card_ui(ui, ctx, &tree.path));

item_ui::select_hovered_on_click(ctx, &response, slice::from_ref(&item));
item_ui::select_hovered_on_click(ctx, &response, item.clone());

let is_closed = body_response.is_none();
let response_rect = response.rect;
Expand Down Expand Up @@ -611,7 +610,7 @@ impl TimePanel {
let response =
re_data_ui::temporary_style_ui_for_component(ui, component_name, |ui| {
ListItem::new(ctx.re_ui, short_component_name)
.selected(ctx.selection().contains(&item))
.selected(ctx.selection().contains_item(&item))
.width_allocation_mode(WidthAllocationMode::Compact)
.force_hovered(
ctx.selection_state().highlight_for_ui_element(&item)
Expand All @@ -626,11 +625,7 @@ impl TimePanel {

ui.set_clip_rect(clip_rect_save);

re_data_ui::item_ui::select_hovered_on_click(
ctx,
&response,
slice::from_ref(&item),
);
re_data_ui::item_ui::select_hovered_on_click(ctx, &response, item.clone());

let response_rect = response.rect;

Expand Down Expand Up @@ -751,7 +746,7 @@ fn highlight_timeline_row(
) {
let item_hovered =
ctx.selection_state().highlight_for_ui_element(item) == HoverHighlight::Hovered;
let item_selected = ctx.selection().contains(item);
let item_selected = ctx.selection().contains_item(item);
let bg_color = if item_selected {
Some(ui.visuals().selection.bg_fill.gamma_multiply(0.4))
} else if item_hovered {
Expand Down
Loading

0 comments on commit c196717

Please sign in to comment.