interactive.rs

  1use gpui::{
  2    geometry::rect::RectF,
  3    platform::{MouseButton, MouseButtonEvent},
  4    EventContext,
  5};
  6use smallvec::SmallVec;
  7use std::{cell::Cell, rc::Rc};
  8
  9use crate::ViewContext;
 10
 11pub trait Interactive<V: 'static> {
 12    fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
 13
 14    fn on_mouse_down(
 15        mut self,
 16        button: MouseButton,
 17        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
 18    ) -> Self
 19    where
 20        Self: Sized,
 21    {
 22        self.interaction_handlers()
 23            .mouse_down
 24            .push(Rc::new(move |view, event, cx| {
 25                if event.button == button {
 26                    handler(view, event, cx)
 27                }
 28            }));
 29        self
 30    }
 31
 32    fn on_mouse_up(
 33        mut self,
 34        button: MouseButton,
 35        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
 36    ) -> Self
 37    where
 38        Self: Sized,
 39    {
 40        self.interaction_handlers()
 41            .mouse_up
 42            .push(Rc::new(move |view, event, cx| {
 43                if event.button == button {
 44                    handler(view, event, cx)
 45                }
 46            }));
 47        self
 48    }
 49
 50    fn on_mouse_down_out(
 51        mut self,
 52        button: MouseButton,
 53        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
 54    ) -> Self
 55    where
 56        Self: Sized,
 57    {
 58        self.interaction_handlers()
 59            .mouse_down_out
 60            .push(Rc::new(move |view, event, cx| {
 61                if event.button == button {
 62                    handler(view, event, cx)
 63                }
 64            }));
 65        self
 66    }
 67
 68    fn on_mouse_up_out(
 69        mut self,
 70        button: MouseButton,
 71        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
 72    ) -> Self
 73    where
 74        Self: Sized,
 75    {
 76        self.interaction_handlers()
 77            .mouse_up_out
 78            .push(Rc::new(move |view, event, cx| {
 79                if event.button == button {
 80                    handler(view, event, cx)
 81                }
 82            }));
 83        self
 84    }
 85
 86    fn on_click(
 87        self,
 88        button: MouseButton,
 89        handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
 90    ) -> Self
 91    where
 92        Self: Sized,
 93    {
 94        let pressed = Rc::new(Cell::new(false));
 95        self.on_mouse_down(button, {
 96            let pressed = pressed.clone();
 97            move |_, _, _| {
 98                pressed.set(true);
 99            }
100        })
101        .on_mouse_up_out(button, {
102            let pressed = pressed.clone();
103            move |_, _, _| {
104                pressed.set(false);
105            }
106        })
107        .on_mouse_up(button, move |view, event, cx| {
108            if pressed.get() {
109                pressed.set(false);
110                handler(view, event, cx);
111            }
112        })
113    }
114}
115
116pub struct InteractionHandlers<V: 'static> {
117    mouse_down: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
118    mouse_down_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
119    mouse_up: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
120    mouse_up_out: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
121}
122
123impl<V: 'static> InteractionHandlers<V> {
124    pub fn paint(&self, order: u32, bounds: RectF, cx: &mut ViewContext<V>) {
125        for handler in self.mouse_down.iter().cloned() {
126            cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
127                if event.is_down && bounds.contains_point(event.position) {
128                    handler(view, event, cx);
129                }
130            })
131        }
132        for handler in self.mouse_up.iter().cloned() {
133            cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
134                if !event.is_down && bounds.contains_point(event.position) {
135                    handler(view, event, cx);
136                }
137            })
138        }
139        for handler in self.mouse_down_out.iter().cloned() {
140            cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
141                if event.is_down && !bounds.contains_point(event.position) {
142                    handler(view, event, cx);
143                }
144            })
145        }
146        for handler in self.mouse_up_out.iter().cloned() {
147            cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
148                if !event.is_down && !bounds.contains_point(event.position) {
149                    handler(view, event, cx);
150                }
151            })
152        }
153    }
154}
155
156impl<V> Default for InteractionHandlers<V> {
157    fn default() -> Self {
158        Self {
159            mouse_down: Default::default(),
160            mouse_up: Default::default(),
161            mouse_down_out: Default::default(),
162            mouse_up_out: Default::default(),
163        }
164    }
165}