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)]);
Examples found in repository?
examples/demo2/destroy.rs (line 138)
136
137
138
139
140
141
142
fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
    let vertical = Layout::vertical([height]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
More examples
Hide additional examples
examples/table.rs (line 204)
203
204
205
206
207
208
209
210
211
212
    fn draw(&mut self, frame: &mut Frame) {
        let vertical = &Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
        let rects = vertical.split(frame.area());

        self.set_colors();

        self.render_table(frame, rects[0]);
        self.render_scrollbar(frame, rects[0]);
        self.render_footer(frame, rects[1]);
    }
examples/async.rs (line 101)
100
101
102
103
104
105
106
    fn draw(&self, frame: &mut Frame) {
        let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
        let [title_area, body_area] = vertical.areas(frame.area());
        let title = Line::from("Ratatui async example").centered().bold();
        frame.render_widget(title, title_area);
        frame.render_widget(&self.pull_requests, body_area);
    }
examples/colors_rgb.rs (line 144)
142
143
144
145
146
147
148
149
150
151
    fn render(self, area: Rect, buf: &mut Buffer) {
        use Constraint::{Length, Min};
        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
        Text::from("colors_rgb example. Press q to quit")
            .centered()
            .render(title, buf);
        self.fps_widget.render(fps, buf);
        self.colors_widget.render(colors, buf);
    }
examples/barchart-grouped.rs (line 84)
82
83
84
85
86
87
88
89
90
    fn draw(&self, frame: &mut Frame) {
        use Constraint::{Fill, Length, Min};
        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
        let [title, top, bottom] = vertical.areas(frame.area());

        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
        frame.render_widget(self.vertical_revenue_barchart(), top);
        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
    }
examples/demo2/tabs/email.rs (line 76)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    fn render(self, area: Rect, buf: &mut Buffer) {
        RgbSwatch.render(area, buf);
        let area = area.inner(Margin {
            vertical: 1,
            horizontal: 2,
        });
        Clear.render(area, buf);
        let vertical = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
        let [inbox, email] = vertical.areas(area);
        render_inbox(self.row_index, inbox, buf);
        render_email(self.row_index, email, buf);
    }
}
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS.iter().map(|e| {
        let from = format!("{:width$}", e.from, width = from_width).into();
        ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
    });
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}

fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let theme = THEME.email;
    let email = EMAILS.get(selected_index);
    let block = Block::new()
        .style(theme.body)
        .padding(Padding::new(2, 2, 0, 0))
        .borders(Borders::TOP)
        .border_type(BorderType::Thick);
    let inner = block.inner(area);
    block.render(area, buf);
    if let Some(email) = email {
        let vertical = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
        let [headers_area, body_area] = vertical.areas(inner);
        let headers = vec![
            Line::from(vec![
                "From: ".set_style(theme.header),
                email.from.set_style(theme.header_value),
            ]),
            Line::from(vec![
                "Subject: ".set_style(theme.header),
                email.subject.set_style(theme.header_value),
            ]),
            "-".repeat(inner.width as usize).dim().into(),
        ];
        Paragraph::new(headers)
            .style(theme.body)
            .render(headers_area, buf);
        let body = email.body.lines().map(Line::from).collect_vec();
        Paragraph::new(body)
            .style(theme.body)
            .render(body_area, buf);
    } else {
        Paragraph::new("No email selected").render(inner, buf);
    }
}
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)]);
Examples found in repository?
examples/demo2/destroy.rs (line 137)
136
137
138
139
140
141
142
fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
    let vertical = Layout::vertical([height]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
More examples
Hide additional examples
examples/widget_impl.rs (line 194)
192
193
194
195
196
197
198
    fn render(self, area: Rect, buf: &mut Buffer) {
        let constraints = vec![Constraint::Length(4); self.squares.len()];
        let areas = Layout::horizontal(constraints).split(area);
        for (widget, area) in self.squares.iter().zip(areas.iter()) {
            widget.render_ref(*area, buf);
        }
    }
examples/demo2/tabs/about.rs (line 63)
61
62
63
64
65
66
67
    fn render(self, area: Rect, buf: &mut Buffer) {
        RgbSwatch.render(area, buf);
        let horizontal = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
        let [description, logo] = horizontal.areas(area);
        render_crate_description(description, buf);
        render_logo(self.row_index, logo, buf);
    }
examples/popup.rs (line 89)
87
88
89
90
91
92
93
fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
    let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
    let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
examples/colors_rgb.rs (line 145)
142
143
144
145
146
147
148
149
150
151
    fn render(self, area: Rect, buf: &mut Buffer) {
        use Constraint::{Length, Min};
        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
        Text::from("colors_rgb example. Press q to quit")
            .centered()
            .render(title, buf);
        self.fps_widget.render(fps, buf);
        self.colors_widget.render(colors, buf);
    }
examples/constraint-explorer.rs (line 350)
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
        let blocks = Layout::horizontal(constraints).split(area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
        }
    }

    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
        let [label_area, axis_area, blocks_area] =
            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);

        if label_area.height > 0 {
            format!("Flex::{flex:?}").bold().render(label_area, buf);
        }

        self.axis(area.width).render(axis_area, buf);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(flex)
            .spacing(self.spacing)
            .split_with_spacers(blocks_area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
        }

        for area in spacers.iter() {
            SpacerBlock.render(*area, buf);
        }
    }
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.

