// #![warn(missing_docs)]

use std::hash::Hash;

use crate::{
    color::*, containers::*, epaint::text::Fonts, layout::*, mutex::MutexGuard, placer::Placer,
    widgets::*, *,
};

// ----------------------------------------------------------------------------

/// This is what you use to place widgets.
///
/// Represents a region of the screen with a type of layout (horizontal or vertical).
///
/// ```
/// # let mut ui = egui::Ui::__test();
/// ui.add(egui::Label::new("Hello World!"));
/// ui.label("A shorter and more convenient way to add a label.");
/// ui.horizontal(|ui| {
///     ui.label("Add widgets");
///     if ui.button("on the same row!").clicked() {
///         /* … */
///     }
/// });
/// ```
pub struct Ui {
    /// ID of this ui.
    /// Generated based on id of parent ui together with
    /// another source of child identity (e.g. window title).
    /// Acts like a namespace for child uis.
    /// Should be unique and persist predictably from one frame to next
    /// so it can be used as a source for storing state (e.g. window position, or if a collapsing header is open).
    id: Id,

    /// This is used to create a unique interact ID for some widgets.
    /// This value is based on where in the hierarchy of widgets this Ui is in,
    /// and the value is increment with each added child widget.
    /// This works as an Id source only as long as new widgets aren't added or removed.
    /// They are therefore only good for Id:s that has no state.
    next_auto_id: u64,

    /// Specifies paint layer, clip rectangle and a reference to `Context`.
    painter: Painter,

    /// The `Style` (visuals, spacing, etc) of this ui.
    /// Commonly many `Ui`:s share the same `Style`.
    /// The `Ui` implements copy-on-write for this.
    style: std::sync::Arc<Style>,

    /// Handles the `Ui` size and the placement of new widgets.
    placer: Placer,

    /// If false we are unresponsive to input,
    /// and all widgets will assume a gray style.
    enabled: bool,
}

impl Ui {
    // ------------------------------------------------------------------------
    // Creation:

    pub fn new(ctx: CtxRef, layer_id: LayerId, id: Id, max_rect: Rect, clip_rect: Rect) -> Self {
        let style = ctx.style();
        Ui {
            id,
            next_auto_id: id.with("auto").value(),
            painter: Painter::new(ctx, layer_id, clip_rect),
            style,
            placer: Placer::new(max_rect, Layout::default()),
            enabled: true,
        }
    }

    pub fn child_ui(&mut self, max_rect: Rect, layout: Layout) -> Self {
        debug_assert!(!max_rect.any_nan());
        self.next_auto_id = self.next_auto_id.wrapping_add(1);

        Ui {
            id: self.id.with("child"),
            next_auto_id: Id::new(self.next_auto_id).with("child").value(),
            painter: self.painter.clone(),
            style: self.style.clone(),
            placer: Placer::new(max_rect, layout),
            enabled: self.enabled,
        }
    }

    /// Empty `Ui` for use in tests.
    pub fn __test() -> Self {
        let mut ctx = CtxRef::default();
        ctx.begin_frame(Default::default());
        let id = Id::new("__test");
        let layer_id = LayerId::new(Order::Middle, id);
        let rect = Rect::from_min_size(Pos2::new(0.0, 0.0), vec2(1000.0, 1000.0));
        Self::new(ctx, layer_id, id, rect, rect)
    }

    // -------------------------------------------------

    /// A unique identity of this `Ui`.
    pub fn id(&self) -> Id {
        self.id
    }

    /// Style options for this `Ui` and its children.
    pub fn style(&self) -> &std::sync::Arc<Style> {
        &self.style
    }

    /// Mutably borrow internal `Style`.
    /// Changes apply to this `Ui` and its subsequent children.
    ///
    /// To set the style of all `Ui`:s, use [`Context::set_style`].
    ///
    /// Example:
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.style_mut().body_text_style = egui::TextStyle::Heading;
    /// ```
    pub fn style_mut(&mut self) -> &mut Style {
        std::sync::Arc::make_mut(&mut self.style) // clone-on-write
    }

    /// Changes apply to this `Ui` and its subsequent children.
    ///
    /// To set the visuals of all `Ui`:s, use [`Context::set_visuals`].
    pub fn set_style(&mut self, style: impl Into<std::sync::Arc<Style>>) {
        self.style = style.into();
    }

    /// The current spacing options for this `Ui`.
    /// Short for `ui.style().spacing`.
    pub fn spacing(&self) -> &crate::style::Spacing {
        &self.style.spacing
    }

    /// Mutably borrow internal `Spacing`.
    /// Changes apply to this `Ui` and its subsequent children.
    ///
    /// Example:
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.spacing_mut().item_spacing = egui::vec2(10.0, 2.0);
    /// ```
    pub fn spacing_mut(&mut self) -> &mut crate::style::Spacing {
        &mut self.style_mut().spacing
    }

    /// The current visuals settings of this `Ui`.
    /// Short for `ui.style().visuals`.
    pub fn visuals(&self) -> &crate::Visuals {
        &self.style.visuals
    }

    /// Mutably borrow internal `visuals`.
    /// Changes apply to this `Ui` and its subsequent children.
    ///
    /// To set the visuals of all `Ui`:s, use [`Context::set_visuals`].
    ///
    /// Example:
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.visuals_mut().override_text_color = Some(egui::Color32::RED);
    /// ```
    pub fn visuals_mut(&mut self) -> &mut crate::Visuals {
        &mut self.style_mut().visuals
    }

    /// Get a reference to the parent [`CtxRef`].
    pub fn ctx(&self) -> &CtxRef {
        self.painter.ctx()
    }

    /// Use this to paint stuff within this `Ui`.
    pub fn painter(&self) -> &Painter {
        &self.painter
    }

    /// If `false`, the `Ui` does not allow any interaction and
    /// the widgets in it will draw with a gray look.
    pub fn enabled(&self) -> bool {
        self.enabled
    }

    /// Calling `set_enabled(false)` will cause the `Ui` to deny all future interaction
    /// and all the widgets will draw with a gray look.
    ///
    /// Calling `set_enabled(true)` has no effect - it will NOT re-enable the `Ui` once disabled.
    ///
    /// ### Example
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// # let mut enabled = true;
    /// ui.group(|ui|{
    ///     ui.checkbox(&mut enabled, "Enable subsection");
    ///     ui.set_enabled(enabled);
    ///     if ui.button("Button that is not always clickable").clicked() {
    ///         /* … */
    ///     }
    /// });
    /// ```
    pub fn set_enabled(&mut self, enabled: bool) {
        self.enabled &= enabled;
        if self.enabled {
            self.painter.set_fade_to_color(None);
        } else {
            self.painter
                .set_fade_to_color(Some(self.visuals().window_fill()));
        }
    }

