| 1 | //! This module contains a configuration of a Border to set its color via [`BorderColor`]. |
| 2 | |
| 3 | use core::marker::PhantomData; |
| 4 | |
| 5 | use crate::{ |
| 6 | grid::{ |
| 7 | config::{Border as GridBorder, ColoredConfig, Entity}, |
| 8 | records::{ExactRecords, Records}, |
| 9 | }, |
| 10 | settings::{style::On, CellOption, Color, TableOption}, |
| 11 | }; |
| 12 | |
| 13 | /// Border represents a border color of a Cell. |
| 14 | /// |
| 15 | /// ```text |
| 16 | /// top border |
| 17 | /// | |
| 18 | /// V |
| 19 | /// corner top left ------> +_______+ <---- corner top left |
| 20 | /// | | |
| 21 | /// left border ----------> | cell | <---- right border |
| 22 | /// | | |
| 23 | /// corner bottom right --> +_______+ <---- corner bottom right |
| 24 | /// ^ |
| 25 | /// | |
| 26 | /// bottom border |
| 27 | /// ``` |
| 28 | /// |
| 29 | /// # Example |
| 30 | /// |
| 31 | /// ```rust,no_run |
| 32 | /// # use tabled::{Table, settings::{style::{Style, BorderColor}, object::Rows, Color}}; |
| 33 | /// # let data: Vec<&'static str> = Vec::new(); |
| 34 | /// let table = Table::new(&data) |
| 35 | /// .with(Style::ascii()) |
| 36 | /// .modify(Rows::single(0), BorderColor::new().set_top(Color::FG_RED)); |
| 37 | /// ``` |
| 38 | #[derive (Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] |
| 39 | pub struct BorderColor<T, B, L, R> { |
| 40 | inner: GridBorder<Color>, |
| 41 | _top: PhantomData<T>, |
| 42 | _bottom: PhantomData<B>, |
| 43 | _left: PhantomData<L>, |
| 44 | _right: PhantomData<R>, |
| 45 | } |
| 46 | |
| 47 | impl<T, B, L, R> BorderColor<T, B, L, R> { |
| 48 | pub(crate) const fn from_border(inner: GridBorder<Color>) -> BorderColor<T, B, L, R> { |
| 49 | BorderColor { |
| 50 | inner, |
| 51 | _top: PhantomData, |
| 52 | _bottom: PhantomData, |
| 53 | _left: PhantomData, |
| 54 | _right: PhantomData, |
| 55 | } |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | impl BorderColor<(), (), (), ()> { |
| 60 | /// Creates an empty border. |
| 61 | pub const fn new() -> Self { |
| 62 | Self::from_border(inner:GridBorder::empty()) |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | impl BorderColor<On, On, On, On> { |
| 67 | /// This function constructs a cell borders with all sides set. |
| 68 | #[allow (clippy::too_many_arguments)] |
| 69 | pub const fn full( |
| 70 | top: Color, |
| 71 | bottom: Color, |
| 72 | left: Color, |
| 73 | right: Color, |
| 74 | top_left: Color, |
| 75 | top_right: Color, |
| 76 | bottom_left: Color, |
| 77 | bottom_right: Color, |
| 78 | ) -> Self { |
| 79 | Self::from_border(GridBorder::full( |
| 80 | top, |
| 81 | bottom, |
| 82 | left, |
| 83 | right, |
| 84 | top_left, |
| 85 | top_right, |
| 86 | bottom_left, |
| 87 | bottom_right, |
| 88 | )) |
| 89 | } |
| 90 | |
| 91 | /// This function constructs a cell borders with all sides's char set to a given color. |
| 92 | /// It behaves like [`BorderColor::full`] with the same color set to each side. |
| 93 | pub fn filled(c: Color) -> Self { |
| 94 | Self::full( |
| 95 | c.clone(), |
| 96 | c.clone(), |
| 97 | c.clone(), |
| 98 | c.clone(), |
| 99 | c.clone(), |
| 100 | c.clone(), |
| 101 | c.clone(), |
| 102 | c, |
| 103 | ) |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | impl<T, B, L, R> BorderColor<T, B, L, R> { |
| 108 | /// Set a top border color. |
| 109 | pub fn set_top(mut self, c: Color) -> BorderColor<On, B, L, R> { |
| 110 | self.inner.top = Some(c); |
| 111 | BorderColor::from_border(self.inner) |
| 112 | } |
| 113 | |
| 114 | /// Set a bottom border color. |
| 115 | pub fn set_bottom(mut self, c: Color) -> BorderColor<T, On, L, R> { |
| 116 | self.inner.bottom = Some(c); |
| 117 | BorderColor::from_border(self.inner) |
| 118 | } |
| 119 | |
| 120 | /// Set a left border color. |
| 121 | pub fn set_left(mut self, c: Color) -> BorderColor<T, B, On, R> { |
| 122 | self.inner.left = Some(c); |
| 123 | BorderColor::from_border(self.inner) |
| 124 | } |
| 125 | |
| 126 | /// Set a right border color. |
| 127 | pub fn set_right(mut self, c: Color) -> BorderColor<T, B, L, On> { |
| 128 | self.inner.right = Some(c); |
| 129 | BorderColor::from_border(self.inner) |
| 130 | } |
| 131 | |
| 132 | /// Converts a border into a general data structure. |
| 133 | pub fn into_inner(self) -> GridBorder<Color> { |
| 134 | self.inner |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | impl<T, B, L> BorderColor<T, B, L, On> { |
| 139 | /// Get a right color. |
| 140 | pub fn get_right(&self) -> Color { |
| 141 | get_color(self.inner.right.clone()) |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | impl<T, B, R> BorderColor<T, B, On, R> { |
| 146 | /// Get a left color. |
| 147 | pub fn get_left(&self) -> Color { |
| 148 | get_color(self.inner.left.clone()) |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | impl<B, L, R> BorderColor<On, B, L, R> { |
| 153 | /// Get a top color. |
| 154 | pub fn get_top(&self) -> Color { |
| 155 | get_color(self.inner.top.clone()) |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | impl<T, L, R> BorderColor<T, On, L, R> { |
| 160 | /// Get a bottom color. |
| 161 | pub fn get_bottom(&self) -> Color { |
| 162 | get_color(self.inner.bottom.clone()) |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | impl<B, R> BorderColor<On, B, On, R> { |
| 167 | /// Set a top left intersection color. |
| 168 | pub fn set_corner_top_left(mut self, c: Color) -> Self { |
| 169 | self.inner.left_top_corner = Some(c); |
| 170 | self |
| 171 | } |
| 172 | |
| 173 | /// Get a top left intersection color. |
| 174 | pub fn get_corner_top_left(&self) -> Color { |
| 175 | get_color(self.inner.left_top_corner.clone()) |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | impl<B, L> BorderColor<On, B, L, On> { |
| 180 | /// Set a top right intersection color. |
| 181 | pub fn set_corner_top_right(mut self, c: Color) -> Self { |
| 182 | self.inner.right_top_corner = Some(c); |
| 183 | self |
| 184 | } |
| 185 | |
| 186 | /// Get a top right intersection color. |
| 187 | pub fn get_corner_top_right(&self) -> Color { |
| 188 | get_color(self.inner.right_top_corner.clone()) |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | impl<T, R> BorderColor<T, On, On, R> { |
| 193 | /// Set a bottom left intersection color. |
| 194 | pub fn set_corner_bottom_left(mut self, c: Color) -> Self { |
| 195 | self.inner.left_bottom_corner = Some(c); |
| 196 | self |
| 197 | } |
| 198 | |
| 199 | /// Get a bottom left intersection color. |
| 200 | pub fn get_corner_bottom_left(&self) -> Color { |
| 201 | get_color(self.inner.left_bottom_corner.clone()) |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | impl<T, L> BorderColor<T, On, L, On> { |
| 206 | /// Set a bottom right intersection color. |
| 207 | pub fn set_corner_bottom_right(mut self, c: Color) -> Self { |
| 208 | self.inner.right_bottom_corner = Some(c); |
| 209 | self |
| 210 | } |
| 211 | |
| 212 | /// Get a bottom left intersection color. |
| 213 | pub fn get_corner_bottom_right(&self) -> Color { |
| 214 | get_color(self.inner.right_bottom_corner.clone()) |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | impl<T, B, L, R> From<BorderColor<T, B, L, R>> for GridBorder<Color> { |
| 219 | fn from(value: BorderColor<T, B, L, R>) -> Self { |
| 220 | value.inner |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | impl<Data, T, B, L, R> CellOption<Data, ColoredConfig> for BorderColor<T, B, L, R> |
| 225 | where |
| 226 | Data: Records + ExactRecords, |
| 227 | { |
| 228 | fn change(self, records: &mut Data, cfg: &mut ColoredConfig, entity: Entity) { |
| 229 | let count_rows: usize = records.count_rows(); |
| 230 | let count_columns: usize = records.count_columns(); |
| 231 | |
| 232 | let border_color: Border = self.inner.clone().convert(); |
| 233 | |
| 234 | for pos: (usize, usize) in entity.iter(count_rows, count_cols:count_columns) { |
| 235 | cfg.set_border_color(pos, border_color.clone()); |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | impl<Data, D, T, B, L, R> TableOption<Data, ColoredConfig, D> for BorderColor<T, B, L, R> |
| 241 | where |
| 242 | Data: Records + ExactRecords, |
| 243 | { |
| 244 | fn change(self, records: &mut Data, cfg: &mut ColoredConfig, _: &mut D) { |
| 245 | let count_rows: usize = records.count_rows(); |
| 246 | let count_columns: usize = records.count_columns(); |
| 247 | |
| 248 | let border_color: Border = self.inner.clone().convert(); |
| 249 | |
| 250 | for row: usize in 0..count_rows { |
| 251 | for col: usize in 0..count_columns { |
| 252 | cfg.set_border_color((row, col), border_color.clone()); |
| 253 | } |
| 254 | } |
| 255 | } |
| 256 | } |
| 257 | |
| 258 | fn get_color(c: Option<Color>) -> Color { |
| 259 | match c { |
| 260 | Some(c: Color) => c, |
| 261 | None => unreachable!(), |
| 262 | } |
| 263 | } |
| 264 | |