div.rs

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