1use duat_core::{
2 context::Handle,
3 data::Pass,
4 text::{Text, txt},
5 ui::{PushSpecs, PushTarget, Side, Widget},
6};
7
8pub struct VertRule {
23 handle: Option<Handle>,
24 text: Text,
25 pub sep_char: SepChar,
26}
27
28impl VertRule {
29 pub fn builder() -> VertRuleBuilder {
32 VertRuleBuilder::default()
33 }
34}
35
36impl Widget for VertRule {
37 fn update(pa: &mut Pass, handle: &Handle<Self>) {
38 let vr = handle.read(pa);
39 let text = if let Some(handle) = vr.handle.as_ref()
40 && let SepChar::ThreeWay(..) | SepChar::TwoWay(..) = vr.sep_char
41 {
42 let (upper, middle, lower) = {
43 let file = handle.read(pa);
44
45 let lines = file.printed_lines();
46 if let Some(main) = file.selections().get_main() {
47 let main = main.line();
48 let upper = lines.iter().filter(|&(line, _)| *line < main).count();
49 let middle = lines.iter().filter(|&(line, _)| *line == main).count();
50 let lower = lines.iter().filter(|&(line, _)| *line > main).count();
51 (upper, middle, lower)
52 } else {
53 (0, lines.len(), 0)
54 }
55 };
56
57 let chars = vr.sep_char.chars();
58 txt!(
59 "[rule.upper]{}[]{}[rule.lower]{}",
60 form_string(chars[0], upper),
61 form_string(chars[1], middle),
62 form_string(chars[2], lower)
63 )
64 } else {
65 let full_line =
66 format!("{}\n", vr.sep_char.chars()[1]).repeat(handle.area().height(pa) as usize);
67
68 txt!("{full_line}")
69 };
70
71 handle.write(pa).text = text;
72 }
73
74 fn needs_update(&self, pa: &Pass) -> bool {
75 matches!(self.sep_char, SepChar::ThreeWay(..) | SepChar::TwoWay(..))
76 && self.handle.as_ref().is_some_and(|fh| fh.has_changed(pa))
77 }
78
79 fn text(&self) -> &Text {
80 &self.text
81 }
82
83 fn text_mut(&mut self) -> &mut Text {
84 &mut self.text
85 }
86}
87
88#[derive(Clone)]
91pub enum SepChar {
92 Uniform(char),
93 TwoWay(char, char),
95 ThreeWay(char, char, char),
97}
98
99impl SepChar {
100 fn chars(&self) -> [char; 3] {
103 match self {
104 SepChar::Uniform(uniform) => [*uniform, *uniform, *uniform],
105 SepChar::TwoWay(main, other) => [*other, *main, *other],
106 SepChar::ThreeWay(main, upper, lower) => [*upper, *main, *lower],
107 }
108 }
109}
110
111#[derive(Default, Clone)]
113pub struct VertRuleBuilder {
114 pub sep_char: SepChar = SepChar::Uniform('│'),
115 pub on_the_right: bool = false
116}
117
118impl VertRuleBuilder {
119 pub fn push_on(self, pa: &mut Pass, push_target: &impl PushTarget) -> Handle<VertRule> {
121 let vert_rule = VertRule {
122 handle: push_target.try_downcast(),
123 text: Text::default(),
124 sep_char: self.sep_char,
125 };
126
127 let specs = PushSpecs {
128 side: if self.on_the_right {
129 Side::Right
130 } else {
131 Side::Left
132 },
133 width: Some(1.0),
134 ..
135 };
136
137 push_target.push_outer(pa, vert_rule, specs)
138 }
139}
140
141fn form_string(char: char, count: usize) -> String {
142 [char, '\n'].repeat(count).iter().collect()
143}