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