1pub(crate) mod event_queue;
2pub(crate) mod handler;
3pub(crate) mod helper;
4
5use as_any::AsAny;
6use singlevec::SingleVec;
7use uid::IdU64;
8use vector2d::Vector2D;
9
10use crate::canvas::{BorderCanvas, Canvas};
11use crate::common::*;
12use std::cell::RefCell;
13use std::rc::*;
14
15pub use event_queue::*;
16pub use handler::WindowHandler;
17pub use helper::*;
18
19
20#[derive(Clone, Copy, Debug, PartialEq, Default)]
22pub enum BorderKind {
23 #[default]
24 Solid,
25 Thick,
26 Dashed,
27}
28
29impl BorderKind {
30 pub const fn corner_style(&self) -> [Grapheme; 4] {
32 match self {
33 BorderKind::Solid => [
34 Grapheme::new_unchecked("┌", GlyphWidth::Half),
35 Grapheme::new_unchecked("┐", GlyphWidth::Half),
36 Grapheme::new_unchecked("└", GlyphWidth::Half),
37 Grapheme::new_unchecked("┘", GlyphWidth::Half),
38 ],
39 BorderKind::Dashed => [
40 Grapheme::new_unchecked("╔", GlyphWidth::Half),
41 Grapheme::new_unchecked("╗", GlyphWidth::Half),
42 Grapheme::new_unchecked("╚", GlyphWidth::Half),
43 Grapheme::new_unchecked("╝", GlyphWidth::Half),
44 ],
45 BorderKind::Thick => [
46 Grapheme::new_unchecked("┏", GlyphWidth::Half),
47 Grapheme::new_unchecked("┓", GlyphWidth::Half),
48 Grapheme::new_unchecked("┗", GlyphWidth::Half),
49 Grapheme::new_unchecked("┛", GlyphWidth::Half),
50 ],
51 }
52 }
53
54 pub const fn cross_style(&self) -> Grapheme {
56 match self {
57 BorderKind::Solid => Grapheme::new_unchecked("┼", GlyphWidth::Half),
58 BorderKind::Dashed => Grapheme::new_unchecked("╬", GlyphWidth::Half),
59 BorderKind::Thick => Grapheme::new_unchecked("╋", GlyphWidth::Half),
60 }
61 }
62
63 pub const fn connector_style(&self) -> [Grapheme; 4] {
65 match self {
66 BorderKind::Solid => [
67 Grapheme::new_unchecked("├", GlyphWidth::Half),
68 Grapheme::new_unchecked("┤", GlyphWidth::Half),
69 Grapheme::new_unchecked("┬", GlyphWidth::Half),
70 Grapheme::new_unchecked("┴", GlyphWidth::Half),
71 ],
72 BorderKind::Dashed => [
73 Grapheme::new_unchecked("╠", GlyphWidth::Half),
74 Grapheme::new_unchecked("╣", GlyphWidth::Half),
75 Grapheme::new_unchecked("╦", GlyphWidth::Half),
76 Grapheme::new_unchecked("╩", GlyphWidth::Half),
77 ],
78 BorderKind::Thick => [
79 Grapheme::new_unchecked("┣", GlyphWidth::Half),
80 Grapheme::new_unchecked("┫", GlyphWidth::Half),
81 Grapheme::new_unchecked("┳", GlyphWidth::Half),
82 Grapheme::new_unchecked("┻", GlyphWidth::Half),
83 ],
84 }
85 }
86
87 pub const fn line_style(&self) -> [Grapheme; 2] {
89 match self {
90 BorderKind::Solid => [
91 Grapheme::new_unchecked("─", GlyphWidth::Half),
92 Grapheme::new_unchecked("│", GlyphWidth::Half),
93 ],
94 BorderKind::Dashed => [
95 Grapheme::new_unchecked("═", GlyphWidth::Half),
96 Grapheme::new_unchecked("║", GlyphWidth::Half),
97 ],
98 BorderKind::Thick => [
99 Grapheme::new_unchecked("━", GlyphWidth::Half),
100 Grapheme::new_unchecked("┃", GlyphWidth::Half),
101 ],
102 }
103 }
104}
105
106pub type CustomStyleFn = fn(&dyn Window, BorderCanvas);
108
109#[derive(Copy, Clone, Debug, Default)]
110pub enum BorderStyle {
111 #[default]
112 None,
113 Preset {
114 kind: BorderKind,
115 bg: Option<Color>,
116 fg: Option<Color>,
117 },
118 Custom(CustomStyleFn, Thickness),
119}
120
121impl PartialEq for BorderStyle {
122 fn eq(&self, other: &Self) -> bool {
123 match self {
124 Self::None => matches!(other, Self::None),
125 Self::Preset {
126 kind: kind0,
127 bg: bg0,
128 fg: fg0,
129 } => match other {
130 Self::Preset { kind, bg, fg } => kind0 == kind && bg0 == bg && fg0 == fg,
131 _ => false,
132 },
133 Self::Custom(_, _) => false,
134 }
135 }
136}
137
138impl BorderStyle {
139 pub const fn new(kind: BorderKind, bg: Option<Color>, fg: Option<Color>) -> Self {
140 Self::Preset { kind, bg, fg }
141 }
142
143 pub const fn custom(f: CustomStyleFn, thickness: Thickness) -> Self {
145 Self::Custom(f, thickness)
146 }
147
148 pub const fn thickness(&self) -> Thickness {
149 match *self {
150 BorderStyle::None => Thickness::from(0),
151 BorderStyle::Custom(_, tn) => tn,
152 _ => Thickness::from(1),
153 }
154 }
155
156 pub const fn get_borderkind(&self) -> Option<BorderKind> {
157 match self {
158 BorderStyle::Preset { kind, .. } => Some(*kind),
159 _ => None,
160 }
161 }
162}
163
164#[derive(Default, Clone, Copy, Debug, PartialEq)]
165pub struct Thickness {
166 pub top: TSize,
167 pub left: TSize,
168 pub right: TSize,
169 pub bottom: TSize,
170}
171
172impl Thickness {
173 pub const fn from(size: TSize) -> Self {
174 Self {
175 top: size,
176 left: size,
177 right: size,
178 bottom: size,
179 }
180 }
181
182 pub const fn new(top: TSize, left: TSize, right: TSize, bottom: TSize) -> Self {
183 Self {
184 top,
185 left,
186 right,
187 bottom,
188 }
189 }
190
191 pub const fn width(&self) -> TSize {
192 self.left + self.right
193 }
194
195 pub const fn height(&self) -> TSize {
196 self.top + self.bottom
197 }
198}
199
200impl From<CustomStyleFn> for BorderStyle {
201 fn from(value: CustomStyleFn) -> Self {
202 Self::Custom(value, Thickness::from(1))
203 }
204}
205
206impl From<BorderKind> for BorderStyle {
207 fn from(value: BorderKind) -> Self {
208 Self::Preset {
209 kind: value,
210 bg: None,
211 fg: None,
212 }
213 }
214}
215
216#[derive(Copy, Clone, Debug, Default)]
217pub struct RectsOverlapping {}
218
219pub struct SubWindowBuilder {
220 base_rect: Rect,
221 children: SingleVec<WindowRef>,
222 rects: SingleVec<Rect>,
223 overlapping: bool,
224}
225
226impl SubWindowBuilder {
227 pub(crate) fn from(base_rect: Rect) -> Self {
228 Self {
229 base_rect,
230 children: SingleVec::new(),
231 rects: SingleVec::new(),
232 overlapping: true,
233 }
234 }
235
236 pub fn enable_overlapping(&mut self) {
239 self.overlapping = true;
240 }
241
242 pub fn disable_overlapping(&mut self) {
244 self.overlapping = false;
245 }
246
247 pub fn add_child(&mut self, child: WindowRef) {
249 self.children.push(child);
250 }
251
252 pub fn add_rect(&mut self, rect: Rect) -> Result<(), RectsOverlapping> {
254 if self.check_overlapping(rect) {
255 return Err(RectsOverlapping::default());
256 }
257 self.rects.push(rect);
258 Ok(())
259 }
260
261 pub fn add_pair(
264 &mut self,
265 child: WindowRef,
266 rect: Option<Rect>,
267 ) -> Result<(), RectsOverlapping> {
268 let rect = rect.unwrap_or(self.base_rect);
269 if self.check_overlapping(rect) {
270 return Err(RectsOverlapping::default());
271 }
272
273 self.children.push(child);
274 self.rects.push(rect);
275 Ok(())
276 }
277
278 #[inline(always)]
279 pub fn base_rect(&self) -> Rect {
280 self.base_rect
281 }
282
283 pub fn build(self) -> Option<SubWindows> {
287 if self.children.len() != self.rects.len() {
288 return None;
289 }
290
291 Some(SubWindows {
292 children: self.children,
293 rects: self.rects,
294 })
295 }
296
297 fn check_overlapping(&self, rect: Rect) -> bool {
298 if !self.overlapping {
299 for rt in self.rects.iter() {
300 if rt.overlaps(&rect) {
301 return true;
302 }
303 }
304 }
305 false
306 }
307}
308
309#[derive(Default)]
311pub struct SubWindows {
312 children: SingleVec<WindowRef>,
313 rects: SingleVec<Rect>,
314}
315
316impl SubWindows {
317 pub fn children(&self) -> &[WindowRef] {
319 &self.children
320 }
321
322 pub fn rects(&self) -> &[Rect] {
325 &self.rects
326 }
327}
328
329pub type WindowRef = Rc<RefCell<dyn Window>>;
330pub type WindowWeakRef = Weak<RefCell<dyn Window>>;
331
332pub trait Window: WindowLayout + HasWindowUID + AsAny {
334 fn handle_event(&mut self, event: &mut WindowEvent) {
342 let _ = event;
343 }
344
345 fn children(&mut self, builder: SubWindowBuilder) -> SubWindows {
348 let _ = builder;
349 SubWindows::default()
350 }
351
352 fn render(&self, canvas: &mut Canvas);
356
357
358 fn focus(&self) -> Option<WindowRef> {
361 None
362 }
363
364 fn is_enabled(&self) -> bool {
368 true
369 }
370}
371
372
373pub trait WindowLayout {
375 fn alignment(&self) -> (HorizontalAlignment, VerticalAlignment) {
377 (HorizontalAlignment::default(), VerticalAlignment::default())
378 }
379
380 fn desired_size_pre_hook(&mut self, available_size: TPoint) {
384 _ = available_size;
385 }
386
387 fn desired_size(&self, available_size: TPoint) -> TPoint {
391 available_size
392 }
393
394 fn margin(&self) -> Thickness {
395 Thickness::default()
396 }
397
398 fn border(&self) -> BorderStyle {
399 BorderStyle::default()
400 }
401
402 fn is_visible(&self) -> bool {
403 true
404 }
405}
406
407
408pub trait HasWindowUID {
409 fn uid(&self) -> WindowUID;
412}
413
414#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
416pub struct WindowUID(u64);
417
418impl std::fmt::Display for WindowUID {
419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420 write!(f, "{}", self.0)
421 }
422}
423
424impl Default for WindowUID {
425 fn default() -> Self {
426 Self::new()
427 }
428}
429
430impl WindowUID {
431 pub fn new() -> Self {
433 Self(IdU64::<Self>::new().get())
434 }
435}