diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index b7075c10..160ea2bc 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -254,7 +254,14 @@ impl CollapsingHeader { header_response, mut state, } = self.begin(ui); - let ret_response = state.add_contents(ui, id, |ui| ui.indent(id, add_contents).0); + let ret_response = state.add_contents(ui, id, |ui| { + ui.indent(id, |ui| { + // make as wide as the header: + ui.expand_to_include_x(header_response.rect.right()); + add_contents(ui) + }) + .0 + }); ui.memory().collapsing_headers.insert(id, state); if let Some((ret, response)) = ret_response { diff --git a/egui/src/layout.rs b/egui/src/layout.rs index 9c2e3f45..70661cba 100644 --- a/egui/src/layout.rs +++ b/egui/src/layout.rs @@ -60,6 +60,16 @@ impl Region { self.min_rect = self.min_rect.union(rect); self.max_rect = self.max_rect.union(rect); } + + /// Ensure we are big enough to contain the given x-coordinate. + /// This is sometimes useful to expand an ui to stretch to a certain place. + pub fn expand_to_include_x(&mut self, x: f32) { + self.min_rect.min.x = self.min_rect.min.x.min(x); + self.min_rect.max.x = self.min_rect.max.x.max(x); + + self.max_rect.min.x = self.max_rect.min.x.min(x); + self.max_rect.max.x = self.max_rect.max.x.max(x); + } } // ---------------------------------------------------------------------------- diff --git a/egui/src/placer.rs b/egui/src/placer.rs index 8673f28b..d56a41f4 100644 --- a/egui/src/placer.rs +++ b/egui/src/placer.rs @@ -118,12 +118,16 @@ impl Placer { } /// Advance the cursor by this many points. + /// [`Self::min_rect`] will expand to contain the cursor. pub(crate) fn advance_cursor(&mut self, amount: f32) { debug_assert!( self.grid.is_none(), "You cannot advance the cursor when in a grid layout" ); - self.layout.advance_cursor(&mut self.region.cursor, amount) + self.layout.advance_cursor(&mut self.region.cursor, amount); + + self.region + .expand_to_include_rect(Rect::from_min_size(self.cursor(), Vec2::zero())); } /// Advance cursor after a widget was added to a specific rectangle @@ -167,6 +171,11 @@ impl Placer { self.region.expand_to_include_rect(rect); } + /// Expand the `min_rect` and `max_rect` of this ui to include a child at the given x-coordinate. + pub(crate) fn expand_to_include_x(&mut self, x: f32) { + self.region.expand_to_include_x(x); + } + /// Set the maximum width of the ui. /// You won't be able to shrink it below the current minimum size. pub(crate) fn set_max_width(&mut self, width: f32) { diff --git a/egui/src/ui.rs b/egui/src/ui.rs index 8bb8ea55..95eb46be 100644 --- a/egui/src/ui.rs +++ b/egui/src/ui.rs @@ -311,6 +311,12 @@ impl Ui { self.set_max_width(width); } + /// Ensure we are big enough to contain the given x-coordinate. + /// This is sometimes useful to expand an ui to stretch to a certain place. + pub fn expand_to_include_x(&mut self, x: f32) { + self.placer.expand_to_include_x(x); + } + // ------------------------------------------------------------------------ // Layout related measures: @@ -426,8 +432,11 @@ impl Ui { // Stuff that moves the cursor, i.e. allocates space in this ui! /// Advance the cursor (where the next widget is put) by this many points. + /// /// The direction is dependent on the layout. /// This is useful for creating some extra space between widgets. + /// + /// [`Self::min_rect`] will expand to contain the cursor. pub fn advance_cursor(&mut self, amount: f32) { self.placer.advance_cursor(amount); } @@ -965,16 +974,27 @@ impl Ui { ..self.child_ui(child_rect, *self.layout()) }; let ret = add_contents(&mut child_ui); + + let end_with_horizontal_line = true; + if end_with_horizontal_line { + child_ui.advance_cursor(4.0); + } + let size = child_ui.min_size(); - // draw a grey line on the left to mark the indented section - let line_start = child_rect.min - indent * 0.5; - let line_start = self.painter().round_pos_to_pixels(line_start); - let line_end = pos2(line_start.x, line_start.y + size.y - 2.0); - self.painter.line_segment( - [line_start, line_end], - self.visuals().widgets.noninteractive.bg_stroke, - ); + // draw a faint line on the left to mark the indented section + let stroke = self.visuals().widgets.noninteractive.bg_stroke; + let left_top = child_rect.min - indent * 0.5; + let left_top = self.painter().round_pos_to_pixels(left_top); + let left_bottom = pos2(left_top.x, left_top.y + size.y - 2.0); + let left_bottom = self.painter().round_pos_to_pixels(left_bottom); + self.painter.line_segment([left_top, left_bottom], stroke); + if end_with_horizontal_line { + let fudge = 2.0; // looks nicer with button rounding in collapsing headers + let right_bottom = pos2(child_ui.min_rect().right() - fudge, left_bottom.y); + self.painter + .line_segment([left_bottom, right_bottom], stroke); + } let response = self.allocate_response(indent + size, Sense::hover()); (ret, response)