div.rs

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