1use alloc::{boxed::Box, string::String};
3use rlvgl_core::event::Event;
4use rlvgl_core::renderer::Renderer;
5use rlvgl_core::widget::{Rect, Widget};
6
7use crate::label::Label;
8use rlvgl_core::style::Style;
9
10type ClickHandler = Box<dyn FnMut(&mut Button)>;
11
12pub struct Button {
14 bounds: Rect,
16 label: Label,
17 on_click: Option<ClickHandler>,
18}
19
20impl Button {
21 pub fn new(text: impl Into<String>, bounds: Rect) -> Self {
23 Self {
24 bounds,
25 label: Label::new(text, bounds),
26 on_click: None,
27 }
28 }
29
30 pub fn style(&self) -> &Style {
32 &self.label.style
33 }
34
35 pub fn style_mut(&mut self) -> &mut Style {
37 &mut self.label.style
38 }
39
40 pub fn set_text(&mut self, text: impl Into<String>) {
42 self.label.set_text(text);
43 }
44
45 pub fn text(&self) -> &str {
47 self.label.text()
48 }
49
50 pub fn set_on_click<F: FnMut(&mut Self) + 'static>(&mut self, handler: F) {
52 self.on_click = Some(Box::new(handler));
53 }
54
55 fn inside_bounds(&self, x: i32, y: i32) -> bool {
57 let b = self.bounds;
58 x >= b.x && x < b.x + b.width && y >= b.y && y < b.y + b.height
59 }
60}
61
62impl Widget for Button {
63 fn bounds(&self) -> Rect {
64 self.bounds
65 }
66
67 fn draw(&self, renderer: &mut dyn Renderer) {
68 self.label.draw(renderer);
69 }
70
71 fn handle_event(&mut self, event: &Event) -> bool {
73 match event {
74 Event::PressRelease { x, y } if self.inside_bounds(*x, *y) => {
75 if let Some(mut cb) = self.on_click.take() {
76 cb(self);
77 self.on_click = Some(cb);
78 }
79 return true;
80 }
81 _ => {}
82 }
83 false
84 }
85}