diff --git a/emigui/src/containers/collapsing_header.rs b/emigui/src/containers/collapsing_header.rs index 87d1e63d..ba5c5003 100644 --- a/emigui/src/containers/collapsing_header.rs +++ b/emigui/src/containers/collapsing_header.rs @@ -54,14 +54,14 @@ impl CollapsingHeader { default_open, } = 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 id = ui.make_unique_id(title); let text_pos = ui.cursor() + vec2(ui.style().indent, 0.0); let (title, text_size) = label.layout(text_pos, ui); 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( vec2( diff --git a/emigui/src/ui.rs b/emigui/src/ui.rs index 839870c4..6bb6b95a 100644 --- a/emigui/src/ui.rs +++ b/emigui/src/ui.rs @@ -28,6 +28,8 @@ pub struct Ui { /// The widgets will TRY to fit within the rect, /// 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. + /// 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 ? /// Bounding box of all children. @@ -161,11 +163,24 @@ impl 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 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 { // If a child doesn't fit in desired_rect, we have effectively expanded: 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. /// The size is the maximum of the origional (minimum/desired) size and /// the size of the containted children. @@ -216,20 +231,31 @@ impl Ui { // ------------------------------------------------------------------------ // 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 { 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 { self.available_space().y } /// This how much more space we can take up without overflowing our parent. /// 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 { 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 { self.dir } diff --git a/emigui/src/widgets.rs b/emigui/src/widgets.rs index ecf79b58..75ae03de 100644 --- a/emigui/src/widgets.rs +++ b/emigui/src/widgets.rs @@ -23,6 +23,7 @@ pub struct Label { // TODO: not pub pub(crate) text: String, pub(crate) multiline: bool, + auto_shrink: bool, pub(crate) text_style: TextStyle, // TODO: Option, where None means "use the default for the ui" pub(crate) text_color: Option, } @@ -32,6 +33,7 @@ impl Label { Self { text: text.into(), multiline: true, + auto_shrink: false, text_style: TextStyle::Body, text_color: None, } @@ -46,6 +48,13 @@ impl Label { 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 { self.text_style = text_style; self @@ -58,7 +67,13 @@ impl Label { pub fn layout(&self, pos: Pos2, ui: &Ui) -> (Vec, Vec2) { 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 { font.layout_multiline(&self.text, max_width) } else { @@ -389,7 +404,8 @@ impl Separator { impl Widget for Separator { 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 (points, interact) = match ui.direction() { Direction::Horizontal => {