-
Notifications
You must be signed in to change notification settings - Fork 395
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
Filter entities in the UI (part 0): Make CustomContent
more useful
#8645
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
25a652b
`CustomContent` wraps closure in an egui::Ui with the correct `max_re…
abey79 deca722
Make `CustomContent` sizing more customisable
abey79 7d970b4
Update list_item test snapshot
abey79 cb3e696
lints
abey79 c3ee2e0
fix doclink
abey79 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
use egui::{NumExt as _, Ui}; | ||
|
||
use crate::list_item::{ContentContext, DesiredWidth, ListItemContent}; | ||
use crate::DesignTokens; | ||
|
||
/// Control how the [`CustomContent`] advertises its width. | ||
#[derive(Debug, Clone, Copy)] | ||
enum CustomContentDesiredWidth { | ||
/// Use the provided [`DesiredWidth`]. | ||
DesiredWidth(DesiredWidth), | ||
|
||
/// Use [`DesiredWidth::AtLeast`] with a width computed from the provided content, plus any | ||
/// extras such as a button. | ||
ContentWidth(f32), | ||
} | ||
|
||
impl Default for CustomContentDesiredWidth { | ||
fn default() -> Self { | ||
Self::DesiredWidth(Default::default()) | ||
} | ||
} | ||
|
||
/// [`ListItemContent`] that mostly delegates to a closure. | ||
#[expect(clippy::type_complexity)] | ||
pub struct CustomContent<'a> { | ||
ui: Box<dyn FnOnce(&mut egui::Ui, &ContentContext<'_>) + 'a>, | ||
desired_width: CustomContentDesiredWidth, | ||
|
||
//TODO(ab): in the future, that should be a `Vec`, with some auto expanding mini-toolbar | ||
button: Option<Box<dyn super::ItemButton + 'a>>, | ||
} | ||
|
||
impl<'a> CustomContent<'a> { | ||
/// Create a content with a custom UI closure. | ||
/// | ||
/// The closure will be called from within a [`egui::Ui`] with its maximum width set as per the | ||
/// list item geometry. Note that this may differ from [`ContentContext::rect`] if a button is | ||
/// set. | ||
pub fn new(ui: impl FnOnce(&mut egui::Ui, &ContentContext<'_>) + 'a) -> Self { | ||
Self { | ||
ui: Box::new(ui), | ||
desired_width: Default::default(), | ||
button: None, | ||
} | ||
} | ||
|
||
/// Set the desired width for the entire content. | ||
#[inline] | ||
pub fn with_desired_width(mut self, desired_width: DesiredWidth) -> Self { | ||
self.desired_width = CustomContentDesiredWidth::DesiredWidth(desired_width); | ||
self | ||
} | ||
|
||
/// Set the desired width based on the provided content width. If a button is set, its width | ||
/// will be taken into account and added to the content width. | ||
#[inline] | ||
pub fn with_content_width(mut self, desired_content_width: f32) -> Self { | ||
self.desired_width = CustomContentDesiredWidth::ContentWidth(desired_content_width); | ||
self | ||
} | ||
|
||
/// Add a right-aligned [`super::ItemButton`]. | ||
/// | ||
/// Note: for aesthetics, space is always reserved for the action button. | ||
// TODO(#6191): accept multiple calls for this function for multiple actions. | ||
#[inline] | ||
pub fn button(mut self, button: impl super::ItemButton + 'a) -> Self { | ||
// TODO(#6191): support multiple action buttons | ||
assert!( | ||
self.button.is_none(), | ||
"Only one action button is supported right now" | ||
); | ||
|
||
self.button = Some(Box::new(button)); | ||
self | ||
} | ||
|
||
/// Helper to add an [`super::ItemActionButton`] to the right of the item. | ||
/// | ||
/// See [`Self::button`] for more information. | ||
#[inline] | ||
pub fn action_button( | ||
self, | ||
icon: &'static crate::icons::Icon, | ||
on_click: impl FnOnce() + 'a, | ||
) -> Self { | ||
self.action_button_with_enabled(icon, true, on_click) | ||
} | ||
|
||
/// Helper to add an enabled/disabled [`super::ItemActionButton`] to the right of the item. | ||
/// | ||
/// See [`Self::button`] for more information. | ||
#[inline] | ||
pub fn action_button_with_enabled( | ||
self, | ||
icon: &'static crate::icons::Icon, | ||
enabled: bool, | ||
on_click: impl FnOnce() + 'a, | ||
) -> Self { | ||
self.button(super::ItemActionButton::new(icon, on_click).enabled(enabled)) | ||
} | ||
|
||
/// Helper to add a [`super::ItemMenuButton`] to the right of the item. | ||
/// | ||
/// See [`Self::button`] for more information. | ||
#[inline] | ||
pub fn menu_button( | ||
self, | ||
icon: &'static crate::icons::Icon, | ||
add_contents: impl FnOnce(&mut egui::Ui) + 'a, | ||
) -> Self { | ||
self.button(super::ItemMenuButton::new(icon, add_contents)) | ||
} | ||
} | ||
|
||
impl ListItemContent for CustomContent<'_> { | ||
fn ui(self: Box<Self>, ui: &mut egui::Ui, context: &ContentContext<'_>) { | ||
let Self { | ||
ui: content_ui, | ||
desired_width: _, | ||
button, | ||
} = *self; | ||
|
||
let button_dimension = | ||
DesignTokens::small_icon_size().x + 2.0 * ui.spacing().button_padding.x; | ||
|
||
let content_width = if button.is_some() { | ||
(context.rect.width() - button_dimension - DesignTokens::text_to_icon_padding()) | ||
.at_least(0.0) | ||
} else { | ||
context.rect.width() | ||
}; | ||
|
||
let content_rect = egui::Rect::from_min_size( | ||
context.rect.min, | ||
egui::vec2(content_width, context.rect.height()), | ||
); | ||
|
||
ui.allocate_new_ui( | ||
egui::UiBuilder::new() | ||
.max_rect(content_rect) | ||
.layout(egui::Layout::left_to_right(egui::Align::Center)), | ||
|ui| { | ||
content_ui(ui, context); | ||
}, | ||
); | ||
|
||
if let Some(button) = button { | ||
let action_button_rect = egui::Rect::from_center_size( | ||
context.rect.right_center() - egui::vec2(button_dimension / 2.0, 0.0), | ||
egui::Vec2::splat(button_dimension), | ||
); | ||
|
||
// the right to left layout is used to mimic LabelContent's buttons behavior and get a | ||
// better alignment | ||
let mut child_ui = ui.new_child( | ||
egui::UiBuilder::new() | ||
.max_rect(action_button_rect) | ||
.layout(egui::Layout::right_to_left(egui::Align::Center)), | ||
); | ||
|
||
button.ui(&mut child_ui); | ||
} | ||
} | ||
|
||
fn desired_width(&self, ui: &Ui) -> DesiredWidth { | ||
match self.desired_width { | ||
CustomContentDesiredWidth::DesiredWidth(desired_width) => desired_width, | ||
CustomContentDesiredWidth::ContentWidth(mut content_width) => { | ||
if self.button.is_some() { | ||
content_width += DesignTokens::small_icon_size().x | ||
+ 2.0 * ui.spacing().button_padding.x | ||
+ DesignTokens::text_to_icon_padding(); | ||
} | ||
DesiredWidth::AtLeast(content_width) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
having a bit of a deja vu - isn't this button handling code already somewhere else? (can't tell without digging if that's actually the case and whether that's even a concern)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I already have some kind of abstraction for button thingies (could be menu, could be action). Look for the
ItemButton
trait. I'm using that inPropertyContent
, so I'm piggy backing on it.