Examples found in repository?
examples/flex.rs (line 167)
161
162
163
164
165
166
167
168
169
170
171
172
173
174
    fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
        // increase the layout cache to account for the number of layout events. This ensures that
        // layout is not generally reprocessed on every frame (which would lead to possible janky
        // results when there are more than one possible solution to the requested layout). This
        // assumes the user changes spacing about a 100 times or so.
        let cache_size = EXAMPLE_DATA.len() * SelectedTab::iter().len() * 100;
        Layout::init_cache(NonZeroUsize::new(cache_size).unwrap());

        while self.is_running() {
            terminal.draw(|frame| frame.render_widget(self, frame.area()))?;
            self.handle_events()?;
        }
        Ok(())
    }
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)]);
Examples found in repository?
examples/inline.rs (line 237)
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
fn draw(frame: &mut Frame, downloads: &Downloads) {
    let area = frame.area();

    let block = Block::new().title(Line::from("Progress").centered());
    frame.render_widget(block, area);

    let vertical = Layout::vertical([Constraint::Length(2), Constraint::Length(4)]).margin(1);
    let horizontal = Layout::horizontal([Constraint::Percentage(20), Constraint::Percentage(80)]);
    let [progress_area, main] = vertical.areas(area);
    let [list_area, gauge_area] = horizontal.areas(main);

    // total progress
    let done = NUM_DOWNLOADS - downloads.pending.len() - downloads.in_progress.len();
    #[allow(clippy::cast_precision_loss)]
    let progress = LineGauge::default()
        .filled_style(Style::default().fg(Color::Blue))
        .label(format!("{done}/{NUM_DOWNLOADS}"))
        .ratio(done as f64 / NUM_DOWNLOADS as f64);
    frame.render_widget(progress, progress_area);

    // in progress downloads
    let items: Vec<ListItem> = downloads
        .in_progress
        .values()
        .map(|download| {
            ListItem::new(Line::from(vec![
                Span::raw(symbols::DOT),
                Span::styled(
                    format!(" download {:>2}", download.id),
                    Style::default()
                        .fg(Color::LightGreen)
                        .add_modifier(Modifier::BOLD),
                ),
                Span::raw(format!(
                    " ({}ms)",
                    download.started_at.elapsed().as_millis()
                )),
            ]))
        })
        .collect();
    let list = List::new(items);
    frame.render_widget(list, list_area);

    #[allow(clippy::cast_possible_truncation)]
    for (i, (_, download)) in downloads.in_progress.iter().enumerate() {
        let gauge = Gauge::default()
            .gauge_style(Style::default().fg(Color::Yellow))
            .ratio(download.progress / 100.0);
        if gauge_area.top().saturating_add(i as u16) > area.bottom() {
            continue;
        }
        frame.render_widget(
            gauge,
            Rect {
                x: gauge_area.left(),
                y: gauge_area.top().saturating_add(i as u16),
                width: gauge_area.width,
                height: 1,
            },
        );
    }
}
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);
Examples found in repository?
examples/demo2/destroy.rs (line 137)
136
137
138
139
140
141
142
fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
    let vertical = Layout::vertical([height]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
More examples
Hide additional examples
examples/popup.rs (line 88)
87
88
89
90
91
92
93
fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
    let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
    let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
examples/flex.rs (line 401)
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    fn render_examples(area: Rect, buf: &mut Buffer, flex: Flex, spacing: u16) {
        let heights = EXAMPLE_DATA
            .iter()
            .map(|(desc, _)| get_description_height(desc) + 4);
        let areas = Layout::vertical(heights).flex(Flex::Start).split(area);
        for (area, (description, constraints)) in areas.iter().zip(EXAMPLE_DATA.iter()) {
            Example::new(constraints, description, flex, spacing).render(*area, buf);
        }
    }
}

