interactive.rs

   1use crate::{
   2    point, px, view, Action, AnyDrag, AppContext, BorrowWindow, Bounds, DispatchContext,
   3    DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, Modifiers, Overflow,
   4    Pixels, Point, SharedString, Size, Style, StyleRefinement, ViewContext,
   5};
   6use collections::HashMap;
   7use derive_more::{Deref, DerefMut};
   8use parking_lot::Mutex;
   9use refineable::Refineable;
  10use smallvec::SmallVec;
  11use std::{
  12    any::{Any, TypeId},
  13    fmt::Debug,
  14    marker::PhantomData,
  15    ops::Deref,
  16    sync::Arc,
  17};
  18
  19pub trait StatelessInteractive: Element {
  20    fn stateless_interactivity(&mut self) -> &mut StatelessInteraction<Self::ViewState>;
  21
  22    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
  23    where
  24        Self: Sized,
  25    {
  26        self.stateless_interactivity().hover_style = f(StyleRefinement::default());
  27        self
  28    }
  29
  30    fn group_hover(
  31        mut self,
  32        group_name: impl Into<SharedString>,
  33        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
  34    ) -> Self
  35    where
  36        Self: Sized,
  37    {
  38        self.stateless_interactivity().group_hover_style = Some(GroupStyle {
  39            group: group_name.into(),
  40            style: f(StyleRefinement::default()),
  41        });
  42        self
  43    }
  44
  45    fn on_mouse_down(
  46        mut self,
  47        button: MouseButton,
  48        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
  49            + Send
  50            + Sync
  51            + 'static,
  52    ) -> Self
  53    where
  54        Self: Sized,
  55    {
  56        self.stateless_interactivity()
  57            .mouse_down_listeners
  58            .push(Arc::new(move |view, event, bounds, phase, cx| {
  59                if phase == DispatchPhase::Bubble
  60                    && event.button == button
  61                    && bounds.contains_point(&event.position)
  62                {
  63                    handler(view, event, cx)
  64                }
  65            }));
  66        self
  67    }
  68
  69    fn on_mouse_up(
  70        mut self,
  71        button: MouseButton,
  72        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
  73            + Send
  74            + Sync
  75            + 'static,
  76    ) -> Self
  77    where
  78        Self: Sized,
  79    {
  80        self.stateless_interactivity()
  81            .mouse_up_listeners
  82            .push(Arc::new(move |view, event, bounds, phase, cx| {
  83                if phase == DispatchPhase::Bubble
  84                    && event.button == button
  85                    && bounds.contains_point(&event.position)
  86                {
  87                    handler(view, event, cx)
  88                }
  89            }));
  90        self
  91    }
  92
  93    fn on_mouse_down_out(
  94        mut self,
  95        button: MouseButton,
  96        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
  97            + Send
  98            + Sync
  99            + 'static,
 100    ) -> Self
 101    where
 102        Self: Sized,
 103    {
 104        self.stateless_interactivity()
 105            .mouse_down_listeners
 106            .push(Arc::new(move |view, event, bounds, phase, cx| {
 107                if phase == DispatchPhase::Capture
 108                    && event.button == button
 109                    && !bounds.contains_point(&event.position)
 110                {
 111                    handler(view, event, cx)
 112                }
 113            }));
 114        self
 115    }
 116
 117    fn on_mouse_up_out(
 118        mut self,
 119        button: MouseButton,
 120        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
 121            + Send
 122            + Sync
 123            + 'static,
 124    ) -> Self
 125    where
 126        Self: Sized,
 127    {
 128        self.stateless_interactivity()
 129            .mouse_up_listeners
 130            .push(Arc::new(move |view, event, bounds, phase, cx| {
 131                if phase == DispatchPhase::Capture
 132                    && event.button == button
 133                    && !bounds.contains_point(&event.position)
 134                {
 135                    handler(view, event, cx);
 136                }
 137            }));
 138        self
 139    }
 140
 141    fn on_mouse_move(
 142        mut self,
 143        handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
 144            + Send
 145            + Sync
 146            + 'static,
 147    ) -> Self
 148    where
 149        Self: Sized,
 150    {
 151        self.stateless_interactivity()
 152            .mouse_move_listeners
 153            .push(Arc::new(move |view, event, bounds, phase, cx| {
 154                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 155                    handler(view, event, cx);
 156                }
 157            }));
 158        self
 159    }
 160
 161    fn on_scroll_wheel(
 162        mut self,
 163        handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
 164            + Send
 165            + Sync
 166            + 'static,
 167    ) -> Self
 168    where
 169        Self: Sized,
 170    {
 171        self.stateless_interactivity()
 172            .scroll_wheel_listeners
 173            .push(Arc::new(move |view, event, bounds, phase, cx| {
 174                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 175                    handler(view, event, cx);
 176                }
 177            }));
 178        self
 179    }
 180
 181    fn context<C>(mut self, context: C) -> Self
 182    where
 183        Self: Sized,
 184        C: TryInto<DispatchContext>,
 185        C::Error: Debug,
 186    {
 187        self.stateless_interactivity().dispatch_context =
 188            context.try_into().expect("invalid dispatch context");
 189        self
 190    }
 191
 192    fn on_action<A: 'static>(
 193        mut self,
 194        listener: impl Fn(&mut Self::ViewState, &A, DispatchPhase, &mut ViewContext<Self::ViewState>)
 195            + Send
 196            + Sync
 197            + 'static,
 198    ) -> Self
 199    where
 200        Self: Sized,
 201    {
 202        self.stateless_interactivity().key_listeners.push((
 203            TypeId::of::<A>(),
 204            Arc::new(move |view, event, _, phase, cx| {
 205                let event = event.downcast_ref().unwrap();
 206                listener(view, event, phase, cx);
 207                None
 208            }),
 209        ));
 210        self
 211    }
 212
 213    fn on_key_down(
 214        mut self,
 215        listener: impl Fn(
 216                &mut Self::ViewState,
 217                &KeyDownEvent,
 218                DispatchPhase,
 219                &mut ViewContext<Self::ViewState>,
 220            ) + Send
 221            + Sync
 222            + 'static,
 223    ) -> Self
 224    where
 225        Self: Sized,
 226    {
 227        self.stateless_interactivity().key_listeners.push((
 228            TypeId::of::<KeyDownEvent>(),
 229            Arc::new(move |view, event, _, phase, cx| {
 230                let event = event.downcast_ref().unwrap();
 231                listener(view, event, phase, cx);
 232                None
 233            }),
 234        ));
 235        self
 236    }
 237
 238    fn on_key_up(
 239        mut self,
 240        listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
 241            + Send
 242            + Sync
 243            + 'static,
 244    ) -> Self
 245    where
 246        Self: Sized,
 247    {
 248        self.stateless_interactivity().key_listeners.push((
 249            TypeId::of::<KeyUpEvent>(),
 250            Arc::new(move |view, event, _, phase, cx| {
 251                let event = event.downcast_ref().unwrap();
 252                listener(view, event, phase, cx);
 253                None
 254            }),
 255        ));
 256        self
 257    }
 258}
 259
 260pub trait StatefulInteractive: StatelessInteractive {
 261    fn stateful_interaction(&mut self) -> &mut StatefulInteraction<Self::ViewState>;
 262
 263    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 264    where
 265        Self: Sized,
 266    {
 267        self.stateful_interaction().active_style = f(StyleRefinement::default());
 268        self
 269    }
 270
 271    fn group_active(
 272        mut self,
 273        group_name: impl Into<SharedString>,
 274        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 275    ) -> Self
 276    where
 277        Self: Sized,
 278    {
 279        self.stateful_interaction().group_active_style = Some(GroupStyle {
 280            group: group_name.into(),
 281            style: f(StyleRefinement::default()),
 282        });
 283        self
 284    }
 285
 286    fn on_click(
 287        mut self,
 288        listener: impl Fn(&mut Self::ViewState, &ClickEvent, &mut ViewContext<Self::ViewState>)
 289            + Send
 290            + Sync
 291            + 'static,
 292    ) -> Self
 293    where
 294        Self: Sized,
 295    {
 296        self.stateful_interaction()
 297            .click_listeners
 298            .push(Arc::new(move |view, event, cx| listener(view, event, cx)));
 299        self
 300    }
 301
 302    fn on_drag<S, R, E>(
 303        mut self,
 304        listener: impl Fn(
 305                &mut Self::ViewState,
 306                &mut ViewContext<Self::ViewState>,
 307            ) -> Drag<S, R, Self::ViewState, E>
 308            + Send
 309            + Sync
 310            + 'static,
 311    ) -> Self
 312    where
 313        Self: Sized,
 314        S: 'static + Send + Sync,
 315        R: 'static + Fn(&mut Self::ViewState, &mut ViewContext<Self::ViewState>) -> E + Send + Sync,
 316        E: Element<ViewState = Self::ViewState>,
 317    {
 318        debug_assert!(
 319            self.stateful_interaction().drag_listener.is_none(),
 320            "calling on_drag more than once on the same element is not supported"
 321        );
 322        self.stateful_interaction().drag_listener =
 323            Some(Arc::new(move |view_state, cursor_offset, cx| {
 324                let drag = listener(view_state, cx);
 325                let view_handle = cx.handle().upgrade().unwrap();
 326                let drag_handle_view = view(view_handle, move |view_state, cx| {
 327                    (drag.render_drag_handle)(view_state, cx)
 328                })
 329                .into_any();
 330                AnyDrag {
 331                    drag_handle_view,
 332                    cursor_offset,
 333                    state: Box::new(drag.state),
 334                    state_type: TypeId::of::<S>(),
 335                }
 336            }));
 337        self
 338    }
 339}
 340
 341pub trait ElementInteraction<V: 'static + Send + Sync>: 'static + Send + Sync {
 342    fn as_stateless(&self) -> &StatelessInteraction<V>;
 343    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V>;
 344    fn as_stateful(&self) -> Option<&StatefulInteraction<V>>;
 345    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>>;
 346
 347    fn initialize<R>(
 348        &mut self,
 349        cx: &mut ViewContext<V>,
 350        f: impl FnOnce(&mut ViewContext<V>) -> R,
 351    ) -> R {
 352        if let Some(stateful) = self.as_stateful_mut() {
 353            cx.with_element_id(stateful.id.clone(), |global_id, cx| {
 354                stateful.key_listeners.push((
 355                    TypeId::of::<KeyDownEvent>(),
 356                    Arc::new(move |_, key_down, context, phase, cx| {
 357                        if phase == DispatchPhase::Bubble {
 358                            let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
 359                            if let KeyMatch::Some(action) =
 360                                cx.match_keystroke(&global_id, &key_down.keystroke, context)
 361                            {
 362                                return Some(action);
 363                            }
 364                        }
 365
 366                        None
 367                    }),
 368                ));
 369                let result = stateful.stateless.initialize(cx, f);
 370                stateful.key_listeners.pop();
 371                result
 372            })
 373        } else {
 374            let stateless = self.as_stateless();
 375            cx.with_key_dispatch_context(stateless.dispatch_context.clone(), |cx| {
 376                cx.with_key_listeners(&stateless.key_listeners, f)
 377            })
 378        }
 379    }
 380
 381    fn refine_style(
 382        &self,
 383        style: &mut Style,
 384        bounds: Bounds<Pixels>,
 385        element_state: &InteractiveElementState,
 386        cx: &mut ViewContext<V>,
 387    ) {
 388        let mouse_position = cx.mouse_position();
 389        let stateless = self.as_stateless();
 390        if let Some(group_hover) = stateless.group_hover_style.as_ref() {
 391            if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
 392                if group_bounds.contains_point(&mouse_position) {
 393                    style.refine(&group_hover.style);
 394                }
 395            }
 396        }
 397        if bounds.contains_point(&mouse_position) {
 398            style.refine(&stateless.hover_style);
 399        }
 400
 401        if let Some(stateful) = self.as_stateful() {
 402            let active_state = element_state.active_state.lock();
 403            if active_state.group {
 404                if let Some(group_style) = stateful.group_active_style.as_ref() {
 405                    style.refine(&group_style.style);
 406                }
 407            }
 408            if active_state.element {
 409                style.refine(&stateful.active_style);
 410            }
 411        }
 412    }
 413
 414    fn paint(
 415        &mut self,
 416        bounds: Bounds<Pixels>,
 417        content_size: Size<Pixels>,
 418        overflow: Point<Overflow>,
 419        element_state: &mut InteractiveElementState,
 420        cx: &mut ViewContext<V>,
 421    ) {
 422        let stateless = self.as_stateless();
 423        for listener in stateless.mouse_down_listeners.iter().cloned() {
 424            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
 425                listener(state, event, &bounds, phase, cx);
 426            })
 427        }
 428
 429        for listener in stateless.mouse_up_listeners.iter().cloned() {
 430            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
 431                listener(state, event, &bounds, phase, cx);
 432            })
 433        }
 434
 435        for listener in stateless.mouse_move_listeners.iter().cloned() {
 436            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
 437                listener(state, event, &bounds, phase, cx);
 438            })
 439        }
 440
 441        for listener in stateless.scroll_wheel_listeners.iter().cloned() {
 442            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
 443                listener(state, event, &bounds, phase, cx);
 444            })
 445        }
 446
 447        let hover_group_bounds = stateless
 448            .group_hover_style
 449            .as_ref()
 450            .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
 451
 452        if let Some(group_bounds) = hover_group_bounds {
 453            paint_hover_listener(group_bounds, cx);
 454        }
 455
 456        if stateless.hover_style.is_some() {
 457            paint_hover_listener(bounds, cx);
 458        }
 459
 460        if let Some(stateful) = self.as_stateful() {
 461            let click_listeners = stateful.click_listeners.clone();
 462            let drag_listener = stateful.drag_listener.clone();
 463
 464            if !click_listeners.is_empty() || drag_listener.is_some() {
 465                let pending_mouse_down = element_state.pending_mouse_down.clone();
 466                let mouse_down = pending_mouse_down.lock().clone();
 467                if let Some(mouse_down) = mouse_down {
 468                    if let Some(drag_listener) = drag_listener {
 469                        cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
 470                            if cx.active_drag.is_some() {
 471                                if phase == DispatchPhase::Capture {
 472                                    cx.notify();
 473                                }
 474                            } else if phase == DispatchPhase::Bubble
 475                                && bounds.contains_point(&event.position)
 476                            {
 477                                let cursor_offset = event.position - bounds.origin;
 478                                let any_drag = drag_listener(view_state, cursor_offset, cx);
 479                                cx.start_drag(any_drag);
 480                                cx.stop_propagation();
 481                            }
 482                        });
 483                    }
 484
 485                    cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
 486                        if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
 487                        {
 488                            let mouse_click = ClickEvent {
 489                                down: mouse_down.clone(),
 490                                up: event.clone(),
 491                            };
 492                            for listener in &click_listeners {
 493                                listener(view_state, &mouse_click, cx);
 494                            }
 495                        }
 496
 497                        if cx.active_drag.is_some() {
 498                            cx.end_drag();
 499                        }
 500                        *pending_mouse_down.lock() = None;
 501                    });
 502                } else {
 503                    cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
 504                        if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
 505                        {
 506                            *pending_mouse_down.lock() = Some(event.clone());
 507                        }
 508                    });
 509                }
 510            }
 511
 512            let active_state = element_state.active_state.clone();
 513            if active_state.lock().is_none() {
 514                let active_group_bounds = stateful
 515                    .group_active_style
 516                    .as_ref()
 517                    .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
 518                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
 519                    if phase == DispatchPhase::Bubble {
 520                        let group = active_group_bounds
 521                            .map_or(false, |bounds| bounds.contains_point(&down.position));
 522                        let element = bounds.contains_point(&down.position);
 523                        if group || element {
 524                            *active_state.lock() = ActiveState { group, element };
 525                            cx.notify();
 526                        }
 527                    }
 528                });
 529            } else {
 530                cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
 531                    if phase == DispatchPhase::Capture {
 532                        *active_state.lock() = ActiveState::default();
 533                        cx.notify();
 534                    }
 535                });
 536            }
 537
 538            if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
 539                let scroll_offset = element_state
 540                    .scroll_offset
 541                    .get_or_insert_with(Arc::default)
 542                    .clone();
 543                let line_height = cx.line_height();
 544                let scroll_max = (content_size - bounds.size).max(&Size::default());
 545
 546                cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
 547                    if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
 548                        let mut scroll_offset = scroll_offset.lock();
 549                        let old_scroll_offset = *scroll_offset;
 550                        let delta = event.delta.pixel_delta(line_height);
 551
 552                        if overflow.x == Overflow::Scroll {
 553                            scroll_offset.x =
 554                                (scroll_offset.x + delta.x).clamp(-scroll_max.width, px(0.));
 555                        }
 556
 557                        if overflow.y == Overflow::Scroll {
 558                            scroll_offset.y =
 559                                (scroll_offset.y + delta.y).clamp(-scroll_max.height, px(0.));
 560                        }
 561
 562                        if *scroll_offset != old_scroll_offset {
 563                            cx.notify();
 564                            cx.stop_propagation();
 565                        }
 566                    }
 567                });
 568            }
 569        }
 570    }
 571}
 572
 573fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
 574where
 575    V: 'static + Send + Sync,
 576{
 577    let hovered = bounds.contains_point(&cx.mouse_position());
 578    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
 579        if phase == DispatchPhase::Capture {
 580            if bounds.contains_point(&event.position) != hovered {
 581                cx.notify();
 582            }
 583        }
 584    });
 585}
 586
 587#[derive(Deref, DerefMut)]
 588pub struct StatefulInteraction<V: 'static + Send + Sync> {
 589    pub id: ElementId,
 590    #[deref]
 591    #[deref_mut]
 592    stateless: StatelessInteraction<V>,
 593    pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
 594    pub(crate) drag_listener: Option<DragListener<V>>,
 595    pub active_style: StyleRefinement,
 596    pub group_active_style: Option<GroupStyle>,
 597}
 598
 599impl<V> ElementInteraction<V> for StatefulInteraction<V>
 600where
 601    V: 'static + Send + Sync,
 602{
 603    fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
 604        Some(self)
 605    }
 606
 607    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
 608        Some(self)
 609    }
 610
 611    fn as_stateless(&self) -> &StatelessInteraction<V> {
 612        &self.stateless
 613    }
 614
 615    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
 616        &mut self.stateless
 617    }
 618}
 619
 620impl<V> From<ElementId> for StatefulInteraction<V>
 621where
 622    V: 'static + Send + Sync,
 623{
 624    fn from(id: ElementId) -> Self {
 625        Self {
 626            id,
 627            stateless: StatelessInteraction::default(),
 628            click_listeners: SmallVec::new(),
 629            drag_listener: None,
 630            active_style: StyleRefinement::default(),
 631            group_active_style: None,
 632        }
 633    }
 634}
 635
 636pub struct StatelessInteraction<V> {
 637    pub dispatch_context: DispatchContext,
 638    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
 639    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
 640    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
 641    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
 642    pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
 643    pub hover_style: StyleRefinement,
 644    pub group_hover_style: Option<GroupStyle>,
 645}
 646
 647impl<V> StatelessInteraction<V>
 648where
 649    V: 'static + Send + Sync,
 650{
 651    pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteraction<V> {
 652        StatefulInteraction {
 653            id: id.into(),
 654            stateless: self,
 655            click_listeners: SmallVec::new(),
 656            drag_listener: None,
 657            active_style: StyleRefinement::default(),
 658            group_active_style: None,
 659        }
 660    }
 661}
 662
 663pub struct GroupStyle {
 664    pub group: SharedString,
 665    pub style: StyleRefinement,
 666}
 667
 668#[derive(Default)]
 669pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
 670
 671impl GroupBounds {
 672    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
 673        cx.default_global_mut::<Self>()
 674            .0
 675            .get(name)
 676            .and_then(|bounds_stack| bounds_stack.last())
 677            .cloned()
 678    }
 679
 680    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
 681        cx.default_global_mut::<Self>()
 682            .0
 683            .entry(name)
 684            .or_default()
 685            .push(bounds);
 686    }
 687
 688    pub fn pop(name: &SharedString, cx: &mut AppContext) {
 689        cx.default_global_mut::<Self>()
 690            .0
 691            .get_mut(name)
 692            .unwrap()
 693            .pop();
 694    }
 695}
 696
 697#[derive(Copy, Clone, Default, Eq, PartialEq)]
 698struct ActiveState {
 699    pub group: bool,
 700    pub element: bool,
 701}
 702
 703impl ActiveState {
 704    pub fn is_none(&self) -> bool {
 705        !self.group && !self.element
 706    }
 707}
 708
 709#[derive(Default)]
 710pub struct InteractiveElementState {
 711    active_state: Arc<Mutex<ActiveState>>,
 712    pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
 713    scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
 714}
 715
 716impl InteractiveElementState {
 717    pub fn scroll_offset(&self) -> Option<Point<Pixels>> {
 718        self.scroll_offset
 719            .as_ref()
 720            .map(|offset| offset.lock().clone())
 721    }
 722}
 723
 724impl<V> Default for StatelessInteraction<V> {
 725    fn default() -> Self {
 726        Self {
 727            dispatch_context: DispatchContext::default(),
 728            mouse_down_listeners: SmallVec::new(),
 729            mouse_up_listeners: SmallVec::new(),
 730            mouse_move_listeners: SmallVec::new(),
 731            scroll_wheel_listeners: SmallVec::new(),
 732            key_listeners: SmallVec::new(),
 733            hover_style: StyleRefinement::default(),
 734            group_hover_style: None,
 735        }
 736    }
 737}
 738
 739impl<V> ElementInteraction<V> for StatelessInteraction<V>
 740where
 741    V: 'static + Send + Sync,
 742{
 743    fn as_stateful(&self) -> Option<&StatefulInteraction<V>> {
 744        None
 745    }
 746
 747    fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteraction<V>> {
 748        None
 749    }
 750
 751    fn as_stateless(&self) -> &StatelessInteraction<V> {
 752        self
 753    }
 754
 755    fn as_stateless_mut(&mut self) -> &mut StatelessInteraction<V> {
 756        self
 757    }
 758}
 759
 760#[derive(Clone, Debug, Eq, PartialEq)]
 761pub struct KeyDownEvent {
 762    pub keystroke: Keystroke,
 763    pub is_held: bool,
 764}
 765
 766#[derive(Clone, Debug)]
 767pub struct KeyUpEvent {
 768    pub keystroke: Keystroke,
 769}
 770
 771#[derive(Clone, Debug, Default)]
 772pub struct ModifiersChangedEvent {
 773    pub modifiers: Modifiers,
 774}
 775
 776impl Deref for ModifiersChangedEvent {
 777    type Target = Modifiers;
 778
 779    fn deref(&self) -> &Self::Target {
 780        &self.modifiers
 781    }
 782}
 783
 784/// The phase of a touch motion event.
 785/// Based on the winit enum of the same name.
 786#[derive(Clone, Copy, Debug)]
 787pub enum TouchPhase {
 788    Started,
 789    Moved,
 790    Ended,
 791}
 792
 793#[derive(Clone, Debug, Default)]
 794pub struct MouseDownEvent {
 795    pub button: MouseButton,
 796    pub position: Point<Pixels>,
 797    pub modifiers: Modifiers,
 798    pub click_count: usize,
 799}
 800
 801#[derive(Clone, Debug, Default)]
 802pub struct MouseUpEvent {
 803    pub button: MouseButton,
 804    pub position: Point<Pixels>,
 805    pub modifiers: Modifiers,
 806    pub click_count: usize,
 807}
 808
 809#[derive(Clone, Debug, Default)]
 810pub struct ClickEvent {
 811    pub down: MouseDownEvent,
 812    pub up: MouseUpEvent,
 813}
 814
 815pub struct Drag<S, R, V, E>
 816where
 817    S: 'static + Send + Sync,
 818    R: Fn(&mut V, &mut ViewContext<V>) -> E,
 819    V: 'static + Send + Sync,
 820    E: Element<ViewState = V>,
 821{
 822    pub state: S,
 823    pub render_drag_handle: R,
 824    view_type: PhantomData<V>,
 825}
 826
 827impl<S, R, V, E> Drag<S, R, V, E>
 828where
 829    S: 'static + Send + Sync,
 830    R: Fn(&mut V, &mut ViewContext<V>) -> E + Send + Sync,
 831    V: 'static + Send + Sync,
 832    E: Element<ViewState = V>,
 833{
 834    pub fn new(state: S, render_drag_handle: R) -> Self {
 835        Drag {
 836            state,
 837            render_drag_handle,
 838            view_type: PhantomData,
 839        }
 840    }
 841}
 842
 843#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 844pub enum MouseButton {
 845    Left,
 846    Right,
 847    Middle,
 848    Navigate(NavigationDirection),
 849}
 850
 851impl MouseButton {
 852    pub fn all() -> Vec<Self> {
 853        vec![
 854            MouseButton::Left,
 855            MouseButton::Right,
 856            MouseButton::Middle,
 857            MouseButton::Navigate(NavigationDirection::Back),
 858            MouseButton::Navigate(NavigationDirection::Forward),
 859        ]
 860    }
 861}
 862
 863impl Default for MouseButton {
 864    fn default() -> Self {
 865        Self::Left
 866    }
 867}
 868
 869#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 870pub enum NavigationDirection {
 871    Back,
 872    Forward,
 873}
 874
 875impl Default for NavigationDirection {
 876    fn default() -> Self {
 877        Self::Back
 878    }
 879}
 880
 881#[derive(Clone, Debug, Default)]
 882pub struct MouseMoveEvent {
 883    pub position: Point<Pixels>,
 884    pub pressed_button: Option<MouseButton>,
 885    pub modifiers: Modifiers,
 886}
 887
 888#[derive(Clone, Debug)]
 889pub struct ScrollWheelEvent {
 890    pub position: Point<Pixels>,
 891    pub delta: ScrollDelta,
 892    pub modifiers: Modifiers,
 893    pub touch_phase: TouchPhase,
 894}
 895
 896impl Deref for ScrollWheelEvent {
 897    type Target = Modifiers;
 898
 899    fn deref(&self) -> &Self::Target {
 900        &self.modifiers
 901    }
 902}
 903
 904#[derive(Clone, Copy, Debug)]
 905pub enum ScrollDelta {
 906    Pixels(Point<Pixels>),
 907    Lines(Point<f32>),
 908}
 909
 910impl Default for ScrollDelta {
 911    fn default() -> Self {
 912        Self::Lines(Default::default())
 913    }
 914}
 915
 916impl ScrollDelta {
 917    pub fn precise(&self) -> bool {
 918        match self {
 919            ScrollDelta::Pixels(_) => true,
 920            ScrollDelta::Lines(_) => false,
 921        }
 922    }
 923
 924    pub fn pixel_delta(&self, line_height: Pixels) -> Point<Pixels> {
 925        match self {
 926            ScrollDelta::Pixels(delta) => *delta,
 927            ScrollDelta::Lines(delta) => point(line_height * delta.x, line_height * delta.y),
 928        }
 929    }
 930}
 931
 932#[derive(Clone, Debug, Default)]
 933pub struct MouseExitEvent {
 934    pub position: Point<Pixels>,
 935    pub pressed_button: Option<MouseButton>,
 936    pub modifiers: Modifiers,
 937}
 938
 939impl Deref for MouseExitEvent {
 940    type Target = Modifiers;
 941
 942    fn deref(&self) -> &Self::Target {
 943        &self.modifiers
 944    }
 945}
 946
 947#[derive(Clone, Debug)]
 948pub enum InputEvent {
 949    KeyDown(KeyDownEvent),
 950    KeyUp(KeyUpEvent),
 951    ModifiersChanged(ModifiersChangedEvent),
 952    MouseDown(MouseDownEvent),
 953    MouseUp(MouseUpEvent),
 954    MouseMoved(MouseMoveEvent),
 955    MouseExited(MouseExitEvent),
 956    ScrollWheel(ScrollWheelEvent),
 957}
 958
 959impl InputEvent {
 960    pub fn position(&self) -> Option<Point<Pixels>> {
 961        match self {
 962            InputEvent::KeyDown { .. } => None,
 963            InputEvent::KeyUp { .. } => None,
 964            InputEvent::ModifiersChanged { .. } => None,
 965            InputEvent::MouseDown(event) => Some(event.position),
 966            InputEvent::MouseUp(event) => Some(event.position),
 967            InputEvent::MouseMoved(event) => Some(event.position),
 968            InputEvent::MouseExited(event) => Some(event.position),
 969            InputEvent::ScrollWheel(event) => Some(event.position),
 970        }
 971    }
 972
 973    pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
 974        match self {
 975            InputEvent::KeyDown { .. } => None,
 976            InputEvent::KeyUp { .. } => None,
 977            InputEvent::ModifiersChanged { .. } => None,
 978            InputEvent::MouseDown(event) => Some(event),
 979            InputEvent::MouseUp(event) => Some(event),
 980            InputEvent::MouseMoved(event) => Some(event),
 981            InputEvent::MouseExited(event) => Some(event),
 982            InputEvent::ScrollWheel(event) => Some(event),
 983        }
 984    }
 985
 986    pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
 987        match self {
 988            InputEvent::KeyDown(event) => Some(event),
 989            InputEvent::KeyUp(event) => Some(event),
 990            InputEvent::ModifiersChanged(event) => Some(event),
 991            InputEvent::MouseDown(_) => None,
 992            InputEvent::MouseUp(_) => None,
 993            InputEvent::MouseMoved(_) => None,
 994            InputEvent::MouseExited(_) => None,
 995            InputEvent::ScrollWheel(_) => None,
 996        }
 997    }
 998}
 999
1000pub struct FocusEvent {
1001    pub blurred: Option<FocusHandle>,
1002    pub focused: Option<FocusHandle>,
1003}
1004
1005pub type MouseDownListener<V> = Arc<
1006    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1007        + Send
1008        + Sync
1009        + 'static,
1010>;
1011pub type MouseUpListener<V> = Arc<
1012    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1013        + Send
1014        + Sync
1015        + 'static,
1016>;
1017
1018pub type MouseMoveListener<V> = Arc<
1019    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1020        + Send
1021        + Sync
1022        + 'static,
1023>;
1024
1025pub type ScrollWheelListener<V> = Arc<
1026    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
1027        + Send
1028        + Sync
1029        + 'static,
1030>;
1031
1032pub type ClickListener<V> =
1033    Arc<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
1034
1035pub(crate) type DragListener<V> =
1036    Arc<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + Send + Sync + 'static>;
1037
1038pub type KeyListener<V> = Arc<
1039    dyn Fn(
1040            &mut V,
1041            &dyn Any,
1042            &[&DispatchContext],
1043            DispatchPhase,
1044            &mut ViewContext<V>,
1045        ) -> Option<Box<dyn Action>>
1046        + Send
1047        + Sync
1048        + 'static,
1049>;