diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index 1a4bd77b997d..24f79cbcedb5 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -447,7 +447,9 @@ fn container_top_level_properties( }); // TODO(jleibs): fix container-editing - re_log::warn!("TODO(jleibs): Fix container editing"); + if container_kind != container.kind() { + re_log::warn!("TODO(jleibs): Fix container editing"); + } //container.set_kind(container_kind); ui.end_row(); diff --git a/crates/re_viewport/src/viewport.rs b/crates/re_viewport/src/viewport.rs index fb5daec05b1e..1210cad01ec5 100644 --- a/crates/re_viewport/src/viewport.rs +++ b/crates/re_viewport/src/viewport.rs @@ -214,20 +214,32 @@ impl<'a> Viewport<'a> { } if self.blueprint.auto_space_views { + let mut new_space_views = vec![]; for space_view_candidate in default_created_space_views(ctx, spaces_info, ctx.entities_per_system_per_class) { - if self.should_auto_add_space_view(&space_view_candidate) { - self.blueprint.add_space_view(space_view_candidate, ctx); + if self.should_auto_add_space_view(&new_space_views, &space_view_candidate) { + new_space_views.push(space_view_candidate); } } + self.blueprint + .add_multi_space_view(new_space_views.into_iter(), ctx); } } - fn should_auto_add_space_view(&self, space_view_candidate: &SpaceViewBlueprint) -> bool { + fn should_auto_add_space_view( + &self, + already_added: &[SpaceViewBlueprint], + space_view_candidate: &SpaceViewBlueprint, + ) -> bool { re_tracing::profile_function!(); - for existing_view in self.blueprint.space_views.values() { + for existing_view in self + .blueprint + .space_views + .values() + .chain(already_added.iter()) + { if existing_view.space_origin == space_view_candidate.space_origin { if existing_view.entities_determined_by_user { // Since the user edited a space view with the same space path, we can't be sure our new one isn't redundant. diff --git a/crates/re_viewport/src/viewport_blueprint.rs b/crates/re_viewport/src/viewport_blueprint.rs index 59f80f24c566..5cbef21012b7 100644 --- a/crates/re_viewport/src/viewport_blueprint.rs +++ b/crates/re_viewport/src/viewport_blueprint.rs @@ -25,7 +25,7 @@ use crate::{ #[derive(Clone, Default)] pub(crate) struct TreeActions { pub reset: bool, - pub create: Option, + pub create: Vec, pub focus_tab: Option, pub remove: Vec, } @@ -205,11 +205,51 @@ impl ViewportBlueprint { ); save_single_component(&VIEWPORT_PATH.into(), component, ctx); - self.deferred_tree_actions.lock().create = Some(space_view_id); + self.deferred_tree_actions.lock().create.push(space_view_id); space_view_id } + pub fn add_multi_space_view( + &self, + space_views: impl Iterator, + ctx: &ViewerContext<'_>, + ) { + let mut new_ids: Vec<_> = self.space_views.keys().cloned().collect(); + + for mut space_view in space_views { + let space_view_id = space_view.id; + + // Find a unique name for the space view + let mut candidate_name = space_view.display_name.clone(); + let mut append_count = 1; + let unique_name = 'outer: loop { + for view in &self.space_views { + if candidate_name == view.1.display_name { + append_count += 1; + candidate_name = format!("{} ({})", space_view.display_name, append_count); + + continue 'outer; + } + } + break candidate_name; + }; + + space_view.display_name = unique_name; + + // Save the space view to the store + space_view.save_full(ctx); + new_ids.push(space_view_id); + + // Update the space-view ids: + + self.deferred_tree_actions.lock().create.push(space_view_id); + } + + let component = IncludedSpaceViews(new_ids.into_iter().map(|id| id.into()).collect()); + save_single_component(&VIEWPORT_PATH.into(), component, ctx); + } + #[allow(clippy::unused_self)] pub fn space_views_containing_entity_path( &self, diff --git a/crates/re_viewport/src/viewport_blueprint_ui.rs b/crates/re_viewport/src/viewport_blueprint_ui.rs index dad9aadfff05..b58c8ce8ab46 100644 --- a/crates/re_viewport/src/viewport_blueprint_ui.rs +++ b/crates/re_viewport/src/viewport_blueprint_ui.rs @@ -44,7 +44,7 @@ impl ViewportBlueprint { let mut focus_tab = std::mem::take(&mut deferred.focus_tab); let remove = std::mem::take(&mut deferred.remove); - if let Some(create) = &create { + for space_view in &create { if self.auto_layout { // Re-run the auto-layout next frame: re_log::trace!( @@ -53,7 +53,7 @@ impl ViewportBlueprint { reset = true; } else if let Some(root_id) = tree.root { - let tile_id = tree.tiles.insert_pane(*create); + let tile_id = tree.tiles.insert_pane(*space_view); if let Some(egui_tiles::Tile::Container(container)) = tree.tiles.get_mut(root_id) { re_log::trace!("Inserting new space view into root container"); container.add_child(tile_id); @@ -65,7 +65,7 @@ impl ViewportBlueprint { re_log::trace!("No root found - will re-run auto-layout"); } - focus_tab = Some(*create); + focus_tab = Some(*space_view); } if let Some(focus_tab) = &focus_tab { @@ -89,6 +89,11 @@ impl ViewportBlueprint { } } + if tree.is_empty() && !self.space_views.is_empty() { + re_log::trace!("Tree is empty - will re-run auto-layout"); + reset = true; + } + if reset { re_log::trace!("Resetting viewport tree"); tree = super::auto_layout::tree_from_space_views(