diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index 117b7811..fd8e249b 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -347,10 +347,19 @@ impl CollapsingHeader { } } + #[inline] pub fn show( self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> CollapsingResponse { + self.show_dyn(ui, Box::new(add_contents)) + } + + fn show_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, ) -> CollapsingResponse { // Make sure contents are bellow header, // and make sure it is one unit (necessary for putting a `CollapsingHeader` in a grid). diff --git a/egui/src/containers/combo_box.rs b/egui/src/containers/combo_box.rs index c088f251..5d171acc 100644 --- a/egui/src/containers/combo_box.rs +++ b/egui/src/containers/combo_box.rs @@ -69,6 +69,14 @@ impl ComboBox { self, ui: &mut Ui, menu_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse> { + self.show_ui_dyn(ui, Box::new(menu_contents)) + } + + fn show_ui_dyn<'c, R>( + self, + ui: &mut Ui, + menu_contents: Box R + 'c>, ) -> InnerResponse> { let Self { id_source, @@ -83,7 +91,7 @@ impl ComboBox { if let Some(width) = width { ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later. } - let mut ir = combo_box(ui, button_id, selected_text, menu_contents); + let mut ir = combo_box_dyn(ui, button_id, selected_text, menu_contents); if let Some(label) = label { ir.response .widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text())); @@ -144,11 +152,11 @@ impl ComboBox { } #[allow(clippy::needless_pass_by_value)] -fn combo_box( +fn combo_box_dyn<'c, R>( ui: &mut Ui, button_id: Id, selected: impl ToString, - menu_contents: impl FnOnce(&mut Ui) -> R, + menu_contents: Box R + 'c>, ) -> InnerResponse> { let popup_id = button_id.with("popup"); diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs index a81710bc..c95ebe4f 100644 --- a/egui/src/containers/frame.rs +++ b/egui/src/containers/frame.rs @@ -155,6 +155,14 @@ impl Frame { } pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { + self.show_dyn(ui, Box::new(add_contents)) + } + + fn show_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, + ) -> InnerResponse { let mut prepared = self.begin(ui); let ret = add_contents(&mut prepared.content_ui); let response = prepared.end(ui); diff --git a/egui/src/containers/panel.rs b/egui/src/containers/panel.rs index 47482083..6bf72de8 100644 --- a/egui/src/containers/panel.rs +++ b/egui/src/containers/panel.rs @@ -147,6 +147,15 @@ impl SidePanel { self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_inside_dyn(ui, Box::new(add_contents)) + } + + /// Show the panel inside a `Ui`. + fn show_inside_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, ) -> InnerResponse { let Self { side, @@ -259,6 +268,15 @@ impl SidePanel { self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_dyn(ctx, Box::new(add_contents)) + } + + /// Show the panel at the top level. + fn show_dyn<'c, R>( + self, + ctx: &CtxRef, + add_contents: Box R + 'c>, ) -> InnerResponse { let layer_id = LayerId::background(); let side = self.side; @@ -266,7 +284,7 @@ impl SidePanel { let clip_rect = ctx.input().screen_rect(); let mut panel_ui = Ui::new(ctx.clone(), layer_id, self.id, available_rect, clip_rect); - let inner_response = self.show_inside(&mut panel_ui, add_contents); + let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents); let rect = inner_response.response.rect; match side { @@ -406,6 +424,15 @@ impl TopBottomPanel { self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_inside_dyn(ui, Box::new(add_contents)) + } + + /// Show the panel inside a `Ui`. + fn show_inside_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, ) -> InnerResponse { let Self { side, @@ -520,6 +547,15 @@ impl TopBottomPanel { self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_dyn(ctx, Box::new(add_contents)) + } + + /// Show the panel at the top level. + fn show_dyn<'c, R>( + self, + ctx: &CtxRef, + add_contents: Box R + 'c>, ) -> InnerResponse { let layer_id = LayerId::background(); let available_rect = ctx.available_rect(); @@ -528,7 +564,7 @@ impl TopBottomPanel { let clip_rect = ctx.input().screen_rect(); let mut panel_ui = Ui::new(ctx.clone(), layer_id, self.id, available_rect, clip_rect); - let inner_response = self.show_inside(&mut panel_ui, add_contents); + let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents); let rect = inner_response.response.rect; match side { @@ -585,6 +621,15 @@ impl CentralPanel { self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_inside_dyn(ui, Box::new(add_contents)) + } + + /// Show the panel inside a `Ui`. + fn show_inside_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, ) -> InnerResponse { let Self { frame } = self; @@ -603,6 +648,15 @@ impl CentralPanel { self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R, + ) -> InnerResponse { + self.show_dyn(ctx, Box::new(add_contents)) + } + + /// Show the panel at the top level. + fn show_dyn<'c, R>( + self, + ctx: &CtxRef, + add_contents: Box R + 'c>, ) -> InnerResponse { let available_rect = ctx.available_rect(); let layer_id = LayerId::background(); @@ -611,7 +665,7 @@ impl CentralPanel { let clip_rect = ctx.input().screen_rect(); let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, available_rect, clip_rect); - let inner_response = self.show_inside(&mut panel_ui, add_contents); + let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents); // Only inform ctx about what we actually used, so we can shrink the native window to fit. ctx.frame_state() diff --git a/egui/src/containers/popup.rs b/egui/src/containers/popup.rs index 54b5f25c..db03aad6 100644 --- a/egui/src/containers/popup.rs +++ b/egui/src/containers/popup.rs @@ -100,12 +100,12 @@ pub fn show_tooltip_under( add_contents: impl FnOnce(&mut Ui) -> R, ) -> Option { let expanded_rect = rect.expand2(vec2(2.0, 4.0)); - show_tooltip_at_avoid( + show_tooltip_at_avoid_dyn( ctx, id, Some(expanded_rect.left_bottom()), expanded_rect, - add_contents, + Box::new(add_contents), ) } @@ -118,15 +118,21 @@ pub fn show_tooltip_at( suggested_position: Option, add_contents: impl FnOnce(&mut Ui) -> R, ) -> Option { - show_tooltip_at_avoid(ctx, id, suggested_position, Rect::NOTHING, add_contents) + show_tooltip_at_avoid_dyn( + ctx, + id, + suggested_position, + Rect::NOTHING, + Box::new(add_contents), + ) } -fn show_tooltip_at_avoid( +fn show_tooltip_at_avoid_dyn<'c, R>( ctx: &CtxRef, mut id: Id, suggested_position: Option, mut avoid_rect: Rect, - add_contents: impl FnOnce(&mut Ui) -> R, + add_contents: Box R + 'c>, ) -> Option { let mut tooltip_rect = Rect::NOTHING; let mut count = 0; @@ -170,7 +176,7 @@ fn show_tooltip_at_avoid( let position = position.max(ctx.input().screen_rect().left_top()); - let InnerResponse { inner, response } = show_tooltip_area(ctx, id, position, add_contents); + let InnerResponse { inner, response } = show_tooltip_area_dyn(ctx, id, position, add_contents); ctx.memory() .data_temp .get_mut_or_default::() @@ -201,11 +207,11 @@ pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl ToString) -> Option<() } /// Show a pop-over window. -fn show_tooltip_area( +fn show_tooltip_area_dyn<'c, R>( ctx: &CtxRef, id: Id, window_pos: Pos2, - add_contents: impl FnOnce(&mut Ui) -> R, + add_contents: Box R + 'c>, ) -> InnerResponse { use containers::*; Area::new(id) diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index a74f8c5b..a4dfdfbd 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -304,7 +304,7 @@ impl ScrollArea { /// /// If the inner area can be very long, consider using [`Self::show_rows`] instead. pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> R { - self.show_viewport(ui, |ui, _viewport| add_contents(ui)) + self.show_viewport_dyn(ui, Box::new(|ui, _viewport| add_contents(ui))) } /// Efficiently show only the visible part of a large number of rows. @@ -357,6 +357,14 @@ impl ScrollArea { /// `add_contents` is past the viewport, which is the relative view of the content. /// So if the passed rect has min = zero, then show the top left content (the user has not scrolled). pub fn show_viewport(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui, Rect) -> R) -> R { + self.show_viewport_dyn(ui, Box::new(add_contents)) + } + + fn show_viewport_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, + ) -> R { let mut prepared = self.begin(ui); let ret = add_contents(&mut prepared.content_ui, prepared.viewport); prepared.end(ui); diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index e9fa1e80..7468eae0 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -240,15 +240,16 @@ impl<'open> Window<'open> { impl<'open> Window<'open> { /// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`). /// Returns `Some(InnerResponse { inner: None })` if the window is collapsed. + #[inline] pub fn show( self, ctx: &CtxRef, add_contents: impl FnOnce(&mut Ui) -> R, ) -> Option>> { - self.show_impl(ctx, Box::new(add_contents)) + self.show_dyn(ctx, Box::new(add_contents)) } - fn show_impl<'c, R>( + fn show_dyn<'c, R>( self, ctx: &CtxRef, add_contents: Box R + 'c>, diff --git a/egui/src/grid.rs b/egui/src/grid.rs index 1b1c5896..b8489f04 100644 --- a/egui/src/grid.rs +++ b/egui/src/grid.rs @@ -328,6 +328,14 @@ impl Grid { impl Grid { pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { + self.show_dyn(ui, Box::new(add_contents)) + } + + fn show_dyn<'c, R>( + self, + ui: &mut Ui, + add_contents: Box R + 'c>, + ) -> InnerResponse { let Self { id_source, num_columns, diff --git a/egui/src/response.rs b/egui/src/response.rs index 65fdd28a..c181626c 100644 --- a/egui/src/response.rs +++ b/egui/src/response.rs @@ -552,6 +552,7 @@ pub struct InnerResponse { } impl InnerResponse { + #[inline] pub fn new(inner: R, response: Response) -> Self { Self { inner, response } } diff --git a/egui/src/ui.rs b/egui/src/ui.rs index d8fefb88..1de9032e 100644 --- a/egui/src/ui.rs +++ b/egui/src/ui.rs @@ -1279,6 +1279,13 @@ impl Ui { /// }); /// ``` pub fn scope(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { + self.scope_dyn(Box::new(add_contents)) + } + + fn scope_dyn<'c, R>( + &mut self, + add_contents: Box R + 'c>, + ) -> InnerResponse { let child_rect = self.available_rect_before_wrap(); let next_auto_id_source = self.next_auto_id_source; let mut child_ui = self.child_ui(child_rect, *self.layout()); @@ -1391,13 +1398,12 @@ impl Ui { /// ``` /// /// See also [`Self::with_layout`] for more options. - #[inline(always)] + #[inline] pub fn horizontal(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { - self.horizontal_with_main_wrap(false, add_contents) + self.horizontal_with_main_wrap_dyn(false, Box::new(add_contents)) } /// Like [`Self::horizontal`], but aligns content with top. - #[inline(always)] pub fn horizontal_top( &mut self, add_contents: impl FnOnce(&mut Ui) -> R, @@ -1431,16 +1437,7 @@ impl Ui { &mut self, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { - self.horizontal_with_main_wrap(true, add_contents) - } - - #[inline(always)] - fn horizontal_with_main_wrap( - &mut self, - main_wrap: bool, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> InnerResponse { - self.horizontal_with_main_wrap_dyn(main_wrap, Box::new(add_contents)) + self.horizontal_with_main_wrap_dyn(true, Box::new(add_contents)) } fn horizontal_with_main_wrap_dyn<'c, R>( @@ -1477,7 +1474,7 @@ impl Ui { /// See also [`Self::with_layout`] for more options. #[inline(always)] pub fn vertical(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse { - self.with_layout(Layout::top_down(Align::Min), add_contents) + self.with_layout_dyn(Layout::top_down(Align::Min), Box::new(add_contents)) } /// Start a ui with vertical layout. @@ -1490,11 +1487,12 @@ impl Ui { /// ui.label("under"); /// }); /// ``` + #[inline] pub fn vertical_centered( &mut self, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { - self.with_layout(Layout::top_down(Align::Center), add_contents) + self.with_layout_dyn(Layout::top_down(Align::Center), Box::new(add_contents)) } /// Start a ui with vertical layout. @@ -1511,9 +1509,9 @@ impl Ui { &mut self, add_contents: impl FnOnce(&mut Ui) -> R, ) -> InnerResponse { - self.with_layout( + self.with_layout_dyn( Layout::top_down(Align::Center).with_cross_justify(true), - add_contents, + Box::new(add_contents), ) } @@ -1529,6 +1527,7 @@ impl Ui { /// /// See also [`Self::allocate_ui_with_layout`], /// and the helpers [`Self::horizontal]`, [`Self::vertical`], etc. + #[inline] pub fn with_layout( &mut self, layout: Layout, @@ -1562,9 +1561,9 @@ impl Ui { &mut self, add_contents: impl FnOnce(&mut Self) -> R, ) -> InnerResponse { - self.with_layout( + self.with_layout_dyn( Layout::centered_and_justified(Direction::TopDown), - add_contents, + Box::new(add_contents), ) } @@ -1605,10 +1604,20 @@ impl Ui { /// columns[1].label("Second column"); /// }); /// ``` - pub fn columns(&mut self, num_columns: usize, add_contents: F) -> R - where - F: FnOnce(&mut [Self]) -> R, - { + #[inline] + pub fn columns( + &mut self, + num_columns: usize, + add_contents: impl FnOnce(&mut [Self]) -> R, + ) -> R { + self.columns_dyn(num_columns, Box::new(add_contents)) + } + + fn columns_dyn<'c, R>( + &mut self, + num_columns: usize, + add_contents: Box R + 'c>, + ) -> R { // TODO: ensure there is space let spacing = self.spacing().item_spacing.x; let total_spacing = spacing * (num_columns as f32 - 1.0); diff --git a/sh/find_bloat.sh b/sh/find_bloat.sh index 813e35fd..f77f8d84 100755 --- a/sh/find_bloat.sh +++ b/sh/find_bloat.sh @@ -4,3 +4,5 @@ script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) cd "$script_path/.." cargo bloat --release --bin egui_demo_app -n 200 | rg "egui " + +cargo llvm-lines -p egui_demo_lib | rg egui | head -30