1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-03 15:20:05 -04:00

Add Align2 helpers (#8485)

Add utilities to make it easier to construct and use `Align2`

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lucas Meurer
2026-09-03 15:55:33 +02:00
committed by GitHub
parent 1a9d2af9ef
commit 2b34fe0c1c
7 changed files with 130 additions and 32 deletions

View File

@@ -345,9 +345,7 @@ impl<'a> AtomLayout<'a> {
let mut shrink_item = None; let mut shrink_item = None;
let align2 = align2.unwrap_or_else(|| { let align2 = align2.unwrap_or_else(|| ui.layout().align2());
Align2([ui.layout().horizontal_align(), ui.layout().vertical_align()])
});
if atoms.len() > 1 { if atoms.len() > 1 {
let gap_space = gap * (atoms.len() as f32 - 1.0); let gap_space = gap * (atoms.len() as f32 - 1.0);

View File

@@ -348,8 +348,8 @@ impl Layout {
} }
/// e.g. for when aligning text within a button. /// e.g. for when aligning text within a button.
fn align2(&self) -> Align2 { pub fn align2(&self) -> Align2 {
Align2([self.horizontal_align(), self.vertical_align()]) Align2::new(self.horizontal_align(), self.vertical_align())
} }
pub fn horizontal_justify(&self) -> bool { pub fn horizontal_justify(&self) -> bool {
@@ -614,10 +614,10 @@ impl Layout {
} }
let align2 = match self.main_dir { let align2 = match self.main_dir {
Direction::LeftToRight => Align2([Align::LEFT, self.vertical_align()]), Direction::LeftToRight => self.align2().with_x(Align::LEFT),
Direction::RightToLeft => Align2([Align::RIGHT, self.vertical_align()]), Direction::RightToLeft => self.align2().with_x(Align::RIGHT),
Direction::TopDown => Align2([self.horizontal_align(), Align::TOP]), Direction::TopDown => self.align2().with_y(Align::TOP),
Direction::BottomUp => Align2([self.horizontal_align(), Align::BOTTOM]), Direction::BottomUp => self.align2().with_y(Align::BOTTOM),
}; };
let mut frame_rect = align2.align_size_within_rect(frame_size, available_rect); let mut frame_rect = align2.align_size_within_rect(frame_size, available_rect);
@@ -818,22 +818,22 @@ impl Layout {
Direction::LeftToRight => { Direction::LeftToRight => {
painter.line_segment([cursor.left_top(), cursor.left_bottom()], stroke); painter.line_segment([cursor.left_top(), cursor.left_bottom()], stroke);
painter.arrow(next_pos, vec2(l, 0.0), stroke); painter.arrow(next_pos, vec2(l, 0.0), stroke);
Align2([Align::LEFT, self.vertical_align()]) self.align2().with_x(Align::LEFT)
} }
Direction::RightToLeft => { Direction::RightToLeft => {
painter.line_segment([cursor.right_top(), cursor.right_bottom()], stroke); painter.line_segment([cursor.right_top(), cursor.right_bottom()], stroke);
painter.arrow(next_pos, vec2(-l, 0.0), stroke); painter.arrow(next_pos, vec2(-l, 0.0), stroke);
Align2([Align::RIGHT, self.vertical_align()]) self.align2().with_x(Align::RIGHT)
} }
Direction::TopDown => { Direction::TopDown => {
painter.line_segment([cursor.left_top(), cursor.right_top()], stroke); painter.line_segment([cursor.left_top(), cursor.right_top()], stroke);
painter.arrow(next_pos, vec2(0.0, l), stroke); painter.arrow(next_pos, vec2(0.0, l), stroke);
Align2([self.horizontal_align(), Align::TOP]) self.align2().with_y(Align::TOP)
} }
Direction::BottomUp => { Direction::BottomUp => {
painter.line_segment([cursor.left_bottom(), cursor.right_bottom()], stroke); painter.line_segment([cursor.left_bottom(), cursor.right_bottom()], stroke);
painter.arrow(next_pos, vec2(0.0, -l), stroke); painter.arrow(next_pos, vec2(0.0, -l), stroke);
Align2([self.horizontal_align(), Align::BOTTOM]) self.align2().with_y(Align::BOTTOM)
} }
}; };

View File

@@ -860,7 +860,7 @@ impl Slider<'_> {
SliderOrientation::Horizontal => rect.x_range().shrink(handle_radius), SliderOrientation::Horizontal => rect.x_range().shrink(handle_radius),
// The vertical case has to be flipped because the largest slider value maps to the // The vertical case has to be flipped because the largest slider value maps to the
// lowest y value (which is at the top) // lowest y value (which is at the top)
SliderOrientation::Vertical => rect.y_range().shrink(handle_radius).flip(), SliderOrientation::Vertical => rect.y_range().shrink(handle_radius).flipped(),
} }
} }

