ui: Properly update scrollbar track color (#41354)

Finn Evers created

Closes https://github.com/zed-industries/zed/issues/41334

This comes down to a caching issue..

Release Notes:

- Fixed an issue where the scrollbar track color would not update in
case the theme was changed.

Change summary

crates/ui/src/components/scrollbar.rs | 45 ++++++++++++++++++----------
1 file changed, 29 insertions(+), 16 deletions(-)

Detailed changes

crates/ui/src/components/scrollbar.rs 🔗

@@ -101,13 +101,21 @@ where
     T: ScrollableHandle,
 {
     let element_id = config.id.take().unwrap_or_else(|| caller_location.into());
+    let track_color = config.track_color;
 
-    window.use_keyed_state(element_id, cx, |window, cx| {
+    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 {
@@ -334,7 +342,7 @@ enum ReservedSpace {
     #[default]
     None,
     Thumb,
-    Track(Hsla),
+    Track,
 }
 
 impl ReservedSpace {
@@ -343,14 +351,7 @@ impl ReservedSpace {
     }
 
     fn needs_scroll_track(&self) -> bool {
-        matches!(self, ReservedSpace::Track(_))
-    }
-
-    fn track_color(&self) -> Option<Hsla> {
-        match self {
-            ReservedSpace::Track(color) => Some(*color),
-            _ => None,
-        }
+        *self == ReservedSpace::Track
     }
 }
 
@@ -385,6 +386,7 @@ pub struct Scrollbars<T: ScrollableHandle = ScrollHandle> {
     tracked_entity: Option<Option<EntityId>>,
     scrollable_handle: Handle<T>,
     visibility: Point<ReservedSpace>,
+    track_color: Option<Hsla>,
     scrollbar_width: ScrollbarWidth,
 }
 
@@ -406,6 +408,7 @@ impl Scrollbars {
             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,
         }
     }
@@ -446,6 +449,7 @@ impl<ScrollHandle: ScrollableHandle> Scrollbars<ScrollHandle> {
             scrollbar_width,
             visibility,
             get_visibility,
+            track_color,
             ..
         } = self;
 
@@ -455,6 +459,7 @@ impl<ScrollHandle: ScrollableHandle> Scrollbars<ScrollHandle> {
             tracked_entity: tracked_entity_id,
             visibility,
             scrollbar_width,
+            track_color,
             get_visibility,
         }
     }
@@ -465,7 +470,8 @@ impl<ScrollHandle: ScrollableHandle> Scrollbars<ScrollHandle> {
     }
 
     pub fn with_track_along(mut self, along: ScrollAxes, background_color: Hsla) -> Self {
-        self.visibility = along.apply_to(self.visibility, ReservedSpace::Track(background_color));
+        self.visibility = along.apply_to(self.visibility, ReservedSpace::Track);
+        self.track_color = Some(background_color);
         self
     }
 
@@ -593,6 +599,7 @@ struct ScrollbarState<T: ScrollableHandle = ScrollHandle> {
     show_behavior: ShowBehavior,
     get_visibility: fn(&App) -> ShowScrollbar,
     visibility: Point<ReservedSpace>,
+    track_color: Option<Hsla>,
     show_state: VisibilityState,
     mouse_in_parent: bool,
     last_prepaint_state: Option<ScrollbarPrepaintState>,
@@ -622,6 +629,7 @@ impl<T: ScrollableHandle> ScrollbarState<T> {
             scroll_handle,
             width: config.scrollbar_width,
             visibility: config.visibility,
+            track_color: config.track_color,
             show_behavior,
             get_visibility: config.get_visibility,
             show_state: VisibilityState::from_behavior(show_behavior),
@@ -794,6 +802,10 @@ impl<T: ScrollableHandle> ScrollbarState<T> {
         }
     }
 
+    fn update_track_color(&mut self, track_color: Option<Hsla>) {
+        self.track_color = track_color;
+    }
+
     fn parent_hovered(&self, window: &Window) -> bool {
         self.last_prepaint_state
             .as_ref()
@@ -1103,8 +1115,10 @@ impl<T: ScrollableHandle> Element for ScrollbarElement<T> {
             .not()
             .then(|| ScrollbarPrepaintState {
                 thumbs: {
-                    let thumb_ranges = self.state.read(cx).thumb_ranges().collect::<Vec<_>>();
-                    let width = self.state.read(cx).width.to_pixels();
+                    let state = self.state.read(cx);
+                    let thumb_ranges = state.thumb_ranges().collect::<Vec<_>>();
+                    let width = state.width.to_pixels();
+                    let track_color = state.track_color;
 
                     let additional_padding = if thumb_ranges.len() == 2 {
                         width
@@ -1169,8 +1183,7 @@ impl<T: ScrollableHandle> Element for ScrollbarElement<T> {
                                     },
                                     HitboxBehavior::BlockMouseExceptScroll,
                                 ),
-                                track_background: reserved_space
-                                    .track_color()
+                                track_background: track_color
                                     .map(|color| (padded_bounds.dilate(SCROLLBAR_PADDING), color)),
                                 reserved_space,
                             }