Skip to main content

gpui_macos/
list.rs

1//! Virtualized lists retain base's sizing and scroll model.
2use crate::ActiveTheme;
3use gpui_kit::rems;
4use gpui_kit::{
5    App, Context, Div, ElementId, Entity, IntoElement, Pixels, Render, Size, Stateful, Styled,
6    Window, div, prelude::*,
7};
8use std::{ops::Range, rc::Rc};
9
10/// Each supplied size must match the corresponding row's rendered height.
11/// Only the visible range is built. Attach a base VirtualListScrollHandle to
12/// preserve scroll position and support navigation to a specific item.
13pub fn virtual_list<V: Render, R: IntoElement>(
14    view: Entity<V>,
15    id: impl Into<ElementId>,
16    sizes: Rc<Vec<Size<Pixels>>>,
17    render: impl Fn(&mut V, Range<usize>, &mut Window, &mut Context<V>) -> Vec<R> + 'static,
18    cx: &App,
19) -> gpui_kit::base::VirtualList {
20    let t = cx.macos();
21    gpui_kit::base::v_virtual_list(view, id, sizes, render)
22        .w_full()
23        .h(rems(17.5))
24        .font_family(t.font.clone())
25        .text_size(rems(0.8125))
26        .text_color(t.foreground)
27        .bg(t.background)
28}
29
30/// Overlay scrollbar for a scrollable region. Render after that region inside a
31/// relative parent, using the same handle as the scrollable content.
32pub fn scrollbar<H: gpui_kit::base::ScrollbarHandle + Clone>(
33    id: impl Into<ElementId>,
34    axis: gpui_kit::base::ScrollbarAxis,
35    handle: &H,
36    window: &Window,
37    cx: &App,
38) -> gpui_kit::base::Scrollbar {
39    let t = cx.macos();
40    gpui_kit::base::Scrollbar::new(handle)
41        .id(id)
42        .axis(axis)
43        .mode(gpui_kit::base::ScrollbarMode::Scrolling)
44        .styles(|style| {
45            style
46                .track(|track| {
47                    track
48                        .width(rems(0.5).to_pixels(window.rem_size()))
49                        .bg(t.foreground.opacity(0.))
50                })
51                .thumb(|thumb| {
52                    thumb
53                        .width(rems(0.375).to_pixels(window.rem_size()))
54                        .inset(rems(0.0625).to_pixels(window.rem_size()))
55                        .radius(rems(0.1875).to_pixels(window.rem_size()))
56                        .bg(t.foreground.opacity(0.35))
57                })
58                .thumb_hover(|thumb| thumb.bg(t.foreground.opacity(0.55)))
59                .thumb_active(|thumb| thumb.bg(t.foreground.opacity(0.7)))
60        })
61}
62
63/// Grouped content, as in System Settings. Compose rows inside this surface.
64pub fn inset_list(cx: &App) -> Div {
65    let t = cx.macos();
66    div()
67        .flex()
68        .flex_col()
69        .w_full()
70        .overflow_hidden()
71        .rounded(rems(0.75))
72        .bg(t.normal_fill())
73        .font_family(t.font.clone())
74        .text_size(rems(0.8125))
75        .text_color(t.foreground)
76}
77
78/// A composable inset row. Add a bottom separator when another row follows.
79/// A stable id allows application-owned click, focus and selection behavior.
80pub fn inset_list_row(id: impl Into<ElementId>, cx: &App) -> Stateful<Div> {
81    div()
82        .id(id)
83        .flex()
84        .items_center()
85        .justify_between()
86        .min_h(rems(2.5))
87        .px(rems(0.875))
88        .py(rems(0.5))
89        .gap(rems(0.75))
90        .border_color(cx.macos().divider())
91}