scrollbar: Improve the scrollbar size. (#830)

## Idle

<img width="1086" alt="image"
src="https://github.com/user-attachments/assets/1acd847c-9ea4-477f-a1be-a9dd6305de60"
/>

## Hover

<img width="1086" alt="image"
src="https://github.com/user-attachments/assets/08a700ce-98f5-41ff-b504-37ea3cf90d81"
/>
This commit is contained in:
Jason Lee 2025-05-06 14:45:22 +08:00 committed by GitHub
parent f4e8b952e9
commit 0c6d631a39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 65 additions and 58 deletions

View file

@ -931,7 +931,7 @@ impl Render for PopupMenu {
.top_0() .top_0()
.left_0() .left_0()
.right_0p5() .right_0p5()
.bottom_0() .bottom_0p5()
.child(Scrollbar::vertical( .child(Scrollbar::vertical(
cx.entity_id(), cx.entity_id(),
self.scroll_state.clone(), self.scroll_state.clone(),

View file

@ -6,10 +6,10 @@ use std::{
use crate::ActiveTheme; use crate::ActiveTheme;
use gpui::{ use gpui::{
fill, point, px, relative, App, BorderStyle, Bounds, ContentMask, CursorStyle, Edges, Element, fill, point, px, relative, size, App, BorderStyle, Bounds, ContentMask, Corner, CursorStyle,
EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Edges, Element, EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent,
Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle, MouseUpEvent, PaintQuad, Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style,
Window, UniformListScrollHandle, Window,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -32,11 +32,18 @@ impl ScrollbarShow {
} }
} }
const BORDER_WIDTH: Pixels = px(0.); /// The width of the scrollbar (THUMB_ACTIVE_INSET * 2 + THUMB_ACTIVE_WIDTH)
pub(crate) const WIDTH: Pixels = px(12.); pub(crate) const WIDTH: Pixels = px(2. * 2. + 8.);
const MIN_THUMB_SIZE: f32 = 24.; const MIN_THUMB_SIZE: f32 = 48.;
const THUMB_RADIUS: Pixels = Pixels(4.0);
const THUMB_INSET: Pixels = Pixels(3.); 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_DURATION: f32 = 3.0;
const FADE_OUT_DELAY: f32 = 2.0; const FADE_OUT_DELAY: f32 = 2.0;
@ -337,49 +344,52 @@ impl Scrollbar {
self 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_thumb_hover,
cx.theme().scrollbar, cx.theme().scrollbar,
cx.theme().border, cx.theme().border,
THUMB_INSET - px(1.), THUMB_ACTIVE_WIDTH,
THUMB_RADIUS, 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_thumb_hover,
cx.theme().scrollbar, cx.theme().scrollbar,
cx.theme().border, cx.theme().border,
THUMB_INSET - px(1.), THUMB_ACTIVE_WIDTH,
THUMB_RADIUS, THUMB_ACTIVE_INSET,
THUMB_ACTIVE_RADIUS,
) )
} }
fn style_for_hovered_bar(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, Pixels) { fn style_for_hovered_bar(cx: &App) -> (Hsla, Hsla, Hsla, Pixels, 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)
};
( (
cx.theme().scrollbar_thumb, cx.theme().scrollbar_thumb,
cx.theme().scrollbar, cx.theme().scrollbar,
gpui::transparent_black(), gpui::transparent_black(),
inset, THUMB_ACTIVE_WIDTH,
radius, 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(), gpui::transparent_black(),
gpui::transparent_black(), gpui::transparent_black(),
THUMB_INSET, width,
THUMB_RADIUS - px(1.), 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. // 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 { let margin_end = if has_both && !is_vertical {
WIDTH THUMB_ACTIVE_WIDTH
} else { } else {
px(0.) 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_bar = state.get().hovered_axis == Some(axis);
let is_hovered_on_thumb = state.get().hovered_on_thumb == 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) { if state.get().dragged_axis == Some(axis) {
Self::style_for_active(cx) Self::style_for_active(cx)
} else if is_hover_to_show && (is_hovered_on_bar || is_hovered_on_thumb) { } else if is_hover_to_show && (is_hovered_on_bar || is_hovered_on_thumb) {
@ -564,38 +575,34 @@ impl Element for Scrollbar {
idle_state idle_state
}; };
// The clickable area of the thumb
let thumb_length = thumb_end - thumb_start - inset * 2;
let thumb_bounds = if is_vertical { let thumb_bounds = if is_vertical {
Bounds::from_corners( Bounds::from_corner_and_size(
point(bounds.origin.x, bounds.origin.y + thumb_start), Corner::TopRight,
point(bounds.origin.x + WIDTH, bounds.origin.y + thumb_end), bounds.top_right() + point(-inset, inset + thumb_start),
size(WIDTH, thumb_length),
) )
} else { } else {
Bounds::from_corners( Bounds::from_corner_and_size(
point(bounds.origin.x + thumb_start, bounds.origin.y), Corner::BottomLeft,
point(bounds.origin.x + thumb_end, bounds.origin.y + WIDTH), 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 { let thumb_fill_bounds = if is_vertical {
Bounds::from_corners( Bounds::from_corner_and_size(
point( Corner::TopRight,
bounds.origin.x + inset + BORDER_WIDTH, bounds.top_right() + point(-inset, inset + thumb_start),
bounds.origin.y + thumb_start + inset, size(thumb_width, thumb_length),
),
point(
bounds.origin.x + WIDTH - inset,
bounds.origin.y + thumb_end - inset,
),
) )
} else { } else {
Bounds::from_corners( Bounds::from_corner_and_size(
point( Corner::BottomLeft,
bounds.origin.x + thumb_start + inset, bounds.bottom_left() + point(inset + thumb_start, -inset),
bounds.origin.y + inset + BORDER_WIDTH, size(thumb_length, thumb_width),
),
point(
bounds.origin.x + thumb_end - inset,
bounds.origin.y + WIDTH - inset,
),
) )
}; };
@ -676,11 +683,11 @@ impl Element for Scrollbar {
top: px(0.), top: px(0.),
right: px(0.), right: px(0.),
bottom: px(0.), bottom: px(0.),
left: BORDER_WIDTH, left: px(0.),
} }
} else { } else {
Edges { Edges {
top: BORDER_WIDTH, top: px(0.),
right: px(0.), right: px(0.),
bottom: px(0.), bottom: px(0.),
left: px(0.), left: px(0.),

View file

@ -287,7 +287,7 @@ impl ThemeColor {
primary_hover: hsl(223.0, 5.9, 15.0), primary_hover: hsl(223.0, 5.9, 15.0),
progress_bar: hsl(223.0, 5.9, 10.0), progress_bar: hsl(223.0, 5.9, 10.0),
ring: hsl(240.0, 5.9, 65.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: hsl(0., 0., 69.).opacity(0.9),
scrollbar_thumb_hover: hsl(0., 0., 59.), scrollbar_thumb_hover: hsl(0., 0., 59.),
secondary: hsl(240.0, 5.9, 96.9), secondary: hsl(240.0, 5.9, 96.9),
@ -380,7 +380,7 @@ impl ThemeColor {
primary_hover: hsl(223.0, 0.0, 90.0), primary_hover: hsl(223.0, 0.0, 90.0),
progress_bar: hsl(223.0, 0.0, 98.0), progress_bar: hsl(223.0, 0.0, 98.0),
ring: hsl(240.0, 4.9, 83.9), 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: hsl(0., 0., 48.).opacity(0.9),
scrollbar_thumb_hover: hsl(0., 0., 68.), scrollbar_thumb_hover: hsl(0., 0., 68.),
secondary: hsl(240.0, 0., 13.0), secondary: hsl(240.0, 0., 13.0),