[go: up one dir, main page]

Struct Rect

Source
pub struct Rect {
    pub x: u16,
    pub y: u16,
    pub width: u16,
    pub height: u16,
}
Expand description

A Rectangular area.

A simple rectangle used in the computation of the layout and to give widgets a hint about the area they are supposed to render to.

Fields§

§x: u16

The x coordinate of the top left corner of the Rect.

§y: u16

The y coordinate of the top left corner of the Rect.

§width: u16

The width of the Rect.

§height: u16

The height of the Rect.

Implementations§

Source§

impl Rect

Source

pub const ZERO: Self

A zero sized Rect at position 0,0

Source

pub const fn new(x: u16, y: u16, width: u16, height: u16) -> Self

Creates a new Rect, with width and height limited to keep both bounds within u16.

If the width or height would cause the right or bottom coordinate to be larger than the maximum value of u16, the width or height will be clamped to keep the right or bottom coordinate within u16.

§Examples
use ratatui::layout::Rect;

let rect = Rect::new(1, 2, 3, 4);
Examples found in repository?
examples/canvas.rs (line 75)
64    const fn new() -> Self {
65        Self {
66            exit: false,
67            x: 0.0,
68            y: 0.0,
69            ball: Circle {
70                x: 20.0,
71                y: 40.0,
72                radius: 10.0,
73                color: Color::Yellow,
74            },
75            playground: Rect::new(10, 10, 200, 100),
76            vx: 1.0,
77            vy: 1.0,
78            tick_count: 0,
79            marker: Marker::Dot,
80            points: vec![],
81            is_drawing: false,
82        }
83    }
More examples
Hide additional examples
examples/demo2/main.rs (line 47)
43fn main() -> Result<()> {
44    color_eyre::install()?;
45    // this size is to match the size of the terminal when running the demo
46    // using vhs in a 1280x640 sized window (github social preview size)
47    let viewport = Viewport::Fixed(Rect::new(0, 0, 81, 18));
48    let terminal = ratatui::init_with_options(TerminalOptions { viewport });
49    execute!(stdout(), EnterAlternateScreen).expect("failed to enter alternate screen");
50    let app_result = App::default().run(terminal);
51    execute!(stdout(), LeaveAlternateScreen).expect("failed to leave alternate screen");
52    ratatui::restore();
53    app_result
54}
examples/flex.rs (line 312)
307    fn render_demo(self, area: Rect, buf: &mut Buffer) -> bool {
308        // render demo content into a separate buffer so all examples fit we add an extra
309        // area.height to make sure the last example is fully visible even when the scroll offset is
310        // at the max
311        let height = example_height();
312        let demo_area = Rect::new(0, 0, area.width, height);
313        let mut demo_buf = Buffer::empty(demo_area);
314
315        let scrollbar_needed = self.scroll_offset != 0 || height > area.height;
316        let content_area = if scrollbar_needed {
317            Rect {
318                width: demo_area.width - 1,
319                ..demo_area
320            }
321        } else {
322            demo_area
323        };
324
325        let mut spacing = self.spacing;
326        self.selected_tab
327            .render(content_area, &mut demo_buf, &mut spacing);
328
329        let visible_content = demo_buf
330            .content
331            .into_iter()
332            .skip((area.width * self.scroll_offset) as usize)
333            .take(area.area() as usize);
334        for (i, cell) in visible_content.enumerate() {
335            let x = i as u16 % area.width;
336            let y = i as u16 / area.width;
337            buf[(area.x + x, area.y + y)] = cell;
338        }
339
340        if scrollbar_needed {
341            let area = area.intersection(buf.area);
342            let mut state = ScrollbarState::new(max_scroll_offset() as usize)
343                .position(self.scroll_offset as usize);
344            Scrollbar::new(ScrollbarOrientation::VerticalRight).render(area, buf, &mut state);
345        }
346        scrollbar_needed
347    }
Source

pub const fn area(self) -> u32

The area of the Rect. If the area is larger than the maximum value of u16, it will be clamped to u16::MAX.

Examples found in repository?
examples/flex.rs (line 333)
307    fn render_demo(self, area: Rect, buf: &mut Buffer) -> bool {
308        // render demo content into a separate buffer so all examples fit we add an extra
309        // area.height to make sure the last example is fully visible even when the scroll offset is
310        // at the max
311        let height = example_height();
312        let demo_area = Rect::new(0, 0, area.width, height);
313        let mut demo_buf = Buffer::empty(demo_area);
314
315        let scrollbar_needed = self.scroll_offset != 0 || height > area.height;
316        let content_area = if scrollbar_needed {
317            Rect {
318                width: demo_area.width - 1,
319                ..demo_area
320            }
321        } else {
322            demo_area
323        };
324
325        let mut spacing = self.spacing;
326        self.selected_tab
327            .render(content_area, &mut demo_buf, &mut spacing);
328
329        let visible_content = demo_buf
330            .content
331            .into_iter()
332            .skip((area.width * self.scroll_offset) as usize)
333            .take(area.area() as usize);
334        for (i, cell) in visible_content.enumerate() {
335            let x = i as u16 % area.width;
336            let y = i as u16 / area.width;
337            buf[(area.x + x, area.y + y)] = cell;
338        }
339
340        if scrollbar_needed {
341            let area = area.intersection(buf.area);
342            let mut state = ScrollbarState::new(max_scroll_offset() as usize)
343                .position(self.scroll_offset as usize);
344            Scrollbar::new(ScrollbarOrientation::VerticalRight).render(area, buf, &mut state);
345        }
346        scrollbar_needed
347    }
Source

pub const fn is_empty(self) -> bool

Returns true if the Rect has no area.

Source

pub const fn left(self) -> u16

Returns the left coordinate of the Rect.

