Skip to main content

quiz/
quiz.rs

1// Copyright (c) 2026 John Law
2// SPDX-License-Identifier: MIT
3
4//! A tray app that asks a question each minute and on "Ask now".
5//!
6//! Run it with `cargo run -p glasskit --example quiz`.
7
8use std::time::{Duration, SystemTime};
9
10use glasskit::Ui;
11use glasskit::events::{Event, EventLoop};
12use glasskit::placement::Placement;
13use glasskit::popup::{ChoicePopup, Mark, Prompt};
14use glasskit::tray::{Icon, MenuItem, Tray};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
17enum Command {
18    AskNow,
19}
20
21fn main() -> glasskit::Result<()> {
22    let ui = Ui::new()?;
23    let mut events = EventLoop::new(&ui)?;
24    let size = Icon::tray_size();
25    let icon = Icon::from_argb(size, vec![0xFF2E_86DE; (size * size) as usize])?;
26    let mut tray = Tray::new(&events, "Quiz", &icon)?;
27    tray.set_menu(&[
28        MenuItem::command(Command::AskNow, "Ask now"),
29        MenuItem::Separator,
30        MenuItem::Quit("Quit".into()),
31    ]);
32    let mut popup = ChoicePopup::new(&ui, Placement::default())?;
33    let mut next = SystemTime::now() + Duration::from_secs(60);
34    loop {
35        match events.next(Some(next))? {
36            Event::Quit => return Ok(()),
37            Event::Deadline | Event::Command(Command::AskNow) => {
38                next = SystemTime::now() + Duration::from_secs(60);
39                if !popup.is_showing() {
40                    let prompt = Prompt::new("What is 2 + 2?", ["3", "4", "5"])
41                        .marks(|clicked| answer_marks(clicked, 1))
42                        .auto_dismiss(Some(Duration::from_secs(30)));
43                    popup.show(&prompt)?;
44                }
45            }
46            Event::Popup(id) if id == popup.id() => {
47                if let Some(reply) = popup.take_reply() {
48                    println!("{:?}", reply.response);
49                }
50            }
51            _ => {}
52        }
53    }
54}
55
56/// Mark the correct answer good and a wrong click bad.
57fn answer_marks(clicked: usize, correct: usize) -> Vec<(usize, Mark)> {
58    let mut marks = vec![(correct, Mark::Good)];
59    if clicked != correct {
60        marks.push((clicked, Mark::Bad));
61    }
62    marks
63}