Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_tui/src/lib_tui/draw/quad.rs

4.0 KiB, 5 runs

created by r1870400018:1179, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::prelude::*;
2use oxedyne_fe2o3_stds::chars::Term;
3
4#[derive(Clone, Debug, Default)]
5pub enum Dimension {
6 Fixed(usize),
7 #[default]
8 ShrinkToFit,
9}
10
11#[derive(Clone, Debug, Default)]
12pub struct BoxSides {
13 pub left: usize,
14 pub top: usize,
15 pub right: usize,
16 pub bottom: usize,
17}
18
19#[derive(Clone, Debug)]
20pub struct FrameLineConfig {
21 pub effect_on: String,
22 pub effect_off: String,
23 pub top_left_char: String,
24 pub top_char: String,
25 pub top_right_char: String,
26 pub right_char: String,
27 pub bottom_right_char: String,
28 pub bottom_char: String,
29 pub bottom_left_char: String,
30 pub left_char: String,
31}
32
33impl Default for FrameLineConfig {
34 fn default() -> Self {
35 Self::simple()
36 }
37}
38
39impl FrameLineConfig {
40 pub fn simple() -> Self {
41 Self {
42 effect_on: fmt!(""),
43 effect_off: fmt!(""),
44 top_left_char: fmt!("┌"),
45 top_char: fmt!("─"),
46 top_right_char: fmt!("┐"),
47 right_char: fmt!("│"),
48 bottom_right_char: fmt!("┘"),
49 bottom_char: fmt!("─"),
50 bottom_left_char: fmt!("└"),
51 left_char: fmt!("│"),
52 }
53 }
54}
55
56#[derive(Clone, Debug, Default)]
57pub struct BoxConfig {
58 pub width: Dimension,
59 pub height: Dimension,
60 pub pad: BoxSides,
61 pub frame: FrameLineConfig,
62}
63
64impl BoxConfig {
65 pub fn width(&self, w: usize) -> usize {
66 match self.width {
67 Dimension::Fixed(w0) => w0,
68 Dimension::ShrinkToFit => w,
69 }
70 }
71 pub fn height(&self, h: usize) -> usize {
72 match self.height{
73 Dimension::Fixed(h0) => h0,
74 Dimension::ShrinkToFit => h,
75 }
76 }
77}
78
79#[derive(Clone, Debug, Default)]
80pub struct Box {
81 pub cfg: BoxConfig,
82}
83
84/// ```ignore
85/// let framer = visual::Box::default().with_frame_effect(
86/// Term::BOLD.to_owned() + Term::SET_BRIGHT_FORE_RED
87/// );
88/// for line in framer.frame(vec![line], about.len() + 2) {
89/// lines.push(line);
90/// }
91/// ```
92impl Box {
93
94 pub fn with_frame_effect(mut self, effect: String) -> Self {
95 self.cfg.frame.effect_on = effect;
96 self.cfg.frame.effect_off = Term::RESET.to_string();
97 self
98 }
99
100 pub fn measure_width(lines: &Vec<String>) -> usize {
101 let mut max = 0;
102 for line in lines {
103 let len = line.chars().count();
104 if len > max {
105 max = len;
106 }
107 }
108 max
109 }
110
111 /// Input should be padded by user so that each line is the same visible length.
112 pub fn frame(
113 &self,
114 lines: Vec<String>,
115 visible_width: usize, // Visible width of lines, excluding ANSI sequences.
116 )
117 -> Vec<String>
118 {
119 let width = visible_width
120 - self.cfg.pad.left
121 - self.cfg.pad.right;
122 let mut result = Vec::new();
123 // Top line.
124 result.push(fmt!(
125 "{}{}{}{}{}",
126 self.cfg.frame.effect_on,
127 self.cfg.frame.top_left_char,
128 self.cfg.frame.top_char.repeat(width),
129 self.cfg.frame.top_right_char,
130 self.cfg.frame.effect_off,
131 ));
132 // Middle lines.
133 for line in lines {
134 result.push(fmt!(
135 "{}{}{}{}{}{}{}",
136 self.cfg.frame.effect_on,
137 self.cfg.frame.left_char,
138 self.cfg.frame.effect_off,
139 line,
140 self.cfg.frame.effect_on,
141 self.cfg.frame.right_char,
142 self.cfg.frame.effect_off,
143 ));
144 }
145 // Bottom line.
146 result.push(fmt!(
147 "{}{}{}{}{}",
148 self.cfg.frame.effect_on,
149 self.cfg.frame.bottom_left_char,
150 self.cfg.frame.bottom_char.repeat(width),
151 self.cfg.frame.bottom_right_char,
152 self.cfg.frame.effect_off,
153 ));
154 result
155 }
156}