Checkpoint

This commit is contained in:
Antonio Scandurra 2023-10-17 10:14:22 +02:00
parent b526fc070d
commit ac5b32c491

View File

@ -1,7 +1,9 @@
use crate::{
group_bounds, AnyElement, DispatchPhase, Element, IntoAnyElement, MouseMoveEvent, SharedString,
Style, StyleCascade, StyleRefinement,
group_bounds, AnyElement, DispatchPhase, Element, IdentifiedElement, IntoAnyElement,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, SharedString, Style, StyleCascade,
StyleRefinement, ViewContext,
};
use parking_lot::Mutex;
use refineable::{CascadeSlot, Refineable};
use smallvec::SmallVec;
use std::sync::{
@ -222,6 +224,153 @@ where
}
}
pub trait Clickable: IdentifiedElement + Sized {
fn active_style(&mut self) -> &mut StyleRefinement;
fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
fn on_click(
&mut self,
f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
+ 'static
+ Send
+ Sync,
) where
Self: Sized,
{
self.listeners().push(Arc::new(f));
}
fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
where
Self: Sized,
{
f(self.active_style());
self
}
}
type ClickListeners<V> =
SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
pub struct ClickableElementState<E: IdentifiedElement> {
mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
child_state: E::ElementState,
}
pub struct MouseClickEvent {
down: MouseDownEvent,
up: MouseUpEvent,
}
pub struct ClickableElement<E: IdentifiedElement> {
child: E,
listeners: ClickListeners<E::ViewState>,
active_style: StyleRefinement,
cascade_slot: CascadeSlot,
}
impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
where
E: IdentifiedElement + Styled,
{
fn into_any(self) -> AnyElement<E::ViewState> {
AnyElement::new(self)
}
}
impl<E> Element for ClickableElement<E>
where
E: IdentifiedElement + Styled,
{
type ViewState = E::ViewState;
type ElementState = ClickableElementState<E>;
fn element_id(&self) -> Option<crate::ElementId> {
Some(IdentifiedElement::element_id(&self.child))
}
fn layout(
&mut self,
state: &mut Self::ViewState,
element_state: Option<Self::ElementState>,
cx: &mut crate::ViewContext<Self::ViewState>,
) -> (crate::LayoutId, Self::ElementState) {
if let Some(element_state) = element_state {
if element_state.mouse_down.lock().is_some() {
self.child
.style_cascade()
.set(self.cascade_slot, Some(self.active_style.clone()));
}
let (layout_id, child_state) =
self.child
.layout(state, Some(element_state.child_state), cx);
(
layout_id,
ClickableElementState {
mouse_down: element_state.mouse_down,
child_state,
},
)
} else {
let (layout_id, child_state) = self.child.layout(state, None, cx);
(
layout_id,
ClickableElementState {
mouse_down: Default::default(),
child_state,
},
)
}
}
fn paint(
&mut self,
bounds: crate::Bounds<crate::Pixels>,
state: &mut Self::ViewState,
element_state: &mut Self::ElementState,
cx: &mut crate::ViewContext<Self::ViewState>,
) {
if !self.listeners.is_empty() || self.active_style.is_some() {
if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
self.child
.style_cascade()
.set(self.cascade_slot, Some(self.active_style.clone()));
let listeners = self.listeners.clone();
let mouse_down_mutex = element_state.mouse_down.clone();
cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
for listener in &*listeners {
listener(
view,
&MouseClickEvent {
down: mouse_down.clone(),
up: up.clone(),
},
cx,
);
}
}
mouse_down_mutex.lock().take();
cx.notify();
});
} else {
let mouse_down_mutex = element_state.mouse_down.clone();
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
*mouse_down_mutex.lock() = Some(down.clone());
cx.notify();
}
});
}
}
self.child
.paint(bounds, state, &mut element_state.child_state, cx);
}
}
struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {