mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-25 16:02:36 +00:00
The detail panel (Info / Outline / Changes / Files), the remote SFTP listing and the tab rail all scrolled with gpui's `overflow_y_scroll()`, which paints nothing: a deep file tree or a long tab list gave no hint that there was more content, or where in it you were (issue #185). Hang gpui-component's `Scrollbar` over each of those containers through one shared helper (`ui::scrollbar`). The handle stays app-owned so `scroll_to_item` keeps working — that rules out gpui-component's `overflow_y_scrollbar()`, which mints its own handle internally. Theme the bar from the active theme's own background→foreground mix ladder rather than the stock fixed greys, and keep the track transparent so the thumb floats instead of laying a slab down the panel edge. Show mode follows the platform: auto-hide on macOS (and anywhere else the OS uses overlay scrollbars), permanently visible on Windows and Linux. gpui-component's own default picks `Hover` there, which only reveals the bar within 16px of the edge — that is the "no scrollbar at all" the issue reports from Windows.
60 lines
2.6 KiB
Rust
60 lines
2.6 KiB
Rust
//! The overlay scrollbar the app's own scroll areas wear (issue #185).
|
|
//!
|
|
//! gpui's `overflow_y_scroll()` scrolls but paints nothing, so a long file tree
|
|
//! or tab list gave no hint that there was more content — or where in it you
|
|
//! were. gpui-component ships the [`Scrollbar`] element for exactly this; the
|
|
//! only thing missing was a house shape for hanging it off our containers.
|
|
//!
|
|
//! Why not gpui-component's own `overflow_y_scrollbar()` wrapper: it mints its
|
|
//! own `ScrollHandle` internally via `use_keyed_state`, which leaves nothing for
|
|
//! `scroll_to_item` to aim at. Our lists need programmatic scrolling (activating
|
|
//! a tab pulls its row into view), so the handle stays app-owned and the
|
|
//! scrollbar is layered on top of it.
|
|
//!
|
|
//! Appearance (thumb colour, whether it auto-hides) comes from the theme — see
|
|
//! the scrollbar block in [`crate::ui::theme::apply_theme`].
|
|
//!
|
|
//! One behaviour worth knowing: while the bar is live it claims mouse-downs in
|
|
//! the 16px strip along the container's right edge, so the trailing few pixels
|
|
//! of a row stop being clickable there. That is inherent to an overlay
|
|
//! scrollbar (macOS's own behave the same way) and the reason the bar is only
|
|
//! permanently live on the platforms whose scrollbars are permanently visible.
|
|
|
|
use gpui::{AnyElement, ElementId, ScrollHandle, div, prelude::*};
|
|
use gpui_component::scroll::Scrollbar;
|
|
use gpui_component::v_flex;
|
|
|
|
/// Wrap a scrolling column so a vertical scrollbar floats over its right edge.
|
|
///
|
|
/// `scroll_area` must be the element that carries `.overflow_y_scroll()` and
|
|
/// `.track_scroll(handle)`; this only adds the positioned parent the scrollbar
|
|
/// measures against and the absolute layer it paints into. The scrollbar draws
|
|
/// *over* the content rather than reserving a gutter, so adopting it never
|
|
/// reflows the wrapped list.
|
|
///
|
|
/// `id` names the scrollbar's element state (hover/drag/fade), so it must be
|
|
/// unique per scroll area — the helper can't fall back to `Location::caller`
|
|
/// the way [`Scrollbar::vertical`] does, since every call site would then share
|
|
/// this function's line.
|
|
pub(crate) fn with_vertical_scrollbar(
|
|
id: impl Into<ElementId>,
|
|
scroll_area: impl IntoElement,
|
|
handle: &ScrollHandle,
|
|
) -> AnyElement {
|
|
v_flex()
|
|
.relative()
|
|
.flex_1()
|
|
.min_h_0()
|
|
.child(scroll_area)
|
|
.child(
|
|
div()
|
|
.absolute()
|
|
.top_0()
|
|
.left_0()
|
|
.right_0()
|
|
.bottom_0()
|
|
.child(Scrollbar::vertical(handle).id(id)),
|
|
)
|
|
.into_any_element()
|
|
}
|