neon_style/
position.rs

1use std::cmp;
2
3use textwrap::core::display_width;
4
5use crate::{
6    align::{get_lines, get_strs_height},
7    whitespace::{WhiteSpace, WhiteSpaceType},
8};
9
10#[derive(Clone, Copy, Debug)]
11pub enum Position {
12    Top,
13    Bottom,
14    Center,
15    Left,
16    Right,
17}
18
19pub fn place(
20    width: i32,
21    height: i32,
22    h_pos: Position,
23    v_pos: Position,
24    strs: String,
25    opts: &[WhiteSpaceType],
26) -> String {
27    return place_vertical(
28        height,
29        v_pos,
30        place_horizontal(width, h_pos, strs, opts),
31        opts,
32    );
33}
34
35pub fn place_horizontal(
36    width: i32,
37    pos: Position,
38    strs: String,
39    opts: &[WhiteSpaceType],
40) -> String {
41    let binding = strs.to_string();
42    let (lines, content_width) = get_lines(&binding);
43    let gap = width as usize - content_width;
44    if gap <= 0 {
45        return strs;
46    }
47
48    let mut ws = WhiteSpace::new(opts);
49
50    let mut b = String::new();
51
52    for (i, line) in lines.clone().enumerate() {
53        let short = cmp::max(0, content_width - display_width(line));
54        match pos {
55            Position::Left => {
56                b.push_str(&line);
57                b.push_str(&ws.render(gap + short));
58            }
59            Position::Right => {
60                b.push_str(&ws.render(gap + short));
61                b.push_str(&line);
62            }
63            _ => {
64                let left = (gap + short) / 2;
65                let right = (gap + short) / 2;
66                b.push_str(&ws.render(left));
67                b.push_str(&line);
68                b.push_str(&ws.render(right));
69            }
70        }
71
72        if i < lines.clone().count() - 1 {
73            b.push('\n');
74        }
75    }
76    b
77}
78
79pub fn place_vertical(height: i32, pos: Position, strs: String, opts: &[WhiteSpaceType]) -> String {
80    let content_height = get_strs_height(&strs);
81    let gap = height as usize - content_height;
82    if gap <= 0 {
83        return strs;
84    }
85
86    let mut ws = WhiteSpace::new(opts);
87
88    let (_, width) = get_lines(&strs);
89    let empty_line = format!("{}\n", ws.render(width));
90
91    let mut b = String::new();
92    match pos {
93        Position::Bottom => {
94            b.push_str(&empty_line.repeat(gap));
95            b.push_str(&strs);
96        }
97        Position::Top => {
98            b.push_str(&strs);
99            for _ in 0..gap {
100                b.push('\n');
101                b.push_str(&empty_line);
102            }
103        }
104        _ => {
105            let top = gap / 2;
106            let bottom = gap / 2;
107            b.push_str(&empty_line.repeat(top));
108            b.push_str(&strs);
109            for _ in 0..bottom {
110                b.push('\n');
111                b.push_str(&empty_line);
112            }
113        }
114    }
115    b
116}