1use crate::core;
5use crate::core::layout::{self, Layout};
6use crate::core::mouse;
7use crate::core::overlay;
8use crate::core::renderer;
9use crate::core::widget::operation;
10use crate::core::widget::tree::{self, Tree};
11use crate::core::widget::{Meta, Operation};
12use crate::core::window;
13use crate::core::{Event, Length, Rectangle, Shell, Size, Vector, Widget};
14
15pub struct Hover<W, V> {
21 base: W,
22 top: V,
23 is_top_focused: bool,
24 is_top_overlay_active: bool,
25 is_hovered: bool,
26}
27
28impl<W, V> Hover<W, V> {
29 pub fn new(base: W, top: V) -> Self {
31 Self {
32 base,
33 top,
34 is_top_focused: false,
35 is_top_overlay_active: false,
36 is_hovered: false,
37 }
38 }
39}
40
41impl<W, V> Meta for Hover<W, V> {}
42
43impl<W, V, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Hover<W, V>
44where
45 Renderer: core::Renderer,
46 W: Widget<Message, Theme, Renderer>,
47 V: Widget<Message, Theme, Renderer>,
48{
49 fn tag(&self) -> tree::Tag {
50 struct Tag;
51 tree::Tag::of::<Tag>()
52 }
53
54 fn diff(&mut self, tree: &mut Tree) {
55 if tree.children.len() != 2 {
56 tree.children = vec![Tree::new(&self.base), Tree::new(&self.top)];
57 }
58
59 tree.children[0].diff(&mut self.base);
60 tree.children[1].diff(&mut self.top);
61 }
62
63 fn size(&self) -> Size<Length> {
64 self.base.size()
65 }
66
67 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
68 self.base.layout(&mut tree.children[0], renderer, limits);
69
70 let base_size = tree.children[0].size;
71
72 self.top.layout(
73 &mut tree.children[1],
74 renderer,
75 &layout::Limits::new(Size::ZERO, base_size),
76 );
77
78 tree.size = base_size;
79 }
80
81 fn draw(
82 &self,
83 tree: &Tree,
84 renderer: &mut Renderer,
85 theme: &Theme,
86 style: &renderer::Style,
87 layout: Layout,
88 cursor: mouse::Cursor,
89 viewport: &Rectangle,
90 ) {
91 if let Some(bounds) = layout.bounds().intersection(viewport) {
92 let mut children = layout.iter(&tree.children);
93
94 let (base_layout, base_tree) = children.next().unwrap();
95
96 self.base.draw(
97 base_tree,
98 renderer,
99 theme,
100 style,
101 base_layout,
102 cursor,
103 viewport,
104 );
105
106 if cursor.is_over(layout.bounds()) || self.is_top_focused || self.is_top_overlay_active
107 {
108 let (top_layout, top_tree) = children.next().unwrap();
109
110 renderer.with_layer(bounds, |renderer| {
111 self.top.draw(
112 top_tree, renderer, theme, style, top_layout, cursor, viewport,
113 );
114 });
115 }
116 }
117 }
118
119 fn operate(
120 &mut self,
121 tree: &mut Tree,
122 layout: Layout,
123 viewport: &Rectangle,
124 renderer: &Renderer,
125 operation: &mut dyn Operation,
126 ) {
127 let mut children = layout.iter_mut(&mut tree.children);
128
129 let (base_layout, base_tree) = children.next().unwrap();
130 let (top_layout, top_tree) = children.next().unwrap();
131
132 self.base
133 .operate(base_tree, base_layout, viewport, renderer, operation);
134 self.top
135 .operate(top_tree, top_layout, viewport, renderer, operation);
136 }
137
138 fn update(
139 &mut self,
140 tree: &mut Tree,
141 event: &Event,
142 layout: Layout,
143 cursor: mouse::Cursor,
144 renderer: &Renderer,
145 shell: &mut Shell<'_, Message>,
146 viewport: &Rectangle,
147 ) {
148 let mut children = layout.iter_mut(&mut tree.children);
149
150 let (base_layout, base_tree) = children.next().unwrap();
151 let (top_layout, top_tree) = children.next().unwrap();
152
153 let is_hovered = cursor.is_over(layout.bounds());
154
155 if matches!(event, Event::Window(window::Event::RedrawRequested(_))) {
156 let mut count_focused = operation::focusable::count();
157
158 self.top.operate(
159 top_tree,
160 top_layout,
161 viewport,
162 renderer,
163 &mut operation::black_box(&mut count_focused),
164 );
165
166 self.is_top_focused = match count_focused.finish() {
167 operation::Outcome::Some(count) => count.focused.is_some(),
168 _ => false,
169 };
170
171 self.is_hovered = is_hovered;
172 } else if is_hovered != self.is_hovered {
173 shell.request_redraw();
174 }
175
176 let is_visible = is_hovered || self.is_top_focused || self.is_top_overlay_active;
177
178 if matches!(
179 event,
180 Event::Mouse(mouse::Event::CursorMoved { .. } | mouse::Event::ButtonReleased(_))
181 ) || is_visible
182 {
183 let redraw_request = shell.redraw_request();
184
185 self.top.update(
186 top_tree, event, top_layout, cursor, renderer, shell, viewport,
187 );
188
189 if !is_visible {
191 Shell::replace_redraw_request(shell, redraw_request);
192 }
193
194 if shell.is_event_captured() {
195 return;
196 }
197 };
198
199 self.base.update(
200 base_tree,
201 event,
202 base_layout,
203 cursor,
204 renderer,
205 shell,
206 viewport,
207 );
208 }
209
210 fn mouse_interaction(
211 &self,
212 tree: &Tree,
213 layout: Layout,
214 cursor: mouse::Cursor,
215 viewport: &Rectangle,
216 renderer: &Renderer,
217 ) -> mouse::Interaction {
218 let mut children = layout.iter(&tree.children).rev();
219
220 let (top_layout, top_tree) = children.next().unwrap();
221 let interaction = self
222 .top
223 .mouse_interaction(top_tree, top_layout, cursor, viewport, renderer);
224
225 if interaction != mouse::Interaction::None {
226 return interaction;
227 }
228
229 let (base_layout, base_tree) = children.next().unwrap();
230 self.base
231 .mouse_interaction(base_tree, base_layout, cursor, viewport, renderer)
232 }
233
234 fn overlay<'b>(
235 &'b mut self,
236 tree: &'b mut Tree,
237 layout: Layout,
238 renderer: &Renderer,
239 viewport: &Rectangle,
240 translation: Vector,
241 window: Size,
242 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
243 let mut children = layout.iter_mut(&mut tree.children);
244
245 let (base_layout, base_tree) = children.next().unwrap();
246 let (top_layout, top_tree) = children.next().unwrap();
247
248 let base_overlays = self.base.overlay(
249 base_tree,
250 base_layout,
251 renderer,
252 viewport,
253 translation,
254 window,
255 );
256 let top_overlays = self.top.overlay(
257 top_tree,
258 top_layout,
259 renderer,
260 viewport,
261 translation,
262 window,
263 );
264
265 self.is_top_overlay_active = !top_overlays.is_empty();
266
267 base_overlays.into_iter().chain(top_overlays).collect()
268 }
269}