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

ListItem 2.0 (part 4): only allocate space for property action buttons when needed #6183

Merged
merged 5 commits into from
May 2, 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
1 change: 0 additions & 1 deletion Cargo.lock

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

5 changes: 2 additions & 3 deletions crates/re_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@ re_format.workspace = true
re_log.workspace = true
re_log_types.workspace = true # syntax-highlighting for EntityPath

egui.workspace = true
egui_commonmark = { workspace = true, features = ["pulldown_cmark"] }
egui_extras.workspace = true
egui.workspace = true
parking_lot.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
strum_macros.workspace = true
strum.workspace = true
strum_macros.workspace = true
sublime_fuzzy.workspace = true
once_cell.workspace = true


eframe = { workspace = true, default-features = false, features = ["wgpu"] }
Expand Down
56 changes: 45 additions & 11 deletions crates/re_ui/examples/re_ui_example/right_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub struct RightPanel {
drag_and_drop: drag_and_drop::ExampleDragAndDrop,
hierarchical_drag_and_drop: hierarchical_drag_and_drop::HierarchicalDragAndDrop,
selected_list_item: Option<usize>,
use_action_button: bool,

// dummy data
text: String,
Expand All @@ -22,6 +23,7 @@ impl Default for RightPanel {
hierarchical_drag_and_drop:
hierarchical_drag_and_drop::HierarchicalDragAndDrop::default(),
selected_list_item: None,
use_action_button: false,
// dummy data
text: "Hello world".to_owned(),
color: [128, 0, 0, 255],
Expand Down Expand Up @@ -236,21 +238,53 @@ impl RightPanel {

re_ui.list_item2().show_hierarchical_with_children(
ui,
"other features",
"property content right button reserve",
true,
list_item2::LabelContent::new("Other contents:"),
list_item2::PropertyContent::new("PropertyContent action button:")
.value_text("demo of right gutter"),
|re_ui, ui| {
re_ui.list_item2().show_hierarchical(
ui,
list_item2::LabelContent::new("next line is a EmptyContent:")
.subdued(true)
.italics(true),
);
// By using an inner scope, we allow the nested properties to not align themselves
// to the parent property, which in this particular case looks better.
list_item2::list_item_scope(ui, "inner_scope", None, |ui| {
fn demo_item(re_ui: &ReUi, ui: &mut egui::Ui) {
re_ui.list_item2().show_hierarchical(
ui,
list_item2::PropertyContent::new("Some item:").value_fn(|_, ui, _| {
ui.ctx().debug_painter().debug_rect(
ui.max_rect(),
egui::Color32::LIGHT_BLUE,
"space for value",
);
}),
);
}

re_ui
.list_item2()
.show_hierarchical(ui, list_item2::EmptyContent);
for _ in 0..3 {
demo_item(re_ui, ui);
}

let mut content = list_item2::PropertyContent::new("Use action button");
if self.use_action_button {
content = content.action_button(&re_ui::icons::ADD, || {
re_log::warn!("Add button clicked");
});
}
content = content.value_bool_mut(&mut self.use_action_button);
re_ui.list_item2().show_hierarchical(ui, content);

for _ in 0..3 {
demo_item(re_ui, ui);
}
});
},
);

re_ui.list_item2().show_hierarchical_with_children(
ui,
"other features",
true,
list_item2::LabelContent::new("Other contents:"),
|re_ui, ui| {
re_ui.list_item2().show_hierarchical(
ui,
list_item2::DebugContent::default()
Expand Down
2 changes: 1 addition & 1 deletion crates/re_ui/src/drag_and_drop.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Helpers for drag and drop support for reordering hierarchical lists.
//!
//! Works well in combination with [`crate::ListItem`].
//! Works well in combination with [`crate::list_item2::ListItem`].

pub enum ItemKind<ItemId: Copy> {
/// Root container item.
Expand Down
23 changes: 18 additions & 5 deletions crates/re_ui/src/list_item2/list_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use egui::{NumExt, Response, Shape, Ui};

use crate::list_item2::{ContentContext, DesiredWidth, ListItemContent, StateStack};
use crate::list_item2::{ContentContext, DesiredWidth, LayoutInfoStack, ListItemContent};
use crate::ReUi;

struct ListItemResponse {
Expand All @@ -22,7 +22,19 @@ pub struct ShowCollapsingResponse<R> {
pub body_response: Option<egui::InnerResponse<R>>,
}

/// Generic list item that delegates its content to a [`ListItemContent`] implementation.
/// Content-generic list item.
///
/// The following features are supported:
/// - Flat or collapsible hierarchical lists.
/// - Full-span background highlighting via [`super::list_item_scope`]. TODO(#6156): fix reference
/// - Interactive or not.
/// - Support for drag and drop with [`crate::drag_and_drop`].
///
/// Besides these core features, [`ListItem`] delegates all content to the [`ListItemContent`]
/// implementations, such as [`super::LabelContent`] and [`super::PropertyContent`].
///
/// Usage example can be found in `re_ui_example`.

#[derive(Debug, Clone)]
pub struct ListItem<'a> {
re_ui: &'a ReUi,
Expand Down Expand Up @@ -226,10 +238,10 @@ impl<'a> ListItem<'a> {

// We use the state set by ListItemContainer to determine how far the background should
// extend.
let state = StateStack::top(ui.ctx());
let layout_info = LayoutInfoStack::top(ui.ctx());
let mut bg_rect = rect;
bg_rect.set_left(state.background_x_range.min);
bg_rect.set_right(state.background_x_range.max);
bg_rect.set_left(layout_info.background_x_range.min);
bg_rect.set_right(layout_info.background_x_range.max);

// We want to be able to select/hover the item across its full span, so we interact over the
// entire background rect. But…
Expand Down Expand Up @@ -283,6 +295,7 @@ impl<'a> ListItem<'a> {
bg_rect,
response: &style_response,
list_item: &self,
layout_info,
};
content.ui(re_ui, ui, &content_ctx);

Expand Down
6 changes: 6 additions & 0 deletions crates/re_ui/src/list_item2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ pub struct ContentContext<'a> {
pub rect: egui::Rect,

/// Background area
///
/// This is the area covered by the full-span highlighting. Useful for testing if the cursor is
/// over the item.
pub bg_rect: egui::Rect,

/// List item response.
Expand All @@ -31,6 +34,9 @@ pub struct ContentContext<'a> {

/// The current list item.
pub list_item: &'a ListItem<'a>,

/// Layout information to use for rendering.
pub layout_info: LayoutInfo,
}

#[derive(Debug, Clone, Copy)]
Expand Down
29 changes: 15 additions & 14 deletions crates/re_ui/src/list_item2/other_contents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,36 @@ use crate::list_item2::{ContentContext, DesiredWidth, ListItemContent};
use crate::ReUi;
use egui::Ui;

/// Empty list item content.
pub struct EmptyContent;

impl ListItemContent for EmptyContent {
fn ui(
self: Box<Self>,
_re_ui: &crate::ReUi,
_ui: &mut egui::Ui,
_context: &ContentContext<'_>,
) {
}
}

/// [`ListItemContent`] that delegates to a closure.
#[allow(clippy::type_complexity)]
pub struct CustomContent<'a> {
ui: Box<dyn FnOnce(&crate::ReUi, &mut egui::Ui, &ContentContext<'_>) + 'a>,
desired_width: DesiredWidth,
}

impl<'a> CustomContent<'a> {
pub fn new(ui: impl FnOnce(&crate::ReUi, &mut egui::Ui, &ContentContext<'_>) + 'a) -> Self {
Self { ui: Box::new(ui) }
Self {
ui: Box::new(ui),
desired_width: Default::default(),
}
}

#[inline]
pub fn with_desired_width(mut self, desired_width: DesiredWidth) -> Self {
self.desired_width = desired_width;
self
}
}

impl ListItemContent for CustomContent<'_> {
fn ui(self: Box<Self>, re_ui: &crate::ReUi, ui: &mut egui::Ui, context: &ContentContext<'_>) {
(self.ui)(re_ui, ui, context);
}

fn desired_width(&self, _re_ui: &ReUi, _ui: &Ui) -> DesiredWidth {
self.desired_width
}
}

/// [`ListItemContent`] that displays the content rect.
Expand Down
Loading
Loading