1466 lines · 46.9 KB · Rust
RawDownload
use std::{    any::Any,    fmt::Debug,    ops::Not,    time::{Duration, Instant},}; use gpui::{    Along, App, AppContext as _, Axis as ScrollbarAxis, BorderStyle, Bounds, ContentMask, Context,    Corner, Corners, CursorStyle, DispatchPhase, Div, Edges, Element, ElementId, Entity, EntityId,    GlobalElementId, Hitbox, HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero,    LayoutId, ListState, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Negate,    ParentElement, Pixels, Point, Position, Render, ScrollHandle, ScrollWheelEvent, Size, Stateful,    StatefulInteractiveElement, Style, Styled, Task, UniformListDecoration,    UniformListScrollHandle, Window, ease_in_out, prelude::FluentBuilder as _, px, quad, relative,    size,};use settings::SettingsStore;use smallvec::SmallVec;use theme::ActiveTheme as _;use util::ResultExt; use std::ops::Range; use crate::scrollbars::{ScrollbarAutoHide, ScrollbarVisibility, ShowScrollbar}; const SCROLLBAR_HIDE_DELAY_INTERVAL: Duration = Duration::from_secs(1);const SCROLLBAR_HIDE_DURATION: Duration = Duration::from_millis(400);const SCROLLBAR_SHOW_DURATION: Duration = Duration::from_millis(50); const SCROLLBAR_PADDING: Pixels = px(4.); pub mod scrollbars {    use gpui::{App, Global};    use schemars::JsonSchema;    use serde::{Deserialize, Serialize};    use settings::Settings;     /// When to show the scrollbar in the editor.    ///    /// Default: auto    #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]    #[serde(rename_all = "snake_case")]    pub enum ShowScrollbar {        /// Show the scrollbar if there's important information or        /// follow the system's configured behavior.        #[default]        Auto,        /// Match the system's configured behavior.        System,        /// Always show the scrollbar.        Always,        /// Never show the scrollbar.        Never,    }     impl From<settings::ShowScrollbar> for ShowScrollbar {        fn from(value: settings::ShowScrollbar) -> Self {            match value {                settings::ShowScrollbar::Auto => ShowScrollbar::Auto,                settings::ShowScrollbar::System => ShowScrollbar::System,                settings::ShowScrollbar::Always => ShowScrollbar::Always,                settings::ShowScrollbar::Never => ShowScrollbar::Never,            }        }    }     pub trait GlobalSetting {        fn get_value(cx: &App) -> &Self;    }     impl<T: Settings> GlobalSetting for T {        fn get_value(cx: &App) -> &T {            T::get_global(cx)        }    }     pub trait ScrollbarVisibility: GlobalSetting + 'static {        fn visibility(&self, cx: &App) -> ShowScrollbar;    }     #[derive(Default)]    pub struct ScrollbarAutoHide(pub bool);     impl ScrollbarAutoHide {        pub fn should_hide(&self) -> bool {            self.0        }    }     impl Global for ScrollbarAutoHide {}} fn get_scrollbar_state<T>(    mut config: Scrollbars<T>,    caller_location: &'static std::panic::Location,    window: &mut Window,    cx: &mut App,) -> Entity<ScrollbarStateWrapper<T>>where    T: ScrollableHandle,{    let element_id = config.id.take().unwrap_or_else(|| caller_location.into());    let track_color = config.track_color;     let state = window.use_keyed_state(element_id, cx, |window, cx| {        let parent_id = cx.entity_id();        ScrollbarStateWrapper(            cx.new(|cx| ScrollbarState::new_from_config(config, parent_id, window, cx)),        )    });     state.update(cx, |state, cx| {        state            .0            .update(cx, |state, _cx| state.update_track_color(track_color))    });    state} pub trait WithScrollbar: Sized {    type Output;     fn custom_scrollbars<T>(        self,        config: Scrollbars<T>,        window: &mut Window,        cx: &mut App,    ) -> Self::Output    where        T: ScrollableHandle;     // TODO: account for these cases properly    // #[track_caller]    // fn horizontal_scrollbar(self, window: &mut Window, cx: &mut App) -> Self::Output {    //     self.custom_scrollbars(    //         Scrollbars::new(ScrollAxes::Horizontal).ensure_id(core::panic::Location::caller()),    //         window,    //         cx,    //     )    // }     // #[track_caller]    // fn vertical_scrollbar(self, window: &mut Window, cx: &mut App) -> Self::Output {    //     self.custom_scrollbars(    //         Scrollbars::new(ScrollAxes::Vertical).ensure_id(core::panic::Location::caller()),    //         window,    //         cx,    //     )    // }     #[track_caller]    fn vertical_scrollbar_for<ScrollHandle: ScrollableHandle + Clone>(        self,        scroll_handle: &ScrollHandle,        window: &mut Window,        cx: &mut App,    ) -> Self::Output {        self.custom_scrollbars(            Scrollbars::new(ScrollAxes::Vertical)                .tracked_scroll_handle(scroll_handle)                .ensure_id(core::panic::Location::caller()),            window,            cx,        )    }} impl WithScrollbar for Stateful<Div> {    type Output = Self;     #[track_caller]    fn custom_scrollbars<T>(        self,        config: Scrollbars<T>,        window: &mut Window,        cx: &mut App,    ) -> Self::Output    where        T: ScrollableHandle,    {        render_scrollbar(            get_scrollbar_state(config, std::panic::Location::caller(), window, cx),            self,            cx,        )    }} impl WithScrollbar for Div {    type Output = Stateful<Div>;     #[track_caller]    fn custom_scrollbars<T>(        self,        config: Scrollbars<T>,        window: &mut Window,        cx: &mut App,    ) -> Self::Output    where        T: ScrollableHandle,    {        let scrollbar = get_scrollbar_state(config, std::panic::Location::caller(), window, cx);        // We know this ID stays consistent as long as the element is rendered for        // consecutive frames, which is sufficient for our use case here        let scrollbar_entity_id = scrollbar.entity_id();         render_scrollbar(            scrollbar,            self.id(("track-scroll", scrollbar_entity_id)),            cx,        )    }} fn render_scrollbar<T>(    scrollbar: Entity<ScrollbarStateWrapper<T>>,    div: Stateful<Div>,    cx: &App,) -> Stateful<Div>where    T: ScrollableHandle,{    let state = &scrollbar.read(cx).0;     div.when_some(state.read(cx).handle_to_track(), |this, handle| {        this.track_scroll(handle).when_some(            state.read(cx).visible_axes(),            |this, axes| match axes {                ScrollAxes::Horizontal => this.overflow_x_scroll(),                ScrollAxes::Vertical => this.overflow_y_scroll(),                ScrollAxes::Both => this.overflow_scroll(),            },        )    })    .when_some(        state            .read(cx)            .space_to_reserve_for(ScrollbarAxis::Horizontal),        |this, space| this.pb(space),    )    .when_some(        state.read(cx).space_to_reserve_for(ScrollbarAxis::Vertical),        |this, space| this.pr(space),    )    .child(state.clone())} impl<T: ScrollableHandle> UniformListDecoration for ScrollbarStateWrapper<T> {    fn compute(        &self,        _visible_range: Range<usize>,        _bounds: Bounds<Pixels>,        scroll_offset: Point<Pixels>,        _item_height: Pixels,        _item_count: usize,        _window: &mut Window,        _cx: &mut App,    ) -> gpui::AnyElement {        ScrollbarElement {            origin: scroll_offset.negate(),            state: self.0.clone(),        }        .into_any()    }} // impl WithScrollbar for UniformList {//     type Output = Self; //     #[track_caller]//     fn custom_scrollbars<S, T>(//         self,//         config: Scrollbars<S, T>,//         window: &mut Window,//         cx: &mut App,//     ) -> Self::Output//     where//         S: ScrollbarVisibilitySetting,//         T: ScrollableHandle,//     {//         let scrollbar = get_scrollbar_state(config, std::panic::Location::caller(), window, cx);//         self.when_some(//             scrollbar.read_with(cx, |wrapper, cx| {//                 wrapper//                     .0//                     .read(cx)//                     .handle_to_track::<UniformListScrollHandle>()//                     .cloned()//             }),//             |this, handle| this.track_scroll(handle),//         )//         .with_decoration(scrollbar)//     }// } #[derive(Copy, Clone, PartialEq, Eq)]enum ShowBehavior {    Always,    Autohide,    Never,} impl ShowBehavior {    fn from_setting(setting: ShowScrollbar, cx: &mut App) -> Self {        match setting {            ShowScrollbar::Never => Self::Never,            ShowScrollbar::Auto => Self::Autohide,            ShowScrollbar::System => {                if cx.default_global::<ScrollbarAutoHide>().should_hide() {                    Self::Autohide                } else {                    Self::Always                }            }            ShowScrollbar::Always => Self::Always,        }    }} pub enum ScrollAxes {    Horizontal,    Vertical,    Both,} impl ScrollAxes {    fn apply_to<T>(self, point: Point<T>, value: T) -> Point<T>    where        T: Debug + Default + PartialEq + Clone,    {        match self {            Self::Horizontal => point.apply_along(ScrollbarAxis::Horizontal, |_| value),            Self::Vertical => point.apply_along(ScrollbarAxis::Vertical, |_| value),            Self::Both => Point::new(value.clone(), value),        }    }} #[derive(Clone, Debug, Default, PartialEq)]enum ReservedSpace {    #[default]    None,    Thumb,    Track,} impl ReservedSpace {    fn is_visible(&self) -> bool {        *self != ReservedSpace::None    }     fn needs_scroll_track(&self) -> bool {        *self == ReservedSpace::Track    }} #[derive(Debug, Default, Clone, Copy)]enum ScrollbarWidth {    #[default]    Normal,    Small,    XSmall,} impl ScrollbarWidth {    fn to_pixels(&self) -> Pixels {        match self {            ScrollbarWidth::Normal => px(8.),            ScrollbarWidth::Small => px(6.),            ScrollbarWidth::XSmall => px(4.),        }    }} #[derive(Clone)]enum Handle<T: ScrollableHandle> {    Tracked(T),    Untracked(fn() -> T),} #[derive(Clone)]pub struct Scrollbars<T: ScrollableHandle = ScrollHandle> {    id: Option<ElementId>,    get_visibility: fn(&App) -> ShowScrollbar,    tracked_entity: Option<Option<EntityId>>,    scrollable_handle: Handle<T>,    visibility: Point<ReservedSpace>,    track_color: Option<Hsla>,    scrollbar_width: ScrollbarWidth,} impl Scrollbars {    pub fn new(show_along: ScrollAxes) -> Self {        Self::new_with_setting(show_along, |_| ShowScrollbar::default())    }     pub fn for_settings<S: ScrollbarVisibility>() -> Scrollbars {        Scrollbars::new_with_setting(ScrollAxes::Both, |cx| S::get_value(cx).visibility(cx))    }} impl Scrollbars {    fn new_with_setting(show_along: ScrollAxes, get_visibility: fn(&App) -> ShowScrollbar) -> Self {        Self {            id: None,            get_visibility,            scrollable_handle: Handle::Untracked(ScrollHandle::new),            tracked_entity: None,            visibility: show_along.apply_to(Default::default(), ReservedSpace::Thumb),            track_color: None,            scrollbar_width: ScrollbarWidth::Normal,        }    }} impl<ScrollHandle: ScrollableHandle> Scrollbars<ScrollHandle> {    pub fn id(mut self, id: impl Into<ElementId>) -> Self {        self.id = Some(id.into());        self    }     fn ensure_id(mut self, id: impl Into<ElementId>) -> Self {        if self.id.is_none() {            self.id = Some(id.into());        }        self    }     /// Notify the current context whenever this scrollbar gets a scroll event    pub fn notify_content(mut self) -> Self {        self.tracked_entity = Some(None);        self    }     /// Set a parent model which should be notified whenever this scrollbar gets a scroll event.    pub fn tracked_entity(mut self, entity_id: EntityId) -> Self {        self.tracked_entity = Some(Some(entity_id));        self    }     pub fn tracked_scroll_handle<TrackedHandle: ScrollableHandle>(        self,        tracked_scroll_handle: &TrackedHandle,    ) -> Scrollbars<TrackedHandle> {        let Self {            id,            tracked_entity: tracked_entity_id,            scrollbar_width,            visibility,            get_visibility,            track_color,            ..        } = self;         Scrollbars {            scrollable_handle: Handle::Tracked(tracked_scroll_handle.clone()),            id,            tracked_entity: tracked_entity_id,            visibility,            scrollbar_width,            track_color,            get_visibility,        }    }     pub fn show_along(mut self, along: ScrollAxes) -> Self {        self.visibility = along.apply_to(self.visibility, ReservedSpace::Thumb);        self    }     pub fn with_track_along(mut self, along: ScrollAxes, background_color: Hsla) -> Self {        self.visibility = along.apply_to(self.visibility, ReservedSpace::Track);        self.track_color = Some(background_color);        self    }     pub fn width_sm(mut self) -> Self {        self.scrollbar_width = ScrollbarWidth::Small;        self    }     pub fn width_xs(mut self) -> Self {        self.scrollbar_width = ScrollbarWidth::XSmall;        self    }} #[derive(PartialEq, Clone, Debug)]enum VisibilityState {    Visible,    Animating { showing: bool, delta: f32 },    Hidden,    Disabled,} const DELTA_MAX: f32 = 1.0; impl VisibilityState {    fn from_behavior(behavior: ShowBehavior) -> Self {

Lines 1–500 of 1466.