mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 07:04:17 +00:00
fix(table): widths() now accepts AsRef<[Constraint]> (#628)
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); ```
This commit is contained in:
parent
ec7b3872b4
commit
36d8c53645
7 changed files with 89 additions and 39 deletions
|
@ -10,6 +10,9 @@ github with a [breaking change] label.
|
|||
|
||||
This is a quick summary of the sections below:
|
||||
|
||||
- Unreleased (0.24.1)
|
||||
-
|
||||
|
||||
- [v0.24.0](#v0240)
|
||||
- MSRV is now 1.70.0
|
||||
- `ScrollbarState`: `position`, `content_length`, and `viewport_content_length` are now `usize`
|
||||
|
@ -32,6 +35,24 @@ This is a quick summary of the sections below:
|
|||
- MSRV is now 1.63.0
|
||||
- `List` no longer ignores empty strings
|
||||
|
||||
## Unreleased (v0.24.1)
|
||||
|
||||
### `Table::widths()` now accepts `AsRef<[Constraint]>` ([#628])
|
||||
|
||||
Previously `Table::widths()` took a slice (`&'a [Constraint]`). This change will introduce clippy
|
||||
`needless_borrow` warnings for places where slices are passed to this method. To fix these, remove
|
||||
the `&`.
|
||||
|
||||
E.g.
|
||||
|
||||
```rust
|
||||
let table = Table::new(rows).widths(&[Constraint::Length(1)]);
|
||||
// becomes
|
||||
let table = Table::new(rows).widths([Constraint::Length(1)]);
|
||||
```
|
||||
|
||||
[#628]: https://github.com/ratatui-org/ratatui/pull/628
|
||||
|
||||
## [v0.24.0](https://github.com/ratatui-org/ratatui/releases/tag/v0.24.0)
|
||||
|
||||
### ScrollbarState field type changed from `u16` to `usize` ([#456])
|
||||
|
|
|
@ -296,7 +296,7 @@ fn draw_second_tab(f: &mut Frame, app: &mut App, area: Rect) {
|
|||
.bottom_margin(1),
|
||||
)
|
||||
.block(Block::default().title("Servers").borders(Borders::ALL))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(15),
|
||||
Constraint::Length(15),
|
||||
Constraint::Length(10),
|
||||
|
@ -395,7 +395,7 @@ fn draw_third_tab(f: &mut Frame, _app: &mut App, area: Rect) {
|
|||
.collect();
|
||||
let table = Table::new(items)
|
||||
.block(Block::default().title("Colors").borders(Borders::ALL))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
Constraint::Ratio(1, 3),
|
||||
|
|
|
@ -149,7 +149,7 @@ fn render_ingredients(selected_row: usize, area: Rect, buf: &mut Buffer) {
|
|||
Table::new(rows)
|
||||
.block(Block::new().style(theme.ingredients))
|
||||
.header(Row::new(vec!["Qty", "Ingredient"]).style(theme.ingredients_header))
|
||||
.widths(&[Constraint::Length(7), Constraint::Length(30)])
|
||||
.widths([Constraint::Length(7), Constraint::Length(30)])
|
||||
.highlight_style(Style::new().light_yellow()),
|
||||
area,
|
||||
buf,
|
||||
|
|
|
@ -52,7 +52,7 @@ fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) {
|
|||
StatefulWidget::render(
|
||||
Table::new(rows)
|
||||
.header(Row::new(vec!["Host", "Address"]).set_style(THEME.traceroute.header))
|
||||
.widths(&[Constraint::Max(100), Constraint::Length(15)])
|
||||
.widths([Constraint::Max(100), Constraint::Length(15)])
|
||||
.highlight_style(THEME.traceroute.selected)
|
||||
.block(block),
|
||||
area,
|
||||
|
|
|
@ -142,7 +142,7 @@ fn ui(f: &mut Frame, app: &mut App) {
|
|||
.block(Block::default().borders(Borders::ALL).title("Table"))
|
||||
.highlight_style(selected_style)
|
||||
.highlight_symbol(">> ")
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Percentage(50),
|
||||
Constraint::Max(30),
|
||||
Constraint::Min(10),
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use std::iter;
|
||||
|
||||
use itertools::Itertools;
|
||||
use strum::{Display, EnumString};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
|
@ -251,7 +254,7 @@ pub struct Table<'a> {
|
|||
/// Base style for the widget
|
||||
style: Style,
|
||||
/// Width constraints for each column
|
||||
widths: &'a [Constraint],
|
||||
widths: Vec<Constraint>,
|
||||
/// Space between each column
|
||||
column_spacing: u16,
|
||||
/// Style used to render the selected row
|
||||
|
@ -294,7 +297,7 @@ impl<'a> Table<'a> {
|
|||
Self {
|
||||
block: None,
|
||||
style: Style::default(),
|
||||
widths: &[],
|
||||
widths: vec![],
|
||||
column_spacing: 1,
|
||||
highlight_style: Style::default(),
|
||||
highlight_symbol: None,
|
||||
|
@ -355,7 +358,24 @@ impl<'a> Table<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn widths(mut self, widths: &'a [Constraint]) -> Self {
|
||||
/// Set the widths of the columns of the [`Table`] widget.
|
||||
///
|
||||
/// The `widths` parameter accepts `AsRef<[Constraint]>`` which can be an array, slice, or Vec.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// let table = Table::new(vec![]).widths([Constraint::Length(5), Constraint::Length(5)]);
|
||||
/// let table = Table::new(vec![]).widths(&[Constraint::Length(5), Constraint::Length(5)]);
|
||||
///
|
||||
/// // widths could also be computed at runtime
|
||||
/// let widths = vec![Constraint::Length(5), Constraint::Length(5)];
|
||||
/// let table = Table::new(vec![]).widths(widths.clone());
|
||||
/// let table = Table::new(vec![]).widths(&widths);
|
||||
/// ```
|
||||
pub fn widths<T: AsRef<[Constraint]>>(mut self, widths: T) -> Self {
|
||||
let widths = widths.as_ref().to_vec();
|
||||
let between_0_and_100 = |&w| match w {
|
||||
Constraint::Percentage(p) => p <= 100,
|
||||
_ => true,
|
||||
|
@ -399,29 +419,21 @@ impl<'a> Table<'a> {
|
|||
/// Get all offsets and widths of all user specified columns
|
||||
/// Returns (x, width)
|
||||
fn get_columns_widths(&self, max_width: u16, selection_width: u16) -> Vec<(u16, u16)> {
|
||||
let mut constraints = Vec::with_capacity(self.widths.len() * 2 + 1);
|
||||
constraints.push(Constraint::Length(selection_width));
|
||||
for constraint in self.widths {
|
||||
constraints.push(*constraint);
|
||||
constraints.push(Constraint::Length(self.column_spacing));
|
||||
}
|
||||
if !self.widths.is_empty() {
|
||||
constraints.pop();
|
||||
}
|
||||
let chunks = Layout::default()
|
||||
let constraints = iter::once(Constraint::Length(selection_width))
|
||||
.chain(Itertools::intersperse(
|
||||
self.widths.iter().cloned(),
|
||||
Constraint::Length(self.column_spacing),
|
||||
))
|
||||
.collect_vec();
|
||||
let layout = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.constraints(constraints)
|
||||
.segment_size(SegmentSize::None)
|
||||
.split(Rect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: max_width,
|
||||
height: 1,
|
||||
});
|
||||
chunks
|
||||
.split(Rect::new(0, 0, max_width, 1));
|
||||
layout
|
||||
.iter()
|
||||
.skip(1)
|
||||
.step_by(2)
|
||||
.skip(1) // skip selection column
|
||||
.step_by(2) // skip spacing between columns
|
||||
.map(|c| (c.x, c.width))
|
||||
.collect()
|
||||
}
|
||||
|
@ -661,7 +673,23 @@ mod tests {
|
|||
#[test]
|
||||
#[should_panic]
|
||||
fn table_invalid_percentages() {
|
||||
Table::new(vec![]).widths(&[Constraint::Percentage(110)]);
|
||||
Table::new(vec![]).widths([Constraint::Percentage(110)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn widths_conversions() {
|
||||
let table = Table::new(vec![]).widths([Constraint::Percentage(100)]);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "array");
|
||||
|
||||
#[allow(clippy::needless_borrow)] // for backwards compatibility with existing code
|
||||
let table = Table::new(vec![]).widths(&[Constraint::Percentage(100)]);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "slice");
|
||||
|
||||
let table = Table::new(vec![]).widths(vec![Constraint::Percentage(100)]);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec");
|
||||
|
||||
let table = Table::new(vec![]).widths(&vec![Constraint::Percentage(100)]);
|
||||
assert_eq!(table.widths, vec![Constraint::Percentage(100)], "vec ref");
|
||||
}
|
||||
|
||||
// test how constraints interact with table column width allocation
|
||||
|
@ -779,7 +807,7 @@ mod tests {
|
|||
Row::new(vec![Line::from("Center").alignment(Alignment::Center)]),
|
||||
Row::new(vec![Line::from("Right").alignment(Alignment::Right)]),
|
||||
])
|
||||
.widths(&[Percentage(100)]);
|
||||
.widths([Percentage(100)]);
|
||||
|
||||
Widget::render(table, Rect::new(0, 0, 20, 3), &mut buf);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ fn widgets_table_column_spacing_can_be_changed() {
|
|||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
|
@ -198,7 +198,8 @@ fn widgets_table_columns_widths_can_use_fixed_length_constraints() {
|
|||
|
||||
#[test]
|
||||
fn widgets_table_columns_widths_can_use_percentage_constraints() {
|
||||
let test_case = |widths, expected| {
|
||||
#[track_caller]
|
||||
fn test_case(widths: &[Constraint], expected: Buffer) {
|
||||
let backend = TestBackend::new(30, 10);
|
||||
let mut terminal = Terminal::new(backend).unwrap();
|
||||
|
||||
|
@ -219,7 +220,7 @@ fn widgets_table_columns_widths_can_use_percentage_constraints() {
|
|||
})
|
||||
.unwrap();
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
};
|
||||
}
|
||||
|
||||
// columns of zero width show nothing
|
||||
test_case(
|
||||
|
@ -536,7 +537,7 @@ fn widgets_table_can_have_rows_with_multi_lines() {
|
|||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_symbol(">> ")
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
|
@ -631,7 +632,7 @@ fn widgets_table_enable_always_highlight_spacing() {
|
|||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_symbol(">> ")
|
||||
.highlight_spacing(space)
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
|
@ -772,7 +773,7 @@ fn widgets_table_can_have_elements_styled_individually() {
|
|||
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.highlight_symbol(">> ")
|
||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
|
@ -833,7 +834,7 @@ fn widgets_table_should_render_even_if_empty() {
|
|||
let table = Table::new(vec![])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]))
|
||||
.block(Block::default().borders(Borders::LEFT | Borders::RIGHT))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(6),
|
||||
|
@ -873,7 +874,7 @@ fn widgets_table_columns_dont_panic() {
|
|||
.block(Block::default().borders(Borders::ALL))
|
||||
.highlight_symbol(">> ")
|
||||
.column_spacing(1)
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(25),
|
||||
|
@ -908,7 +909,7 @@ fn widgets_table_should_clamp_offset_if_rows_are_removed() {
|
|||
])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
|
@ -937,7 +938,7 @@ fn widgets_table_should_clamp_offset_if_rows_are_removed() {
|
|||
let table = Table::new(vec![Row::new(vec!["Row31", "Row32", "Row33"])])
|
||||
.header(Row::new(vec!["Head1", "Head2", "Head3"]).bottom_margin(1))
|
||||
.block(Block::default().borders(Borders::ALL))
|
||||
.widths(&[
|
||||
.widths([
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
Constraint::Length(5),
|
||||
|
|
Loading…
Reference in a new issue