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