This commit adds `scroll` to the flex example. It also adds more examples to showcase how constraints interact. It improves the UI to make it easier to understand and short terminal friendly.
<img width="380" alt="image" src="https://github.com/ratatui-org/ratatui/assets/1813121/30541efc-ecbe-4e28-b4ef-4d5f1dc63fec"/>
---------
Co-authored-by: Dheepak Krishnamurthy <me@kdheepak.com>
```shell
cargo run --example demo2 --features="crossterm widget-calendar"
```
Press `d` to activate destroy mode and Enjoy!
![Destroy
Demo2](1d39444e3d/examples/demo2-destroy.gif)
Vendors a copy of tui-big-text to allow us to use it in the demo.
This PR adds a new way to space elements in a `Layout`.
Loosely based on
[flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/), this
PR adds a `Flex` enum with the following variants:
- Start
- Center
- End
- SpaceAround
- SpaceBetween
<img width="380" alt="image" src="https://github.com/ratatui-org/ratatui/assets/1813121/b744518c-eae7-4e35-bbc4-fe3c95193cde">
It also adds two more variants, to make this backward compatible and to
make it replace `SegmentSize`:
- StretchLast (default in the `Flex` enum, also behavior matches old
default `SegmentSize::LastTakesRemainder`)
- Stretch (behavior matches `SegmentSize::EvenDistribution`)
The `Start` variant from above matches `SegmentSize::None`.
This allows `Flex` to be a complete replacement for `SegmentSize`, hence
this PR also deprecates the `segment_size` constructor on `Layout`.
`SegmentSize` is still used in `Table` but under the hood `segment_size`
maps to `Flex` with all tests passing unchanged.
I also put together a simple example for `Flex` layouts so that I could
test it visually, shared below:
https://github.com/ratatui-org/ratatui/assets/1813121/c8716c59-493f-4631-add5-feecf4bd4e06
Any iterator whose item is convertible into `Row` can now be
collected into a `Table`.
Where previously, `Table::new` accepted `IntoIterator<Item = Row>`, it
now accepts `IntoIterator<Item: Into<Row>>`.
BREAKING CHANGE:
The compiler can no longer infer the element type of the container
passed to `Table::new()`. For example, `Table::new(vec![], widths)`
will no longer compile, as the type of `vec![]` can no longer be
inferred.
Any iterator whose item is convertible into `Line` can now be
collected into `Tabs`.
In addition, where previously `Tabs::new` required a `Vec`, it can now
accept any object that implements `IntoIterator` with an item type
implementing `Into<Line>`.
BREAKING CHANGE:
Calls to `Tabs::new()` whose argument is collected from an iterator
will no longer compile. For example,
`Tabs::new(["a","b"].into_iter().collect())` will no longer compile,
because the return type of `.collect()` can no longer be inferred to
be a `Vec<_>`.
This allows for multi-line symbols to be used as the highlight symbol.
```rust
let table = Table::new(rows, widths)
.highlight_symbol(Text::from(vec![
"".into(),
" █ ".into(),
" █ ".into(),
"".into(),
]));
```
Previously, `patch_style` and `reset_style` in `Text`, `Line` and `Span`
were using a mutable reference to `Self`. To be more consistent with
the rest of `ratatui`, which is using fluent setters, these now take
ownership of `Self` and return it.
The `Row::new` constructor accepts a single argument that implements
`IntoIterator`. This commit adds an implementation of `FromIterator`,
as a thin wrapper around `Row::new`. This allows `.collect::<Row>()`
to be used at the end of an iterator chain, rather than wrapping the
entire iterator chain in `Row::new`.
* feat: accept Color and Modifier for all Styles
All style related methods now accept `S: Into<Style>` instead of
`Style`.
`Color` and `Modifier` implement `Into<Style>` so this is allows for
more ergonomic usage. E.g.:
```rust
Line::styled("hello", Style::new().red());
Line::styled("world", Style::new().bold());
// can now be simplified to
Line::styled("hello", Color::Red);
Line::styled("world", Modifier::BOLD);
```
Fixes https://github.com/ratatui-org/ratatui/issues/694
BREAKING CHANGE: All style related methods now accept `S: Into<Style>`
instead of `Style`. This means that if you are already passing an
ambiguous type that implements `Into<Style>` you will need to remove
the `.into()` call.
`Block` style methods can no longer be called from a const context as
trait functions cannot (yet) be const.
* feat: add tuple conversions to Style
Adds conversions for various Color and Modifier combinations
* chore: add unit tests
* feat(table): Add a Table::footer method
Signed-off-by: Antonio Yang <yanganto@gmail.com>
* feat(table): Add a Row::top_margin method
- add Row::top_margin
- update table example
Signed-off-by: Antonio Yang <yanganto@gmail.com>
---------
Signed-off-by: Antonio Yang <yanganto@gmail.com>
The previous name `start_corner` did not communicate clearly the intent of the method.
A new method `direction` and a new enum `ListDirection` were added.
`start_corner` is now deprecated
This prevents creating a table that doesn't actually render anything.
Fixes: https://github.com/ratatui-org/ratatui/issues/537
BREAKING CHANGE: Table::new() now takes an additional widths parameter.
This allows passing an array, slice or Vec of constraints, which is more
ergonomic than requiring this to always be a slice.
The following calls now all succeed:
```rust
Table::new(rows).widths([Constraint::Length(5), Constraint::Length(5)]);
Table::new(rows).widths(&[Constraint::Length(5), Constraint::Length(5)]);
// widths could also be computed at runtime
let widths = vec![Constraint::Length(5), Constraint::Length(5)];
Table::new(rows).widths(widths.clone());
Table::new(rows).widths(&widths);
```
The background colors of the gauge had a workaround for the issue we had
with VHS / TTYD rendering the background color of the gauge. This
workaround is no longer necessary in the updated versions of VHS / TTYD.
Fixes https://github.com/ratatui-org/ratatui/issues/501
* feat(canvas): implement half block marker
A useful technique for the terminal is to use half blocks to draw a grid
of "pixels" on the screen. Because we can set two colors per cell, and
because terminal cells are about twice as tall as they are wide, we can
draw a grid of half blocks that looks like a grid of square pixels.
This commit adds a new `HalfBlock` marker that can be used in the Canvas
widget and the associated HalfBlockGrid.
Also updated demo2 to use the new marker as it looks much nicer.
Adds docs for many of the methods and structs on canvas.
Changes the grid resolution method to return the pixel count
rather than the index of the last pixel.
This is an internal detail with no user impact.
* docs: make library and README consistent
Generate the bulk of the README from the library documentation, so that
they are consistent using cargo-rdme.
- Removed the Contributors section, as it is redundant with the github
contributors list.
- Removed the info about the other backends and replaced it with a
pointer to the documentation.
- add docsrs example, vhs tape and images that will end up in the README
Fixes: https://github.com/ratatui-org/ratatui/issues/512
This change simplifys UI code that uses the Frame type. E.g.:
```rust
fn draw<B: Backend>(frame: &mut Frame<B>) {
// ...
}
```
Frame was generic over Backend because it stored a reference to the
terminal in the field. Instead it now directly stores the viewport area
and current buffer. These are provided at creation time and are valid
for the duration of the frame.
BREAKING CHANGE: Frame is no longer generic over Backend. Code that
accepted `Frame<Backend>` will now need to accept `Frame`. To migrate
existing code, remove any generic parameters from code that uses an
instance of a Frame. E.g. the above code becomes:
```rust
fn draw(frame: &mut Frame) {
// ...
}
```
Although the `Stylize` trait is already implemented for `&str` which
extends to `String`, it is not implemented for `String` itself. This
commit adds an impl of Stylize that returns a Span<'static> for `String`
so that code can call Stylize methods on temporary `String`s.
E.g. the following now compiles instead of failing with a compile error
about referencing a temporary value:
let s = format!("hello {name}!", "world").red();
BREAKING CHANGE: This may break some code that expects to call Stylize
methods on `String` values and then use the String value later. This
will now fail to compile because the String is consumed by set_style
instead of a slice being created and consumed.
This can be fixed by cloning the `String`. E.g.:
let s = String::from("hello world");
let line = Line::from(vec![s.red(), s.green()]); // fails to compile
let line = Line::from(vec![s.clone().red(), s.green()]); // works
* feat(barchart): Add direction attribute
Enable rendring the bars horizontally. In some cases this allow us to
make more efficient use of the available space.
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
* feat(barchart)!: render the group labels depending on the alignment
This is a breaking change, since the alignment by default is set to
Left and the group labels are always rendered in the center.
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
---------
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
Previously the layout used the floor of the calculated start and width
as the value to use for the split Rects. This resulted in gaps between
the split rects.
This change modifies the layout to round to the nearest column instead
of taking the floor of the start and width. This results in the start
and end of each rect being rounded the same way and being strictly
adjacent without gaps.
Because there is a required constraint that ensures that the last end is
equal to the area end, there is no longer the need to fixup the last
item width when the fill (as e.g. width = x.99 now rounds to x+1 not x).
The colors example has been updated to use Ratio(1, 8) instead of
Percentage(13), as this now renders without gaps for all possible sizes,
whereas previously it would have left odd gaps between columns.
The track symbol is now optional, simplifying composition with other
widgets.
BREAKING_CHANGE: The `track_symbol` needs to be set in the following way
now:
```
let scrollbar = Scrollbar::default().track_symbol(Some("-"));
```
The symbols and sets are moved from `widgets::scrollbar` to
`symbols::scrollbar`. This makes it consistent with the other symbol
sets and allows us to make the scrollbar module private rather than
re-exporting it.
BREAKING CHANGE: The symbols are now in the `symbols` module. To update
your code, add an import for `ratatui:🔣:scrollbar::*` (or the
specific symbols you need). The scrollbar module is no longer public. To
update your code, remove any `widgets::scrollbar` imports and replace it
with `ratatui::widgets::Scrollbar`.
This commit adds a readme to the examples directory with gifs of each
example. This should make it easier to see what each example does
without having to run it.
I modified the examples to fit better in the gifs. Mostly this was just
removing the margins, but for the block example I cleaned up the code a
bit to make it more readable and changed it so the background bug is not
triggered.
For the table example, the combination of Min, Length, and Percent
constraints was causing the table to panic when the terminal was too
small. I changed the example to use the Max constraint instead of the
Length constraint.
The layout example now shows information about how the layout is
constrained on each block (which is now a paragraph with a block).
This helps to keep the prelude small and less likely to conflict with
other crates.
- remove widgets module from prelude as the entire module can be just as
easily imported with `use ratatui::widgets::*;`
- move prelude module into its own file
- update examples to import widgets module instead of just prelude
- added several modules to prelude to make it possible to qualify
imports that collide with other types that have similar names
for now the value is converted to a string and then printed. in many
cases the values are too wide or double values. so it make sense
to set a custom value text instead of the default behavior.
this patch suggests to add a method
"fn text_value(mut self, text_value: String)"
to the Bar, which allows to override the value printed in the bar
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
The user_input example now responds to left/right and allows the
character at the cursor position to be deleted / inserted.
Co-authored-by: Leon Sautour <leon1.sautour@epitech.eu>
* feat(barchart): allow to add a group of bars
Example: to show the revenue of different companies:
┌────────────────────────┐
│ ████ │
│ ████ │
│ ████ ████ │
│ ▄▄▄▄ ████ ████ ████ │
│ ████ ████ ████ ████ │
│ ████ ████ ████ ████ │
│ █50█ █60█ █90█ █55█ │
│ Mars April │
└────────────────────────┘
new structs are introduced: Group and Bar.
the data function is modified to accept "impl Into<Group<'a>>".
a new function "group_gap" is introduced to set the gap between each group
unit test changed to allow the label to be in the center
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
* feat(barchart)!: center labels by default
The bar labels are currently printed string from the left side of
bar. This commit centers the labels under the bar.
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
---------
Signed-off-by: Ben Fekih, Hichem <hichem.f@live.de>
Before this change, it wasn't possible to build all features and all
targets at the same time, which prevents rust-analyzer from working
for the whole project.
Adds a bacon.toml file to the project, which is used by bacon
https://dystroy.org/bacon/
Configures docs.rs to show the feature flags that are necessary to
make modules / types / functions available.
Represents a scrollbar widget that renders a track, thumb and arrows
either horizontally or vertically. State is kept in ScrollbarState, and
passed as a parameter to the render function.
* fix(gauge): render gauge with unicode correctly
Gauge now correctly renders a block rather than a space when in unicode mode.
* docs: update demo.gif
- remove existing gif
- upload using VHS (https://github.com/charmbracelet/vhs)
- add instructions to RELEASE.md
- link new gif in README
This is an opinionated default that helps avoid horizontal scrolling.
100 is the most common width on github rust projects and works well for
displaying code on a 16in macbook pro.
- Reformat summary info
- Add badges for dependencies, discord, license
- point existing badges to shields.io
- add Table of Contents
- tweaked installation instructions to show instructions for new and
existing crates
- moved fork status lower
- chop lines generally to 100 limit
- add a quickstart based on a simplified hello_world example
- added / updated some internal links to point locally
- removed some details to simplify the readme (e.g. tick-rate)
- reordered widgets and pointed these at the widget docs
- adds a hello_world example that has just the absolute basic code
necessary to run a ratatui app. This includes some comments that help
guide the user towards other approaches and considerations for a real
world app.
* refactor: add Line type to replace Spans
`Line` is a significantly better name over `Spans` as the plural causes
confusion and the type really is a representation of a line of text made
up of spans.
This is a backwards compatible version of the approach from
https://github.com/tui-rs-revival/ratatui/pull/175
There is a significant amount of code that uses the Spans type and
methods, so instead of just renaming it, we add a new type and replace
parameters that accepts a `Spans` with a parameter that accepts
`Into<Line>`.
Note that the examples have been intentionally left using `Spans` in
this commit to demonstrate the compiler warnings that will be emitted in
existing code.
Implementation notes:
- moves the Spans code to text::spans and publicly reexports on the text
module. This makes the test in that module only relevant to the Spans
type.
- adds a line module with a copy of the code and tests from Spans with a
single addition: `impl<'a> From<Spans<'a>> for Line<'a>`
- adds tests for `Spans` (created and checked before refactoring)
- adds the same tests for `Line`
- updates all widget methods that accept and store Spans to instead
store `Line` and accept `Into<Line>`
* refactor: move text::Masked to text::masked::Masked
Re-exports the Masked type at text::Masked
* refactor: replace Spans with Line in tests/examples/docs
* build: bump MSRV to 1.65
The latest version of the time crate requires Rust 1.65.0
```
cargo +1.64.0-x86_64-apple-darwin test --no-default-features \
--features serde,crossterm,all-widgets --lib --tests --examples
error: package `time v0.3.21` cannot be built because it requires rustc
1.65.0 or newer, while the currently active rustc version is 1.64.0
```
* feat(backend): add termwiz backend and demo
* ci(termwiz): add termwiz to makefile.toml
---------
Co-authored-by: Josh McKinney <joshka@users.noreply.github.com>
Co-authored-by: Prabir Shrestha <mail@prabir.me>
Adds a new type Masked that can mask data with a mask character, and can
be used anywhere we expect Cow<'a, str> or Text<'a>. E.g. Paragraph,
ListItem, Table Cells etc.
BREAKING CHANGE:
Because Masked implements From for Text<'a>, code that binds
Into<Text<'a>> without type annotations may no longer compile
(e.g. `Paragraph::new("".as_ref())`)
To fix this, annotate or call to_string() / to_owned() / as_str()
Without a terminal-resetting panic hook there are two main problems when
an application panics:
1. The report of the panic is distorted because the terminal has not
properly left the alternate screen and is still in raw mode.
2. The terminal needs to be manually reset with the `reset` command.
To avoid this, the standard panic hook can be extended to first reset
the terminal.
Third column in table example was using the `Max` constraint.
But since version 0.16, the layout system does not add a hidden constraint on the last column which would ensure that it fills the remaining available space (a change that was already mentioned in #525). In addition, `tui` does not support sizing based on content because of its immediate mode nature. Therefore, `Max` is now resolved to `0`. Replacing with `Min` fixes the issue.
A new way of specifying constraints is being worked on at #519 which should for more deterministic and advanced layout.
The thread spawned by `Events` to listen for keyboard inputs had knowlegde of
the exit key to exit on its own when it was pressed. It is however a source of
confusion (#491) because the exit behavior is wired in both the event handler
and the input handling performed by the app. In addition, this is not needed as
the thread will exit anyway when the main thread finishes as it is already the
case for the "tick" thread. Therefore, this commit removes both the option to
configure the exit key in the `Events` handler and the option to temporarily
ignore it.