Skip to content

Commit

Permalink
Add PaddingExpand setting to expand Padding to set Color
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiburt committed Jul 19, 2024
1 parent 2d82644 commit 27187f2
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 56 deletions.
64 changes: 8 additions & 56 deletions tabled/examples/colored_padding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,10 @@ use std::convert::TryFrom;
use owo_colors::OwoColorize;

use tabled::{
grid::{
config::{ColoredConfig, Entity},
dimension::SpannedGridDimension,
records::{
vec_records::{Cell, VecRecords},
ExactRecords, PeekableRecords, Records,
},
util::string::string_width_multiline,
},
settings::{
object::{Columns, Object, Rows, Segment},
Alignment, CellOption, Color, Format, Margin, MarginColor, Modify, Padding, PaddingColor,
Style,
style::BorderColor,
Alignment, Color, Format, Margin, MarginColor, Modify, Padding, PaddingColor, Style,
},
Table, Tabled,
};
Expand Down Expand Up @@ -73,19 +64,14 @@ fn main() {
Color::BG_MAGENTA,
Color::BG_CYAN,
))
.with(MakeMaxPadding)
.with(Alignment::center())
.with(Padding::expand(true))
.with(Format::content(|s| s.on_black().white().to_string()));

let data_settings = Modify::new(Rows::first().inverse())
.with(Alignment::left())
.with(MakeMaxPadding)
.with(Padding::new(1, 1, 0, 0))
.with(PaddingColor::new(
Color::default(),
Color::default(),
data_color.clone(),
data_color.clone(),
));
.with(Alignment::center())
.with(Padding::expand(true))
.with(PaddingColor::filled(data_color.clone()));

let symbol_settings = Modify::new(Columns::single(1).not(Rows::first()))
.with(Format::content(|s| s.bold().to_string()));
Expand All @@ -97,7 +83,7 @@ fn main() {
.with(Style::rounded())
.with(Margin::new(1, 2, 1, 1))
.with(MarginColor::filled(pane_color))
.with(border_color)
.with(BorderColor::filled(border_color))
.with(Modify::new(Segment::all()).with(data_color))
.with(header_settings)
.with(data_settings)
Expand All @@ -107,37 +93,3 @@ fn main() {

println!("\n\n{table}\n\n");
}

#[derive(Debug, Clone)]
struct MakeMaxPadding;

impl<T> CellOption<VecRecords<T>, ColoredConfig> for MakeMaxPadding
where
T: Cell + AsRef<str>,
{
fn change(self, records: &mut VecRecords<T>, cfg: &mut ColoredConfig, entity: Entity) {
let widths = SpannedGridDimension::width(&*records, cfg);

let count_rows = records.count_rows();
let count_cols = records.count_columns();

for (row, col) in entity.iter(count_rows, count_cols) {
let column_width = widths[col];
let text = records.get_text((row, col));
let width = string_width_multiline(text);

if width < column_width {
let available_width = column_width - width;
let left = available_width / 2;
let right = available_width - left;

let pos = (row, col).into();
let mut pad = cfg.get_padding(pos);
pad.left.size = left;
pad.right.size = right;

cfg.set_padding(pos, pad);
}
}
}
}
3 changes: 3 additions & 0 deletions tabled/src/settings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ pub mod measurement;
pub mod merge;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod padding_expand;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
pub mod panel;
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
Expand Down
14 changes: 14 additions & 0 deletions tabled/src/settings/padding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use crate::{
settings::CellOption,
};

use super::padding_expand::PaddingExpand;

/// Padding is responsible for a left/right/top/bottom inner indent of a particular cell.
///
/// # Example
Expand Down Expand Up @@ -101,8 +103,19 @@ impl Padding {
self.indent.bottom.fill = bottom;
self
}

#[cfg(feature = "std")]
/// Construct's an PaddingExpand object.
pub const fn expand(horizontal: bool) -> PaddingExpand {
if horizontal {
PaddingExpand::Horizontal
} else {
PaddingExpand::Vertical
}
}
}

