Better handling of full-width widgets inside of Ui:s with inf max size

This commit is contained in:
Emil Ernerfeldt 2020-05-10 18:59:18 +02:00
parent be6ada6923
commit 274acff47e
3 changed files with 46 additions and 4 deletions

View file

@ -54,14 +54,14 @@ impl CollapsingHeader {
default_open, default_open,
} = self; } = self;
// TODO: horizontal layout, with icon and text as labels. Inser background behind using Frame. // TODO: horizontal layout, with icon and text as labels. Insert background behind using Frame.
let title = &label.text; // TODO: not this let title = &label.text; // TODO: not this
let id = ui.make_unique_id(title); let id = ui.make_unique_id(title);
let text_pos = ui.cursor() + vec2(ui.style().indent, 0.0); let text_pos = ui.cursor() + vec2(ui.style().indent, 0.0);
let (title, text_size) = label.layout(text_pos, ui); let (title, text_size) = label.layout(text_pos, ui);
let text_max_x = text_pos.x + text_size.x; let text_max_x = text_pos.x + text_size.x;
let desired_width = ui.available_width().max(text_max_x - ui.cursor().x); let desired_width = ui.available_space_min().x.max(text_max_x - ui.cursor().x);
let interact = ui.reserve_space( let interact = ui.reserve_space(
vec2( vec2(

View file

@ -28,6 +28,8 @@ pub struct Ui {
/// The widgets will TRY to fit within the rect, /// The widgets will TRY to fit within the rect,
/// but may overflow (which you will see in child_bounds). /// 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. /// Some widgets (like separator lines) will try to fill the full desired width of the ui.
/// If the desired size is zero, it is a signal that child widgets should be as small as possible.
/// If the desired size is initie, it is a signal that child widgets should take up as much room as they want.
desired_rect: Rect, // TODO: rename as max_rect ? desired_rect: Rect, // TODO: rename as max_rect ?
/// Bounding box of all children. /// Bounding box of all children.
@ -161,11 +163,24 @@ impl Ui {
/// 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 inifnity if the desired rect is initinite,
/// which mappens when a parent widget says "be as big as you want to be".
pub fn bottom_right(&self) -> Pos2 { pub fn bottom_right(&self) -> Pos2 {
// If a child doesn't fit in desired_rect, we have effectively expanded: // If a child doesn't fit in desired_rect, we have effectively expanded:
self.desired_rect.max.max(self.child_bounds.max) self.desired_rect.max.max(self.child_bounds.max)
} }
pub fn finite_bottom_right(&self) -> Pos2 {
let mut bottom_right = self.child_bounds.max;
if self.desired_rect.max.x.is_finite() {
bottom_right.x = bottom_right.x.max(self.desired_rect.max.x);
}
if self.desired_rect.max.y.is_finite() {
bottom_right.y = bottom_right.y.max(self.desired_rect.max.y);
}
bottom_right
}
/// Position and current size of the ui. /// Position and current size of the ui.
/// The size is the maximum of the origional (minimum/desired) size and /// The size is the maximum of the origional (minimum/desired) size and
/// the size of the containted children. /// the size of the containted children.
@ -216,20 +231,31 @@ impl Ui {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Layout related measures: // Layout related measures:
/// A zero should be intepreted as "as little as possible".
/// An infinite value should be intereted as "as much as you want"
pub fn available_width(&self) -> f32 { pub fn available_width(&self) -> f32 {
self.available_space().x self.available_space().x
} }
/// A zero should be intepreted as "as little as possible".
/// An infinite value should be intereted as "as much as you want"
pub fn available_height(&self) -> f32 { pub fn available_height(&self) -> f32 {
self.available_space().y self.available_space().y
} }
/// This how much more space we can take up without overflowing our parent. /// This how much more space we can take up without overflowing our parent.
/// Shrinks as cursor increments. /// Shrinks as cursor increments.
/// A zero size should be intepreted as "as little as possible".
/// An infinite size should be intereted as "as much as you want"
pub fn available_space(&self) -> Vec2 { pub fn available_space(&self) -> Vec2 {
self.bottom_right() - self.cursor self.bottom_right() - self.cursor
} }
/// Use this for components that want to grow witout bounds.
pub fn available_space_min(&self) -> Vec2 {
self.finite_bottom_right() - self.cursor
}
pub fn direction(&self) -> Direction { pub fn direction(&self) -> Direction {
self.dir self.dir
} }

View file

@ -23,6 +23,7 @@ pub struct Label {
// TODO: not pub // TODO: not pub
pub(crate) text: String, pub(crate) text: String,
pub(crate) multiline: bool, pub(crate) multiline: bool,
auto_shrink: bool,
pub(crate) text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the ui" pub(crate) text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the ui"
pub(crate) text_color: Option<Color>, pub(crate) text_color: Option<Color>,
} }
@ -32,6 +33,7 @@ impl Label {
Self { Self {
text: text.into(), text: text.into(),
multiline: true, multiline: true,
auto_shrink: false,
text_style: TextStyle::Body, text_style: TextStyle::Body,
text_color: None, text_color: None,
} }
@ -46,6 +48,13 @@ impl Label {
self self
} }
/// If true, will word wrap to the width of the current child_bounds.
/// If false (defailt), will word wrap to the available width
pub fn auto_shrink(mut self) -> Self {
self.auto_shrink = true;
self
}
pub fn text_style(mut self, text_style: TextStyle) -> Self { pub fn text_style(mut self, text_style: TextStyle) -> Self {
self.text_style = text_style; self.text_style = text_style;
self self
@ -58,7 +67,13 @@ impl Label {
pub fn layout(&self, pos: Pos2, ui: &Ui) -> (Vec<font::TextFragment>, Vec2) { pub fn layout(&self, pos: Pos2, ui: &Ui) -> (Vec<font::TextFragment>, Vec2) {
let font = &ui.fonts()[self.text_style]; let font = &ui.fonts()[self.text_style];
let max_width = ui.rect().right() - pos.x;
let max_width = if self.auto_shrink {
ui.child_bounds().right() - pos.x
} else {
ui.rect().right() - pos.x
};
if self.multiline { if self.multiline {
font.layout_multiline(&self.text, max_width) font.layout_multiline(&self.text, max_width)
} else { } else {
@ -389,7 +404,8 @@ impl Separator {
impl Widget for Separator { impl Widget for Separator {
fn ui(self, ui: &mut Ui) -> GuiResponse { fn ui(self, ui: &mut Ui) -> GuiResponse {
let available_space = ui.available_space(); let available_space = ui.available_space_min();
let extra = self.extra; let extra = self.extra;
let (points, interact) = match ui.direction() { let (points, interact) = match ui.direction() {
Direction::Horizontal => { Direction::Horizontal => {