    pub fn layout(&self) -> &Layout {
        self.placer.layout()
    }

    /// Should text wrap in this `Ui`?
    /// This is determined first by [`Style::wrap`], and then by the layout of this `Ui`.
    pub fn wrap_text(&self) -> bool {
        if let Some(wrap) = self.style.wrap {
            wrap
        } else if let Some(grid) = self.placer.grid() {
            grid.wrap_text()
        } else {
            // In vertical layouts we wrap text, but in horizontal we keep going.
            self.layout().is_vertical()
        }
    }

    /// Create a painter for a sub-region of this Ui.
    ///
    /// The clip-rect of the returned `Painter` will be the intersection
    /// of the given rectangle and the `clip_rect()` of this `Ui`.
    pub fn painter_at(&self, rect: Rect) -> Painter {
        self.painter().sub_region(rect)
    }

    /// Use this to paint stuff within this `Ui`.
    pub fn layer_id(&self) -> LayerId {
        self.painter().layer_id()
    }

    /// The `Input` of the `Context` associated with the `Ui`.
    /// Equivalent to `.ctx().input()`.
    pub fn input(&self) -> &InputState {
        self.ctx().input()
    }

    /// The `Memory` of the `Context` associated with the `Ui`.
    /// Equivalent to `.ctx().memory()`.
    pub fn memory(&self) -> MutexGuard<'_, Memory> {
        self.ctx().memory()
    }

    /// The `Output` of the `Context` associated with the `Ui`.
    /// Equivalent to `.ctx().output()`.
    pub fn output(&self) -> MutexGuard<'_, Output> {
        self.ctx().output()
    }

    /// The `Fonts` of the `Context` associated with the `Ui`.
    /// Equivalent to `.ctx().fonts()`.
    pub fn fonts(&self) -> &Fonts {
        self.ctx().fonts()
    }

    /// Screen-space rectangle for clipping what we paint in this ui.
    /// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
    pub fn clip_rect(&self) -> Rect {
        self.painter.clip_rect()
    }

    /// Screen-space rectangle for clipping what we paint in this ui.
    /// This is used, for instance, to avoid painting outside a window that is smaller than its contents.
    pub fn set_clip_rect(&mut self, clip_rect: Rect) {
        self.painter.set_clip_rect(clip_rect);
    }
}

// ------------------------------------------------------------------------

/// # Sizes etc
impl Ui {
    /// Where and how large the `Ui` is already.
    /// All widgets that have been added ot this `Ui` fits within this rectangle.
    ///
    /// No matter what, the final Ui will be at least this large.
    ///
    /// This will grow as new widgets are added, but never shrink.
    pub fn min_rect(&self) -> Rect {
        self.placer.min_rect()
    }

    /// Size of content; same as `min_rect().size()`
    pub fn min_size(&self) -> Vec2 {
        self.min_rect().size()
    }

    /// New widgets will *try* to fit within this rectangle.
    ///
    /// Text labels will wrap to fit within `max_rect`.
    /// Separator lines will span the `max_rect`.
    ///
    /// If a new widget doesn't fit within the `max_rect` then the
    /// `Ui` will make room for it by expanding both `min_rect` and `max_rect`.
    pub fn max_rect(&self) -> Rect {
        self.placer.max_rect()
    }

    /// This is like `max_rect()`, but will never be infinite.
    /// This can be useful for widgets that expand to fit the available space.
    pub fn max_rect_finite(&self) -> Rect {
        self.placer.max_rect_finite()
    }

    /// Used for animation, kind of hacky
    pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
        self.placer.force_set_min_rect(min_rect)
    }

    // ------------------------------------------------------------------------

    /// Set the maximum size of the ui.
    /// You won't be able to shrink it below the current minimum size.
    pub fn set_max_size(&mut self, size: Vec2) {
        self.set_max_width(size.x);
        self.set_max_height(size.y);
    }

    /// Set the maximum width of the ui.
    /// You won't be able to shrink it below the current minimum size.
    pub fn set_max_width(&mut self, width: f32) {
        self.placer.set_max_width(width);
    }

    /// Set the maximum height of the ui.
    /// You won't be able to shrink it below the current minimum size.
    pub fn set_max_height(&mut self, height: f32) {
        self.placer.set_max_height(height);
    }

    // ------------------------------------------------------------------------

    /// Set the minimum size of the ui.
    /// This can't shrink the ui, only make it larger.
    pub fn set_min_size(&mut self, size: Vec2) {
        self.set_min_width(size.x);
        self.set_min_height(size.y);
    }

    /// Set the minimum width of the ui.
    /// This can't shrink the ui, only make it larger.
    pub fn set_min_width(&mut self, width: f32) {
        self.placer.set_min_width(width);
    }

    /// Set the minimum height of the ui.
    /// This can't shrink the ui, only make it larger.
    pub fn set_min_height(&mut self, height: f32) {
        self.placer.set_min_height(height);
    }

    // ------------------------------------------------------------------------

    /// Helper: shrinks the max width to the current width,
    /// so further widgets will try not to be wider than previous widgets.
    /// Useful for normal vertical layouts.
    pub fn shrink_width_to_current(&mut self) {
        self.set_max_width(self.min_rect().width())
    }

    /// Helper: shrinks the max height to the current height,
    /// so further widgets will try not to be wider than previous widgets.
    pub fn shrink_height_to_current(&mut self) {
        self.set_max_height(self.min_rect().height())
    }

    /// Expand the `min_rect` and `max_rect` of this ui to include a child at the given rect.
    pub fn expand_to_include_rect(&mut self, rect: Rect) {
        self.placer.expand_to_include_rect(rect);
    }

    /// `ui.set_width_range(min..=max);` is equivalent to `ui.set_min_width(min); ui.set_max_width(max);`.
    pub fn set_width_range(&mut self, width: std::ops::RangeInclusive<f32>) {
        self.set_min_width(*width.start());
        self.set_max_width(*width.end());
    }

    /// `ui.set_width_range(width);` is equivalent to `ui.set_min_width(width); ui.set_max_width(width);`.
    pub fn set_width(&mut self, width: f32) {
        self.set_min_width(width);
        self.set_max_width(width);
    }

    /// Ensure we are big enough to contain the given x-coordinate.
    /// This is sometimes useful to expand an ui to stretch to a certain place.
    pub fn expand_to_include_x(&mut self, x: f32) {
        self.placer.expand_to_include_x(x);
    }

    // ------------------------------------------------------------------------
    // Layout related measures:

    /// The available space at the moment, given the current cursor.
    /// This how much more space we can take up without overflowing our parent.
    /// Shrinks as widgets allocate space and the cursor moves.
    /// A small size should be interpreted as "as little as possible".
    /// An infinite size should be interpreted as "as much as you want".
    pub fn available_size(&self) -> Vec2 {
        self.placer.available_size()
    }

    pub fn available_width(&self) -> f32 {
        self.available_size().x
    }

    /// In case of a wrapping layout, how much space is left on this row/column?
    pub fn available_size_before_wrap(&self) -> Vec2 {
        self.placer.available_rect_before_wrap().size()
    }

    /// This is like `available_size_before_wrap()`, but will never be infinite.
    /// This can be useful for widgets that expand to fit the available space.
    /// In most layouts the next widget will be put in the top left corner of this `Rect`.
    pub fn available_size_before_wrap_finite(&self) -> Vec2 {
        self.placer.available_rect_before_wrap_finite().size()
    }

    pub fn available_rect_before_wrap(&self) -> Rect {
        self.placer.available_rect_before_wrap()
    }

    /// This is like `available_rect_before_wrap()`, but will never be infinite.
    /// This can be useful for widgets that expand to fit the available space.
    /// In most layouts the next widget will be put in the top left corner of this `Rect`.
    pub fn available_rect_before_wrap_finite(&self) -> Rect {
        self.placer.available_rect_before_wrap_finite()
    }
}

/// # `Id` creation
impl Ui {
    /// Use this to generate widget ids for widgets that have persistent state in `Memory`.
    pub fn make_persistent_id<IdSource>(&self, id_source: IdSource) -> Id
    where
        IdSource: Hash + std::fmt::Debug,
    {
        self.id.with(&id_source)
    }

    #[deprecated = "This id now returned from ui.allocate_space"]
    pub fn make_position_id(&self) -> Id {
        Id::new(self.next_auto_id)
    }

    pub(crate) fn auto_id_with<IdSource>(&self, id_source: IdSource) -> Id
    where
        IdSource: Hash + std::fmt::Debug,
    {
        Id::new(self.next_auto_id).with(id_source)
    }
}

/// # Interaction
impl Ui {
    /// Check for clicks, drags and/or hover on a specific region of this `Ui`.
    pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response {
        self.ctx().interact(
            self.clip_rect(),
            self.spacing().item_spacing,
            self.layer_id(),
            id,
            rect,
            sense,
            self.enabled,
        )
    }

    /// Is the pointer (mouse/touch) above this rectangle in this `Ui`?
    ///
    /// The `clip_rect` and layer of this `Ui` will be respected, so, for instance,
    /// if this `Ui` is behind some other window, this will always return `false`.
    pub fn rect_contains_pointer(&self, rect: Rect) -> bool {
        self.ctx()
            .rect_contains_pointer(self.layer_id(), self.clip_rect().intersect(rect))
    }

    /// Is the pointer (mouse/touch) above this `Ui`?
    /// Equivalent to `ui.rect_contains_pointer(ui.min_rect())`
    pub fn ui_contains_pointer(&self) -> bool {
        self.rect_contains_pointer(self.min_rect())
    }

    #[deprecated = "renamed rect_contains_pointer"]
    pub fn rect_contains_mouse(&self, rect: Rect) -> bool {
        self.rect_contains_pointer(rect)
    }

    #[deprecated = "renamed ui_contains_pointer"]
    pub fn ui_contains_mouse(&self) -> bool {
        self.ui_contains_pointer()
    }

    #[deprecated = "Use: interact(rect, id, Sense::hover())"]
    pub fn interact_hover(&self, rect: Rect) -> Response {
        self.interact(rect, self.auto_id_with("hover_rect"), Sense::hover())
    }

    #[deprecated = "Use: rect_contains_pointer()"]
    pub fn hovered(&self, rect: Rect) -> bool {
        self.interact(rect, self.id, Sense::hover()).hovered
    }

    // ------------------------------------------------------------------------
    // Stuff that moves the cursor, i.e. allocates space in this ui!

    /// Advance the cursor (where the next widget is put) by this many points.
    ///
    /// The direction is dependent on the layout.
    /// This is useful for creating some extra space between widgets.
    ///
    /// [`Self::min_rect`] will expand to contain the cursor.
    pub fn advance_cursor(&mut self, amount: f32) {
        self.placer.advance_cursor(amount);
    }
}

/// # Allocating space: where do I put my widgets?
impl Ui {
    /// Allocate space for a widget and check for interaction in the space.
    /// Returns a `Response` which contains a rectangle, id, and interaction info.
    ///
    /// ## How sizes are negotiated
    /// Each widget should have a *minimum desired size* and a *desired size*.
    /// When asking for space, ask AT LEAST for you minimum, and don't ask for more than you need.
    /// If you want to fill the space, ask about `available().size()` and use that.
    ///
    /// You may get MORE space than you asked for, for instance
    /// for justified layouts, like in menus.
    ///
    /// You will never get a rectangle that is smaller than the amount of space you asked for.
    ///
    /// ```
    /// # let mut ui = egui::Ui::__test();
    /// let response = ui.allocate_response(egui::vec2(100.0, 200.0), egui::Sense::click());
    /// if response.clicked() { /* … */ }
    /// ui.painter().rect_stroke(response.rect, 0.0, (1.0, egui::Color32::WHITE));
    /// ```
    pub fn allocate_response(&mut self, desired_size: Vec2, sense: Sense) -> Response {
        let (id, rect) = self.allocate_space(desired_size);
        self.interact(rect, id, sense)
    }

    /// Returns a `Rect` with exactly what you asked for.
    ///
    /// The response rect will be larger if this is part of a justified layout or similar.
    /// This means that iof this is a narrow widget in a wide justified layout, then
    /// the widget will react to interactions outside the returned `Rect`.
    pub fn allocate_exact_size(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) {
        let response = self.allocate_response(desired_size, sense);
        let rect = self
            .placer
            .align_size_within_rect(desired_size, response.rect);
        (rect, response)
    }

