1use crate::{
2 group_bounds, AnyElement, DispatchPhase, Element, IdentifiedElement, IntoAnyElement,
3 MouseDownEvent, MouseMoveEvent, MouseUpEvent, SharedString, Style, StyleCascade,
4 StyleRefinement, ViewContext,
5};
6use parking_lot::Mutex;
7use refineable::{CascadeSlot, Refineable};
8use smallvec::SmallVec;
9use std::sync::{
10 atomic::{AtomicBool, Ordering::SeqCst},
11 Arc,
12};
13
14trait LayoutNode<V: 'static + Send + Sync> {
15 fn state(&mut self) -> &mut LayoutNodeState<V>;
16
17 fn child(mut self, child: impl IntoAnyElement<V>) -> Self
18 where
19 Self: Sized,
20 {
21 self.state().children.push(child.into_any());
22 self
23 }
24
25 fn children<C, E>(mut self, children: C) -> Self
26 where
27 C: IntoIterator<Item = E>,
28 E: IntoAnyElement<V>,
29 Self: Sized,
30 {
31 for child in children {
32 self.state().children.push(child.into_any());
33 }
34 self
35 }
36}
37
38struct LayoutNodeState<V: 'static + Send + Sync> {
39 style_cascade: StyleCascade,
40 computed_style: Option<Style>,
41 children: SmallVec<[AnyElement<V>; 2]>,
42}
43
44impl<V> IntoAnyElement<V> for LayoutNodeState<V>
45where
46 V: 'static + Send + Sync,
47{
48 fn into_any(self) -> AnyElement<V> {
49 AnyElement::new(self)
50 }
51}
52
53impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
54 type ViewState = V;
55 type ElementState = ();
56
57 fn element_id(&self) -> Option<crate::ElementId> {
58 None
59 }
60
61 fn layout(
62 &mut self,
63 state: &mut Self::ViewState,
64 _: Option<Self::ElementState>,
65 cx: &mut crate::ViewContext<Self::ViewState>,
66 ) -> (crate::LayoutId, Self::ElementState) {
67 let layout_ids = self
68 .children
69 .iter_mut()
70 .map(|child| child.layout(state, cx))
71 .collect::<Vec<_>>();
72
73 // todo!("pass just the style cascade")
74 let style = self.computed_style().clone();
75 let layout_id = cx.request_layout(style, layout_ids);
76 (layout_id, ())
77 }
78
79 fn paint(
80 &mut self,
81 _: crate::Bounds<crate::Pixels>,
82 state: &mut Self::ViewState,
83 _: &mut Self::ElementState,
84 cx: &mut crate::ViewContext<Self::ViewState>,
85 ) {
86 for child in &mut self.children {
87 child.paint(state, None, cx);
88 }
89 }
90}
91
92pub trait Styled {
93 fn style_cascade(&mut self) -> &mut StyleCascade;
94 fn computed_style(&mut self) -> &Style;
95}
96
97pub struct StyledElement<E> {
98 child: E,
99}
100
101impl<E> IntoAnyElement<E::ViewState> for StyledElement<E>
102where
103 E: Element + Styled,
104{
105 fn into_any(self) -> AnyElement<E::ViewState> {
106 AnyElement::new(self)
107 }
108}
109
110impl<E: Element + Styled> Element for StyledElement<E> {
111 type ViewState = E::ViewState;
112 type ElementState = E::ElementState;
113
114 fn element_id(&self) -> Option<crate::ElementId> {
115 self.child.element_id()
116 }
117
118 fn layout(
119 &mut self,
120 state: &mut Self::ViewState,
121 element_state: Option<Self::ElementState>,
122 cx: &mut crate::ViewContext<Self::ViewState>,
123 ) -> (crate::LayoutId, Self::ElementState) {
124 self.child.layout(state, element_state, cx)
125 }
126
127 fn paint(
128 &mut self,
129 bounds: crate::Bounds<crate::Pixels>,
130 state: &mut Self::ViewState,
131 element_state: &mut Self::ElementState,
132 cx: &mut crate::ViewContext<Self::ViewState>,
133 ) {
134 self.child.computed_style().paint(bounds, cx);
135 self.child.paint(bounds, state, element_state, cx);
136 }
137}
138
139pub trait Hoverable {
140 fn hover_style(&mut self) -> &mut StyleRefinement;
141
142 fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
143 where
144 Self: Sized,
145 {
146 f(self.hover_style());
147 self
148 }
149}
150
151struct HoverableElement<Child> {
152 hover_style: StyleRefinement,
153 group: Option<SharedString>,
154 cascade_slot: CascadeSlot,
155 hovered: Arc<AtomicBool>,
156 child: Child,
157}
158
159impl<Child: Styled + Element> HoverableElement<Child> {
160 fn hover_style(&mut self) -> &mut StyleRefinement {
161 &mut self.hover_style
162 }
163}
164
165impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
166where
167 E: Element + Styled,
168{
169 fn into_any(self) -> AnyElement<E::ViewState> {
170 AnyElement::new(self)
171 }
172}
173
174impl<E> Element for HoverableElement<E>
175where
176 E: Element + Styled,
177{
178 type ViewState = E::ViewState;
179 type ElementState = E::ElementState;
180
181 fn element_id(&self) -> Option<crate::ElementId> {
182 self.child.element_id()
183 }
184
185 fn layout(
186 &mut self,
187 state: &mut Self::ViewState,
188 element_state: Option<Self::ElementState>,
189 cx: &mut crate::ViewContext<Self::ViewState>,
190 ) -> (crate::LayoutId, Self::ElementState) {
191 self.child.layout(state, element_state, cx)
192 }
193
194 fn paint(
195 &mut self,
196 bounds: crate::Bounds<crate::Pixels>,
197 state: &mut Self::ViewState,
198 element_state: &mut Self::ElementState,
199 cx: &mut crate::ViewContext<Self::ViewState>,
200 ) {
201 let target_bounds = self
202 .group
203 .as_ref()
204 .and_then(|group| group_bounds(group, cx))
205 .unwrap_or(bounds);
206
207 let hovered = target_bounds.contains_point(cx.mouse_position());
208
209 let slot = self.cascade_slot;
210 let style = hovered.then_some(self.hover_style.clone());
211 self.child.style_cascade().set(slot, style);
212 self.hovered.store(hovered, SeqCst);
213
214 let hovered = self.hovered.clone();
215 cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
216 if phase == DispatchPhase::Capture {
217 if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
218 cx.notify();
219 }
220 }
221 });
222
223 self.child.paint(bounds, state, element_state, cx);
224 }
225}
226
227pub trait Clickable: IdentifiedElement + Sized {
228 fn active_style(&mut self) -> &mut StyleRefinement;
229 fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
230
231 fn on_click(
232 &mut self,
233 f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
234 + 'static
235 + Send
236 + Sync,
237 ) where
238 Self: Sized,
239 {
240 self.listeners().push(Arc::new(f));
241 }
242
243 fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
244 where
245 Self: Sized,
246 {
247 f(self.active_style());
248 self
249 }
250}
251
252type ClickListeners<V> =
253 SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
254
255pub struct ClickableElementState<E: IdentifiedElement> {
256 mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
257 child_state: E::ElementState,
258}
259
260pub struct MouseClickEvent {
261 down: MouseDownEvent,
262 up: MouseUpEvent,
263}
264
265pub struct ClickableElement<E: IdentifiedElement> {
266 child: E,
267 listeners: ClickListeners<E::ViewState>,
268 active_style: StyleRefinement,
269 cascade_slot: CascadeSlot,
270}
271
272impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
273where
274 E: IdentifiedElement + Styled,
275{
276 fn into_any(self) -> AnyElement<E::ViewState> {
277 AnyElement::new(self)
278 }
279}
280
281impl<E> Element for ClickableElement<E>
282where
283 E: IdentifiedElement + Styled,
284{
285 type ViewState = E::ViewState;
286 type ElementState = ClickableElementState<E>;
287
288 fn element_id(&self) -> Option<crate::ElementId> {
289 Some(IdentifiedElement::element_id(&self.child))
290 }
291
292 fn layout(
293 &mut self,
294 state: &mut Self::ViewState,
295 element_state: Option<Self::ElementState>,
296 cx: &mut crate::ViewContext<Self::ViewState>,
297 ) -> (crate::LayoutId, Self::ElementState) {
298 if let Some(element_state) = element_state {
299 if element_state.mouse_down.lock().is_some() {
300 self.child
301 .style_cascade()
302 .set(self.cascade_slot, Some(self.active_style.clone()));
303 }
304
305 let (layout_id, child_state) =
306 self.child
307 .layout(state, Some(element_state.child_state), cx);
308 (
309 layout_id,
310 ClickableElementState {
311 mouse_down: element_state.mouse_down,
312 child_state,
313 },
314 )
315 } else {
316 let (layout_id, child_state) = self.child.layout(state, None, cx);
317 (
318 layout_id,
319 ClickableElementState {
320 mouse_down: Default::default(),
321 child_state,
322 },
323 )
324 }
325 }
326
327 fn paint(
328 &mut self,
329 bounds: crate::Bounds<crate::Pixels>,
330 state: &mut Self::ViewState,
331 element_state: &mut Self::ElementState,
332 cx: &mut crate::ViewContext<Self::ViewState>,
333 ) {
334 if !self.listeners.is_empty() || self.active_style.is_some() {
335 if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
336 self.child
337 .style_cascade()
338 .set(self.cascade_slot, Some(self.active_style.clone()));
339 let listeners = self.listeners.clone();
340 let mouse_down_mutex = element_state.mouse_down.clone();
341 cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
342 if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
343 for listener in &*listeners {
344 listener(
345 view,
346 &MouseClickEvent {
347 down: mouse_down.clone(),
348 up: up.clone(),
349 },
350 cx,
351 );
352 }
353 }
354
355 mouse_down_mutex.lock().take();
356 cx.notify();
357 });
358 } else {
359 let mouse_down_mutex = element_state.mouse_down.clone();
360 cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
361 if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
362 *mouse_down_mutex.lock() = Some(down.clone());
363 cx.notify();
364 }
365 });
366 }
367 }
368
369 self.child
370 .paint(bounds, state, &mut element_state.child_state, cx);
371 }
372}
373
374struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
375
376impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
377 fn state(&mut self) -> &mut LayoutNodeState<V> {
378 &mut self.0.child
379 }
380}
381
382impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
383 fn style_cascade(&mut self) -> &mut StyleCascade {
384 &mut self.style_cascade
385 }
386
387 fn computed_style(&mut self) -> &Style {
388 self.computed_style
389 .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
390 }
391}
392
393impl<V: 'static + Send + Sync> Styled for Div<V> {
394 fn style_cascade(&mut self) -> &mut StyleCascade {
395 self.0.child.style_cascade()
396 }
397
398 fn computed_style(&mut self) -> &Style {
399 self.0.child.computed_style()
400 }
401}
402
403impl<V: 'static + Send + Sync> Hoverable for Div<V> {
404 fn hover_style(&mut self) -> &mut StyleRefinement {
405 self.0.hover_style()
406 }
407}