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 | |