lv_tui/widgets/
overlay.rs1use crate::component::{Component, EventCx, LayoutCx, MeasureCx};
2use crate::event::Event;
3use crate::geom::{Rect, Size};
4use crate::layout::Constraint;
5use crate::node::Node;
6use crate::render::RenderCx;
7use crate::style::{Color, Style};
8
9pub struct Overlay {
11 background: Option<Node>,
12 foreground: Option<Node>,
13 active: bool,
14}
15
16impl Overlay {
17 pub fn new(
18 background: impl Component + 'static,
19 foreground: impl Component + 'static,
20 ) -> Self {
21 Self {
22 background: Some(Node::new(background)),
23 foreground: Some(Node::new(foreground)),
24 active: false,
25 }
26 }
27
28 pub fn show(&mut self) { self.active = true; }
29 pub fn hide(&mut self) { self.active = false; }
30 pub fn is_active(&self) -> bool { self.active }
31}
32
33impl Component for Overlay {
34 fn render(&self, cx: &mut RenderCx) {
35 if let Some(bg) = &self.background {
37 bg.render_with_clip(cx.buffer, cx.focused_id, None);
38 }
39
40 if self.active {
41 let viewport = cx.rect;
43 for y in viewport.y..viewport.y.saturating_add(viewport.height) {
44 for x in viewport.x..viewport.x.saturating_add(viewport.width) {
45 if let Some(cell) = cx.buffer.get_mut(x, y) {
46 cell.style.bg = Some(Color::Black);
47 if cell.style.fg.is_none() {
48 cell.style.fg = Some(Color::Gray);
49 }
50 }
51 }
52 }
53
54 if let Some(fg) = &self.foreground {
56 let fg_size = fg.measure(Constraint::loose(viewport.width.saturating_sub(4), viewport.height.saturating_sub(4)));
57 let fg_w = fg_size.width.min(viewport.width.saturating_sub(4));
58 let fg_h = fg_size.height.min(viewport.height.saturating_sub(4));
59 let fg_x = viewport.x.saturating_add(viewport.width.saturating_sub(fg_w) / 2);
60 let fg_y = viewport.y.saturating_add(viewport.height.saturating_sub(fg_h) / 2);
61 let fg_rect = Rect { x: fg_x, y: fg_y, width: fg_w + 4, height: fg_h + 4 };
62
63 for y in fg_rect.y..fg_rect.y.saturating_add(fg_rect.height) {
65 for x in fg_rect.x..fg_rect.x.saturating_add(fg_rect.width) {
66 if let Some(cell) = cx.buffer.get_mut(x, y) {
67 cell.style.bg = Some(Color::White);
68 cell.style.fg = Some(Color::Black);
69 }
70 }
71 }
72
73 let inner = fg_rect.inner(crate::geom::Insets::all(2));
75 let saved = fg.rect();
76 fg.set_rect(inner);
77 fg.render(cx.buffer, cx.focused_id);
78 fg.set_rect(saved);
79 }
80 }
81 }
82
83 fn measure(&self, constraint: Constraint, _cx: &mut MeasureCx) -> Size {
84 if let Some(bg) = &self.background {
85 bg.measure(constraint)
86 } else {
87 Size { width: constraint.max.width, height: constraint.max.height }
88 }
89 }
90
91 fn focusable(&self) -> bool { false }
92
93 fn event(&mut self, event: &Event, cx: &mut EventCx) {
94 if matches!(event, Event::Focus | Event::Blur | Event::Tick) { return; }
95
96 if self.active {
97 if let Event::Key(key) = event {
99 if key.key == crate::event::Key::Esc {
100 self.hide();
101 cx.invalidate_paint();
102 return;
103 }
104 }
105 if let Some(fg) = &mut self.foreground {
107 let mut child_cx = EventCx::new(
108 &mut fg.dirty, cx.global_dirty, cx.quit, cx.phase, cx.propagation_stopped,
109 );
110 child_cx.task_sender = cx.task_sender.clone();
111 fg.component.event(event, &mut child_cx);
112 }
113 } else {
114 if let Some(bg) = &mut self.background {
115 let mut child_cx = EventCx::new(
116 &mut bg.dirty, cx.global_dirty, cx.quit, cx.phase, cx.propagation_stopped,
117 );
118 child_cx.task_sender = cx.task_sender.clone();
119 bg.component.event(event, &mut child_cx);
120 }
121 }
122 }
123
124 fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) {
125 if let Some(bg) = &mut self.background {
126 bg.layout(rect);
127 }
128 if let Some(fg) = &mut self.foreground {
129 fg.layout(rect); }
131 }
132
133 fn for_each_child(&self, f: &mut dyn FnMut(&Node)) {
134 if self.active {
135 if let Some(fg) = &self.foreground { f(fg); }
136 } else {
137 if let Some(bg) = &self.background { f(bg); }
138 }
139 }
140
141 fn for_each_child_mut(&mut self, f: &mut dyn FnMut(&mut Node)) {
142 if self.active {
143 if let Some(fg) = &mut self.foreground { f(fg); }
144 } else {
145 if let Some(bg) = &mut self.background { f(bg); }
146 }
147 }
148
149 fn style(&self) -> Style { Style::default() }
150}