Skip to content

Commit

Permalink
Improve style of toggled rows
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasPickering committed Jan 14, 2024
1 parent d575b79 commit 4bd659f
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 29 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased] - ReleaseDate

### Changed

- Improved styling of toggled table rows

## [0.12.0] - 2024-01-07

### Added
Expand Down
105 changes: 95 additions & 10 deletions src/tui/view/common/table.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
use crate::tui::{context::TuiContext, view::draw::Generate};
use crate::tui::{
context::TuiContext,
view::{common::Checkbox, draw::Generate},
};
use itertools::Itertools;
use ratatui::{
prelude::Constraint,
style::Styled,
text::Text,
widgets::{Block, Cell, Row},
};
use std::{iter, marker::PhantomData};

/// Tabular data display with a static number of columns
/// Tabular data display with a static number of columns.
///
/// The `R` generic defines the row type, which should be either an array of
/// cell types (e.g. `[Text; 3]`) or [ratatui::widgets::Row]. If using an array,
/// the length should match `COLS`. Allowing `Row` makes it possible to override
/// styling on a row-by-row basis.
#[derive(Debug)]
pub struct Table<'a, const COLS: usize, Rows> {
pub struct Table<'a, const COLS: usize, R> {
pub title: Option<&'a str>,
pub rows: Rows,
pub rows: Vec<R>,
/// Optional header row. Length should match column length
pub header: Option<[&'a str; COLS]>,
/// Use a different styling for alternating rows
Expand All @@ -31,28 +43,48 @@ impl<'a, const COLS: usize, Rows: Default> Default for Table<'a, COLS, Rows> {
}
}

impl<'a, const COLS: usize, Cll, Rows> Generate for Table<'a, COLS, Rows>
impl<'a, const COLS: usize, Cll> Generate for Table<'a, COLS, [Cll; COLS]>
where
Cll: Into<Cell<'a>>,
Rows: IntoIterator<Item = [Cll; COLS]>,
{
type Output<'this> = ratatui::widgets::Table<'this>
where
Self: 'this;

fn generate<'this>(self) -> Self::Output<'this>
where
Self: 'this,
{
let table = Table {
title: self.title,
alternate_row_style: self.alternate_row_style,
header: self.header,
column_widths: self.column_widths,
rows: self.rows.into_iter().map(Row::new).collect_vec(),
};
table.generate()
}
}

impl<'a, const COLS: usize> Generate for Table<'a, COLS, Row<'a>> {
type Output<'this> = ratatui::widgets::Table<'this>
where
Self: 'this;

fn generate<'this>(self) -> Self::Output<'this>
where
Self: 'this,
{
let theme = &TuiContext::get().theme;
let rows = self.rows.into_iter().enumerate().map(|(i, row)| {
// Alternate row style for readability
let style = if self.alternate_row_style && i % 2 == 1 {
theme.table_alt_text_style
// Apply theme styles, but let the row's individual styles override
let base_style = if self.alternate_row_style && i % 2 == 1 {
theme.table_alt_style
} else {
theme.table_text_style
};
Row::new(row).style(style)
let row_style = Styled::style(&row);
row.set_style(base_style.patch(row_style))
});
let mut table = ratatui::widgets::Table::new(rows, self.column_widths)
.highlight_style(theme.table_highlight_style);
Expand All @@ -75,3 +107,56 @@ where
table
}
}

/// A row in a table that can be toggled on/off. This will generate the checkbox
/// column, and apply the appropriate row styling.
#[derive(Debug)]
pub struct ToggleRow<'a, Cells> {
/// Needed to attach the lifetime of this value to the lifetime of the
/// generated row
phantom: PhantomData<&'a ()>,
cells: Cells,
enabled: bool,
}

impl<'a, Cells> ToggleRow<'a, Cells> {
pub fn new(cells: Cells, enabled: bool) -> Self {
Self {
phantom: PhantomData,
cells,
enabled,
}
}
}

