rlvgl_widgets/
checkbox.rs1use alloc::string::String;
3use rlvgl_core::draw::{draw_widget_bg, fill_rounded_rect};
4use rlvgl_core::event::Event;
5use rlvgl_core::font::{FontMetrics, WidgetFont, shape_text_ltr};
6use rlvgl_core::renderer::{ClipRenderer, Renderer};
7use rlvgl_core::style::Style;
8use rlvgl_core::widget::{Color, Rect, Widget};
9
10pub struct Checkbox {
12 bounds: Rect,
13 text: String,
14 pub style: Style,
16 pub text_color: Color,
18 pub check_color: Color,
20 checked: bool,
21 font: WidgetFont,
24}
25
26impl Checkbox {
27 pub fn new(text: impl Into<String>, bounds: Rect) -> Self {
29 Self {
30 bounds,
31 text: text.into(),
32 style: Style::default(),
33 text_color: Color(0, 0, 0, 255),
34 check_color: Color(0, 0, 0, 255),
35 checked: false,
36 font: WidgetFont::new(),
37 }
38 }
39
40 pub fn is_checked(&self) -> bool {
42 self.checked
43 }
44
45 pub fn set_checked(&mut self, value: bool) {
47 self.checked = value;
48 }
49
50 pub fn set_font(&mut self, font: &'static dyn FontMetrics) {
53 self.font.set(font);
54 }
55}
56
57impl Widget for Checkbox {
58 fn bounds(&self) -> Rect {
59 self.bounds
60 }
61
62 fn widget_font_mut(&mut self) -> Option<&mut WidgetFont> {
63 Some(&mut self.font)
64 }
65
66 fn draw(&self, renderer: &mut dyn Renderer) {
67 let a = self.style.alpha;
68 let r = self.style.radius;
69 draw_widget_bg(renderer, self.bounds, &self.style);
71
72 let square_size = 10;
74 let box_rect = Rect {
75 x: self.bounds.x,
76 y: self.bounds.y,
77 width: square_size,
78 height: square_size,
79 };
80 fill_rounded_rect(renderer, box_rect, self.style.border_color.with_alpha(a), r);
81
82 if self.checked {
83 let inner = Rect {
84 x: box_rect.x + 2,
85 y: box_rect.y + 2,
86 width: box_rect.width - 4,
87 height: box_rect.height - 4,
88 };
89 fill_rounded_rect(renderer, inner, self.check_color.with_alpha(a), r);
90 }
91
92 let text_origin = (
94 self.bounds.x + square_size + 4,
95 self.bounds.y + self.bounds.height,
96 );
97 let clip = Rect {
98 x: text_origin.0,
99 y: self.bounds.y,
100 width: self.bounds.width - (square_size + 4),
101 height: self.bounds.height,
102 };
103 let font = self.font.resolve();
104 let shaped = shape_text_ltr(font, &self.text, text_origin, 0);
105 let mut clipped = ClipRenderer::new(renderer, clip);
106 clipped.draw_text_shaped(&shaped, (0, 0), self.text_color.with_alpha(a));
107 }
108
109 fn handle_event(&mut self, event: &Event) -> bool {
111 if let Event::PressRelease { x, y } = event {
112 let inside = *x >= self.bounds.x
113 && *x < self.bounds.x + self.bounds.width
114 && *y >= self.bounds.y
115 && *y < self.bounds.y + self.bounds.height;
116 if inside {
117 self.checked = !self.checked;
118 return true;
119 }
120 }
121 false
122 }
123}