From 08b08cc45b60274a48824d488127a014e083d95a Mon Sep 17 00:00:00 2001 From: Tatesa Uradnik Date: Mon, 28 Apr 2025 20:16:58 +0200 Subject: [PATCH] feat(rect): centering (#1814) Resolves #617 --- ratatui-core/src/layout/rect.rs | 94 +++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/ratatui-core/src/layout/rect.rs b/ratatui-core/src/layout/rect.rs index d572b3aa..cc8b22bd 100644 --- a/ratatui-core/src/layout/rect.rs +++ b/ratatui-core/src/layout/rect.rs @@ -7,6 +7,8 @@ use crate::layout::{Margin, Position, Size}; mod iter; pub use iter::*; +use super::{Constraint, Flex, Layout}; + /// A Rectangular area. /// /// A simple rectangle used in the computation of the layout and to give widgets a hint about the @@ -351,6 +353,70 @@ impl Rect { } } + /// Returns a new Rect, centered horizontally based on the provided constraint. + /// + /// # Examples + /// + /// ``` + /// use ratatui_core::layout::Constraint; + /// use ratatui_core::terminal::Frame; + /// + /// fn render(frame: &mut Frame) { + /// let area = frame.area().centered_horizontally(Constraint::Ratio(1, 2)); + /// } + /// ``` + #[must_use] + pub fn centered_horizontally(self, constraint: Constraint) -> Self { + let [area] = Layout::horizontal([constraint]) + .flex(Flex::Center) + .areas(self); + area + } + + /// Returns a new Rect, centered vertically based on the provided constraint. + /// + /// # Examples + /// + /// ``` + /// use ratatui_core::layout::Constraint; + /// use ratatui_core::terminal::Frame; + /// + /// fn render(frame: &mut Frame) { + /// let area = frame.area().centered_vertically(Constraint::Ratio(1, 2)); + /// } + /// ``` + #[must_use] + pub fn centered_vertically(self, constraint: Constraint) -> Self { + let [area] = Layout::vertical([constraint]) + .flex(Flex::Center) + .areas(self); + area + } + + /// Returns a new Rect, centered horizontally and vertically based on the provided constraints. + /// + /// # Examples + /// + /// ``` + /// use ratatui_core::layout::Constraint; + /// use ratatui_core::terminal::Frame; + /// + /// fn render(frame: &mut Frame) { + /// let area = frame + /// .area() + /// .centered(Constraint::Ratio(1, 2), Constraint::Ratio(1, 3)); + /// } + /// ``` + #[must_use] + pub fn centered( + self, + horizontal_constraint: Constraint, + vertical_constraint: Constraint, + ) -> Self { + self.centered_horizontally(horizontal_constraint) + .centered_vertically(vertical_constraint) + } + /// indents the x value of the `Rect` by a given `offset` /// /// This is pub(crate) for now as we need to stabilize the naming / design of this API. @@ -381,6 +447,7 @@ mod tests { use alloc::vec; use alloc::vec::Vec; + use pretty_assertions::assert_eq; use rstest::rstest; use super::*; @@ -662,4 +729,31 @@ mod tests { } ); } + + #[test] + fn centered_horizontally() { + let rect = Rect::new(0, 0, 5, 5); + assert_eq!( + rect.centered_horizontally(Constraint::Length(3)), + Rect::new(1, 0, 3, 5) + ); + } + + #[test] + fn centered_vertically() { + let rect = Rect::new(0, 0, 5, 5); + assert_eq!( + rect.centered_vertically(Constraint::Length(1)), + Rect::new(0, 2, 5, 1) + ); + } + + #[test] + fn centered() { + let rect = Rect::new(0, 0, 5, 5); + assert_eq!( + rect.centered(Constraint::Length(3), Constraint::Length(1)), + Rect::new(1, 2, 3, 1) + ); + } }