1//! A module which contains configuration options for a [`Grid`].
2//!
3//! [`Grid`]: crate::grid::iterable::Grid
4
5mod borders_config;
6mod entity_map;
7mod formatting;
8mod offset;
9
10use std::collections::HashMap;
11
12use crate::color::{AnsiColor, StaticColor};
13use crate::config::compact::CompactConfig;
14use crate::config::{
15 AlignmentHorizontal, AlignmentVertical, Border, Borders, Entity, Indent, Position, Sides,
16};
17use borders_config::BordersConfig;
18
19pub use self::{entity_map::EntityMap, formatting::Formatting, offset::Offset};
20
21/// This structure represents a settings of a grid.
22///
23/// grid: crate::Grid.
24#[derive(Debug, PartialEq, Eq, Clone)]
25pub struct SpannedConfig {
26 margin: Sides<ColoredMarginIndent>,
27 padding: EntityMap<Sides<ColoredIndent>>,
28 alignment_h: EntityMap<AlignmentHorizontal>,
29 alignment_v: EntityMap<AlignmentVertical>,
30 formatting: EntityMap<Formatting>,
31 span_columns: HashMap<Position, usize>,
32 span_rows: HashMap<Position, usize>,
33 borders: BordersConfig<char>,
34 borders_colors: BordersConfig<AnsiColor<'static>>,
35 borders_missing_char: char,
36 horizontal_chars: HashMap<Position, HashMap<Offset, char>>,
37 horizontal_colors: HashMap<Position, HashMap<Offset, AnsiColor<'static>>>,
38 vertical_chars: HashMap<Position, HashMap<Offset, char>>,
39 vertical_colors: HashMap<Position, HashMap<Offset, AnsiColor<'static>>>,
40 justification: EntityMap<char>,
41 justification_color: EntityMap<Option<AnsiColor<'static>>>,
42}
43
44impl Default for SpannedConfig {
45 fn default() -> Self {
46 Self {
47 margin: Sides::default(),
48 padding: EntityMap::default(),
49 formatting: EntityMap::default(),
50 alignment_h: EntityMap::new(global:AlignmentHorizontal::Left),
51 alignment_v: EntityMap::new(global:AlignmentVertical::Top),
52 span_columns: HashMap::default(),
53 span_rows: HashMap::default(),
54 borders: BordersConfig::default(),
55 borders_colors: BordersConfig::default(),
56 borders_missing_char: ' ',
57 horizontal_chars: HashMap::default(),
58 horizontal_colors: HashMap::default(),
59 vertical_chars: HashMap::default(),
60 vertical_colors: HashMap::default(),
61 justification: EntityMap::new(global:' '),
62 justification_color: EntityMap::default(),
63 }
64 }
65}
66
67impl SpannedConfig {
68 /// Set a margin of a grid.
69 pub fn set_margin(&mut self, margin: Sides<Indent>) {
70 self.margin.left.indent = margin.left;
71 self.margin.right.indent = margin.right;
72 self.margin.top.indent = margin.top;
73 self.margin.bottom.indent = margin.bottom;
74 }
75
76 /// Set a color of margin of a grid.
77 pub fn set_margin_color(&mut self, margin: Sides<Option<AnsiColor<'static>>>) {
78 self.margin.left.color = margin.left;
79 self.margin.right.color = margin.right;
80 self.margin.top.color = margin.top;
81 self.margin.bottom.color = margin.bottom;
82 }
83
84 /// Set an offset of margin of a grid.
85 pub fn set_margin_offset(&mut self, margin: Sides<Offset>) {
86 self.margin.left.offset = margin.left;
87 self.margin.right.offset = margin.right;
88 self.margin.top.offset = margin.top;
89 self.margin.bottom.offset = margin.bottom;
90 }
91
92 /// Returns a margin value currently set.
93 pub fn get_margin(&self) -> Sides<Indent> {
94 Sides::new(
95 self.margin.left.indent,
96 self.margin.right.indent,
97 self.margin.top.indent,
98 self.margin.bottom.indent,
99 )
100 }
101
102 /// Returns a margin color value currently set.
103 pub fn get_margin_color(&self) -> Sides<Option<AnsiColor<'static>>> {
104 Sides::new(
105 self.margin.left.color.clone(),
106 self.margin.right.color.clone(),
107 self.margin.top.color.clone(),
108 self.margin.bottom.color.clone(),
109 )
110 }
111
112 /// Returns a margin offset value currently set.
113 pub fn get_margin_offset(&self) -> Sides<Offset> {
114 Sides::new(
115 self.margin.left.offset,
116 self.margin.right.offset,
117 self.margin.top.offset,
118 self.margin.bottom.offset,
119 )
120 }
121
122 /// Clears all theme changes.
123 /// And sets it to default.
124 pub fn clear_theme(&mut self) {
125 self.borders = BordersConfig::default();
126 self.horizontal_chars.clear();
127 self.vertical_chars.clear();
128 self.horizontal_colors.clear();
129 self.vertical_colors.clear();
130 }
131
132 /// Set the [`Borders`] value as correct one.
133 pub fn set_borders(&mut self, borders: Borders<char>) {
134 self.borders.set_borders(borders);
135 }
136
137 /// Gets a global border value if set.
138 pub fn get_global_border(&self) -> Option<&char> {
139 self.borders.get_global()
140 }
141
142 /// Set the all [`Borders`] values to a char.
143 pub fn set_global_border(&mut self, c: char) {
144 self.borders.set_global(c);
145 }
146
147 /// Returns a current [`Borders`] structure.
148 pub fn get_borders(&self) -> &Borders<char> {
149 self.borders.get_borders()
150 }
151
152 /// Set the border line by row index.
153 ///
154 /// Row `0` means the top row.
155 /// Row `grid.count_rows()` means the bottom row.
156 pub fn insert_horizontal_line(&mut self, line: usize, val: HorizontalLine) {
157 self.borders.insert_horizontal_line(line, val);
158 }
159
160 /// Sets off the border line by row index if any were set
161 ///
162 /// Row `0` means the top row.
163 /// Row `grid.count_rows()` means the bottom row.
164 pub fn remove_horizontal_line(&mut self, line: usize, count_rows: usize) {
165 self.borders.remove_horizontal_line(line, count_rows);
166 }
167
168 /// Gets a overridden vertical line.
169 ///
170 /// Row `0` means the left row.
171 /// Row `grid.count_columns()` means the right most row.
172 pub fn get_vertical_line(&self, line: usize) -> Option<&VerticalLine> {
173 self.borders.get_vertical_line(line)
174 }
175
176 /// Set the border line by column index.
177 ///
178 /// Row `0` means the left row.
179 /// Row `grid.count_columns()` means the right most row.
180 pub fn insert_vertical_line(&mut self, line: usize, val: VerticalLine) {
181 self.borders.insert_vertical_line(line, val);
182 }
183
184 /// Sets off the border line by column index if any were set
185 ///
186 /// Row `0` means the left row.
187 /// Row `grid.count_columns()` means the right most row.
188 pub fn remove_vertical_line(&mut self, line: usize, count_columns: usize) {
189 self.borders.remove_vertical_line(line, count_columns);
190 }
191
192 /// Gets a overridden line.
193 ///
194 /// Row `0` means the top row.
195 /// Row `grid.count_rows()` means the bottom row.
196 pub fn get_horizontal_line(&self, line: usize) -> Option<&HorizontalLine> {
197 self.borders.get_horizontal_line(line)
198 }
199
200 /// Override a character on a horizontal line.
201 ///
202 /// If borders are not set the char won't be used.
203 ///
204 /// It takes not cell position but line as row and column of a cell;
205 /// So its range is line <= count_rows && col < count_columns.
206 pub fn set_horizontal_char(&mut self, pos: Position, c: char, offset: Offset) {
207 let chars = self
208 .horizontal_chars
209 .entry(pos)
210 .or_insert_with(|| HashMap::with_capacity(1));
211
212 chars.insert(offset, c);
213 }
214
215 /// Get a list of overridden chars in a horizontal border.
216 ///
217 /// It takes not cell position but line as row and column of a cell;
218 /// So its range is line <= count_rows && col < count_columns.
219 pub fn lookup_horizontal_char(&self, pos: Position, offset: usize, end: usize) -> Option<char> {
220 self.horizontal_chars
221 .get(&pos)
222 .and_then(|chars| {
223 chars.get(&Offset::Begin(offset)).or_else(|| {
224 if end > offset {
225 if end == 0 {
226 chars.get(&Offset::End(0))
227 } else {
228 chars.get(&Offset::End(end - offset - 1))
229 }
230 } else {
231 None
232 }
233 })
234 })
235 .copied()
236 }
237
238 /// Checks if there any char in a horizontal border being overridden.
239 ///
240 /// It takes not cell position but line as row and column of a cell;
241 /// So its range is line <= count_rows && col < count_columns.
242 pub fn is_overridden_horizontal(&self, pos: Position) -> bool {
243 self.horizontal_chars.get(&pos).is_some()
244 }
245
246 /// Removes a list of overridden chars in a horizontal border.
247 ///
248 /// It takes not cell position but line as row and column of a cell;
249 /// So its range is line <= count_rows && col < count_columns.
250 pub fn remove_overridden_horizontal(&mut self, pos: Position) {
251 self.horizontal_chars.remove(&pos);
252 }
253
254 /// Override a vertical split line.
255 ///
256 /// If borders are not set the char won't be used.
257 ///
258 /// It takes not cell position but cell row and column of a line;
259 /// So its range is row < count_rows && col <= count_columns.
260 pub fn set_vertical_char(&mut self, pos: Position, c: char, offset: Offset) {
261 let chars = self
262 .vertical_chars
263 .entry(pos)
264 .or_insert_with(|| HashMap::with_capacity(1));
265
266 chars.insert(offset, c);
267 }
268
269 /// Get a list of overridden chars in a horizontal border.
270 ///
271 /// It takes not cell position but cell row and column of a line;
272 /// So its range is row < count_rows && col <= count_columns.
273 pub fn lookup_vertical_char(&self, pos: Position, offset: usize, end: usize) -> Option<char> {
274 self.vertical_chars
275 .get(&pos)
276 .and_then(|chars| {
277 chars.get(&Offset::Begin(offset)).or_else(|| {
278 if end > offset {
279 if end == 0 {
280 chars.get(&Offset::End(0))
281 } else {
282 chars.get(&Offset::End(end - offset - 1))
283 }
284 } else {
285 None
286 }
287 })
288 })
289 .copied()
290 }
291
292 /// Checks if there any char in a horizontal border being overridden.
293 ///
294 /// It takes not cell position but cell row and column of a line;
295 /// So its range is row < count_rows && col <= count_columns.
296 pub fn is_overridden_vertical(&self, pos: Position) -> bool {
297 self.vertical_chars.get(&pos).is_some()
298 }
299
300 /// Removes a list of overridden chars in a horizontal border.
301 ///
302 /// It takes not cell position but cell row and column of a line;
303 /// So its range is row < count_rows && col <= count_columns.
304 pub fn remove_overridden_vertical(&mut self, pos: Position) {
305 self.vertical_chars.remove(&pos);
306 }
307
308 /// Override a character color on a horizontal line.
309 pub fn set_horizontal_color(&mut self, pos: Position, c: AnsiColor<'static>, offset: Offset) {
310 let chars = self
311 .horizontal_colors
312 .entry(pos)
313 .or_insert_with(|| HashMap::with_capacity(1));
314
315 chars.insert(offset, c);
316 }
317
318 /// Get a overridden color in a horizontal border.
319 pub fn lookup_horizontal_color(
320 &self,
321 pos: Position,
322 offset: usize,
323 end: usize,
324 ) -> Option<&AnsiColor<'static>> {
325 self.horizontal_colors.get(&pos).and_then(|chars| {
326 chars.get(&Offset::Begin(offset)).or_else(|| {
327 if end > offset {
328 if end == 0 {
329 chars.get(&Offset::End(0))
330 } else {
331 chars.get(&Offset::End(end - offset - 1))
332 }
333 } else {
334 None
335 }
336 })
337 })
338 }
339
340 /// Override a character color on a vertical line.
341 pub fn set_vertical_color(&mut self, pos: Position, c: AnsiColor<'static>, offset: Offset) {
342 let chars = self
343 .vertical_colors
344 .entry(pos)
345 .or_insert_with(|| HashMap::with_capacity(1));
346
347 chars.insert(offset, c);
348 }
349
350 /// Get a overridden color in a vertical border.
351 pub fn lookup_vertical_color(
352 &self,
353 pos: Position,
354 offset: usize,
355 end: usize,
356 ) -> Option<&AnsiColor<'static>> {
357 self.vertical_colors.get(&pos).and_then(|chars| {
358 chars.get(&Offset::Begin(offset)).or_else(|| {
359 if end > offset {
360 if end == 0 {
361 chars.get(&Offset::End(0))
362 } else {
363 chars.get(&Offset::End(end - offset - 1))
364 }
365 } else {
366 None
367 }
368 })
369 })
370 }
371
372 /// Set a padding to a given cells.
373 pub fn set_padding(&mut self, entity: Entity, padding: Sides<Indent>) {
374 let mut pad = self.padding.get(entity).clone();
375 pad.left.indent = padding.left;
376 pad.right.indent = padding.right;
377 pad.top.indent = padding.top;
378 pad.bottom.indent = padding.bottom;
379
380 self.padding.insert(entity, pad);
381 }
382
383 /// Set a padding to a given cells.
384 pub fn set_padding_color(
385 &mut self,
386 entity: Entity,
387 padding: Sides<Option<AnsiColor<'static>>>,
388 ) {
389 let mut pad = self.padding.get(entity).clone();
390 pad.left.color = padding.left;
391 pad.right.color = padding.right;
392 pad.top.color = padding.top;
393 pad.bottom.color = padding.bottom;
394
395 self.padding.insert(entity, pad);
396 }
397
398 /// Get a padding for a given [Entity].
399 pub fn get_padding(&self, entity: Entity) -> Sides<Indent> {
400 let pad = self.padding.get(entity);
401 Sides::new(
402 pad.left.indent,
403 pad.right.indent,
404 pad.top.indent,
405 pad.bottom.indent,
406 )
407 }
408
409 /// Get a padding color for a given [Entity].
410 pub fn get_padding_color(&self, entity: Entity) -> Sides<Option<AnsiColor<'static>>> {
411 let pad = self.padding.get(entity);
412 Sides::new(
413 pad.left.color.clone(),
414 pad.right.color.clone(),
415 pad.top.color.clone(),
416 pad.bottom.color.clone(),
417 )
418 }
419
420 /// Set a formatting to a given cells.
421 pub fn set_formatting(&mut self, entity: Entity, formatting: Formatting) {
422 self.formatting.insert(entity, formatting);
423 }
424
425 /// Get a formatting settings for a given [Entity].
426 pub fn get_formatting(&self, entity: Entity) -> &Formatting {
427 self.formatting.get(entity)
428 }
429
430 /// Set a vertical alignment to a given cells.
431 pub fn set_alignment_vertical(&mut self, entity: Entity, alignment: AlignmentVertical) {
432 self.alignment_v.insert(entity, alignment);
433 }
434
435 /// Get a vertical alignment for a given [Entity].
436 pub fn get_alignment_vertical(&self, entity: Entity) -> &AlignmentVertical {
437 self.alignment_v.get(entity)
438 }
439
440 /// Set a horizontal alignment to a given cells.
441 pub fn set_alignment_horizontal(&mut self, entity: Entity, alignment: AlignmentHorizontal) {
442 self.alignment_h.insert(entity, alignment);
443 }
444
445 /// Get a horizontal alignment for a given [Entity].
446 pub fn get_alignment_horizontal(&self, entity: Entity) -> &AlignmentHorizontal {
447 self.alignment_h.get(entity)
448 }
449
450 /// Set border set a border value to all cells in [`Entity`].
451 pub fn set_border(&mut self, pos: Position, border: Border<char>) {
452 self.borders.insert_border(pos, border);
453 }
454
455 /// Returns a border of a cell.
456 pub fn get_border(&self, pos: Position, shape: (usize, usize)) -> Border<char> {
457 self.borders.get_border(pos, shape).copied()
458 }
459
460 /// Returns a border color of a cell.
461 pub fn get_border_color(
462 &self,
463 pos: Position,
464 shape: (usize, usize),
465 ) -> Border<&AnsiColor<'static>> {
466 self.borders_colors.get_border(pos, shape)
467 }
468
469 /// Set a character which will be used in case any misconfiguration of borders.
470 ///
471 /// It will be usde for example when you set a left char for border frame and top but didn't set a top left corner.
472 pub fn set_borders_missing(&mut self, c: char) {
473 self.borders_missing_char = c;
474 }
475
476 /// Get a character which will be used in case any misconfiguration of borders.
477 pub fn get_borders_missing(&self) -> char {
478 self.borders_missing_char
479 }
480
481 /// Gets a color of all borders on the grid.
482 pub fn get_border_color_global(&self) -> Option<&AnsiColor<'static>> {
483 self.borders_colors.get_global()
484 }
485
486 /// Sets a color of all borders on the grid.
487 pub fn set_border_color_global(&mut self, clr: AnsiColor<'static>) {
488 self.borders_colors = BordersConfig::default();
489 self.borders_colors.set_global(clr);
490 }
491
492 /// Gets colors of a borders carcass on the grid.
493 pub fn get_color_borders(&self) -> &Borders<AnsiColor<'static>> {
494 self.borders_colors.get_borders()
495 }
496
497 /// Sets colors of border carcass on the grid.
498 pub fn set_borders_color(&mut self, clrs: Borders<AnsiColor<'static>>) {
499 self.borders_colors.set_borders(clrs);
500 }
501
502 /// Sets a color of border of a cell on the grid.
503 pub fn set_border_color(&mut self, pos: Position, border: Border<AnsiColor<'static>>) {
504 self.borders_colors.insert_border(pos, border)
505 }
506
507 /// Sets off all borders possible on the [`Entity`].
508 ///
509 /// It doesn't changes globally set borders through [`SpannedConfig::set_borders`].
510 //
511 // todo: would be great to remove a shape
512 pub fn remove_border(&mut self, pos: Position, shape: (usize, usize)) {
513 self.borders.remove_border(pos, shape);
514 }
515
516 /// Gets a color of border of a cell on the grid.
517 //
518 // todo: would be great to remove a shape
519 pub fn remove_border_color(&mut self, pos: Position, shape: (usize, usize)) {
520 self.borders_colors.remove_border(pos, shape);
521 }
522
523 /// Get a justification which will be used while expanding cells width/height.
524 pub fn get_justification(&self, entity: Entity) -> char {
525 *self.justification.get(entity)
526 }
527
528 /// Get a justification color which will be used while expanding cells width/height.
529 ///
530 /// `None` means no color.
531 pub fn get_justification_color(&self, entity: Entity) -> Option<&AnsiColor<'static>> {
532 self.justification_color.get(entity).as_ref()
533 }
534
535 /// Set a justification which will be used while expanding cells width/height.
536 pub fn set_justification(&mut self, entity: Entity, c: char) {
537 self.justification.insert(entity, c);
538 }
539
540 /// Set a justification color which will be used while expanding cells width/height.
541 ///
542 /// `None` removes it.
543 pub fn set_justification_color(&mut self, entity: Entity, color: Option<AnsiColor<'static>>) {
544 self.justification_color.insert(entity, color);
545 }
546
547 /// Get a span value of the cell, if any is set.
548 pub fn get_column_spans(&self) -> HashMap<Position, usize> {
549 self.span_columns.clone()
550 }
551
552 /// Get a span value of the cell, if any is set.
553 pub fn get_row_spans(&self) -> HashMap<Position, usize> {
554 self.span_rows.clone()
555 }
556
557 /// Get a span value of the cell, if any is set.
558 pub fn get_column_span(&self, pos: Position) -> Option<usize> {
559 self.span_columns.get(&pos).copied()
560 }
561
562 /// Get a span value of the cell, if any is set.
563 pub fn get_row_span(&self, pos: Position) -> Option<usize> {
564 self.span_rows.get(&pos).copied()
565 }
566
567 /// Removes column spans.
568 pub fn remove_column_spans(&mut self) {
569 self.span_columns.clear()
570 }
571
572 /// Removes row spans.
573 pub fn remove_row_spans(&mut self) {
574 self.span_rows.clear()
575 }
576
577 /// Set a column span to a given cells.
578 ///
579 /// BEWARE
580 ///
581 /// IT'S CALLER RESPONSIBILITY TO MAKE SURE
582 /// THAT THERE NO INTERSECTIONS IN PLACE AND THE SPAN VALUE IS CORRECT
583 pub fn set_column_span(&mut self, pos: Position, span: usize) {
584 set_cell_column_span(self, pos, span);
585 }
586
587 /// Verifies if there's any spans set.
588 pub fn has_column_spans(&self) -> bool {
589 !self.span_columns.is_empty()
590 }
591
592 /// Set a column span to a given cells.
593 ///
594 /// BEWARE
595 ///
596 /// IT'S CALLER RESPONSIBILITY TO MAKE SURE
597 /// THAT THERE NO INTERSECTIONS IN PLACE AND THE SPAN VALUE IS CORRECT
598 pub fn set_row_span(&mut self, pos: Position, span: usize) {
599 set_cell_row_span(self, pos, span);
600 }
601
602 /// Verifies if there's any spans set.
603 pub fn has_row_spans(&self) -> bool {
604 !self.span_rows.is_empty()
605 }
606
607 /// Gets an intersection character which would be rendered on the grid.
608 ///
609 /// grid: crate::Grid
610 pub fn get_intersection(&self, pos: Position, shape: (usize, usize)) -> Option<char> {
611 let c = self.borders.get_intersection(pos, shape);
612 if let Some(c) = c {
613 return Some(*c);
614 }
615
616 if self.has_horizontal(pos.0, shape.0) && self.has_vertical(pos.1, shape.1) {
617 return Some(self.get_borders_missing());
618 }
619
620 None
621 }
622
623 /// Gets a horizontal character which would be rendered on the grid.
624 ///
625 /// grid: crate::Grid
626 pub fn get_horizontal(&self, pos: Position, count_rows: usize) -> Option<char> {
627 let c = self.borders.get_horizontal(pos, count_rows);
628 if let Some(c) = c {
629 return Some(*c);
630 }
631
632 if self.has_horizontal(pos.0, count_rows) {
633 return Some(self.get_borders_missing());
634 }
635
636 None
637 }
638
639 /// Gets a vertical character which would be rendered on the grid.
640 ///
641 /// grid: crate::Grid
642 pub fn get_vertical(&self, pos: Position, count_columns: usize) -> Option<char> {
643 if let Some(c) = self.borders.get_vertical(pos, count_columns) {
644 return Some(*c);
645 }
646
647 if self.has_vertical(pos.1, count_columns) {
648 return Some(self.get_borders_missing());
649 }
650
651 None
652 }
653
654 /// Gets a color of a cell horizontal.
655 pub fn get_horizontal_color(
656 &self,
657 pos: Position,
658 count_rows: usize,
659 ) -> Option<&AnsiColor<'static>> {
660 self.borders_colors.get_horizontal(pos, count_rows)
661 }
662
663 /// Gets a color of a cell vertical.
664 pub fn get_vertical_color(
665 &self,
666 pos: Position,
667 count_columns: usize,
668 ) -> Option<&AnsiColor<'static>> {
669 self.borders_colors.get_vertical(pos, count_columns)
670 }
671
672 /// Gets a color of a cell vertical.
673 pub fn get_intersection_color(
674 &self,
675 pos: Position,
676 shape: (usize, usize),
677 ) -> Option<&AnsiColor<'static>> {
678 self.borders_colors.get_intersection(pos, shape)
679 }
680
681 /// Checks if grid would have a horizontal border with the current configuration.
682 ///
683 /// grid: crate::Grid
684 pub fn has_horizontal(&self, row: usize, count_rows: usize) -> bool {
685 self.borders.has_horizontal(row, count_rows)
686 }
687
688 /// Checks if grid would have a vertical border with the current configuration.
689 ///
690 /// grid: crate::Grid
691 pub fn has_vertical(&self, col: usize, count_columns: usize) -> bool {
692 self.borders.has_vertical(col, count_columns)
693 }
694
695 /// Calculates an amount of horizontal lines would present on the grid.
696 ///
697 /// grid: crate::Grid
698 pub fn count_horizontal(&self, count_rows: usize) -> usize {
699 (0..=count_rows)
700 .filter(|&row| self.has_horizontal(row, count_rows))
701 .count()
702 }
703
704 /// Calculates an amount of vertical lines would present on the grid.
705 ///
706 /// grid: crate::Grid
707 pub fn count_vertical(&self, count_columns: usize) -> usize {
708 (0..=count_columns)
709 .filter(|&col| self.has_vertical(col, count_columns))
710 .count()
711 }
712
713 /// The function returns whether the cells will be rendered or it will be hidden because of a span.
714 pub fn is_cell_visible(&self, pos: Position) -> bool {
715 !(self.is_cell_covered_by_column_span(pos)
716 || self.is_cell_covered_by_row_span(pos)
717 || self.is_cell_covered_by_both_spans(pos))
718 }
719
720 /// The function checks if a cell is hidden because of a row span.
721 pub fn is_cell_covered_by_row_span(&self, pos: Position) -> bool {
722 is_cell_covered_by_row_span(self, pos)
723 }
724
725 /// The function checks if a cell is hidden because of a column span.
726 pub fn is_cell_covered_by_column_span(&self, pos: Position) -> bool {
727 is_cell_covered_by_column_span(self, pos)
728 }
729
730 /// The function checks if a cell is hidden indirectly because of a row and column span combination.
731 pub fn is_cell_covered_by_both_spans(&self, pos: Position) -> bool {
732 is_cell_covered_by_both_spans(self, pos)
733 }
734}
735
736impl From<CompactConfig> for SpannedConfig {
737 fn from(compact: CompactConfig) -> Self {
738 use Entity::Global;
739
740 let mut cfg = Self::default();
741
742 cfg.set_padding(Global, *compact.get_padding());
743 cfg.set_padding_color(Global, to_ansi_color(compact.get_padding_color()));
744 cfg.set_margin(*compact.get_margin());
745 cfg.set_margin_color(to_ansi_color(compact.get_margin_color()));
746 cfg.set_alignment_horizontal(Global, compact.get_alignment_horizontal());
747 cfg.set_borders(*compact.get_borders());
748 cfg.set_borders_color(borders_static_color_to_ansi_color(
749 *compact.get_borders_color(),
750 ));
751
752 if let Some(line) = compact.get_first_horizontal_line() {
753 cfg.insert_horizontal_line(
754 1,
755 HorizontalLine {
756 intersection: line.intersection,
757 left: line.connect1,
758 right: line.connect2,
759 main: Some(line.main),
760 },
761 );
762 }
763
764 cfg
765 }
766}
767
768fn to_ansi_color(b: Sides<StaticColor>) -> Sides<Option<AnsiColor<'static>>> {
769 Sides::new(
770 left:Some(b.left.into()),
771 right:Some(b.right.into()),
772 top:Some(b.top.into()),
773 bottom:Some(b.bottom.into()),
774 )
775}
776
777fn borders_static_color_to_ansi_color(b: Borders<StaticColor>) -> Borders<AnsiColor<'static>> {
778 Borders {
779 left: b.left.map(|c: StaticColor| c.into()),
780 right: b.right.map(|c: StaticColor| c.into()),
781 top: b.top.map(|c: StaticColor| c.into()),
782 bottom: b.bottom.map(|c: StaticColor| c.into()),
783 bottom_intersection: b.bottom_intersection.map(|c: StaticColor| c.into()),
784 bottom_left: b.bottom_left.map(|c: StaticColor| c.into()),
785 bottom_right: b.bottom_right.map(|c: StaticColor| c.into()),
786 horizontal: b.horizontal.map(|c: StaticColor| c.into()),
787 intersection: b.intersection.map(|c: StaticColor| c.into()),
788 left_intersection: b.left_intersection.map(|c: StaticColor| c.into()),
789 right_intersection: b.right_intersection.map(|c: StaticColor| c.into()),
790 top_intersection: b.top_intersection.map(|c: StaticColor| c.into()),
791 top_left: b.top_left.map(|c: StaticColor| c.into()),
792 top_right: b.top_right.map(|c: StaticColor| c.into()),
793 vertical: b.vertical.map(|c: StaticColor| c.into()),
794 }
795}
796
797fn set_cell_row_span(cfg: &mut SpannedConfig, pos: Position, span: usize) {
798 // such spans aren't supported
799 if span == 0 {
800 return;
801 }
802
803 // It's a default span so we can do nothing.
804 // but we check if it's an override of a span.
805 if span == 1 {
806 cfg.span_rows.remove(&pos);
807 return;
808 }
809
810 cfg.span_rows.insert(k:pos, v:span);
811}
812
813fn set_cell_column_span(cfg: &mut SpannedConfig, pos: Position, span: usize) {
814 // such spans aren't supported
815 if span == 0 {
816 return;
817 }
818
819 // It's a default span so we can do nothing.
820 // but we check if it's an override of a span.
821 if span == 1 {
822 cfg.span_columns.remove(&pos);
823 return;
824 }
825
826 cfg.span_columns.insert(k:pos, v:span);
827}
828
829fn is_cell_covered_by_column_span(cfg: &SpannedConfig, pos: Position) -> bool {
830 cfgIter<'_, (usize, usize), …>.span_columns
831 .iter()
832 .any(|(&(row: usize, col: usize), span: &usize)| pos.1 > col && pos.1 < col + span && row == pos.0)
833}
834
835fn is_cell_covered_by_row_span(cfg: &SpannedConfig, pos: Position) -> bool {
836 cfgIter<'_, (usize, usize), …>.span_rows
837 .iter()
838 .any(|(&(row: usize, col: usize), span: &usize)| pos.0 > row && pos.0 < row + span && col == pos.1)
839}
840
841fn is_cell_covered_by_both_spans(cfg: &SpannedConfig, pos: Position) -> bool {
842 if !cfg.has_column_spans() || !cfg.has_row_spans() {
843 return false;
844 }
845
846 cfg.span_rows.iter().any(|(p1: &(usize, usize), row_span: &usize)| {
847 cfgimpl Iterator.span_columns
848 .iter()
849 .filter(|(p2: &&(usize, usize), _)| &p1 == p2)
850 .any(|(_, col_span: &usize)| {
851 pos.0 > p1.0 && pos.0 < p1.0 + row_span && pos.1 > p1.1 && pos.1 < p1.1 + col_span
852 })
853 })
854}
855
856#[derive(Default, Debug, Clone, PartialEq, Eq)]
857struct ColoredIndent {
858 indent: Indent,
859 color: Option<AnsiColor<'static>>,
860}
861
862/// A colorefull margin indent.
863#[derive(Debug, Clone, PartialEq, Eq)]
864struct ColoredMarginIndent {
865 /// An indent value.
866 indent: Indent,
867 /// An offset value.
868 offset: Offset,
869 /// An color value.
870 color: Option<AnsiColor<'static>>,
871}
872
873impl Default for ColoredMarginIndent {
874 fn default() -> Self {
875 Self {
876 indent: Indent::default(),
877 offset: Offset::Begin(0),
878 color: None,
879 }
880 }
881}
882
883/// HorizontalLine represents a horizontal border line.
884pub type HorizontalLine = borders_config::HorizontalLine<char>;
885
886/// HorizontalLine represents a vertical border line.
887pub type VerticalLine = borders_config::VerticalLine<char>;
888