View File

@@ -75,10 +75,10 @@ impl crate::View for TextEditDemo {
let output = egui::TextEdit::multiline(text) let output = egui::TextEdit::multiline(text)
.hint_text("Type something!") .hint_text("Type something!")
// Atoms are centered by default, so we need to pass the right align here: // Atoms are centered by default, so we need to pass the right align here:
.prefix("🔎".atom_align(Align2([Align::LEFT, *valign]))) .prefix("🔎".atom_align(Align2::new(Align::LEFT, *valign)))
.suffix( .suffix(
egui::Atom::custom(clear_id, clear_size) egui::Atom::custom(clear_id, clear_size)
.atom_align(Align2([Align::RIGHT, *valign])), .atom_align(Align2::new(Align::RIGHT, *valign)),
) )
.horizontal_align(*halign) .horizontal_align(*halign)
.vertical_align(*valign) .vertical_align(*valign)

View File

@@ -52,7 +52,8 @@ impl Align {
/// Returns the inverse alignment. /// Returns the inverse alignment.
/// `Min` becomes `Max`, `Center` stays the same, `Max` becomes `Min`. /// `Min` becomes `Max`, `Center` stays the same, `Max` becomes `Min`.
pub fn flip(self) -> Self { #[must_use]
pub fn flipped(self) -> Self {
match self { match self {
Self::Min => Self::Max, Self::Min => Self::Max,
Self::Center => Self::Center, Self::Center => Self::Center,
@@ -60,6 +61,14 @@ impl Align {
} }
} }
/// Returns the inverse alignment.
/// `Min` becomes `Max`, `Center` stays the same, `Max` becomes `Min`.
#[must_use]
#[deprecated = "Renamed to `flipped`"]
pub fn flip(self) -> Self {
self.flipped()
}
/// Returns a range of given size within a specified range. /// Returns a range of given size within a specified range.
/// ///
/// If the requested `size` is bigger than the size of `range`, then the returned /// If the requested `size` is bigger than the size of `range`, then the returned
@@ -163,6 +172,37 @@ impl Align2 {
} }
impl Align2 { impl Align2 {
#[inline(always)]
pub fn new(x: Align, y: Align) -> Self {
Self([x, y])
}
/// Set align on the horizontal axis.
#[inline]
pub fn with_x(mut self, x: Align) -> Self {
self.set_x(x);
self
}
/// Set align on the vertical axis.
#[inline]
pub fn with_y(mut self, y: Align) -> Self {
self.set_y(y);
self
}
/// Set align on the horizontal axis.
#[inline(always)]
pub fn set_x(&mut self, x: Align) {
self.0[0] = x;
}
/// Set align on the vertical axis.
#[inline(always)]
pub fn set_y(&mut self, y: Align) {
self.0[1] = y;
}
/// Returns an alignment by the X (horizontal) axis /// Returns an alignment by the X (horizontal) axis
#[inline(always)] #[inline(always)]
pub fn x(self) -> Align { pub fn x(self) -> Align {
@@ -182,20 +222,47 @@ impl Align2 {
/// Flip on the x-axis /// Flip on the x-axis
/// e.g. `TOP_LEFT` -> `TOP_RIGHT` /// e.g. `TOP_LEFT` -> `TOP_RIGHT`
#[must_use]
pub fn flipped_x(self) -> Self {
self.with_x(self.x().flipped())
}
/// Flip on the x-axis
/// e.g. `TOP_LEFT` -> `TOP_RIGHT`
#[must_use]
#[deprecated = "Renamed to `flipped_x`"]
pub fn flip_x(self) -> Self { pub fn flip_x(self) -> Self {
Self([self.x().flip(), self.y()]) self.flipped_x()
} }
/// Flip on the y-axis /// Flip on the y-axis
/// e.g. `TOP_LEFT` -> `BOTTOM_LEFT` /// e.g. `TOP_LEFT` -> `BOTTOM_LEFT`
#[must_use]
pub fn flipped_y(self) -> Self {
self.with_y(self.y().flipped())
}
/// Flip on the y-axis
/// e.g. `TOP_LEFT` -> `BOTTOM_LEFT`
#[must_use]
#[deprecated = "Renamed to `flipped_y`"]
pub fn flip_y(self) -> Self { pub fn flip_y(self) -> Self {
Self([self.x(), self.y().flip()]) self.flipped_y()
} }
/// Flip on both axes /// Flip on both axes
/// e.g. `TOP_LEFT` -> `BOTTOM_RIGHT` /// e.g. `TOP_LEFT` -> `BOTTOM_RIGHT`
#[must_use]
pub fn flipped(self) -> Self {
Self::new(self.x().flipped(), self.y().flipped())
}
/// Flip on both axes
/// e.g. `TOP_LEFT` -> `BOTTOM_RIGHT`
#[must_use]
#[deprecated = "Renamed to `flipped`"]
pub fn flip(self) -> Self { pub fn flip(self) -> Self {
Self([self.x().flip(), self.y().flip()]) self.flipped()
} }
/// Used e.g. to anchor a piece of text to a part of the rectangle. /// Used e.g. to anchor a piece of text to a part of the rectangle.

View File

@@ -102,13 +102,21 @@ impl Rangef {
/// Flip the min and the max /// Flip the min and the max
#[inline] #[inline]
#[must_use] #[must_use]
pub fn flip(self) -> Self { pub fn flipped(self) -> Self {
Self { Self {
min: self.max, min: self.max,
max: self.min, max: self.min,
} }
} }
/// Flip the min and the max
#[inline]
#[must_use]
#[deprecated = "Renamed to `flipped`"]
pub fn flip(self) -> Self {
self.flipped()
}
/// The overlap of two ranges, i.e. the range that is contained by both. /// The overlap of two ranges, i.e. the range that is contained by both.
/// ///
/// If the ranges do not overlap, returns a range with `span() < 0.0`. /// If the ranges do not overlap, returns a range with `span() < 0.0`.

View File

@@ -161,7 +161,7 @@ impl RectAlign {
pub fn outside(align: Align2) -> Self { pub fn outside(align: Align2) -> Self {
Self { Self {
parent: align, parent: align,
child: align.flip(), child: align.flipped(),
} }
} }
@@ -206,33 +206,58 @@ impl RectAlign {
} }
/// Flip the alignment on the x-axis. /// Flip the alignment on the x-axis.
pub fn flip_x(self) -> Self { #[must_use]
pub fn flipped_x(self) -> Self {
Self { Self {
parent: self.parent.flip_x(), parent: self.parent.flipped_x(),
child: self.child.flip_x(), child: self.child.flipped_x(),
}
}
/// Flip the alignment on the x-axis.
#[must_use]
#[deprecated = "Renamed to `flipped_x`"]
pub fn flip_x(self) -> Self {
self.flipped_x()
}
/// Flip the alignment on the y-axis.
#[must_use]
pub fn flipped_y(self) -> Self {
Self {
parent: self.parent.flipped_y(),
child: self.child.flipped_y(),
} }
} }
/// Flip the alignment on the y-axis. /// Flip the alignment on the y-axis.
#[must_use]
#[deprecated = "Renamed to `flipped_y`"]
pub fn flip_y(self) -> Self { pub fn flip_y(self) -> Self {
self.flipped_y()
}
/// Flip the alignment on both axes.
#[must_use]
pub fn flipped(self) -> Self {
Self { Self {
parent: self.parent.flip_y(), parent: self.parent.flipped(),
child: self.child.flip_y(), child: self.child.flipped(),
} }
} }
/// Flip the alignment on both axes. /// Flip the alignment on both axes.
#[must_use]
#[deprecated = "Renamed to `flipped`"]
pub fn flip(self) -> Self { pub fn flip(self) -> Self {
Self { self.flipped()
parent: self.parent.flip(),
child: self.child.flip(),
}
} }
/// Returns the 3 alternative [`RectAlign`]s that are flipped in various ways, for use /// Returns the 3 alternative [`RectAlign`]s that are flipped in various ways, for use
/// with [`RectAlign::find_best_align`]. /// with [`RectAlign::find_best_align`].
#[must_use]
pub fn symmetries(self) -> [Self; 3] { pub fn symmetries(self) -> [Self; 3] {
[self.flip_x(), self.flip_y(), self.flip()] [self.flipped_x(), self.flipped_y(), self.flipped()]
} }
/// Look for the first alternative [`RectAlign`] that allows the child rect to fit /// Look for the first alternative [`RectAlign`] that allows the child rect to fit