impl Example {
    fn new(constraints: &[Constraint], description: &str, flex: Flex, spacing: u16) -> Self {
        Self {
            constraints: constraints.into(),
            description: description.into(),
            flex,
            spacing,
        }
    }
}

impl Widget for Example {
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title_height = get_description_height(&self.description);
        let layout = Layout::vertical([Length(title_height), Fill(0)]);
        let [title, illustrations] = layout.areas(area);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(self.flex)
            .spacing(self.spacing)
            .split_with_spacers(illustrations);

        if !self.description.is_empty() {
            Paragraph::new(
                self.description
                    .split('\n')
                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
                    .map(Line::from)
                    .collect::<Vec<Line>>(),
            )
            .render(title, buf);
        }

        for (block, constraint) in blocks.iter().zip(&self.constraints) {
            Self::illustration(*constraint, block.width).render(*block, buf);
        }

        for spacer in spacers.iter() {
            Self::render_spacer(*spacer, buf);
        }
    }
examples/constraint-explorer.rs (line 369)
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
        let [label_area, axis_area, blocks_area] =
            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);

        if label_area.height > 0 {
            format!("Flex::{flex:?}").bold().render(label_area, buf);
        }

        self.axis(area.width).render(axis_area, buf);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(flex)
            .spacing(self.spacing)
            .split_with_spacers(blocks_area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
        }

        for area in spacers.iter() {
            SpacerBlock.render(*area, buf);
        }
    }
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);
Examples found in repository?
examples/barchart-grouped.rs (line 84)
82
83
84
85
86
87
88
89
90
    fn draw(&self, frame: &mut Frame) {
        use Constraint::{Fill, Length, Min};
        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
        let [title, top, bottom] = vertical.areas(frame.area());

        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
        frame.render_widget(self.vertical_revenue_barchart(), top);
        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
    }
More examples
Hide additional examples
examples/barchart.rs (line 73)
67
68
69
70
71
72
73
74
75
76
77
78
79
    fn draw(&self, frame: &mut Frame) {
        let [title, vertical, horizontal] = Layout::vertical([
            Constraint::Length(1),
            Constraint::Fill(1),
            Constraint::Fill(1),
        ])
        .spacing(1)
        .areas(frame.area());

        frame.render_widget("Barchart".bold().into_centered_line(), title);
        frame.render_widget(vertical_barchart(&self.temperatures), vertical);
        frame.render_widget(horizontal_barchart(&self.temperatures), horizontal);
    }
examples/constraint-explorer.rs (line 333)
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    fn render_layout_blocks(&self, area: Rect, buf: &mut Buffer) {
        let [user_constraints, area] = Layout::vertical([Length(3), Fill(1)])
            .spacing(1)
            .areas(area);

        self.render_user_constraints_legend(user_constraints, buf);

        let [start, center, end, space_around, space_between] =
            Layout::vertical([Length(7); 5]).areas(area);

        self.render_layout_block(Flex::Start, start, buf);
        self.render_layout_block(Flex::Center, center, buf);
        self.render_layout_block(Flex::End, end, buf);
        self.render_layout_block(Flex::SpaceAround, space_around, buf);
        self.render_layout_block(Flex::SpaceBetween, space_between, buf);
    }

    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
        let blocks = Layout::horizontal(constraints).split(area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
        }
    }

    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
        let [label_area, axis_area, blocks_area] =
            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);

        if label_area.height > 0 {
            format!("Flex::{flex:?}").bold().render(label_area, buf);
        }

        self.axis(area.width).render(axis_area, buf);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(flex)
            .spacing(self.spacing)
            .split_with_spacers(blocks_area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
        }

        for area in spacers.iter() {
            SpacerBlock.render(*area, buf);
        }
    }
