Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make our collapsing triangle thinner for more consistency with our icons #8408

Merged
merged 5 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 144 additions & 126 deletions crates/viewer/re_selection_panel/src/view_entity_picker.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use egui::NumExt as _;
use itertools::Itertools;
use nohash_hasher::IntMap;

use re_data_ui::item_ui;
use re_entity_db::{EntityPath, EntityTree, InstancePath};
use re_log_types::{EntityPathFilter, EntityPathRule};
use re_ui::UiExt as _;
use re_ui::{list_item, UiExt as _};
use re_viewer_context::{DataQueryResult, ViewClassExt as _, ViewId, ViewerContext};
use re_viewport_blueprint::{ViewBlueprint, ViewportBlueprint};

Expand Down Expand Up @@ -32,7 +33,11 @@ impl ViewEntityPicker {
) {
self.modal_handler.ui(
egui_ctx,
|| re_ui::modal::ModalWrapper::new("Add/remove Entities").default_height(640.0),
|| {
re_ui::modal::ModalWrapper::new("Add/remove Entities")
.default_height(640.0)
.full_span_content(true)
},
|ui, open| {
let Some(view_id) = &self.view_id else {
*open = false;
Expand All @@ -44,9 +49,21 @@ impl ViewEntityPicker {
return;
};

egui::ScrollArea::vertical().show(ui, |ui| {
add_entities_ui(ctx, ui, view);
});
// Make the modal size less jumpy and work around https://github.com/emilk/egui/issues/5138
// TODO(ab): move that boilerplate to `ModalWrapper` by adding a `scrollable` flag.
let max_height = 0.85 * ui.ctx().screen_rect().height();
let min_height = 0.3 * ui.ctx().screen_rect().height().at_most(max_height);

egui::ScrollArea::vertical()
.min_scrolled_height(max_height)
.max_height(max_height)
.show(ui, |ui| {
add_entities_ui(ctx, ui, view);

if ui.min_rect().height() < min_height {
ui.add_space(min_height - ui.min_rect().height());
}
});
},
);
}
Expand All @@ -61,16 +78,18 @@ fn add_entities_ui(ctx: &ViewerContext<'_>, ui: &mut egui::Ui, view: &ViewBluepr
let entity_path_filter = &view.contents.entity_path_filter;
let entities_add_info = create_entity_add_info(ctx, tree, view, &query_result);

add_entities_tree_ui(
ctx,
ui,
&tree.path.to_string(),
tree,
view,
&query_result,
entity_path_filter,
&entities_add_info,
);
list_item::list_item_scope(ui, "view_entity_picker", |ui| {
add_entities_tree_ui(
ctx,
ui,
&tree.path.to_string(),
tree,
view,
&query_result,
entity_path_filter,
&entities_add_info,
);
});
}

#[allow(clippy::too_many_arguments)]
Expand All @@ -84,56 +103,58 @@ fn add_entities_tree_ui(
entity_path_filter: &EntityPathFilter,
entities_add_info: &IntMap<EntityPath, EntityAddInfo>,
) {
if tree.is_leaf() {
let item_content = list_item::CustomContent::new(|ui, content_ctx| {
let mut child_ui = ui.new_child(
egui::UiBuilder::new()
.max_rect(content_ctx.rect)
.layout(egui::Layout::left_to_right(egui::Align::Center)),
);
add_entities_line_ui(
ctx,
ui,
&mut child_ui,
name,
tree,
view,
query_result,
entity_path_filter,
entities_add_info,
);
});

let list_item = ui.list_item().interactive(false);
if tree.is_leaf() {
list_item.show_hierarchical(ui, item_content);
} else {
let level = tree.path.len();
let default_open =
view.space_origin.is_descendant_of(&tree.path) || tree.children.len() <= 3 || level < 2;
egui::collapsing_header::CollapsingState::load_with_default_open(
ui.ctx(),

list_item.show_hierarchical_with_children(
ui,
ui.id().with(name),
default_open,
)
.show_header(ui, |ui| {
add_entities_line_ui(
ctx,
ui,
name,
tree,
view,
query_result,
entity_path_filter,
entities_add_info,
);
})
.body(|ui| {
for (path_comp, child_tree) in tree.children.iter().sorted_by_key(|(_, child_tree)| {
// Put descendants of the space path always first
let put_first = child_tree.path.starts_with(&view.space_origin);
!put_first
}) {
add_entities_tree_ui(
ctx,
ui,
&path_comp.ui_string(),
child_tree,
view,
query_result,
entity_path_filter,
entities_add_info,
);
}
});
item_content,
|ui| {
for (path_comp, child_tree) in
tree.children.iter().sorted_by_key(|(_, child_tree)| {
// Put descendants of the space path always first
let put_first = child_tree.path.starts_with(&view.space_origin);
!put_first
})
{
add_entities_tree_ui(
ctx,
ui,
&path_comp.ui_string(),
child_tree,
view,
query_result,
entity_path_filter,
entities_add_info,
);
}
},
);
};
}

Expand All @@ -151,98 +172,95 @@ fn add_entities_line_ui(
re_tracing::profile_function!();

let query = ctx.current_query();
let entity_path = &entity_tree.path;

#[allow(clippy::unwrap_used)]
let add_info = entities_add_info.get(entity_path).unwrap();

let is_explicitly_excluded = entity_path_filter.is_explicitly_excluded(entity_path);
let is_explicitly_included = entity_path_filter.is_explicitly_included(entity_path);
let is_included = entity_path_filter.matches(entity_path);

ui.add_enabled_ui(add_info.can_add_self_or_descendant.is_compatible(), |ui| {
let widget_text = if is_explicitly_excluded {
// TODO(jleibs): Better design-language for excluded.
egui::RichText::new(name).italics()
} else if entity_path == &view.space_origin {
egui::RichText::new(name).strong()
} else {
egui::RichText::new(name)
};
let response = item_ui::instance_path_button_to(
ctx,
&query,
ctx.recording(),
ui,
Some(view.id),
&InstancePath::entity_all(entity_path.clone()),
widget_text,
);
if query_result.contains_entity(entity_path) {
response.highlight();
}
});

ui.horizontal(|ui| {
let entity_path = &entity_tree.path;

#[allow(clippy::unwrap_used)]
let add_info = entities_add_info.get(entity_path).unwrap();
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if entity_path_filter.contains_rule_for_exactly(entity_path) {
// Reset-button
// Shows when an entity is explicitly excluded or included
let response = ui.small_icon_button(&re_ui::icons::RESET);

let is_explicitly_excluded = entity_path_filter.is_explicitly_excluded(entity_path);
let is_explicitly_included = entity_path_filter.is_explicitly_included(entity_path);
let is_included = entity_path_filter.matches(entity_path);
if response.clicked() {
view.contents.remove_filter_rule_for(ctx, &entity_tree.path);
}

ui.add_enabled_ui(add_info.can_add_self_or_descendant.is_compatible(), |ui| {
let widget_text = if is_explicitly_excluded {
// TODO(jleibs): Better design-language for excluded.
egui::RichText::new(name).italics()
} else if entity_path == &view.space_origin {
egui::RichText::new(name).strong()
} else {
egui::RichText::new(name)
};
let response = item_ui::instance_path_button_to(
ctx,
&query,
ctx.recording(),
ui,
Some(view.id),
&InstancePath::entity_all(entity_path.clone()),
widget_text,
);
if query_result.contains_entity(entity_path) {
response.highlight();
if is_explicitly_excluded {
response.on_hover_text("Stop excluding this entity path.");
} else if is_explicitly_included {
response.on_hover_text("Stop including this entity path.");
}
});
} else if is_included {
// Remove-button
// Shows when an entity is already included (but not explicitly)
let response = ui.small_icon_button(&re_ui::icons::REMOVE);

ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if entity_path_filter.contains_rule_for_exactly(entity_path) {
// Reset-button
// Shows when an entity is explicitly excluded or included
let response = ui.small_icon_button(&re_ui::icons::RESET);
if response.clicked() {
view.contents.raw_add_entity_exclusion(
ctx,
EntityPathRule::including_subtree(entity_tree.path.clone()),
);
}

if response.clicked() {
view.contents.remove_filter_rule_for(ctx, &entity_tree.path);
}
response.on_hover_text("Exclude this entity and all its descendants from the view");
} else {
// Add-button:
// Shows when an entity is not included
// Only enabled if the entity is compatible.
let enabled = add_info.can_add_self_or_descendant.is_compatible();

if is_explicitly_excluded {
response.on_hover_text("Stop excluding this entity path.");
} else if is_explicitly_included {
response.on_hover_text("Stop including this entity path.");
}
} else if is_included {
// Remove-button
// Shows when an entity is already included (but not explicitly)
let response = ui.small_icon_button(&re_ui::icons::REMOVE);
ui.add_enabled_ui(enabled, |ui| {
let response = ui.small_icon_button(&re_ui::icons::ADD);

if response.clicked() {
view.contents.raw_add_entity_exclusion(
view.contents.raw_add_entity_inclusion(
ctx,
EntityPathRule::including_subtree(entity_tree.path.clone()),
);
}

response.on_hover_text("Exclude this entity and all its descendants from the view");
} else {
// Add-button:
// Shows when an entity is not included
// Only enabled if the entity is compatible.
let enabled = add_info.can_add_self_or_descendant.is_compatible();

ui.add_enabled_ui(enabled, |ui| {
let response = ui.small_icon_button(&re_ui::icons::ADD);

if response.clicked() {
view.contents.raw_add_entity_inclusion(
ctx,
EntityPathRule::including_subtree(entity_tree.path.clone()),
if enabled {
if add_info.can_add.is_compatible_and_missing() {
response.on_hover_text(
"Include this entity and all its descendants in the view",
);
} else {
response.on_hover_text("Add descendants of this entity to the view");
}

if enabled {
if add_info.can_add.is_compatible_and_missing() {
response.on_hover_text(
"Include this entity and all its descendants in the view",
);
} else {
response.on_hover_text("Add descendants of this entity to the view");
}
} else if let CanAddToView::No { reason } = &add_info.can_add {
response.on_disabled_hover_text(reason);
}
});
}
});
} else if let CanAddToView::No { reason } = &add_info.can_add {
response.on_disabled_hover_text(reason);
}
});
}
});
}

Expand Down
Loading
Loading