Examples found in repository?
examples/widget_impl.rs (line 254)
251fn fill<S: Into<Style>>(area: Rect, buf: &mut Buffer, symbol: &str, style: S) {
252    let style = style.into();
253    for y in area.top()..area.bottom() {
254        for x in area.left()..area.right() {
255            buf[(x, y)].set_symbol(symbol).set_style(style);
256        }
257    }
258}
More examples
Hide additional examples
examples/demo2/colors.rs (line 18)
13    fn render(self, area: Rect, buf: &mut Buffer) {
14        for (yi, y) in (area.top()..area.bottom()).enumerate() {
15            let value = f32::from(area.height) - yi as f32;
16            let value_fg = value / f32::from(area.height);
17            let value_bg = (value - 0.5) / f32::from(area.height);
18            for (xi, x) in (area.left()..area.right()).enumerate() {
19                let hue = xi as f32 * 360.0 / f32::from(area.width);
20                let fg = color_from_oklab(hue, Okhsv::max_saturation(), value_fg);
21                let bg = color_from_oklab(hue, Okhsv::max_saturation(), value_bg);
22                buf[(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
23            }
24        }
25    }
examples/colors_rgb.rs (line 209)
206    fn render(self, area: Rect, buf: &mut Buffer) {
207        self.setup_colors(area);
208        let colors = &self.colors;
209        for (xi, x) in (area.left()..area.right()).enumerate() {
210            // animate the colors by shifting the x index by the frame number
211            let xi = (xi + self.frame_count) % (area.width as usize);
212            for (yi, y) in (area.top()..area.bottom()).enumerate() {
213                // render a half block character for each row of pixels with the foreground color
214                // set to the color of the pixel and the background color set to the color of the
215                // pixel below it
216                let fg = colors[yi * 2][xi];
217                let bg = colors[yi * 2 + 1][xi];
218                buf[Position::new(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
219            }
220        }
221        self.frame_count += 1;
222    }
examples/canvas.rs (line 147)
132    fn on_tick(&mut self) {
133        self.tick_count += 1;
134        // only change marker every 180 ticks (3s) to avoid stroboscopic effect
135        if (self.tick_count % 180) == 0 {
136            self.marker = match self.marker {
137                Marker::Dot => Marker::Braille,
138                Marker::Braille => Marker::Block,
139                Marker::Block => Marker::HalfBlock,
140                Marker::HalfBlock => Marker::Bar,
141                Marker::Bar => Marker::Dot,
142            };
143        }
144        // bounce the ball by flipping the velocity vector
145        let ball = &self.ball;
146        let playground = self.playground;
147        if ball.x - ball.radius < f64::from(playground.left())
148            || ball.x + ball.radius > f64::from(playground.right())
149        {
150            self.vx = -self.vx;
151        }
152        if ball.y - ball.radius < f64::from(playground.top())
153            || ball.y + ball.radius > f64::from(playground.bottom())
154        {
155            self.vy = -self.vy;
156        }
157
158        self.ball.x += self.vx;
159        self.ball.y += self.vy;
160    }
161
162    fn draw(&self, frame: &mut Frame) {
163        let horizontal =
164            Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
165        let vertical = Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]);
166        let [left, right] = horizontal.areas(frame.area());
167        let [draw, map] = vertical.areas(left);
168        let [pong, boxes] = vertical.areas(right);
169
170        frame.render_widget(self.map_canvas(), map);
171        frame.render_widget(self.draw_canvas(draw), draw);
172        frame.render_widget(self.pong_canvas(), pong);
173        frame.render_widget(self.boxes_canvas(boxes), boxes);
174    }
175
176    fn map_canvas(&self) -> impl Widget + '_ {
177        Canvas::default()
178            .block(Block::bordered().title("World"))
179            .marker(self.marker)
180            .paint(|ctx| {
181                ctx.draw(&Map {
182                    color: Color::Green,
183                    resolution: MapResolution::High,
184                });
185                ctx.print(self.x, -self.y, "You are here".yellow());
186            })
187            .x_bounds([-180.0, 180.0])
188            .y_bounds([-90.0, 90.0])
189    }
190
191    fn draw_canvas(&self, area: Rect) -> impl Widget + '_ {
192        Canvas::default()
193            .block(Block::bordered().title("Draw here"))
194            .marker(self.marker)
195            .x_bounds([0.0, f64::from(area.width)])
196            .y_bounds([0.0, f64::from(area.height)])
197            .paint(move |ctx| {
198                let points = self
199                    .points
200                    .iter()
201                    .map(|p| {
202                        (
203                            f64::from(p.x) - f64::from(area.left()),
204                            f64::from(area.bottom()) - f64::from(p.y),
205                        )
206                    })
207                    .collect_vec();
208                ctx.draw(&Points {
209                    coords: &points,
210                    color: Color::White,
211                });
212            })
213    }
examples/demo2/destroy.rs (line 57)
42fn drip(frame_count: usize, area: Rect, buf: &mut Buffer) {
43    // a seeded rng as we have to move the same random pixels each frame
44    let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
45    let ramp_frames = 450;
46    let fractional_speed = frame_count as f64 / f64::from(ramp_frames);
47    let variable_speed = DRIP_SPEED as f64 * fractional_speed * fractional_speed * fractional_speed;
48    let pixel_count = (frame_count as f64 * variable_speed).floor() as usize;
49    for _ in 0..pixel_count {
50        let src_x = rng.gen_range(0..area.width);
51        let src_y = rng.gen_range(1..area.height - 2);
52        let src = buf[(src_x, src_y)].clone();
53        // 1% of the time, move a blank or pixel (10:1) to the top line of the screen
54        if rng.gen_ratio(1, 100) {
55            let dest_x = rng
56                .gen_range(src_x.saturating_sub(5)..src_x.saturating_add(5))
57                .clamp(area.left(), area.right() - 1);
58            let dest_y = area.top() + 1;
59
60            let dest = &mut buf[(dest_x, dest_y)];
61            // copy the cell to the new location about 1/10 of the time blank out the cell the rest
62            // of the time. This has the effect of gradually removing the pixels from the screen.
63            if rng.gen_ratio(1, 10) {
64                *dest = src;
65            } else {
66                dest.reset();
67            }
68        } else {
69            // move the pixel down one row
70            let dest_x = src_x;
71            let dest_y = src_y.saturating_add(1).min(area.bottom() - 2);
72            // copy the cell to the new location
73            buf[(dest_x, dest_y)] = src;
74        }
75    }
76}
examples/demo2/tabs/about.rs (line 117)
105pub fn render_logo(selected_row: usize, area: Rect, buf: &mut Buffer) {
106    let eye_color = if selected_row % 2 == 0 {
107        THEME.logo.rat_eye
108    } else {
109        THEME.logo.rat_eye_alt
110    };
111    let area = area.inner(Margin {
112        vertical: 0,
113        horizontal: 2,
114    });
115    for (y, (line1, line2)) in RATATUI_LOGO.iter().tuples().enumerate() {
116        for (x, (ch1, ch2)) in line1.chars().zip(line2.chars()).enumerate() {
117            let x = area.left() + x as u16;
118            let y = area.top() + y as u16;
119            let cell = &mut buf[(x, y)];
120            let rat_color = THEME.logo.rat;
121            let term_color = THEME.logo.term;
122            match (ch1, ch2) {
123                ('█', '█') => {
124                    cell.set_char('█');
125                    cell.fg = rat_color;
126                    cell.bg = rat_color;
127                }
128                ('█', ' ') => {
129                    cell.set_char('▀');
130                    cell.fg = rat_color;
131                }
132                (' ', '█') => {
133                    cell.set_char('▄');
134                    cell.fg = rat_color;
135                }
136                ('█', 'x') => {
137                    cell.set_char('▀');
138                    cell.fg = rat_color;
139                    cell.bg = term_color;
140                }
141                ('x', '█') => {
142                    cell.set_char('▄');
143                    cell.fg = rat_color;
144                    cell.bg = term_color;
145                }
146                ('x', 'x') => {
147                    cell.set_char(' ');
148                    cell.fg = term_color;
149                    cell.bg = term_color;
150                }
151                ('█', 'e') => {
152                    cell.set_char('▀');
153                    cell.fg = rat_color;
154                    cell.bg = eye_color;
155                }
156                ('e', '█') => {
157                    cell.set_char('▄');
158                    cell.fg = rat_color;
159                    cell.bg = eye_color;
160                }
161                (_, _) => {}
162            };
163        }
164    }
165}
Source

