ratatui::layout

Struct Layout

Source
pub struct Layout { /* private fields */ }
Expand description

A layout is a set of constraints that can be applied to a given area to split it into smaller ones.

A layout is composed of:

  • a direction (horizontal or vertical)
  • a set of constraints (length, ratio, percentage, fill, min, max)
  • a margin (horizontal and vertical), the space between the edge of the main area and the split areas
  • a flex option
  • a spacing option

The algorithm used to compute the layout is based on the cassowary-rs solver. It is a simple linear solver that can be used to solve linear equations and inequalities. In our case, we define a set of constraints that are applied to split the provided area into Rects aligned in a single direction, and the solver computes the values of the position and sizes that satisfy as many of the constraints in order of their priorities.

When the layout is computed, the result is cached in a thread-local cache, so that subsequent calls with the same parameters are faster. The cache is a LruCache, and the size of the cache can be configured using Layout::init_cache().

§Constructors

There are four ways to create a new layout:

§Setters

There are several setters to modify the layout:

§Example

use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    widgets::Paragraph,
    Frame,
};

fn render(frame: &mut Frame, area: Rect) {
    let layout = Layout::new(
        Direction::Vertical,
        [Constraint::Length(5), Constraint::Min(0)],
    )
    .split(Rect::new(0, 0, 10, 10));
    frame.render_widget(Paragraph::new("foo"), layout[0]);
    frame.render_widget(Paragraph::new("bar"), layout[1]);
}

See the layout, flex, and constraints examples in the Examples folder for more details about how to use layouts.

layout example

Implementations§

Source§

impl Layout

Source

pub const DEFAULT_CACHE_SIZE: usize = 500usize

This is a somewhat arbitrary size for the layout cache based on adding the columns and rows on my laptop’s terminal (171+51 = 222) and doubling it for good measure and then adding a bit more to make it a round number. This gives enough entries to store a layout for every row and every column, twice over, which should be enough for most apps. For those that need more, the cache size can be set with Layout::init_cache().

Source

pub fn new<I>(direction: Direction, constraints: I) -> Self

Creates a new layout with default values.

The constraints parameter accepts any type that implements IntoIterator<Item = Into<Constraint>>. This includes arrays, slices, vectors, iterators. Into<Constraint> is implemented on u16, so you can pass an array, Vec, etc. of u16 to this function to create a layout with fixed size chunks.

Default values for the other fields are:

§Examples
use ratatui::layout::{Constraint, Direction, Layout};

Layout::new(
    Direction::Horizontal,
    [Constraint::Length(5), Constraint::Min(0)],
);

Layout::new(
    Direction::Vertical,
    [1, 2, 3].iter().map(|&c| Constraint::Length(c)),
);

Layout::new(Direction::Horizontal, vec![1, 2]);
Source

pub fn vertical<I>(constraints: I) -> Self

Creates a new vertical layout with default values.

The constraints parameter accepts any type that implements IntoIterator<Item = Into<Constraint>>. This includes arrays, slices, vectors, iterators, etc.

§Examples
use ratatui::layout::{Constraint, Layout};

let layout = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
Source

pub fn horizontal<I>(constraints: I) -> Self

Creates a new horizontal layout with default values.

The constraints parameter accepts any type that implements IntoIterator<Item = Into<Constraint>>. This includes arrays, slices, vectors, iterators, etc.

§Examples
use ratatui::layout::{Constraint, Layout};

let layout = Layout::horizontal([Constraint::Length(5), Constraint::Min(0)]);
Source

pub fn init_cache(cache_size: NonZeroUsize)

Initialize an empty cache with a custom size. The cache is keyed on the layout and area, so that subsequent calls with the same parameters are faster. The cache is a LruCache, and grows until cache_size is reached.

By default, the cache size is Self::DEFAULT_CACHE_SIZE.

Source

pub const fn direction(self, direction: Direction) -> Self

Set the direction of the layout.

§Examples
use ratatui::layout::{Constraint, Direction, Layout, Rect};

let layout = Layout::default()
    .direction(Direction::Horizontal)
    .constraints([Constraint::Length(5), Constraint::Min(0)])
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(layout[..], [Rect::new(0, 0, 5, 10), Rect::new(5, 0, 5, 10)]);

let layout = Layout::default()
    .direction(Direction::Vertical)
    .constraints([Constraint::Length(5), Constraint::Min(0)])
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(layout[..], [Rect::new(0, 0, 10, 5), Rect::new(0, 5, 10, 5)]);
Source

pub fn constraints<I>(self, constraints: I) -> Self

Sets the constraints of the layout.

The constraints parameter accepts any type that implements IntoIterator<Item = Into<Constraint>>. This includes arrays, slices, vectors, iterators. Into<Constraint> is implemented on u16, so you can pass an array or vec of u16 to this function to create a layout with fixed size chunks.

