Add `Ui::place`, to place widgets without changing the cursor (#7359)

* Closes <https://github.com/emilk/egui/issues/7353>

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");
```

<img width="253" height="86" alt="Screenshot 2025-07-14 at 10 58 30"
src="https://github.com/user-attachments/assets/fca56e60-e3c0-4b59-8e2d-0a39aefea9f9"
/>


<img width="361" height="107" alt="Screenshot 2025-07-14 at 10 58 51"
src="https://github.com/user-attachments/assets/85e2fbf9-9174-41e0-adaa-60c721b16bf6"
/>

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`?).
This commit is contained in:
Lucas Meurer 2025-09-04 10:07:35 +02:00 committed by GitHub
parent 4947b191e4
commit d3cd6d44cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 20 additions and 6 deletions

View File

@ -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("⏵"));
/// }
/// # });
/// ```

View File

@ -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()