div.rs

   1use crate::{
   2    point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
   3    BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, IntoElement,
   4    KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
   5    MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size,
   6    StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
   7};
   8
   9use collections::HashMap;
  10use refineable::Refineable;
  11use smallvec::SmallVec;
  12use std::{
  13    any::{Any, TypeId},
  14    cell::RefCell,
  15    cmp::Ordering,
  16    fmt::Debug,
  17    marker::PhantomData,
  18    mem,
  19    rc::Rc,
  20    time::Duration,
  21};
  22use taffy::style::Overflow;
  23use util::ResultExt;
  24
  25const DRAG_THRESHOLD: f64 = 2.;
  26const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
  27
  28pub struct GroupStyle {
  29    pub group: SharedString,
  30    pub style: Box<StyleRefinement>,
  31}
  32
  33pub struct DragMoveEvent<T> {
  34    pub event: MouseMoveEvent,
  35    pub bounds: Bounds<Pixels>,
  36    drag: PhantomData<T>,
  37}
  38
  39impl<T: 'static> DragMoveEvent<T> {
  40    pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T {
  41        cx.active_drag
  42            .as_ref()
  43            .and_then(|drag| drag.value.downcast_ref::<T>())
  44            .expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
  45    }
  46}
  47
  48impl Interactivity {
  49    pub fn on_mouse_down(
  50        &mut self,
  51        button: MouseButton,
  52        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  53    ) {
  54        self.mouse_down_listeners
  55            .push(Box::new(move |event, bounds, phase, cx| {
  56                if phase == DispatchPhase::Bubble
  57                    && event.button == button
  58                    && bounds.visibly_contains(&event.position, cx)
  59                {
  60                    (listener)(event, cx)
  61                }
  62            }));
  63    }
  64
  65    pub fn capture_any_mouse_down(
  66        &mut self,
  67        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  68    ) {
  69        self.mouse_down_listeners
  70            .push(Box::new(move |event, bounds, phase, cx| {
  71                if phase == DispatchPhase::Capture && bounds.visibly_contains(&event.position, cx) {
  72                    (listener)(event, cx)
  73                }
  74            }));
  75    }
  76
  77    pub fn on_any_mouse_down(
  78        &mut self,
  79        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
  80    ) {
  81        self.mouse_down_listeners
  82            .push(Box::new(move |event, bounds, phase, cx| {
  83                if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
  84                    (listener)(event, cx)
  85                }
  86            }));
  87    }
  88
  89    pub fn on_mouse_up(
  90        &mut self,
  91        button: MouseButton,
  92        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
  93    ) {
  94        self.mouse_up_listeners
  95            .push(Box::new(move |event, bounds, phase, cx| {
  96                if phase == DispatchPhase::Bubble
  97                    && event.button == button
  98                    && bounds.visibly_contains(&event.position, cx)
  99                {
 100                    (listener)(event, cx)
 101                }
 102            }));
 103    }
 104
 105    pub fn capture_any_mouse_up(
 106        &mut self,
 107        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 108    ) {
 109        self.mouse_up_listeners
 110            .push(Box::new(move |event, bounds, phase, cx| {
 111                if phase == DispatchPhase::Capture && bounds.visibly_contains(&event.position, cx) {
 112                    (listener)(event, cx)
 113                }
 114            }));
 115    }
 116
 117    pub fn on_any_mouse_up(
 118        &mut self,
 119        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 120    ) {
 121        self.mouse_up_listeners
 122            .push(Box::new(move |event, bounds, phase, cx| {
 123                if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
 124                    (listener)(event, cx)
 125                }
 126            }));
 127    }
 128
 129    pub fn on_mouse_down_out(
 130        &mut self,
 131        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 132    ) {
 133        self.mouse_down_listeners
 134            .push(Box::new(move |event, bounds, phase, cx| {
 135                if phase == DispatchPhase::Capture && !bounds.visibly_contains(&event.position, cx)
 136                {
 137                    (listener)(event, cx)
 138                }
 139            }));
 140    }
 141
 142    pub fn on_mouse_up_out(
 143        &mut self,
 144        button: MouseButton,
 145        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 146    ) {
 147        self.mouse_up_listeners
 148            .push(Box::new(move |event, bounds, phase, cx| {
 149                if phase == DispatchPhase::Capture
 150                    && event.button == button
 151                    && !bounds.visibly_contains(&event.position, cx)
 152                {
 153                    (listener)(event, cx);
 154                }
 155            }));
 156    }
 157
 158    pub fn on_mouse_move(
 159        &mut self,
 160        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 161    ) {
 162        self.mouse_move_listeners
 163            .push(Box::new(move |event, bounds, phase, cx| {
 164                if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
 165                    (listener)(event, cx);
 166                }
 167            }));
 168    }
 169
 170    pub fn on_drag_move<T>(
 171        &mut self,
 172        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 173    ) where
 174        T: 'static,
 175    {
 176        self.mouse_move_listeners
 177            .push(Box::new(move |event, bounds, phase, cx| {
 178                if phase == DispatchPhase::Capture {
 179                    if cx
 180                        .active_drag
 181                        .as_ref()
 182                        .is_some_and(|drag| drag.value.as_ref().type_id() == TypeId::of::<T>())
 183                    {
 184                        (listener)(
 185                            &DragMoveEvent {
 186                                event: event.clone(),
 187                                bounds: bounds.bounds,
 188                                drag: PhantomData,
 189                            },
 190                            cx,
 191                        );
 192                    }
 193                }
 194            }));
 195    }
 196
 197    pub fn on_scroll_wheel(
 198        &mut self,
 199        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 200    ) {
 201        self.scroll_wheel_listeners
 202            .push(Box::new(move |event, bounds, phase, cx| {
 203                if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
 204                    (listener)(event, cx);
 205                }
 206            }));
 207    }
 208
 209    pub fn capture_action<A: Action>(
 210        &mut self,
 211        listener: impl Fn(&A, &mut WindowContext) + 'static,
 212    ) {
 213        self.action_listeners.push((
 214            TypeId::of::<A>(),
 215            Box::new(move |action, phase, cx| {
 216                let action = action.downcast_ref().unwrap();
 217                if phase == DispatchPhase::Capture {
 218                    (listener)(action, cx)
 219                }
 220            }),
 221        ));
 222    }
 223
 224    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) {
 225        self.action_listeners.push((
 226            TypeId::of::<A>(),
 227            Box::new(move |action, phase, cx| {
 228                let action = action.downcast_ref().unwrap();
 229                if phase == DispatchPhase::Bubble {
 230                    (listener)(action, cx)
 231                }
 232            }),
 233        ));
 234    }
 235
 236    pub fn on_boxed_action(
 237        &mut self,
 238        action: &Box<dyn Action>,
 239        listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
 240    ) {
 241        let action = action.boxed_clone();
 242        self.action_listeners.push((
 243            (*action).type_id(),
 244            Box::new(move |_, phase, cx| {
 245                if phase == DispatchPhase::Bubble {
 246                    (listener)(&action, cx)
 247                }
 248            }),
 249        ));
 250    }
 251
 252    pub fn on_key_down(&mut self, listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static) {
 253        self.key_down_listeners
 254            .push(Box::new(move |event, phase, cx| {
 255                if phase == DispatchPhase::Bubble {
 256                    (listener)(event, cx)
 257                }
 258            }));
 259    }
 260
 261    pub fn capture_key_down(
 262        &mut self,
 263        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 264    ) {
 265        self.key_down_listeners
 266            .push(Box::new(move |event, phase, cx| {
 267                if phase == DispatchPhase::Capture {
 268                    listener(event, cx)
 269                }
 270            }));
 271    }
 272
 273    pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 274        self.key_up_listeners
 275            .push(Box::new(move |event, phase, cx| {
 276                if phase == DispatchPhase::Bubble {
 277                    listener(event, cx)
 278                }
 279            }));
 280    }
 281
 282    pub fn capture_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
 283        self.key_up_listeners
 284            .push(Box::new(move |event, phase, cx| {
 285                if phase == DispatchPhase::Capture {
 286                    listener(event, cx)
 287                }
 288            }));
 289    }
 290
 291    pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
 292        self.drop_listeners.push((
 293            TypeId::of::<T>(),
 294            Box::new(move |dragged_value, cx| {
 295                listener(dragged_value.downcast_ref().unwrap(), cx);
 296            }),
 297        ));
 298    }
 299
 300    pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
 301    where
 302        Self: Sized,
 303    {
 304        self.click_listeners
 305            .push(Box::new(move |event, cx| listener(event, cx)));
 306    }
 307
 308    pub fn on_drag<T, W>(
 309        &mut self,
 310        value: T,
 311        constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
 312    ) where
 313        Self: Sized,
 314        T: 'static,
 315        W: 'static + Render,
 316    {
 317        debug_assert!(
 318            self.drag_listener.is_none(),
 319            "calling on_drag more than once on the same element is not supported"
 320        );
 321        self.drag_listener = Some((
 322            Box::new(value),
 323            Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()),
 324        ));
 325    }
 326
 327    pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
 328    where
 329        Self: Sized,
 330    {
 331        debug_assert!(
 332            self.hover_listener.is_none(),
 333            "calling on_hover more than once on the same element is not supported"
 334        );
 335        self.hover_listener = Some(Box::new(listener));
 336    }
 337
 338    pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static)
 339    where
 340        Self: Sized,
 341    {
 342        debug_assert!(
 343            self.tooltip_builder.is_none(),
 344            "calling tooltip more than once on the same element is not supported"
 345        );
 346        self.tooltip_builder = Some(Rc::new(build_tooltip));
 347    }
 348}
 349
 350pub trait InteractiveElement: Sized {
 351    fn interactivity(&mut self) -> &mut Interactivity;
 352
 353    fn group(mut self, group: impl Into<SharedString>) -> Self {
 354        self.interactivity().group = Some(group.into());
 355        self
 356    }
 357
 358    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
 359        self.interactivity().element_id = Some(id.into());
 360
 361        Stateful { element: self }
 362    }
 363
 364    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
 365        self.interactivity().focusable = true;
 366        self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
 367        Focusable { element: self }
 368    }
 369
 370    fn key_context<C, E>(mut self, key_context: C) -> Self
 371    where
 372        C: TryInto<KeyContext, Error = E>,
 373        E: Debug,
 374    {
 375        if let Some(key_context) = key_context.try_into().log_err() {
 376            self.interactivity().key_context = Some(key_context);
 377        }
 378        self
 379    }
 380
 381    fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 382        debug_assert!(
 383            self.interactivity().hover_style.is_none(),
 384            "hover style already set"
 385        );
 386        self.interactivity().hover_style = Some(Box::new(f(StyleRefinement::default())));
 387        self
 388    }
 389
 390    fn group_hover(
 391        mut self,
 392        group_name: impl Into<SharedString>,
 393        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 394    ) -> Self {
 395        self.interactivity().group_hover_style = Some(GroupStyle {
 396            group: group_name.into(),
 397            style: Box::new(f(StyleRefinement::default())),
 398        });
 399        self
 400    }
 401
 402    fn on_mouse_down(
 403        mut self,
 404        button: MouseButton,
 405        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 406    ) -> Self {
 407        self.interactivity().on_mouse_down(button, listener);
 408        self
 409    }
 410
 411    fn capture_any_mouse_down(
 412        mut self,
 413        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 414    ) -> Self {
 415        self.interactivity().capture_any_mouse_down(listener);
 416        self
 417    }
 418
 419    fn on_any_mouse_down(
 420        mut self,
 421        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 422    ) -> Self {
 423        self.interactivity().on_any_mouse_down(listener);
 424        self
 425    }
 426
 427    fn on_mouse_up(
 428        mut self,
 429        button: MouseButton,
 430        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 431    ) -> Self {
 432        self.interactivity().on_mouse_up(button, listener);
 433        self
 434    }
 435
 436    fn capture_any_mouse_up(
 437        mut self,
 438        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 439    ) -> Self {
 440        self.interactivity().capture_any_mouse_up(listener);
 441        self
 442    }
 443
 444    fn on_mouse_down_out(
 445        mut self,
 446        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
 447    ) -> Self {
 448        self.interactivity().on_mouse_down_out(listener);
 449        self
 450    }
 451
 452    fn on_mouse_up_out(
 453        mut self,
 454        button: MouseButton,
 455        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
 456    ) -> Self {
 457        self.interactivity().on_mouse_up_out(button, listener);
 458        self
 459    }
 460
 461    fn on_mouse_move(
 462        mut self,
 463        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
 464    ) -> Self {
 465        self.interactivity().on_mouse_move(listener);
 466        self
 467    }
 468
 469    fn on_drag_move<T: 'static>(
 470        mut self,
 471        listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
 472    ) -> Self
 473    where
 474        T: 'static,
 475    {
 476        self.interactivity().on_drag_move(listener);
 477        self
 478    }
 479
 480    fn on_scroll_wheel(
 481        mut self,
 482        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
 483    ) -> Self {
 484        self.interactivity().on_scroll_wheel(listener);
 485        self
 486    }
 487
 488    /// Capture the given action, before normal action dispatch can fire
 489    fn capture_action<A: Action>(
 490        mut self,
 491        listener: impl Fn(&A, &mut WindowContext) + 'static,
 492    ) -> Self {
 493        self.interactivity().capture_action(listener);
 494        self
 495    }
 496
 497    /// Add a listener for the given action, fires during the bubble event phase
 498    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
 499        self.interactivity().on_action(listener);
 500        self
 501    }
 502
 503    fn on_boxed_action(
 504        mut self,
 505        action: &Box<dyn Action>,
 506        listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
 507    ) -> Self {
 508        self.interactivity().on_boxed_action(action, listener);
 509        self
 510    }
 511
 512    fn on_key_down(
 513        mut self,
 514        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 515    ) -> Self {
 516        self.interactivity().on_key_down(listener);
 517        self
 518    }
 519
 520    fn capture_key_down(
 521        mut self,
 522        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
 523    ) -> Self {
 524        self.interactivity().capture_key_down(listener);
 525        self
 526    }
 527
 528    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
 529        self.interactivity().on_key_up(listener);
 530        self
 531    }
 532
 533    fn capture_key_up(
 534        mut self,
 535        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
 536    ) -> Self {
 537        self.interactivity().capture_key_up(listener);
 538        self
 539    }
 540
 541    fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
 542        self.interactivity()
 543            .drag_over_styles
 544            .push((TypeId::of::<S>(), f(StyleRefinement::default())));
 545        self
 546    }
 547
 548    fn group_drag_over<S: 'static>(
 549        mut self,
 550        group_name: impl Into<SharedString>,
 551        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 552    ) -> Self {
 553        self.interactivity().group_drag_over_styles.push((
 554            TypeId::of::<S>(),
 555            GroupStyle {
 556                group: group_name.into(),
 557                style: Box::new(f(StyleRefinement::default())),
 558            },
 559        ));
 560        self
 561    }
 562
 563    fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
 564        self.interactivity().on_drop(listener);
 565        self
 566    }
 567}
 568
 569pub trait StatefulInteractiveElement: InteractiveElement {
 570    fn focusable(mut self) -> Focusable<Self> {
 571        self.interactivity().focusable = true;
 572        Focusable { element: self }
 573    }
 574
 575    fn overflow_scroll(mut self) -> Self {
 576        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 577        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 578        self
 579    }
 580
 581    fn overflow_x_scroll(mut self) -> Self {
 582        self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
 583        self
 584    }
 585
 586    fn overflow_y_scroll(mut self) -> Self {
 587        self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
 588        self
 589    }
 590
 591    fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
 592        self.interactivity().scroll_handle = Some(scroll_handle.clone());
 593        self
 594    }
 595
 596    fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 597    where
 598        Self: Sized,
 599    {
 600        self.interactivity().active_style = Some(Box::new(f(StyleRefinement::default())));
 601        self
 602    }
 603
 604    fn group_active(
 605        mut self,
 606        group_name: impl Into<SharedString>,
 607        f: impl FnOnce(StyleRefinement) -> StyleRefinement,
 608    ) -> Self
 609    where
 610        Self: Sized,
 611    {
 612        self.interactivity().group_active_style = Some(GroupStyle {
 613            group: group_name.into(),
 614            style: Box::new(f(StyleRefinement::default())),
 615        });
 616        self
 617    }
 618
 619    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
 620    where
 621        Self: Sized,
 622    {
 623        self.interactivity().on_click(listener);
 624        self
 625    }
 626
 627    fn on_drag<T, W>(
 628        mut self,
 629        value: T,
 630        constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
 631    ) -> Self
 632    where
 633        Self: Sized,
 634        T: 'static,
 635        W: 'static + Render,
 636    {
 637        self.interactivity().on_drag(value, constructor);
 638        self
 639    }
 640
 641    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
 642    where
 643        Self: Sized,
 644    {
 645        self.interactivity().on_hover(listener);
 646        self
 647    }
 648
 649    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
 650    where
 651        Self: Sized,
 652    {
 653        self.interactivity().tooltip(build_tooltip);
 654        self
 655    }
 656}
 657
 658pub trait FocusableElement: InteractiveElement {
 659    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 660    where
 661        Self: Sized,
 662    {
 663        self.interactivity().focus_style = Some(Box::new(f(StyleRefinement::default())));
 664        self
 665    }
 666
 667    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
 668    where
 669        Self: Sized,
 670    {
 671        self.interactivity().in_focus_style = Some(Box::new(f(StyleRefinement::default())));
 672        self
 673    }
 674}
 675
 676pub type MouseDownListener =
 677    Box<dyn Fn(&MouseDownEvent, &InteractiveBounds, DispatchPhase, &mut WindowContext) + 'static>;
 678pub type MouseUpListener =
 679    Box<dyn Fn(&MouseUpEvent, &InteractiveBounds, DispatchPhase, &mut WindowContext) + 'static>;
 680
 681pub type MouseMoveListener =
 682    Box<dyn Fn(&MouseMoveEvent, &InteractiveBounds, DispatchPhase, &mut WindowContext) + 'static>;
 683
 684pub type ScrollWheelListener =
 685    Box<dyn Fn(&ScrollWheelEvent, &InteractiveBounds, DispatchPhase, &mut WindowContext) + 'static>;
 686
 687pub type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
 688
 689pub type DragListener = Box<dyn Fn(&dyn Any, &mut WindowContext) -> AnyView + 'static>;
 690
 691type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
 692
 693pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
 694
 695pub type KeyDownListener = Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
 696
 697pub type KeyUpListener = Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
 698
 699pub type DragEventListener = Box<dyn Fn(&MouseMoveEvent, &mut WindowContext) + 'static>;
 700
 701pub type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
 702
 703#[track_caller]
 704pub fn div() -> Div {
 705    #[cfg(debug_assertions)]
 706    let interactivity = {
 707        let mut interactivity = Interactivity::default();
 708        interactivity.location = Some(*core::panic::Location::caller());
 709        interactivity
 710    };
 711
 712    #[cfg(not(debug_assertions))]
 713    let interactivity = Interactivity::default();
 714
 715    Div {
 716        interactivity,
 717        children: SmallVec::default(),
 718    }
 719}
 720
 721pub struct Div {
 722    interactivity: Interactivity,
 723    children: SmallVec<[AnyElement; 2]>,
 724}
 725
 726impl Styled for Div {
 727    fn style(&mut self) -> &mut StyleRefinement {
 728        &mut self.interactivity.base_style
 729    }
 730}
 731
 732impl InteractiveElement for Div {
 733    fn interactivity(&mut self) -> &mut Interactivity {
 734        &mut self.interactivity
 735    }
 736}
 737
 738impl ParentElement for Div {
 739    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
 740        &mut self.children
 741    }
 742}
 743
 744impl Element for Div {
 745    type State = DivState;
 746
 747    fn layout(
 748        &mut self,
 749        element_state: Option<Self::State>,
 750        cx: &mut WindowContext,
 751    ) -> (LayoutId, Self::State) {
 752        let mut child_layout_ids = SmallVec::new();
 753        let (layout_id, interactive_state) = self.interactivity.layout(
 754            element_state.map(|s| s.interactive_state),
 755            cx,
 756            |style, cx| {
 757                cx.with_text_style(style.text_style().cloned(), |cx| {
 758                    child_layout_ids = self
 759                        .children
 760                        .iter_mut()
 761                        .map(|child| child.layout(cx))
 762                        .collect::<SmallVec<_>>();
 763                    cx.request_layout(&style, child_layout_ids.iter().copied())
 764                })
 765            },
 766        );
 767        (
 768            layout_id,
 769            DivState {
 770                interactive_state,
 771                child_layout_ids,
 772            },
 773        )
 774    }
 775
 776    fn paint(
 777        &mut self,
 778        bounds: Bounds<Pixels>,
 779        element_state: &mut Self::State,
 780        cx: &mut WindowContext,
 781    ) {
 782        let mut child_min = point(Pixels::MAX, Pixels::MAX);
 783        let mut child_max = Point::default();
 784        let content_size = if element_state.child_layout_ids.is_empty() {
 785            bounds.size
 786        } else if let Some(scroll_handle) = self.interactivity.scroll_handle.as_ref() {
 787            let mut state = scroll_handle.0.borrow_mut();
 788            state.child_bounds = Vec::with_capacity(element_state.child_layout_ids.len());
 789            state.bounds = bounds;
 790            let requested = state.requested_scroll_top.take();
 791
 792            for (ix, child_layout_id) in element_state.child_layout_ids.iter().enumerate() {
 793                let child_bounds = cx.layout_bounds(*child_layout_id);
 794                child_min = child_min.min(&child_bounds.origin);
 795                child_max = child_max.max(&child_bounds.lower_right());
 796                state.child_bounds.push(child_bounds);
 797
 798                if let Some(requested) = requested.as_ref() {
 799                    if requested.0 == ix {
 800                        *state.offset.borrow_mut() =
 801                            bounds.origin - (child_bounds.origin - point(px(0.), requested.1));
 802                    }
 803                }
 804            }
 805            (child_max - child_min).into()
 806        } else {
 807            for child_layout_id in &element_state.child_layout_ids {
 808                let child_bounds = cx.layout_bounds(*child_layout_id);
 809                child_min = child_min.min(&child_bounds.origin);
 810                child_max = child_max.max(&child_bounds.lower_right());
 811            }
 812            (child_max - child_min).into()
 813        };
 814
 815        self.interactivity.paint(
 816            bounds,
 817            content_size,
 818            &mut element_state.interactive_state,
 819            cx,
 820            |style, scroll_offset, cx| {
 821                style.paint(bounds, cx, |cx| {
 822                    cx.with_text_style(style.text_style().cloned(), |cx| {
 823                        cx.with_content_mask(style.overflow_mask(bounds), |cx| {
 824                            cx.with_element_offset(scroll_offset, |cx| {
 825                                for child in &mut self.children {
 826                                    child.paint(cx);
 827                                }
 828                            })
 829                        })
 830                    })
 831                })
 832            },
 833        );
 834    }
 835}
 836
 837impl IntoElement for Div {
 838    type Element = Self;
 839
 840    fn element_id(&self) -> Option<ElementId> {
 841        self.interactivity.element_id.clone()
 842    }
 843
 844    fn into_element(self) -> Self::Element {
 845        self
 846    }
 847}
 848
 849pub struct DivState {
 850    child_layout_ids: SmallVec<[LayoutId; 2]>,
 851    interactive_state: InteractiveElementState,
 852}
 853
 854impl DivState {
 855    pub fn is_active(&self) -> bool {
 856        self.interactive_state
 857            .pending_mouse_down
 858            .as_ref()
 859            .map_or(false, |pending| pending.borrow().is_some())
 860    }
 861}
 862
 863pub struct Interactivity {
 864    pub element_id: Option<ElementId>,
 865    pub key_context: Option<KeyContext>,
 866    pub focusable: bool,
 867    pub tracked_focus_handle: Option<FocusHandle>,
 868    pub scroll_handle: Option<ScrollHandle>,
 869    pub group: Option<SharedString>,
 870    pub base_style: Box<StyleRefinement>,
 871    pub focus_style: Option<Box<StyleRefinement>>,
 872    pub in_focus_style: Option<Box<StyleRefinement>>,
 873    pub hover_style: Option<Box<StyleRefinement>>,
 874    pub group_hover_style: Option<GroupStyle>,
 875    pub active_style: Option<Box<StyleRefinement>>,
 876    pub group_active_style: Option<GroupStyle>,
 877    pub drag_over_styles: Vec<(TypeId, StyleRefinement)>,
 878    pub group_drag_over_styles: Vec<(TypeId, GroupStyle)>,
 879    pub mouse_down_listeners: Vec<MouseDownListener>,
 880    pub mouse_up_listeners: Vec<MouseUpListener>,
 881    pub mouse_move_listeners: Vec<MouseMoveListener>,
 882    pub scroll_wheel_listeners: Vec<ScrollWheelListener>,
 883    pub key_down_listeners: Vec<KeyDownListener>,
 884    pub key_up_listeners: Vec<KeyUpListener>,
 885    pub action_listeners: Vec<(TypeId, ActionListener)>,
 886    pub drop_listeners: Vec<(TypeId, DropListener)>,
 887    pub click_listeners: Vec<ClickListener>,
 888    pub drag_listener: Option<(Box<dyn Any>, DragListener)>,
 889    pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
 890    pub tooltip_builder: Option<TooltipBuilder>,
 891
 892    #[cfg(debug_assertions)]
 893    pub location: Option<core::panic::Location<'static>>,
 894}
 895
 896#[derive(Clone, Debug)]
 897pub struct InteractiveBounds {
 898    pub bounds: Bounds<Pixels>,
 899    pub stacking_order: StackingOrder,
 900}
 901
 902impl InteractiveBounds {
 903    pub fn visibly_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
 904        self.bounds.contains(point) && cx.was_top_layer(&point, &self.stacking_order)
 905    }
 906
 907    pub fn drag_target_contains(&self, point: &Point<Pixels>, cx: &WindowContext) -> bool {
 908        self.bounds.contains(point)
 909            && cx.was_top_layer_under_active_drag(&point, &self.stacking_order)
 910    }
 911}
 912
 913impl Interactivity {
 914    pub fn layout(
 915        &mut self,
 916        element_state: Option<InteractiveElementState>,
 917        cx: &mut WindowContext,
 918        f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
 919    ) -> (LayoutId, InteractiveElementState) {
 920        let mut element_state = element_state.unwrap_or_default();
 921
 922        // Ensure we store a focus handle in our element state if we're focusable.
 923        // If there's an explicit focus handle we're tracking, use that. Otherwise
 924        // create a new handle and store it in the element state, which lives for as
 925        // as frames contain an element with this id.
 926        if self.focusable {
 927            element_state.focus_handle.get_or_insert_with(|| {
 928                self.tracked_focus_handle
 929                    .clone()
 930                    .unwrap_or_else(|| cx.focus_handle())
 931            });
 932        }
 933
 934        if let Some(scroll_handle) = self.scroll_handle.as_ref() {
 935            element_state.scroll_offset = Some(scroll_handle.0.borrow().offset.clone());
 936        }
 937
 938        let style = self.compute_style(None, &mut element_state, cx);
 939        let layout_id = f(style, cx);
 940        (layout_id, element_state)
 941    }
 942
 943    pub fn paint(
 944        &mut self,
 945        bounds: Bounds<Pixels>,
 946        content_size: Size<Pixels>,
 947        element_state: &mut InteractiveElementState,
 948        cx: &mut WindowContext,
 949        f: impl FnOnce(Style, Point<Pixels>, &mut WindowContext),
 950    ) {
 951        let style = self.compute_style(Some(bounds), element_state, cx);
 952
 953        if style.visibility == Visibility::Hidden {
 954            return;
 955        }
 956
 957        let z_index = style.z_index.unwrap_or(0);
 958        cx.with_z_index(z_index, |cx| {
 959            #[cfg(debug_assertions)]
 960            if self.element_id.is_some()
 961                && (style.debug || style.debug_below || cx.has_global::<crate::DebugBelow>())
 962                && bounds.contains(&cx.mouse_position())
 963            {
 964                const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
 965                let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
 966                let str_len = element_id.len();
 967
 968                let render_debug_text = |cx: &mut WindowContext| {
 969                    if let Some(text) = cx
 970                        .text_system()
 971                        .shape_text(
 972                            &element_id,
 973                            FONT_SIZE,
 974                            &[cx.text_style().to_run(str_len)],
 975                            None,
 976                        )
 977                        .ok()
 978                        .map(|mut text| text.pop())
 979                        .flatten()
 980                    {
 981                        text.paint(bounds.origin, FONT_SIZE, cx).ok();
 982
 983                        let text_bounds = crate::Bounds {
 984                            origin: bounds.origin,
 985                            size: text.size(FONT_SIZE),
 986                        };
 987                        if self.location.is_some()
 988                            && text_bounds.contains(&cx.mouse_position())
 989                            && cx.modifiers().command
 990                        {
 991                            let command_held = cx.modifiers().command;
 992                            cx.on_key_event({
 993                                let text_bounds = text_bounds.clone();
 994                                move |e: &crate::ModifiersChangedEvent, _phase, cx| {
 995                                    if e.modifiers.command != command_held
 996                                        && text_bounds.contains(&cx.mouse_position())
 997                                    {
 998                                        cx.notify();
 999                                    }
1000                                }
1001                            });
1002
1003                            let hovered = bounds.contains(&cx.mouse_position());
1004                            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1005                                if phase == DispatchPhase::Capture {
1006                                    if bounds.contains(&event.position) != hovered {
1007                                        cx.notify();
1008                                    }
1009                                }
1010                            });
1011
1012                            cx.on_mouse_event({
1013                                let location = self.location.clone().unwrap();
1014                                let text_bounds = text_bounds.clone();
1015                                move |e: &crate::MouseDownEvent, phase, cx| {
1016                                    if text_bounds.contains(&e.position) && phase.capture() {
1017                                        cx.stop_propagation();
1018                                        let Ok(dir) = std::env::current_dir() else {
1019                                            return;
1020                                        };
1021
1022                                        eprintln!(
1023                                            "This element is created at:\n{}:{}:{}",
1024                                            location.file(),
1025                                            location.line(),
1026                                            location.column()
1027                                        );
1028
1029                                        std::process::Command::new("zed")
1030                                            .arg(format!(
1031                                                "{}/{}:{}:{}",
1032                                                dir.to_string_lossy(),
1033                                                location.file(),
1034                                                location.line(),
1035                                                location.column()
1036                                            ))
1037                                            .spawn()
1038                                            .ok();
1039                                    }
1040                                }
1041                            });
1042                            cx.paint_quad(crate::outline(
1043                                crate::Bounds {
1044                                    origin: bounds.origin
1045                                        + crate::point(crate::px(0.), FONT_SIZE - px(2.)),
1046                                    size: crate::Size {
1047                                        width: text_bounds.size.width,
1048                                        height: crate::px(1.),
1049                                    },
1050                                },
1051                                crate::red(),
1052                            ))
1053                        }
1054                    }
1055                };
1056
1057                cx.with_z_index(1, |cx| {
1058                    cx.with_text_style(
1059                        Some(crate::TextStyleRefinement {
1060                            color: Some(crate::red()),
1061                            line_height: Some(FONT_SIZE.into()),
1062                            background_color: Some(crate::white()),
1063                            ..Default::default()
1064                        }),
1065                        render_debug_text,
1066                    )
1067                });
1068            }
1069
1070            if style
1071                .background
1072                .as_ref()
1073                .is_some_and(|fill| fill.color().is_some_and(|color| !color.is_transparent()))
1074            {
1075                cx.add_opaque_layer(bounds)
1076            }
1077
1078            let interactive_bounds = InteractiveBounds {
1079                bounds: bounds.intersect(&cx.content_mask().bounds),
1080                stacking_order: cx.stacking_order().clone(),
1081            };
1082
1083            if let Some(mouse_cursor) = style.mouse_cursor {
1084                let mouse_position = &cx.mouse_position();
1085                let hovered = interactive_bounds.visibly_contains(mouse_position, cx);
1086                if hovered {
1087                    cx.set_cursor_style(mouse_cursor);
1088                }
1089            }
1090
1091            // If this element can be focused, register a mouse down listener
1092            // that will automatically transfer focus when hitting the element.
1093            // This behavior can be suppressed by using `cx.prevent_default()`.
1094            if let Some(focus_handle) = element_state.focus_handle.clone() {
1095                cx.on_mouse_event({
1096                    let interactive_bounds = interactive_bounds.clone();
1097                    move |event: &MouseDownEvent, phase, cx| {
1098                        if phase == DispatchPhase::Bubble
1099                            && !cx.default_prevented()
1100                            && interactive_bounds.visibly_contains(&event.position, cx)
1101                        {
1102                            cx.focus(&focus_handle);
1103                            // If there is a parent that is also focusable, prevent it
1104                            // from transferring focus because we already did so.
1105                            cx.prevent_default();
1106                        }
1107                    }
1108                });
1109            }
1110
1111            for listener in self.mouse_down_listeners.drain(..) {
1112                let interactive_bounds = interactive_bounds.clone();
1113                cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
1114                    listener(event, &interactive_bounds, phase, cx);
1115                })
1116            }
1117
1118            for listener in self.mouse_up_listeners.drain(..) {
1119                let interactive_bounds = interactive_bounds.clone();
1120                cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
1121                    listener(event, &interactive_bounds, phase, cx);
1122                })
1123            }
1124
1125            for listener in self.mouse_move_listeners.drain(..) {
1126                let interactive_bounds = interactive_bounds.clone();
1127                cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1128                    listener(event, &interactive_bounds, phase, cx);
1129                })
1130            }
1131
1132            for listener in self.scroll_wheel_listeners.drain(..) {
1133                let interactive_bounds = interactive_bounds.clone();
1134                cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1135                    listener(event, &interactive_bounds, phase, cx);
1136                })
1137            }
1138
1139            let hover_group_bounds = self
1140                .group_hover_style
1141                .as_ref()
1142                .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
1143
1144            if let Some(group_bounds) = hover_group_bounds {
1145                let hovered = group_bounds.contains(&cx.mouse_position());
1146                cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1147                    if phase == DispatchPhase::Capture {
1148                        if group_bounds.contains(&event.position) != hovered {
1149                            cx.notify();
1150                        }
1151                    }
1152                });
1153            }
1154
1155            if self.hover_style.is_some()
1156                || self.base_style.mouse_cursor.is_some()
1157                || cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
1158            {
1159                let bounds = bounds.intersect(&cx.content_mask().bounds);
1160                let hovered = bounds.contains(&cx.mouse_position());
1161                cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1162                    if phase == DispatchPhase::Capture {
1163                        if bounds.contains(&event.position) != hovered {
1164                            cx.notify();
1165                        }
1166                    }
1167                });
1168            }
1169
1170            let mut drag_listener = mem::take(&mut self.drag_listener);
1171            let drop_listeners = mem::take(&mut self.drop_listeners);
1172            let click_listeners = mem::take(&mut self.click_listeners);
1173
1174            if !drop_listeners.is_empty() {
1175                cx.on_mouse_event({
1176                    let interactive_bounds = interactive_bounds.clone();
1177                    move |event: &MouseUpEvent, phase, cx| {
1178                        if let Some(drag) = &cx.active_drag {
1179                            if phase == DispatchPhase::Bubble
1180                                && interactive_bounds.drag_target_contains(&event.position, cx)
1181                            {
1182                                let drag_state_type = drag.value.as_ref().type_id();
1183                                for (drop_state_type, listener) in &drop_listeners {
1184                                    if *drop_state_type == drag_state_type {
1185                                        let drag = cx
1186                                            .active_drag
1187                                            .take()
1188                                            .expect("checked for type drag state type above");
1189
1190                                        listener(drag.value.as_ref(), cx);
1191                                        cx.notify();
1192                                        cx.stop_propagation();
1193                                    }
1194                                }
1195                            }
1196                        }
1197                    }
1198                });
1199            }
1200
1201            if !click_listeners.is_empty() || drag_listener.is_some() {
1202                let pending_mouse_down = element_state
1203                    .pending_mouse_down
1204                    .get_or_insert_with(Default::default)
1205                    .clone();
1206
1207                let active_state = element_state
1208                    .clicked_state
1209                    .get_or_insert_with(Default::default)
1210                    .clone();
1211
1212                cx.on_mouse_event({
1213                    let interactive_bounds = interactive_bounds.clone();
1214                    let pending_mouse_down = pending_mouse_down.clone();
1215                    move |event: &MouseDownEvent, phase, cx| {
1216                        if phase == DispatchPhase::Bubble
1217                            && event.button == MouseButton::Left
1218                            && interactive_bounds.visibly_contains(&event.position, cx)
1219                        {
1220                            *pending_mouse_down.borrow_mut() = Some(event.clone());
1221                            cx.notify();
1222                        }
1223                    }
1224                });
1225
1226                cx.on_mouse_event({
1227                    let pending_mouse_down = pending_mouse_down.clone();
1228                    move |event: &MouseMoveEvent, phase, cx| {
1229                        if phase == DispatchPhase::Capture {
1230                            return;
1231                        }
1232
1233                        let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1234                        if let Some(mouse_down) = pending_mouse_down.clone() {
1235                            if !cx.has_active_drag()
1236                                && (event.position - mouse_down.position).magnitude()
1237                                    > DRAG_THRESHOLD
1238                            {
1239                                if let Some((drag_value, drag_listener)) = drag_listener.take() {
1240                                    *active_state.borrow_mut() = ElementClickedState::default();
1241                                    let cursor_offset = event.position - bounds.origin;
1242                                    let drag = (drag_listener)(drag_value.as_ref(), cx);
1243                                    cx.active_drag = Some(AnyDrag {
1244                                        view: drag,
1245                                        value: drag_value,
1246                                        cursor_offset,
1247                                    });
1248                                    pending_mouse_down.take();
1249                                    cx.notify();
1250                                    cx.stop_propagation();
1251                                }
1252                            }
1253                        }
1254                    }
1255                });
1256
1257                cx.on_mouse_event({
1258                    let interactive_bounds = interactive_bounds.clone();
1259                    let mut captured_mouse_down = None;
1260                    move |event: &MouseUpEvent, phase, cx| match phase {
1261                        // Clear the pending mouse down during the capture phase,
1262                        // so that it happens even if another event handler stops
1263                        // propagation.
1264                        DispatchPhase::Capture => {
1265                            let mut pending_mouse_down = pending_mouse_down.borrow_mut();
1266                            if pending_mouse_down.is_some() {
1267                                captured_mouse_down = pending_mouse_down.take();
1268                                cx.notify();
1269                            }
1270                        }
1271                        // Fire click handlers during the bubble phase.
1272                        DispatchPhase::Bubble => {
1273                            if let Some(mouse_down) = captured_mouse_down.take() {
1274                                if interactive_bounds.visibly_contains(&event.position, cx) {
1275                                    let mouse_click = ClickEvent {
1276                                        down: mouse_down,
1277                                        up: event.clone(),
1278                                    };
1279                                    for listener in &click_listeners {
1280                                        listener(&mouse_click, cx);
1281                                    }
1282                                }
1283                            }
1284                        }
1285                    }
1286                });
1287            }
1288
1289            if let Some(hover_listener) = self.hover_listener.take() {
1290                let was_hovered = element_state
1291                    .hover_state
1292                    .get_or_insert_with(Default::default)
1293                    .clone();
1294                let has_mouse_down = element_state
1295                    .pending_mouse_down
1296                    .get_or_insert_with(Default::default)
1297                    .clone();
1298                let interactive_bounds = interactive_bounds.clone();
1299
1300                cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1301                    if phase != DispatchPhase::Bubble {
1302                        return;
1303                    }
1304                    let is_hovered = interactive_bounds.visibly_contains(&event.position, cx)
1305                        && has_mouse_down.borrow().is_none();
1306                    let mut was_hovered = was_hovered.borrow_mut();
1307
1308                    if is_hovered != was_hovered.clone() {
1309                        *was_hovered = is_hovered;
1310                        drop(was_hovered);
1311
1312                        hover_listener(&is_hovered, cx);
1313                    }
1314                });
1315            }
1316
1317            if let Some(tooltip_builder) = self.tooltip_builder.take() {
1318                let active_tooltip = element_state
1319                    .active_tooltip
1320                    .get_or_insert_with(Default::default)
1321                    .clone();
1322                let pending_mouse_down = element_state
1323                    .pending_mouse_down
1324                    .get_or_insert_with(Default::default)
1325                    .clone();
1326                let interactive_bounds = interactive_bounds.clone();
1327
1328                cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
1329                    let is_hovered = interactive_bounds.visibly_contains(&event.position, cx)
1330                        && pending_mouse_down.borrow().is_none();
1331                    if !is_hovered {
1332                        active_tooltip.borrow_mut().take();
1333                        return;
1334                    }
1335
1336                    if phase != DispatchPhase::Bubble {
1337                        return;
1338                    }
1339
1340                    if active_tooltip.borrow().is_none() {
1341                        let task = cx.spawn({
1342                            let active_tooltip = active_tooltip.clone();
1343                            let tooltip_builder = tooltip_builder.clone();
1344
1345                            move |mut cx| async move {
1346                                cx.background_executor().timer(TOOLTIP_DELAY).await;
1347                                cx.update(|_, cx| {
1348                                    active_tooltip.borrow_mut().replace(ActiveTooltip {
1349                                        tooltip: Some(AnyTooltip {
1350                                            view: tooltip_builder(cx),
1351                                            cursor_offset: cx.mouse_position(),
1352                                        }),
1353                                        _task: None,
1354                                    });
1355                                    cx.notify();
1356                                })
1357                                .ok();
1358                            }
1359                        });
1360                        active_tooltip.borrow_mut().replace(ActiveTooltip {
1361                            tooltip: None,
1362                            _task: Some(task),
1363                        });
1364                    }
1365                });
1366
1367                let active_tooltip = element_state
1368                    .active_tooltip
1369                    .get_or_insert_with(Default::default)
1370                    .clone();
1371                cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
1372                    active_tooltip.borrow_mut().take();
1373                });
1374
1375                if let Some(active_tooltip) = element_state
1376                    .active_tooltip
1377                    .get_or_insert_with(Default::default)
1378                    .borrow()
1379                    .as_ref()
1380                {
1381                    if active_tooltip.tooltip.is_some() {
1382                        cx.active_tooltip = active_tooltip.tooltip.clone()
1383                    }
1384                }
1385            }
1386
1387            let active_state = element_state
1388                .clicked_state
1389                .get_or_insert_with(Default::default)
1390                .clone();
1391            if active_state.borrow().is_clicked() {
1392                cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
1393                    if phase == DispatchPhase::Capture {
1394                        *active_state.borrow_mut() = ElementClickedState::default();
1395                        cx.notify();
1396                    }
1397                });
1398            } else {
1399                let active_group_bounds = self
1400                    .group_active_style
1401                    .as_ref()
1402                    .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
1403                let interactive_bounds = interactive_bounds.clone();
1404                cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
1405                    if phase == DispatchPhase::Bubble && !cx.default_prevented() {
1406                        let group = active_group_bounds
1407                            .map_or(false, |bounds| bounds.contains(&down.position));
1408                        let element = interactive_bounds.visibly_contains(&down.position, cx);
1409                        if group || element {
1410                            *active_state.borrow_mut() = ElementClickedState { group, element };
1411                            cx.notify();
1412                        }
1413                    }
1414                });
1415            }
1416
1417            let overflow = style.overflow;
1418            if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
1419                if let Some(scroll_handle) = &self.scroll_handle {
1420                    scroll_handle.0.borrow_mut().overflow = overflow;
1421                }
1422
1423                let scroll_offset = element_state
1424                    .scroll_offset
1425                    .get_or_insert_with(Rc::default)
1426                    .clone();
1427                let line_height = cx.line_height();
1428                let scroll_max = (content_size - bounds.size).max(&Size::default());
1429                let interactive_bounds = interactive_bounds.clone();
1430                cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
1431                    if phase == DispatchPhase::Bubble
1432                        && interactive_bounds.visibly_contains(&event.position, cx)
1433                    {
1434                        let mut scroll_offset = scroll_offset.borrow_mut();
1435                        let old_scroll_offset = *scroll_offset;
1436                        let delta = event.delta.pixel_delta(line_height);
1437
1438                        if overflow.x == Overflow::Scroll {
1439                            scroll_offset.x =
1440                                (scroll_offset.x + delta.x).clamp(-scroll_max.width, px(0.));
1441                        }
1442
1443                        if overflow.y == Overflow::Scroll {
1444                            scroll_offset.y =
1445                                (scroll_offset.y + delta.y).clamp(-scroll_max.height, px(0.));
1446                        }
1447
1448                        if *scroll_offset != old_scroll_offset {
1449                            cx.notify();
1450                            cx.stop_propagation();
1451                        }
1452                    }
1453                });
1454            }
1455
1456            if let Some(group) = self.group.clone() {
1457                GroupBounds::push(group, bounds, cx);
1458            }
1459
1460            let scroll_offset = element_state
1461                .scroll_offset
1462                .as_ref()
1463                .map(|scroll_offset| *scroll_offset.borrow());
1464
1465            let key_down_listeners = mem::take(&mut self.key_down_listeners);
1466            let key_up_listeners = mem::take(&mut self.key_up_listeners);
1467            let action_listeners = mem::take(&mut self.action_listeners);
1468            cx.with_key_dispatch(
1469                self.key_context.clone(),
1470                element_state.focus_handle.clone(),
1471                |_, cx| {
1472                    for listener in key_down_listeners {
1473                        cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
1474                            listener(event, phase, cx);
1475                        })
1476                    }
1477
1478                    for listener in key_up_listeners {
1479                        cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
1480                            listener(event, phase, cx);
1481                        })
1482                    }
1483
1484                    for (action_type, listener) in action_listeners {
1485                        cx.on_action(action_type, listener)
1486                    }
1487
1488                    cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
1489                        if style.background.as_ref().is_some_and(|fill| {
1490                            fill.color().is_some_and(|color| !color.is_transparent())
1491                        }) {
1492                            cx.add_opaque_layer(bounds)
1493                        }
1494
1495                        f(style, scroll_offset.unwrap_or_default(), cx)
1496                    })
1497                },
1498            );
1499
1500            if let Some(group) = self.group.as_ref() {
1501                GroupBounds::pop(group, cx);
1502            }
1503        });
1504    }
1505
1506    pub fn compute_style(
1507        &self,
1508        bounds: Option<Bounds<Pixels>>,
1509        element_state: &mut InteractiveElementState,
1510        cx: &mut WindowContext,
1511    ) -> Style {
1512        let mut style = Style::default();
1513        style.refine(&self.base_style);
1514
1515        cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
1516            if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
1517                if let Some(in_focus_style) = self.in_focus_style.as_ref() {
1518                    if focus_handle.within_focused(cx) {
1519                        style.refine(in_focus_style);
1520                    }
1521                }
1522
1523                if let Some(focus_style) = self.focus_style.as_ref() {
1524                    if focus_handle.is_focused(cx) {
1525                        style.refine(focus_style);
1526                    }
1527                }
1528            }
1529
1530            if let Some(bounds) = bounds {
1531                let mouse_position = cx.mouse_position();
1532                if let Some(group_hover) = self.group_hover_style.as_ref() {
1533                    if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
1534                        if group_bounds.contains(&mouse_position)
1535                            && cx.was_top_layer(&mouse_position, cx.stacking_order())
1536                        {
1537                            style.refine(&group_hover.style);
1538                        }
1539                    }
1540                }
1541                if let Some(hover_style) = self.hover_style.as_ref() {
1542                    if bounds
1543                        .intersect(&cx.content_mask().bounds)
1544                        .contains(&mouse_position)
1545                        && cx.was_top_layer(&mouse_position, cx.stacking_order())
1546                    {
1547                        style.refine(hover_style);
1548                    }
1549                }
1550
1551                if let Some(drag) = cx.active_drag.take() {
1552                    for (state_type, group_drag_style) in &self.group_drag_over_styles {
1553                        if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
1554                            if *state_type == drag.value.as_ref().type_id()
1555                                && group_bounds.contains(&mouse_position)
1556                            {
1557                                style.refine(&group_drag_style.style);
1558                            }
1559                        }
1560                    }
1561
1562                    for (state_type, drag_over_style) in &self.drag_over_styles {
1563                        if *state_type == drag.value.as_ref().type_id()
1564                            && bounds
1565                                .intersect(&cx.content_mask().bounds)
1566                                .contains(&mouse_position)
1567                            && cx.was_top_layer_under_active_drag(
1568                                &mouse_position,
1569                                cx.stacking_order(),
1570                            )
1571                        {
1572                            style.refine(drag_over_style);
1573                        }
1574                    }
1575
1576                    cx.active_drag = Some(drag);
1577                }
1578            }
1579
1580            let clicked_state = element_state
1581                .clicked_state
1582                .get_or_insert_with(Default::default)
1583                .borrow();
1584            if clicked_state.group {
1585                if let Some(group) = self.group_active_style.as_ref() {
1586                    style.refine(&group.style)
1587                }
1588            }
1589
1590            if let Some(active_style) = self.active_style.as_ref() {
1591                if clicked_state.element {
1592                    style.refine(active_style)
1593                }
1594            }
1595        });
1596
1597        style
1598    }
1599}
1600
1601impl Default for Interactivity {
1602    fn default() -> Self {
1603        Self {
1604            element_id: None,
1605            key_context: None,
1606            focusable: false,
1607            tracked_focus_handle: None,
1608            scroll_handle: None,
1609            // scroll_offset: Point::default(),
1610            group: None,
1611            base_style: Box::new(StyleRefinement::default()),
1612            focus_style: None,
1613            in_focus_style: None,
1614            hover_style: None,
1615            group_hover_style: None,
1616            active_style: None,
1617            group_active_style: None,
1618            drag_over_styles: Vec::new(),
1619            group_drag_over_styles: Vec::new(),
1620            mouse_down_listeners: Vec::new(),
1621            mouse_up_listeners: Vec::new(),
1622            mouse_move_listeners: Vec::new(),
1623            scroll_wheel_listeners: Vec::new(),
1624            key_down_listeners: Vec::new(),
1625            key_up_listeners: Vec::new(),
1626            action_listeners: Vec::new(),
1627            drop_listeners: Vec::new(),
1628            click_listeners: Vec::new(),
1629            drag_listener: None,
1630            hover_listener: None,
1631            tooltip_builder: None,
1632
1633            #[cfg(debug_assertions)]
1634            location: None,
1635        }
1636    }
1637}
1638
1639#[derive(Default)]
1640pub struct InteractiveElementState {
1641    pub focus_handle: Option<FocusHandle>,
1642    pub clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
1643    pub hover_state: Option<Rc<RefCell<bool>>>,
1644    pub pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
1645    pub scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
1646    pub active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
1647}
1648
1649pub struct ActiveTooltip {
1650    tooltip: Option<AnyTooltip>,
1651    _task: Option<Task<()>>,
1652}
1653
1654/// Whether or not the element or a group that contains it is clicked by the mouse.
1655#[derive(Copy, Clone, Default, Eq, PartialEq)]
1656pub struct ElementClickedState {
1657    pub group: bool,
1658    pub element: bool,
1659}
1660
1661impl ElementClickedState {
1662    fn is_clicked(&self) -> bool {
1663        self.group || self.element
1664    }
1665}
1666
1667#[derive(Default)]
1668pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
1669
1670impl GroupBounds {
1671    pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
1672        cx.default_global::<Self>()
1673            .0
1674            .get(name)
1675            .and_then(|bounds_stack| bounds_stack.last())
1676            .cloned()
1677    }
1678
1679    pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
1680        cx.default_global::<Self>()
1681            .0
1682            .entry(name)
1683            .or_default()
1684            .push(bounds);
1685    }
1686
1687    pub fn pop(name: &SharedString, cx: &mut AppContext) {
1688        cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
1689    }
1690}
1691
1692pub struct Focusable<E> {
1693    pub element: E,
1694}
1695
1696impl<E: InteractiveElement> FocusableElement for Focusable<E> {}
1697
1698impl<E> InteractiveElement for Focusable<E>
1699where
1700    E: InteractiveElement,
1701{
1702    fn interactivity(&mut self) -> &mut Interactivity {
1703        self.element.interactivity()
1704    }
1705}
1706
1707impl<E: StatefulInteractiveElement> StatefulInteractiveElement for Focusable<E> {}
1708
1709impl<E> Styled for Focusable<E>
1710where
1711    E: Styled,
1712{
1713    fn style(&mut self) -> &mut StyleRefinement {
1714        self.element.style()
1715    }
1716}
1717
1718impl<E> Element for Focusable<E>
1719where
1720    E: Element,
1721{
1722    type State = E::State;
1723
1724    fn layout(
1725        &mut self,
1726        state: Option<Self::State>,
1727        cx: &mut WindowContext,
1728    ) -> (LayoutId, Self::State) {
1729        self.element.layout(state, cx)
1730    }
1731
1732    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
1733        self.element.paint(bounds, state, cx)
1734    }
1735}
1736
1737impl<E> IntoElement for Focusable<E>
1738where
1739    E: IntoElement,
1740{
1741    type Element = E::Element;
1742
1743    fn element_id(&self) -> Option<ElementId> {
1744        self.element.element_id()
1745    }
1746
1747    fn into_element(self) -> Self::Element {
1748        self.element.into_element()
1749    }
1750}
1751
1752impl<E> ParentElement for Focusable<E>
1753where
1754    E: ParentElement,
1755{
1756    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
1757        self.element.children_mut()
1758    }
1759}
1760
1761pub struct Stateful<E> {
1762    element: E,
1763}
1764
1765impl<E> Styled for Stateful<E>
1766where
1767    E: Styled,
1768{
1769    fn style(&mut self) -> &mut StyleRefinement {
1770        self.element.style()
1771    }
1772}
1773
1774impl<E> StatefulInteractiveElement for Stateful<E>
1775where
1776    E: Element,
1777    Self: InteractiveElement,
1778{
1779}
1780
1781impl<E> InteractiveElement for Stateful<E>
1782where
1783    E: InteractiveElement,
1784{
1785    fn interactivity(&mut self) -> &mut Interactivity {
1786        self.element.interactivity()
1787    }
1788}
1789
1790impl<E: FocusableElement> FocusableElement for Stateful<E> {}
1791
1792impl<E> Element for Stateful<E>
1793where
1794    E: Element,
1795{
1796    type State = E::State;
1797
1798    fn layout(
1799        &mut self,
1800        state: Option<Self::State>,
1801        cx: &mut WindowContext,
1802    ) -> (LayoutId, Self::State) {
1803        self.element.layout(state, cx)
1804    }
1805
1806    fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
1807        self.element.paint(bounds, state, cx)
1808    }
1809}
1810
1811impl<E> IntoElement for Stateful<E>
1812where
1813    E: Element,
1814{
1815    type Element = Self;
1816
1817    fn element_id(&self) -> Option<ElementId> {
1818        self.element.element_id()
1819    }
1820
1821    fn into_element(self) -> Self::Element {
1822        self
1823    }
1824}
1825
1826impl<E> ParentElement for Stateful<E>
1827where
1828    E: ParentElement,
1829{
1830    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
1831        self.element.children_mut()
1832    }
1833}
1834
1835#[derive(Default)]
1836struct ScrollHandleState {
1837    // not great to have the nested rc's...
1838    offset: Rc<RefCell<Point<Pixels>>>,
1839    bounds: Bounds<Pixels>,
1840    child_bounds: Vec<Bounds<Pixels>>,
1841    requested_scroll_top: Option<(usize, Pixels)>,
1842    overflow: Point<Overflow>,
1843}
1844
1845#[derive(Clone)]
1846pub struct ScrollHandle(Rc<RefCell<ScrollHandleState>>);
1847
1848impl ScrollHandle {
1849    pub fn new() -> Self {
1850        Self(Rc::default())
1851    }
1852
1853    pub fn offset(&self) -> Point<Pixels> {
1854        self.0.borrow().offset.borrow().clone()
1855    }
1856
1857    pub fn top_item(&self) -> usize {
1858        let state = self.0.borrow();
1859        let top = state.bounds.top() - state.offset.borrow().y;
1860
1861        match state.child_bounds.binary_search_by(|bounds| {
1862            if top < bounds.top() {
1863                Ordering::Greater
1864            } else if top > bounds.bottom() {
1865                Ordering::Less
1866            } else {
1867                Ordering::Equal
1868            }
1869        }) {
1870            Ok(ix) => ix,
1871            Err(ix) => ix.min(state.child_bounds.len().saturating_sub(1)),
1872        }
1873    }
1874
1875    pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
1876        self.0.borrow().child_bounds.get(ix).cloned()
1877    }
1878
1879    /// scroll_to_item scrolls the minimal amount to ensure that the item is
1880    /// fully visible
1881    pub fn scroll_to_item(&self, ix: usize) {
1882        let state = self.0.borrow();
1883
1884        let Some(bounds) = state.child_bounds.get(ix) else {
1885            return;
1886        };
1887
1888        let mut scroll_offset = state.offset.borrow_mut();
1889
1890        if state.overflow.y == Overflow::Scroll {
1891            if bounds.top() + scroll_offset.y < state.bounds.top() {
1892                scroll_offset.y = state.bounds.top() - bounds.top();
1893            } else if bounds.bottom() + scroll_offset.y > state.bounds.bottom() {
1894                scroll_offset.y = state.bounds.bottom() - bounds.bottom();
1895            }
1896        }
1897
1898        if state.overflow.x == Overflow::Scroll {
1899            if bounds.left() + scroll_offset.x < state.bounds.left() {
1900                scroll_offset.x = state.bounds.left() - bounds.left();
1901            } else if bounds.right() + scroll_offset.x > state.bounds.right() {
1902                scroll_offset.x = state.bounds.right() - bounds.right();
1903            }
1904        }
1905    }
1906
1907    pub fn logical_scroll_top(&self) -> (usize, Pixels) {
1908        let ix = self.top_item();
1909        let state = self.0.borrow();
1910
1911        if let Some(child_bounds) = state.child_bounds.get(ix) {
1912            (
1913                ix,
1914                child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
1915            )
1916        } else {
1917            (ix, px(0.))
1918        }
1919    }
1920
1921    pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
1922        self.0.borrow_mut().requested_scroll_top = Some((ix, px));
1923    }
1924}