From d3cd6d44cf1bc980d186b61ccf3ce27db7ea1450 Mon Sep 17 00:00:00 2001 From: Lucas Meurer Date: Thu, 4 Sep 2025 10:07:35 +0200 Subject: [PATCH] Add `Ui::place`, to place widgets without changing the cursor (#7359) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Closes Currently `ui.put` moves the cursor after the placed widget. In my opinion that is a bit unexpected and counterproductive in most cases where `ui.put` makes sense. The following example breakes with the current behavior and looks right with my change: ```rs ui.horizontal(|ui| { let custom_button_id = Id::new("custom_button"); let response = Button::new(( Atom::custom(custom_button_id, Vec2::splat(18.0)), "Look at my mini button!", )) .atom_ui(ui); if let Some(rect) = response.rect(custom_button_id) { ui.put(rect, Button::new("🔎").frame_when_inactive(false)); } let custom_button_id = Id::new("custom_button"); let response = Button::new(( Atom::custom(custom_button_id, Vec2::splat(18.0)), "Look at my mini button!", )) .atom_ui(ui); if let Some(rect) = response.rect(custom_button_id) { ui.put(rect, Button::new("🔎").frame_when_inactive(false)); } }); ui.add_space(10.0); let response = ui.button("Notifications"); ui.put( Rect::from_center_size(response.rect.right_top(), Vec2::splat(12.0)), |ui: &mut Ui| { Frame::new() .fill(Color32::RED) .corner_radius(10.0) .show(ui, |ui| { ui.label(RichText::new("11").size(8.0).color(Color32::WHITE)); }).response }, ); ui.button("Some other button"); ``` Screenshot 2025-07-14 at 10 58 30 Screenshot 2025-07-14 at 10 58 51 I had a look at reruns source code and there are no uses of `ui.put` that would break with this change (very little usages in general). ## Alternatives Instead of a breaking change we could of course instead introduce a new metheod (e.g. `Ui::place`?). --- crates/egui/src/atomics/atom_kind.rs | 4 ++-- crates/egui/src/ui.rs | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/crates/egui/src/atomics/atom_kind.rs b/crates/egui/src/atomics/atom_kind.rs index f58b39f8..3c54c496 100644 --- a/crates/egui/src/atomics/atom_kind.rs +++ b/crates/egui/src/atomics/atom_kind.rs @@ -41,7 +41,7 @@ pub enum AtomKind<'a> { /// For custom rendering. /// /// You can get the [`crate::Rect`] with the [`Id`] from [`crate::AtomLayoutResponse`] and use a - /// [`crate::Painter`] or [`Ui::put`] to add/draw some custom content. + /// [`crate::Painter`] or [`Ui::place`] to add/draw some custom content. /// /// Example: /// ``` @@ -53,7 +53,7 @@ pub enum AtomKind<'a> { /// /// let rect = response.rect(id); /// if let Some(rect) = rect { - /// ui.put(rect, Button::new("⏵")); + /// ui.place(rect, Button::new("⏵")); /// } /// # }); /// ``` diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 67d210b2..f595469b 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -1710,7 +1710,7 @@ impl Ui { /// The returned [`Response`] can be used to check for interactions, /// as well as adding tooltips using [`Response::on_hover_text`]. /// - /// See also [`Self::add_sized`] and [`Self::put`]. + /// See also [`Self::add_sized`], [`Self::place`] and [`Self::put`]. /// /// ``` /// # egui::__run_test_ui(|ui| { @@ -1729,7 +1729,7 @@ impl Ui { /// /// To fill all remaining area, use `ui.add_sized(ui.available_size(), widget);` /// - /// See also [`Self::add`] and [`Self::put`]. + /// See also [`Self::add`], [`Self::place`] and [`Self::put`]. /// /// ``` /// # egui::__run_test_ui(|ui| { @@ -1748,9 +1748,23 @@ impl Ui { .inner } - /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout). + /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout) without + /// affecting this [`Ui`]s cursor. /// - /// See also [`Self::add`] and [`Self::add_sized`]. + /// See also [`Self::add`] and [`Self::add_sized`] and [`Self::put`]. + pub fn place(&mut self, max_rect: Rect, widget: impl Widget) -> Response { + self.new_child( + UiBuilder::new() + .max_rect(max_rect) + .layout(Layout::centered_and_justified(Direction::TopDown)), + ) + .add(widget) + } + + /// Add a [`Widget`] to this [`Ui`] at a specific location (manual layout) and advance the + /// cursor after the widget. + /// + /// See also [`Self::add`], [`Self::add_sized`], and [`Self::place`]. pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response { self.scope_builder( UiBuilder::new()