#[cfg(feature = "std")]
impl<R> CellOption<R, ColoredConfig> for Padding {
fn change(self, _: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
let indent = self.indent;
Expand All @@ -111,6 +124,7 @@ impl<R> CellOption<R, ColoredConfig> for Padding {
}
}

#[cfg(feature = "std")]
impl<R, D> TableOption<R, ColoredConfig, D> for Padding {
fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
<Self as CellOption<R, ColoredConfig>>::change(self, records, cfg, Entity::Global)
Expand Down
187 changes: 187 additions & 0 deletions tabled/src/settings/padding_expand/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
//! This module contains a [`PaddingExpand`] setting to expand cells padding to its limit a cell.
use papergrid::{
config::{AlignmentHorizontal, AlignmentVertical},
dimension::spanned::SpannedGridDimension,
records::{ExactRecords, IntoRecords, PeekableRecords, Records},
};

#[cfg(feature = "std")]
use crate::{
grid::{config::ColoredConfig, config::Entity},
settings::CellOption,
};

use super::TableOption;

/// PaddingExpand is able to expand padding to its limit a cell.
/// Maybe usefull in cases were its colorization is supposed to be used next.
///
/// # Example
///
#[cfg_attr(feature = "ansi", doc = "```")]
#[cfg_attr(not(feature = "ansi"), doc = "```ignore")]
/// use std::iter::FromIterator;
///
/// use tabled::{
/// settings::{Padding, Style, Color, PaddingColor},
/// Table,
/// };
///
/// let char_split = |s: &str| s.chars().map(|c| c.to_string()).collect::<Vec<_>>();
/// let data = vec![
/// char_split("2021"),
/// char_split("2022"),
/// char_split("2023"),
/// char_split("2024"),
/// ];
///
/// let table = Table::from_iter(&data)
/// .with(Style::ascii())
/// .with(PaddingColor::filled(Color::BG_BLUE))
/// .modify((2, 1), Padding::new(2, 2, 3, 3))
/// .with(Padding::expand(true))
/// .with(Padding::expand(false))
/// .to_string();
///
/// assert_eq!(
/// table,
/// concat!(
/// "+---+-----+---+---+\n",
/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|1\u{1b}[44m \u{1b}[49m|\n",
/// "+---+-----+---+---+\n",
/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|\n",
/// "+---+-----+---+---+\n",
/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|3\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\u{1b}[44m \u{1b}[49m|\n",
/// "+---+-----+---+---+\n",
/// "|2\u{1b}[44m \u{1b}[49m|0\u{1b}[44m \u{1b}[49m|2\u{1b}[44m \u{1b}[49m|4\u{1b}[44m \u{1b}[49m|\n",
/// "+---+-----+---+---+",
/// ),
/// );
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum PaddingExpand {
/// Horizontal expansion of padding (LEFT and RIGHT)
Horizontal,
/// Vertical expansion of padding (TOP and BOTTOM)
Vertical,
}

impl<R, D> TableOption<R, ColoredConfig, D> for PaddingExpand
where
R: Records + ExactRecords + PeekableRecords,
for<'a> &'a R: Records,
for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
{
fn change(self, records: &mut R, cfg: &mut ColoredConfig, _: &mut D) {
<Self as CellOption<R, ColoredConfig>>::change(self, records, cfg, Entity::Global)
}
}

impl<R> CellOption<R, ColoredConfig> for PaddingExpand
where
R: Records + ExactRecords + PeekableRecords,
for<'a> &'a R: Records,
for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
{
fn change(self, records: &mut R, cfg: &mut ColoredConfig, entity: Entity) {
match self {
PaddingExpand::Vertical => expand_vertical(records, cfg, entity),
PaddingExpand::Horizontal => expand_horizontal(records, cfg, entity),
}
}
}

fn expand_horizontal<R>(records: &mut R, cfg: &mut ColoredConfig, entity: Entity)
where
R: Records + ExactRecords + PeekableRecords,
for<'a> &'a R: Records,
for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
{
let widths = SpannedGridDimension::width(&*records, cfg);

let count_rows = records.count_rows();
let count_cols = records.count_columns();

for (row, col) in entity.iter(count_rows, count_cols) {
let pos = Entity::Cell(row, col);

let column_width = widths[col];
let width = records.get_width((row, col));

if width < column_width {
let alignment = *cfg.get_alignment_horizontal(pos);

let available_width = column_width - width;
let (left, right) = split_horizontal_space(alignment, available_width);

let mut pad = cfg.get_padding(pos);
pad.left.size = left;
pad.right.size = right;

cfg.set_padding(pos, pad);
}
}
}

fn expand_vertical<R>(records: &mut R, cfg: &mut ColoredConfig, entity: Entity)
where
R: Records + ExactRecords + PeekableRecords,
for<'a> &'a R: Records,
for<'a> <<&'a R as Records>::Iter as IntoRecords>::Cell: AsRef<str>,
{
let heights = SpannedGridDimension::height(&*records, cfg);

let count_rows = records.count_rows();
let count_cols = records.count_columns();

for (row, col) in entity.iter(count_rows, count_cols) {
let pos = Entity::Cell(row, col);

let row_height = heights[row];
let cell_height = records.count_lines((row, col));

if cell_height < row_height {
let alignment = *cfg.get_alignment_vertical(pos);

let available_width = row_height - cell_height;
let (top, bottom) = split_vertical_space(alignment, available_width);

let mut pad = cfg.get_padding(pos);
pad.top.size = top;
pad.bottom.size = bottom;

cfg.set_padding(pos, pad);
}
}
}

fn split_horizontal_space(al: AlignmentHorizontal, space: usize) -> (usize, usize) {
match al {
AlignmentHorizontal::Center => {
let left = space / 2;
let right = space - left;
(left, right)
}
AlignmentHorizontal::Left => (0, space),
AlignmentHorizontal::Right => (space, 0),
}
}

fn split_vertical_space(al: AlignmentVertical, space: usize) -> (usize, usize) {
match al {
AlignmentVertical::Center => {
let left = space / 2;
let right = space - left;
(left, right)
}
AlignmentVertical::Top => (0, space),
AlignmentVertical::Bottom => (space, 0),
}
}

0 comments on commit 27187f2

Please sign in to comment.