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()
.left_0()
.right_0p5()
.bottom_0()
.bottom_0p5()
.child(Scrollbar::vertical(
cx.entity_id(),
self.scroll_state.clone(),

View file

@ -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.),

View file

@ -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),