Skip to content

Commit

Permalink
Style container's label as unnamed (#4975)
Browse files Browse the repository at this point in the history
### What

This PR styles the container label like unnamed space views in the
blueprint tree and the children list (container selection panel). It
also fixes the UI and behaviour of tiles tabs for container (which
typically appear when a tab container's direct child is also a
container).

* Fixes #4966


<img width="2168" alt="image"
src="https://github.com/rerun-io/rerun/assets/49431240/833d9c56-e371-417a-8bdf-9ebf11a50c1e">


### 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/4975/index.html)
* Using examples from latest `main` build:
[app.rerun.io](https://app.rerun.io/pr/4975/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/4975/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/4975)
- [Docs
preview](https://rerun.io/preview/62492dfe767dece952ea8c12e62269e42af6053d/docs)
<!--DOCS-PREVIEW-->
- [Examples
preview](https://rerun.io/preview/62492dfe767dece952ea8c12e62269e42af6053d/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
abey79 authored Jan 31, 2024
1 parent ffe8a10 commit a7356ca
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 53 deletions.
1 change: 1 addition & 0 deletions crates/re_viewer/src/ui/selection_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,7 @@ fn show_list_item_for_container_child(
(
Item::Container(*container_id),
ListItem::new(ctx.re_ui, format!("{:?}", container.container_kind))
.label_style(re_ui::LabelStyle::Unnamed)
.with_icon(icon_for_container_kind(&container.container_kind))
.with_buttons(|re_ui, ui| {
let response = re_ui
Expand Down
155 changes: 102 additions & 53 deletions crates/re_viewport/src/viewport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use re_viewer_context::{

use crate::container::blueprint_id_to_tile_id;
use crate::{
container::Contents, space_view_entity_picker::SpaceViewEntityPicker,
container::Contents, icon_for_container_kind, space_view_entity_picker::SpaceViewEntityPicker,
space_view_heuristics::default_created_space_views,
system_execution::execute_systems_for_space_views, SpaceViewBlueprint, ViewportBlueprint,
};
Expand Down Expand Up @@ -237,6 +237,11 @@ impl<'a, 'b> Viewport<'a, 'b> {
let executed_systems_per_space_view =
execute_systems_for_space_views(ctx, tree, &blueprint.space_views);

let contents_per_tile_id = blueprint
.contents_iter()
.map(|contents| (contents.as_tile_id(), contents))
.collect();

ui.scope(|ui| {
ui.spacing_mut().item_spacing.x = re_ui::ReUi::view_padding();

Expand All @@ -249,6 +254,7 @@ impl<'a, 'b> Viewport<'a, 'b> {
maximized: &mut maximized,
edited: false,
executed_systems_per_space_view,
contents_per_tile_id,
};

tree.ui(&mut tab_viewer, ui);
Expand Down Expand Up @@ -519,6 +525,9 @@ struct TabViewer<'a, 'b> {
/// List of query & system execution results for each space view.
executed_systems_per_space_view: HashMap<SpaceViewId, (ViewQuery<'a>, SystemExecutionOutput)>,

/// List of contents for each tile id
contents_per_tile_id: HashMap<egui_tiles::TileId, Contents>,

/// The user edited the tree.
edited: bool,
}
Expand Down Expand Up @@ -591,26 +600,6 @@ impl<'a, 'b> egui_tiles::Behavior<SpaceViewId> for TabViewer<'a, 'b> {
}
}

fn tab_title_for_tile(
&mut self,
tiles: &egui_tiles::Tiles<SpaceViewId>,
tile_id: egui_tiles::TileId,
) -> egui::WidgetText {
if let Some(tile) = tiles.get(tile_id) {
match tile {
egui_tiles::Tile::Pane(pane) => self.tab_title_for_pane(pane),

// E.g. a tab with a grid of other tiles
egui_tiles::Tile::Container(container) => {
format!("{:?} Container", container.kind()).into()
}
}
} else {
re_log::warn_once!("SpaceViewId missing during tab_title_for_tile");
self.ctx.re_ui.error_text("Internal error").into()
}
}

#[allow(clippy::fn_params_excessive_bools)]
fn tab_ui(
&mut self,
Expand All @@ -630,9 +619,22 @@ impl<'a, 'b> egui_tiles::Behavior<SpaceViewId> for TabViewer<'a, 'b> {
tab_widget.paint(ui);
}

if let Some(egui_tiles::Tile::Pane(space_view_id)) = tiles.get(tile_id) {
self.ctx
.select_hovered_on_click(&response, Item::SpaceView(*space_view_id));
match tiles.get(tile_id) {
Some(egui_tiles::Tile::Pane(space_view_id)) => {
self.ctx
.select_hovered_on_click(&response, Item::SpaceView(*space_view_id));
}

Some(egui_tiles::Tile::Container(_)) => {
if let Some(Contents::Container(container_id)) =
self.contents_per_tile_id.get(&tile_id)
{
self.ctx
.select_hovered_on_click(&response, Item::Container(*container_id));
}
}

None => {}
}

response
Expand Down Expand Up @@ -783,42 +785,89 @@ impl TabWidget {
active: bool,
gamma: f32,
) -> Self {
// Not all tabs are for tiles (space views) - some are for containers (e.g. a grid of space views).
let space_view = if let Some(egui_tiles::Tile::Pane(space_view_id)) = tiles.get(tile_id) {
tab_viewer.space_views.get(space_view_id)
} else {
None
struct TabDesc {
label: egui::WidgetText,
user_named: bool,
icon: &'static re_ui::Icon,
item: Option<Item>,
}

let tab_desc = match tiles.get(tile_id) {
Some(egui_tiles::Tile::Pane(space_view_id)) => {
if let Some(space_view) = tab_viewer.space_views.get(space_view_id) {
TabDesc {
label: tab_viewer.tab_title_for_pane(space_view_id),
user_named: space_view.display_name.is_some(),
icon: space_view
.class(tab_viewer.ctx.space_view_class_registry)
.icon(),
item: Some(Item::SpaceView(*space_view_id)),
}
} else {
re_log::warn_once!("Space View {space_view_id} not found");

TabDesc {
label: tab_viewer.ctx.re_ui.error_text("Unknown Space View").into(),
icon: &re_ui::icons::SPACE_VIEW_GENERIC,
user_named: false,
item: None,
}
}
}
Some(egui_tiles::Tile::Container(container)) => {
if let Some(Contents::Container(container_id)) =
tab_viewer.contents_per_tile_id.get(&tile_id)
{
TabDesc {
label: format!("{:?}", container.kind()).into(),
user_named: false,
icon: icon_for_container_kind(&container.kind()),
item: Some(Item::Container(*container_id)),
}
} else {
re_log::warn_once!("Container for tile ID {tile_id:?} not found");

TabDesc {
label: tab_viewer.ctx.re_ui.error_text("Unknown Container").into(),
icon: &re_ui::icons::SPACE_VIEW_GENERIC,
user_named: false,
item: None,
}
}
}
None => {
re_log::warn_once!("Tile {tile_id:?} not found");

TabDesc {
label: tab_viewer.ctx.re_ui.error_text("Internal error").into(),
icon: &re_ui::icons::SPACE_VIEW_UNKNOWN,
user_named: false,
item: None,
}
}
};
let selected = space_view.map_or(false, |space_view| {
tab_viewer
.ctx
.selection()
.contains_item(&Item::SpaceView(space_view.id))
});
let named = space_view.map_or(false, |space_view| space_view.display_name.is_some());

let hovered = space_view.map_or(false, |space_view| {
tab_viewer
.ctx
.hovered()
.contains_item(&Item::SpaceView(space_view.id))
});
let hovered = tab_desc
.item
.as_ref()
.map_or(false, |item| tab_viewer.ctx.hovered().contains_item(item));
let selected = tab_desc
.item
.as_ref()
.map_or(false, |item| tab_viewer.ctx.selection().contains_item(item));

// tab icon
let icon_size = ReUi::small_icon_size();
let icon_width_plus_padding = icon_size.x + ReUi::text_to_icon_padding();
let icon = space_view.map_or(&re_ui::icons::SPACE_VIEW_GENERIC, |space_view| {
space_view
.class(tab_viewer.ctx.space_view_class_registry)
.icon()
});

// tab title
let mut text = tab_viewer.tab_title_for_tile(tiles, tile_id);
if !named {
let text = if !tab_desc.user_named {
//TODO(ab): use design tokens
text = text.italics();
}
tab_desc.label.italics()
} else {
tab_desc.label
};

let font_id = egui::TextStyle::Button.resolve(ui.style());
let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id);

Expand Down Expand Up @@ -852,12 +901,12 @@ impl TabWidget {
galley,
rect,
galley_rect,
icon,
icon: tab_desc.icon,
icon_size,
icon_rect,
bg_color,
text_color,
unnamed_style: !named,
unnamed_style: !tab_desc.user_named,
}
}

Expand Down
12 changes: 12 additions & 0 deletions crates/re_viewport/src/viewport_blueprint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,18 @@ impl ViewportBlueprint {
new_ids
}

/// Returns an iterator over all the contents (space views and containers) in the viewport.
pub fn contents_iter(&self) -> impl Iterator<Item = Contents> + '_ {
self.space_views
.keys()
.map(|space_view_id| Contents::SpaceView(*space_view_id))
.chain(
self.containers
.keys()
.map(|container_id| Contents::Container(*container_id)),
)
}

/// Given a predicate, finds the (first) matching contents by recursively walking from the root
/// container.
pub fn find_contents_by(&self, predicate: &impl Fn(&Contents) -> bool) -> Option<Contents> {
Expand Down
1 change: 1 addition & 0 deletions crates/re_viewport/src/viewport_blueprint_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ impl Viewport<'_, '_> {
.selected(ctx.selection().contains_item(&item))
.draggable(true)
.drop_target_style(self.state.is_candidate_drop_parent_container(container_id))
.label_style(re_ui::LabelStyle::Unnamed)
.with_icon(crate::icon_for_container_kind(
&container_blueprint.container_kind,
))
Expand Down

0 comments on commit a7356ca

Please sign in to comment.