Skip to main content

slt/context/
widget.rs

1use super::*;
2
3/// Trait for creating custom widgets.
4///
5/// Implement this trait to build reusable, composable widgets with full access
6/// to the [`Context`] API — focus, events, theming, layout, and mouse interaction.
7/// Choose `Self::Response` based on what the widget needs to report:
8/// `()` for pure display, `bool` for simple changed/not-changed signals,
9/// or [`Response`] for click/hover/focus-aware interaction.
10///
11/// # Examples
12///
13/// A simple rating widget:
14///
15/// ```no_run
16/// use slt::{Context, Widget, Color};
17///
18/// struct Rating {
19///     value: u8,
20///     max: u8,
21/// }
22///
23/// impl Rating {
24///     fn new(value: u8, max: u8) -> Self {
25///         Self { value, max }
26///     }
27/// }
28///
29/// impl Widget for Rating {
30///     type Response = bool;
31///
32///     fn ui(&mut self, ui: &mut Context) -> bool {
33///         let focused = ui.register_focusable();
34///         let mut changed = false;
35///
36///         if focused {
37///             if ui.key('+') && self.value < self.max {
38///                 self.value += 1;
39///                 changed = true;
40///             }
41///             if ui.key('-') && self.value > 0 {
42///                 self.value -= 1;
43///                 changed = true;
44///             }
45///         }
46///
47///         let stars: String = (0..self.max).map(|i| {
48///             if i < self.value { '★' } else { '☆' }
49///         }).collect();
50///
51///         let color = if focused { Color::Yellow } else { Color::White };
52///         ui.styled(stars, slt::Style::new().fg(color));
53///
54///         changed
55///     }
56/// }
57///
58/// fn main() -> std::io::Result<()> {
59///     let mut rating = Rating::new(3, 5);
60///     slt::run(|ui| {
61///         if ui.key('q') { ui.quit(); }
62///         ui.text("Rate this:");
63///         ui.widget(&mut rating);
64///     })
65/// }
66/// ```
67pub trait Widget {
68    /// The value returned after rendering. Use `()` for widgets with no return,
69    /// `bool` for widgets that report changes, or [`Response`] for click/hover.
70    type Response;
71
72    /// Render the widget into the given context.
73    ///
74    /// Use [`Context::register_focusable`] to participate in Tab focus cycling,
75    /// [`Context::key`] / [`Context::key_code`] to handle keyboard input,
76    /// and [`Context::interaction`] to detect clicks and hovers.
77    fn ui(&mut self, ctx: &mut Context) -> Self::Response;
78}