1use duat_core::prelude::*;
2
3use crate::Ui;
4
5pub struct VertRule {
29 handle: Option<FileHandle<Ui>>,
30 text: Text,
31 sep_char: SepChar,
32}
33
34impl Widget<Ui> for VertRule {
35 type Cfg = VertRuleCfg;
36
37 fn update(pa: &mut Pass, handle: Handle<Self, Ui>) {
38 let text = handle.read(pa, |wid, area| {
39 if let Some(handle) = wid.handle.as_ref()
40 && let SepChar::ThreeWay(..) | SepChar::TwoWay(..) = wid.sep_char
41 {
42 let (upper, middle, lower) = handle.read(pa, |file, _| {
43 let lines = file.printed_lines();
44 if let Some(main) = file.selections().get_main() {
45 let main = main.line();
46 let upper = lines.iter().filter(|&(line, _)| *line < main).count();
47 let middle = lines.iter().filter(|&(line, _)| *line == main).count();
48 let lower = lines.iter().filter(|&(line, _)| *line > main).count();
49 (upper, middle, lower)
50 } else {
51 (0, lines.len(), 0)
52 }
53 });
54
55 let chars = wid.sep_char.chars();
56 txt!(
57 "[rule.upper]{}[]{}[rule.lower]{}",
58 form_string(chars[0], upper),
59 form_string(chars[1], middle),
60 form_string(chars[2], lower)
61 )
62 .build()
63 } else {
64 let full_line =
65 format!("{}\n", wid.sep_char.chars()[1]).repeat(area.height() as usize);
66
67 txt!("{full_line}").build()
68 }
69 });
70
71 handle.widget().replace_text(pa, text);
72 }
73
74 fn needs_update(&self) -> bool {
75 matches!(self.sep_char, SepChar::ThreeWay(..) | SepChar::TwoWay(..))
76 && self.handle.as_ref().is_some_and(FileHandle::has_changed)
77 }
78
79 fn cfg() -> Self::Cfg {
80 VertRuleCfg::new()
81 }
82
83 fn text(&self) -> &Text {
84 &self.text
85 }
86
87 fn text_mut(&mut self) -> &mut Text {
88 &mut self.text
89 }
90
91 fn once() -> Result<(), Text> {
92 form::set_weak("rule.upper", "default.VertRule");
93 form::set_weak("rule.lower", "default.VertRule");
94 Ok(())
95 }
96}
97
98#[derive(Clone)]
101enum SepChar {
102 Uniform(char),
103 TwoWay(char, char),
105 ThreeWay(char, char, char),
107}
108
109impl SepChar {
110 fn chars(&self) -> [char; 3] {
113 match self {
114 SepChar::Uniform(uniform) => [*uniform, *uniform, *uniform],
115 SepChar::TwoWay(main, other) => [*other, *main, *other],
116 SepChar::ThreeWay(main, upper, lower) => [*upper, *main, *lower],
117 }
118 }
119}
120
121#[derive(Clone)]
123pub struct VertRuleCfg {
124 sep_char: SepChar,
125 specs: PushSpecs,
126}
127
128impl VertRuleCfg {
129 pub fn new() -> Self {
131 Self {
132 sep_char: SepChar::Uniform('│'),
133 specs: PushSpecs::left().with_hor_len(1.0),
134 }
135 }
136
137 pub fn on_the_right(self) -> Self {
139 Self {
140 specs: PushSpecs::right().with_hor_len(1.0),
141 ..self
142 }
143 }
144
145 pub fn with_char(self, char: char) -> Self {
147 Self { sep_char: SepChar::Uniform(char), ..self }
148 }
149
150 pub fn with_main_char(self, main: char) -> Self {
155 Self {
156 sep_char: match self.sep_char {
157 SepChar::Uniform(other) => SepChar::TwoWay(main, other),
158 SepChar::TwoWay(_, other) => SepChar::TwoWay(main, other),
159 SepChar::ThreeWay(_, above, below) => SepChar::ThreeWay(main, above, below),
160 },
161 ..self
162 }
163 }
164
165 pub fn with_char_above(self, above: char) -> Self {
170 Self {
171 sep_char: match self.sep_char {
172 SepChar::Uniform(other) => SepChar::ThreeWay(other, above, other),
173 SepChar::TwoWay(main, below) => SepChar::ThreeWay(main, above, below),
174 SepChar::ThreeWay(main, _, below) => SepChar::ThreeWay(main, above, below),
175 },
176 ..self
177 }
178 }
179
180 pub fn with_char_below(self, below: char) -> Self {
181 Self {
182 sep_char: match self.sep_char {
183 SepChar::Uniform(other) => SepChar::ThreeWay(other, other, below),
184 SepChar::TwoWay(main, above) => SepChar::ThreeWay(main, above, below),
185 SepChar::ThreeWay(main, above, _) => SepChar::ThreeWay(main, above, below),
186 },
187 ..self
188 }
189 }
190}
191
192impl Default for VertRuleCfg {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl WidgetCfg<Ui> for VertRuleCfg {
199 type Widget = VertRule;
200
201 fn build(self, _: &mut Pass, handle: Option<FileHandle<Ui>>) -> (Self::Widget, PushSpecs) {
202 let widget = VertRule {
203 handle,
204 text: Text::default(),
205 sep_char: self.sep_char,
206 };
207
208 (widget, self.specs)
209 }
210}
211
212fn form_string(char: char, count: usize) -> String {
213 [char, '\n'].repeat(count).iter().collect()
214}