Ui: clean up min_rect/max_rect related functions

This commit is contained in:
Emil Ernerfeldt 2020-10-08 22:24:27 +02:00
parent ba98ea715f
commit 3f345b5963
5 changed files with 90 additions and 71 deletions

View file

@ -81,14 +81,13 @@ impl State {
clip_rect.max.y = clip_rect.max.y.min(child_ui.max_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 left_top = child_ui.left_top();
let r = add_contents(child_ui); let r = add_contents(child_ui);
self.open_height = Some(child_ui.min_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 min_rect = child_ui.min_rect(); let mut min_rect = child_ui.min_rect();
min_rect.max.y = min_rect.max.y.min(left_top.y + max_height); min_rect.max.y = min_rect.max.y.min(min_rect.top() + max_height);
child_ui.force_set_min_rect(min_rect); child_ui.force_set_min_rect(min_rect);
r r
})) }))

View file

@ -261,7 +261,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.left_top(), state.desired_size); let rect = Rect::from_min_size(content_ui.min_rect().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,
@ -283,12 +283,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.left_top(), state.desired_size), Rect::from_min_size(content_ui.min_rect().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.left_top(), state.last_content_size), Rect::from_min_size(content_ui.min_rect().left_top(), state.last_content_size),
color::LIGHT_BLUE, color::LIGHT_BLUE,
"last_content_size", "last_content_size",
); );

View file

