Compare commits
13 Commits
jm/widget-
...
kd/multi-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ccf9d92f10 | ||
|
|
b712034644 | ||
|
|
38fca62fa9 | ||
|
|
3a51a027a6 | ||
|
|
5b30f2275c | ||
|
|
b4c27c744c | ||
|
|
977a4899c8 | ||
|
|
cd27b4829a | ||
|
|
feee871519 | ||
|
|
0051bb2037 | ||
|
|
477217c77a | ||
|
|
31de3586f7 | ||
|
|
f702025b75 |
@@ -213,6 +213,15 @@ pub struct Table<'a> {
|
||||
/// Symbol in front of the selected row
|
||||
highlight_symbol: Text<'a>,
|
||||
|
||||
/// Symbol in front of the marked row
|
||||
mark_symbol: Text<'a>,
|
||||
|
||||
/// Symbol in front of the unmarked row
|
||||
unmark_symbol: Text<'a>,
|
||||
|
||||
/// Symbol in front of the marked and selected row
|
||||
mark_highlight_symbol: Text<'a>,
|
||||
|
||||
/// Decides when to allocate spacing for the row selection
|
||||
highlight_spacing: HighlightSpacing,
|
||||
|
||||
@@ -232,6 +241,9 @@ impl<'a> Default for Table<'a> {
|
||||
style: Style::new(),
|
||||
highlight_style: Style::new(),
|
||||
highlight_symbol: Text::default(),
|
||||
mark_symbol: Text::default(),
|
||||
unmark_symbol: Text::default(),
|
||||
mark_highlight_symbol: Text::default(),
|
||||
highlight_spacing: HighlightSpacing::default(),
|
||||
flex: Flex::Start,
|
||||
}
|
||||
@@ -503,6 +515,60 @@ impl<'a> Table<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the symbol to be displayed in front of the marked row
|
||||
///
|
||||
/// This is a fluent setter method which must be chained or used as it consumes self
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// # let rows = [Row::new(vec!["Cell1", "Cell2"])];
|
||||
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
|
||||
/// let table = Table::new(rows, widths).mark_symbol("\u{2714}");
|
||||
/// ```
|
||||
#[must_use = "method moves the value of self and returns the modified value"]
|
||||
pub fn mark_symbol<T: Into<Text<'a>>>(mut self, mark_symbol: T) -> Self {
|
||||
self.mark_symbol = mark_symbol.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the symbol to be displayed in front of the unmarked row
|
||||
///
|
||||
/// This is a fluent setter method which must be chained or used as it consumes self
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// # let rows = [Row::new(vec!["Cell1", "Cell2"])];
|
||||
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
|
||||
/// let table = Table::new(rows, widths).unmark_symbol(" ");
|
||||
/// ```
|
||||
#[must_use = "method moves the value of self and returns the modified value"]
|
||||
pub fn unmark_symbol<T: Into<Text<'a>>>(mut self, unmark_symbol: T) -> Self {
|
||||
self.unmark_symbol = unmark_symbol.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the symbol to be displayed in front of the marked and selected row
|
||||
///
|
||||
/// This is a fluent setter method which must be chained or used as it consumes self
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// # let rows = [Row::new(vec!["Cell1", "Cell2"])];
|
||||
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
|
||||
/// let table = Table::new(rows, widths).mark_highlight_symbol("\u{29bf}");
|
||||
/// ```
|
||||
#[must_use = "method moves the value of self and returns the modified value"]
|
||||
pub fn mark_highlight_symbol<T: Into<Text<'a>>>(mut self, mark_highlight_symbol: T) -> Self {
|
||||
self.mark_highlight_symbol = mark_highlight_symbol.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set when to show the highlight spacing
|
||||
///
|
||||
/// The highlight spacing is the spacing that is allocated for the selection symbol column (if
|
||||
@@ -604,8 +670,8 @@ impl StatefulWidgetRef for Table<'_> {
|
||||
return;
|
||||
}
|
||||
|
||||
let selection_width = self.selection_width(state);
|
||||
let columns_widths = self.get_columns_widths(table_area.width, selection_width);
|
||||
let highlight_column_width = self.highlight_column_width(state);
|
||||
let columns_widths = self.get_columns_widths(table_area.width, highlight_column_width);
|
||||
let (header_area, rows_area, footer_area) = self.layout(table_area);
|
||||
|
||||
self.render_header(header_area, buf, &columns_widths);
|
||||
@@ -614,8 +680,13 @@ impl StatefulWidgetRef for Table<'_> {
|
||||
rows_area,
|
||||
buf,
|
||||
state,
|
||||
selection_width,
|
||||
&self.highlight_symbol,
|
||||
highlight_column_width,
|
||||
(
|
||||
&self.highlight_symbol,
|
||||
&self.mark_symbol,
|
||||
&self.unmark_symbol,
|
||||
&self.mark_highlight_symbol,
|
||||
),
|
||||
&columns_widths,
|
||||
);
|
||||
|
||||
@@ -670,14 +741,16 @@ impl Table<'_> {
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
state: &mut TableState,
|
||||
selection_width: u16,
|
||||
highlight_symbol: &Text<'_>,
|
||||
highlight_column_width: u16,
|
||||
symbols: (&Text<'_>, &Text<'_>, &Text<'_>, &Text<'_>),
|
||||
columns_widths: &[(u16, u16)],
|
||||
) {
|
||||
if self.rows.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let (highlight_symbol, mark_symbol, unmark_symbol, mark_highlight_symbol) = symbols;
|
||||
|
||||
let (start_index, end_index) =
|
||||
self.get_row_bounds(state.selected, state.offset, area.height);
|
||||
state.offset = start_index;
|
||||
@@ -698,22 +771,37 @@ impl Table<'_> {
|
||||
);
|
||||
buf.set_style(row_area, row.style);
|
||||
|
||||
let is_selected = state.selected().is_some_and(|index| index == i);
|
||||
if selection_width > 0 && is_selected {
|
||||
let selection_area = Rect {
|
||||
width: selection_width,
|
||||
let is_marked = state.marked().contains(&(i + state.offset));
|
||||
let is_highlighted = state.selected().is_some_and(|index| index == i);
|
||||
if highlight_column_width > 0 {
|
||||
let area = Rect {
|
||||
width: highlight_column_width,
|
||||
..row_area
|
||||
};
|
||||
buf.set_style(selection_area, row.style);
|
||||
highlight_symbol.clone().render(selection_area, buf);
|
||||
};
|
||||
buf.set_style(area, row.style);
|
||||
|
||||
match (is_marked, is_highlighted) {
|
||||
(true, true) => {
|
||||
mark_highlight_symbol.render(area, buf);
|
||||
}
|
||||
(true, false) => {
|
||||
mark_symbol.render(area, buf);
|
||||
}
|
||||
(false, true) => {
|
||||
highlight_symbol.render(area, buf);
|
||||
}
|
||||
(false, false) => {
|
||||
unmark_symbol.render(area, buf);
|
||||
}
|
||||
};
|
||||
}
|
||||
for ((x, width), cell) in columns_widths.iter().zip(row.cells.iter()) {
|
||||
cell.render(
|
||||
Rect::new(row_area.x + x, row_area.y, *width, row_area.height),
|
||||
buf,
|
||||
);
|
||||
}
|
||||
if is_selected {
|
||||
if is_highlighted {
|
||||
buf.set_style(row_area, self.highlight_style);
|
||||
}
|
||||
y_offset += row.height_with_margin();
|
||||
@@ -788,15 +876,35 @@ impl Table<'_> {
|
||||
(start, end)
|
||||
}
|
||||
|
||||
/// Returns the width of the selection column if a row is selected, or the `highlight_spacing`
|
||||
/// is set to show the column always, otherwise 0.
|
||||
fn selection_width(&self, state: &TableState) -> u16 {
|
||||
let has_selection = state.selected().is_some();
|
||||
if self.highlight_spacing.should_add(has_selection) {
|
||||
/// Returns the width of the indicator column if a row is selected, rows are marked,
|
||||
/// or the `highlight_spacing` is set to show the column always, otherwise 0.
|
||||
fn highlight_column_width(&self, state: &TableState) -> u16 {
|
||||
let has_highlight = state.selected().is_some() || state.marked().len() > 0;
|
||||
let highlight_column_width = if self.highlight_spacing.should_add(has_highlight) {
|
||||
self.highlight_symbol.width() as u16
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
let mark_column_width = if self.highlight_spacing.should_add(has_highlight) {
|
||||
self.mark_symbol.width() as u16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mark_highlight_column_width = if self.highlight_spacing.should_add(has_highlight) {
|
||||
self.mark_highlight_symbol.width() as u16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let unmark_column_width = if self.highlight_spacing.should_add(has_highlight) {
|
||||
self.unmark_symbol.width() as u16
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
highlight_column_width
|
||||
.max(mark_column_width)
|
||||
.max(mark_highlight_column_width)
|
||||
.max(unmark_column_width)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,6 +1298,100 @@ mod tests {
|
||||
]);
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_with_selected_marked_unmarked() {
|
||||
let rows = vec![
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
Row::new(vec!["Cell", "Cell"]),
|
||||
];
|
||||
let table = Table::new(rows, [Constraint::Length(5); 2])
|
||||
.highlight_symbol("• ")
|
||||
.mark_symbol("⦾")
|
||||
.unmark_symbol(" ")
|
||||
.mark_highlight_symbol("⦿");
|
||||
|
||||
let mut state = TableState::new().with_selected(0);
|
||||
|
||||
state.mark(1);
|
||||
state.mark(3);
|
||||
state.mark(5);
|
||||
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 10));
|
||||
StatefulWidget::render(table.clone(), Rect::new(0, 0, 15, 10), &mut buf, &mut state);
|
||||
let expected = Buffer::with_lines(Text::from(vec![
|
||||
"• Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
]));
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
state.mark(0);
|
||||
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 10));
|
||||
StatefulWidget::render(table.clone(), Rect::new(0, 0, 15, 10), &mut buf, &mut state);
|
||||
let expected = Buffer::with_lines(Text::from(vec![
|
||||
"⦿ Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
]));
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
state.select(Some(1));
|
||||
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 10));
|
||||
StatefulWidget::render(table.clone(), Rect::new(0, 0, 15, 10), &mut buf, &mut state);
|
||||
let expected = Buffer::with_lines(Text::from(vec![
|
||||
"⦾ Cell Cell ".into(),
|
||||
"⦿ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
]));
|
||||
assert_eq!(buf, expected);
|
||||
|
||||
state.unmark(0);
|
||||
|
||||
let mut buf = Buffer::empty(Rect::new(0, 0, 15, 10));
|
||||
StatefulWidget::render(table.clone(), Rect::new(0, 0, 15, 10), &mut buf, &mut state);
|
||||
let expected = Buffer::with_lines(Text::from(vec![
|
||||
" Cell Cell ".into(),
|
||||
"⦿ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
"⦾ Cell Cell ".into(),
|
||||
" Cell Cell ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
" ".into(),
|
||||
]));
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
}
|
||||
|
||||
// test how constraints interact with table column width allocation
|
||||
@@ -1388,6 +1590,214 @@ mod tests {
|
||||
assert_eq!(table.get_columns_widths(10, 0), [(0, 5), (5, 5)]);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn test_table_with_selection_and_marks<'line, Lines, Marks>(
|
||||
highlight_spacing: HighlightSpacing,
|
||||
columns: u16,
|
||||
spacing: u16,
|
||||
selection: Option<usize>,
|
||||
marks: Marks,
|
||||
expected: Lines,
|
||||
) where
|
||||
Lines: IntoIterator,
|
||||
Lines::Item: Into<Line<'line>>,
|
||||
Marks: IntoIterator<Item = usize>,
|
||||
{
|
||||
let table = Table::default()
|
||||
.rows(vec![Row::new(vec!["ABCDE", "12345"])])
|
||||
.highlight_spacing(highlight_spacing)
|
||||
.highlight_symbol(">>>")
|
||||
.mark_symbol(" MMM ")
|
||||
.mark_highlight_symbol(" >M> ")
|
||||
.column_spacing(spacing);
|
||||
let area = Rect::new(0, 0, columns, 3);
|
||||
let mut buf = Buffer::empty(area);
|
||||
let mut state = TableState::default().with_selected(selection);
|
||||
for mark in marks {
|
||||
state.mark(mark);
|
||||
}
|
||||
StatefulWidget::render(table, area, &mut buf, &mut state);
|
||||
assert_eq!(buf, Buffer::with_lines(expected));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn highlight_symbol_mark_symbol_and_column_spacing_with_highlight_spacing() {
|
||||
// no highlight_symbol or mark_symbol rendered ever
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Never,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[], // marks
|
||||
[
|
||||
"ABCDE 12345 ", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
// no highlight_symbol or mark_symbol rendered ever
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Never,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[0], // marks
|
||||
[
|
||||
"ABCDE 12345 ", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
// no highlight_symbol or mark_symbol rendered ever
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Never,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[], // marks
|
||||
[
|
||||
"ABCDE 12345 ", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// no highlight_symbol or mark_symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::WhenSelected,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[], // marks
|
||||
[
|
||||
"ABCDE 12345 ", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// mark_symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::WhenSelected,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[0], // marks
|
||||
[
|
||||
" MMM ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// highlight symbol rendered with mark symbol width
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::WhenSelected,
|
||||
15, // width
|
||||
0, // spacing
|
||||
Some(0), // selection
|
||||
[], // marks
|
||||
[
|
||||
">>> ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// mark highlight symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::WhenSelected,
|
||||
15, // width
|
||||
0, // spacing
|
||||
Some(0), // selection
|
||||
[0], // marks
|
||||
[
|
||||
" >M> ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// no highlight_symbol or mark_symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Always,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[], // marks
|
||||
[
|
||||
" ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// mark_symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Always,
|
||||
15, // width
|
||||
0, // spacing
|
||||
None, // selection
|
||||
[0], // marks
|
||||
[
|
||||
" MMM ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// highlight symbol rendered with mark symbol width
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Always,
|
||||
15, // width
|
||||
0, // spacing
|
||||
Some(0), // selection
|
||||
[], // marks
|
||||
[
|
||||
">>> ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
|
||||
// mark highlight symbol rendered
|
||||
test_table_with_selection_and_marks(
|
||||
HighlightSpacing::Always,
|
||||
15, // width
|
||||
0, // spacing
|
||||
Some(0), // selection
|
||||
[0], // marks
|
||||
[
|
||||
" >M> ABCDE12345", /* default layout is Flex::Start but columns length
|
||||
* constraints are calculated as `max_area / n_columns`,
|
||||
* i.e. they are distributed amongst available space */
|
||||
" ", // row 2
|
||||
" ", // row 3
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn test_table_with_selection<'line, Lines>(
|
||||
highlight_spacing: HighlightSpacing,
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
pub struct TableState {
|
||||
pub(crate) offset: usize,
|
||||
pub(crate) selected: Option<usize>,
|
||||
pub(crate) marked: Vec<usize>,
|
||||
}
|
||||
|
||||
impl TableState {
|
||||
@@ -64,6 +65,7 @@ impl TableState {
|
||||
Self {
|
||||
offset: 0,
|
||||
selected: None,
|
||||
marked: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,6 +177,78 @@ impl TableState {
|
||||
self.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the index of the row as marked
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// let mut state = TableState::default();
|
||||
/// state.mark(1);
|
||||
/// ```
|
||||
pub fn mark(&mut self, index: usize) {
|
||||
if !self.marked.contains(&index) {
|
||||
self.marked.push(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the index of the row as unmarked
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// let mut state = TableState::default();
|
||||
/// state.unmark(1);
|
||||
/// ```
|
||||
pub fn unmark(&mut self, index: usize) {
|
||||
self.marked.retain(|i| *i != index);
|
||||
}
|
||||
|
||||
/// Toggles the index of the row as marked or unmarked
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// let mut state = TableState::default();
|
||||
/// state.toggle_mark(1);
|
||||
/// ```
|
||||
pub fn toggle_mark(&mut self, index: usize) {
|
||||
if self.marked.contains(&index) {
|
||||
self.unmark(index);
|
||||
} else {
|
||||
self.mark(index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a iterator of all marked rows
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// # use itertools::Itertools;
|
||||
/// let mut state = TableState::default();
|
||||
/// state.marked().contains(&1);
|
||||
/// ```
|
||||
pub fn marked(&self) -> std::slice::Iter<'_, usize> {
|
||||
self.marked.iter()
|
||||
}
|
||||
|
||||
/// Clears all marks from all rows
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::{prelude::*, widgets::*};
|
||||
/// let mut state = TableState::default();
|
||||
/// state.clear_marks();
|
||||
/// ```
|
||||
pub fn clear_marks(&mut self) {
|
||||
self.marked.drain(..);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// not too happy about the redundancy in these tests,
|
||||
// but if that helps readability then it's ok i guess /shrug
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::{backend::TestBackend, prelude::*, widgets::*};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
@@ -98,7 +99,8 @@ const DEFAULT_STATE_REPR: &str = r#"{
|
||||
},
|
||||
"table": {
|
||||
"offset": 0,
|
||||
"selected": null
|
||||
"selected": null,
|
||||
"marked": []
|
||||
},
|
||||
"scrollbar": {
|
||||
"content_length": 10,
|
||||
@@ -135,7 +137,8 @@ const SELECTED_STATE_REPR: &str = r#"{
|
||||
},
|
||||
"table": {
|
||||
"offset": 0,
|
||||
"selected": 1
|
||||
"selected": 1,
|
||||
"marked": []
|
||||
},
|
||||
"scrollbar": {
|
||||
"content_length": 10,
|
||||
@@ -174,7 +177,8 @@ const SCROLLED_STATE_REPR: &str = r#"{
|
||||
},
|
||||
"table": {
|
||||
"offset": 4,
|
||||
"selected": 8
|
||||
"selected": 8,
|
||||
"marked": []
|
||||
},
|
||||
"scrollbar": {
|
||||
"content_length": 10,
|
||||
|
||||
Reference in New Issue
Block a user