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