    /// Allocate at least as much space as needed, and interact with that rect.
    ///
    /// The returned `Rect` will be the same size as `Response::rect`.
    pub fn allocate_at_least(&mut self, desired_size: Vec2, sense: Sense) -> (Rect, Response) {
        let response = self.allocate_response(desired_size, sense);
        (response.rect, response)
    }

    /// Reserve this much space and move the cursor.
    /// Returns where to put the widget.
    ///
    /// ## How sizes are negotiated
    /// Each widget should have a *minimum desired size* and a *desired size*.
    /// When asking for space, ask AT LEAST for you minimum, and don't ask for more than you need.
    /// If you want to fill the space, ask about `available().size()` and use that.
    ///
    /// You may get MORE space than you asked for, for instance
    /// for justified layouts, like in menus.
    ///
    /// You will never get a rectangle that is smaller than the amount of space you asked for.
    ///
    /// Returns an automatic `Id` (which you can use for interaction) and the `Rect` of where to put your widget.
    ///
    /// ```
    /// # let mut ui = egui::Ui::__test();
    /// let (id, rect) = ui.allocate_space(egui::vec2(100.0, 200.0));
    /// let response = ui.interact(rect, id, egui::Sense::click());
    /// ```
    pub fn allocate_space(&mut self, desired_size: Vec2) -> (Id, Rect) {
        // For debug rendering
        let original_available = self.available_size_before_wrap();
        let too_wide = desired_size.x > original_available.x;
        let too_high = desired_size.y > original_available.y;

        let rect = self.allocate_space_impl(desired_size);

        if self.visuals().debug_widgets && self.rect_contains_pointer(rect) {
            let painter = self.ctx().debug_painter();
            painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
            self.placer.debug_paint_cursor(&painter);
        }

        let debug_expand_width = self.visuals().debug_expand_width;
        let debug_expand_height = self.visuals().debug_expand_height;

        if (debug_expand_width && too_wide) || (debug_expand_height && too_high) {
            self.painter
                .rect_stroke(rect, 0.0, (1.0, Color32::LIGHT_BLUE));

            let stroke = Stroke::new(2.5, Color32::from_rgb(200, 0, 0));
            let paint_line_seg = |a, b| self.painter().line_segment([a, b], stroke);

            if debug_expand_width && too_wide {
                paint_line_seg(rect.left_top(), rect.left_bottom());
                paint_line_seg(rect.left_center(), rect.right_center());
                paint_line_seg(
                    pos2(rect.left() + original_available.x, rect.top()),
                    pos2(rect.left() + original_available.x, rect.bottom()),
                );
                paint_line_seg(rect.right_top(), rect.right_bottom());
            }

            if debug_expand_height && too_high {
                paint_line_seg(rect.left_top(), rect.right_top());
                paint_line_seg(rect.center_top(), rect.center_bottom());
                paint_line_seg(rect.left_bottom(), rect.right_bottom());
            }
        }

        self.next_auto_id = self.next_auto_id.wrapping_add(1);
        let id = Id::new(self.next_auto_id);

        (id, rect)
    }

    /// Reserve this much space and move the cursor.
    /// Returns where to put the widget.
    fn allocate_space_impl(&mut self, desired_size: Vec2) -> Rect {
        let item_spacing = self.spacing().item_spacing;
        let frame_rect = self.placer.next_space(desired_size, item_spacing);
        let widget_rect = self.placer.justify_and_align(frame_rect, desired_size);

        self.placer
            .advance_after_rects(frame_rect, widget_rect, item_spacing);

        widget_rect
    }

    /// Allocate a specific part of the `Ui‘.
    ///
    /// Ignore the layout of the `Ui‘: just put my widget here!
    /// The layout cursor will advance to past this `rect`.
    pub fn allocate_rect(&mut self, rect: Rect, sense: Sense) -> Response {
        let id = self.advance_cursor_after_rect(rect);
        self.interact(rect, id, sense)
    }

    pub(crate) fn advance_cursor_after_rect(&mut self, rect: Rect) -> Id {
        let item_spacing = self.spacing().item_spacing;
        self.placer.advance_after_rects(rect, rect, item_spacing);

        if self.visuals().debug_widgets && self.rect_contains_pointer(rect) {
            let painter = self.ctx().debug_painter();
            painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
            self.placer.debug_paint_cursor(&painter);
        }

        self.next_auto_id = self.next_auto_id.wrapping_add(1);
        Id::new(self.next_auto_id)
    }

    pub(crate) fn placer(&self) -> &Placer {
        &self.placer
    }

    pub(crate) fn cursor(&self) -> Rect {
        self.placer.cursor()
    }

    /// Where do we expect a zero-sized widget to be placed?
    pub(crate) fn next_widget_position(&self) -> Pos2 {
        self.placer.next_widget_position()
    }

    /// Allocated the given space and then adds content to that space.
    /// If the contents overflow, more space will be allocated.
    /// When finished, the amount of space actually used (`min_rect`) will be allocated.
    /// So you can request a lot of space and then use less.
    pub fn allocate_ui<R>(
        &mut self,
        desired_size: Vec2,
        add_contents: impl FnOnce(&mut Self) -> R,
    ) -> InnerResponse<R> {
        debug_assert!(desired_size.x >= 0.0 && desired_size.y >= 0.0);
        let item_spacing = self.spacing().item_spacing;
        let frame_rect = self.placer.next_space(desired_size, item_spacing);
        let child_rect = self.placer.justify_and_align(frame_rect, desired_size);

        let mut child_ui = self.child_ui(child_rect, *self.layout());
        let ret = add_contents(&mut child_ui);
        let final_child_rect = child_ui.min_rect();

        let final_frame = frame_rect.union(final_child_rect);
        self.placer
            .advance_after_rects(final_frame, final_child_rect, item_spacing);

        if self.visuals().debug_widgets && self.rect_contains_pointer(final_frame) {
            let painter = self.ctx().debug_painter();
            painter.rect_stroke(frame_rect, 4.0, (1.0, Color32::LIGHT_BLUE));
            painter.rect_stroke(final_child_rect, 4.0, (1.0, Color32::LIGHT_BLUE));
            self.placer.debug_paint_cursor(&painter);
        }

        let response = self.interact(final_child_rect, child_ui.id, Sense::hover());
        InnerResponse::new(ret, response)
    }

