mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-26 20:40:44 +00:00
feat: add ergonomic methods for layouting Rects (#1909)
This commit introduces new methods for the `Rect` struct that simplify the process of splitting a `Rect` into sub-rects according to a given `Layout`. By putting these methods on the `Rect` struct, we make it a bit more natural that a layout is applied to the `Rect` itself, rather than passing a `Rect` to the `Layout` struct to be split. Adds: - `Rect::layout` and `Rect::try_layout` methods that allow splitting a `Rect` into an array of sub-rects according to a given `Layout`. - `Rect::layout_vec` method that returns a `Vec` of sub-rects. - `Layout::try_areas` method that returns an array of sub-rects, with compile-time checks for the number of constraints. This is added mainly for consistency with the new `Rect` methods. ```rust use ratatui_core::layout::{Layout, Constraint, Rect}; let area = Rect::new(0, 0, 10, 10); let layout = Layout::vertical([Constraint::Fill(1); 2]); // Rect::layout() infers the number of constraints at compile time: let [top, main] = area.layout(&layout); // Rect::try_layout() and Layout::try_areas() do the same, but return a // Result: let [top, main] = area.try_layout(&layout)?; let [top, main] = layout.try_areas(area)?; // Rect::layout_vec() returns a Vec of sub-rects: let areas_vec = area.layout_vec(&layout); // you can also explicitly specify the number of constraints: let areas = area.layout::<2>(&layout); let areas = area.try_layout::<2>(&layout)?; let areas = layout.try_areas::<2>(area)?; ```
This commit is contained in:
parent
d99984f1e9
commit
6dcd53bc6b
@ -68,7 +68,7 @@ impl App {
|
||||
impl Widget for &mut App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let constraints = Constraint::from_lengths([1, 1, 2, 1]);
|
||||
let [greeting, timer, squares, position] = Layout::vertical(constraints).areas(area);
|
||||
let [greeting, timer, squares, position] = area.layout(&Layout::vertical(constraints));
|
||||
|
||||
// render an ephemeral greeting widget
|
||||
Greeting::new("Ratatui!").render(greeting, buf);
|
||||
@ -174,9 +174,9 @@ struct BlueSquare;
|
||||
impl Widget for &BoxedSquares {
|
||||
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);
|
||||
let areas = area.layout_vec(&Layout::horizontal(constraints));
|
||||
for (widget, area) in self.squares.iter().zip(areas) {
|
||||
widget.render_ref(area, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +78,8 @@ impl App {
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [title_area, body_area] = vertical.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [title_area, body_area] = frame.area().layout(&layout);
|
||||
let title = Line::from("Ratatui async example").centered().bold();
|
||||
frame.render_widget(title, title_area);
|
||||
frame.render_widget(&self.pull_requests, body_area);
|
||||
|
@ -81,11 +81,10 @@ fn render(frame: &mut Frame, calendar_style: StyledCalendar, selected_date: Date
|
||||
)),
|
||||
]);
|
||||
|
||||
let vertical = Layout::vertical([
|
||||
let [text_area, area] = frame.area().layout(&Layout::vertical([
|
||||
Constraint::Length(header.height() as u16),
|
||||
Constraint::Fill(1),
|
||||
]);
|
||||
let [text_area, area] = vertical.areas(frame.area());
|
||||
]));
|
||||
frame.render_widget(header.centered(), text_area);
|
||||
calendar_style
|
||||
.render_year(frame, area, selected_date)
|
||||
@ -133,16 +132,13 @@ impl StyledCalendar {
|
||||
fn render_year(self, frame: &mut Frame, area: Rect, date: Date) -> Result<()> {
|
||||
let events = events(date)?;
|
||||
|
||||
let area = area.inner(Margin {
|
||||
vertical: 1,
|
||||
horizontal: 1,
|
||||
});
|
||||
let rows = Layout::vertical([Constraint::Ratio(1, 3); 3]).split(area);
|
||||
let areas = rows.iter().flat_map(|row| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 4); 4])
|
||||
.split(*row)
|
||||
.to_vec()
|
||||
});
|
||||
let vertical = Layout::vertical([Constraint::Ratio(1, 3); 3]);
|
||||
let horizontal = &Layout::horizontal([Constraint::Ratio(1, 4); 4]);
|
||||
let areas = area
|
||||
.inner(Margin::new(1, 1))
|
||||
.layout_vec(&vertical)
|
||||
.into_iter()
|
||||
.flat_map(|row| row.layout_vec(horizontal));
|
||||
for (i, area) in areas.enumerate() {
|
||||
let month = date
|
||||
.replace_day(1)
|
||||
|
@ -153,16 +153,15 @@ impl App {
|
||||
|
||||
let vertical = Layout::vertical([
|
||||
Constraint::Length(header.height() as u16),
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
]);
|
||||
let [text_area, up, down] = vertical.areas(frame.area());
|
||||
let [text_area, up, down] = frame.area().layout(&vertical);
|
||||
frame.render_widget(header.centered(), text_area);
|
||||
|
||||
let horizontal =
|
||||
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
|
||||
let [draw, pong] = horizontal.areas(up);
|
||||
let [map, boxes] = horizontal.areas(down);
|
||||
let horizontal = Layout::horizontal([Constraint::Fill(1); 2]);
|
||||
let [draw, pong] = up.layout(&horizontal);
|
||||
let [map, boxes] = down.layout(&horizontal);
|
||||
|
||||
frame.render_widget(self.map_canvas(), map);
|
||||
frame.render_widget(self.draw_canvas(draw), draw);
|
||||
|
@ -108,10 +108,11 @@ impl App {
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let [top, bottom] = Layout::vertical([Constraint::Fill(1); 2]).areas(frame.area());
|
||||
let [animated_chart, bar_chart] =
|
||||
Layout::horizontal([Constraint::Fill(1), Constraint::Length(29)]).areas(top);
|
||||
let [line_chart, scatter] = Layout::horizontal([Constraint::Fill(1); 2]).areas(bottom);
|
||||
let vertical = Layout::vertical([Constraint::Fill(1); 2]);
|
||||
let [top, bottom] = frame.area().layout(&vertical);
|
||||
let horizontal = Layout::horizontal([Constraint::Fill(1), Constraint::Length(29)]);
|
||||
let [animated_chart, bar_chart] = top.layout(&horizontal);
|
||||
let [line_chart, scatter] = bottom.layout(&Layout::horizontal([Constraint::Fill(1); 2]));
|
||||
|
||||
self.render_animated_chart(frame, animated_chart);
|
||||
render_barchart(frame, bar_chart);
|
||||
|
@ -82,12 +82,12 @@ fn render_fg_named_colors(frame: &mut Frame, bg: Color, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
|
||||
let areas = vertical.iter().flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
});
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]);
|
||||
let horizontal = Layout::horizontal([Constraint::Ratio(1, 8); 8]);
|
||||
let areas = inner
|
||||
.layout_vec(&vertical)
|
||||
.into_iter()
|
||||
.flat_map(|area| area.layout_vec(&horizontal));
|
||||
for (fg, area) in NAMED_COLORS.into_iter().zip(areas) {
|
||||
let color_name = fg.to_string();
|
||||
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
|
||||
@ -100,12 +100,12 @@ fn render_bg_named_colors(frame: &mut Frame, fg: Color, area: Rect) {
|
||||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
|
||||
let areas = vertical.iter().flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
});
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]);
|
||||
let horizontal = Layout::horizontal([Constraint::Ratio(1, 8); 8]);
|
||||
let areas = inner
|
||||
.layout_vec(&vertical)
|
||||
.into_iter()
|
||||
.flat_map(|area| area.layout_vec(&horizontal));
|
||||
for (bg, area) in NAMED_COLORS.into_iter().zip(areas) {
|
||||
let color_name = bg.to_string();
|
||||
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
|
||||
|
@ -124,8 +124,8 @@ impl App {
|
||||
impl Widget for &mut App {
|
||||
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);
|
||||
let [top, colors] = area.layout(&Layout::vertical([Length(1), Min(0)]));
|
||||
let [title, fps] = top.layout(&Layout::horizontal([Min(0), Length(8)]));
|
||||
Text::from("colors_rgb example. Press q to quit")
|
||||
.centered()
|
||||
.render(title, buf);
|
||||
|
@ -242,14 +242,13 @@ impl Widget for &App {
|
||||
swap_legend_area,
|
||||
_,
|
||||
blocks_area,
|
||||
] = Layout::vertical([
|
||||
] = area.layout(&Layout::vertical([
|
||||
Length(2), // header
|
||||
Length(2), // instructions
|
||||
Length(1), // swap key legend
|
||||
Length(1), // gap
|
||||
Fill(1), // blocks
|
||||
])
|
||||
.areas(area);
|
||||
]));
|
||||
|
||||
App::header().render(header_area, buf);
|
||||
App::instructions().render(instructions_area, buf);
|
||||
@ -319,9 +318,8 @@ impl App {
|
||||
}
|
||||
|
||||
fn render_layout_blocks(&self, area: Rect, buf: &mut Buffer) {
|
||||
let [user_constraints, area] = Layout::vertical([Length(3), Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(area);
|
||||
let main_layout = Layout::vertical([Length(3), Fill(1)]).spacing(1);
|
||||
let [user_constraints, area] = area.layout(&main_layout);
|
||||
|
||||
self.render_user_constraints_legend(user_constraints, buf);
|
||||
|
||||
@ -332,7 +330,7 @@ impl App {
|
||||
space_between,
|
||||
space_around,
|
||||
space_evenly,
|
||||
] = Layout::vertical([Length(7); 6]).areas(area);
|
||||
] = area.layout(&Layout::vertical([Length(7); 6]));
|
||||
|
||||
self.render_layout_block(Flex::Start, start, buf);
|
||||
self.render_layout_block(Flex::Center, center, buf);
|
||||
@ -353,8 +351,8 @@ impl App {
|
||||
}
|
||||
|
||||
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);
|
||||
let layout = Layout::vertical([Length(1), Max(1), Length(4)]);
|
||||
let [label_area, axis_area, blocks_area] = area.layout(&layout);
|
||||
|
||||
if label_area.height > 0 {
|
||||
format!("Flex::{flex:?}").bold().render(label_area, buf);
|
||||
|
@ -140,7 +140,7 @@ impl App {
|
||||
|
||||
impl Widget for App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let [tabs, axis, demo] = Layout::vertical([Length(3), Length(3), Fill(0)]).areas(area);
|
||||
let [tabs, axis, demo] = area.layout(&Layout::vertical([Length(3), Length(3), Fill(0)]));
|
||||
|
||||
self.render_tabs(tabs, buf);
|
||||
Self::render_axis(axis, buf);
|
||||
@ -281,8 +281,8 @@ impl Widget for SelectedTab {
|
||||
|
||||
impl SelectedTab {
|
||||
fn render_length_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, example3, _] =
|
||||
Layout::vertical([Length(EXAMPLE_HEIGHT); 4]).areas(area);
|
||||
let layout = Layout::vertical([Length(EXAMPLE_HEIGHT); 4]);
|
||||
let [example1, example2, example3, _] = area.layout(&layout);
|
||||
|
||||
Example::new(&[Length(20), Length(20)]).render(example1, buf);
|
||||
Example::new(&[Length(20), Min(20)]).render(example2, buf);
|
||||
@ -290,8 +290,8 @@ impl SelectedTab {
|
||||
}
|
||||
|
||||
fn render_percentage_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, example3, example4, example5, _] =
|
||||
Layout::vertical([Length(EXAMPLE_HEIGHT); 6]).areas(area);
|
||||
let layout = Layout::vertical([Length(EXAMPLE_HEIGHT); 6]);
|
||||
let [example1, example2, example3, example4, example5, _] = area.layout(&layout);
|
||||
|
||||
Example::new(&[Percentage(75), Fill(0)]).render(example1, buf);
|
||||
Example::new(&[Percentage(25), Fill(0)]).render(example2, buf);
|
||||
@ -301,8 +301,8 @@ impl SelectedTab {
|
||||
}
|
||||
|
||||
fn render_ratio_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, example3, example4, _] =
|
||||
Layout::vertical([Length(EXAMPLE_HEIGHT); 5]).areas(area);
|
||||
let layout = Layout::vertical([Length(EXAMPLE_HEIGHT); 5]);
|
||||
let [example1, example2, example3, example4, _] = area.layout(&layout);
|
||||
|
||||
Example::new(&[Ratio(1, 2); 2]).render(example1, buf);
|
||||
Example::new(&[Ratio(1, 4); 4]).render(example2, buf);
|
||||
@ -311,15 +311,15 @@ impl SelectedTab {
|
||||
}
|
||||
|
||||
fn render_fill_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, _] = Layout::vertical([Length(EXAMPLE_HEIGHT); 3]).areas(area);
|
||||
let [example1, example2, _] = area.layout(&Layout::vertical([Length(EXAMPLE_HEIGHT); 3]));
|
||||
|
||||
Example::new(&[Fill(1), Fill(2), Fill(3)]).render(example1, buf);
|
||||
Example::new(&[Fill(1), Percentage(50), Fill(1)]).render(example2, buf);
|
||||
}
|
||||
|
||||
fn render_min_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, example3, example4, example5, _] =
|
||||
Layout::vertical([Length(EXAMPLE_HEIGHT); 6]).areas(area);
|
||||
let layout = Layout::vertical([Length(EXAMPLE_HEIGHT); 6]);
|
||||
let [example1, example2, example3, example4, example5, _] = area.layout(&layout);
|
||||
|
||||
Example::new(&[Percentage(100), Min(0)]).render(example1, buf);
|
||||
Example::new(&[Percentage(100), Min(20)]).render(example2, buf);
|
||||
@ -329,8 +329,8 @@ impl SelectedTab {
|
||||
}
|
||||
|
||||
fn render_max_example(area: Rect, buf: &mut Buffer) {
|
||||
let [example1, example2, example3, example4, example5, _] =
|
||||
Layout::vertical([Length(EXAMPLE_HEIGHT); 6]).areas(area);
|
||||
let layout = Layout::vertical([Length(EXAMPLE_HEIGHT); 6]);
|
||||
let [example1, example2, example3, example4, example5, _] = area.layout(&layout);
|
||||
|
||||
Example::new(&[Percentage(0), Max(0)]).render(example1, buf);
|
||||
Example::new(&[Percentage(0), Max(20)]).render(example2, buf);
|
||||
@ -354,9 +354,10 @@ impl Example {
|
||||
|
||||
impl Widget for Example {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let [area, _] =
|
||||
Layout::vertical([Length(ILLUSTRATION_HEIGHT), Length(SPACER_HEIGHT)]).areas(area);
|
||||
let blocks = Layout::horizontal(&self.constraints).split(area);
|
||||
let vertical = Layout::vertical([Length(ILLUSTRATION_HEIGHT), Length(SPACER_HEIGHT)]);
|
||||
let horizontal = Layout::horizontal(&self.constraints);
|
||||
let [area, _] = area.layout(&vertical);
|
||||
let blocks = area.layout_vec(&horizontal);
|
||||
|
||||
for (block, constraint) in blocks.iter().zip(&self.constraints) {
|
||||
Self::illustration(*constraint, block.width).render(*block, buf);
|
||||
|
@ -15,7 +15,7 @@ use crossterm::event::{
|
||||
};
|
||||
use crossterm::execute;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::{Constraint, Layout, Rect};
|
||||
use ratatui::layout::{Constraint, Flex, Layout, Rect};
|
||||
use ratatui::style::{Color, Style};
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::{Paragraph, Widget};
|
||||
@ -167,13 +167,13 @@ fn run(mut terminal: DefaultTerminal) -> Result<()> {
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame, states: [State; 3]) {
|
||||
let vertical = Layout::vertical([
|
||||
let layout = Layout::vertical([
|
||||
Constraint::Length(1),
|
||||
Constraint::Max(3),
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(0), // ignore remaining space
|
||||
]);
|
||||
let [title, buttons, help, _] = vertical.areas(frame.area());
|
||||
let [title, buttons, help, _] = frame.area().layout(&layout);
|
||||
|
||||
frame.render_widget(
|
||||
Paragraph::new("Custom Widget Example (mouse enabled)"),
|
||||
@ -184,13 +184,8 @@ fn render(frame: &mut Frame, states: [State; 3]) {
|
||||
}
|
||||
|
||||
fn render_buttons(frame: &mut Frame<'_>, area: Rect, states: [State; 3]) {
|
||||
let horizontal = Layout::horizontal([
|
||||
Constraint::Length(15),
|
||||
Constraint::Length(15),
|
||||
Constraint::Length(15),
|
||||
Constraint::Min(0), // ignore remaining space
|
||||
]);
|
||||
let [red, green, blue, _] = horizontal.areas(area);
|
||||
let layout = Layout::horizontal([Constraint::Length(15); 3]).flex(Flex::Start);
|
||||
let [red, green, blue] = area.layout(&layout);
|
||||
|
||||
frame.render_widget(Button::new("Red").theme(RED).state(states[0]), red);
|
||||
frame.render_widget(Button::new("Green").theme(GREEN).state(states[1]), green);
|
||||
|
@ -129,12 +129,12 @@ impl App {
|
||||
/// matter, but for larger apps this can be a significant performance improvement.
|
||||
impl Widget for &App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let vertical = Layout::vertical([
|
||||
let layout = Layout::vertical([
|
||||
Constraint::Length(1),
|
||||
Constraint::Min(0),
|
||||
Constraint::Length(1),
|
||||
]);
|
||||
let [title_bar, tab, bottom_bar] = vertical.areas(area);
|
||||
let [title_bar, tab, bottom_bar] = area.layout(&layout);
|
||||
|
||||
Block::new().style(THEME.root).render(area, buf);
|
||||
self.render_title_bar(title_bar, buf);
|
||||
@ -146,7 +146,7 @@ impl Widget for &App {
|
||||
impl App {
|
||||
fn render_title_bar(&self, area: Rect, buf: &mut Buffer) {
|
||||
let layout = Layout::horizontal([Constraint::Min(0), Constraint::Length(43)]);
|
||||
let [title, tabs] = layout.areas(area);
|
||||
let [title, tabs] = area.layout(&layout);
|
||||
|
||||
Span::styled("Ratatui", THEME.app_title).render(title, buf);
|
||||
let titles = Tab::iter().map(Tab::title);
|
||||
|
@ -134,7 +134,7 @@ fn blend(mask_color: Color, cell_color: Color, percentage: f64) -> Color {
|
||||
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);
|
||||
let [area] = area.layout(&vertical);
|
||||
let [area] = area.layout(&horizontal);
|
||||
area
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ impl AboutTab {
|
||||
impl Widget for AboutTab {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
RgbSwatch.render(area, buf);
|
||||
let horizontal = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
|
||||
let [logo_area, description] = horizontal.areas(area);
|
||||
let layout = Layout::horizontal([Constraint::Length(34), Constraint::Min(0)]);
|
||||
let [logo_area, description] = area.layout(&layout);
|
||||
render_crate_description(description, buf);
|
||||
let eye_state = if self.row_index % 2 == 0 {
|
||||
MascotEyeColor::Default
|
||||
|
@ -71,15 +71,15 @@ impl Widget for EmailTab {
|
||||
horizontal: 2,
|
||||
});
|
||||
Clear.render(area, buf);
|
||||
let vertical = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
|
||||
let [inbox, email] = vertical.areas(area);
|
||||
let layout = Layout::vertical([Constraint::Length(5), Constraint::Min(0)]);
|
||||
let [inbox, email] = area.layout(&layout);
|
||||
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 layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
let [tabs, inbox] = area.layout(&layout);
|
||||
let theme = THEME.email;
|
||||
Tabs::new(vec![" Inbox ", " Sent ", " Drafts "])
|
||||
.style(theme.tabs)
|
||||
@ -130,8 +130,8 @@ fn render_email(selected_index: usize, area: Rect, buf: &mut Buffer) {
|
||||
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 layout = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]);
|
||||
let [headers_area, body_area] = inner.layout(&layout);
|
||||
let headers = vec![
|
||||
Line::from(vec![
|
||||
"From: ".set_style(theme.header),
|
||||
|
@ -135,8 +135,8 @@ impl Widget for RecipeTab {
|
||||
horizontal: 2,
|
||||
vertical: 1,
|
||||
});
|
||||
let [recipe, ingredients] =
|
||||
Layout::horizontal([Constraint::Length(44), Constraint::Min(0)]).areas(area);
|
||||
let layout = Layout::horizontal([Constraint::Length(44), Constraint::Min(0)]);
|
||||
let [recipe, ingredients] = area.layout(&layout);
|
||||
|
||||
render_recipe(recipe, buf);
|
||||
render_ingredients(self.row_index, ingredients, buf);
|
||||
|
@ -39,8 +39,8 @@ impl Widget for TracerouteTab {
|
||||
Block::new().style(THEME.content).render(area, buf);
|
||||
let horizontal = Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]);
|
||||
let vertical = Layout::vertical([Constraint::Min(0), Constraint::Length(3)]);
|
||||
let [left, map] = horizontal.areas(area);
|
||||
let [hops, pings] = vertical.areas(left);
|
||||
let [left, map] = area.layout(&horizontal);
|
||||
let [hops, pings] = left.layout(&vertical);
|
||||
|
||||
render_hops(self.row_index, hops, buf);
|
||||
render_ping(self.row_index, pings, buf);
|
||||
|
@ -41,16 +41,16 @@ impl Widget for WeatherTab {
|
||||
horizontal: 2,
|
||||
vertical: 1,
|
||||
});
|
||||
let [main, _, gauges] = Layout::vertical([
|
||||
let tab_layout = Layout::vertical([
|
||||
Constraint::Min(0),
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(1),
|
||||
])
|
||||
.areas(area);
|
||||
let [calendar, charts] =
|
||||
Layout::horizontal([Constraint::Length(23), Constraint::Min(0)]).areas(main);
|
||||
let [simple, horizontal] =
|
||||
Layout::vertical([Constraint::Length(29), Constraint::Min(0)]).areas(charts);
|
||||
]);
|
||||
let [main, _, gauges] = area.layout(&tab_layout);
|
||||
let main_layout = Layout::horizontal([Constraint::Length(23), Constraint::Min(0)]);
|
||||
let [calendar, charts] = main.layout(&main_layout);
|
||||
let charts_layout = Layout::vertical([Constraint::Length(29), Constraint::Min(0)]);
|
||||
let [simple, horizontal] = charts.layout(&charts_layout);
|
||||
|
||||
render_calendar(calendar, buf);
|
||||
render_simple_barchart(simple, buf);
|
||||
|
@ -256,7 +256,7 @@ fn example_height() -> u16 {
|
||||
impl Widget for App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let layout = Layout::vertical([Length(3), Length(1), Fill(0)]);
|
||||
let [tabs, axis, demo] = layout.areas(area);
|
||||
let [tabs, axis, demo] = area.layout(&layout);
|
||||
self.tabs().render(tabs, buf);
|
||||
let scroll_needed = self.render_demo(demo, buf);
|
||||
let axis_width = if scroll_needed {
|
||||
@ -421,7 +421,7 @@ 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 [title, illustrations] = area.layout(&layout);
|
||||
|
||||
let (blocks, spacers) = Layout::horizontal(&self.constraints)
|
||||
.flex(self.flex)
|
||||
|
@ -103,10 +103,10 @@ impl Widget for &App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
use Constraint::{Length, Min, Ratio};
|
||||
let layout = Layout::vertical([Length(2), Min(0), Length(1)]);
|
||||
let [header_area, gauge_area, footer_area] = layout.areas(area);
|
||||
let [header_area, gauge_area, footer_area] = area.layout(&layout);
|
||||
|
||||
let layout = Layout::vertical([Ratio(1, 4); 4]);
|
||||
let [gauge1_area, gauge2_area, gauge3_area, gauge4_area] = layout.areas(gauge_area);
|
||||
let [gauge1_area, gauge2_area, gauge3_area, gauge4_area] = gauge_area.layout(&layout);
|
||||
|
||||
render_header(header_area, buf);
|
||||
render_footer(footer_area, buf);
|
||||
|
@ -230,8 +230,8 @@ fn render(frame: &mut Frame, downloads: &Downloads) {
|
||||
|
||||
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);
|
||||
let [progress_area, main] = area.layout(&vertical);
|
||||
let [list_area, gauge_area] = main.layout(&horizontal);
|
||||
|
||||
// total progress
|
||||
let done = NUM_DOWNLOADS - downloads.pending.len() - downloads.in_progress.len();
|
||||
|
@ -115,8 +115,8 @@ impl InputForm {
|
||||
///
|
||||
/// The cursor is placed at the end of the focused field.
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let [first_name_area, last_name_area, age_area] =
|
||||
Layout::vertical(Constraint::from_lengths([1, 1, 1])).areas(frame.area());
|
||||
let layout = Layout::vertical(Constraint::from_lengths([1, 1, 1]));
|
||||
let [first_name_area, last_name_area, age_area] = frame.area().layout(&layout);
|
||||
|
||||
frame.render_widget(&self.first_name, first_name_area);
|
||||
frame.render_widget(&self.last_name, last_name_area);
|
||||
@ -185,11 +185,11 @@ impl StringField {
|
||||
|
||||
impl Widget for &StringField {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let constraints = [
|
||||
let layout = Layout::horizontal([
|
||||
Constraint::Length(self.label.len() as u16 + 2),
|
||||
Constraint::Fill(1),
|
||||
];
|
||||
let [label_area, value_area] = Layout::horizontal(constraints).areas(area);
|
||||
]);
|
||||
let [label_area, value_area] = area.layout(&layout);
|
||||
let label = Line::from_iter([self.label, ": "]).bold();
|
||||
label.render(label_area, buf);
|
||||
self.value.clone().render(value_area, buf);
|
||||
@ -250,11 +250,11 @@ impl AgeField {
|
||||
|
||||
impl Widget for &AgeField {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let constraints = [
|
||||
let layout = Layout::horizontal([
|
||||
Constraint::Length(self.label.len() as u16 + 2),
|
||||
Constraint::Fill(1),
|
||||
];
|
||||
let [label_area, value_area] = Layout::horizontal(constraints).areas(area);
|
||||
]);
|
||||
let [label_area, value_area] = area.layout(&layout);
|
||||
let label = Line::from_iter([self.label, ": "]).bold();
|
||||
let value = self.value.to_string();
|
||||
label.render(label_area, buf);
|
||||
|
@ -33,8 +33,8 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
let [text_area, main_area] = vertical.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
let [text_area, main_area] = frame.area().layout(&layout);
|
||||
frame.render_widget(
|
||||
Paragraph::new("Note: not all terminals support all modifiers")
|
||||
.style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD)),
|
||||
|
@ -41,8 +41,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame, show_popup: bool) {
|
||||
let area = frame.area();
|
||||
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [instructions, content] = vertical.areas(area);
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [instructions, content] = area.layout(&layout);
|
||||
|
||||
frame.render_widget(
|
||||
Line::from("Press 'p' to toggle popup, 'q' to quit").centered(),
|
||||
@ -64,7 +64,7 @@ fn render(frame: &mut Frame, show_popup: bool) {
|
||||
fn centered_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);
|
||||
let [area] = area.layout(&vertical);
|
||||
let [area] = area.layout(&horizontal);
|
||||
area
|
||||
}
|
||||
|
@ -186,8 +186,8 @@ impl App {
|
||||
}
|
||||
|
||||
fn render(&mut self, frame: &mut Frame) {
|
||||
let vertical = &Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
|
||||
let rects = vertical.split(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Min(5), Constraint::Length(4)]);
|
||||
let rects = frame.area().layout_vec(&layout);
|
||||
|
||||
self.set_colors();
|
||||
|
||||
|
@ -178,15 +178,15 @@ impl App {
|
||||
|
||||
impl Widget for &mut App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let [header_area, main_area, footer_area] = Layout::vertical([
|
||||
let main_layout = Layout::vertical([
|
||||
Constraint::Length(2),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Length(1),
|
||||
])
|
||||
.areas(area);
|
||||
]);
|
||||
let [header_area, content_area, footer_area] = area.layout(&main_layout);
|
||||
|
||||
let [list_area, item_area] =
|
||||
Layout::vertical([Constraint::Fill(1), Constraint::Fill(1)]).areas(main_area);
|
||||
let content_layout = Layout::vertical([Constraint::Fill(1), Constraint::Fill(1)]);
|
||||
let [list_area, item_area] = content_area.layout(&content_layout);
|
||||
|
||||
App::render_header(header_area, buf);
|
||||
App::render_footer(footer_area, buf);
|
||||
|
@ -155,12 +155,12 @@ impl App {
|
||||
}
|
||||
|
||||
fn render(&self, frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([
|
||||
let layout = Layout::vertical([
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(3),
|
||||
Constraint::Min(1),
|
||||
]);
|
||||
let [help_area, input_area, messages_area] = vertical.areas(frame.area());
|
||||
let [help_area, input_area, messages_area] = frame.area().layout(&layout);
|
||||
|
||||
let (msg, style) = match self.input_mode {
|
||||
InputMode::Normal => (
|
||||
|
@ -32,9 +32,8 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
fn render(frame: &mut Frame, temperatures: &[u8]) {
|
||||
let [title, main] = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)])
|
||||
.spacing(1)
|
||||
.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [title, main] = frame.area().layout(&layout);
|
||||
|
||||
frame.render_widget("Weather demo".bold().into_centered_line(), title);
|
||||
frame.render_widget(vertical_barchart(temperatures), main);
|
||||
|
@ -1,5 +1,6 @@
|
||||
use alloc::rc::Rc;
|
||||
use alloc::vec::Vec;
|
||||
use core::array::TryFromSliceError;
|
||||
use core::iter;
|
||||
#[cfg(feature = "layout-cache")]
|
||||
use core::num::NonZeroUsize;
|
||||
@ -550,8 +551,43 @@ impl Layout {
|
||||
/// let areas = layout.areas::<2>(area);
|
||||
/// ```
|
||||
pub fn areas<const N: usize>(&self, area: Rect) -> [Rect; N] {
|
||||
let (areas, _) = self.split_with_spacers(area);
|
||||
areas.as_ref().try_into().expect("invalid number of rects")
|
||||
let areas = self.split(area);
|
||||
areas.as_ref().try_into().unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"invalid number of rects: expected {N}, found {}",
|
||||
areas.len()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
||||
///
|
||||
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
||||
/// `Rc<[Rect]>`.
|
||||
///
|
||||
/// This method requires the number of constraints to be known at compile time. If you don't
|
||||
/// know the number of constraints at compile time, use [`Layout::split`] instead.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the number of constraints is not equal to the length of the returned
|
||||
/// array.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
||||
///
|
||||
/// let area = Rect::new(0, 0, 10, 10);
|
||||
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
/// let [top, main] = layout.try_areas(area)?;
|
||||
///
|
||||
/// // or explicitly specify the number of constraints:
|
||||
/// let areas = layout.try_areas::<2>(area)?;
|
||||
/// # Ok::<(), core::array::TryFromSliceError>(())
|
||||
/// ```
|
||||
pub fn try_areas<const N: usize>(&self, area: Rect) -> Result<[Rect; N], TryFromSliceError> {
|
||||
self.split(area).as_ref().try_into()
|
||||
}
|
||||
|
||||
/// Split the rect into a number of sub-rects according to the given [`Layout`] and return just
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(missing_docs)]
|
||||
use core::array::TryFromSliceError;
|
||||
use core::cmp::{max, min};
|
||||
use core::fmt;
|
||||
|
||||
@ -482,9 +483,7 @@ impl Rect {
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn centered_horizontally(self, constraint: Constraint) -> Self {
|
||||
let [area] = Layout::horizontal([constraint])
|
||||
.flex(Flex::Center)
|
||||
.areas(self);
|
||||
let [area] = self.layout(&Layout::horizontal([constraint]).flex(Flex::Center));
|
||||
area
|
||||
}
|
||||
|
||||
@ -502,9 +501,7 @@ impl Rect {
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn centered_vertically(self, constraint: Constraint) -> Self {
|
||||
let [area] = Layout::vertical([constraint])
|
||||
.flex(Flex::Center)
|
||||
.areas(self);
|
||||
let [area] = self.layout(&Layout::vertical([constraint]).flex(Flex::Center));
|
||||
area
|
||||
}
|
||||
|
||||
@ -532,6 +529,99 @@ impl Rect {
|
||||
.centered_vertically(vertical_constraint)
|
||||
}
|
||||
|
||||
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
||||
///
|
||||
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
||||
/// `Rc<[Rect]>`.
|
||||
///
|
||||
/// This method requires the number of constraints to be known at compile time. If you don't
|
||||
/// know the number of constraints at compile time, use [`Layout::split`] instead.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the number of constraints is not equal to the length of the returned array.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
||||
///
|
||||
/// let area = Rect::new(0, 0, 10, 10);
|
||||
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
/// let [top, main] = area.layout(&layout);
|
||||
/// assert_eq!(top, Rect::new(0, 0, 10, 1));
|
||||
/// assert_eq!(main, Rect::new(0, 1, 10, 9));
|
||||
///
|
||||
/// // or explicitly specify the number of constraints:
|
||||
/// let areas = area.layout::<2>(&layout);
|
||||
/// assert_eq!(areas, [Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn layout<const N: usize>(self, layout: &Layout) -> [Self; N] {
|
||||
let areas = layout.split(self);
|
||||
areas.as_ref().try_into().unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"invalid number of rects: expected {N}, found {}",
|
||||
areas.len()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
||||
///
|
||||
/// An ergonomic wrapper around [`Layout::split`] that returns a [`Vec`] of `Rect`s instead of
|
||||
/// `Rc<[Rect]>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
||||
///
|
||||
/// let area = Rect::new(0, 0, 10, 10);
|
||||
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
/// let areas = area.layout_vec(&layout);
|
||||
/// assert_eq!(areas, vec![Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
||||
/// ```
|
||||
///
|
||||
/// [`Vec`]: alloc::vec::Vec
|
||||
#[must_use]
|
||||
pub fn layout_vec(self, layout: &Layout) -> alloc::vec::Vec<Self> {
|
||||
layout.split(self).as_ref().to_vec()
|
||||
}
|
||||
|
||||
/// Try to split the rect into a number of sub-rects according to the given [`Layout`].
|
||||
///
|
||||
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
||||
/// `Rc<[Rect]>`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the number of constraints is not equal to the length of the returned
|
||||
/// array.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
||||
///
|
||||
/// let area = Rect::new(0, 0, 10, 10);
|
||||
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
||||
/// let [top, main] = area.try_layout(&layout)?;
|
||||
/// assert_eq!(top, Rect::new(0, 0, 10, 1));
|
||||
/// assert_eq!(main, Rect::new(0, 1, 10, 9));
|
||||
///
|
||||
/// // or explicitly specify the number of constraints:
|
||||
/// let areas = area.try_layout::<2>(&layout)?;
|
||||
/// assert_eq!(areas, [Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
||||
/// # Ok::<(), core::array::TryFromSliceError>(())
|
||||
/// ``````
|
||||
pub fn try_layout<const N: usize>(
|
||||
self,
|
||||
layout: &Layout,
|
||||
) -> Result<[Self; N], TryFromSliceError> {
|
||||
layout.split(self).as_ref().try_into()
|
||||
}
|
||||
|
||||
/// indents the x value of the `Rect` by a given `offset`
|
||||
///
|
||||
/// This is pub(crate) for now as we need to stabilize the naming / design of this API.
|
||||
@ -892,4 +982,54 @@ mod tests {
|
||||
Rect::new(1, 2, 3, 1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout() {
|
||||
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
||||
|
||||
let [a, b] = Rect::new(0, 0, 10, 10).layout(&layout);
|
||||
assert_eq!(a, Rect::new(0, 0, 3, 10));
|
||||
assert_eq!(b, Rect::new(3, 0, 7, 10));
|
||||
|
||||
let areas = Rect::new(0, 0, 10, 10).layout::<2>(&layout);
|
||||
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
||||
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "invalid number of rects: expected 3, found 1")]
|
||||
fn layout_invalid_number_of_rects() {
|
||||
let layout = Layout::horizontal([Constraint::Length(1)]);
|
||||
let [_, _, _] = Rect::new(0, 0, 10, 10).layout(&layout);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_vec() {
|
||||
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
||||
|
||||
let areas = Rect::new(0, 0, 10, 10).layout_vec(&layout);
|
||||
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
||||
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_layout() {
|
||||
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
||||
|
||||
let [a, b] = Rect::new(0, 0, 10, 10).try_layout(&layout).unwrap();
|
||||
assert_eq!(a, Rect::new(0, 0, 3, 10));
|
||||
assert_eq!(b, Rect::new(3, 0, 7, 10));
|
||||
|
||||
let areas = Rect::new(0, 0, 10, 10).try_layout::<2>(&layout).unwrap();
|
||||
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
||||
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_layout_invalid_number_of_rects() {
|
||||
let layout = Layout::horizontal([Constraint::Length(1)]);
|
||||
Rect::new(0, 0, 10, 10)
|
||||
.try_layout::<3>(&layout)
|
||||
.unwrap_err();
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Fill(1); 2]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [left, right] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [left, right] = main.layout(&horizontal);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("BarChart Widget (Grouped)").bold(),
|
||||
|
@ -38,8 +38,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Length(28), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [left, right] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [left, right] = main.layout(&horizontal);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("BarChart Widget").bold(),
|
||||
|
@ -38,8 +38,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Percentage(33); 3]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [left, middle, right] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [left, middle, right] = main.layout(&horizontal);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Block Widget").bold(),
|
||||
|
@ -40,8 +40,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Percentage(50); 2]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [left, right] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [left, right] = main.layout(&horizontal);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Calendar Widget").bold(),
|
||||
|
@ -40,8 +40,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Percentage(100)]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [area] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [area] = main.layout(&horizontal);
|
||||
|
||||
let title = TextLine::from_iter([
|
||||
Span::from("Canvas Widget").bold(),
|
||||
|
@ -37,8 +37,8 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Render the UI with a chart.
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Chart Widget").bold(),
|
||||
|
@ -36,13 +36,13 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Render the UI with various progress bars.
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([
|
||||
let constraints = [
|
||||
Constraint::Length(1),
|
||||
Constraint::Max(2),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.spacing(1);
|
||||
let [top, first, second] = vertical.areas(frame.area());
|
||||
];
|
||||
let layout = Layout::vertical(constraints).spacing(1);
|
||||
let [top, first, second] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Gauge Widget").bold(),
|
||||
|
@ -98,10 +98,10 @@ impl App {
|
||||
impl Widget for &App {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let layout = Layout::vertical([Length(3), Min(0)]);
|
||||
let [header_area, main_area] = layout.areas(area);
|
||||
let [header_area, main_area] = area.layout(&layout);
|
||||
|
||||
let [gauge1_area, gauge4_area, gauge6_area] =
|
||||
Layout::vertical([Length(2); 3]).areas(main_area);
|
||||
let gauges_layout = Layout::vertical([Length(2); 3]);
|
||||
let [gauge1_area, gauge4_area, gauge6_area] = main_area.layout(&gauges_layout);
|
||||
|
||||
header(header_area, buf);
|
||||
|
||||
@ -112,7 +112,7 @@ impl Widget for &App {
|
||||
}
|
||||
|
||||
fn header(area: Rect, buf: &mut Buffer) {
|
||||
let [p1_area, p2_area] = Layout::vertical([Length(1), Min(1)]).areas(area);
|
||||
let [p1_area, p2_area] = area.layout(&Layout::vertical([Length(1), Min(1)]));
|
||||
Paragraph::new("LineGauge Example")
|
||||
.bold()
|
||||
.centered()
|
||||
|
@ -42,13 +42,13 @@ fn main() -> color_eyre::Result<()> {
|
||||
|
||||
/// Render the UI with various lists.
|
||||
fn render(frame: &mut Frame, list_state: &mut ListState) {
|
||||
let vertical = Layout::vertical([
|
||||
let constraints = [
|
||||
Constraint::Length(1),
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.spacing(1);
|
||||
let [top, first, second] = vertical.areas(frame.area());
|
||||
];
|
||||
let layout = Layout::vertical(constraints).spacing(1);
|
||||
let [top, first, second] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("List Widget").bold(),
|
||||
|
@ -50,8 +50,8 @@ fn run(mut terminal: DefaultTerminal, size: RatatuiLogoSize) -> Result<()> {
|
||||
|
||||
/// Render the UI with a logo.
|
||||
fn render(frame: &mut Frame, size: RatatuiLogoSize) {
|
||||
let [top, bottom] =
|
||||
Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
||||
let [top, bottom] = frame.area().layout(&layout);
|
||||
|
||||
frame.render_widget("Powered by", top);
|
||||
frame.render_widget(RatatuiLogo::new(size), bottom);
|
||||
|
@ -38,8 +38,8 @@ fn main() -> Result<()> {
|
||||
fn render(frame: &mut Frame) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let horizontal = Layout::horizontal([Constraint::Percentage(50); 2]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let [first, second] = horizontal.areas(main);
|
||||
let [top, main] = frame.area().layout(&vertical);
|
||||
let [first, second] = main.layout(&horizontal);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Paragraph Widget").bold(),
|
||||
|
@ -47,8 +47,8 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Render the UI with vertical/horizontal scrollbars.
|
||||
fn render(frame: &mut Frame, vertical: &mut ScrollbarState, horizontal: &mut ScrollbarState) {
|
||||
let vertical_layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = vertical_layout.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Scrollbar Widget").bold(),
|
||||
|
@ -45,7 +45,8 @@ fn render(frame: &mut Frame) {
|
||||
Constraint::Fill(1),
|
||||
Constraint::Fill(1),
|
||||
];
|
||||
let [top, first, second, _] = Layout::vertical(constraints).spacing(1).areas(frame.area());
|
||||
let layout = Layout::vertical(constraints).spacing(1);
|
||||
let [top, first, second, _] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Sparkline Widget").bold(),
|
||||
|
@ -49,8 +49,8 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Render the UI with a table.
|
||||
fn render(frame: &mut Frame, table_state: &mut TableState) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Table Widget").bold(),
|
||||
|
@ -43,8 +43,8 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Render the UI with tabs.
|
||||
fn render(frame: &mut Frame, selected_tab: usize) {
|
||||
let vertical = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = vertical.areas(frame.area());
|
||||
let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]).spacing(1);
|
||||
let [top, main] = frame.area().layout(&layout);
|
||||
|
||||
let title = Line::from_iter([
|
||||
Span::from("Tabs Widget").bold(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user