pub const fn right(self) -> u16

Returns the right coordinate of the Rect. This is the first coordinate outside of the Rect.

If the right coordinate is larger than the maximum value of u16, it will be clamped to u16::MAX.

Examples found in repository?
examples/widget_impl.rs (line 239)
237    fn render(self, area: Rect, buf: &mut Buffer) {
238        const WIDTH: u16 = 4;
239        let x = area.right() - WIDTH; // Align to the right
240        self.last_position = Position { x, y: area.y };
241        let size = Size::new(WIDTH, area.height);
242        let area = Rect::from((self.last_position, size));
243        fill(area, buf, "█", Color::Green);
244    }
245}
246
247/// Fill the area with the specified symbol and style.
248///
249/// This probably should be a method on the `Buffer` type, but it is defined here for simplicity.
250/// <https://github.com/ratatui-org/ratatui/issues/1146>
251fn fill<S: Into<Style>>(area: Rect, buf: &mut Buffer, symbol: &str, style: S) {
252    let style = style.into();
253    for y in area.top()..area.bottom() {
254        for x in area.left()..area.right() {
255            buf[(x, y)].set_symbol(symbol).set_style(style);
256        }
257    }
258}
More examples
Hide additional examples
examples/demo2/colors.rs (line 18)
13    fn render(self, area: Rect, buf: &mut Buffer) {
14        for (yi, y) in (area.top()..area.bottom()).enumerate() {
15            let value = f32::from(area.height) - yi as f32;
16            let value_fg = value / f32::from(area.height);
17            let value_bg = (value - 0.5) / f32::from(area.height);
18            for (xi, x) in (area.left()..area.right()).enumerate() {
19                let hue = xi as f32 * 360.0 / f32::from(area.width);
20                let fg = color_from_oklab(hue, Okhsv::max_saturation(), value_fg);
21                let bg = color_from_oklab(hue, Okhsv::max_saturation(), value_bg);
22                buf[(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
23            }
24        }
25    }
examples/colors_rgb.rs (line 209)
206    fn render(self, area: Rect, buf: &mut Buffer) {
207        self.setup_colors(area);
208        let colors = &self.colors;
209        for (xi, x) in (area.left()..area.right()).enumerate() {
210            // animate the colors by shifting the x index by the frame number
211            let xi = (xi + self.frame_count) % (area.width as usize);
212            for (yi, y) in (area.top()..area.bottom()).enumerate() {
213                // render a half block character for each row of pixels with the foreground color
214                // set to the color of the pixel and the background color set to the color of the
215                // pixel below it
216                let fg = colors[yi * 2][xi];
217                let bg = colors[yi * 2 + 1][xi];
218                buf[Position::new(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
219            }
220        }
221        self.frame_count += 1;
222    }
examples/canvas.rs (line 148)
132    fn on_tick(&mut self) {
133        self.tick_count += 1;
134        // only change marker every 180 ticks (3s) to avoid stroboscopic effect
135        if (self.tick_count % 180) == 0 {
136            self.marker = match self.marker {
137                Marker::Dot => Marker::Braille,
138                Marker::Braille => Marker::Block,
139                Marker::Block => Marker::HalfBlock,
140                Marker::HalfBlock => Marker::Bar,
141                Marker::Bar => Marker::Dot,
142            };
143        }
144        // bounce the ball by flipping the velocity vector
145        let ball = &self.ball;
146        let playground = self.playground;
147        if ball.x - ball.radius < f64::from(playground.left())
148            || ball.x + ball.radius > f64::from(playground.right())
149        {
150            self.vx = -self.vx;
151        }
152        if ball.y - ball.radius < f64::from(playground.top())
153            || ball.y + ball.radius > f64::from(playground.bottom())
154        {
155            self.vy = -self.vy;
156        }
157
158        self.ball.x += self.vx;
159        self.ball.y += self.vy;
160    }
examples/demo2/destroy.rs (line 57)
42fn drip(frame_count: usize, area: Rect, buf: &mut Buffer) {
43    // a seeded rng as we have to move the same random pixels each frame
44    let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
45    let ramp_frames = 450;
46    let fractional_speed = frame_count as f64 / f64::from(ramp_frames);
47    let variable_speed = DRIP_SPEED as f64 * fractional_speed * fractional_speed * fractional_speed;
48    let pixel_count = (frame_count as f64 * variable_speed).floor() as usize;
49    for _ in 0..pixel_count {
50        let src_x = rng.gen_range(0..area.width);
51        let src_y = rng.gen_range(1..area.height - 2);
52        let src = buf[(src_x, src_y)].clone();
53        // 1% of the time, move a blank or pixel (10:1) to the top line of the screen
54        if rng.gen_ratio(1, 100) {
55            let dest_x = rng
56                .gen_range(src_x.saturating_sub(5)..src_x.saturating_add(5))
57                .clamp(area.left(), area.right() - 1);
58            let dest_y = area.top() + 1;
59
60            let dest = &mut buf[(dest_x, dest_y)];
61            // copy the cell to the new location about 1/10 of the time blank out the cell the rest
62            // of the time. This has the effect of gradually removing the pixels from the screen.
63            if rng.gen_ratio(1, 10) {
64                *dest = src;
65            } else {
66                dest.reset();
67            }
68        } else {
69            // move the pixel down one row
70            let dest_x = src_x;
71            let dest_y = src_y.saturating_add(1).min(area.bottom() - 2);
72            // copy the cell to the new location
73            buf[(dest_x, dest_y)] = src;
74        }
75    }
76}
Source

pub const fn top(self) -> u16

Returns the top coordinate of the Rect.

Examples found in repository?
examples/widget_impl.rs (line 253)
251fn fill<S: Into<Style>>(area: Rect, buf: &mut Buffer, symbol: &str, style: S) {
252    let style = style.into();
253    for y in area.top()..area.bottom() {
254        for x in area.left()..area.right() {
255            buf[(x, y)].set_symbol(symbol).set_style(style);
256        }
257    }
258}
More examples
Hide additional examples
examples/demo2/colors.rs (line 14)
13    fn render(self, area: Rect, buf: &mut Buffer) {
14        for (yi, y) in (area.top()..area.bottom()).enumerate() {
15            let value = f32::from(area.height) - yi as f32;
16            let value_fg = value / f32::from(area.height);
17            let value_bg = (value - 0.5) / f32::from(area.height);
18            for (xi, x) in (area.left()..area.right()).enumerate() {
19                let hue = xi as f32 * 360.0 / f32::from(area.width);
20                let fg = color_from_oklab(hue, Okhsv::max_saturation(), value_fg);
21                let bg = color_from_oklab(hue, Okhsv::max_saturation(), value_bg);
22                buf[(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
23            }
24        }
25    }
examples/colors_rgb.rs (line 212)
206    fn render(self, area: Rect, buf: &mut Buffer) {
207        self.setup_colors(area);
208        let colors = &self.colors;
209        for (xi, x) in (area.left()..area.right()).enumerate() {
210            // animate the colors by shifting the x index by the frame number
211            let xi = (xi + self.frame_count) % (area.width as usize);
212            for (yi, y) in (area.top()..area.bottom()).enumerate() {
213                // render a half block character for each row of pixels with the foreground color
214                // set to the color of the pixel and the background color set to the color of the
215                // pixel below it
216                let fg = colors[yi * 2][xi];
217                let bg = colors[yi * 2 + 1][xi];
218                buf[Position::new(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
219            }
220        }
221        self.frame_count += 1;
222    }
examples/canvas.rs (line 152)
132    fn on_tick(&mut self) {
133        self.tick_count += 1;
134        // only change marker every 180 ticks (3s) to avoid stroboscopic effect
135        if (self.tick_count % 180) == 0 {
136            self.marker = match self.marker {
137                Marker::Dot => Marker::Braille,
138                Marker::Braille => Marker::Block,
139                Marker::Block => Marker::HalfBlock,
140                Marker::HalfBlock => Marker::Bar,
141                Marker::Bar => Marker::Dot,
142            };
143        }
144        // bounce the ball by flipping the velocity vector
145        let ball = &self.ball;
146        let playground = self.playground;
147        if ball.x - ball.radius < f64::from(playground.left())
148            || ball.x + ball.radius > f64::from(playground.right())
149        {
150            self.vx = -self.vx;
151        }
152        if ball.y - ball.radius < f64::from(playground.top())
153            || ball.y + ball.radius > f64::from(playground.bottom())
154        {
155            self.vy = -self.vy;
156        }
157
158        self.ball.x += self.vx;
159        self.ball.y += self.vy;
160    }
examples/demo2/destroy.rs (line 58)
42fn drip(frame_count: usize, area: Rect, buf: &mut Buffer) {
43    // a seeded rng as we have to move the same random pixels each frame
44    let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
45    let ramp_frames = 450;
46    let fractional_speed = frame_count as f64 / f64::from(ramp_frames);
47    let variable_speed = DRIP_SPEED as f64 * fractional_speed * fractional_speed * fractional_speed;
48    let pixel_count = (frame_count as f64 * variable_speed).floor() as usize;
49    for _ in 0..pixel_count {
50        let src_x = rng.gen_range(0..area.width);
51        let src_y = rng.gen_range(1..area.height - 2);
52        let src = buf[(src_x, src_y)].clone();
53        // 1% of the time, move a blank or pixel (10:1) to the top line of the screen
54        if rng.gen_ratio(1, 100) {
55            let dest_x = rng
56                .gen_range(src_x.saturating_sub(5)..src_x.saturating_add(5))
57                .clamp(area.left(), area.right() - 1);
58            let dest_y = area.top() + 1;
59
60            let dest = &mut buf[(dest_x, dest_y)];
61            // copy the cell to the new location about 1/10 of the time blank out the cell the rest
62            // of the time. This has the effect of gradually removing the pixels from the screen.
63            if rng.gen_ratio(1, 10) {
64                *dest = src;
65            } else {
66                dest.reset();
67            }
68        } else {
69            // move the pixel down one row
70            let dest_x = src_x;
71            let dest_y = src_y.saturating_add(1).min(area.bottom() - 2);
72            // copy the cell to the new location
73            buf[(dest_x, dest_y)] = src;
74        }
75    }
76}
examples/demo2/tabs/about.rs (line 118)
105pub fn render_logo(selected_row: usize, area: Rect, buf: &mut Buffer) {
106    let eye_color = if selected_row % 2 == 0 {
107        THEME.logo.rat_eye
108    } else {
109        THEME.logo.rat_eye_alt
110    };
111    let area = area.inner(Margin {
112        vertical: 0,
113        horizontal: 2,
114    });
115    for (y, (line1, line2)) in RATATUI_LOGO.iter().tuples().enumerate() {
116        for (x, (ch1, ch2)) in line1.chars().zip(line2.chars()).enumerate() {
117            let x = area.left() + x as u16;
118            let y = area.top() + y as u16;
119            let cell = &mut buf[(x, y)];
120            let rat_color = THEME.logo.rat;
121            let term_color = THEME.logo.term;
122            match (ch1, ch2) {
123                ('█', '█') => {
124                    cell.set_char('█');
125                    cell.fg = rat_color;
126                    cell.bg = rat_color;
127                }
128                ('█', ' ') => {
129                    cell.set_char('▀');
130                    cell.fg = rat_color;
131                }
132                (' ', '█') => {
133                    cell.set_char('▄');
134                    cell.fg = rat_color;
135                }
136                ('█', 'x') => {
137                    cell.set_char('▀');
138                    cell.fg = rat_color;
139                    cell.bg = term_color;
140                }
141                ('x', '█') => {
142                    cell.set_char('▄');
143                    cell.fg = rat_color;
144                    cell.bg = term_color;
145                }
146                ('x', 'x') => {
147                    cell.set_char(' ');
148                    cell.fg = term_color;
149                    cell.bg = term_color;
150                }
151                ('█', 'e') => {
152                    cell.set_char('▀');
153                    cell.fg = rat_color;
154                    cell.bg = eye_color;
155                }
156                ('e', '█') => {
157                    cell.set_char('▄');
158                    cell.fg = rat_color;
159                    cell.bg = eye_color;
160                }
161                (_, _) => {}
162            };
163        }
164    }
165}
Source

pub const fn bottom(self) -> u16

Returns the bottom coordinate of the Rect. This is the first coordinate outside of the Rect.

If the bottom coordinate is larger than the maximum value of u16, it will be clamped to u16::MAX.

Examples found in repository?
examples/widget_impl.rs (line 253)
251fn fill<S: Into<Style>>(area: Rect, buf: &mut Buffer, symbol: &str, style: S) {
252    let style = style.into();
253    for y in area.top()..area.bottom() {
254        for x in area.left()..area.right() {
255            buf[(x, y)].set_symbol(symbol).set_style(style);
256        }
257    }
258}
More examples
Hide additional examples
examples/demo2/colors.rs (line 14)
13    fn render(self, area: Rect, buf: &mut Buffer) {
14        for (yi, y) in (area.top()..area.bottom()).enumerate() {
15            let value = f32::from(area.height) - yi as f32;
16            let value_fg = value / f32::from(area.height);
17            let value_bg = (value - 0.5) / f32::from(area.height);
18            for (xi, x) in (area.left()..area.right()).enumerate() {
19                let hue = xi as f32 * 360.0 / f32::from(area.width);
20                let fg = color_from_oklab(hue, Okhsv::max_saturation(), value_fg);
21                let bg = color_from_oklab(hue, Okhsv::max_saturation(), value_bg);
22                buf[(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
23            }
24        }
25    }
examples/colors_rgb.rs (line 212)
206    fn render(self, area: Rect, buf: &mut Buffer) {
207        self.setup_colors(area);
208        let colors = &self.colors;
209        for (xi, x) in (area.left()..area.right()).enumerate() {
210            // animate the colors by shifting the x index by the frame number
211            let xi = (xi + self.frame_count) % (area.width as usize);
212            for (yi, y) in (area.top()..area.bottom()).enumerate() {
213                // render a half block character for each row of pixels with the foreground color
214                // set to the color of the pixel and the background color set to the color of the
215                // pixel below it
216                let fg = colors[yi * 2][xi];
217                let bg = colors[yi * 2 + 1][xi];
218                buf[Position::new(x, y)].set_char('▀').set_fg(fg).set_bg(bg);
219            }
220        }
221        self.frame_count += 1;
222    }
examples/canvas.rs (line 153)
132    fn on_tick(&mut self) {
133        self.tick_count += 1;
134        // only change marker every 180 ticks (3s) to avoid stroboscopic effect
135        if (self.tick_count % 180) == 0 {
136            self.marker = match self.marker {
137                Marker::Dot => Marker::Braille,
138                Marker::Braille => Marker::Block,
139                Marker::Block => Marker::HalfBlock,
140                Marker::HalfBlock => Marker::Bar,
141                Marker::Bar => Marker::Dot,
142            };
143        }
144        // bounce the ball by flipping the velocity vector
145        let ball = &self.ball;
146        let playground = self.playground;
147        if ball.x - ball.radius < f64::from(playground.left())
148            || ball.x + ball.radius > f64::from(playground.right())
149        {
150            self.vx = -self.vx;
151        }
152        if ball.y - ball.radius < f64::from(playground.top())
153            || ball.y + ball.radius > f64::from(playground.bottom())
154        {
155            self.vy = -self.vy;
156        }
157
158        self.ball.x += self.vx;
159        self.ball.y += self.vy;
160    }
161
162    fn draw(&self, frame: &mut Frame) {
163        let horizontal =
164            Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
165        let vertical = Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]);
166        let [left, right] = horizontal.areas(frame.area());
167        let [draw, map] = vertical.areas(left);
168        let [pong, boxes] = vertical.areas(right);
169
170        frame.render_widget(self.map_canvas(), map);
171        frame.render_widget(self.draw_canvas(draw), draw);
172        frame.render_widget(self.pong_canvas(), pong);
173        frame.render_widget(self.boxes_canvas(boxes), boxes);
174    }
175
176    fn map_canvas(&self) -> impl Widget + '_ {
177        Canvas::default()
178            .block(Block::bordered().title("World"))
179            .marker(self.marker)
180            .paint(|ctx| {
181                ctx.draw(&Map {
182                    color: Color::Green,
183                    resolution: MapResolution::High,
184                });
185                ctx.print(self.x, -self.y, "You are here".yellow());
186            })
187            .x_bounds([-180.0, 180.0])
188            .y_bounds([-90.0, 90.0])
189    }
190
191    fn draw_canvas(&self, area: Rect) -> impl Widget + '_ {
192        Canvas::default()
193            .block(Block::bordered().title("Draw here"))
194            .marker(self.marker)
195            .x_bounds([0.0, f64::from(area.width)])
196            .y_bounds([0.0, f64::from(area.height)])
197            .paint(move |ctx| {
198                let points = self
199                    .points
200                    .iter()
201                    .map(|p| {
202                        (
203                            f64::from(p.x) - f64::from(area.left()),
204                            f64::from(area.bottom()) - f64::from(p.y),
205                        )
206                    })
207                    .collect_vec();
208                ctx.draw(&Points {
209                    coords: &points,
210                    color: Color::White,
211                });
212            })
213    }
examples/demo2/destroy.rs (line 71)
42fn drip(frame_count: usize, area: Rect, buf: &mut Buffer) {
43    // a seeded rng as we have to move the same random pixels each frame
44    let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(10);
45    let ramp_frames = 450;
46    let fractional_speed = frame_count as f64 / f64::from(ramp_frames);
47    let variable_speed = DRIP_SPEED as f64 * fractional_speed * fractional_speed * fractional_speed;
48    let pixel_count = (frame_count as f64 * variable_speed).floor() as usize;
49    for _ in 0..pixel_count {
50        let src_x = rng.gen_range(0..area.width);
51        let src_y = rng.gen_range(1..area.height - 2);
52        let src = buf[(src_x, src_y)].clone();
53        // 1% of the time, move a blank or pixel (10:1) to the top line of the screen
54        if rng.gen_ratio(1, 100) {
55            let dest_x = rng
56                .gen_range(src_x.saturating_sub(5)..src_x.saturating_add(5))
57                .clamp(area.left(), area.right() - 1);
58            let dest_y = area.top() + 1;
59
60            let dest = &mut buf[(dest_x, dest_y)];
61            // copy the cell to the new location about 1/10 of the time blank out the cell the rest
62            // of the time. This has the effect of gradually removing the pixels from the screen.
63            if rng.gen_ratio(1, 10) {
64                *dest = src;
65            } else {
66                dest.reset();
67            }
68        } else {
69            // move the pixel down one row
70            let dest_x = src_x;
71            let dest_y = src_y.saturating_add(1).min(area.bottom() - 2);
72            // copy the cell to the new location
73            buf[(dest_x, dest_y)] = src;
74        }
75    }
76}
examples/inline.rs (line 279)
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 inner(self, margin: Margin) -> Self

Returns a new Rect inside the current one, with the given margin on each side.

If the margin is larger than the Rect, the returned Rect will have no area.

Examples found in repository?
examples/table.rs (lines 275-278)
269    fn render_scrollbar(&mut self, frame: &mut Frame, area: Rect) {
270        frame.render_stateful_widget(
271            Scrollbar::default()
272                .orientation(ScrollbarOrientation::VerticalRight)
273                .begin_symbol(None)
274                .end_symbol(None),
275            area.inner(Margin {
276                vertical: 1,
277                horizontal: 1,
278            }),
279            &mut self.scroll_state,
280        );
281    }
More examples
Hide additional examples
examples/demo2/tabs/email.rs (lines 71-74)
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    }
examples/demo2/tabs/traceroute.rs (lines 36-39)
34    fn render(self, area: Rect, buf: &mut Buffer) {
35        RgbSwatch.render(area, buf);
36        let area = area.inner(Margin {
37            vertical: 1,
38            horizontal: 2,
39        });
40        Clear.render(area, buf);
41        Block::new().style(THEME.content).render(area, buf);
42        let horizontal = Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]);
43        let vertical = Layout::vertical([Constraint::Min(0), Constraint::Length(3)]);
44        let [left, map] = horizontal.areas(area);
45        let [hops, pings] = vertical.areas(left);
46
47        render_hops(self.row_index, hops, buf);
48        render_ping(self.row_index, pings, buf);
49        render_map(self.row_index, map, buf);
50    }
examples/calendar.rs (lines 46-49)
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}
examples/demo2/tabs/about.rs (lines 71-74)
70fn render_crate_description(area: Rect, buf: &mut Buffer) {
71    let area = area.inner(Margin {
72        vertical: 4,
73        horizontal: 2,
74    });
75    Clear.render(area, buf); // clear out the color swatches
76    Block::new().style(THEME.content).render(area, buf);
77    let area = area.inner(Margin {
78        vertical: 1,
79        horizontal: 2,
80    });
81    let text = "- cooking up terminal user interfaces -
82
83    Ratatui is a Rust crate that provides widgets (e.g. Paragraph, Table) and draws them to the \
84    screen efficiently every frame.";
85    Paragraph::new(text)
86        .style(THEME.description)
87        .block(
88            Block::new()
89                .title(" Ratatui ")
90                .title_alignment(Alignment::Center)
91                .borders(Borders::TOP)
92                .border_style(THEME.description_title)
93                .padding(Padding::new(0, 0, 0, 0)),
94        )
95        .wrap(Wrap { trim: true })
96        .scroll((0, 0))
97        .render(area, buf);
98}
99
100/// Use half block characters to render a logo based on the `RATATUI_LOGO` const.
101///
102/// The logo is rendered in three colors, one for the rat, one for the terminal, and one for the
103/// rat's eye. The eye color alternates between two colors based on the selected row.
104#[allow(clippy::cast_possible_truncation)]
105pub fn render_logo(selected_row: usize, area: Rect, buf: &mut Buffer) {
106    let eye_color = if selected_row % 2 == 0 {
107        THEME.logo.rat_eye
108    } else {
109        THEME.logo.rat_eye_alt
110    };
111    let area = area.inner(Margin {
112        vertical: 0,
113        horizontal: 2,
114    });
115    for (y, (line1, line2)) in RATATUI_LOGO.iter().tuples().enumerate() {
116        for (x, (ch1, ch2)) in line1.chars().zip(line2.chars()).enumerate() {
117            let x = area.left() + x as u16;
118            let y = area.top() + y as u16;
119            let cell = &mut buf[(x, y)];
120            let rat_color = THEME.logo.rat;
121            let term_color = THEME.logo.term;
122            match (ch1, ch2) {
123                ('█', '█') => {
124                    cell.set_char('█');
125                    cell.fg = rat_color;
126                    cell.bg = rat_color;
127                }
128                ('█', ' ') => {
129                    cell.set_char('▀');
130                    cell.fg = rat_color;
131                }
132                (' ', '█') => {
133                    cell.set_char('▄');
134                    cell.fg = rat_color;
135                }
136                ('█', 'x') => {
137                    cell.set_char('▀');
138                    cell.fg = rat_color;
139                    cell.bg = term_color;
140                }
141                ('x', '█') => {
142                    cell.set_char('▄');
143                    cell.fg = rat_color;
144                    cell.bg = term_color;
145                }
146                ('x', 'x') => {
147                    cell.set_char(' ');
148                    cell.fg = term_color;
149                    cell.bg = term_color;
150                }
151                ('█', 'e') => {
152                    cell.set_char('▀');
153                    cell.fg = rat_color;
154                    cell.bg = eye_color;
155                }
156                ('e', '█') => {
157                    cell.set_char('▄');
158                    cell.fg = rat_color;
159                    cell.bg = eye_color;
160                }
161                (_, _) => {}
162            };
163        }
164    }
165}
examples/demo2/tabs/recipe.rs (lines 117-120)
115    fn render(self, area: Rect, buf: &mut Buffer) {
116        RgbSwatch.render(area, buf);
117        let area = area.inner(Margin {
118            vertical: 1,
119            horizontal: 2,
120        });
121        Clear.render(area, buf);
122        Block::new()
123            .title("Ratatouille Recipe".bold().white())
124            .title_alignment(Alignment::Center)
125            .style(THEME.content)
126            .padding(Padding::new(1, 1, 2, 1))
127            .render(area, buf);
128
129        let scrollbar_area = Rect {
130            y: area.y + 2,
131            height: area.height - 3,
132            ..area
133        };
134        render_scrollbar(self.row_index, scrollbar_area, buf);
135
136        let area = area.inner(Margin {
137            horizontal: 2,
138            vertical: 1,
139        });
140        let [recipe, ingredients] =
141            Layout::horizontal([Constraint::Length(44), Constraint::Min(0)]).areas(area);
142
143        render_recipe(recipe, buf);
144        render_ingredients(self.row_index, ingredients, buf);
145    }
Source

pub fn offset(self, offset: Offset) -> Self

Moves the Rect without modifying its size.

Moves the Rect according to the given offset without modifying its width or height.

  • Positive x moves the whole Rect to the right, negative to the left.
  • Positive y moves the whole Rect to the bottom, negative to the top.

See Offset for details.

Source

pub fn union(self, other: Self) -> Self

Returns a new Rect that contains both the current one and the given one.

Source

pub fn intersection(self, other: Self) -> Self

Returns a new Rect that is the intersection of the current one and the given one.

If the two Rects do not intersect, the returned Rect will have no area.

Examples found in repository?
examples/flex.rs (line 341)
307    fn render_demo(self, area: Rect, buf: &mut Buffer) -> bool {
308        // render demo content into a separate buffer so all examples fit we add an extra
309        // area.height to make sure the last example is fully visible even when the scroll offset is
310        // at the max
311        let height = example_height();
312        let demo_area = Rect::new(0, 0, area.width, height);
313        let mut demo_buf = Buffer::empty(demo_area);
314
315        let scrollbar_needed = self.scroll_offset != 0 || height > area.height;
316        let content_area = if scrollbar_needed {
317            Rect {
318                width: demo_area.width - 1,
319                ..demo_area
320            }
321        } else {
322            demo_area
323        };
324
325        let mut spacing = self.spacing;
326        self.selected_tab
327            .render(content_area, &mut demo_buf, &mut spacing);
328
329        let visible_content = demo_buf
330            .content
331            .into_iter()
332            .skip((area.width * self.scroll_offset) as usize)
333            .take(area.area() as usize);
334        for (i, cell) in visible_content.enumerate() {
335            let x = i as u16 % area.width;
336            let y = i as u16 / area.width;
337            buf[(area.x + x, area.y + y)] = cell;
338        }
339
340        if scrollbar_needed {
341            let area = area.intersection(buf.area);
342            let mut state = ScrollbarState::new(max_scroll_offset() as usize)
343                .position(self.scroll_offset as usize);
344            Scrollbar::new(ScrollbarOrientation::VerticalRight).render(area, buf, &mut state);
345        }
346        scrollbar_needed
347    }
Source

pub const fn intersects(self, other: Self) -> bool

Returns true if the two Rects intersect.

Source

pub const fn contains(self, position: Position) -> bool

Returns true if the given position is inside the Rect.

The position is considered inside the Rect if it is on the Rect’s border.

§Examples
use ratatui::layout::{Position, Rect};

let rect = Rect::new(1, 2, 3, 4);
assert!(rect.contains(Position { x: 1, y: 2 }));
Source

pub fn clamp(self, other: Self) -> Self

Clamp this Rect to fit inside the other Rect.

If the width or height of this Rect is larger than the other Rect, it will be clamped to the other Rect’s width or height.

If the left or top coordinate of this Rect is smaller than the other Rect, it will be clamped to the other Rect’s left or top coordinate.

If the right or bottom coordinate of this Rect is larger than the other Rect, it will be clamped to the other Rect’s right or bottom coordinate.

This is different from Rect::intersection because it will move this Rect to fit inside the other Rect, while Rect::intersection instead would keep this Rect’s position and truncate its size to only that which is inside the other Rect.

§Examples
use ratatui::{layout::Rect, Frame};

let area = frame.area();
let rect = Rect::new(0, 0, 100, 100).clamp(area);
Source

pub const fn rows(self) -> Rows

An iterator over rows within the Rect.

§Example
use ratatui::{buffer::Buffer, layout::Rect, text::Line, widgets::Widget};

fn render(area: Rect, buf: &mut Buffer) {
    for row in area.rows() {
        Line::raw("Hello, world!").render(row, buf);
    }
}
Examples found in repository?
examples/constraint-explorer.rs (line 480)
448    fn render_4px(&self, area: Rect, buf: &mut Buffer) {
449        let lighter_color = ConstraintName::from(self.constraint).lighter_color();
450        let main_color = ConstraintName::from(self.constraint).color();
451        let selected_color = if self.selected {
452            lighter_color
453        } else {
454            main_color
455        };
456        let color = if self.legend {
457            selected_color
458        } else {
459            main_color
460        };
461        let label = self.label(area.width);
462        let block = Block::bordered()
463            .border_set(symbols::border::QUADRANT_OUTSIDE)
464            .border_style(Style::reset().fg(color).reversed())
465            .fg(Self::TEXT_COLOR)
466            .bg(color);
467        Paragraph::new(label)
468            .centered()
469            .fg(Self::TEXT_COLOR)
470            .bg(color)
471            .block(block)
472            .render(area, buf);
473
474        if !self.legend {
475            let border_color = if self.selected {
476                lighter_color
477            } else {
478                main_color
479            };
480            if let Some(last_row) = area.rows().last() {
481                buf.set_style(last_row, border_color);
482            }
483        }
484    }
485}
486
487impl Widget for SpacerBlock {
488    fn render(self, area: Rect, buf: &mut Buffer) {
489        match area.height {
490            1 => (),
491            2 => Self::render_2px(area, buf),
492            3 => Self::render_3px(area, buf),
493            _ => Self::render_4px(area, buf),
494        }
495    }
496}
497
498impl SpacerBlock {
499    const TEXT_COLOR: Color = SLATE.c500;
500    const BORDER_COLOR: Color = SLATE.c600;
501
502    /// A block with a corner borders
503    fn block() -> impl Widget {
504        let corners_only = symbols::border::Set {
505            top_left: line::NORMAL.top_left,
506            top_right: line::NORMAL.top_right,
507            bottom_left: line::NORMAL.bottom_left,
508            bottom_right: line::NORMAL.bottom_right,
509            vertical_left: " ",
510            vertical_right: " ",
511            horizontal_top: " ",
512            horizontal_bottom: " ",
513        };
514        Block::bordered()
515            .border_set(corners_only)
516            .border_style(Self::BORDER_COLOR)
517    }
518
519    /// A vertical line used if there is not enough space to render the block
520    fn line() -> impl Widget {
521        Paragraph::new(Text::from(vec![
522            Line::from(""),
523            Line::from("│"),
524            Line::from("│"),
525            Line::from(""),
526        ]))
527        .style(Self::BORDER_COLOR)
528    }
529
530    /// A label that says "Spacer" if there is enough space
531    fn spacer_label(width: u16) -> impl Widget {
532        let label = if width >= 6 { "Spacer" } else { "" };
533        label.fg(Self::TEXT_COLOR).into_centered_line()
534    }
535
536    /// A label that says "8 px" if there is enough space
537    fn label(width: u16) -> impl Widget {
538        let long_label = format!("{width} px");
539        let short_label = format!("{width}");
540        let label = if long_label.len() < width as usize {
541            long_label
542        } else if short_label.len() < width as usize {
543            short_label
544        } else {
545            String::new()
546        };
547        Line::styled(label, Self::TEXT_COLOR).centered()
548    }
549
550    fn render_2px(area: Rect, buf: &mut Buffer) {
551        if area.width > 1 {
552            Self::block().render(area, buf);
553        } else {
554            Self::line().render(area, buf);
555        }
556    }
557
558    fn render_3px(area: Rect, buf: &mut Buffer) {
559        if area.width > 1 {
560            Self::block().render(area, buf);
561        } else {
562            Self::line().render(area, buf);
563        }
564
565        let row = area.rows().nth(1).unwrap_or_default();
566        Self::spacer_label(area.width).render(row, buf);
567    }
568
569    fn render_4px(area: Rect, buf: &mut Buffer) {
570        if area.width > 1 {
571            Self::block().render(area, buf);
572        } else {
573            Self::line().render(area, buf);
574        }
575
576        let row = area.rows().nth(1).unwrap_or_default();
577        Self::spacer_label(area.width).render(row, buf);
578
579        let row = area.rows().nth(2).unwrap_or_default();
580        Self::label(area.width).render(row, buf);
581    }
More examples
Hide additional examples
examples/demo2/destroy.rs (line 101)
80fn text(frame_count: usize, area: Rect, buf: &mut Buffer) {
81    let sub_frame = frame_count.saturating_sub(TEXT_DELAY);
82    if sub_frame == 0 {
83        return;
84    }
85
86    let logo = indoc::indoc! {"
87        ██████      ████    ██████    ████    ██████  ██    ██  ██
88        ██    ██  ██    ██    ██    ██    ██    ██    ██    ██  ██
89        ██████    ████████    ██    ████████    ██    ██    ██  ██
90        ██  ██    ██    ██    ██    ██    ██    ██    ██    ██  ██
91        ██    ██  ██    ██    ██    ██    ██    ██      ████    ██
92    "};
93    let logo_text = Text::styled(logo, Color::Rgb(255, 255, 255));
94    let area = centered_rect(area, logo_text.width() as u16, logo_text.height() as u16);
95
96    let mask_buf = &mut Buffer::empty(area);
97    logo_text.render(area, mask_buf);
98
99    let percentage = (sub_frame as f64 / 480.0).clamp(0.0, 1.0);
100
101    for row in area.rows() {
102        for col in row.columns() {
103            let cell = &mut buf[(col.x, col.y)];
104            let mask_cell = &mut mask_buf[(col.x, col.y)];
105            cell.set_symbol(mask_cell.symbol());
106
107            // blend the mask cell color with the cell color
108            let cell_color = cell.style().bg.unwrap_or(Color::Rgb(0, 0, 0));
109            let mask_color = mask_cell.style().fg.unwrap_or(Color::Rgb(255, 0, 0));
110
111            let color = blend(mask_color, cell_color, percentage);
112            cell.set_style(Style::new().fg(color));
113        }
114    }
115}
Source

pub const fn columns(self) -> Columns

An iterator over columns within the Rect.

§Example
use ratatui::{
    buffer::Buffer,
    layout::Rect,
    widgets::{Block, Borders, Widget},
};
fn render(area: Rect, buf: &mut Buffer) {
    if let Some(left) = area.columns().next() {
        Block::new().borders(Borders::LEFT).render(left, buf);
    }
}
Examples found in repository?
examples/demo2/destroy.rs (line 102)
80fn text(frame_count: usize, area: Rect, buf: &mut Buffer) {
81    let sub_frame = frame_count.saturating_sub(TEXT_DELAY);
82    if sub_frame == 0 {
83        return;
84    }
85
86    let logo = indoc::indoc! {"
87        ██████      ████    ██████    ████    ██████  ██    ██  ██
88        ██    ██  ██    ██    ██    ██    ██    ██    ██    ██  ██
89        ██████    ████████    ██    ████████    ██    ██    ██  ██
90        ██  ██    ██    ██    ██    ██    ██    ██    ██    ██  ██
91        ██    ██  ██    ██    ██    ██    ██    ██      ████    ██
92    "};
93    let logo_text = Text::styled(logo, Color::Rgb(255, 255, 255));
94    let area = centered_rect(area, logo_text.width() as u16, logo_text.height() as u16);
95
96    let mask_buf = &mut Buffer::empty(area);
97    logo_text.render(area, mask_buf);
98
99    let percentage = (sub_frame as f64 / 480.0).clamp(0.0, 1.0);
100
101    for row in area.rows() {
102        for col in row.columns() {
103            let cell = &mut buf[(col.x, col.y)];
104            let mask_cell = &mut mask_buf[(col.x, col.y)];
105            cell.set_symbol(mask_cell.symbol());
106
107            // blend the mask cell color with the cell color
108            let cell_color = cell.style().bg.unwrap_or(Color::Rgb(0, 0, 0));
109            let mask_color = mask_cell.style().fg.unwrap_or(Color::Rgb(255, 0, 0));
110
111            let color = blend(mask_color, cell_color, percentage);
112            cell.set_style(Style::new().fg(color));
113        }
114    }
115}
Source

pub const fn positions(self) -> Positions

An iterator over the positions within the Rect.

The positions are returned in a row-major order (left-to-right, top-to-bottom).

§Example
use ratatui::{buffer::Buffer, layout::Rect};

fn render(area: Rect, buf: &mut Buffer) {
    for position in area.positions() {
        buf[(position.x, position.y)].set_symbol("x");
    }
}
Source

pub const fn as_position(self) -> Position

Returns a Position with the same coordinates as this Rect.

§Examples
use ratatui::layout::Rect;

let rect = Rect::new(1, 2, 3, 4);
let position = rect.as_position();
Source

pub const fn as_size(self) -> Size

Converts the Rect into a size struct.

Trait Implementations§

Source§

impl Clone for Rect

Source§

fn clone(&self) -> Rect

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 Rect

Source§

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

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

impl Default for Rect

Source§

fn default() -> Rect

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

impl<'de> Deserialize<'de> for Rect

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Display for Rect

Source§

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

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

impl From<(Position, Size)> for Rect

Source§

fn from((position, size): (Position, Size)) -> Self

Converts to this type from the input type.
Source§

impl From<Rect> for Position

Source§

fn from(rect: Rect) -> Self

Converts to this type from the input type.
Source§

impl From<Rect> for Size

Source§

fn from(rect: Rect) -> Self

Converts to this type from the input type.
Source§

impl Hash for Rect

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 Rect

Source§

fn eq(&self, other: &Rect) -> 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 Serialize for Rect

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Copy for Rect

Source§

impl Eq for Rect

Source§

impl StructuralPartialEq for Rect

Auto Trait Implementations§

§

impl Freeze for Rect

§

impl RefUnwindSafe for Rect

§

impl Send for Rect

§

impl Sync for Rect

§

impl Unpin for Rect

§

impl UnwindSafe for Rect

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> ToCompactString for T
where T: Display,

Source§

impl<T> ToLine for T
where T: Display,

Source§

fn to_line(&self) -> Line<'_>

Converts the value to a Line.
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> ToSpan for T
where T: Display,

Source§

fn to_span(&self) -> Span<'_>

Converts the value to a Span.
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T> ToText for T
where T: Display,

Source§

fn to_text(&self) -> Text<'_>

Converts the value to a Text.
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.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,