div.rs

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