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 align2 = align2.unwrap_or_else(|| {
Align2([ui.layout().horizontal_align(), ui.layout().vertical_align()])
});
let align2 = align2.unwrap_or_else(|| ui.layout().align2());
if atoms.len() > 1 {
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.
fn align2(&self) -> Align2 {
Align2([self.horizontal_align(), self.vertical_align()])
pub fn align2(&self) -> Align2 {
Align2::new(self.horizontal_align(), self.vertical_align())
}
pub fn horizontal_justify(&self) -> bool {
@@ -614,10 +614,10 @@ impl Layout {
}
let align2 = match self.main_dir {
Direction::LeftToRight => Align2([Align::LEFT, self.vertical_align()]),
Direction::RightToLeft => Align2([Align::RIGHT, self.vertical_align()]),
Direction::TopDown => Align2([self.horizontal_align(), Align::TOP]),
Direction::BottomUp => Align2([self.horizontal_align(), Align::BOTTOM]),
Direction::LeftToRight => self.align2().with_x(Align::LEFT),
Direction::RightToLeft => self.align2().with_x(Align::RIGHT),
Direction::TopDown => self.align2().with_y(Align::TOP),
Direction::BottomUp => self.align2().with_y(Align::BOTTOM),
};
let mut frame_rect = align2.align_size_within_rect(frame_size, available_rect);
@@ -818,22 +818,22 @@ impl Layout {
Direction::LeftToRight => {
painter.line_segment([cursor.left_top(), cursor.left_bottom()], stroke);
painter.arrow(next_pos, vec2(l, 0.0), stroke);
Align2([Align::LEFT, self.vertical_align()])
self.align2().with_x(Align::LEFT)
}
Direction::RightToLeft => {
painter.line_segment([cursor.right_top(), cursor.right_bottom()], stroke);
painter.arrow(next_pos, vec2(-l, 0.0), stroke);
Align2([Align::RIGHT, self.vertical_align()])
self.align2().with_x(Align::RIGHT)
}
Direction::TopDown => {
painter.line_segment([cursor.left_top(), cursor.right_top()], stroke);
painter.arrow(next_pos, vec2(0.0, l), stroke);
Align2([self.horizontal_align(), Align::TOP])
self.align2().with_y(Align::TOP)
}
Direction::BottomUp => {
painter.line_segment([cursor.left_bottom(), cursor.right_bottom()], 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),
// The vertical case has to be flipped because the largest slider value maps to the
// 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)
.hint_text("Type something!")
// 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(
egui::Atom::custom(clear_id, clear_size)
.atom_align(Align2([Align::RIGHT, *valign])),
.atom_align(Align2::new(Align::RIGHT, *valign)),
)
.horizontal_align(*halign)
.vertical_align(*valign)

View File

@@ -52,7 +52,8 @@ impl Align {
/// Returns the inverse alignment.
/// `Min` becomes `Max`, `Center` stays the same, `Max` becomes `Min`.
pub fn flip(self) -> Self {
#[must_use]
pub fn flipped(self) -> Self {
match self {
Self::Min => Self::Max,
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.
///
/// If the requested `size` is bigger than the size of `range`, then the returned
@@ -163,6 +172,37 @@ 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
#[inline(always)]
pub fn x(self) -> Align {
@@ -182,20 +222,47 @@ impl Align2 {
/// Flip on the x-axis
/// 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 {
Self([self.x().flip(), self.y()])
self.flipped_x()
}
/// Flip on the y-axis
/// 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 {
Self([self.x(), self.y().flip()])
self.flipped_y()
}
/// Flip on both axes
/// 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 {
Self([self.x().flip(), self.y().flip()])
self.flipped()
}
/// 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
#[inline]
#[must_use]
pub fn flip(self) -> Self {
pub fn flipped(self) -> Self {
Self {
min: self.max,
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.
///
/// 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 {
Self {
parent: align,
child: align.flip(),
child: align.flipped(),
}
}
@@ -206,33 +206,58 @@ impl RectAlign {
}
/// Flip the alignment on the x-axis.
pub fn flip_x(self) -> Self {
#[must_use]
pub fn flipped_x(self) -> Self {
Self {
parent: self.parent.flip_x(),
child: self.child.flip_x(),
parent: self.parent.flipped_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.
#[must_use]
#[deprecated = "Renamed to `flipped_y`"]
pub fn flip_y(self) -> Self {
self.flipped_y()
}
/// Flip the alignment on both axes.
#[must_use]
pub fn flipped(self) -> Self {
Self {
parent: self.parent.flip_y(),
child: self.child.flip_y(),
parent: self.parent.flipped(),
child: self.child.flipped(),
}
}
/// Flip the alignment on both axes.
#[must_use]
#[deprecated = "Renamed to `flipped`"]
pub fn flip(self) -> Self {
Self {
parent: self.parent.flip(),
child: self.child.flip(),
}
self.flipped()
}
/// Returns the 3 alternative [`RectAlign`]s that are flipped in various ways, for use
/// with [`RectAlign::find_best_align`].
#[must_use]
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