Skip to main content

scrollbar/
scrollbar.rs

1//! scrollbar — demonstrates the default-on scrollbar thumb.
2//!
3//! Three side-by-side scrollables in a row:
4//!
5//! - `scroll(...)` — overflowing list, default-on thumb visible.
6//! - `virtual_list(...)` — 200 rows in a 240px viewport; thumb scales
7//!   to viewport/content ratio.
8//! - `scroll(...).no_scrollbar()` — same content as the first, but
9//!   author opted out: no thumb.
10//!
11//! Inspect `out/scrollbar.draw_ops.txt` — the first two scrollables
12//! emit a `Quad shader=stock::rounded_rect ... id=root....scrollbar-thumb`
13//! after their children; the third does not. The SVG fallback paints
14//! the same rounded thumb rect.
15//!
16//! Run: `cargo run -p aetna-core --example scrollbar`
17
18use aetna_core::prelude::*;
19
20fn list_rows() -> Vec<El> {
21    (0..40)
22        .map(|i| {
23            row([
24                text(format!("{i:02}.")).mono().muted(),
25                text(format!("scrollable list item {i}")),
26            ])
27            .gap(tokens::SPACE_2)
28            .padding(Sides::xy(tokens::SPACE_2, tokens::SPACE_1))
29            .height(Size::Fixed(28.0))
30            .align(Align::Center)
31        })
32        .collect()
33}
34
35fn fixture() -> El {
36    column([
37        h2("Scrollbar"),
38        text("scroll() and virtual_list() show a draggable thumb by default.").muted(),
39        row([
40            // 1) scroll() — default-on scrollbar.
41            column([
42                text("scroll() — default").bold(),
43                scroll(list_rows())
44                    .height(Size::Fixed(240.0))
45                    .padding(tokens::SPACE_2)
46                    .stroke(tokens::BORDER)
47                    .stroke_width(1.0)
48                    .radius(tokens::RADIUS_MD),
49            ])
50            .gap(tokens::SPACE_2)
51            .width(Size::Fill(1.0))
52            .height(Size::Hug),
53            // 2) virtual_list — thumb scales to content size.
54            column([
55                text("virtual_list(200, 28)").bold(),
56                virtual_list(200, 28.0, |i| {
57                    row([
58                        text(format!("{i:03}")).mono().muted(),
59                        text(format!("row {i}")),
60                    ])
61                    .gap(tokens::SPACE_2)
62                    .padding(Sides::xy(tokens::SPACE_2, tokens::SPACE_1))
63                    .height(Size::Fixed(28.0))
64                    .align(Align::Center)
65                })
66                .height(Size::Fixed(240.0))
67                .padding(tokens::SPACE_2)
68                .stroke(tokens::BORDER)
69                .stroke_width(1.0)
70                .radius(tokens::RADIUS_MD),
71            ])
72            .gap(tokens::SPACE_2)
73            .width(Size::Fill(1.0))
74            .height(Size::Hug),
75            // 3) Opt-out: same content, no thumb.
76            column([
77                text("scroll().no_scrollbar()").bold(),
78                scroll(list_rows())
79                    .no_scrollbar()
80                    .height(Size::Fixed(240.0))
81                    .padding(tokens::SPACE_2)
82                    .stroke(tokens::BORDER)
83                    .stroke_width(1.0)
84                    .radius(tokens::RADIUS_MD),
85            ])
86            .gap(tokens::SPACE_2)
87            .width(Size::Fill(1.0))
88            .height(Size::Hug),
89        ])
90        .gap(tokens::SPACE_4)
91        .width(Size::Fill(1.0)),
92    ])
93    .gap(tokens::SPACE_4)
94    .padding(tokens::SPACE_7)
95}
96
97fn main() -> std::io::Result<()> {
98    let mut root = fixture();
99
100    let viewport = Rect::new(0.0, 0.0, 960.0, 360.0);
101    let bundle = render_bundle(&mut root, viewport);
102
103    let out_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("out");
104    let written = write_bundle(&bundle, &out_dir, "scrollbar")?;
105    for p in &written {
106        println!("wrote {}", p.display());
107    }
108
109    if !bundle.lint.findings.is_empty() {
110        eprintln!("\nlint findings ({}):", bundle.lint.findings.len());
111        eprint!("{}", bundle.lint.text());
112    }
113
114    Ok(())
115}