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)?;
```
Resolves https://github.com/ratatui/ratatui/issues/1951
BREAKING CHANGE: Old `Flex::SpaceAround` behavior is available by using
`Flex::SpaceEvenly` and new
`Flex::SpaceAround` now distributes space evenly around each element
except the middle spacers
are twice the size of first and last elements
With this change, the following variants of `Flex` are supported:
- `Flex::Start`: Aligns items to the start; excess space appears at the
end.
- `Flex::End`: Aligns items to the end; excess space appears at the
start.
- `Flex::Center`: Centers items with equal space on both sides.
- `Flex::SpaceAround` (**new**): Distributes space _around_ items; space
between items is _twice_ the edge spacing.
- `Flex::SpaceBetween`: Distributes space _evenly between_ items except
no space at the edges.
- `Flex::SpaceEvenly` (**previously `Flex::SpaceAround`**): Distributes
space _evenly between_ items and edges.
- `Flex::Legacy`: Preserves legacy behavior, placing all excess space at
the end.
This aligns behavior of `Flex` with CSS flexbox more closely.
The following is a screenshot in action:
<img width="1090" alt="image"
src="https://github.com/user-attachments/assets/2c7cd797-27bd-4242-a824-4565d369227b"
/>
---------
Co-authored-by: Jagoda Estera Ślązak <128227338+j-g00da@users.noreply.github.com>
This introduces a new `ratatui::run()` method which runs a closure with
a terminal initialized with reasonable defaults for most applications.
This calls `ratatui::init()` before running the closure and
`ratatui::restore()` after the closure completes, and returns the result
of the closure.
A minimal hello world example using the new `ratatui::run()` method:
```rust
fn main() -> Result<(), Box<dyn std::error::Error>> {
ratatui::run(|terminal| {
loop {
terminal.draw(|frame| frame.render_widget("Hello World!", frame.area()))?;
if crossterm::event::read()?.is_key_press() {
break Ok(());
}
}
})
}
```
Of course, this also works both with apps that use free methods and
structs:
```rust
fn run(terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
ratatui::run(run)?;
```
```rust
struct App { ... }
impl App {
fn new() -> Self { ... }
fn run(mut self, terminal: &mut DefaultTerminal) -> Result<(), AppError> { ... }
}
ratatui::run(|terminal| App::new().run(terminal))?;
```
Crossterm 0.29 introduced methods to easily check / extract the event
type. E.g. as_key_press_event() and is_key_press(). This commit
updates the examples to use these methods instead of matching on
the event type. This makes the code cleaner and easier to read.
Also does a general cleanup of the event handling code in the examples.
The Clippy check for this (missing_const_for_fn) is already enabled, but
catches more cases in upcoming toolchain versions.
This is part of the work to unblock #1727
I was swayed by the arguments about this made by the compiler team In
<https://github.com/rust-lang/compiler-team/issues/750> and decided to
look at how this organization affects ratatui. I found this reduces the
number of lines across the codebase by about 350 and makes the imports
more readable and definitely more greppable as you usually only have
to read a single line. I've found in the past that maintaining imports
regularly leads to merge conflicts which have to be resolved by hand
and this change should reduce the likelihood of that happening.
Main change is in rustfmt.toml, and the rest is just the result of
running `cargo xtask format`.
While implementing this, cargo machete brings up that the various
backend crates are unused by the example crates.
The re-export of each backend crate under ratatui is to make it possible
for libs that rely on a specific version of ratatui to use the same
version of the backend crate. Apps in general should use the backend
crate directly rather than through ratatui as this is less confusing.
- Removes all usages of `ratatui::{crossterm, termion, termwiz}`` in the
examples.
- Adds the backend crate to the dependencies of the examples that use
the backend crate directly.