    /// Allocated the given rectangle and then adds content to that rectangle.
    /// If the contents overflow, more space will be allocated.
    /// When finished, the amount of space actually used (`min_rect`) will be allocated.
    /// So you can request a lot of space and then use less.
    pub fn allocate_ui_at_rect<R>(
        &mut self,
        max_rect: Rect,
        add_contents: impl FnOnce(&mut Self) -> R,
    ) -> InnerResponse<R> {
        let mut child_ui = self.child_ui(max_rect, *self.layout());
        let ret = add_contents(&mut child_ui);
        let final_child_rect = child_ui.min_rect();

        self.placer.advance_after_rects(
            final_child_rect,
            final_child_rect,
            self.spacing().item_spacing,
        );

        let response = self.interact(final_child_rect, child_ui.id, Sense::hover());
        InnerResponse::new(ret, response)
    }

    /// Convenience function to get a region to paint on
    pub fn allocate_painter(&mut self, desired_size: Vec2, sense: Sense) -> (Response, Painter) {
        let response = self.allocate_response(desired_size, sense);
        let clip_rect = self.clip_rect().intersect(response.rect); // Make sure we don't paint out of bounds
        let painter = Painter::new(self.ctx().clone(), self.layer_id(), clip_rect);
        (response, painter)
    }

    /// Move the scroll to this cursor position with the specified alignment.
    ///
    /// ```
    /// # use egui::Align;
    /// # let mut ui = &mut egui::Ui::__test();
    /// egui::ScrollArea::auto_sized().show(ui, |ui| {
    ///     let scroll_bottom = ui.button("Scroll to bottom.").clicked();
    ///     for i in 0..1000 {
    ///         ui.label(format!("Item {}", i));
    ///     }
    ///
    ///     if scroll_bottom {
    ///         ui.scroll_to_cursor(Align::BOTTOM);
    ///     }
    /// });
    /// ```
    pub fn scroll_to_cursor(&mut self, align: Align) {
        let target_y = self.next_widget_position().y;
        self.ctx().frame_state().scroll_target = Some((target_y, align));
    }
}

/// # Adding widgets
impl Ui {
    /// Add a [`Widget`] to this `Ui` at a location dependent on the current [`Layout`].
    ///
    /// The returned [`Response`] can be used to check for interactions,
    /// as well as adding tooltips using [`Response::on_hover_text`].
    ///
    /// ```
    /// # let mut ui = egui::Ui::__test();
    /// # let mut my_value = 42;
    /// let response = ui.add(egui::Slider::new(&mut my_value, 0..=100));
    /// response.on_hover_text("Drag me!");
    /// ```
    pub fn add(&mut self, widget: impl Widget) -> Response {
        widget.ui(self)
    }

    /// Add a [`Widget`] to this `Ui` with a given max size.
    pub fn add_sized(&mut self, max_size: Vec2, widget: impl Widget) -> Response {
        self.allocate_ui(max_size, |ui| {
            ui.centered_and_justified(|ui| ui.add(widget)).inner
        })
        .inner
    }

    /// Add a [`Widget`] to this `Ui` at a specific location (manual layout).
    pub fn put(&mut self, max_rect: Rect, widget: impl Widget) -> Response {
        self.allocate_ui_at_rect(max_rect, |ui| {
            ui.centered_and_justified(|ui| ui.add(widget)).inner
        })
        .inner
    }

    /// Shortcut for `add(Label::new(text))`
    ///
    /// Se also [`Label`].
    pub fn label(&mut self, label: impl Into<Label>) -> Response {
        self.add(label.into())
    }

    /// Shortcut for `add(Label::new(text).text_color(color))`
    pub fn colored_label(
        &mut self,
        color: impl Into<Color32>,
        label: impl Into<Label>,
    ) -> Response {
        self.add(label.into().text_color(color))
    }

    /// Shortcut for `add(Label::new(text).heading())`
    pub fn heading(&mut self, label: impl Into<Label>) -> Response {
        self.add(label.into().heading())
    }

    /// Shortcut for `add(Label::new(text).monospace())`
    pub fn monospace(&mut self, label: impl Into<Label>) -> Response {
        self.add(label.into().monospace())
    }

    /// Show text as monospace with a gray background.
    ///
    /// Shortcut for `add(Label::new(text).code())`
    pub fn code(&mut self, label: impl Into<Label>) -> Response {
        self.add(label.into().code())
    }

    /// Shortcut for `add(Label::new(text).small())`
    pub fn small(&mut self, label: impl Into<Label>) -> Response {
        self.add(label.into().small())
    }

    /// Shortcut for `add(Hyperlink::new(url))`
    ///
    /// Se also [`Hyperlink`].
    pub fn hyperlink(&mut self, url: impl Into<String>) -> Response {
        self.add(Hyperlink::new(url))
    }

    /// Shortcut for `add(Hyperlink::new(url).text(label))`
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.hyperlink_to("egui on GitHub", "https://www.github.com/emilk/egui/");
    /// ```
    ///
    /// Se also [`Hyperlink`].
    pub fn hyperlink_to(&mut self, label: impl Into<String>, url: impl Into<String>) -> Response {
        self.add(Hyperlink::new(url).text(label))
    }

    #[deprecated = "Use `text_edit_singleline` or `text_edit_multiline`"]
    pub fn text_edit(&mut self, text: &mut String) -> Response {
        self.text_edit_multiline(text)
    }

    /// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_focus`).
    ///
    /// Se also [`TextEdit`].
    pub fn text_edit_singleline(&mut self, text: &mut String) -> Response {
        self.add(TextEdit::singleline(text))
    }

    /// A `TextEdit` for multiple lines. Pressing enter key will create a new line.
    ///
    /// Se also [`TextEdit`].
    pub fn text_edit_multiline(&mut self, text: &mut String) -> Response {
        self.add(TextEdit::multiline(text))
    }

    /// Usage: `if ui.button("Click me").clicked() { … }`
    ///
    /// Shortcut for `add(Button::new(text))`
    ///
    /// Se also [`Button`].
    #[must_use = "You should check if the user clicked this with `if ui.button(…).clicked() { … } "]
    pub fn button(&mut self, text: impl Into<String>) -> Response {
        self.add(Button::new(text))
    }

    /// A button as small as normal body text.
    ///
    /// Usage: `if ui.small_button("Click me").clicked() { … }`
    ///
    /// Shortcut for `add(Button::new(text).small())`
    #[must_use = "You should check if the user clicked this with `if ui.small_button(…).clicked() { … } "]
    pub fn small_button(&mut self, text: impl Into<String>) -> Response {
        self.add(Button::new(text).small())
    }