examples/flex.rs (line 427)
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title_height = get_description_height(&self.description);
        let layout = Layout::vertical([Length(title_height), Fill(0)]);
        let [title, illustrations] = layout.areas(area);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(self.flex)
            .spacing(self.spacing)
            .split_with_spacers(illustrations);

        if !self.description.is_empty() {
            Paragraph::new(
                self.description
                    .split('\n')
                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
                    .map(Line::from)
                    .collect::<Vec<Line>>(),
            )
            .render(title, buf);
        }

        for (block, constraint) in blocks.iter().zip(&self.constraints) {
            Self::illustration(*constraint, block.width).render(*block, buf);
        }

        for spacer in spacers.iter() {
            Self::render_spacer(*spacer, buf);
        }
    }
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);
Examples found in repository?
examples/demo2/destroy.rs (line 139)
136
137
138
139
140
141
142
fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
    let vertical = Layout::vertical([height]).flex(Flex::Center);
    let [area] = vertical.areas(area);
    let [area] = horizontal.areas(area);
    area
}
More examples
Hide additional examples
examples/demo2/tabs/about.rs (line 64)
61
62
63
64
65
66
67
    fn render(self, area: Rect, buf: &mut Buffer) {
        RgbSwatch.render(area, buf);
        let horizontal = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
        let [description, logo] = horizontal.areas(area);
        render_crate_description(description, buf);
        render_logo(self.row_index, logo, buf);
    }
examples/async.rs (line 102)
100
101
102
103
104
105
106
    fn draw(&self, frame: &mut Frame) {
        let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
        let [title_area, body_area] = vertical.areas(frame.area());
        let title = Line::from("Ratatui async example").centered().bold();
        frame.render_widget(title, title_area);
        frame.render_widget(&self.pull_requests, body_area);
    }
examples/colors_rgb.rs (line 144)
142
143
144
145
146
147
148
149
150
151
    fn render(self, area: Rect, buf: &mut Buffer) {
        use Constraint::{Length, Min};
        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
        Text::from("colors_rgb example. Press q to quit")
            .centered()
            .render(title, buf);
        self.fps_widget.render(fps, buf);
        self.colors_widget.render(colors, buf);
    }
examples/barchart-grouped.rs (line 85)
82
83
84
85
86
87
88
89
90
    fn draw(&self, frame: &mut Frame) {
        use Constraint::{Fill, Length, Min};
        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
        let [title, top, bottom] = vertical.areas(frame.area());

        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
        frame.render_widget(self.vertical_revenue_barchart(), top);
        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
    }
examples/demo2/tabs/email.rs (line 77)
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    fn render(self, area: Rect, buf: &mut Buffer) {
        RgbSwatch.render(area, buf);
        let area = area.inner(Margin {
            vertical: 1,
            horizontal: 2,
        });
        Clear.render(area, buf);
        let vertical = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
        let [inbox, email] = vertical.areas(area);
        render_inbox(self.row_index, inbox, buf);
        render_email(self.row_index, email, buf);
    }
}
fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let [tabs, inbox] = vertical.areas(area);
    let theme = THEME.email;
    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
        .style(theme.tabs)
        .highlight_style(theme.tabs_selected)
        .select(0)
        .divider("")
        .render(tabs, buf);

    let highlight_symbol = ">>";
    let from_width = EMAILS
        .iter()
        .map(|e| e.from.width())
        .max()
        .unwrap_or_default();
    let items = EMAILS.iter().map(|e| {
        let from = format!("{:width$}", e.from, width = from_width).into();
        ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
    });
    let mut state = ListState::default().with_selected(Some(selected_index));
    StatefulWidget::render(
        List::new(items)
            .style(theme.inbox)
            .highlight_style(theme.selected_item)
            .highlight_symbol(highlight_symbol),
        inbox,
        buf,
        &mut state,
    );
    let mut scrollbar_state = ScrollbarState::default()
        .content_length(EMAILS.len())
        .position(selected_index);
    Scrollbar::default()
        .begin_symbol(None)
        .end_symbol(None)
        .track_symbol(None)
        .thumb_symbol("▐")
        .render(inbox, buf, &mut scrollbar_state);
}

fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
    let theme = THEME.email;
    let email = EMAILS.get(selected_index);
    let block = Block::new()
        .style(theme.body)
        .padding(Padding::new(2, 2, 0, 0))
        .borders(Borders::TOP)
        .border_type(BorderType::Thick);
    let inner = block.inner(area);
    block.render(area, buf);
    if let Some(email) = email {
        let vertical = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
        let [headers_area, body_area] = vertical.areas(inner);
        let headers = vec![
            Line::from(vec![
                "From: ".set_style(theme.header),
                email.from.set_style(theme.header_value),
            ]),
            Line::from(vec![
                "Subject: ".set_style(theme.header),
                email.subject.set_style(theme.header_value),
            ]),
            "-".repeat(inner.width as usize).dim().into(),
        ];
        Paragraph::new(headers)
            .style(theme.body)
            .render(headers_area, buf);
        let body = email.body.lines().map(Line::from).collect_vec();
        Paragraph::new(body)
            .style(theme.body)
            .render(body_area, buf);
    } else {
        Paragraph::new("No email selected").render(inner, buf);
    }
}
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)]);
Examples found in repository?
examples/widget_impl.rs (line 194)
192
193
194
195
196
197
198
    fn render(self, area: Rect, buf: &mut Buffer) {
        let constraints = vec![Constraint::Length(4); self.squares.len()];
        let areas = Layout::horizontal(constraints).split(area);
        for (widget, area) in self.squares.iter().zip(areas.iter()) {
            widget.render_ref(*area, buf);
        }
    }
More examples
Hide additional examples
examples/table.rs (line 205)
203
204
205
206
207
208
209
210
211
212
    fn draw(&mut self, frame: &mut Frame) {
        let vertical = &Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
        let rects = vertical.split(frame.area());

        self.set_colors();

        self.render_table(frame, rects[0]);
        self.render_scrollbar(frame, rects[0]);
        self.render_footer(frame, rects[1]);
    }
examples/flex.rs (line 401)
397
398
399
400
401
402
403
404
405
    fn render_examples(area: Rect, buf: &mut Buffer, flex: Flex, spacing: u16) {
        let heights = EXAMPLE_DATA
            .iter()
            .map(|(desc, _)| get_description_height(desc) + 4);
        let areas = Layout::vertical(heights).flex(Flex::Start).split(area);
        for (area, (description, constraints)) in areas.iter().zip(EXAMPLE_DATA.iter()) {
            Example::new(constraints, description, flex, spacing).render(*area, buf);
        }
    }
examples/constraint-explorer.rs (line 350)
348
349
350
351
352
353
354
355
356
    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
        let blocks = Layout::horizontal(constraints).split(area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
        }
    }
examples/block.rs (line 82)
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
    let main_layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
    let block_layout = Layout::vertical([Constraint::Max(4); 9]);
    let [title_area, main_area] = main_layout.areas(area);
    let main_areas = block_layout
        .split(main_area)
        .iter()
        .map(|&area| {
            Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
                .split(area)
                .to_vec()
        })
        .collect();
    (title_area, main_areas)
}
examples/calendar.rs (line 61)
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
fn draw(frame: &mut Frame) {
    let area = frame.area().inner(Margin {
        vertical: 1,
        horizontal: 1,
    });

    let mut start = OffsetDateTime::now_local()
        .unwrap()
        .date()
        .replace_month(Month::January)
        .unwrap()
        .replace_day(1)
        .unwrap();

    let list = make_dates(start.year());

    let rows = Layout::vertical([Constraint::Ratio(1, 3); 3]).split(area);
    let cols = rows.iter().flat_map(|row| {
        Layout::horizontal([Constraint::Ratio(1, 4); 4])
            .split(*row)
            .to_vec()
    });
    for col in cols {
        let cal = cals::get_cal(start.month(), start.year(), &list);
        frame.render_widget(cal, col);
        start = start.replace_month(start.month().next()).unwrap();
    }
}
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)
    ]
);
Examples found in repository?
examples/constraint-explorer.rs (line 371)
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
        let [label_area, axis_area, blocks_area] =
            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);

        if label_area.height > 0 {
            format!("Flex::{flex:?}").bold().render(label_area, buf);
        }

        self.axis(area.width).render(axis_area, buf);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(flex)
            .spacing(self.spacing)
            .split_with_spacers(blocks_area);

        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
            let selected = self.selected_index == i;
            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
        }

        for area in spacers.iter() {
            SpacerBlock.render(*area, buf);
        }
    }
