use crate::{ group_bounds, AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, IntoAnyElement, MouseDownEvent, MouseEventListeners, MouseUpEvent, ParentElement, Pixels, SharedString, Styled, ViewContext, }; use refineable::{Cascade, CascadeSlot, Refineable}; use smallvec::SmallVec; use std::sync::{ atomic::{AtomicBool, Ordering::SeqCst}, Arc, }; pub struct Pressable { group: Option, cascade_slot: CascadeSlot, pressed_style: ::Refinement, child: E, } pub struct PressableState { pressed: Arc, child_state: S, } impl Pressable { pub fn new(mut child: E, group: Option) -> Self { Self { group, cascade_slot: child.style_cascade().reserve(), pressed_style: Default::default(), child, } } } impl Styled for Pressable where E: Styled, { type Style = E::Style; fn style_cascade(&mut self) -> &mut Cascade { self.child.style_cascade() } fn declared_style(&mut self) -> &mut ::Refinement { &mut self.pressed_style } } impl + Styled> Interactive for Pressable { fn listeners(&mut self) -> &mut MouseEventListeners { self.child.listeners() } } impl IntoAnyElement for Pressable where E: Styled + IdentifiedElement, ::Style: 'static + Refineable + Send + Sync + Default, <::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default, { fn into_any(self) -> AnyElement { AnyElement::new(self) } } impl Element for Pressable where E: Styled + IdentifiedElement, ::Style: 'static + Refineable + Send + Sync + Default, <::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default, { type ViewState = E::ViewState; type ElementState = PressableState; fn element_id(&self) -> Option { Some(IdentifiedElement::element_id(&self.child)) } fn layout( &mut self, state: &mut Self::ViewState, element_state: Option, cx: &mut ViewContext, ) -> (crate::LayoutId, Self::ElementState) { if let Some(element_state) = element_state { let (id, child_state) = self .child .layout(state, Some(element_state.child_state), cx); let element_state = PressableState { pressed: element_state.pressed, child_state, }; (id, element_state) } else { let (id, child_state) = self.child.layout(state, None, cx); let element_state = PressableState { pressed: Default::default(), child_state, }; (id, element_state) } } fn paint( &mut self, bounds: Bounds, state: &mut Self::ViewState, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) { let target_bounds = self .group .as_ref() .and_then(|group| group_bounds(group, cx)) .unwrap_or(bounds); let style = element_state .pressed .load(SeqCst) .then_some(self.pressed_style.clone()); let slot = self.cascade_slot; self.style_cascade().set(slot, style); let pressed = element_state.pressed.clone(); cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| { if phase == DispatchPhase::Bubble { if target_bounds.contains_point(event.position) { pressed.store(true, SeqCst); cx.notify(); } } }); let pressed = element_state.pressed.clone(); cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Capture { if pressed.load(SeqCst) { pressed.store(false, SeqCst); cx.notify(); } } }); self.child .paint(bounds, state, &mut element_state.child_state, cx); } } impl ParentElement for Pressable where E: ParentElement + IdentifiedElement + Styled, { type State = E::State; fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { self.child.children_mut() } } impl IdentifiedElement for Pressable where E: IdentifiedElement + Styled, ::Style: 'static + Refineable + Send + Sync + Default, <::Style as Refineable>::Refinement: 'static + Refineable + Send + Sync + Default, { }