    /// Show a checkbox.
    pub fn checkbox(&mut self, checked: &mut bool, text: impl Into<String>) -> Response {
        self.add(Checkbox::new(checked, text))
    }

    /// Show a [`RadioButton`].
    /// Often you want to use [`Self::radio_value`] instead.
    #[must_use = "You should check if the user clicked this with `if ui.radio(…).clicked() { … } "]
    pub fn radio(&mut self, selected: bool, text: impl Into<String>) -> Response {
        self.add(RadioButton::new(selected, text))
    }

    /// Show a [`RadioButton`]. It is selected if `*current_value == selected_value`.
    /// If clicked, `selected_value` is assigned to `*current_value`.
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    ///
    /// #[derive(PartialEq)]
    /// enum Enum { First, Second, Third }
    /// let mut my_enum = Enum::First;
    ///
    /// ui.radio_value(&mut my_enum, Enum::First, "First");
    ///
    /// // is equivalent to:
    ///
    /// if ui.add(egui::RadioButton::new(my_enum == Enum::First, "First")).clicked() {
    ///     my_enum = Enum::First
    /// }
    pub fn radio_value<Value: PartialEq>(
        &mut self,
        current_value: &mut Value,
        selected_value: Value,
        text: impl Into<String>,
    ) -> Response {
        let mut response = self.radio(*current_value == selected_value, text);
        if response.clicked() {
            *current_value = selected_value;
            response.mark_changed();
        }
        response
    }

    /// Show a label which can be selected or not.
    ///
    /// Se also [`SelectableLabel`].
    #[must_use = "You should check if the user clicked this with `if ui.selectable_label(…).clicked() { … } "]
    pub fn selectable_label(&mut self, checked: bool, text: impl Into<String>) -> Response {
        self.add(SelectableLabel::new(checked, text))
    }

    /// Show selectable text. It is selected if `*current_value == selected_value`.
    /// If clicked, `selected_value` is assigned to `*current_value`.
    ///
    /// Example: `ui.selectable_value(&mut my_enum, Enum::Alternative, "Alternative")`.
    ///
    /// Se also [`SelectableLabel`].
    pub fn selectable_value<Value: PartialEq>(
        &mut self,
        current_value: &mut Value,
        selected_value: Value,
        text: impl Into<String>,
    ) -> Response {
        let mut response = self.selectable_label(*current_value == selected_value, text);
        if response.clicked() {
            *current_value = selected_value;
            response.mark_changed();
        }
        response
    }

    /// Shortcut for `add(Separator::new())` (see [`Separator`]).
    pub fn separator(&mut self) -> Response {
        self.add(Separator::new())
    }

    /// Modify an angle. The given angle should be in radians, but is shown to the user in degrees.
    /// The angle is NOT wrapped, so the user may select, for instance 720° = 2𝞃 = 4π
    pub fn drag_angle(&mut self, radians: &mut f32) -> Response {
        #![allow(clippy::float_cmp)]

        let mut degrees = radians.to_degrees();
        let mut response = self.add(DragValue::new(&mut degrees).speed(1.0).suffix("°"));

        // only touch `*radians` if we actually changed the degree value
        if degrees != radians.to_degrees() {
            *radians = degrees.to_radians();
            response.changed = true;
        }

        response
    }

    /// Modify an angle. The given angle should be in radians,
    /// but is shown to the user in fractions of one Tau (i.e. fractions of one turn).
    /// The angle is NOT wrapped, so the user may select, for instance 2𝞃 (720°)
    pub fn drag_angle_tau(&mut self, radians: &mut f32) -> Response {
        #![allow(clippy::float_cmp)]

        use std::f32::consts::TAU;

        let mut taus = *radians / TAU;
        let mut response = self
            .add(DragValue::new(&mut taus).speed(0.01).suffix("τ"))
            .on_hover_text("1τ = one turn, 0.5τ = half a turn, etc. 0.25τ = 90°");

        // only touch `*radians` if we actually changed the value
        if taus != *radians / TAU {
            *radians = taus * TAU;
            response.changed = true;
        }

        response
    }

    /// Show an image here with the given size.
    ///
    /// See also [`Image`].
    pub fn image(&mut self, texture_id: TextureId, size: impl Into<Vec2>) -> Response {
        self.add(Image::new(texture_id, size))
    }
}

/// # Colors
impl Ui {
    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    pub fn color_edit_button_srgba(&mut self, srgba: &mut Color32) -> Response {
        color_picker::color_edit_button_srgba(self, srgba, color_picker::Alpha::BlendOrAdditive)
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    pub fn color_edit_button_hsva(&mut self, hsva: &mut Hsva) -> Response {
        color_picker::color_edit_button_hsva(self, hsva, color_picker::Alpha::BlendOrAdditive)
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in `sRGB` space.
    pub fn color_edit_button_srgb(&mut self, srgb: &mut [u8; 3]) -> Response {
        let mut hsva = Hsva::from_srgb(*srgb);
        let response =
            color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::Opaque);
        *srgb = hsva.to_srgb();
        response
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in linear RGB space.
    pub fn color_edit_button_rgb(&mut self, rgb: &mut [f32; 3]) -> Response {
        let mut hsva = Hsva::from_rgb(*rgb);
        let response =
            color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::Opaque);
        *rgb = hsva.to_rgb();
        response
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in `sRGBA` space with premultiplied alpha
    pub fn color_edit_button_srgba_premultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
        let mut color = Color32::from_rgba_premultiplied(srgba[0], srgba[1], srgba[2], srgba[3]);
        let response = self.color_edit_button_srgba(&mut color);
        *srgba = color.to_array();
        response
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in `sRGBA` space without premultiplied alpha.
    /// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
    pub fn color_edit_button_srgba_unmultiplied(&mut self, srgba: &mut [u8; 4]) -> Response {
        let mut hsva = Hsva::from_srgba_unmultiplied(*srgba);
        let response =
            color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::OnlyBlend);
        *srgba = hsva.to_srgba_unmultiplied();
        response
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in linear RGBA space with premultiplied alpha
    pub fn color_edit_button_rgba_premultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
        let mut hsva = Hsva::from_rgba_premultiplied(*rgba);
        let response = color_picker::color_edit_button_hsva(
            self,
            &mut hsva,
            color_picker::Alpha::BlendOrAdditive,
        );
        *rgba = hsva.to_rgba_premultiplied();
        response
    }

    /// Shows a button with the given color.
    /// If the user clicks the button, a full color picker is shown.
    /// The given color is in linear RGBA space without premultiplied alpha.
    /// If unsure, what "premultiplied alpha" is, then this is probably the function you want to use.
    pub fn color_edit_button_rgba_unmultiplied(&mut self, rgba: &mut [f32; 4]) -> Response {
        let mut hsva = Hsva::from_rgba_unmultiplied(*rgba);
        let response =
            color_picker::color_edit_button_hsva(self, &mut hsva, color_picker::Alpha::OnlyBlend);
        *rgba = hsva.to_rgba_unmultiplied();
        response
    }
}

/// # Adding Containers / Sub-uis:
impl Ui {
    /// Put into a [`Frame::group`], visually grouping the contents together
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.group(|ui|{
    ///     ui.label("Within a frame");
    /// });
    /// ```
    pub fn group<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
        crate::Frame::group(self.style()).show(self, add_contents)
    }

    /// Create a child ui. You can use this to temporarily change the Style of a sub-region, for instance.
    pub fn wrap<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
        let child_rect = self.available_rect_before_wrap();
        let mut child_ui = self.child_ui(child_rect, *self.layout());
        let ret = add_contents(&mut child_ui);
        let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
        InnerResponse::new(ret, response)
    }

