Refactor: move min_rect/max_rect/cursor into struct Region

This commit is contained in:
Emil Ernerfeldt 2020-12-06 10:16:37 +01:00
parent 6e8d5c87a0
commit b0ba66b90d
3 changed files with 187 additions and 124 deletions

View file

@ -2,6 +2,12 @@
TODO-list for the Egui project. If you looking for something to do, look here. TODO-list for the Egui project. If you looking for something to do, look here.
## Layout refactor
* Deprecate `add_custom_contents`
* Fix and test `allocate_ui`
*
## Misc ## Misc
* Widgets * Widgets

View file

@ -2,6 +2,68 @@ use crate::{math::*, Align};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/// This describes the bounds and existing contents of an `Ui`.
/// It is what is used and updated by `Layout` when adding new widgets.
#[derive(Clone, Copy, Debug)]
pub struct Region {
/// This is the minimal size of the `Ui`.
/// When adding new widgets, this will generally expand.
///
/// Always finite.
///
/// The bounding box of all child widgets, but not necessarily a tight bounding box
/// since `Ui` can start with a non-zero min_rect size.
pub min_rect: Rect,
/// The maximum size of this `Ui`. This is a *soft max*
/// meaning new widgets will *try* not to expand beyond it,
/// but if they have to, they will.
///
/// 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.
pub max_rect: Rect,
/// Where the next widget will be put.
/// 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 min_rect.
pub(crate) cursor: Pos2,
}
impl Region {
/// This is like `max_rect`, but will never be infinite.
/// If the desired rect is infinite ("be as big as you want")
/// this will be bounded by `min_rect` instead.
pub fn max_rect_finite(&self) -> Rect {
let mut result = self.max_rect;
if !result.min.x.is_finite() {
result.min.x = self.min_rect.min.x;
}
if !result.min.y.is_finite() {
result.min.y = self.min_rect.min.y;
}
if !result.max.x.is_finite() {
result.max.x = self.min_rect.max.x;
}
if !result.max.y.is_finite() {
result.max.y = self.min_rect.max.y;
}
result
}
/// 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.min_rect = self.min_rect.union(rect);
self.max_rect = self.max_rect.union(rect);
}
}
// ----------------------------------------------------------------------------
/// `Layout` direction (horizontal or vertical). /// `Layout` direction (horizontal or vertical).
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
@ -112,7 +174,7 @@ impl Layout {
self.reversed self.reversed
} }
pub fn initial_cursor(self, max_rect: Rect) -> Pos2 { fn initial_cursor(self, max_rect: Rect) -> Pos2 {
match self.dir { match self.dir {
Direction::Horizontal => { Direction::Horizontal => {
if self.reversed { if self.reversed {
@ -131,9 +193,27 @@ impl Layout {
} }
} }
pub fn region_from_max_rect(&self, max_rect: Rect) -> Region {
let cursor = self.initial_cursor(max_rect);
let min_rect = Rect::from_min_size(cursor, Vec2::zero());
Region {
min_rect,
max_rect,
cursor,
}
}
pub fn available(&self, region: &Region) -> Rect {
self.available_from_cursor_max_rect(region.cursor, region.max_rect)
}
pub fn available_finite(&self, region: &Region) -> Rect {
self.available_from_cursor_max_rect(region.cursor, region.max_rect_finite())
}
/// Given the cursor in the region, how much space is available /// Given the cursor in the region, how much space is available
/// for the next widget? /// for the next widget?
pub fn available(self, cursor: Pos2, max_rect: Rect) -> Rect { fn available_from_cursor_max_rect(self, cursor: Pos2, max_rect: Rect) -> Rect {
let mut rect = max_rect; let mut rect = max_rect;
match self.dir { match self.dir {
Direction::Horizontal => { Direction::Horizontal => {
@ -157,46 +237,46 @@ impl Layout {
} }
/// Advance the cursor by this many points. /// Advance the cursor by this many points.
pub fn advance_cursor(self, cursor: &mut Pos2, amount: f32) { pub fn advance_cursor(self, region: &mut Region, amount: f32) {
match self.dir() { match self.dir() {
Direction::Horizontal => { Direction::Horizontal => {
if self.is_reversed() { if self.is_reversed() {
cursor.x -= amount; region.cursor.x -= amount;
} else { } else {
cursor.x += amount; region.cursor.x += amount;
} }
} }
Direction::Vertical => { Direction::Vertical => {
if self.is_reversed() { if self.is_reversed() {
cursor.y -= amount; region.cursor.y -= amount;
} else { } else {
cursor.y += amount; region.cursor.y += amount;
} }
} }
} }
} }
/// Advance the cursor by this spacing /// Advance the cursor by this spacing
pub fn advance_cursor2(self, cursor: &mut Pos2, amount: Vec2) { pub fn advance_cursor2(self, region: &mut Region, amount: Vec2) {
match self.dir() { match self.dir() {
Direction::Horizontal => self.advance_cursor(cursor, amount.x), Direction::Horizontal => self.advance_cursor(region, amount.x),
Direction::Vertical => self.advance_cursor(cursor, amount.y), Direction::Vertical => self.advance_cursor(region, amount.y),
} }
} }
pub fn rect_from_cursor_size(self, cursor: Pos2, size: Vec2) -> Rect { pub fn rect_from_cursor_size(self, region: &Region, size: Vec2) -> Rect {
let mut rect = Rect::from_min_size(cursor, size); let mut rect = Rect::from_min_size(region.cursor, size);
match self.dir { match self.dir {
Direction::Horizontal => { Direction::Horizontal => {
if self.reversed { if self.reversed {
rect.min.x = cursor.x - size.x; rect.min.x = region.cursor.x - size.x;
rect.max.x = rect.min.x - size.x rect.max.x = rect.min.x - size.x
} }
} }
Direction::Vertical => { Direction::Vertical => {
if self.reversed { if self.reversed {
rect.min.y = cursor.y - size.y; rect.min.y = region.cursor.y - size.y;
rect.max.y = rect.min.y - size.y rect.max.y = rect.min.y - size.y
} }
} }
@ -217,12 +297,8 @@ impl Layout {
/// for `Justified` aligned layouts, like in menus. /// for `Justified` aligned layouts, like in menus.
/// ///
/// You may get LESS space than you asked for if the current layout won't fit what you asked for. /// You may get LESS space than you asked for if the current layout won't fit what you asked for.
pub fn allocate_space( pub fn allocate_space(self, region: &mut Region, minimum_child_size: Vec2) -> Rect {
self, let available_size = self.available_finite(region).size();
cursor: &mut Pos2,
available_size: Vec2,
minimum_child_size: Vec2,
) -> Rect {
let available_size = available_size.at_least(minimum_child_size); let available_size = available_size.at_least(minimum_child_size);
let mut child_size = minimum_child_size; let mut child_size = minimum_child_size;
@ -260,16 +336,16 @@ impl Layout {
} }
if self.is_reversed() { if self.is_reversed() {
let child_pos = *cursor + child_move; let child_pos = region.cursor + child_move;
let child_pos = match self.dir { let child_pos = match self.dir {
Direction::Horizontal => child_pos + vec2(-child_size.x, 0.0), Direction::Horizontal => child_pos + vec2(-child_size.x, 0.0),
Direction::Vertical => child_pos + vec2(0.0, -child_size.y), Direction::Vertical => child_pos + vec2(0.0, -child_size.y),
}; };
*cursor -= cursor_change; region.cursor -= cursor_change; // TODO: separate call
Rect::from_min_size(child_pos, child_size) Rect::from_min_size(child_pos, child_size)
} else { } else {
let child_pos = *cursor + child_move; let child_pos = region.cursor + child_move;
*cursor += cursor_change; region.cursor += cursor_change; // TODO: separate call
Rect::from_min_size(child_pos, child_size) Rect::from_min_size(child_pos, child_size)
} }
} }
@ -280,8 +356,11 @@ impl Layout {
/// ## Debug stuff /// ## Debug stuff
impl Layout { impl Layout {
/// Shows where the next widget is going to be placed /// Shows where the next widget is going to be placed
pub fn debug_paint_cursor(&self, cursor: Pos2, painter: &crate::Painter) { pub fn debug_paint_cursor(&self, region: &Region, painter: &crate::Painter) {
use crate::paint::*; use crate::paint::*;
let cursor = region.cursor;
let color = color::GREEN; let color = color::GREEN;
let stroke = Stroke::new(2.0, color); let stroke = Stroke::new(2.0, color);

View file

@ -22,41 +22,19 @@ pub struct Ui {
/// They are therefore only good for Id:s that has no state. /// They are therefore only good for Id:s that has no state.
next_auto_id: u64, next_auto_id: u64,
/// Specifies paint layer, clip rectangle and a reference to `Context`.
painter: Painter, painter: Painter,
/// This is the minimal size of the `Ui`. /// The `Style` (visuals, spacing, etc) of this ui.
/// When adding new widgets, this will generally expand. /// Commonly many `Ui`:s share the same `Style`.
/// /// The `Ui` implements copy-on-write for this.
/// Always finite.
///
/// The bounding box of all child widgets, but not necessarily a tight bounding box
/// since `Ui` can start with a non-zero min_rect size.
min_rect: Rect,
/// The maximum size of this `Ui`. This is a *soft max*
/// meaning new widgets will *try* not to expand beyond it,
/// but if they have to, they will.
///
/// 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
style: Arc<Style>, style: Arc<Style>,
/// The strategy for where to put the next widget.
layout: Layout, layout: Layout,
/// Where the next widget will be put. /// Sizes/bounds and cursor used by `Layout`.
/// Progresses along self.dir. region: Region,
/// Initially set to rect.min
/// 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 min_rect.
cursor: Pos2, // TODO: move into Layout?
} }
impl Ui { impl Ui {
@ -72,36 +50,28 @@ impl Ui {
) -> Self { ) -> Self {
let style = ctx.style(); let style = ctx.style();
let layout = Layout::default(); let layout = Layout::default();
let cursor = layout.initial_cursor(max_rect); let region = layout.region_from_max_rect(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,
next_auto_id: id.with("auto").value(), next_auto_id: id.with("auto").value(),
painter: Painter::new(ctx, layer_id, clip_rect), painter: Painter::new(ctx, layer_id, clip_rect),
min_rect,
max_rect,
style, style,
layout, layout,
cursor, region,
} }
} }
pub fn child_ui(&mut self, max_rect: Rect, layout: Layout) -> Self { pub fn child_ui(&mut self, max_rect: Rect, layout: Layout) -> Self {
self.next_auto_id = self.next_auto_id.wrapping_add(1); self.next_auto_id = self.next_auto_id.wrapping_add(1);
let cursor = layout.initial_cursor(max_rect); let region = layout.region_from_max_rect(max_rect);
let min_size = Vec2::zero(); // TODO: From Style
let min_rect = layout.rect_from_cursor_size(cursor, min_size);
Ui { Ui {
id: self.id.with("child"), id: self.id.with("child"),
next_auto_id: Id::new(self.next_auto_id).with("child").value(), next_auto_id: Id::new(self.next_auto_id).with("child").value(),
painter: self.painter.clone(), painter: self.painter.clone(),
min_rect,
max_rect,
style: self.style.clone(), style: self.style.clone(),
layout, layout,
cursor, region,
} }
} }
@ -210,12 +180,12 @@ impl Ui {
/// ///
/// This will grow as new widgets are added, but never shrink. /// This will grow as new widgets are added, but never shrink.
pub fn min_rect(&self) -> Rect { pub fn min_rect(&self) -> Rect {
self.min_rect self.region.min_rect
} }
/// Size of content; same as `min_rect().size()` /// Size of content; same as `min_rect().size()`
pub fn min_size(&self) -> Vec2 { pub fn min_size(&self) -> Vec2 {
self.min_rect.size() self.min_rect().size()
} }
/// New widgets will *try* to fit within this rectangle. /// New widgets will *try* to fit within this rectangle.
@ -226,32 +196,19 @@ impl Ui {
/// If a new widget doesn't fit within the `max_rect` then the /// 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`. /// `Ui` will make room for it by expanding both `min_rect` and `max_rect`.
pub fn max_rect(&self) -> Rect { pub fn max_rect(&self) -> Rect {
self.max_rect self.region.max_rect
} }
/// Used for animation, kind of hacky /// Used for animation, kind of hacky
pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) { pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
self.min_rect = min_rect; self.region.min_rect = min_rect;
} }
/// This is like `max_rect()`, but will never be infinite. /// 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 `min_rect` instead. /// this will be bounded by `min_rect` instead.
pub fn max_rect_finite(&self) -> Rect { pub fn max_rect_finite(&self) -> Rect {
let mut result = self.max_rect; self.region.max_rect_finite()
if !result.min.x.is_finite() {
result.min.x = self.min_rect.min.x;
}
if !result.min.y.is_finite() {
result.min.y = self.min_rect.min.y;
}
if !result.max.x.is_finite() {
result.max.x = self.min_rect.max.x;
}
if !result.max.y.is_finite() {
result.max.y = self.min_rect.max.y;
}
result
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -267,11 +224,13 @@ impl Ui {
/// You won't be able to shrink it below the current minimum size. /// You won't be able to shrink it below the current minimum size.
pub fn set_max_width(&mut self, width: f32) { pub fn set_max_width(&mut self, width: f32) {
if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() { if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.x, self.max_rect.max.x); debug_assert_eq!(self.min_rect().max.x, self.max_rect().max.x);
self.max_rect.min.x = self.max_rect.max.x - width.at_least(self.min_rect.width()); self.region.max_rect.min.x =
self.region.max_rect.max.x - width.at_least(self.min_rect().width());
} else { } else {
debug_assert_eq!(self.min_rect.min.x, self.max_rect.min.x); debug_assert_eq!(self.min_rect().min.x, self.region.max_rect.min.x);
self.max_rect.max.x = self.max_rect.min.x + width.at_least(self.min_rect.width()); self.region.max_rect.max.x =
self.region.max_rect.min.x + width.at_least(self.min_rect().width());
} }
} }
@ -279,11 +238,13 @@ impl Ui {
/// You won't be able to shrink it below the current minimum size. /// You won't be able to shrink it below the current minimum size.
pub fn set_max_height(&mut self, height: f32) { pub fn set_max_height(&mut self, height: f32) {
if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() { if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.y, self.max_rect.max.y); debug_assert_eq!(self.min_rect().max.y, self.region.max_rect.max.y);
self.max_rect.min.y = self.max_rect.max.y - height.at_least(self.min_rect.height()); self.region.max_rect.min.y =
self.region.max_rect.max.y - height.at_least(self.min_rect().height());
} else { } else {
debug_assert_eq!(self.min_rect.min.y, self.max_rect.min.y); debug_assert_eq!(self.min_rect().min.y, self.region.max_rect.min.y);
self.max_rect.max.y = self.max_rect.min.y + height.at_least(self.min_rect.height()); self.region.max_rect.max.y =
self.region.max_rect.min.y + height.at_least(self.min_rect().height());
} }
} }
@ -300,26 +261,30 @@ impl Ui {
/// This can't shrink the ui, only make it larger. /// This can't shrink the ui, only make it larger.
pub fn set_min_width(&mut self, width: f32) { pub fn set_min_width(&mut self, width: f32) {
if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() { if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.x, self.max_rect.max.x); debug_assert_eq!(self.region.min_rect.max.x, self.region.max_rect.max.x);
self.min_rect.min.x = self.min_rect.min.x.min(self.min_rect.max.x - width); let min_rect = &mut self.region.min_rect;
min_rect.min.x = min_rect.min.x.min(min_rect.max.x - width);
} else { } else {
debug_assert_eq!(self.min_rect.min.x, self.max_rect.min.x); debug_assert_eq!(self.region.min_rect.min.x, self.region.max_rect.min.x);
self.min_rect.max.x = self.min_rect.max.x.max(self.min_rect.min.x + width); let min_rect = &mut self.region.min_rect;
min_rect.max.x = min_rect.max.x.max(min_rect.min.x + width);
} }
self.max_rect = self.max_rect.union(self.min_rect); self.region.max_rect = self.region.max_rect.union(self.min_rect());
} }
/// Set the minimum height of the ui. /// Set the minimum height of the ui.
/// This can't shrink the ui, only make it larger. /// This can't shrink the ui, only make it larger.
pub fn set_min_height(&mut self, height: f32) { pub fn set_min_height(&mut self, height: f32) {
if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() { if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() {
debug_assert_eq!(self.min_rect.max.y, self.max_rect.max.y); debug_assert_eq!(self.region.min_rect.max.y, self.region.max_rect.max.y);
self.min_rect.min.y = self.min_rect.min.y.min(self.min_rect.max.y - height); let min_rect = &mut self.region.min_rect;
min_rect.min.y = min_rect.min.y.min(min_rect.max.y - height);
} else { } else {
debug_assert_eq!(self.min_rect.min.y, self.max_rect.min.y); debug_assert_eq!(self.region.min_rect.min.y, self.region.max_rect.min.y);
self.min_rect.max.y = self.min_rect.max.y.max(self.min_rect.min.y + height); let min_rect = &mut self.region.min_rect;
min_rect.max.y = min_rect.max.y.max(min_rect.min.y + height);
} }
self.max_rect = self.max_rect.union(self.min_rect); self.region.max_rect = self.region.max_rect.union(self.min_rect());
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -339,8 +304,7 @@ impl Ui {
/// Expand the `min_rect` and `max_rect` of this ui to include a child at the given rect. /// 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) { pub fn expand_to_include_rect(&mut self, rect: Rect) {
self.min_rect = self.min_rect.union(rect); self.region.expand_to_include_rect(rect);
self.max_rect = self.max_rect.union(rect);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -353,14 +317,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.max_rect()) self.layout.available(&self.region)
} }
/// 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.max_rect_finite()) self.layout.available_finite(&self.region)
} }
} }
@ -417,7 +381,7 @@ impl Ui {
/// The direction is dependent on the layout. /// The direction is dependent on the layout.
/// This is useful for creating some extra space between widgets. /// This is useful for creating some extra space between widgets.
pub fn advance_cursor(&mut self, amount: f32) { pub fn advance_cursor(&mut self, amount: f32) {
self.layout.advance_cursor(&mut self.cursor, amount); self.layout.advance_cursor(&mut self.region, amount);
} }
/// Reserve this much space and move the cursor. /// Reserve this much space and move the cursor.
@ -438,7 +402,7 @@ impl Ui {
let too_wide = desired_size.x > original_size.x; let too_wide = desired_size.x > original_size.x;
let too_high = desired_size.y > original_size.y; let too_high = desired_size.y > original_size.y;
let rect = self.reserve_space_impl(desired_size); let rect = self.allocate_space_impl(desired_size);
let debug_expand_width = self.style().visuals.debug_expand_width; let debug_expand_width = self.style().visuals.debug_expand_width;
let debug_expand_height = self.style().visuals.debug_expand_height; let debug_expand_height = self.style().visuals.debug_expand_height;
@ -473,17 +437,27 @@ impl Ui {
/// Reserve this much space and move the cursor. /// Reserve this much space and move the cursor.
/// Returns where to put the widget. /// Returns where to put the widget.
fn reserve_space_impl(&mut self, child_size: Vec2) -> Rect { fn allocate_space_impl(&mut self, child_size: Vec2) -> Rect {
let available_size = self.available_finite().size();
let child_rect = self
.layout
.allocate_space(&mut self.cursor, available_size, child_size);
let item_spacing = self.style().spacing.item_spacing; let item_spacing = self.style().spacing.item_spacing;
self.layout.advance_cursor2(&mut self.cursor, item_spacing); let child_rect = self.layout.allocate_space(&mut self.region, child_size);
self.layout.advance_cursor2(&mut self.region, item_spacing);
self.expand_to_include_rect(child_rect); self.expand_to_include_rect(child_rect);
self.next_auto_id = self.next_auto_id.wrapping_add(1); self.next_auto_id = self.next_auto_id.wrapping_add(1);
child_rect child_rect
} }
/// Allocated the given space and then adds content to that space.
/// If the contents overflow, more space will be allocated.
/// At least the amount of space requested will always be allocated.
/// Thus you can ask for a little and use more, but you cannot ask for a lot and use less.
pub fn allocate_ui(&mut self, desired_size: Vec2, add_contents: impl FnOnce(&mut Ui)) -> Rect {
let child_rect = self.allocate_space(desired_size);
let mut child_ui = self.child_ui(child_rect, self.layout);
add_contents(&mut child_ui);
let final_rect = child_ui.region.max_rect;
self.expand_to_include_rect(final_rect);
final_rect
}
} }
/// # Adding widgets /// # Adding widgets
@ -705,7 +679,7 @@ impl Ui {
/// 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.region, 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.min_size()) self.allocate_space(child_ui.min_size())
@ -731,7 +705,8 @@ 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.max_rect.right_bottom()); // TODO: wrong for reversed layouts let child_rect =
Rect::from_min_max(self.region.cursor + indent, self.max_rect().right_bottom()); // TODO: wrong for reversed layouts
let mut child_ui = Self { let mut child_ui = Self {
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)
@ -773,7 +748,7 @@ impl Ui {
}; };
self.child_ui( self.child_ui(
Rect::from_min_size( Rect::from_min_size(
self.cursor + vec2(x, 0.0), self.region.cursor + vec2(x, 0.0),
vec2(width, self.available().height()), vec2(width, self.available().height()),
), ),
self.layout, self.layout,
@ -781,13 +756,13 @@ impl Ui {
} }
/// Start a ui with horizontal layout. /// Start a ui with horizontal layout.
/// After you have called this, the registers the contents as any other widget. /// After you have called this, the function registers the contents as any other widget.
/// ///
/// Elements will be centered on the Y axis, i.e. /// Elements will be centered on the Y axis, i.e.
/// adjusted up and down to lie in the center of the horizontal layout. /// adjusted up and down to lie in the center of the horizontal layout.
/// The initial height is `style.spacing.interact_size.y`. /// The initial height is `style.spacing.interact_size.y`.
/// Centering is almost always what you want if you are /// Centering is almost always what you want if you are
/// planning to to mix widgets or just different types of text. /// planning to to mix widgets or use different types of text.
/// ///
/// The returned `Response` will only have checked for mouse hover /// The returned `Response` will only have checked for mouse hover
/// but can be used for tooltips (`on_hover_text`). /// but can be used for tooltips (`on_hover_text`).
@ -820,7 +795,9 @@ impl Ui {
initial_size: Vec2, initial_size: Vec2,
add_contents: impl FnOnce(&mut Self) -> R, add_contents: impl FnOnce(&mut Self) -> R,
) -> (R, Response) { ) -> (R, Response) {
let child_rect = self.layout.rect_from_cursor_size(self.cursor, initial_size); let child_rect = self
.layout
.rect_from_cursor_size(&self.region, 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.min_size(); let size = child_ui.min_size();
@ -860,10 +837,11 @@ impl Ui {
let mut columns: Vec<Self> = (0..num_columns) let mut columns: Vec<Self> = (0..num_columns)
.map(|col_idx| { .map(|col_idx| {
let pos = self.cursor + vec2((col_idx as f32) * (column_width + spacing), 0.0); let pos =
self.region.cursor + vec2((col_idx as f32) * (column_width + spacing), 0.0);
let child_rect = Rect::from_min_max( let child_rect = Rect::from_min_max(
pos, pos,
pos2(pos.x + column_width, self.max_rect.right_bottom().y), pos2(pos.x + column_width, self.max_rect().right_bottom().y),
); );
self.child_ui(child_rect, self.layout) self.child_ui(child_rect, self.layout)
}) })
@ -873,7 +851,7 @@ 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.min_rect.width(); sum_width += column.min_rect().width();
} }
let mut max_height = 0.0; let mut max_height = 0.0;
@ -894,6 +872,6 @@ impl Ui {
impl Ui { impl Ui {
/// Shows where the next widget is going to be placed /// Shows where the next widget is going to be placed
pub fn debug_paint_cursor(&self) { pub fn debug_paint_cursor(&self) {
self.layout.debug_paint_cursor(self.cursor, &self.painter); self.layout.debug_paint_cursor(&self.region, &self.painter);
} }
} }