[refactor] Ui: rename child_bounds to min_rect, desired_rect to max_rect

This commit is contained in:
Emil Ernerfeldt 2020-09-27 11:04:12 +02:00
parent 43bb670c0c
commit 908d1d0c08
10 changed files with 153 additions and 121 deletions

View file

@ -173,7 +173,7 @@ impl Prepared {
movable, movable,
} = self; } = self;
state.size = (content_ui.child_bounds().max - state.pos).ceil(); state.size = (content_ui.min_rect().max - state.pos).ceil();
let rect = Rect::from_min_size(state.pos, state.size); let rect = Rect::from_min_size(state.pos, state.size);
let clip_rect = Rect::everything(); // TODO: get from context let clip_rect = Rect::everything(); // TODO: get from context
@ -214,11 +214,6 @@ impl Prepared {
)); ));
state.pos = ctx.round_pos_to_pixels(state.pos); state.pos = ctx.round_pos_to_pixels(state.pos);
// ctx.debug_rect(
// Rect::from_min_size(state.pos, state.size),
// &format!("Area size: {:?}", state.size),
// );
if move_response.active if move_response.active
|| mouse_pressed_on_area(ctx, layer) || mouse_pressed_on_area(ctx, layer)
|| !ctx.memory().areas.visible_last_frame(&layer) || !ctx.memory().areas.visible_last_frame(&layer)

View file