    /// Redirect shapes to another paint layer.
    pub fn with_layer_id<R>(
        &mut self,
        layer_id: LayerId,
        add_contents: impl FnOnce(&mut Self) -> R,
    ) -> InnerResponse<R> {
        self.wrap(|ui| {
            ui.painter.set_layer_id(layer_id);
            add_contents(ui)
        })
    }

    #[deprecated = "Use `ui.allocate_ui` instead"]
    pub fn add_custom_contents(
        &mut self,
        desired_size: Vec2,
        add_contents: impl FnOnce(&mut Ui),
    ) -> Rect {
        self.allocate_ui(desired_size, add_contents).response.rect
    }

    /// A [`CollapsingHeader`] that starts out collapsed.
    pub fn collapsing<R>(
        &mut self,
        heading: impl Into<String>,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> CollapsingResponse<R> {
        CollapsingHeader::new(heading).show(self, add_contents)
    }

    /// Create a child ui which is indented to the right.
    pub fn indent<R>(
        &mut self,
        id_source: impl Hash,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        assert!(
            self.layout().is_vertical(),
            "You can only indent vertical layouts, found {:?}",
            self.layout()
        );

        let indent = self.spacing().indent;
        let mut child_rect = self.placer.available_rect_before_wrap();
        child_rect.min.x += indent;

        let mut child_ui = Self {
            id: self.id.with(id_source),
            ..self.child_ui(child_rect, *self.layout())
        };
        let ret = add_contents(&mut child_ui);

        let end_with_horizontal_line = true;
        if end_with_horizontal_line {
            child_ui.advance_cursor(4.0);
        }

        // draw a faint line on the left to mark the indented section
        let stroke = self.visuals().widgets.noninteractive.bg_stroke;
        let left_top = child_rect.min - 0.5 * indent * Vec2::X;
        let left_top = self.painter().round_pos_to_pixels(left_top);
        let left_bottom = pos2(left_top.x, child_ui.min_rect().bottom() - 2.0);
        let left_bottom = self.painter().round_pos_to_pixels(left_bottom);
        self.painter.line_segment([left_top, left_bottom], stroke);
        if end_with_horizontal_line {
            let fudge = 2.0; // looks nicer with button rounding in collapsing headers
            let right_bottom = pos2(child_ui.min_rect().right() - fudge, left_bottom.y);
            self.painter
                .line_segment([left_bottom, right_bottom], stroke);
        }

        let response = self.allocate_rect(child_ui.min_rect(), Sense::hover());
        InnerResponse::new(ret, response)
    }

    /// Start a ui with horizontal layout.
    /// After you have called this, the function registers the contents as any other widget.
    ///
    /// Elements will be centered on the Y axis, i.e.
    /// adjusted up and down to lie in the center of the horizontal layout.
    /// The initial height is `style.spacing.interact_size.y`.
    /// Centering is almost always what you want if you are
    /// planning to to mix widgets or use different types of text.
    ///
    /// The returned `Response` will only have checked for mouse hover
    /// but can be used for tooltips (`on_hover_text`).
    /// It also contains the `Rect` used by the horizontal layout.
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.horizontal(|ui|{
    ///     ui.label("Same");
    ///     ui.label("row");
    /// });
    /// ```
    pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
        self.horizontal_with_main_wrap(false, add_contents)
    }

    /// Like `horizontal`, but will set up the spacing to match that of a normal label.
    ///
    /// In particular, the space between widgets is the same width as the space character.
    ///
    /// You can still add any widgets to the layout (not only Labels).
    #[deprecated = "Use horizontal instead and set the desired spacing manually with `ui.spacing_mut().item_spacing`"]
    pub fn horizontal_for_text<R>(
        &mut self,
        text_style: TextStyle,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        self.wrap(|ui| {
            let font = &ui.fonts()[text_style];
            let row_height = font.row_height();
            let space_width = font.glyph_width(' ');
            let spacing = ui.spacing_mut();
            spacing.interact_size.y = row_height;
            spacing.item_spacing.x = space_width;
            spacing.item_spacing.y = 0.0;
            ui.horizontal(add_contents).inner
        })
    }

    /// Start a ui with horizontal layout that wraps to a new row
    /// when it reaches the right edge of the `max_size`.
    /// After you have called this, the function registers the contents as any other widget.
    ///
    /// Elements will be centered on the Y axis, i.e.
    /// adjusted up and down to lie in the center of the horizontal layout.
    /// The initial height is `style.spacing.interact_size.y`.
    /// Centering is almost always what you want if you are
    /// planning to to mix widgets or use different types of text.
    ///
    /// The returned `Response` will only have checked for mouse hover
    /// but can be used for tooltips (`on_hover_text`).
    /// It also contains the `Rect` used by the horizontal layout.
    pub fn horizontal_wrapped<R>(
        &mut self,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        self.horizontal_with_main_wrap(true, add_contents)
    }

    /// Like `horizontal_wrapped`, but will set up the spacing and
    /// line size to match that of a normal label.
    ///
    /// In particular, the space between widgets is the same width as the space character
    /// and the line spacing is the same as that for text.
    ///
    /// You can still add any widgets to the layout (not only Labels).
    #[deprecated = "Use horizontal_wrapped instead and set the desired spacing manually with `ui.spacing_mut().item_spacing`"]
    pub fn horizontal_wrapped_for_text<R>(
        &mut self,
        text_style: TextStyle,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        self.wrap(|ui| {
            let font = &ui.fonts()[text_style];
            let row_height = font.row_height();
            let space_width = font.glyph_width(' ');
            let spacing = ui.spacing_mut();
            spacing.interact_size.y = row_height;
            spacing.item_spacing.x = space_width;
            spacing.item_spacing.y = 0.0;
            ui.horizontal_wrapped(add_contents).inner
        })
    }

    fn horizontal_with_main_wrap<R>(
        &mut self,
        main_wrap: bool,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        let initial_size = vec2(
            self.available_size_before_wrap_finite().x,
            self.spacing().interact_size.y, // Assume there will be something interactive on the horizontal layout
        );

        let layout = if self.placer.prefer_right_to_left() {
            Layout::right_to_left()
        } else {
            Layout::left_to_right()
        }
        .with_main_wrap(main_wrap);

        self.allocate_ui(initial_size, |ui| {
            ui.with_layout(layout, add_contents).inner
        })
    }

    /// Start a ui with vertical layout.
    /// Widgets will be left-justified.
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.vertical(|ui|{
    ///     ui.label("over");
    ///     ui.label("under");
    /// });
    /// ```
    pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
        self.with_layout(Layout::top_down(Align::Min), add_contents)
    }

    /// Start a ui with vertical layout.
    /// Widgets will be horizontally centered.
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.vertical_centered(|ui|{
    ///     ui.label("over");
    ///     ui.label("under");
    /// });
    /// ```
    pub fn vertical_centered<R>(
        &mut self,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        self.with_layout(Layout::top_down(Align::Center), add_contents)
    }

    /// Start a ui with vertical layout.
    /// Widgets will be horizontally centered and justified (fill full width).
    ///
    /// ```
    /// # let ui = &mut egui::Ui::__test();
    /// ui.vertical_centered_justified(|ui|{
    ///     ui.label("over");
    ///     ui.label("under");
    /// });
    /// ```
    pub fn vertical_centered_justified<R>(
        &mut self,
        add_contents: impl FnOnce(&mut Ui) -> R,
    ) -> InnerResponse<R> {
        self.with_layout(
            Layout::top_down(Align::Center).with_cross_justify(true),
            add_contents,
        )
    }

    pub fn with_layout<R>(
        &mut self,
        layout: Layout,
        add_contents: impl FnOnce(&mut Self) -> R,
    ) -> InnerResponse<R> {
        let mut child_ui = self.child_ui(self.available_rect_before_wrap(), layout);
        let inner = add_contents(&mut child_ui);
        let rect = child_ui.min_rect();
        let item_spacing = self.spacing().item_spacing;
        self.placer.advance_after_rects(rect, rect, item_spacing);

        if self.visuals().debug_widgets && self.rect_contains_pointer(rect) {
            let painter = self.ctx().debug_painter();
            painter.rect_stroke(rect, 4.0, (1.0, Color32::LIGHT_BLUE));
            self.placer.debug_paint_cursor(&painter);
        }

        InnerResponse::new(inner, self.interact(rect, child_ui.id, Sense::hover()))
    }

    /// This will make the next added widget centered and justified in the available space.
    pub fn centered_and_justified<R>(
        &mut self,
        add_contents: impl FnOnce(&mut Self) -> R,
    ) -> InnerResponse<R> {
        self.with_layout(
            Layout::centered_and_justified(Direction::TopDown),
            add_contents,
        )
    }

    pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
        self.placer.set_grid(grid);
    }

    pub(crate) fn save_grid(&mut self) {
        self.placer.save_grid();
    }

    pub(crate) fn is_grid(&self) -> bool {
        self.placer.is_grid()
    }

    pub(crate) fn grid(&self) -> Option<&grid::GridLayout> {
        self.placer.grid()
    }

    /// Move to the next row in a grid layout or wrapping layout.
    /// Otherwise does nothing.
    pub fn end_row(&mut self) {
        self.placer
            .end_row(self.spacing().item_spacing, &self.painter().clone());
    }

    /// Set row height in horizontal wrapping layout.
    pub fn set_row_height(&mut self, height: f32) {
        self.placer.set_row_height(height);
    }

    /// Temporarily split split an Ui into several columns.
    ///
    /// ```
    /// # let mut ui = egui::Ui::__test();
    /// ui.columns(2, |columns| {
    ///     columns[0].label("First column");
    ///     columns[1].label("Second column");
    /// });
    /// ```
    pub fn columns<F, R>(&mut self, num_columns: usize, add_contents: F) -> R
    where
        F: FnOnce(&mut [Self]) -> R,
    {
        // TODO: ensure there is space
        let spacing = self.spacing().item_spacing.x;
        let total_spacing = spacing * (num_columns as f32 - 1.0);
        let column_width = (self.available_width() - total_spacing) / (num_columns as f32);
        let top_left = self.cursor().min;

        let mut columns: Vec<Self> = (0..num_columns)
            .map(|col_idx| {
                let pos = top_left + vec2((col_idx as f32) * (column_width + spacing), 0.0);
                let child_rect = Rect::from_min_max(
                    pos,
                    pos2(pos.x + column_width, self.max_rect().right_bottom().y),
                );
                let mut column_ui =
                    self.child_ui(child_rect, Layout::top_down_justified(Align::LEFT));
                column_ui.set_width(column_width);
                column_ui
            })
            .collect();

        let result = add_contents(&mut columns[..]);

        let mut max_column_width = column_width;
        let mut max_height = 0.0;
        for column in &columns {
            max_column_width = max_column_width.max(column.min_rect().width());
            max_height = column.min_size().y.max(max_height);
        }

        // Make sure we fit everything next frame:
        let total_required_width = total_spacing + max_column_width * (num_columns as f32);

        let size = vec2(self.available_width().max(total_required_width), max_height);
        self.advance_cursor_after_rect(Rect::from_min_size(top_left, size));
        result
    }
}

// ----------------------------------------------------------------------------

/// # Debug stuff
impl Ui {
    /// Shows where the next widget is going to be placed
    pub fn debug_paint_cursor(&self) {
        self.placer.debug_paint_cursor(&self.painter);
    }
}