impl<'a, Cells> Generate for ToggleRow<'a, Cells>
where
Cells: IntoIterator,
Cells::Item: Into<Text<'a>>,
{
type Output<'this> = Row<'this>
where
Self: 'this;

fn generate<'this>(self) -> Self::Output<'this>
where
Self: 'this,
{
let theme = &TuiContext::get().theme;
// Include the given cells, then tack on the checkbox for enabled state
Row::new(
self.cells.into_iter().map(Cell::from).chain(iter::once(
Checkbox {
checked: self.enabled,
}
.generate()
.into(),
)),
)
.style(if self.enabled {
theme.table_text_style
} else {
theme.table_disabled_style
})
}
}
2 changes: 1 addition & 1 deletion src/tui/view/component/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl Draw for HelpModal {
// Collection metadata
let collection_metadata = Table {
title: Some("General"),
rows: [
rows: vec![
[
Line::from("Configuration"),
Line::from(tui_context.config.path().display().to_string())
Expand Down
28 changes: 13 additions & 15 deletions src/tui/view/component/recipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ use crate::{
input::Action,
view::{
common::{
actions::ActionsModal, table::Table, tabs::Tabs,
template_preview::TemplatePreview, text_window::TextWindow,
Checkbox, Pane,
actions::ActionsModal,
table::{Table, ToggleRow},
tabs::Tabs,
template_preview::TemplatePreview,
text_window::TextWindow,
Pane,
},
component::primary::PrimaryPane,
draw::{Draw, Generate, ToStringGenerate},
Expand All @@ -29,8 +32,7 @@ use derive_more::Display;
use itertools::Itertools;
use ratatui::{
prelude::{Constraint, Direction, Rect},
text::Text,
widgets::{Paragraph, TableState},
widgets::{Paragraph, Row, TableState},
Frame,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -395,20 +397,17 @@ impl RowState {
fn to_table<'a>(
state: &'a SelectState<Dynamic, RowState, TableState>,
header: [&'a str; 3],
) -> Table<'a, 3, Vec<[Text<'a>; 3]>> {
) -> Table<'a, 3, Row<'a>> {
Table {
rows: state
.items()
.iter()
.map(|item| {
[
item.key.as_str().into(),
item.value.generate(),
Checkbox {
checked: *item.enabled,
}
.generate(),
]
ToggleRow::new(
[item.key.as_str().into(), item.value.generate()],
*item.enabled,
)
.generate()
})
.collect_vec(),
header: Some(header),
Expand All @@ -417,7 +416,6 @@ fn to_table<'a>(
Constraint::Percentage(50),
Constraint::Min(3),
],
alternate_row_style: true,
..Default::default()
}
}
Expand Down
11 changes: 8 additions & 3 deletions src/tui/view/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ pub struct Theme {
/// Table column header text
pub table_header_style: Style,
pub table_text_style: Style,
pub table_alt_text_style: Style,
pub table_alt_style: Style,
pub table_disabled_style: Style,
pub table_highlight_style: Style,
pub table_title_style: Style,

Expand Down Expand Up @@ -70,11 +71,15 @@ impl Default for Theme {
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::UNDERLINED),
table_text_style: Style::default(),
table_alt_text_style: Style::default().bg(Color::DarkGray),
table_alt_style: Style::default().bg(Color::DarkGray),
table_disabled_style: Style::default()
.fg(Color::DarkGray)
.add_modifier(Modifier::CROSSED_OUT),
table_highlight_style: Style::default()
.bg(PRIMARY_COLOR)
.fg(Color::Black)
.add_modifier(Modifier::BOLD),
.add_modifier(Modifier::BOLD)
.add_modifier(Modifier::UNDERLINED),
table_title_style: Style::default().add_modifier(Modifier::BOLD),

template_preview_text: Style::default().fg(Color::Blue),
Expand Down

0 comments on commit 4bd659f

Please sign in to comment.