@ -643,7 +643,7 @@ fn show_title_bar(
), ),
Vec2::splat(button_size), Vec2::splat(button_size),
); );
ui.expand_to_include_child(close_rect); ui.expand_to_include_rect(close_rect);
} }
TitleBar { TitleBar {
@ -724,7 +724,7 @@ impl TitleBar {
fn close_button(ui: &mut Ui, rect: Rect) -> Response { fn close_button(ui: &mut Ui, rect: Rect) -> Response {
let close_id = ui.make_child_id("window_close_button"); let close_id = ui.make_child_id("window_close_button");
let response = ui.interact(rect, close_id, Sense::click()); let response = ui.interact(rect, close_id, Sense::click());
ui.expand_to_include_child(response.rect); ui.expand_to_include_rect(response.rect);
let stroke = ui.style().interact(&response).fg_stroke; let stroke = ui.style().interact(&response).fg_stroke;
ui.painter() ui.painter()

View file

@ -30,7 +30,11 @@ 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.left_top()); let pos = ui
.input()
.mouse
.pos
.unwrap_or_else(|| ui.min_rect().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.x_range(), 0.0..=tex_w); let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h); let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);

View file

@ -179,28 +179,24 @@ impl Ui {
/// ## Sizes etc /// ## Sizes etc
impl Ui { impl Ui {
/// Screen-space position of this Ui. /// The current size of this Ui.
/// This may have moved from its original if a child overflowed to the left or up (rare). /// Bounding box of all contained child widgets.
pub fn left_top(&self) -> Pos2 { /// No matter what, the final Ui will be at least this large.
// If a child doesn't fit in max_rect, we have effectively expanded: /// This will grow as new widgets are added, but never shrink.
self.max_rect.min
}
/// 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 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".
pub fn right_bottom(&self) -> Pos2 {
// If a child doesn't fit in max_rect, we have effectively expanded:
self.max_rect.max
}
/// Bounding box of all contained children
pub fn min_rect(&self) -> Rect { pub fn min_rect(&self) -> Rect {
self.min_rect self.min_rect
} }
/// Size of content; same as `min_rect().size()`
pub fn min_size(&self) -> Vec2 {
self.min_rect.size()
}
/// This is the soft max size of the Ui. /// This is the soft max size of the Ui.
/// New widgets will *try* to fit within this rectangle.
/// For instance, text will wrap to fit within it.
/// If a widget doesn't fit within the `max_rect` then it will expand.
/// `max_rect()` is always at least as large as `min_rect()`.
pub fn max_rect(&self) -> Rect { pub fn max_rect(&self) -> Rect {
self.max_rect self.max_rect
} }
@ -214,91 +210,111 @@ impl Ui {
/// 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 right_bottom = self.min_rect.max; let mut result = self.max_rect;
if self.max_rect.max.x.is_finite() { if !result.min.x.is_finite() {
right_bottom.x = right_bottom.x.max(self.max_rect.max.x); result.min.x = self.min_rect.min.x;
} }
if self.max_rect.max.y.is_finite() { if !result.min.y.is_finite() {
right_bottom.y = right_bottom.y.max(self.max_rect.max.y); 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
} }
Rect::from_min_max(self.left_top(), right_bottom) // ------------------------------------------------------------------------
/// 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 width of the ui. /// Set the maximum 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 below the current minimum size.
pub fn set_max_width(&mut self, width: f32) { pub fn set_max_width(&mut self, width: f32) {
let min_width = self.min_rect.max.x - self.left_top().x; if self.layout.dir() == Direction::Horizontal && self.layout.is_reversed() {
let width = width.at_least(min_width); debug_assert_eq!(self.min_rect.max.x, self.max_rect.max.x);
self.max_rect.max.x = self.left_top().x + width; self.max_rect.min.x = self.max_rect.max.x - width.at_least(self.min_rect.width());
} else {
debug_assert_eq!(self.min_rect.min.x, self.max_rect.min.x);
self.max_rect.max.x = self.max_rect.min.x + width.at_least(self.min_rect.width());
}
} }
/// Set the height of the ui. /// Set the maximum 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 below the current minimum size.
pub fn set_max_height(&mut self, height: f32) { pub fn set_max_height(&mut self, height: f32) {
let min_height = self.min_rect.max.y - self.left_top().y; if self.layout.dir() == Direction::Vertical && self.layout.is_reversed() {
let height = height.at_least(min_height); debug_assert_eq!(self.min_rect.max.y, self.max_rect.max.y);
self.max_rect.max.y = self.left_top().y + height; self.max_rect.min.y = self.max_rect.max.y - height.at_least(self.min_rect.height());
} else {
debug_assert_eq!(self.min_rect.min.y, self.max_rect.min.y);
self.max_rect.max.y = self.max_rect.min.y + height.at_least(self.min_rect.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) { pub fn set_min_size(&mut self, size: Vec2) {
self.set_min_width(size.x); self.set_min_width(size.x);
self.set_min_height(size.y); 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) { 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.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.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 { } else {
debug_assert_eq!(self.min_rect.min.x, self.max_rect.min.x); 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.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);
} }
self.max_rect = self.max_rect.union(self.min_rect);
} }
/// 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) { 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.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.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 { } else {
debug_assert_eq!(self.min_rect.min.y, self.max_rect.min.y); 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.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);
} }
self.max_rect = self.max_rect.union(self.min_rect);
} }
/// Helper: shrinks the max/desired width to the current width, // ------------------------------------------------------------------------
/// Helper: shrinks the max 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_max_width(self.min_rect().width()) self.set_max_width(self.min_rect().width())
} }
/// Helper: shrinks the max/desired height to the current height, /// Helper: shrinks the max 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_min_height(self.min_rect().height()) self.set_max_height(self.min_rect().height())
} }
/// Size of content /// Expand the `min_rect` and `max_rect` of this ui to include a child at the given rect.
pub fn min_size(&self) -> Vec2 { pub fn expand_to_include_rect(&mut self, rect: Rect) {
self.min_rect.size()
}
/// 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) {
self.min_rect = self.min_rect.union(rect); self.min_rect = self.min_rect.union(rect);
self.max_rect = self.max_rect.union(rect); self.max_rect = self.max_rect.union(rect);
} }
pub fn expand_to_size(&mut self, size: Vec2) {
self.min_rect.extend_with(self.left_top() + size);
self.max_rect.extend_with(self.left_top() + size);
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Layout related measures: // Layout related measures:
@ -318,13 +334,6 @@ impl Ui {
pub fn available_finite(&self) -> Rect { pub fn available_finite(&self) -> Rect {
self.layout.available(self.cursor, self.max_rect_finite()) self.layout.available(self.cursor, self.max_rect_finite())
} }
// ------------------------------------------------------------------------
pub fn contains_mouse(&self, rect: Rect) -> bool {
self.ctx()
.contains_mouse(self.layer(), self.clip_rect(), rect)
}
} }
/// # `Id` creation /// # `Id` creation
@ -393,6 +402,11 @@ impl Ui {
self.interact_hover(rect).hovered self.interact_hover(rect).hovered
} }
pub fn contains_mouse(&self, rect: Rect) -> bool {
self.ctx()
.contains_mouse(self.layer(), self.clip_rect(), rect)
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Stuff that moves the cursor, i.e. allocates space in this ui! // Stuff that moves the cursor, i.e. allocates space in this ui!
@ -664,7 +678,7 @@ 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.right_bottom()); // TODO: wrong for reversed layouts let child_rect = Rect::from_min_max(self.cursor + indent, self.max_rect.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)
@ -788,8 +802,10 @@ 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.cursor + vec2((col_idx as f32) * (column_width + spacing), 0.0);
let child_rect = let child_rect = Rect::from_min_max(
Rect::from_min_max(pos, pos2(pos.x + column_width, self.right_bottom().y)); pos,
pos2(pos.x + column_width, self.max_rect.right_bottom().y),
);
Self { Self {
id: self.make_child_id(&("column", col_idx)), id: self.make_child_id(&("column", col_idx)),