Note that the constraints are applied to the whole area that is to be split, so using percentages and ratios with the other constraints may not have the desired effect of splitting the area up. (e.g. splitting 100 into [min 20, 50%, 50%], may not result in [20, 40, 40] but rather an indeterminate result between [20, 50, 30] and [20, 30, 50]).

§Examples
use ratatui::layout::{Constraint, Layout, Rect};

let layout = Layout::default()
    .constraints([
        Constraint::Percentage(20),
        Constraint::Ratio(1, 5),
        Constraint::Length(2),
        Constraint::Min(2),
        Constraint::Max(2),
    ])
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(
    layout[..],
    [
        Rect::new(0, 0, 10, 2),
        Rect::new(0, 2, 10, 2),
        Rect::new(0, 4, 10, 2),
        Rect::new(0, 6, 10, 2),
        Rect::new(0, 8, 10, 2),
    ]
);

Layout::default().constraints([Constraint::Min(0)]);
Layout::default().constraints(&[Constraint::Min(0)]);
Layout::default().constraints(vec![Constraint::Min(0)]);
Layout::default().constraints([Constraint::Min(0)].iter().filter(|_| true));
Layout::default().constraints([1, 2, 3].iter().map(|&c| Constraint::Length(c)));
Layout::default().constraints([1, 2, 3]);
Layout::default().constraints(vec![1, 2, 3]);
Source

pub const fn margin(self, margin: u16) -> Self

Set the margin of the layout.

§Examples
use ratatui::layout::{Constraint, Layout, Rect};

let layout = Layout::default()
    .constraints([Constraint::Min(0)])
    .margin(2)
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(layout[..], [Rect::new(2, 2, 6, 6)]);
Source

pub const fn horizontal_margin(self, horizontal: u16) -> Self

Set the horizontal margin of the layout.

§Examples
use ratatui::layout::{Constraint, Layout, Rect};

let layout = Layout::default()
    .constraints([Constraint::Min(0)])
    .horizontal_margin(2)
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(layout[..], [Rect::new(2, 0, 6, 10)]);
Source

pub const fn vertical_margin(self, vertical: u16) -> Self

Set the vertical margin of the layout.

§Examples
use ratatui::layout::{Constraint, Layout, Rect};

let layout = Layout::default()
    .constraints([Constraint::Min(0)])
    .vertical_margin(2)
    .split(Rect::new(0, 0, 10, 10));
assert_eq!(layout[..], [Rect::new(0, 2, 10, 6)]);
Source

pub const fn flex(self, flex: Flex) -> Self

The flex method allows you to specify the flex behavior of the layout.

§Arguments
  • flex: A Flex enum value that represents the flex behavior of the layout. It can be one of the following:
    • Flex::Legacy: The last item is stretched to fill the excess space.
    • Flex::Start: The items are aligned to the start of the layout.
    • Flex::Center: The items are aligned to the center of the layout.
    • Flex::End: The items are aligned to the end of the layout.
    • Flex::SpaceAround: The items are evenly distributed with equal space around them.
    • Flex::SpaceBetween: The items are evenly distributed with equal space between them.
§Examples

In this example, the items in the layout will be aligned to the start.

use ratatui::layout::{Constraint::*, Flex, Layout};

let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Start);

In this example, the items in the layout will be stretched equally to fill the available space.

use ratatui::layout::{Constraint::*, Flex, Layout};

let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Legacy);
Source

pub fn spacing<T>(self, spacing: T) -> Self
where T: Into<Spacing>,

Sets the spacing between items in the layout.

The spacing method sets the spacing between items in the layout. The spacing is applied evenly between all segments. The spacing value represents the number of cells between each item.

Spacing can be positive integers, representing gaps between segments; or negative integers representing overlaps. Additionally, one of the variants of the Spacing enum can be passed to this function. See the documentation of the Spacing enum for more information.

Note that if the layout has only one segment, the spacing will not be applied. Also, spacing will not be applied for Flex::SpaceAround and Flex::SpaceBetween

§Examples

In this example, the spacing between each item in the layout is set to 2 cells.

use ratatui::layout::{Constraint::*, Layout};

let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).spacing(2);

In this example, the spacing between each item in the layout is set to -1 cells, i.e. the three segments will have an overlapping border.

use ratatui::layout::{Constraint::*, Layout};
let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).spacing(-1);
Source

pub fn areas<const N: usize>(&self, area: Rect) -> [Rect; N]

Split the rect into a number of sub-rects according to the given Layout.

An ergonomic wrapper around Layout::split that returns an array of Rects instead of Rc<[Rect]>.

This method requires the number of constraints to be known at compile time. If you don’t know the number of constraints at compile time, use Layout::split instead.

§Panics

Panics if the number of constraints is not equal to the length of the returned array.

§Examples
use ratatui::{layout::{Layout, Constraint}, Frame};

let area = frame.area();
let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
let [top, main] = layout.areas(area);

// or explicitly specify the number of constraints:
let areas = layout.areas::<2>(area);
Source

