diff --git a/egui/src/grid.rs b/egui/src/grid.rs index 13d5e7ba..3b4c224d 100644 --- a/egui/src/grid.rs +++ b/egui/src/grid.rs @@ -100,6 +100,15 @@ impl GridLayout { Rect::from_min_size(cursor, size) } + pub(crate) fn align_size_within_rect(&self, size: Vec2, frame: Rect) -> Rect { + // TODO: allow this alignment to be customized + Align2::LEFT_CENTER.align_size_within_rect(size, frame) + } + + pub(crate) fn justify_or_align(&self, frame: Rect, size: Vec2) -> Rect { + self.align_size_within_rect(size, frame) + } + pub(crate) fn advance(&mut self, cursor: &mut Pos2, frame_rect: Rect, widget_rect: Rect) { self.curr_state .set_min_col_width(self.col, widget_rect.width()); @@ -145,6 +154,10 @@ impl GridLayout { /// A simple `Grid` layout. /// +/// The contents of each cell be aligned to the left and center. +/// If you want to add multiple widgets to a cell you need to group them with +/// [`Ui::horizontal`], [`Ui::vertical`] etc. +/// /// ``` /// # let ui = &mut egui::Ui::__test(); /// egui::Grid::new("some_unique_id").show(ui, |ui| { @@ -196,7 +209,11 @@ impl Grid { min_row_height, } = self; - ui.wrap(|ui| { + // Each grid cell is aligned LEFT_CENTER. + // If somebody wants to wrap more things inside a cell, + // then we should pick a default layout that matches that alignment, + // which we do here: + ui.horizontal(|ui| { let id = ui.make_persistent_id(id_source); let grid = GridLayout { striped, diff --git a/egui/src/layout.rs b/egui/src/layout.rs index 4a024a4b..9c2e3f45 100644 --- a/egui/src/layout.rs +++ b/egui/src/layout.rs @@ -432,16 +432,27 @@ impl Layout { /// Apply justify or alignment after calling `next_space`. pub(crate) fn justify_or_align(&self, rect: Rect, mut child_size: Vec2) -> Rect { - if self.main_dir.is_horizontal() { - if self.cross_justify { + if self.cross_justify { + if self.main_dir.is_horizontal() { child_size.y = rect.height(); // fill full height - } - Align2([Align::Center, self.cross_align]).align_size_within_rect(child_size, rect) - } else { - if self.cross_justify { + } else { child_size.x = rect.width(); // fill full width } - Align2([self.cross_align, Align::Center]).align_size_within_rect(child_size, rect) + } + + match self.main_dir { + Direction::LeftToRight => { + Align2([Align::Min, self.cross_align]).align_size_within_rect(child_size, rect) + } + Direction::RightToLeft => { + Align2([Align::Max, self.cross_align]).align_size_within_rect(child_size, rect) + } + Direction::TopDown => { + Align2([self.cross_align, Align::Min]).align_size_within_rect(child_size, rect) + } + Direction::BottomUp => { + Align2([self.cross_align, Align::Max]).align_size_within_rect(child_size, rect) + } } } diff --git a/egui/src/placer.rs b/egui/src/placer.rs index e7edca6b..54194feb 100644 --- a/egui/src/placer.rs +++ b/egui/src/placer.rs @@ -58,7 +58,11 @@ impl Placer { impl Placer { pub(crate) fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect { - self.layout.align_size_within_rect(size, outer) + if let Some(grid) = &self.grid { + grid.align_size_within_rect(size, outer) + } else { + self.layout.align_size_within_rect(size, outer) + } } pub(crate) fn available_rect_before_wrap(&self) -> Rect { @@ -102,7 +106,11 @@ impl Placer { /// Apply justify or alignment after calling `next_space`. pub(crate) fn justify_or_align(&self, rect: Rect, child_size: Vec2) -> Rect { - self.layout.justify_or_align(rect, child_size) + if let Some(grid) = &self.grid { + grid.justify_or_align(rect, child_size) + } else { + self.layout.justify_or_align(rect, child_size) + } } /// Advance the cursor by this many points. @@ -115,7 +123,7 @@ impl Placer { } /// Advance cursor after a widget was added to a specific rectangle - /// and expand the region min_rect. + /// and expand the region `min_rect`. /// /// * `frame_rect`: the frame inside which a widget was e.g. centered /// * `widget_rect`: the actual rect used by the widget diff --git a/egui/src/widgets/separator.rs b/egui/src/widgets/separator.rs index 53507c9a..9e3605be 100644 --- a/egui/src/widgets/separator.rs +++ b/egui/src/widgets/separator.rs @@ -4,11 +4,15 @@ use crate::*; #[must_use = "You should put this widget in an ui with `ui.add(widget);`"] pub struct Separator { spacing: f32, + is_horizontal_line: Option, } impl Separator { pub fn new() -> Self { - Self { spacing: 6.0 } + Self { + spacing: 6.0, + is_horizontal_line: None, + } } /// How much space we take up. The line is painted in the middle of this. @@ -16,31 +20,53 @@ impl Separator { self.spacing = spacing; self } + + /// Explicitly ask for a horizontal line. + /// By default you will get a horizontal line in vertical layouts, + /// and a vertical line in horizontal layouts. + pub fn horizontal(mut self) -> Self { + self.is_horizontal_line = Some(true); + self + } + + /// Explicitly ask for a vertical line. + /// By default you will get a horizontal line in vertical layouts, + /// and a vertical line in horizontal layouts. + pub fn vertical(mut self) -> Self { + self.is_horizontal_line = Some(false); + self + } } impl Widget for Separator { fn ui(self, ui: &mut Ui) -> Response { - let Separator { spacing } = self; + let Separator { + spacing, + is_horizontal_line, + } = self; + + let is_horizontal_line = + is_horizontal_line.unwrap_or_else(|| !ui.layout().main_dir().is_horizontal()); let available_space = ui.available_size_before_wrap_finite(); - let size = if ui.layout().main_dir().is_horizontal() { - vec2(spacing, available_space.y) - } else { + let size = if is_horizontal_line { vec2(available_space.x, spacing) + } else { + vec2(spacing, available_space.y) }; let (rect, response) = ui.allocate_at_least(size, Sense::hover()); - let points = if ui.layout().main_dir().is_horizontal() { - [ - pos2(rect.center().x, rect.top()), - pos2(rect.center().x, rect.bottom()), - ] - } else { + let points = if is_horizontal_line { [ pos2(rect.left(), rect.center().y), pos2(rect.right(), rect.center().y), ] + } else { + [ + pos2(rect.center().x, rect.top()), + pos2(rect.center().x, rect.bottom()), + ] }; let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke; ui.painter().line_segment(points, stroke); diff --git a/egui_demo_lib/src/apps/demo/widget_gallery.rs b/egui_demo_lib/src/apps/demo/widget_gallery.rs index f4b2e230..b3ab79ac 100644 --- a/egui_demo_lib/src/apps/demo/widget_gallery.rs +++ b/egui_demo_lib/src/apps/demo/widget_gallery.rs @@ -131,7 +131,9 @@ impl super::View for WidgetGallery { ui.end_row(); ui.label("Separator:"); - ui.separator(); + // Putting a separator in a grid is kind of meaningless since there is no well-defined direction. + // Normally you'd just do ui.separator(), but here we need to explicitly pick a dimension: + ui.add(egui::Separator::new().horizontal()); ui.end_row(); ui.label("CollapsingHeader:");