More examples
Hide additional examples
examples/flex.rs (line 428)
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    fn render(self, area: Rect, buf: &mut Buffer) {
        let title_height = get_description_height(&self.description);
        let layout = Layout::vertical([Length(title_height), Fill(0)]);
        let [title, illustrations] = layout.areas(area);

        let (blocks, spacers) = Layout::horizontal(&self.constraints)
            .flex(self.flex)
            .spacing(self.spacing)
            .split_with_spacers(illustrations);

        if !self.description.is_empty() {
            Paragraph::new(
                self.description
                    .split('\n')
                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
                    .map(Line::from)
                    .collect::<Vec<Line>>(),
            )
            .render(title, buf);
        }

        for (block, constraint) in blocks.iter().zip(&self.constraints) {
            Self::illustration(*constraint, block.width).render(*block, buf);
        }

        for spacer in spacers.iter() {
            Self::render_spacer(*spacer, buf);
        }
    }

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<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where T: Real + Zero + Arithmetics + Clone, Swp: WhitePoint<T>, Dwp: WhitePoint<T>, D: AdaptFrom<S, Swp, Dwp, T>,

source§

fn adapt_into_using<M>(self, method: M) -> D
where M: TransformMatrix<T>,

Convert the source color to the destination color using the specified method.
source§

fn adapt_into(self) -> D

Convert the source color to the destination color using the bradford method by default.
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, C> ArraysFrom<C> for T
where C: IntoArrays<T>,

source§

fn arrays_from(colors: C) -> T

Cast a collection of colors into a collection of arrays.
source§

impl<T, C> ArraysInto<C> for T
where C: FromArrays<T>,

source§

fn arrays_into(self) -> C

Cast this collection of arrays into a collection of colors.
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<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for U
where T: FromCam16Unclamped<WpParam, U>,

source§

type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
source§

fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
source§

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

source§

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

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

impl<T, C> ComponentsFrom<C> for T
where C: IntoComponents<T>,

source§

fn components_from(colors: C) -> T

Cast a collection of colors into a collection of color components.
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> FromAngle<T> for T

source§

fn from_angle(angle: T) -> T

Performs a conversion from angle.
source§

impl<T, U> FromStimulus<U> for T
where U: IntoStimulus<T>,

source§

fn from_stimulus(other: U) -> T

Converts other into Self, while performing the appropriate scaling, rounding and clamping.
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, U> IntoAngle<U> for T
where U: FromAngle<T>,

source§

fn into_angle(self) -> U

Performs a conversion into T.
source§

impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for U
where T: Cam16FromUnclamped<WpParam, U>,

source§

type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar

The number type that’s used in parameters when converting.
source§

fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T

Converts self into C, using the provided parameters.
source§

impl<T, U> IntoColor<U> for T
where U: FromColor<T>,

source§

fn into_color(self) -> U

Convert into T with values clamped to the color defined bounds Read more
source§

impl<T, U> IntoColorUnclamped<U> for T
where U: FromColorUnclamped<T>,

source§

fn into_color_unclamped(self) -> U

Convert into T. The resulting color might be invalid in its color space Read more
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> IntoStimulus<T> for T

source§

fn into_stimulus(self) -> T

Converts self into T, while performing the appropriate scaling, rounding and clamping.
source§

impl<T> Same for T

source§

type Output = T

Should always be Self
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, C> TryComponentsInto<C> for T
where C: TryFromComponents<T>,

source§

type Error = <C as TryFromComponents<T>>::Error

The error for when try_into_colors fails to cast.
source§

fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>

Try to cast this collection of color components into a collection of colors. 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.
source§

impl<T, U> TryIntoColor<U> for T
where U: TryFromColor<T>,

source§

fn try_into_color(self) -> Result<U, OutOfBounds<U>>

Convert into T, returning ok if the color is inside of its defined range, otherwise an OutOfBounds error is returned which contains the unclamped color. Read more
source§

impl<C, U> UintsFrom<C> for U
where C: IntoUints<U>,

source§

fn uints_from(colors: C) -> U

Cast a collection of colors into a collection of unsigned integers.
source§

impl<C, U> UintsInto<C> for U
where C: FromUints<U>,

source§

fn uints_into(self) -> C

Cast this collection of unsigned integers into a collection of colors.