pub fn spacers<const N: usize>(&self, area: Rect) -> [Rect; N]

Split the rect into a number of sub-rects according to the given Layout and return just the spacers between the areas.

This method requires the number of constraints to be known at compile time. If you don’t know the number of constraints at compile time, use Layout::split_with_spacers instead.

This method is similar to Layout::areas, and can be called with the same parameters, but it returns just the spacers between the areas. The result of calling the areas method is cached, so this will generally not re-run the solver, but will just return the cached result.

§Panics

Panics if the number of constraints + 1 is not equal to the length of the returned array.

§Examples
use ratatui::{layout::{Layout, Constraint}, Frame};

let area = frame.area();
let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
let [top, main] = layout.areas(area);
let [before, inbetween, after] = layout.spacers(area);

// or explicitly specify the number of constraints:
let spacers = layout.spacers::<2>(area);
Source

pub fn split(&self, area: Rect) -> Rc<[Rect]>

Wrapper function around the cassowary-rs solver to be able to split a given area into smaller ones based on the preferred widths or heights and the direction.

Note that the constraints are applied to the whole area that is to be split, so using percentages and ratios with the other constraints may not have the desired effect of splitting the area up. (e.g. splitting 100 into [min 20, 50%, 50%], may not result in [20, 40, 40] but rather an indeterminate result between [20, 50, 30] and [20, 30, 50]).

This method stores the result of the computation in a thread-local cache keyed on the layout and area, so that subsequent calls with the same parameters are faster. The cache is a LruCache, and grows until Self::DEFAULT_CACHE_SIZE is reached by default, if the cache is initialized with the Layout::init_cache() grows until the initialized cache size.

There is a helper method that can be used to split the whole area into smaller ones based on the layout: Layout::areas(). That method is a shortcut for calling this method. It allows you to destructure the result directly into variables, which is useful when you know at compile time the number of areas that will be created.

§Examples
use ratatui::layout::{Constraint, Direction, Layout, Rect};
let layout = Layout::default()
    .direction(Direction::Vertical)
    .constraints([Constraint::Length(5), Constraint::Min(0)])
    .split(Rect::new(2, 2, 10, 10));
assert_eq!(layout[..], [Rect::new(2, 2, 10, 5), Rect::new(2, 7, 10, 5)]);

let layout = Layout::default()
    .direction(Direction::Horizontal)
    .constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
    .split(Rect::new(0, 0, 9, 2));
assert_eq!(layout[..], [Rect::new(0, 0, 3, 2), Rect::new(3, 0, 6, 2)]);
Source

pub fn split_with_spacers(&self, area: Rect) -> (Rc<[Rect]>, Rc<[Rect]>)

Wrapper function around the cassowary-rs solver that splits the given area into smaller ones based on the preferred widths or heights and the direction, with the ability to include spacers between the areas.

This method is similar to split, but it returns two sets of rectangles: one for the areas and one for the spacers.

This method stores the result of the computation in a thread-local cache keyed on the layout and area, so that subsequent calls with the same parameters are faster. The cache is a LruCache, and grows until Self::DEFAULT_CACHE_SIZE is reached by default, if the cache is initialized with the Layout::init_cache() grows until the initialized cache size.

§Examples
use ratatui::layout::{Constraint, Direction, Layout, Rect};

let (areas, spacers) = Layout::default()
    .direction(Direction::Vertical)
    .constraints([Constraint::Length(5), Constraint::Min(0)])
    .split_with_spacers(Rect::new(2, 2, 10, 10));
assert_eq!(areas[..], [Rect::new(2, 2, 10, 5), Rect::new(2, 7, 10, 5)]);
assert_eq!(
    spacers[..],
    [
        Rect::new(2, 2, 10, 0),
        Rect::new(2, 7, 10, 0),
        Rect::new(2, 12, 10, 0)
    ]
);

let (areas, spacers) = Layout::default()
    .direction(Direction::Horizontal)
    .spacing(1)
    .constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
    .split_with_spacers(Rect::new(0, 0, 10, 2));
assert_eq!(areas[..], [Rect::new(0, 0, 3, 2), Rect::new(4, 0, 6, 2)]);
assert_eq!(
    spacers[..],
    [
        Rect::new(0, 0, 0, 2),
        Rect::new(3, 0, 1, 2),
        Rect::new(10, 0, 0, 2)
    ]
);

Trait Implementations§

Source§

impl Clone for Layout

Source§

fn clone(&self) -> Layout

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Layout

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Layout

Source§

fn default() -> Layout

Returns the “default value” for a type. Read more
Source§

impl Hash for Layout

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Layout

Source§

fn eq(&self, other: &Layout) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Layout

Source§

impl StructuralPartialEq for Layout

Auto Trait Implementations§

§

impl Freeze for Layout

§

impl RefUnwindSafe for Layout

§

impl Send for Layout

§

impl Sync for Layout

§

impl Unpin for Layout

§

impl UnwindSafe for Layout

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.