Skip to main content

slt/context/
widget.rs

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