1use std::sync::{
2 Arc,
3 atomic::{AtomicU32, Ordering},
4};
5
6use duat_core::ui::Axis;
7
8use crate::{area::Coord, print::VarPoint};
9
10#[derive(Default, Clone, Copy, Debug)]
12pub enum Brush {
13 #[default]
15 Regular,
16 Thick,
18 Dashed,
20 ThickDashed,
22 Double,
24 Rounded,
26 Ascii,
28 Custom(char),
30}
31
32#[derive(Debug)]
34pub struct Edge {
35 pub width: Arc<AtomicU32>,
36 lhs: VarPoint,
37 rhs: VarPoint,
38 axis: Axis,
39 fr: Frame,
40}
41
42impl Edge {
43 pub fn new(
45 width: &Arc<AtomicU32>,
46 lhs: &VarPoint,
47 rhs: &VarPoint,
48 axis: Axis,
49 fr: Frame,
50 ) -> Self {
51 Self {
52 width: width.clone(),
53 lhs: lhs.clone(),
54 rhs: rhs.clone(),
55 axis,
56 fr,
57 }
58 }
59
60 pub fn edge_coords(&self) -> Option<EdgeCoords> {
62 if self.width.load(Ordering::Acquire) == 0 {
63 return None;
64 }
65
66 let start = match self.axis {
67 Axis::Horizontal => Coord::new(self.rhs.x().value(), self.lhs.y().value()),
68 Axis::Vertical => Coord::new(self.lhs.x().value(), self.rhs.y().value()),
69 };
70 let end = match self.axis {
71 Axis::Horizontal => Coord::new(self.lhs.x().value(), self.rhs.y().value()),
72 Axis::Vertical => Coord::new(self.rhs.x().value(), self.lhs.y().value()),
73 };
74
75 Some(EdgeCoords::new(start, end, self.axis, self.fr.brush()))
76 }
77}
78
79#[derive(Clone, Copy)]
80pub struct EdgeCoords {
81 pub tl: Coord,
82 pub br: Coord,
83 pub axis: Axis,
84 pub line: Option<Brush>,
85}
86
87impl EdgeCoords {
88 fn new(tl: Coord, br: Coord, axis: Axis, line: Option<Brush>) -> Self {
89 Self { tl, br, axis, line }
90 }
91
92 #[allow(clippy::type_complexity)]
93 pub fn crossing(&self, other: EdgeCoords) -> Option<(Coord, [Option<Brush>; 4])> {
94 if let Axis::Vertical = self.axis {
95 if let Axis::Vertical = other.axis
96 && self.br.x == other.tl.x
97 && self.br.y + 2 == other.tl.y
98 {
99 let coord = Coord::new(self.br.x, self.br.y + 1);
100 return Some((coord, [None, self.line, None, other.line]));
101 } else {
102 return other.crossing(*self);
103 }
104 }
105
106 if let Axis::Horizontal = other.axis {
107 if self.br.y == other.br.y && self.br.x + 2 == other.tl.x {
108 let coord = Coord::new(self.br.x + 1, self.br.y);
109 Some((coord, [other.line, None, self.line, None]))
110 } else {
111 None
112 }
113 } else if self.tl.x <= other.tl.x + 1 && other.tl.x <= self.br.x + 1 {
114 let right_height = (other.tl.y..=other.br.y + 2).contains(&(self.br.y + 1));
115 let right = match right_height && other.br.x <= self.br.x {
116 true => self.line,
117 false => None,
118 };
119 let up = match other.tl.y <= self.tl.y && self.br.y <= other.br.y + 1 {
120 true => other.line,
121 false => None,
122 };
123 let left = match right_height && self.tl.x <= other.tl.x {
124 true => self.line,
125 false => None,
126 };
127 let down = match self.br.y <= other.br.y && other.tl.y <= self.tl.y + 1 {
128 true => other.line,
129 false => None,
130 };
131
132 if up.is_some() || down.is_some() {
133 let coord = Coord { x: other.tl.x, y: self.tl.y };
134
135 Some((coord, [right, up, left, down]))
136 } else {
137 None
138 }
139 } else {
140 None
141 }
142 }
143}
144
145#[derive(Clone, Copy, Debug)]
166pub enum Frame {
167 Empty,
169 Surround(Brush),
171 Border(Brush),
173 Vertical(Brush),
175 VerBorder(Brush),
177 Horizontal(Brush),
179 HorBorder(Brush),
181}
182
183impl Default for Frame {
184 fn default() -> Self {
185 Self::Border(Brush::Regular)
186 }
187}
188
189impl Frame {
190 pub(crate) fn files_edge_on(&self, axis: Axis) -> f64 {
194 let (hor_fr, ver_fr) = self.files_edges();
195 match axis {
196 Axis::Horizontal => hor_fr,
197 Axis::Vertical => ver_fr,
198 }
199 }
200
201 pub(crate) fn border_edge_on(&self, axis: Axis) -> f64 {
205 let (hor_fr, ver_fr) = self.border_edges();
206 match axis {
207 Axis::Horizontal => hor_fr,
208 Axis::Vertical => ver_fr,
209 }
210 }
211
212 fn brush(&self) -> Option<Brush> {
214 match self {
215 Self::Empty => None,
216 Self::Surround(brush)
217 | Self::Border(brush)
218 | Self::Vertical(brush)
219 | Self::VerBorder(brush)
220 | Self::Horizontal(brush)
221 | Self::HorBorder(brush) => Some(*brush),
222 }
223 }
224
225 fn files_edges(&self) -> (f64, f64) {
229 match self {
230 Self::Surround(_) => (1.0, 1.0),
231 Self::Vertical(_) => (1.0, 0.0),
232 Self::Horizontal(_) => (0.0, 1.0),
233 _ => (0.0, 0.0),
234 }
235 }
236
237 fn border_edges(&self) -> (f64, f64) {
241 match self {
242 Self::Surround(_) | Self::Border(_) => (1.0, 1.0),
243 Self::Vertical(_) | Self::VerBorder(_) => (1.0, 0.0),
244 Self::Horizontal(_) | Self::HorBorder(_) => (0.0, 1.0),
245 Self::Empty => (0.0, 0.0),
246 }
247 }
248}