1//! This module contains a configuration of a Border to set its color via [`BorderColor`].
2
3use core::marker::PhantomData;
4
5use 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)]
39pub 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
47impl<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
59impl BorderColor<(), (), (), ()> {
60 /// Creates an empty border.
61 pub const fn new() -> Self {
62 Self::from_border(inner:GridBorder::empty())
63 }
64}
65
66impl 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
107impl<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
138impl<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
145impl<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
152impl<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
159impl<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
166impl<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
179impl<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
192impl<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
205impl<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
218impl<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
224impl<Data, T, B, L, R> CellOption<Data, ColoredConfig> for BorderColor<T, B, L, R>
225where
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
240impl<Data, D, T, B, L, R> TableOption<Data, ColoredConfig, D> for BorderColor<T, B, L, R>
241where
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
258fn get_color(c: Option<Color>) -> Color {
259 match c {
260 Some(c: Color) => c,
261 None => unreachable!(),
262 }
263}
264