From a97141fe0683a62202ea9afe4eb3c3e64d744ada Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 6 Dec 2020 13:12:34 +0100 Subject: [PATCH] Correctly align buttons and labels in justified layouts --- egui/src/demos/demo_window.rs | 13 +++++++------ egui/src/layout.rs | 32 ++++++++++++++++++++++++++++++++ egui/src/widgets/mod.rs | 11 +++++------ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/egui/src/demos/demo_window.rs b/egui/src/demos/demo_window.rs index e2b2ddf6..74b088df 100644 --- a/egui/src/demos/demo_window.rs +++ b/egui/src/demos/demo_window.rs @@ -335,14 +335,13 @@ impl LayoutDemo { pub fn content_ui(&mut self, ui: &mut Ui) { // ui.label(format!("Available space: {:?}", ui.available().size())); - if ui.button("Reset").clicked { + if ui.button("Default").clicked { *self = Default::default(); } + ui.separator(); - ui.label("Direction:"); - - // TODO: enum iter + ui.label("Main Direction:"); for &dir in &[ Direction::LeftToRight, Direction::RightToLeft, @@ -354,12 +353,14 @@ impl LayoutDemo { ui.separator(); - ui.label("Align:"); + ui.label("Cross Align:"); for &align in &[Align::Min, Align::Center, Align::Max] { ui.radio_value(&mut self.cross_align, align, format!("{:?}", align)); } - ui.checkbox(&mut self.cross_justify, "Justified") + ui.separator(); + + ui.checkbox(&mut self.cross_justify, "Cross Justified") .on_hover_text("Try to fill full width/height (e.g. buttons)"); } } diff --git a/egui/src/layout.rs b/egui/src/layout.rs index f3f32c38..fab74bf4 100644 --- a/egui/src/layout.rs +++ b/egui/src/layout.rs @@ -216,6 +216,37 @@ impl Layout { || self.main_dir.is_vertical() && self.cross_align == Align::Max } + pub fn horizontal_align(self) -> Align { + match self.main_dir { + Direction::LeftToRight => Align::left(), + Direction::RightToLeft => Align::right(), + Direction::TopDown | Direction::BottomUp => self.cross_align, + } + } + + pub fn vertical_align(self) -> Align { + match self.main_dir { + Direction::TopDown => Align::top(), + Direction::BottomUp => Align::bottom(), + Direction::LeftToRight | Direction::RightToLeft => self.cross_align, + } + } + + pub fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect { + let x = match self.horizontal_align() { + Align::Min => outer.left(), + Align::Center => outer.center().x - size.x / 2.0, + Align::Max => outer.right() - size.x, + }; + let y = match self.vertical_align() { + Align::Min => outer.top(), + Align::Center => outer.center().y - size.y / 2.0, + Align::Max => outer.bottom() - size.y, + }; + + Rect::from_min_size(Pos2::new(x, y), size) + } + // ------------------------------------------------------------------------ fn initial_cursor(self, max_rect: Rect) -> Pos2 { @@ -303,6 +334,7 @@ impl Layout { /// for justified layouts, like in menus. /// /// You may get LESS space than you asked for if the current layout won't fit what you asked for. + #[allow(clippy::collapsible_if)] pub fn next_space(self, region: &Region, minimum_child_size: Vec2) -> Rect { let available_size = self.available_finite(region).size(); let available_size = available_size.at_least(minimum_child_size); diff --git a/egui/src/widgets/mod.rs b/egui/src/widgets/mod.rs index 04bd44b2..eba37003 100644 --- a/egui/src/widgets/mod.rs +++ b/egui/src/widgets/mod.rs @@ -127,6 +127,7 @@ impl Widget for Label { fn ui(self, ui: &mut Ui) -> Response { let galley = self.layout(ui); let rect = ui.allocate_space(galley.size); + let rect = ui.layout().align_size_within_rect(galley.size, rect); self.paint_galley(ui, rect.min, galley); ui.interact_hover(rect) } @@ -314,11 +315,10 @@ impl Widget for Button { let id = ui.make_position_id(); let response = ui.interact(rect, id, sense); let visuals = ui.style().interact(&response); - // let text_cursor = response.rect.center() - 0.5 * galley.size; // centered-centered (looks bad for justified drop-down menus - let text_cursor = pos2( - response.rect.left() + button_padding.x, - response.rect.center().y - 0.5 * galley.size.y, - ); // left-centered + let text_cursor = ui + .layout() + .align_size_within_rect(galley.size, response.rect.shrink2(button_padding)) + .min; let fill = fill.unwrap_or(visuals.bg_fill); ui.painter().rect( response.rect, @@ -473,7 +473,6 @@ impl Widget for RadioButton { desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size.y = desired_size.y.max(icon_width); let rect = ui.allocate_space(desired_size); - let id = ui.make_position_id(); let response = ui.interact(rect, id, Sense::click());