1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use crossterm::event::Event;
6use singlevec::SingleVec;
7
8use crate::canvas::*;
9use crate::common::*;
10use crate::framebuffer::Framebuffer;
11use crate::window::*;
12
13#[derive(Clone)]
14struct WindowStructure {
15 rect: Rect,
16 has_border: bool,
17 depth: u8,
18 border: Thickness,
19 render_inner: bool,
20 weak: WindowWeakRef,
21 parent: Option<WindowUID>,
22 children: SingleVec<WindowUID>,
23}
24
25impl WindowStructure {
26 fn new(
27 ctx: &WindowRef,
28 rect: Rect,
29 has_border: bool,
30 border: Thickness,
31 depth: u8,
32 parent: Option<WindowUID>,
33 ) -> Self {
34 Self {
35 rect,
36 has_border,
37 border,
38 depth,
39 render_inner: false,
40 weak: Rc::downgrade(ctx),
41 children: SingleVec::new(),
42 parent,
43 }
44 }
45
46 fn subtract_border(&self, rect: &mut Rect) {
47 rect.start.x += self.border.left;
48 rect.size.x -= self.border.width();
49 rect.start.y += self.border.top;
50 rect.size.y -= self.border.height();
51 }
52
53 fn inner_rect(&self) -> Rect {
54 let mut rect = self.rect;
55 if self.has_border {
56 self.subtract_border(&mut rect);
57 }
58 rect
59 }
60}
61
62
63struct Focus {
64 win: WindowRef,
65 uid: WindowUID,
67}
68
69impl PartialEq for Focus {
70 fn eq(&self, other: &Self) -> bool {
71 self.uid == other.uid
72 }
73}
74
75struct SizeCache {
76 size: TPoint,
77 map: RefCell<HashMap<WindowUID, TPoint>>,
78}
79
80impl SizeCache {
81 fn new(size: TPoint) -> Self {
82 Self {
83 size,
84 map: RefCell::new(HashMap::with_capacity(128)),
85 }
86 }
87
88 fn resize(&mut self, size: TPoint) {
89 self.size = size;
90 }
91
92 fn compare_n_update(&self, uid: WindowUID, size: TPoint) -> bool {
94 let mut brw = self.map.borrow_mut();
95 let old = brw
96 .insert(uid, size)
97 .unwrap_or(Vector2D::new(TSize::MIN, TSize::MIN));
98 old != size
99 }
100}
101
102
103pub struct WindowHandler {
104 structure: HashMap<WindowUID, WindowStructure>,
105 main_window: Rc<RefCell<dyn Window>>,
106 focus: Focus,
107 size_cache: SizeCache,
108 queue: WindowEventQueue,
109}
110
111impl WindowHandler {
112 pub(crate) fn new(main_window: WindowRef, size: TPoint) -> Self {
113 let focus = Self::find_focus(&main_window);
114 focus
115 .win
116 .borrow_mut()
117 .handle_event(&mut WindowEvent::new(Event::FocusGained));
118 let queue = WindowEventQueue::initialize();
119 let mut window_handler = Self {
121 main_window,
122 focus,
123 structure: HashMap::with_capacity(128),
124 size_cache: SizeCache::new(size),
125 queue,
126 };
127 window_handler.broadcast_resize(size);
128 window_handler
129 }
130
131 pub(crate) fn handle_event(&mut self, event: Event) {
132 let mut win_event = WindowEvent::new(event);
133 self.handle_event_inner(self.focus.uid, &mut win_event);
134 }
135
136 pub(crate) fn broadcast_resize(&mut self, size: TPoint) {
137 self.size_cache.resize(size);
138 let uid = Self::determine_window_structure(
139 &mut self.structure,
140 Rect::from(size.x, size.y),
141 &self.main_window,
142 u8::MIN,
143 None,
144 );
145 self.broadcast_resize_rec(uid);
146 self.structure
147 .retain(|_, s| s.weak.strong_count() > usize::MIN);
148 }
149
150 pub(crate) fn render(&mut self, framebuffer: &mut Framebuffer) {
151 self.handle_events();
152 let uid = self.main_window.borrow().uid();
153 self.render_window_rec(&mut Canvas::from_framebuffer(framebuffer), uid);
154 }
155
156 fn broadcast_resize_rec(&self, win: WindowUID) {
157 let struc = self.structure.get(&win).unwrap();
158 let rect = struc.inner_rect();
159 if self.size_cache.compare_n_update(win, rect.size) {
160 struc
161 .weak
162 .upgrade()
163 .unwrap()
164 .borrow_mut()
165 .handle_event(&mut WindowEvent::new(Event::Resize(
166 rect.size.x as TSize,
167 rect.size.y as TSize,
168 )));
169 }
170 for w in struc.children.iter() {
171 self.broadcast_resize_rec(*w);
172 }
173 }
174
175 fn get_parent_rect(&self, ws: &WindowStructure) -> Rect {
176 if let Some(uid) = ws.parent {
177 if let Some(parent) = self.structure.get(&uid) {
178 let inner = parent.inner_rect();
179 return Rect::from(inner.size.x, inner.size.y);
180 }
181 }
182 Rect::from(self.size_cache.size.x, self.size_cache.size.y)
183 }
184
185 pub(crate) fn handle_events(&mut self) {
186 let mut window: Option<TreeUpdate> = None;
187 let mut focus: Option<FocusUpdate> = None;
188 for e in self.queue.recv.try_iter() {
189 match e.property {
190 WindowProperty::Focus => {
191 if let Some(w) = self.structure.get(&e.uid) {
192 match focus.as_ref() {
193 Some(current) => {
194 if w.depth < current.depth {
195 focus = w.weak.upgrade().map(|v| FocusUpdate {
196 win: v,
197 depth: w.depth,
198 });
199 }
200 }
201 None => {
202 focus = w.weak.upgrade().map(|v| FocusUpdate {
203 win: v,
204 depth: w.depth,
205 })
206 }
207 }
208 }
209 }
210 WindowProperty::Children => {
211 if let Some(w) = self.structure.get(&e.uid) {
212 match window.as_ref() {
213 Some(current) => {
214 if w.depth < current.depth {
215 window = w.weak.upgrade().map(|v| TreeUpdate {
216 win: v,
217 depth: w.depth,
218 rect: w.rect,
219 });
220 }
221 }
222 None => {
223 window = w.weak.upgrade().map(|v| TreeUpdate {
224 win: v,
225 depth: w.depth,
226 rect: w.rect,
227 })
228 }
229 }
230 }
231 }
232 _ => {
233 if let Some(w) = self.structure.get(&e.uid) {
236 if let Some(p) = w.parent {
237 match self.structure.get(&p) {
238 Some(parent) => match window.as_ref() {
239 Some(current) => {
240 if parent.depth < current.depth {
241 window = parent.weak.upgrade().map(|v| TreeUpdate {
242 win: v,
243 depth: parent.depth,
244 rect: self.get_parent_rect(parent),
245 });
246 }
247 }
248 None => {
249 window = parent.weak.upgrade().map(|v| TreeUpdate {
250 win: v,
251 depth: parent.depth,
252 rect: self.get_parent_rect(parent),
253 });
254 }
255 },
256 None => {
257 window = Some(TreeUpdate {
258 win: self.main_window.clone(),
259 depth: u8::MIN,
260 rect: self.get_parent_rect(w),
261 })
262 }
263 }
264 }
265 }
266 }
267 }
268 }
269
270 if let Some(update) = window.as_ref() {
271 let parent = {
272 match self.structure.get(&update.win.borrow().uid()) {
273 Some(ws) => ws.parent,
274 None => None,
275 }
276 };
277
278 Self::determine_window_structure(
279 &mut self.structure,
280 update.rect,
281 &update.win,
282 update.depth,
283 parent,
284 );
285 }
286
287 if let Some(update) = focus.as_ref() {
288 let focus = Self::find_focus(&update.win);
289 if self.focus != focus && self.structure.contains_key(&focus.uid) {
291 self.focus
292 .win
293 .borrow_mut()
294 .handle_event(&mut WindowEvent::new(Event::FocusLost));
295 self.focus = focus;
296 self.focus
297 .win
298 .borrow_mut()
299 .handle_event(&mut WindowEvent::new(Event::FocusGained));
300 }
301 }
302
303 if window.is_some() {
304 self.structure
305 .retain(|_, s| s.weak.strong_count() > usize::MIN);
306
307 let uid = self.main_window.borrow().uid();
308 self.broadcast_resize_rec(uid);
309 }
310 }
311
312 fn determine_window_structure(
313 map: &mut HashMap<WindowUID, WindowStructure>,
314 base_rect: Rect,
315 window: &WindowRef,
316 depth: u8,
317 parent: Option<WindowUID>,
318 ) -> WindowUID {
319 let mut rect = base_rect;
320 let has_border = Self::determine_window_rect(&mut rect, &mut *window.borrow_mut());
321 let mut ws = WindowStructure::new(
323 window,
324 rect,
325 has_border,
326 window.borrow().border().thickness(),
327 depth,
328 parent,
329 );
330 let uid = window.borrow().uid();
331 let inner_rect = ws.inner_rect();
332
333 if inner_rect.area() > TSize::MIN {
334 ws.render_inner = true;
335 let child_rect = Rect::from(inner_rect.size.x, inner_rect.size.y);
336 let sub_wins = window
337 .borrow_mut()
338 .children(SubWindowBuilder::from(child_rect));
339 for (sub, child_rect) in sub_wins
340 .children()
341 .iter()
342 .zip(sub_wins.rects())
343 .filter(|(sub, _)| sub.borrow().is_visible())
344 {
345 let ch_uid =
346 Self::determine_window_structure(map, *child_rect, sub, depth + 1, Some(uid));
347 ws.children.push(ch_uid);
348 }
349 }
350
351 map.insert(uid, ws);
352 uid
353 }
354
355 fn determine_window_rect(base_rect: &mut Rect, window: &mut dyn Window) -> bool {
357 let (h_align, v_align) = window.alignment();
358 let margin = window.margin();
359 let tn = window.border().thickness();
360 let (w, h) = (tn.width(), tn.height());
361
362 window.desired_size_pre_hook(Vector2D::new(base_rect.size.x, base_rect.size.y));
363 let mut size = window.desired_size(Vector2D::new(base_rect.size.x, base_rect.size.y));
364 let has_border = window.border() != BorderStyle::None;
365 if size.x > base_rect.size.x || size.y > base_rect.size.y {
367 size = Vector2D::default();
368 }
369 if size.x * size.y > 0 {
371 if size.x <= w && size.x + w <= base_rect.size.x {
372 size.x += w;
373 }
374 if size.y <= h && size.y + h <= base_rect.size.y {
375 size.y += h;
376 }
377 }
378
379 Self::handle_margin(
380 base_rect,
381 margin.left,
382 margin.top,
383 margin.right,
384 margin.bottom,
385 );
386 Self::handle_alignment(base_rect, 0, h_align.into(), size.x);
387 Self::handle_alignment(base_rect, 1, v_align.into(), size.y);
388 has_border && base_rect.size.x > w && base_rect.size.y > h
389 }
390
391 fn find_focus(window: &WindowRef) -> Focus {
392 let win_brw = window.borrow();
393 match win_brw.focus() {
394 Some(sub) => Self::find_focus(&sub),
395 None => Focus {
396 win: window.clone(),
397 uid: win_brw.uid(),
398 },
399 }
400 }
401
402 fn handle_event_inner(&self, win: WindowUID, event: &mut WindowEvent) {
403 if let Some(ws) = self.structure.get(&win) {
404 if let Some(window) = ws.weak.upgrade() {
405 if window.borrow().is_enabled() {
406 window.borrow_mut().handle_event(event);
407 }
408 if !event.handled {
409 if let Some(parent) = ws.parent {
410 self.handle_event_inner(parent, event);
411 }
412 }
413 }
414 }
415 }
416
417 fn render_window_rec(&self, canvas: &mut Canvas, win: WindowUID) {
418 let ws = self.structure.get(&win).unwrap();
419 if let Some(ctx) = ws.weak.upgrade() {
420 let brw = ctx.borrow();
421 let mut rect = ws.rect;
422 if ws.has_border {
423 Self::render_border(&*brw, &mut Canvas::from_existing(canvas, rect).unwrap())
424 .unwrap();
425 ws.subtract_border(&mut rect);
426 }
427
428 if ws.render_inner {
429 let mut inner_canvas = Canvas::from_existing(canvas, rect).unwrap();
430 brw.render(&mut inner_canvas);
431 for sub in ws.children.iter() {
432 self.render_window_rec(&mut Canvas::from_existing(canvas, rect).unwrap(), *sub);
433 }
434 }
435 }
436 }
437
438 fn handle_margin(rect: &mut Rect, left: TSize, top: TSize, right: TSize, bottom: TSize) {
439 if rect.size.x > left {
440 rect.start.x += left;
441 rect.size.x -= left;
442 }
443 if rect.size.x > right {
444 rect.size.x -= right;
445 }
446 if rect.size.y > top {
447 rect.start.y += top;
448 rect.size.y -= top;
449 }
450 if rect.size.y > bottom {
451 rect.size.y -= bottom;
452 }
453 }
454
455 fn handle_alignment(
456 rect: &mut Rect,
457 rect_index: usize,
458 alignment: Alignment,
459 base_size: TSize,
460 ) {
461 if let Some(size) = rect.size[rect_index].checked_sub(base_size) {
462 match alignment {
463 Alignment::LowerBound => {
464 rect.size[rect_index] -= size;
465 }
466 Alignment::Center => {
467 let rem = size % 2;
468 if size + rem <= rect.size[rect_index] {
469 rect.start[rect_index] += size / 2 + rem;
470 rect.size[rect_index] -= size;
471 }
472 }
473 Alignment::HigherBound => {
474 rect.start[rect_index] += size;
475 }
476 }
477 }
478 }
479
480 fn render_border(window: &dyn Window, canvas: &mut Canvas) -> Result<(), GraphemeError> {
481 let border = window.border();
482 let tn = border.thickness();
483 let mut bcanvas = BorderCanvas::from(canvas, tn);
484 match border {
485 BorderStyle::Custom(f, _) => f(window, bcanvas),
486 BorderStyle::Preset { kind, bg, fg } => bcanvas.draw_preset_border(kind, bg, fg, "")?,
487 BorderStyle::None => {}
488 }
489
490 Ok(())
491 }
492}