Skip to main content

rosace_widgets/tree/
pressable.rs

1use std::sync::Arc;
2
3use super::{Widget, Children, PaintCtx};
4
5/// Makes ANY widget clickable — the whole child rect becomes a press target
6/// (clip-aware, z-ordered, persistent via the render tree).
7///
8/// Usually created through the blanket [`PressApi`]:
9///
10/// ```rust,ignore
11/// Text::new("tap me").on_press(|| do_thing())
12/// Card::new(content).on_press(open_details)
13/// ```
14///
15/// Widgets with their own `on_press` builder (Button, ListTile) keep it —
16/// inherent methods win. Press/hover visual feedback (the InkWell ripple)
17/// arrives with the interaction-states work; this is the hit plumbing.
18pub struct Pressable<W: Widget> {
19    child: W,
20    on_press: Arc<dyn Fn() + Send + Sync>,
21}
22
23impl<W: Widget + Send + Sync + 'static> Pressable<W> {
24    pub fn new(child: W, on_press: impl Fn() + Send + Sync + 'static) -> Self {
25        Self { child, on_press: Arc::new(on_press) }
26    }
27}
28
29impl<W: Widget + Send + Sync + 'static> Widget for Pressable<W> {
30    fn children(&self) -> Children<'_> {
31        Children::One(&self.child)
32    }
33
34    fn paint(&self, ctx: &mut PaintCtx) {
35        let f = self.on_press.clone();
36        ctx.on_press(move || f());
37        let r = ctx.rect;
38        self.child.paint(&mut ctx.child(r));
39    }
40    // layout, flex_factor: protocol defaults delegate to the child.
41}
42
43/// Wraps any widget with a long-press (≈500 ms) callback on its rect.
44pub struct LongPressable<W: Widget> {
45    child: W,
46    on_long_press: Arc<dyn Fn() + Send + Sync>,
47}
48
49impl<W: Widget + Send + Sync + 'static> LongPressable<W> {
50    pub fn new(child: W, f: impl Fn() + Send + Sync + 'static) -> Self {
51        Self { child, on_long_press: Arc::new(f) }
52    }
53}
54
55impl<W: Widget + Send + Sync + 'static> Widget for LongPressable<W> {
56    fn children(&self) -> Children<'_> { Children::One(&self.child) }
57    fn paint(&self, ctx: &mut PaintCtx) {
58        let f = self.on_long_press.clone();
59        ctx.on_long_press(move || f());
60        let r = ctx.rect;
61        self.child.paint(&mut ctx.child(r));
62    }
63}
64
65/// `.on_press(cb)` / `.on_long_press(cb)` on any widget (D094 vocabulary —
66/// never on_click/on_tap).
67pub trait PressApi: Widget + Sized + Send + Sync + 'static {
68    fn on_press(self, f: impl Fn() + Send + Sync + 'static) -> Pressable<Self> {
69        Pressable::new(self, f)
70    }
71    fn on_long_press(self, f: impl Fn() + Send + Sync + 'static) -> LongPressable<Self> {
72        LongPressable::new(self, f)
73    }
74}
75
76impl<W: Widget + Send + Sync + 'static> PressApi for W {}