170 lines · 5.7 KB · Rust
RawDownload
#![cfg_attr(target_family = "wasm", no_main)] use gpui::{    App, Bounds, Context, ListAlignment, ListState, Render, Window, WindowBounds, WindowOptions,    div, list, prelude::*, px, rgb, size,};use gpui_platform::application; const ITEM_COUNT: usize = 40;const SCROLLBAR_WIDTH: f32 = 12.; struct BottomListDemo {    list_state: ListState,} impl BottomListDemo {    fn new() -> Self {        Self {            list_state: ListState::new(ITEM_COUNT, ListAlignment::Bottom, px(500.)).measure_all(),        }    }} impl Render for BottomListDemo {    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {        let max_offset = self.list_state.max_offset_for_scrollbar().y;        let current_offset = -self.list_state.scroll_px_offset_for_scrollbar().y;         let viewport_height = self.list_state.viewport_bounds().size.height;         let raw_fraction = if max_offset > px(0.) {            current_offset / max_offset        } else {            0.        };         let total_height = viewport_height + max_offset;        let thumb_height = if total_height > px(0.) {            px(viewport_height.as_f32() * viewport_height.as_f32() / total_height.as_f32())                .max(px(30.))        } else {            px(30.)        };         let track_space = viewport_height - thumb_height;        let thumb_top = track_space * raw_fraction;         let bug_detected = raw_fraction > 1.0;         div()            .size_full()            .bg(rgb(0xFFFFFF))            .flex()            .flex_col()            .p_4()            .gap_2()            .child(                div()                    .text_sm()                    .flex()                    .flex_col()                    .gap_1()                    .child(format!(                        "offset: {:.0} / max: {:.0} | fraction: {:.3}",                        current_offset.as_f32(),                        max_offset.as_f32(),                        raw_fraction,                    ))                    .child(                        div()                            .text_color(if bug_detected {                                rgb(0xCC0000)                            } else {                                rgb(0x008800)                            })                            .child(if bug_detected {                                format!(                                    "BUG: fraction is {:.3} (> 1.0) — thumb is off-track!",                                    raw_fraction                                )                            } else {                                "OK: fraction <= 1.0 — thumb is within track.".to_string()                            }),                    ),            )            .child(                div()                    .flex_1()                    .flex()                    .flex_row()                    .overflow_hidden()                    .border_1()                    .border_color(rgb(0xCCCCCC))                    .rounded_sm()                    .child(                        list(self.list_state.clone(), |index, _window, _cx| {                            let height = px(30. + (index % 5) as f32 * 10.);                            div()                                .h(height)                                .w_full()                                .flex()                                .items_center()                                .px_3()                                .border_b_1()                                .border_color(rgb(0xEEEEEE))                                .bg(if index % 2 == 0 {                                    rgb(0xFAFAFA)                                } else {                                    rgb(0xFFFFFF)                                })                                .text_sm()                                .child(format!("Item {index}"))                                .into_any()                        })                        .flex_1(),                    )                    // Scrollbar track                    .child(                        div()                            .w(px(SCROLLBAR_WIDTH))                            .h_full()                            .flex_shrink_0()                            .bg(rgb(0xE0E0E0))                            .relative()                            .child(                                // Thumb — position is unclamped to expose the bug                                div()                                    .absolute()                                    .top(thumb_top)                                    .w_full()                                    .h(thumb_height)                                    .bg(if bug_detected {                                        rgb(0xCC0000)                                    } else {                                        rgb(0x888888)                                    })                                    .rounded_sm(),                            ),                    ),            )    }} fn run_example() {    application().run(|cx: &mut App| {        let bounds = Bounds::centered(None, size(px(400.), px(500.)), cx);        cx.open_window(            WindowOptions {                focus: true,                window_bounds: Some(WindowBounds::Windowed(bounds)),                ..Default::default()            },            |_, cx| cx.new(|_| BottomListDemo::new()),        )        .unwrap();        cx.activate(true);    });} #[cfg(not(target_family = "wasm"))]fn main() {    run_example();} #[cfg(target_family = "wasm")]#[wasm_bindgen::prelude::wasm_bindgen(start)]pub fn start() {    gpui_platform::web_init();    run_example();}