@ -78,18 +78,18 @@ impl State {
}; };
let mut clip_rect = child_ui.clip_rect(); let mut clip_rect = child_ui.clip_rect();
clip_rect.max.y = clip_rect.max.y.min(child_ui.rect().top() + max_height); clip_rect.max.y = clip_rect.max.y.min(child_ui.max_rect().top() + max_height);
child_ui.set_clip_rect(clip_rect); child_ui.set_clip_rect(clip_rect);
let top_left = child_ui.top_left(); let left_top = child_ui.left_top();
let r = add_contents(child_ui); let r = add_contents(child_ui);
self.open_height = Some(child_ui.bounding_size().y); self.open_height = Some(child_ui.min_size().y);
// Pretend children took up less space: // Pretend children took up less space:
let mut child_bounds = child_ui.child_bounds(); let mut min_rect = child_ui.min_rect();
child_bounds.max.y = child_bounds.max.y.min(top_left.y + max_height); min_rect.max.y = min_rect.max.y.min(left_top.y + max_height);
child_ui.force_set_child_bounds(child_bounds); child_ui.force_set_min_rect(min_rect);
r r
})) }))
} else if self.open { } else if self.open {

View file

@ -35,11 +35,11 @@ pub fn combo_box(
selected.ui(ui); selected.ui(ui);
let advance = full_minimum_width - icon_width - ui.child_bounds().width(); let advance = full_minimum_width - icon_width - ui.min_rect().width();
ui.advance_cursor(advance.at_least(0.0)); ui.advance_cursor(advance.at_least(0.0));
let icon_rect = ui.allocate_space(Vec2::splat(icon_width)); let icon_rect = ui.allocate_space(Vec2::splat(icon_width));
let button_rect = ui.rect().expand2(ui.style().spacing.button_padding); let button_rect = ui.min_rect().expand2(ui.style().spacing.button_padding);
let mut response = ui.interact(button_rect, button_id, Sense::click()); let mut response = ui.interact(button_rect, button_id, Sense::click());
response.active |= button_active; response.active |= button_active;
paint_icon(ui.painter(), icon_rect, ui.style().interact(&response)); paint_icon(ui.painter(), icon_rect, ui.style().interact(&response));
@ -57,8 +57,10 @@ pub fn combo_box(
let frame = Frame::popup(ui.style()); let frame = Frame::popup(ui.style());
let frame_margin = frame.margin; let frame_margin = frame.margin;
frame.show(ui, |ui| { frame.show(ui, |ui| {
ui.set_min_width(button_response.rect.width() - 2.0 * frame_margin.x); ui.with_layout(Layout::justified(Direction::Vertical), |ui| {
ui.with_layout(Layout::justified(Direction::Vertical), menu_contents); ui.set_min_width(button_response.rect.width() - 2.0 * frame_margin.x);
menu_contents(ui);
});
}) })
}); });
@ -85,10 +87,7 @@ fn button_frame(
let mut content_ui = ui.child_ui(inner_rect, *ui.layout()); let mut content_ui = ui.child_ui(inner_rect, *ui.layout());
add_contents(&mut content_ui); add_contents(&mut content_ui);
let outer_rect = Rect::from_min_max( let outer_rect = Rect::from_min_max(outer_rect_bounds.min, content_ui.min_rect().max + margin);
outer_rect_bounds.min,
content_ui.child_bounds().max + margin,
);
let mut response = ui.interact(outer_rect, id, sense); let mut response = ui.interact(outer_rect, id, sense);
response.active |= button_active; response.active |= button_active;

View file

@ -102,7 +102,7 @@ impl Prepared {
pub fn outer_rect(&self) -> Rect { pub fn outer_rect(&self) -> Rect {
Rect::from_min_max( Rect::from_min_max(
self.outer_rect_bounds.min, self.outer_rect_bounds.min,
self.content_ui.child_bounds().max + self.frame.margin, self.content_ui.min_rect().max + self.frame.margin,
) )
} }

View file

@ -229,7 +229,7 @@ impl Resize {
content_ui, content_ui,
} = prepared; } = prepared;
state.last_content_size = content_ui.bounding_size(); state.last_content_size = content_ui.min_size();
state.last_content_size = state.last_content_size.ceil(); // Avoid rounding errors in math state.last_content_size = state.last_content_size.ceil(); // Avoid rounding errors in math
// ------------------------------ // ------------------------------
@ -251,7 +251,7 @@ impl Resize {
// ------------------------------ // ------------------------------
if self.with_stroke && corner_response.is_some() { if self.with_stroke && corner_response.is_some() {
let rect = Rect::from_min_size(content_ui.top_left(), state.desired_size); let rect = Rect::from_min_size(content_ui.left_top(), state.desired_size);
let rect = rect.expand(2.0); // breathing room for content let rect = rect.expand(2.0); // breathing room for content
ui.painter().add(paint::PaintCmd::Rect { ui.painter().add(paint::PaintCmd::Rect {
rect, rect,
@ -273,12 +273,12 @@ impl Resize {
if ui.ctx().style().visuals.debug_resize { if ui.ctx().style().visuals.debug_resize {
ui.ctx().debug_painter().debug_rect( ui.ctx().debug_painter().debug_rect(
Rect::from_min_size(content_ui.top_left(), state.desired_size), Rect::from_min_size(content_ui.left_top(), state.desired_size),
color::GREEN, color::GREEN,
"desired_size", "desired_size",
); );
ui.ctx().debug_painter().debug_rect( ui.ctx().debug_painter().debug_rect(
Rect::from_min_size(content_ui.top_left(), state.last_content_size), Rect::from_min_size(content_ui.left_top(), state.last_content_size),
color::LIGHT_BLUE, color::LIGHT_BLUE,
"last_content_size", "last_content_size",
); );

View file

@ -141,7 +141,7 @@ impl Prepared {
content_ui, content_ui,
} = self; } = self;
let content_size = content_ui.bounding_size(); let content_size = content_ui.min_size();
let inner_rect = Rect::from_min_size( let inner_rect = Rect::from_min_size(
inner_rect.min, inner_rect.min,

View file

@ -602,7 +602,7 @@ fn show_title_bar(
collapsible: bool, collapsible: bool,
) -> TitleBar { ) -> TitleBar {
let title_bar_and_rect = ui.horizontal(|ui| { let title_bar_and_rect = ui.horizontal(|ui| {
ui.set_desired_height(title_label.font_height(ui.fonts(), ui.style())); ui.set_min_height(title_label.font_height(ui.fonts(), ui.style()));
let item_spacing = ui.style().spacing.item_spacing; let item_spacing = ui.style().spacing.item_spacing;
let button_size = ui.style().spacing.icon_width; let button_size = ui.style().spacing.icon_width;
@ -625,7 +625,7 @@ fn show_title_bar(
if show_close_button { if show_close_button {
// Reserve space for close button which will be added later (once we know our full width): // Reserve space for close button which will be added later (once we know our full width):
let close_max_x = title_rect.right() + item_spacing.x + button_size + item_spacing.x; let close_max_x = title_rect.right() + item_spacing.x + button_size + item_spacing.x;
let close_max_x = close_max_x.max(ui.rect_finite().right()); let close_max_x = close_max_x.max(ui.max_rect_finite().right());
let close_rect = Rect::from_min_size( let close_rect = Rect::from_min_size(
pos2( pos2(
close_max_x - button_size, close_max_x - button_size,

View file

@ -30,7 +30,7 @@ impl Texture {
if ui.hovered(rect) { if ui.hovered(rect) {
show_tooltip(ui.ctx(), |ui| { show_tooltip(ui.ctx(), |ui| {
let pos = ui.input().mouse.pos.unwrap_or_else(|| ui.top_left()); let pos = ui.input().mouse.pos.unwrap_or_else(|| ui.left_top());
let zoom_rect = ui.allocate_space(vec2(128.0, 128.0)); let zoom_rect = ui.allocate_space(vec2(128.0, 128.0));
let u = remap_clamp(pos.x, rect.range_x(), 0.0..=tex_w); let u = remap_clamp(pos.x, rect.range_x(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.range_y(), 0.0..=tex_h); let v = remap_clamp(pos.y, rect.range_y(), 0.0..=tex_h);

View file

@ -52,8 +52,7 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
// Take full width and fixed height: // Take full width and fixed height:
let height = ui.style().spacing.interact_size.y; let height = ui.style().spacing.interact_size.y;
ui.set_desired_height(height); ui.set_min_size(vec2(ui.available().width(), height));
ui.expand_to_size(vec2(ui.available().width(), height));
add_contents(ui) add_contents(ui)
}) })

View file

@ -14,21 +14,27 @@ pub struct Ui {
painter: Painter, painter: Painter,
/// The `rect` represents where in screen-space the ui is /// This is the minimal size of the `Ui`.
/// and its max size (original available_space). /// When adding new widgets, this will generally expand.
/// Note that the size may be infinite in one or both dimensions. ///
/// The widgets will TRY to fit within the rect, /// Always finite.
/// but may overflow (which you will see in child_bounds). ///
/// Some widgets (like separator lines) will try to fill the full desired width of the ui. /// The bounding box of all child widgets, but not necessarily a tight bounding box
/// If the desired size is zero, it is a signal that child widgets should be as small as possible. /// since `Ui` can start with a non-zero min_rect size.
/// If the desired size is infinite, it is a signal that child widgets should take up as much room as they want. min_rect: Rect,
desired_rect: Rect, // TODO: rename as max_rect ?
/// Bounding box of all children. /// The maximum size of this `Ui`. This is a *soft max*
/// This is used to see how large a ui actually /// meaning new widgets will *try* not to expand beyond it,
/// needs to be after all children has been added. /// but if they have to, they will.
/// You can think of this as the minimum size. ///
child_bounds: Rect, // TODO: rename as min_rect ? /// Text will wrap at `max_rect.right()`.
/// Some widgets (like separator lines) will try to fill the full `max_rect` width of the ui.
///
/// `max_rect` will always be at least the size of `min_rect`.
///
/// If the `max_rect` size is zero, it is a signal that child widgets should be as small as possible.
/// If the `max_rect` size is infinite, it is a signal that child widgets should take up as much room as they want.
max_rect: Rect,
/// Override default style in this ui /// Override default style in this ui
style: Style, style: Style,
@ -39,7 +45,7 @@ pub struct Ui {
/// Progresses along self.dir. /// Progresses along self.dir.
/// Initially set to rect.min /// Initially set to rect.min
/// If something has already been added, this will point ot style.spacing.item_spacing beyond the latest child. /// If something has already been added, this will point ot style.spacing.item_spacing beyond the latest child.
/// The cursor can thus be style.spacing.item_spacing pixels outside of the child_bounds. /// The cursor can thus be style.spacing.item_spacing pixels outside of the min_rect.
cursor: Pos2, // TODO: move into Layout? cursor: Pos2, // TODO: move into Layout?
/// How many children has been added to us? /// How many children has been added to us?
@ -52,32 +58,38 @@ impl Ui {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Creation: // Creation:
pub fn new(ctx: Arc<Context>, layer: Layer, id: Id, rect: Rect) -> Self { pub fn new(ctx: Arc<Context>, layer: Layer, id: Id, max_rect: Rect) -> Self {
let style = ctx.style(); let style = ctx.style();
let clip_rect = rect.expand(style.visuals.clip_rect_margin); let clip_rect = max_rect.expand(style.visuals.clip_rect_margin);
let layout = Layout::default();
let cursor = layout.initial_cursor(max_rect);
let min_size = Vec2::zero(); // TODO: From Style
let min_rect = layout.rect_from_cursor_size(cursor, min_size);
Ui { Ui {
id, id,
painter: Painter::new(ctx, layer, clip_rect), painter: Painter::new(ctx, layer, clip_rect),
desired_rect: rect, min_rect,
child_bounds: Rect::from_min_size(rect.min, Vec2::zero()), // TODO: Rect::nothing() ? max_rect,
style, style,
layout: Default::default(), layout,
cursor: rect.min, cursor,
child_count: 0, child_count: 0,
} }
} }
pub fn child_ui(&mut self, child_rect: Rect, layout: Layout) -> Self { pub fn child_ui(&mut self, max_rect: Rect, layout: Layout) -> Self {
let id = self.make_position_id(); // TODO: is this a good idea? let id = self.make_position_id(); // TODO: is this a good idea?
self.child_count += 1; self.child_count += 1;
let cursor = layout.initial_cursor(child_rect); let cursor = layout.initial_cursor(max_rect);
let min_size = Vec2::zero(); // TODO: From Style
let min_rect = layout.rect_from_cursor_size(cursor, min_size);
Ui { Ui {
id, id,
painter: self.painter.clone(), painter: self.painter.clone(),
desired_rect: child_rect, min_rect,
child_bounds: Rect::from_min_size(child_rect.min, Vec2::zero()), // TODO: Rect::nothing() ? max_rect,
style: self.style().clone(), style: self.style().clone(),
layout, layout,
cursor, cursor,
@ -115,6 +127,10 @@ impl Ui {
&self.painter &self.painter
} }
pub fn layout(&self) -> &Layout {
&self.layout
}
/// Create a painter for a sub-region of this Ui. /// Create a painter for a sub-region of this Ui.
/// ///
/// The clip-rect of the returned `Painter` will be the intersection /// The clip-rect of the returned `Painter` will be the intersection
@ -155,103 +171,129 @@ impl Ui {
pub fn set_clip_rect(&mut self, clip_rect: Rect) { pub fn set_clip_rect(&mut self, clip_rect: Rect) {
self.painter.set_clip_rect(clip_rect); self.painter.set_clip_rect(clip_rect);
} }
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// ## Sizes etc
impl Ui {
/// Screen-space position of this Ui. /// Screen-space position of this Ui.
/// This may have moved from its original if a child overflowed to the left or up (rare). /// This may have moved from its original if a child overflowed to the left or up (rare).
pub fn top_left(&self) -> Pos2 { pub fn left_top(&self) -> Pos2 {
// If a child doesn't fit in desired_rect, we have effectively expanded: // If a child doesn't fit in max_rect, we have effectively expanded:
self.desired_rect.min.min(self.child_bounds.min) self.max_rect.min
} }
/// Screen-space position of the current bottom right corner of this Ui. /// Screen-space position of the current bottom right corner of this Ui.
/// This may move when we add children that overflow our desired rectangle bounds. /// This may move when we add children that overflow our desired rectangle bounds.
/// This position may be at infinity if the desired rect is infinite, /// This position may be at infinity if the desired rect is infinite,
/// which happens when a parent widget says "be as big as you want to be". /// which happens when a parent widget says "be as big as you want to be".
pub fn bottom_right(&self) -> Pos2 { pub fn right_bottom(&self) -> Pos2 {
// If a child doesn't fit in desired_rect, we have effectively expanded: // If a child doesn't fit in max_rect, we have effectively expanded:
self.desired_rect.max.max(self.child_bounds.max) self.max_rect.max
} }
/// Position and current size of the ui. /// Bounding box of all contained children
/// The size is the maximum of the original (minimum/desired) size and pub fn min_rect(&self) -> Rect {
/// the size of the contained children. self.min_rect
pub fn rect(&self) -> Rect {
Rect::from_min_max(self.top_left(), self.bottom_right())
} }
/// This is like `rect()`, but will never be infinite. /// This is the soft max size of the Ui.
pub fn max_rect(&self) -> Rect {
self.max_rect
}
/// Used for animation, kind of hacky
pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
self.min_rect = min_rect;
}
/// This is like `max_rect()`, but will never be infinite.
/// If the desired rect is infinite ("be as big as you want") /// If the desired rect is infinite ("be as big as you want")
/// this will be bounded by child bounds. /// this will be bounded by min_rect instead.
pub fn rect_finite(&self) -> Rect { pub fn max_rect_finite(&self) -> Rect {
let mut bottom_right = self.child_bounds.max; let mut right_bottom = self.min_rect.max;
if self.desired_rect.max.x.is_finite() { if self.max_rect.max.x.is_finite() {
bottom_right.x = bottom_right.x.max(self.desired_rect.max.x); right_bottom.x = right_bottom.x.max(self.max_rect.max.x);
} }
if self.desired_rect.max.y.is_finite() { if self.max_rect.max.y.is_finite() {
bottom_right.y = bottom_right.y.max(self.desired_rect.max.y); right_bottom.y = right_bottom.y.max(self.max_rect.max.y);
} }
Rect::from_min_max(self.top_left(), bottom_right) Rect::from_min_max(self.left_top(), right_bottom)
}
pub fn set_min_width(&mut self, width: f32) {
self.child_bounds.max.x = self.child_bounds.max.x.max(self.child_bounds.min.x + width);
self.desired_rect.max.x = self.desired_rect.max.x.max(self.desired_rect.min.x + width);
} }
/// Set the width of the ui. /// Set the width of the ui.
/// You won't be able to shrink it beyond its current child bounds. /// You won't be able to shrink it beyond its current child bounds.
pub fn set_desired_width(&mut self, width: f32) { pub fn set_max_width(&mut self, width: f32) {
let min_width = self.child_bounds.max.x - self.top_left().x; let min_width = self.min_rect.max.x - self.left_top().x;
let width = width.at_least(min_width); let width = width.at_least(min_width);
self.desired_rect.max.x = self.top_left().x + width; self.max_rect.max.x = self.left_top().x + width;
} }
/// Set the height of the ui. /// Set the height of the ui.
/// You won't be able to shrink it beyond its current child bounds. /// You won't be able to shrink it beyond its current child bounds.
pub fn set_desired_height(&mut self, height: f32) { pub fn set_max_height(&mut self, height: f32) {
let min_height = self.child_bounds.max.y - self.top_left().y; let min_height = self.min_rect.max.y - self.left_top().y;
let height = height.at_least(min_height); let height = height.at_least(min_height);
self.desired_rect.max.y = self.top_left().y + height; self.max_rect.max.y = self.left_top().y + height;
}
pub fn set_min_size(&mut self, size: Vec2) {
self.set_min_width(size.x);
self.set_min_height(size.y);
}
pub fn set_min_width(&mut self, width: f32) {
if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.x, self.max_rect.max.x);
self.min_rect.min.x = self.min_rect.min.x.min(self.min_rect.max.x - width);
self.max_rect.min.x = self.max_rect.min.x.min(self.max_rect.max.x - width);
} else {
debug_assert_eq!(self.min_rect.min.x, self.max_rect.min.x);
self.min_rect.max.x = self.min_rect.max.x.max(self.min_rect.min.x + width);
self.max_rect.max.x = self.max_rect.max.x.max(self.max_rect.min.x + width);
}
}
pub fn set_min_height(&mut self, height: f32) {
if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.y, self.max_rect.max.y);
self.min_rect.min.y = self.min_rect.min.y.min(self.min_rect.max.y - height);
self.max_rect.min.y = self.max_rect.min.y.min(self.max_rect.max.y - height);
} else {
debug_assert_eq!(self.min_rect.min.y, self.max_rect.min.y);
self.min_rect.max.y = self.min_rect.max.y.max(self.min_rect.min.y + height);
self.max_rect.max.y = self.max_rect.max.y.max(self.max_rect.min.y + height);
}
} }
/// Helper: shrinks the max/desired width to the current width, /// Helper: shrinks the max/desired width to the current width,
/// so further widgets will try not to be wider than previous widgets. /// so further widgets will try not to be wider than previous widgets.
/// Useful for normal vertical layouts. /// Useful for normal vertical layouts.
pub fn shrink_width_to_current(&mut self) { pub fn shrink_width_to_current(&mut self) {
self.set_desired_width(self.child_bounds().width()) self.set_max_width(self.min_rect().width())
} }
/// Helper: shrinks the max/desired height to the current height, /// Helper: shrinks the max/desired height to the current height,
/// so further widgets will try not to be wider than previous widgets. /// so further widgets will try not to be wider than previous widgets.
pub fn shrink_height_to_current(&mut self) { pub fn shrink_height_to_current(&mut self) {
self.set_desired_height(self.child_bounds().height()) self.set_min_height(self.min_rect().height())
} }
/// Size of content /// Size of content
pub fn bounding_size(&self) -> Vec2 { pub fn min_size(&self) -> Vec2 {
self.child_bounds.size() self.min_rect.size()
} }
/// Expand the bounding rect of this ui to include a child at the given rect. /// Expand the bounding rect of this ui to include a child at the given rect.
pub fn expand_to_include_child(&mut self, rect: Rect) { pub fn expand_to_include_child(&mut self, rect: Rect) {
self.child_bounds.extend_with(rect.min); self.min_rect.extend_with(rect.min);
self.child_bounds.extend_with(rect.max); self.min_rect.extend_with(rect.max);
} }
pub fn expand_to_size(&mut self, size: Vec2) { pub fn expand_to_size(&mut self, size: Vec2) {
self.child_bounds.extend_with(self.top_left() + size); self.min_rect.extend_with(self.left_top() + size);
}
/// Bounding box of all contained children
pub fn child_bounds(&self) -> Rect {
self.child_bounds
}
pub fn force_set_child_bounds(&mut self, child_bounds: Rect) {
self.child_bounds = child_bounds;
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -264,18 +306,14 @@ impl Ui {
/// An infinite rectangle should be interpreted as "as much as you want". /// An infinite rectangle should be interpreted as "as much as you want".
/// In most layouts the next widget will be put in the top left corner of this `Rect`. /// In most layouts the next widget will be put in the top left corner of this `Rect`.
pub fn available(&self) -> Rect { pub fn available(&self) -> Rect {
self.layout.available(self.cursor, self.rect()) self.layout.available(self.cursor, self.max_rect())
} }
/// This is like `available()`, but will never be infinite. /// This is like `available()`, but will never be infinite.
/// Use this for components that want to grow without bounds (but shouldn't). /// Use this for components that want to grow without bounds (but shouldn't).
/// In most layouts the next widget will be put in the top left corner of this `Rect`. /// In most layouts the next widget will be put in the top left corner of this `Rect`.
pub fn available_finite(&self) -> Rect { pub fn available_finite(&self) -> Rect {
self.layout.available(self.cursor, self.rect_finite()) self.layout.available(self.cursor, self.max_rect_finite())
}
pub fn layout(&self) -> &Layout {
&self.layout
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -415,7 +453,8 @@ impl Ui {
let child_rect = let child_rect =
self.layout self.layout
.allocate_space(&mut self.cursor, &self.style, available_size, child_size); .allocate_space(&mut self.cursor, &self.style, available_size, child_size);
self.child_bounds = self.child_bounds.union(child_rect); self.min_rect = self.min_rect.union(child_rect);
self.max_rect = self.max_rect.union(child_rect);
self.child_count += 1; self.child_count += 1;
child_rect child_rect
} }
@ -586,14 +625,14 @@ impl Ui {
/// Actual size may be much smaller if `available_size()` is not enough. /// Actual size may be much smaller if `available_size()` is not enough.
/// Set `size` to `Vec::infinity()` to get as much space as possible. /// Set `size` to `Vec::infinity()` to get as much space as possible.
/// Just because you ask for a lot of space does not mean you have to use it! /// Just because you ask for a lot of space does not mean you have to use it!
/// After `add_contents` is called the contents of `bounding_size` /// After `add_contents` is called the contents of `min_size`
/// will decide how much space will be used in the parent ui. /// will decide how much space will be used in the parent ui.
pub fn add_custom_contents(&mut self, size: Vec2, add_contents: impl FnOnce(&mut Ui)) -> Rect { pub fn add_custom_contents(&mut self, size: Vec2, add_contents: impl FnOnce(&mut Ui)) -> Rect {
let size = size.at_most(self.available().size()); let size = size.at_most(self.available().size());
let child_rect = self.layout.rect_from_cursor_size(self.cursor, size); let child_rect = self.layout.rect_from_cursor_size(self.cursor, size);
let mut child_ui = self.child_ui(child_rect, self.layout); let mut child_ui = self.child_ui(child_rect, self.layout);
add_contents(&mut child_ui); add_contents(&mut child_ui);
self.allocate_space(child_ui.bounding_size()) self.allocate_space(child_ui.min_size())
} }
/// Create a child ui. You can use this to temporarily change the Style of a sub-region, for instance. /// Create a child ui. You can use this to temporarily change the Style of a sub-region, for instance.
@ -601,7 +640,7 @@ impl Ui {
let child_rect = self.available(); let child_rect = self.available();
let mut child_ui = self.child_ui(child_rect, self.layout); let mut child_ui = self.child_ui(child_rect, self.layout);
let r = add_contents(&mut child_ui); let r = add_contents(&mut child_ui);
let size = child_ui.bounding_size(); let size = child_ui.min_size();
(r, self.allocate_space(size)) (r, self.allocate_space(size))
} }
@ -616,13 +655,13 @@ impl Ui {
"You can only indent vertical layouts" "You can only indent vertical layouts"
); );
let indent = vec2(self.style().spacing.indent, 0.0); let indent = vec2(self.style().spacing.indent, 0.0);
let child_rect = Rect::from_min_max(self.cursor + indent, self.bottom_right()); // TODO: wrong for reversed layouts let child_rect = Rect::from_min_max(self.cursor + indent, self.right_bottom()); // TODO: wrong for reversed layouts
let mut child_ui = Ui { let mut child_ui = Ui {
id: self.id.with(id_source), id: self.id.with(id_source),
..self.child_ui(child_rect, self.layout) ..self.child_ui(child_rect, self.layout)
}; };
let ret = add_contents(&mut child_ui); let ret = add_contents(&mut child_ui);
let size = child_ui.bounding_size(); let size = child_ui.min_size();
// draw a grey line on the left to mark the indented section // draw a grey line on the left to mark the indented section
let line_start = child_rect.min - indent * 0.5; let line_start = child_rect.min - indent * 0.5;
@ -698,7 +737,7 @@ impl Ui {
let child_rect = self.layout.rect_from_cursor_size(self.cursor, initial_size); let child_rect = self.layout.rect_from_cursor_size(self.cursor, initial_size);
let mut child_ui = self.child_ui(child_rect, layout); let mut child_ui = self.child_ui(child_rect, layout);
let ret = add_contents(&mut child_ui); let ret = add_contents(&mut child_ui);
let size = child_ui.bounding_size(); let size = child_ui.min_size();
let rect = self.allocate_space(size); let rect = self.allocate_space(size);
(ret, rect) (ret, rect)
} }
@ -710,7 +749,7 @@ impl Ui {
) -> (R, Rect) { ) -> (R, Rect) {
let mut child_ui = self.child_ui(self.available(), layout); let mut child_ui = self.child_ui(self.available(), layout);
let ret = add_contents(&mut child_ui); let ret = add_contents(&mut child_ui);
let size = child_ui.bounding_size(); let size = child_ui.min_size();
let rect = self.allocate_space(size); let rect = self.allocate_space(size);
(ret, rect) (ret, rect)
} }
@ -736,7 +775,7 @@ impl Ui {
.map(|col_idx| { .map(|col_idx| {
let pos = self.cursor + vec2((col_idx as f32) * (column_width + spacing), 0.0); let pos = self.cursor + vec2((col_idx as f32) * (column_width + spacing), 0.0);
let child_rect = let child_rect =
Rect::from_min_max(pos, pos2(pos.x + column_width, self.bottom_right().y)); Rect::from_min_max(pos, pos2(pos.x + column_width, self.right_bottom().y));
Self { Self {
id: self.make_child_id(&("column", col_idx)), id: self.make_child_id(&("column", col_idx)),
@ -749,12 +788,12 @@ impl Ui {
let mut sum_width = total_spacing; let mut sum_width = total_spacing;
for column in &columns { for column in &columns {
sum_width += column.child_bounds.width(); sum_width += column.min_rect.width();
} }
let mut max_height = 0.0; let mut max_height = 0.0;
for ui in columns { for ui in columns {
let size = ui.bounding_size(); let size = ui.min_size();
max_height = size.y.max(max_height); max_height = size.y.max(max_height);
} }