Skip to main content

gallery/
gallery.rs

1// Copyright (c) 2026 John Law
2// SPDX-License-Identifier: MIT
3
4//! Show one kind of popup, by name, until it ends. CI takes a picture of each kind.
5//!
6//! Run it with `cargo run -p glasskit --example gallery -- <kind>`. With no kind, it lists
7//! the kinds.
8
9use std::time::Duration;
10
11use glasskit::Ui;
12use glasskit::placement::Placement;
13use glasskit::popup::{ChoicePopup, Image, Prompt};
14
15/// The kinds of popup. "stack" shows two popups at once: the second goes above the first.
16const KINDS: &[&str] = &["plain", "countdown", "markup", "stack", "image", "input"];
17
18fn prompt(kind: &str) -> Option<Prompt> {
19    Some(match kind {
20        "plain" => Prompt::new("Which planet is the largest?", ["Mars", "Jupiter", "Venus"]),
21        "countdown" => Prompt::new("Take a short break?", ["Yes", "Later"])
22            .dismiss_label("Skip")
23            .auto_dismiss(Some(Duration::from_secs(90))),
24        "input" => Prompt::new("How do you write 'remember' in Chinese?", [] as [&str; 0])
25            .input("Type the answer")
26            .dismiss_label("Skip"),
27        "image" => {
28            Prompt::new("Which shape is this?", ["Circle", "Square", "Ring"]).image(ring(160))
29        }
30        "stack" => Prompt::new("And a second question?", ["Yes", "No"]),
31        "markup" => Prompt::new(
32            "What does **`git stash`** do with your *uncommitted* changes?",
33            ["Saves them aside", "Deletes them", "Commits them"],
34        )
35        .markup(),
36        _ => return None,
37    })
38}
39
40fn main() -> glasskit::Result<()> {
41    let kind = std::env::args().nth(1).unwrap_or_default();
42    let Some(prompt) = prompt(&kind) else {
43        println!("kinds: {}", KINDS.join(", "));
44        return Ok(());
45    };
46    let ui = Ui::new()?;
47    let mut first = ChoicePopup::new(&ui, Placement::default())?;
48    if kind == "stack" {
49        first.show(&Prompt::new("A first question?", ["Yes", "No"]))?;
50    }
51    let mut popup = ChoicePopup::new(&ui, Placement::default())?;
52    println!("{:?}", popup.ask(&prompt)?.response);
53    Ok(())
54}
55
56/// A blue ring on a clear background, `size` pixels square.
57fn ring(size: u32) -> Image {
58    let center = size as f32 / 2.0;
59    let (outer, inner) = (center - 2.0, center * 0.55);
60    let pixels: Vec<u32> = (0..size * size)
61        .map(|i| {
62            let (x, y) = ((i % size) as f32 + 0.5, (i / size) as f32 + 0.5);
63            let d = ((x - center).powi(2) + (y - center).powi(2)).sqrt();
64            let alpha = (outer - d + 0.5).clamp(0.0, 1.0) * (d - inner + 0.5).clamp(0.0, 1.0);
65            ((alpha * 255.0) as u32) << 24 | 0x002E_86DE
66        })
67        .collect();
68    Image::from_argb(size, size, &pixels).expect("the size matches the pixels")
69}