From e20e3baa98db0228771f7ea6f3f76fdd409b33df Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 21 Mar 2021 14:31:55 +0100 Subject: [PATCH] Bug-fixes related to recent layout rewrite --- egui/src/layout.rs | 52 ++++++++++++++++++++++++++++----------- egui/src/widgets/label.rs | 34 ++++++++++++++----------- epaint/src/text/galley.rs | 6 +++++ 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/egui/src/layout.rs b/egui/src/layout.rs index e93f9279..b6a276c4 100644 --- a/egui/src/layout.rs +++ b/egui/src/layout.rs @@ -395,26 +395,49 @@ impl Layout { /// Given the cursor in the region, how much space is available /// for the next widget? - fn available_from_cursor_max_rect(&self, cursor: Rect, mut max_rect: Rect) -> Rect { + fn available_from_cursor_max_rect(&self, cursor: Rect, max_rect: Rect) -> Rect { // NOTE: in normal top-down layout the cursor has moved below the current max_rect, // but the available shouldn't be negative. + // ALSO: with wrapping layouts, cursor jumps to new row before expanding max_rect + + let mut avail = max_rect; + match self.main_dir { Direction::LeftToRight => { - max_rect.max.x = max_rect.max.x.max(cursor.min.x); + avail.min.x = cursor.min.x; + avail.max.x = avail.max.x.max(cursor.min.x); + if self.main_wrap { + avail.min.y = cursor.min.y; + avail.max.y = cursor.max.y; + } } Direction::RightToLeft => { - max_rect.min.x = max_rect.min.x.min(cursor.max.x); + avail.max.x = cursor.max.x; + avail.min.x = avail.min.x.min(cursor.max.x); + if self.main_wrap { + avail.min.y = cursor.min.y; + avail.max.y = cursor.max.y; + } } Direction::TopDown => { - max_rect.max.y = max_rect.max.y.max(cursor.min.y); + avail.min.y = cursor.min.y; + avail.max.y = avail.max.y.max(cursor.min.y); + if self.main_wrap { + avail.min.x = cursor.min.x; + avail.max.x = cursor.max.x; + } } Direction::BottomUp => { - max_rect.min.y = max_rect.min.y.min(cursor.max.y); + avail.min.y = avail.min.y.min(cursor.max.y); + if self.main_wrap { + avail.min.x = cursor.min.x; + avail.max.x = cursor.max.x; + } } } - max_rect.intersect(cursor) + avail } /// Returns where to put the next widget that is of the given size. @@ -438,9 +461,11 @@ impl Layout { if available_size.x < child_size.x && max_rect.left() < cursor.left() { // New row let new_row_height = cursor.height().max(child_size.y); + // let new_top = cursor.bottom() + spacing.y; + let new_top = min_rect.bottom() + spacing.y; // tighter packing cursor = Rect::from_min_max( - pos2(max_rect.left(), cursor.bottom() + spacing.y), - pos2(INFINITY, cursor.bottom() + spacing.y + new_row_height), + pos2(max_rect.left(), new_top), + pos2(INFINITY, new_top + new_row_height), ); max_rect.max.y = max_rect.max.y.max(cursor.max.y); } @@ -449,12 +474,11 @@ impl Layout { if available_size.x < child_size.x && cursor.right() < max_rect.right() { // New row let new_row_height = cursor.height().max(child_size.y); + // let new_top = cursor.bottom() + spacing.y; + let new_top = min_rect.bottom() + spacing.y; // tighter packing cursor = Rect::from_min_max( - pos2(-INFINITY, cursor.bottom() + spacing.y), - pos2( - max_rect.right(), - cursor.bottom() + spacing.y + new_row_height, - ), + pos2(-INFINITY, new_top), + pos2(max_rect.right(), new_top + new_row_height), ); max_rect.max.y = max_rect.max.y.max(cursor.max.y); } @@ -601,7 +625,7 @@ impl Layout { item_spacing: Vec2, ) { if self.main_wrap { - if cursor.intersects(frame_rect) { + if cursor.intersects(frame_rect.shrink(1.0)) { // make row/column larger if necessary *cursor = cursor.union(frame_rect); } else { diff --git a/egui/src/widgets/label.rs b/egui/src/widgets/label.rs index 27e83361..12662718 100644 --- a/egui/src/widgets/label.rs +++ b/egui/src/widgets/label.rs @@ -249,9 +249,10 @@ impl Widget for Label { && ui.layout().main_dir() == Direction::LeftToRight && ui.layout().main_wrap() { - // On a wrapping horizontal layout we want text to start after the last widget, + // On a wrapping horizontal layout we want text to start after the previous widget, // then continue on the line below! This will take some extra work: + let cursor = ui.cursor(); let max_width = ui.available_width(); let first_row_indentation = max_width - ui.available_size_before_wrap().x; @@ -263,25 +264,30 @@ impl Widget for Label { max_width, ); - let pos = pos2(ui.min_rect().left(), ui.cursor().top()); + let pos = pos2(ui.max_rect().left(), ui.cursor().top()); assert!(!galley.rows.is_empty(), "Galleys are never empty"); - let rect = galley.rows[0].rect().translate(vec2(pos.x, pos.y)); - let id = ui.advance_cursor_after_rect(rect); - let mut response = ui.interact(rect, id, sense); - let mut y_translation = 0.0; - if let Some(row) = galley.rows.get(1) { - // We could be sharing the first row with e.g. a button, that is higher than text. - // So we need to compensate for that: - if pos.y + row.y_min < ui.min_rect().bottom() { - y_translation = ui.min_rect().bottom() - row.y_min - pos.y; + // Center first row within the cursor: + let dy = 0.5 * (cursor.height() - galley.rows[0].height()); + galley.rows[0].translate_y(dy); + + // We could be sharing the first row with e.g. a button which is higher than text. + // So we need to compensate for that: + if let Some(row) = galley.rows.get_mut(1) { + if pos.y + row.y_min < cursor.bottom() { + let y_translation = cursor.bottom() - row.y_min - pos.y; + if y_translation != 0.0 { + for row in galley.rows.iter_mut().skip(1) { + row.translate_y(y_translation); + } + } } } - for row in galley.rows.iter_mut().skip(1) { - row.y_min += y_translation; - row.y_max += y_translation; + let rect = galley.rows[0].rect().translate(vec2(pos.x, pos.y)); + let mut response = ui.allocate_rect(rect, sense); + for row in galley.rows.iter().skip(1) { let rect = row.rect().translate(vec2(pos.x, pos.y)); response |= ui.allocate_rect(rect, sense); } diff --git a/epaint/src/text/galley.rs b/epaint/src/text/galley.rs index cd3f4b4a..14f0fd3a 100644 --- a/epaint/src/text/galley.rs +++ b/epaint/src/text/galley.rs @@ -115,6 +115,12 @@ impl Row { pub fn x_offset(&self, column: usize) -> f32 { self.x_offsets[column.min(self.x_offsets.len() - 1)] } + + // Move down this much + pub fn translate_y(&mut self, dy: f32) { + self.y_min += dy; + self.y_max += dy; + } } impl Galley {