1 | //! This module contains a [`Shadow`] option for a [`Table`]. |
2 | //! |
3 | //! # Example |
4 | //! |
5 | //! ``` |
6 | //! use tabled::{Table, settings::{Shadow, Style}}; |
7 | //! |
8 | //! let data = vec!["Hello" , "World" , "!" ]; |
9 | //! |
10 | //! let table = Table::new(data) |
11 | //! .with(Style::markdown()) |
12 | //! .with(Shadow::new(1)) |
13 | //! .to_string(); |
14 | //! |
15 | //! assert_eq!( |
16 | //! table, |
17 | //! concat!( |
18 | //! "| &str | \n" , |
19 | //! "|-------|▒ \n" , |
20 | //! "| Hello |▒ \n" , |
21 | //! "| World |▒ \n" , |
22 | //! "| ! |▒ \n" , |
23 | //! " ▒▒▒▒▒▒▒▒▒" , |
24 | //! ) |
25 | //! ); |
26 | //! ``` |
27 | //! |
28 | //! [`Table`]: crate::Table |
29 | |
30 | use crate::{ |
31 | grid::color::AnsiColor, |
32 | grid::config::{ColoredConfig, Indent, Offset, Sides}, |
33 | settings::{color::Color, TableOption}, |
34 | }; |
35 | |
36 | /// The structure represents a shadow of a table. |
37 | /// |
38 | /// NOTICE: It uses [`Margin`] therefore it often can't be combined. |
39 | /// |
40 | /// [`Margin`]: crate::settings::Margin |
41 | #[derive (Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] |
42 | pub struct Shadow { |
43 | c: char, |
44 | size: usize, |
45 | size_offset: usize, |
46 | direction: Sides<bool>, |
47 | color: Option<Color>, |
48 | } |
49 | |
50 | impl Shadow { |
51 | /// A default fill character to be used. |
52 | pub const DEFAULT_FILL: char = '▒' ; |
53 | |
54 | /// Construct's an [`Shadow`] object with default fill [`Shadow::DEFAULT_FILL`]. |
55 | /// |
56 | /// It uses space(' ') as a default fill character. |
57 | /// To set a custom character you can use [`Self::set_fill`] function. |
58 | pub fn new(size: usize) -> Self { |
59 | Self { |
60 | c: Self::DEFAULT_FILL, |
61 | size, |
62 | size_offset: 1, |
63 | direction: Sides::new(false, true, false, true), |
64 | color: None, |
65 | } |
66 | } |
67 | |
68 | /// The function, sets a characters for the [`Shadow`] to be used. |
69 | pub fn set_fill(mut self, c: char) -> Self { |
70 | self.c = c; |
71 | self |
72 | } |
73 | |
74 | /// Set an offset value (default is '1'). |
75 | pub fn set_offset(mut self, size: usize) -> Self { |
76 | self.size_offset = size; |
77 | self |
78 | } |
79 | |
80 | /// Switch shadow to top. |
81 | pub fn set_top(mut self) -> Self { |
82 | self.direction.top = true; |
83 | self.direction.bottom = false; |
84 | self |
85 | } |
86 | |
87 | /// Switch shadow to bottom. |
88 | pub fn set_bottom(mut self) -> Self { |
89 | self.direction.bottom = true; |
90 | self.direction.top = false; |
91 | self |
92 | } |
93 | |
94 | /// Switch shadow to left. |
95 | pub fn set_left(mut self) -> Self { |
96 | self.direction.left = true; |
97 | self.direction.right = false; |
98 | self |
99 | } |
100 | |
101 | /// Switch shadow to right. |
102 | pub fn set_right(mut self) -> Self { |
103 | self.direction.right = true; |
104 | self.direction.left = false; |
105 | self |
106 | } |
107 | |
108 | /// Sets a color for a shadow. |
109 | pub fn set_color(mut self, color: Color) -> Self { |
110 | self.color = Some(color); |
111 | self |
112 | } |
113 | } |
114 | |
115 | impl<R, D> TableOption<R, D, ColoredConfig> for Shadow { |
116 | fn change(self, _: &mut R, cfg: &mut ColoredConfig, _: &mut D) { |
117 | set_margin(cfg, self.size, self.c, &self.direction); |
118 | set_margin_offset(cfg, self.size_offset, &self.direction); |
119 | |
120 | if let Some(color: &Color) = &self.color { |
121 | set_margin_color(cfg, color:color.clone().into(), &self.direction); |
122 | } |
123 | } |
124 | } |
125 | |
126 | fn set_margin(cfg: &mut ColoredConfig, size: usize, c: char, direction: &Sides<bool>) { |
127 | let mut margin: Sides<Indent> = Sides::default(); |
128 | if direction.top { |
129 | margin.top.size = size; |
130 | margin.top.fill = c; |
131 | } |
132 | |
133 | if direction.bottom { |
134 | margin.bottom.size = size; |
135 | margin.bottom.fill = c; |
136 | } |
137 | |
138 | if direction.left { |
139 | margin.left.size = size; |
140 | margin.left.fill = c; |
141 | } |
142 | |
143 | if direction.right { |
144 | margin.right.size = size; |
145 | margin.right.fill = c; |
146 | } |
147 | |
148 | cfg.set_margin(margin); |
149 | } |
150 | |
151 | fn set_margin_offset(cfg: &mut ColoredConfig, size: usize, direction: &Sides<bool>) { |
152 | let mut margin: Sides = Sides::filled(Offset::Begin(0)); |
153 | if direction.right && direction.bottom { |
154 | margin.bottom = Offset::Begin(size); |
155 | margin.right = Offset::Begin(size); |
156 | } |
157 | |
158 | if direction.right && direction.top { |
159 | margin.top = Offset::Begin(size); |
160 | margin.right = Offset::End(size); |
161 | } |
162 | |
163 | if direction.left && direction.bottom { |
164 | margin.bottom = Offset::End(size); |
165 | margin.left = Offset::Begin(size); |
166 | } |
167 | |
168 | if direction.left && direction.top { |
169 | margin.top = Offset::End(size); |
170 | margin.left = Offset::End(size); |
171 | } |
172 | |
173 | cfg.set_margin_offset(margin); |
174 | } |
175 | |
176 | fn set_margin_color(cfg: &mut ColoredConfig, color: AnsiColor<'static>, direction: &Sides<bool>) { |
177 | let mut margin: Sides<Option<AnsiColor<'static>>> = Sides::default(); |
178 | if direction.right { |
179 | margin.right = Some(color.clone()); |
180 | } |
181 | |
182 | if direction.top { |
183 | margin.top = Some(color.clone()); |
184 | } |
185 | |
186 | if direction.left { |
187 | margin.left = Some(color.clone()); |
188 | } |
189 | |
190 | if direction.bottom { |
191 | margin.bottom = Some(color.clone()); |
192 | } |
193 | |
194 | cfg.set_margin_color(margin); |
195 | } |
196 | |