Refactor: move min_rect/max_rect/cursor into struct Region
This commit is contained in:
parent
6e8d5c87a0
commit
b0ba66b90d
3 changed files with 187 additions and 124 deletions
6
TODO.md
6
TODO.md
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
176
egui/src/ui.rs
176
egui/src/ui.rs
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue