Correctly align buttons and labels in justified layouts

This commit is contained in:
Emil Ernerfeldt 2020-12-06 13:12:34 +01:00
parent c520f2e9cc
commit a97141fe06
3 changed files with 44 additions and 12 deletions

View file

@ -335,14 +335,13 @@ impl LayoutDemo {
pub fn content_ui(&mut self, ui: &mut Ui) { pub fn content_ui(&mut self, ui: &mut Ui) {
// ui.label(format!("Available space: {:?}", ui.available().size())); // ui.label(format!("Available space: {:?}", ui.available().size()));
if ui.button("Reset").clicked { if ui.button("Default").clicked {
*self = Default::default(); *self = Default::default();
} }
ui.separator(); ui.separator();
ui.label("Direction:");
// TODO: enum iter
ui.label("Main Direction:");
for &dir in &[ for &dir in &[
Direction::LeftToRight, Direction::LeftToRight,
Direction::RightToLeft, Direction::RightToLeft,
@ -354,12 +353,14 @@ impl LayoutDemo {
ui.separator(); ui.separator();
ui.label("Align:"); ui.label("Cross Align:");
for &align in &[Align::Min, Align::Center, Align::Max] { for &align in &[Align::Min, Align::Center, Align::Max] {
ui.radio_value(&mut self.cross_align, align, format!("{:?}", align)); 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)"); .on_hover_text("Try to fill full width/height (e.g. buttons)");
} }
} }

View file

@ -216,6 +216,37 @@ impl Layout {
|| self.main_dir.is_vertical() && self.cross_align == Align::Max || 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 { fn initial_cursor(self, max_rect: Rect) -> Pos2 {
@ -303,6 +334,7 @@ impl Layout {
/// for justified layouts, like in menus. /// 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. /// 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 { pub fn next_space(self, region: &Region, minimum_child_size: Vec2) -> Rect {
let available_size = self.available_finite(region).size(); let available_size = self.available_finite(region).size();
let available_size = available_size.at_least(minimum_child_size); let available_size = available_size.at_least(minimum_child_size);

View file

@ -127,6 +127,7 @@ impl Widget for Label {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let galley = self.layout(ui); let galley = self.layout(ui);
let rect = ui.allocate_space(galley.size); 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); self.paint_galley(ui, rect.min, galley);
ui.interact_hover(rect) ui.interact_hover(rect)
} }
@ -314,11 +315,10 @@ impl Widget for Button {
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, sense); let response = ui.interact(rect, id, sense);
let visuals = ui.style().interact(&response); 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 = ui
let text_cursor = pos2( .layout()
response.rect.left() + button_padding.x, .align_size_within_rect(galley.size, response.rect.shrink2(button_padding))
response.rect.center().y - 0.5 * galley.size.y, .min;
); // left-centered
let fill = fill.unwrap_or(visuals.bg_fill); let fill = fill.unwrap_or(visuals.bg_fill);
ui.painter().rect( ui.painter().rect(
response.rect, response.rect,
@ -473,7 +473,6 @@ impl Widget for RadioButton {
desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size = desired_size.at_least(ui.style().spacing.interact_size);
desired_size.y = desired_size.y.max(icon_width); desired_size.y = desired_size.y.max(icon_width);
let rect = ui.allocate_space(desired_size); let rect = ui.allocate_space(desired_size);
let id = ui.make_position_id(); let id = ui.make_position_id();
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());