[go: up one dir, main page]

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)
136fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
137    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
138    let vertical = Layout::vertical([height]).flex(Flex::Center);
139    let [area] = vertical.areas(area);
140    let [area] = horizontal.areas(area);
141    area
142}
More examples
Hide additional examples
examples/table.rs (line 204)
203    fn draw(&mut self, frame: &mut Frame) {
204        let vertical = &Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
205        let rects = vertical.split(frame.area());
206
207        self.set_colors();
208
209        self.render_table(frame, rects[0]);
210        self.render_scrollbar(frame, rects[0]);
211        self.render_footer(frame, rects[1]);
212    }
examples/async.rs (line 101)
100    fn draw(&self, frame: &mut Frame) {
101        let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
102        let [title_area, body_area] = vertical.areas(frame.area());
103        let title = Line::from("Ratatui async example").centered().bold();
104        frame.render_widget(title, title_area);
105        frame.render_widget(&self.pull_requests, body_area);
106    }
examples/colors_rgb.rs (line 144)
142    fn render(self, area: Rect, buf: &mut Buffer) {
143        use Constraint::{Length, Min};
144        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
145        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
146        Text::from("colors_rgb example. Press q to quit")
147            .centered()
148            .render(title, buf);
149        self.fps_widget.render(fps, buf);
150        self.colors_widget.render(colors, buf);
151    }
examples/barchart-grouped.rs (line 84)
82    fn draw(&self, frame: &mut Frame) {
83        use Constraint::{Fill, Length, Min};
84        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
85        let [title, top, bottom] = vertical.areas(frame.area());
86
87        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
88        frame.render_widget(self.vertical_revenue_barchart(), top);
89        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
90    }
examples/demo2/tabs/email.rs (line 76)
69    fn render(self, area: Rect, buf: &mut Buffer) {
70        RgbSwatch.render(area, buf);
71        let area = area.inner(Margin {
72            vertical: 1,
73            horizontal: 2,
74        });
75        Clear.render(area, buf);
76        let vertical = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
77        let [inbox, email] = vertical.areas(area);
78        render_inbox(self.row_index, inbox, buf);
79        render_email(self.row_index, email, buf);
80    }
81}
82fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
83    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
84    let [tabs, inbox] = vertical.areas(area);
85    let theme = THEME.email;
86    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
87        .style(theme.tabs)
88        .highlight_style(theme.tabs_selected)
89        .select(0)
90        .divider("")
91        .render(tabs, buf);
92
93    let highlight_symbol = ">>";
94    let from_width = EMAILS
95        .iter()
96        .map(|e| e.from.width())
97        .max()
98        .unwrap_or_default();
99    let items = EMAILS.iter().map(|e| {
100        let from = format!("{:width$}", e.from, width = from_width).into();
101        ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
102    });
103    let mut state = ListState::default().with_selected(Some(selected_index));
104    StatefulWidget::render(
105        List::new(items)
106            .style(theme.inbox)
107            .highlight_style(theme.selected_item)
108            .highlight_symbol(highlight_symbol),
109        inbox,
110        buf,
111        &mut state,
112    );
113    let mut scrollbar_state = ScrollbarState::default()
114        .content_length(EMAILS.len())
115        .position(selected_index);
116    Scrollbar::default()
117        .begin_symbol(None)
118        .end_symbol(None)
119        .track_symbol(None)
120        .thumb_symbol("▐")
121        .render(inbox, buf, &mut scrollbar_state);
122}
123
124fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
125    let theme = THEME.email;
126    let email = EMAILS.get(selected_index);
127    let block = Block::new()
128        .style(theme.body)
129        .padding(Padding::new(2, 2, 0, 0))
130        .borders(Borders::TOP)
131        .border_type(BorderType::Thick);
132    let inner = block.inner(area);
133    block.render(area, buf);
134    if let Some(email) = email {
135        let vertical = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
136        let [headers_area, body_area] = vertical.areas(inner);
137        let headers = vec![
138            Line::from(vec![
139                "From: ".set_style(theme.header),
140                email.from.set_style(theme.header_value),
141            ]),
142            Line::from(vec![
143                "Subject: ".set_style(theme.header),
144                email.subject.set_style(theme.header_value),
145            ]),
146            "-".repeat(inner.width as usize).dim().into(),
147        ];
148        Paragraph::new(headers)
149            .style(theme.body)
150            .render(headers_area, buf);
151        let body = email.body.lines().map(Line::from).collect_vec();
152        Paragraph::new(body)
153            .style(theme.body)
154            .render(body_area, buf);
155    } else {
156        Paragraph::new("No email selected").render(inner, buf);
157    }
158}
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)
136fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
137    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
138    let vertical = Layout::vertical([height]).flex(Flex::Center);
139    let [area] = vertical.areas(area);
140    let [area] = horizontal.areas(area);
141    area
142}
More examples
Hide additional examples
examples/widget_impl.rs (line 194)
192    fn render(self, area: Rect, buf: &mut Buffer) {
193        let constraints = vec![Constraint::Length(4); self.squares.len()];
194        let areas = Layout::horizontal(constraints).split(area);
195        for (widget, area) in self.squares.iter().zip(areas.iter()) {
196            widget.render_ref(*area, buf);
197        }
198    }
examples/demo2/tabs/about.rs (line 63)
61    fn render(self, area: Rect, buf: &mut Buffer) {
62        RgbSwatch.render(area, buf);
63        let horizontal = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
64        let [description, logo] = horizontal.areas(area);
65        render_crate_description(description, buf);
66        render_logo(self.row_index, logo, buf);
67    }
examples/popup.rs (line 89)
87fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
88    let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
89    let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
90    let [area] = vertical.areas(area);
91    let [area] = horizontal.areas(area);
92    area
93}
examples/colors_rgb.rs (line 145)
142    fn render(self, area: Rect, buf: &mut Buffer) {
143        use Constraint::{Length, Min};
144        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
145        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
146        Text::from("colors_rgb example. Press q to quit")
147            .centered()
148            .render(title, buf);
149        self.fps_widget.render(fps, buf);
150        self.colors_widget.render(colors, buf);
151    }
examples/constraint-explorer.rs (line 350)
348    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
349        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
350        let blocks = Layout::horizontal(constraints).split(area);
351
352        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
353            let selected = self.selected_index == i;
354            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
355        }
356    }
357
358    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
359        let [label_area, axis_area, blocks_area] =
360            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);
361
362        if label_area.height > 0 {
363            format!("Flex::{flex:?}").bold().render(label_area, buf);
364        }
365
366        self.axis(area.width).render(axis_area, buf);
367
368        let (blocks, spacers) = Layout::horizontal(&self.constraints)
369            .flex(flex)
370            .spacing(self.spacing)
371            .split_with_spacers(blocks_area);
372
373        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
374            let selected = self.selected_index == i;
375            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
376        }
377
378        for area in spacers.iter() {
379            SpacerBlock.render(*area, buf);
380        }
381    }
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    fn run(mut self, mut terminal: DefaultTerminal) -> Result<()> {
162        // increase the layout cache to account for the number of layout events. This ensures that
163        // layout is not generally reprocessed on every frame (which would lead to possible janky
164        // results when there are more than one possible solution to the requested layout). This
165        // assumes the user changes spacing about a 100 times or so.
166        let cache_size = EXAMPLE_DATA.len() * SelectedTab::iter().len() * 100;
167        Layout::init_cache(NonZeroUsize::new(cache_size).unwrap());
168
169        while self.is_running() {
170            terminal.draw(|frame| frame.render_widget(self, frame.area()))?;
171            self.handle_events()?;
172        }
173        Ok(())
174    }
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)
231fn draw(frame: &mut Frame, downloads: &Downloads) {
232    let area = frame.area();
233
234    let block = Block::new().title(Line::from("Progress").centered());
235    frame.render_widget(block, area);
236
237    let vertical = Layout::vertical([Constraint::Length(2), Constraint::Length(4)]).margin(1);
238    let horizontal = Layout::horizontal([Constraint::Percentage(20), Constraint::Percentage(80)]);
239    let [progress_area, main] = vertical.areas(area);
240    let [list_area, gauge_area] = horizontal.areas(main);
241
242    // total progress
243    let done = NUM_DOWNLOADS - downloads.pending.len() - downloads.in_progress.len();
244    #[allow(clippy::cast_precision_loss)]
245    let progress = LineGauge::default()
246        .filled_style(Style::default().fg(Color::Blue))
247        .label(format!("{done}/{NUM_DOWNLOADS}"))
248        .ratio(done as f64 / NUM_DOWNLOADS as f64);
249    frame.render_widget(progress, progress_area);
250
251    // in progress downloads
252    let items: Vec<ListItem> = downloads
253        .in_progress
254        .values()
255        .map(|download| {
256            ListItem::new(Line::from(vec![
257                Span::raw(symbols::DOT),
258                Span::styled(
259                    format!(" download {:>2}", download.id),
260                    Style::default()
261                        .fg(Color::LightGreen)
262                        .add_modifier(Modifier::BOLD),
263                ),
264                Span::raw(format!(
265                    " ({}ms)",
266                    download.started_at.elapsed().as_millis()
267                )),
268            ]))
269        })
270        .collect();
271    let list = List::new(items);
272    frame.render_widget(list, list_area);
273
274    #[allow(clippy::cast_possible_truncation)]
275    for (i, (_, download)) in downloads.in_progress.iter().enumerate() {
276        let gauge = Gauge::default()
277            .gauge_style(Style::default().fg(Color::Yellow))
278            .ratio(download.progress / 100.0);
279        if gauge_area.top().saturating_add(i as u16) > area.bottom() {
280            continue;
281        }
282        frame.render_widget(
283            gauge,
284            Rect {
285                x: gauge_area.left(),
286                y: gauge_area.top().saturating_add(i as u16),
287                width: gauge_area.width,
288                height: 1,
289            },
290        );
291    }
292}
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)
136fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
137    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
138    let vertical = Layout::vertical([height]).flex(Flex::Center);
139    let [area] = vertical.areas(area);
140    let [area] = horizontal.areas(area);
141    area
142}
More examples
Hide additional examples
examples/popup.rs (line 88)
87fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
88    let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
89    let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
90    let [area] = vertical.areas(area);
91    let [area] = horizontal.areas(area);
92    area
93}
examples/flex.rs (line 401)
397    fn render_examples(area: Rect, buf: &mut Buffer, flex: Flex, spacing: u16) {
398        let heights = EXAMPLE_DATA
399            .iter()
400            .map(|(desc, _)| get_description_height(desc) + 4);
401        let areas = Layout::vertical(heights).flex(Flex::Start).split(area);
402        for (area, (description, constraints)) in areas.iter().zip(EXAMPLE_DATA.iter()) {
403            Example::new(constraints, description, flex, spacing).render(*area, buf);
404        }
405    }
406}
407
408impl Example {
409    fn new(constraints: &[Constraint], description: &str, flex: Flex, spacing: u16) -> Self {
410        Self {
411            constraints: constraints.into(),
412            description: description.into(),
413            flex,
414            spacing,
415        }
416    }
417}
418
419impl Widget for Example {
420    fn render(self, area: Rect, buf: &mut Buffer) {
421        let title_height = get_description_height(&self.description);
422        let layout = Layout::vertical([Length(title_height), Fill(0)]);
423        let [title, illustrations] = layout.areas(area);
424
425        let (blocks, spacers) = Layout::horizontal(&self.constraints)
426            .flex(self.flex)
427            .spacing(self.spacing)
428            .split_with_spacers(illustrations);
429
430        if !self.description.is_empty() {
431            Paragraph::new(
432                self.description
433                    .split('\n')
434                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
435                    .map(Line::from)
436                    .collect::<Vec<Line>>(),
437            )
438            .render(title, buf);
439        }
440
441        for (block, constraint) in blocks.iter().zip(&self.constraints) {
442            Self::illustration(*constraint, block.width).render(*block, buf);
443        }
444
445        for spacer in spacers.iter() {
446            Self::render_spacer(*spacer, buf);
447        }
448    }
examples/constraint-explorer.rs (line 369)
358    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
359        let [label_area, axis_area, blocks_area] =
360            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);
361
362        if label_area.height > 0 {
363            format!("Flex::{flex:?}").bold().render(label_area, buf);
364        }
365
366        self.axis(area.width).render(axis_area, buf);
367
368        let (blocks, spacers) = Layout::horizontal(&self.constraints)
369            .flex(flex)
370            .spacing(self.spacing)
371            .split_with_spacers(blocks_area);
372
373        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
374            let selected = self.selected_index == i;
375            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
376        }
377
378        for area in spacers.iter() {
379            SpacerBlock.render(*area, buf);
380        }
381    }
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    fn draw(&self, frame: &mut Frame) {
83        use Constraint::{Fill, Length, Min};
84        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
85        let [title, top, bottom] = vertical.areas(frame.area());
86
87        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
88        frame.render_widget(self.vertical_revenue_barchart(), top);
89        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
90    }
More examples
Hide additional examples
examples/barchart.rs (line 73)
67    fn draw(&self, frame: &mut Frame) {
68        let [title, vertical, horizontal] = Layout::vertical([
69            Constraint::Length(1),
70            Constraint::Fill(1),
71            Constraint::Fill(1),
72        ])
73        .spacing(1)
74        .areas(frame.area());
75
76        frame.render_widget("Barchart".bold().into_centered_line(), title);
77        frame.render_widget(vertical_barchart(&self.temperatures), vertical);
78        frame.render_widget(horizontal_barchart(&self.temperatures), horizontal);
79    }
examples/constraint-explorer.rs (line 333)
331    fn render_layout_blocks(&self, area: Rect, buf: &mut Buffer) {
332        let [user_constraints, area] = Layout::vertical([Length(3), Fill(1)])
333            .spacing(1)
334            .areas(area);
335
336        self.render_user_constraints_legend(user_constraints, buf);
337
338        let [start, center, end, space_around, space_between] =
339            Layout::vertical([Length(7); 5]).areas(area);
340
341        self.render_layout_block(Flex::Start, start, buf);
342        self.render_layout_block(Flex::Center, center, buf);
343        self.render_layout_block(Flex::End, end, buf);
344        self.render_layout_block(Flex::SpaceAround, space_around, buf);
345        self.render_layout_block(Flex::SpaceBetween, space_between, buf);
346    }
347
348    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
349        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
350        let blocks = Layout::horizontal(constraints).split(area);
351
352        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
353            let selected = self.selected_index == i;
354            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
355        }
356    }
357
358    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
359        let [label_area, axis_area, blocks_area] =
360            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);
361
362        if label_area.height > 0 {
363            format!("Flex::{flex:?}").bold().render(label_area, buf);
364        }
365
366        self.axis(area.width).render(axis_area, buf);
367
368        let (blocks, spacers) = Layout::horizontal(&self.constraints)
369            .flex(flex)
370            .spacing(self.spacing)
371            .split_with_spacers(blocks_area);
372
373        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
374            let selected = self.selected_index == i;
375            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
376        }
377
378        for area in spacers.iter() {
379            SpacerBlock.render(*area, buf);
380        }
381    }
examples/flex.rs (line 427)
420    fn render(self, area: Rect, buf: &mut Buffer) {
421        let title_height = get_description_height(&self.description);
422        let layout = Layout::vertical([Length(title_height), Fill(0)]);
423        let [title, illustrations] = layout.areas(area);
424
425        let (blocks, spacers) = Layout::horizontal(&self.constraints)
426            .flex(self.flex)
427            .spacing(self.spacing)
428            .split_with_spacers(illustrations);
429
430        if !self.description.is_empty() {
431            Paragraph::new(
432                self.description
433                    .split('\n')
434                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
435                    .map(Line::from)
436                    .collect::<Vec<Line>>(),
437            )
438            .render(title, buf);
439        }
440
441        for (block, constraint) in blocks.iter().zip(&self.constraints) {
442            Self::illustration(*constraint, block.width).render(*block, buf);
443        }
444
445        for spacer in spacers.iter() {
446            Self::render_spacer(*spacer, buf);
447        }
448    }
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)
136fn centered_rect(area: Rect, width: u16, height: u16) -> Rect {
137    let horizontal = Layout::horizontal([width]).flex(Flex::Center);
138    let vertical = Layout::vertical([height]).flex(Flex::Center);
139    let [area] = vertical.areas(area);
140    let [area] = horizontal.areas(area);
141    area
142}
More examples
Hide additional examples
examples/demo2/tabs/about.rs (line 64)
61    fn render(self, area: Rect, buf: &mut Buffer) {
62        RgbSwatch.render(area, buf);
63        let horizontal = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
64        let [description, logo] = horizontal.areas(area);
65        render_crate_description(description, buf);
66        render_logo(self.row_index, logo, buf);
67    }
examples/async.rs (line 102)
100    fn draw(&self, frame: &mut Frame) {
101        let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
102        let [title_area, body_area] = vertical.areas(frame.area());
103        let title = Line::from("Ratatui async example").centered().bold();
104        frame.render_widget(title, title_area);
105        frame.render_widget(&self.pull_requests, body_area);
106    }
examples/colors_rgb.rs (line 144)
142    fn render(self, area: Rect, buf: &mut Buffer) {
143        use Constraint::{Length, Min};
144        let [top, colors] = Layout::vertical([Length(1), Min(0)]).areas(area);
145        let [title, fps] = Layout::horizontal([Min(0), Length(8)]).areas(top);
146        Text::from("colors_rgb example. Press q to quit")
147            .centered()
148            .render(title, buf);
149        self.fps_widget.render(fps, buf);
150        self.colors_widget.render(colors, buf);
151    }
examples/barchart-grouped.rs (line 85)
82    fn draw(&self, frame: &mut Frame) {
83        use Constraint::{Fill, Length, Min};
84        let vertical = Layout::vertical([Length(1), Fill(1), Min(20)]).spacing(1);
85        let [title, top, bottom] = vertical.areas(frame.area());
86
87        frame.render_widget("Grouped Barchart".bold().into_centered_line(), title);
88        frame.render_widget(self.vertical_revenue_barchart(), top);
89        frame.render_widget(self.horizontal_revenue_barchart(), bottom);
90    }
examples/demo2/tabs/email.rs (line 77)
69    fn render(self, area: Rect, buf: &mut Buffer) {
70        RgbSwatch.render(area, buf);
71        let area = area.inner(Margin {
72            vertical: 1,
73            horizontal: 2,
74        });
75        Clear.render(area, buf);
76        let vertical = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
77        let [inbox, email] = vertical.areas(area);
78        render_inbox(self.row_index, inbox, buf);
79        render_email(self.row_index, email, buf);
80    }
81}
82fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
83    let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
84    let [tabs, inbox] = vertical.areas(area);
85    let theme = THEME.email;
86    Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
87        .style(theme.tabs)
88        .highlight_style(theme.tabs_selected)
89        .select(0)
90        .divider("")
91        .render(tabs, buf);
92
93    let highlight_symbol = ">>";
94    let from_width = EMAILS
95        .iter()
96        .map(|e| e.from.width())
97        .max()
98        .unwrap_or_default();
99    let items = EMAILS.iter().map(|e| {
100        let from = format!("{:width$}", e.from, width = from_width).into();
101        ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
102    });
103    let mut state = ListState::default().with_selected(Some(selected_index));
104    StatefulWidget::render(
105        List::new(items)
106            .style(theme.inbox)
107            .highlight_style(theme.selected_item)
108            .highlight_symbol(highlight_symbol),
109        inbox,
110        buf,
111        &mut state,
112    );
113    let mut scrollbar_state = ScrollbarState::default()
114        .content_length(EMAILS.len())
115        .position(selected_index);
116    Scrollbar::default()
117        .begin_symbol(None)
118        .end_symbol(None)
119        .track_symbol(None)
120        .thumb_symbol("▐")
121        .render(inbox, buf, &mut scrollbar_state);
122}
123
124fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
125    let theme = THEME.email;
126    let email = EMAILS.get(selected_index);
127    let block = Block::new()
128        .style(theme.body)
129        .padding(Padding::new(2, 2, 0, 0))
130        .borders(Borders::TOP)
131        .border_type(BorderType::Thick);
132    let inner = block.inner(area);
133    block.render(area, buf);
134    if let Some(email) = email {
135        let vertical = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
136        let [headers_area, body_area] = vertical.areas(inner);
137        let headers = vec![
138            Line::from(vec![
139                "From: ".set_style(theme.header),
140                email.from.set_style(theme.header_value),
141            ]),
142            Line::from(vec![
143                "Subject: ".set_style(theme.header),
144                email.subject.set_style(theme.header_value),
145            ]),
146            "-".repeat(inner.width as usize).dim().into(),
147        ];
148        Paragraph::new(headers)
149            .style(theme.body)
150            .render(headers_area, buf);
151        let body = email.body.lines().map(Line::from).collect_vec();
152        Paragraph::new(body)
153            .style(theme.body)
154            .render(body_area, buf);
155    } else {
156        Paragraph::new("No email selected").render(inner, buf);
157    }
158}
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    fn render(self, area: Rect, buf: &mut Buffer) {
193        let constraints = vec![Constraint::Length(4); self.squares.len()];
194        let areas = Layout::horizontal(constraints).split(area);
195        for (widget, area) in self.squares.iter().zip(areas.iter()) {
196            widget.render_ref(*area, buf);
197        }
198    }
More examples
Hide additional examples
examples/table.rs (line 205)
203    fn draw(&mut self, frame: &mut Frame) {
204        let vertical = &Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
205        let rects = vertical.split(frame.area());
206
207        self.set_colors();
208
209        self.render_table(frame, rects[0]);
210        self.render_scrollbar(frame, rects[0]);
211        self.render_footer(frame, rects[1]);
212    }
examples/flex.rs (line 401)
397    fn render_examples(area: Rect, buf: &mut Buffer, flex: Flex, spacing: u16) {
398        let heights = EXAMPLE_DATA
399            .iter()
400            .map(|(desc, _)| get_description_height(desc) + 4);
401        let areas = Layout::vertical(heights).flex(Flex::Start).split(area);
402        for (area, (description, constraints)) in areas.iter().zip(EXAMPLE_DATA.iter()) {
403            Example::new(constraints, description, flex, spacing).render(*area, buf);
404        }
405    }
examples/constraint-explorer.rs (line 350)
348    fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
349        let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
350        let blocks = Layout::horizontal(constraints).split(area);
351
352        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
353            let selected = self.selected_index == i;
354            ConstraintBlock::new(*constraint, selected, true).render(*area, buf);
355        }
356    }
examples/block.rs (line 82)
77fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
78    let main_layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
79    let block_layout = Layout::vertical([Constraint::Max(4); 9]);
80    let [title_area, main_area] = main_layout.areas(area);
81    let main_areas = block_layout
82        .split(main_area)
83        .iter()
84        .map(|&area| {
85            Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
86                .split(area)
87                .to_vec()
88        })
89        .collect();
90    (title_area, main_areas)
91}
examples/calendar.rs (line 61)
45fn draw(frame: &mut Frame) {
46    let area = frame.area().inner(Margin {
47        vertical: 1,
48        horizontal: 1,
49    });
50
51    let mut start = OffsetDateTime::now_local()
52        .unwrap()
53        .date()
54        .replace_month(Month::January)
55        .unwrap()
56        .replace_day(1)
57        .unwrap();
58
59    let list = make_dates(start.year());
60
61    let rows = Layout::vertical([Constraint::Ratio(1, 3); 3]).split(area);
62    let cols = rows.iter().flat_map(|row| {
63        Layout::horizontal([Constraint::Ratio(1, 4); 4])
64            .split(*row)
65            .to_vec()
66    });
67    for col in cols {
68        let cal = cals::get_cal(start.month(), start.year(), &list);
69        frame.render_widget(cal, col);
70        start = start.replace_month(start.month().next()).unwrap();
71    }
72}
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    fn render_layout_block(&self, flex: Flex, area: Rect, buf: &mut Buffer) {
359        let [label_area, axis_area, blocks_area] =
360            Layout::vertical([Length(1), Max(1), Length(4)]).areas(area);
361
362        if label_area.height > 0 {
363            format!("Flex::{flex:?}").bold().render(label_area, buf);
364        }
365
366        self.axis(area.width).render(axis_area, buf);
367
368        let (blocks, spacers) = Layout::horizontal(&self.constraints)
369            .flex(flex)
370            .spacing(self.spacing)
371            .split_with_spacers(blocks_area);
372
373        for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
374            let selected = self.selected_index == i;
375            ConstraintBlock::new(*constraint, selected, false).render(*area, buf);
376        }
377
378        for area in spacers.iter() {
379            SpacerBlock.render(*area, buf);
380        }
381    }
More examples
Hide additional examples
examples/flex.rs (line 428)
420    fn render(self, area: Rect, buf: &mut Buffer) {
421        let title_height = get_description_height(&self.description);
422        let layout = Layout::vertical([Length(title_height), Fill(0)]);
423        let [title, illustrations] = layout.areas(area);
424
425        let (blocks, spacers) = Layout::horizontal(&self.constraints)
426            .flex(self.flex)
427            .spacing(self.spacing)
428            .split_with_spacers(illustrations);
429
430        if !self.description.is_empty() {
431            Paragraph::new(
432                self.description
433                    .split('\n')
434                    .map(|s| format!("// {s}").italic().fg(tailwind::SLATE.c400))
435                    .map(Line::from)
436                    .collect::<Vec<Line>>(),
437            )
438            .render(title, buf);
439        }
440
441        for (block, constraint) in blocks.iter().zip(&self.constraints) {
442            Self::illustration(*constraint, block.width).render(*block, buf);
443        }
444
445        for spacer in spacers.iter() {
446            Self::render_spacer(*spacer, buf);
447        }
448    }

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, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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.