diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs index 0311c266..07f3b176 100644 --- a/crates/ui/src/popup_menu.rs +++ b/crates/ui/src/popup_menu.rs @@ -931,7 +931,7 @@ impl Render for PopupMenu { .top_0() .left_0() .right_0p5() - .bottom_0() + .bottom_0p5() .child(Scrollbar::vertical( cx.entity_id(), self.scroll_state.clone(), diff --git a/crates/ui/src/scroll/scrollbar.rs b/crates/ui/src/scroll/scrollbar.rs index 2f249989..423ac3f3 100644 --- a/crates/ui/src/scroll/scrollbar.rs +++ b/crates/ui/src/scroll/scrollbar.rs @@ -6,10 +6,10 @@ use std::{ use crate::ActiveTheme; use gpui::{ - fill, point, px, relative, App, BorderStyle, Bounds, ContentMask, CursorStyle, Edges, Element, - EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, - Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle, - Window, + fill, point, px, relative, size, App, BorderStyle, Bounds, ContentMask, Corner, CursorStyle, + Edges, Element, EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style, + UniformListScrollHandle, Window, }; use serde::{Deserialize, Serialize}; @@ -32,11 +32,18 @@ impl ScrollbarShow { } } -const BORDER_WIDTH: Pixels = px(0.); -pub(crate) const WIDTH: Pixels = px(12.); -const MIN_THUMB_SIZE: f32 = 24.; -const THUMB_RADIUS: Pixels = Pixels(4.0); -const THUMB_INSET: Pixels = Pixels(3.); +/// The width of the scrollbar (THUMB_ACTIVE_INSET * 2 + THUMB_ACTIVE_WIDTH) +pub(crate) const WIDTH: Pixels = px(2. * 2. + 8.); +const MIN_THUMB_SIZE: f32 = 48.; + +const THUMB_WIDTH: Pixels = px(6.); +const THUMB_RADIUS: Pixels = Pixels(6. / 2.); +const THUMB_INSET: Pixels = Pixels(2.); + +const THUMB_ACTIVE_WIDTH: Pixels = px(8.); +const THUMB_ACTIVE_RADIUS: Pixels = Pixels(8. / 2.); +const THUMB_ACTIVE_INSET: Pixels = Pixels(2.); + const FADE_OUT_DURATION: f32 = 3.0; const FADE_OUT_DELAY: f32 = 2.0; @@ -337,49 +344,52 @@ impl Scrollbar { self } - fn style_for_active(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels) { + fn style_for_active(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { ( cx.theme().scrollbar_thumb_hover, cx.theme().scrollbar, cx.theme().border, - THUMB_INSET - px(1.), - THUMB_RADIUS, + THUMB_ACTIVE_WIDTH, + THUMB_ACTIVE_INSET, + THUMB_ACTIVE_RADIUS, ) } - fn style_for_hovered_thumb(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels) { + fn style_for_hovered_thumb(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { ( cx.theme().scrollbar_thumb_hover, cx.theme().scrollbar, cx.theme().border, - THUMB_INSET - px(1.), - THUMB_RADIUS, + THUMB_ACTIVE_WIDTH, + THUMB_ACTIVE_INSET, + THUMB_ACTIVE_RADIUS, ) } - fn style_for_hovered_bar(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels) { - let (inset, radius) = if cx.theme().scrollbar_show.is_hover() { - (THUMB_INSET, THUMB_RADIUS - px(1.)) - } else { - (THUMB_INSET - px(1.), THUMB_RADIUS) - }; - + fn style_for_hovered_bar(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { ( cx.theme().scrollbar_thumb, cx.theme().scrollbar, gpui::transparent_black(), - inset, - radius, + THUMB_ACTIVE_WIDTH, + THUMB_ACTIVE_INSET, + THUMB_ACTIVE_RADIUS, ) } - fn style_for_idle(_: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels) { + fn style_for_idle(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels, Pixels) { + let (width, inset, radius) = match cx.theme().scrollbar_show { + ScrollbarShow::Scrolling => (THUMB_WIDTH, THUMB_INSET, THUMB_RADIUS), + _ => (THUMB_ACTIVE_WIDTH, THUMB_ACTIVE_INSET, THUMB_ACTIVE_RADIUS), + }; + ( gpui::transparent_black(), gpui::transparent_black(), gpui::transparent_black(), - THUMB_INSET, - THUMB_RADIUS - px(1.), + width, + inset, + radius, ) } } @@ -472,8 +482,9 @@ impl Element for Scrollbar { }; // The horizontal scrollbar is set avoid overlapping with the vertical scrollbar, if the vertical scrollbar is visible. + let margin_end = if has_both && !is_vertical { - WIDTH + THUMB_ACTIVE_WIDTH } else { px(0.) }; @@ -519,7 +530,7 @@ impl Element for Scrollbar { let is_hovered_on_bar = state.get().hovered_axis == Some(axis); let is_hovered_on_thumb = state.get().hovered_on_thumb == Some(axis); - let (thumb_bg, bar_bg, bar_border, inset, radius) = + let (thumb_bg, bar_bg, bar_border, thumb_width, inset, radius) = if state.get().dragged_axis == Some(axis) { Self::style_for_active(cx) } else if is_hover_to_show && (is_hovered_on_bar || is_hovered_on_thumb) { @@ -564,38 +575,34 @@ impl Element for Scrollbar { idle_state }; + // The clickable area of the thumb + let thumb_length = thumb_end - thumb_start - inset * 2; let thumb_bounds = if is_vertical { - Bounds::from_corners( - point(bounds.origin.x, bounds.origin.y + thumb_start), - point(bounds.origin.x + WIDTH, bounds.origin.y + thumb_end), + Bounds::from_corner_and_size( + Corner::TopRight, + bounds.top_right() + point(-inset, inset + thumb_start), + size(WIDTH, thumb_length), ) } else { - Bounds::from_corners( - point(bounds.origin.x + thumb_start, bounds.origin.y), - point(bounds.origin.x + thumb_end, bounds.origin.y + WIDTH), + Bounds::from_corner_and_size( + Corner::BottomLeft, + bounds.bottom_left() + point(inset + thumb_start, -inset), + size(thumb_length, WIDTH), ) }; + + // The actual render area of the thumb let thumb_fill_bounds = if is_vertical { - Bounds::from_corners( - point( - bounds.origin.x + inset + BORDER_WIDTH, - bounds.origin.y + thumb_start + inset, - ), - point( - bounds.origin.x + WIDTH - inset, - bounds.origin.y + thumb_end - inset, - ), + Bounds::from_corner_and_size( + Corner::TopRight, + bounds.top_right() + point(-inset, inset + thumb_start), + size(thumb_width, thumb_length), ) } else { - Bounds::from_corners( - point( - bounds.origin.x + thumb_start + inset, - bounds.origin.y + inset + BORDER_WIDTH, - ), - point( - bounds.origin.x + thumb_end - inset, - bounds.origin.y + WIDTH - inset, - ), + Bounds::from_corner_and_size( + Corner::BottomLeft, + bounds.bottom_left() + point(inset + thumb_start, -inset), + size(thumb_length, thumb_width), ) }; @@ -676,11 +683,11 @@ impl Element for Scrollbar { top: px(0.), right: px(0.), bottom: px(0.), - left: BORDER_WIDTH, + left: px(0.), } } else { Edges { - top: BORDER_WIDTH, + top: px(0.), right: px(0.), bottom: px(0.), left: px(0.), diff --git a/crates/ui/src/theme.rs b/crates/ui/src/theme.rs index b7fb028d..7ba81d08 100644 --- a/crates/ui/src/theme.rs +++ b/crates/ui/src/theme.rs @@ -287,7 +287,7 @@ impl ThemeColor { primary_hover: hsl(223.0, 5.9, 15.0), progress_bar: hsl(223.0, 5.9, 10.0), ring: hsl(240.0, 5.9, 65.0), - scrollbar: hsl(0., 0., 92.).opacity(0.75), + scrollbar: hsl(0., 0., 98.).opacity(0.95), scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9), scrollbar_thumb_hover: hsl(0., 0., 59.), secondary: hsl(240.0, 5.9, 96.9), @@ -380,7 +380,7 @@ impl ThemeColor { primary_hover: hsl(223.0, 0.0, 90.0), progress_bar: hsl(223.0, 0.0, 98.0), ring: hsl(240.0, 4.9, 83.9), - scrollbar: hsl(240., 1., 15.).opacity(0.75), + scrollbar: hsl(240.0, 0.0, 10.0).opacity(0.95), scrollbar_thumb: hsl(0., 0., 48.).opacity(0.9), scrollbar_thumb_hover: hsl(0., 0., 68.), secondary: hsl(240.0, 0., 13.0),