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:
Layout::default
: create a new layout with default valuesLayout::new
: create a new layout with a given direction and constraintsLayout::vertical
: create a new vertical layout with the given constraintsLayout::horizontal
: create a new horizontal layout with the given constraints
§Setters
There are several setters to modify the layout:
Layout::direction
: set the direction of the layoutLayout::constraints
: set the constraints of the layoutLayout::margin
: set the margin of the layoutLayout::horizontal_margin
: set the horizontal margin of the layoutLayout::vertical_margin
: set the vertical margin of the layoutLayout::flex
: set the way the space is distributed when the constraints are satisfiedLayout::spacing
: sets the gap between the constraints of 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.
Implementations§
Source§impl Layout
impl Layout
Sourcepub const DEFAULT_CACHE_SIZE: usize = 500usize
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()
.
Sourcepub fn new<I>(direction: Direction, constraints: I) -> Self
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:
margin
: 0, 0flex
:Flex::Start
spacing
: 0
§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]);
Sourcepub fn vertical<I>(constraints: I) -> Self
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)]);
Sourcepub fn horizontal<I>(constraints: I) -> Self
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)]);
Sourcepub fn init_cache(cache_size: NonZeroUsize)
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
.
Sourcepub const fn direction(self, direction: Direction) -> Self
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)]);
Sourcepub fn constraints<I>(self, constraints: I) -> Self
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]);
Sourcepub const fn margin(self, margin: u16) -> Self
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)]);
Sourcepub const fn horizontal_margin(self, horizontal: u16) -> Self
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)]);
Sourcepub const fn vertical_margin(self, vertical: u16) -> Self
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)]);
Sourcepub const fn flex(self, flex: Flex) -> Self
pub const fn flex(self, flex: Flex) -> Self
The flex
method allows you to specify the flex behavior of the layout.
§Arguments
flex
: AFlex
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);
Sourcepub fn spacing<T>(self, spacing: T) -> Self
pub fn spacing<T>(self, spacing: T) -> Self
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);
Sourcepub fn areas<const N: usize>(&self, area: Rect) -> [Rect; N]
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 Rect
s 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);
Sourcepub fn spacers<const N: usize>(&self, area: Rect) -> [Rect; N]
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);
Sourcepub fn split(&self, area: Rect) -> Rc<[Rect]>
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)]);
Sourcepub fn split_with_spacers(&self, area: Rect) -> (Rc<[Rect]>, Rc<[Rect]>)
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§
impl Eq for Layout
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> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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