1use crate::bindings;
19use crate::error::{Error, Result};
20
21pub const ALIGN_CENTER: u8 = 9;
27pub const ALIGN_TOP_MID: u8 = 2;
29pub const ALIGN_TOP_LEFT: u8 = 1;
31
32pub const PART_MAIN: u32 = 0x000000;
34pub const PART_INDICATOR: u32 = 0x010000;
36
37pub const SIZE_CONTENT: i32 = 0x3FFF_FFFF;
41
42#[repr(C)]
48#[derive(Clone, Copy)]
49pub struct Color {
50 pub blue: u8,
51 pub green: u8,
52 pub red: u8,
53}
54
55impl Color {
56 pub const fn make(r: u8, g: u8, b: u8) -> Self {
58 Self {
59 blue: b,
60 green: g,
61 red: r,
62 }
63 }
64
65 pub const fn white() -> Self {
67 Self::make(255, 255, 255)
68 }
69
70 pub const fn black() -> Self {
72 Self::make(0, 0, 0)
73 }
74
75 pub fn hex(hex: u32) -> Self {
77 Self::make(
78 ((hex >> 16) & 0xFF) as u8,
79 ((hex >> 8) & 0xFF) as u8,
80 (hex & 0xFF) as u8,
81 )
82 }
83
84 pub fn palette_main(p: u32) -> Self {
88 unsafe {
89 let c = bindings::lv_palette_main(p as _);
90 core::mem::transmute(c)
91 }
92 }
93
94 fn to_raw(self) -> bindings::lv_color_t {
95 unsafe { core::mem::transmute(self) }
96 }
97}
98
99pub const PALETTE_BLUE: u32 = 6;
101
102pub fn font_montserrat_32() -> *const bindings::lv_font_t {
108 unsafe { &bindings::lv_font_montserrat_32 }
109}
110
111pub fn font_montserrat_14() -> *const bindings::lv_font_t {
113 unsafe { &bindings::lv_font_montserrat_14 }
114}
115
116pub trait Widget: Copy {
128 fn raw(self) -> *mut bindings::lv_obj_t;
133}
134
135pub trait Layout: Widget + Sized {
142 fn size(self, w: i32, h: i32) -> Self {
144 unsafe { bindings::lv_obj_set_size(self.raw(), w, h) };
145 self
146 }
147
148 fn width(self, w: i32) -> Self {
150 unsafe { bindings::lv_obj_set_width(self.raw(), w) };
151 self
152 }
153
154 fn height(self, h: i32) -> Self {
156 unsafe { bindings::lv_obj_set_height(self.raw(), h) };
157 self
158 }
159
160 fn pos(self, x: i32, y: i32) -> Self {
162 unsafe { bindings::lv_obj_set_pos(self.raw(), x, y) };
163 self
164 }
165
166 fn center(self) -> Self {
168 unsafe { bindings::lv_obj_center(self.raw()) };
169 self
170 }
171
172 fn align(self, a: u8, x_ofs: i32, y_ofs: i32) -> Self {
176 unsafe { bindings::lv_obj_align(self.raw(), a as _, x_ofs, y_ofs) };
177 self
178 }
179
180 fn hide(self) -> Self {
182 unsafe { bindings::lv_obj_add_flag(self.raw(), bindings::LV_OBJ_FLAG_HIDDEN) };
183 self
184 }
185
186 fn show(self) -> Self {
188 unsafe { bindings::lv_obj_remove_flag(self.raw(), bindings::LV_OBJ_FLAG_HIDDEN) };
189 self
190 }
191
192 fn visible(self, v: bool) -> Self {
194 if v { self.show() } else { self.hide() }
195 }
196
197 fn add_flag(self, f: u32) -> Self {
199 unsafe { bindings::lv_obj_add_flag(self.raw(), f) };
200 self
201 }
202
203 fn remove_flag(self, f: u32) -> Self {
205 unsafe { bindings::lv_obj_remove_flag(self.raw(), f) };
206 self
207 }
208
209 fn add_state(self, s: u32) -> Self {
211 unsafe { bindings::lv_obj_add_state(self.raw(), s as _) };
212 self
213 }
214
215 fn remove_state(self, s: u32) -> Self {
217 unsafe { bindings::lv_obj_remove_state(self.raw(), s as _) };
218 self
219 }
220
221 fn clickable(self, on: bool) -> Self {
223 if on {
224 self.add_flag(bindings::LV_OBJ_FLAG_CLICKABLE)
225 } else {
226 self.remove_flag(bindings::LV_OBJ_FLAG_CLICKABLE)
227 }
228 }
229}
230
231impl<T: Widget> Layout for T {}
232
233pub trait Styleable: Widget + Sized {
240 fn bg_color(self, c: Color) -> Self {
242 unsafe { bindings::lv_obj_set_style_bg_color(self.raw(), c.to_raw(), PART_MAIN) };
243 self
244 }
245
246 fn bg_opa(self, opa: u8) -> Self {
248 unsafe { bindings::lv_obj_set_style_bg_opa(self.raw(), opa, PART_MAIN) };
249 self
250 }
251
252 fn border_color(self, c: Color) -> Self {
254 unsafe { bindings::lv_obj_set_style_border_color(self.raw(), c.to_raw(), PART_MAIN) };
255 self
256 }
257
258 fn border_width(self, w: i32) -> Self {
260 unsafe { bindings::lv_obj_set_style_border_width(self.raw(), w, PART_MAIN) };
261 self
262 }
263
264 fn radius(self, r: i32) -> Self {
266 unsafe { bindings::lv_obj_set_style_radius(self.raw(), r, PART_MAIN) };
267 self
268 }
269
270 fn pad_all(self, p: i32) -> Self {
272 unsafe {
273 let r = self.raw();
274 bindings::lv_obj_set_style_pad_left(r, p, PART_MAIN);
275 bindings::lv_obj_set_style_pad_right(r, p, PART_MAIN);
276 bindings::lv_obj_set_style_pad_top(r, p, PART_MAIN);
277 bindings::lv_obj_set_style_pad_bottom(r, p, PART_MAIN);
278 }
279 self
280 }
281
282 fn pad_hor(self, p: i32) -> Self {
284 unsafe {
285 let r = self.raw();
286 bindings::lv_obj_set_style_pad_left(r, p, PART_MAIN);
287 bindings::lv_obj_set_style_pad_right(r, p, PART_MAIN);
288 }
289 self
290 }
291
292 fn pad_ver(self, p: i32) -> Self {
294 unsafe {
295 let r = self.raw();
296 bindings::lv_obj_set_style_pad_top(r, p, PART_MAIN);
297 bindings::lv_obj_set_style_pad_bottom(r, p, PART_MAIN);
298 }
299 self
300 }
301
302 fn pad_gap(self, g: i32) -> Self {
304 unsafe {
305 let r = self.raw();
306 bindings::lv_obj_set_style_pad_row(r, g, PART_MAIN);
307 bindings::lv_obj_set_style_pad_column(r, g, PART_MAIN);
308 }
309 self
310 }
311
312 fn text_color(self, c: Color) -> Self {
314 unsafe { bindings::lv_obj_set_style_text_color(self.raw(), c.to_raw(), PART_MAIN) };
315 self
316 }
317
318 fn text_font(self, f: *const bindings::lv_font_t) -> Self {
320 unsafe { bindings::lv_obj_set_style_text_font(self.raw(), f, PART_MAIN) };
321 self
322 }
323
324 fn add_style(self, style: &mut Style, selector: u32) -> Self {
326 unsafe { bindings::lv_obj_add_style(self.raw(), style.as_mut_ptr(), selector) };
327 self
328 }
329}
330
331impl<T: Widget> Styleable for T {}
332
333pub trait EventTarget: Widget + Sized {
340 fn on(self, code: bindings::lv_event_code_t, cb: bindings::lv_event_cb_t, user_data: *mut core::ffi::c_void) -> Self {
344 unsafe { bindings::lv_obj_add_event_cb(self.raw(), cb, code, user_data) };
345 self
346 }
347
348 fn on_click(self, cb: bindings::lv_event_cb_t, user_data: *mut core::ffi::c_void) -> Self {
350 self.on(bindings::LV_EVENT_CLICKED, cb, user_data)
351 }
352
353 fn on_value_changed(self, cb: bindings::lv_event_cb_t, user_data: *mut core::ffi::c_void) -> Self {
355 self.on(bindings::LV_EVENT_VALUE_CHANGED, cb, user_data)
356 }
357}
358
359impl<T: Widget> EventTarget for T {}
360
361#[derive(Clone, Copy)]
370pub struct Obj {
371 raw: *mut bindings::lv_obj_t,
372}
373
374impl Obj {
375 pub unsafe fn from_raw(raw: *mut bindings::lv_obj_t) -> Self {
380 Self { raw }
381 }
382
383 pub fn as_raw(self) -> *mut bindings::lv_obj_t {
385 self.raw
386 }
387
388 pub fn create(parent: Obj) -> Self {
390 let raw = unsafe { bindings::lv_obj_create(parent.raw) };
391 Self { raw }
392 }
393
394 pub fn del(self) {
396 unsafe { bindings::lv_obj_delete(self.raw) };
397 }
398
399 pub fn clean(self) {
401 unsafe { bindings::lv_obj_clean(self.raw) };
402 }
403
404 pub fn parent(self) -> Self {
406 Self {
407 raw: unsafe { bindings::lv_obj_get_parent(self.raw) },
408 }
409 }
410
411 pub fn child_count(self) -> u32 {
413 unsafe { bindings::lv_obj_get_child_count(self.raw) }
414 }
415
416 pub fn get_width(self) -> i32 {
418 unsafe { bindings::lv_obj_get_width(self.raw) }
419 }
420
421 pub fn get_height(self) -> i32 {
423 unsafe { bindings::lv_obj_get_height(self.raw) }
424 }
425
426 pub fn set_user_data(self, data: *mut core::ffi::c_void) -> Self {
428 unsafe { bindings::lv_obj_set_user_data(self.raw, data) };
429 self
430 }
431
432 pub fn get_user_data(self) -> *mut core::ffi::c_void {
434 unsafe { bindings::lv_obj_get_user_data(self.raw) }
435 }
436
437 pub fn set_size(self, w: i32, h: i32) {
440 unsafe { bindings::lv_obj_set_size(self.raw, w, h) };
441 }
442
443 pub fn set_pos(self, x: i32, y: i32) {
445 unsafe { bindings::lv_obj_set_pos(self.raw, x, y) };
446 }
447
448 pub fn set_style_bg_color(self, color: Color, selector: u32) {
450 unsafe { bindings::lv_obj_set_style_bg_color(self.raw, color.to_raw(), selector) };
451 }
452
453 pub fn set_style_text_color(self, color: Color, selector: u32) {
455 unsafe { bindings::lv_obj_set_style_text_color(self.raw, color.to_raw(), selector) };
456 }
457
458 pub fn set_style_radius(self, radius: i32, selector: u32) {
460 unsafe { bindings::lv_obj_set_style_radius(self.raw, radius, selector) };
461 }
462
463 pub fn set_style_text_font(self, font: *const bindings::lv_font_t, selector: u32) {
465 unsafe { bindings::lv_obj_set_style_text_font(self.raw, font, selector) };
466 }
467}
468
469impl Widget for Obj {
470 fn raw(self) -> *mut bindings::lv_obj_t {
471 self.raw
472 }
473}
474
475#[derive(Clone, Copy)]
481pub struct Label {
482 raw: *mut bindings::lv_obj_t,
483}
484
485impl Label {
486 pub fn create(parent: impl Widget) -> Self {
488 let raw = unsafe { bindings::lv_label_create(parent.raw()) };
489 Self { raw }
490 }
491
492 pub fn set_text(self, text: &[u8]) {
494 unsafe { bindings::lv_label_set_text(self.raw, text.as_ptr() as *const _) };
495 }
496
497 pub fn text(self, txt: &[u8]) -> Self {
499 unsafe { bindings::lv_label_set_text(self.raw, txt.as_ptr() as *const _) };
500 self
501 }
502
503 pub fn text_static(self, txt: &'static [u8]) -> Self {
505 unsafe { bindings::lv_label_set_text_static(self.raw, txt.as_ptr() as *const _) };
506 self
507 }
508
509 pub fn font(self, f: *const bindings::lv_font_t) -> Self {
511 unsafe { bindings::lv_obj_set_style_text_font(self.raw, f, PART_MAIN) };
512 self
513 }
514
515 pub fn color(self, c: Color) -> Self {
517 unsafe { bindings::lv_obj_set_style_text_color(self.raw, c.to_raw(), PART_MAIN) };
518 self
519 }
520}
521
522impl Widget for Label {
523 fn raw(self) -> *mut bindings::lv_obj_t {
524 self.raw
525 }
526}
527
528impl core::ops::Deref for Label {
529 type Target = Obj;
530 fn deref(&self) -> &Obj {
531 unsafe { &*(self as *const Label as *const Obj) }
533 }
534}
535
536#[derive(Clone, Copy)]
542pub struct Bar {
543 raw: *mut bindings::lv_obj_t,
544}
545
546impl Bar {
547 pub fn create(parent: impl Widget) -> Self {
549 let raw = unsafe { bindings::lv_bar_create(parent.raw()) };
550 Self { raw }
551 }
552
553 pub fn set_value(self, value: i32, anim: bool) {
555 unsafe {
556 #[allow(clippy::unnecessary_cast)]
557 bindings::lv_bar_set_value(self.raw, value, anim as _);
558 }
559 }
560
561 pub fn set_range(self, min: i32, max: i32) {
563 unsafe { bindings::lv_bar_set_range(self.raw, min, max) };
564 }
565
566 pub fn value(self, val: i32) -> Self {
568 unsafe {
569 #[allow(clippy::unnecessary_cast)]
570 bindings::lv_bar_set_value(self.raw, val, true as _);
571 }
572 self
573 }
574
575 pub fn value_anim(self, val: i32, anim: bool) -> Self {
577 unsafe {
578 #[allow(clippy::unnecessary_cast)]
579 bindings::lv_bar_set_value(self.raw, val, anim as _);
580 }
581 self
582 }
583
584 pub fn range(self, min: i32, max: i32) -> Self {
586 unsafe { bindings::lv_bar_set_range(self.raw, min, max) };
587 self
588 }
589
590 pub fn indicator_color(self, c: Color) -> Self {
592 unsafe { bindings::lv_obj_set_style_bg_color(self.raw, c.to_raw(), PART_INDICATOR) };
593 self
594 }
595
596 pub fn bar_color(self, c: Color) -> Self {
598 unsafe { bindings::lv_obj_set_style_bg_color(self.raw, c.to_raw(), PART_MAIN) };
599 self
600 }
601}
602
603impl Widget for Bar {
604 fn raw(self) -> *mut bindings::lv_obj_t {
605 self.raw
606 }
607}
608
609impl core::ops::Deref for Bar {
610 type Target = Obj;
611 fn deref(&self) -> &Obj {
612 unsafe { &*(self as *const Bar as *const Obj) }
613 }
614}
615
616#[derive(Clone, Copy)]
622pub struct Box {
623 raw: *mut bindings::lv_obj_t,
624}
625
626impl Box {
627 pub fn create(parent: impl Widget) -> Self {
629 let raw = unsafe {
630 let obj = bindings::lv_obj_create(parent.raw());
631 bindings::lv_obj_remove_flag(obj, bindings::LV_OBJ_FLAG_SCROLLABLE);
632 obj
633 };
634 Self { raw }
635 }
636}
637
638impl Widget for Box {
639 fn raw(self) -> *mut bindings::lv_obj_t {
640 self.raw
641 }
642}
643
644impl core::ops::Deref for Box {
645 type Target = Obj;
646 fn deref(&self) -> &Obj {
647 unsafe { &*(self as *const Box as *const Obj) }
648 }
649}
650
651pub fn vbox(parent: impl Widget) -> Box {
657 let b = Box::create(parent);
658 unsafe {
659 bindings::lv_obj_set_flex_flow(b.raw, bindings::LV_FLEX_FLOW_COLUMN);
660 bindings::lv_obj_set_size(b.raw, SIZE_CONTENT, SIZE_CONTENT);
661 }
662 b
663}
664
665pub fn hbox(parent: impl Widget) -> Box {
667 let b = Box::create(parent);
668 unsafe {
669 bindings::lv_obj_set_flex_flow(b.raw, bindings::LV_FLEX_FLOW_ROW);
670 bindings::lv_obj_set_size(b.raw, SIZE_CONTENT, SIZE_CONTENT);
671 }
672 b
673}
674
675pub struct Style {
681 inner: bindings::lv_style_t,
682}
683
684impl Style {
685 pub fn new() -> Self {
687 let mut s = Self {
688 inner: unsafe { core::mem::zeroed() },
689 };
690 unsafe { bindings::lv_style_init(&mut s.inner) };
691 s
692 }
693
694 pub fn as_mut_ptr(&mut self) -> *mut bindings::lv_style_t {
696 &mut self.inner
697 }
698
699 pub fn bg_color(mut self, c: Color) -> Self {
701 unsafe { bindings::lv_style_set_bg_color(&mut self.inner, c.to_raw()) };
702 self
703 }
704
705 pub fn bg_opa(mut self, opa: u8) -> Self {
707 unsafe { bindings::lv_style_set_bg_opa(&mut self.inner, opa) };
708 self
709 }
710
711 pub fn radius(mut self, r: i32) -> Self {
713 unsafe { bindings::lv_style_set_radius(&mut self.inner, r) };
714 self
715 }
716
717 pub fn border_color(mut self, c: Color) -> Self {
719 unsafe { bindings::lv_style_set_border_color(&mut self.inner, c.to_raw()) };
720 self
721 }
722
723 pub fn border_width(mut self, w: i32) -> Self {
725 unsafe { bindings::lv_style_set_border_width(&mut self.inner, w) };
726 self
727 }
728
729 pub fn pad_all(mut self, p: i32) -> Self {
731 unsafe {
732 let s = &mut self.inner;
733 bindings::lv_style_set_pad_left(s, p);
734 bindings::lv_style_set_pad_right(s, p);
735 bindings::lv_style_set_pad_top(s, p);
736 bindings::lv_style_set_pad_bottom(s, p);
737 }
738 self
739 }
740
741 pub fn text_color(mut self, c: Color) -> Self {
743 unsafe { bindings::lv_style_set_text_color(&mut self.inner, c.to_raw()) };
744 self
745 }
746
747 pub fn text_font(mut self, f: *const bindings::lv_font_t) -> Self {
749 unsafe { bindings::lv_style_set_text_font(&mut self.inner, f) };
750 self
751 }
752}
753
754impl Drop for Style {
755 fn drop(&mut self) {
756 unsafe { bindings::lv_style_reset(&mut self.inner) };
757 }
758}
759
760unsafe impl Send for Obj {}
765unsafe impl Sync for Obj {}
766unsafe impl Send for Label {}
767unsafe impl Sync for Label {}
768unsafe impl Send for Bar {}
769unsafe impl Sync for Bar {}
770unsafe impl Send for Box {}
771unsafe impl Sync for Box {}
772
773pub struct LvglGuard(());
779
780impl Drop for LvglGuard {
781 fn drop(&mut self) {
782 unsafe { bindings::ove_lvgl_unlock() };
783 }
784}
785
786pub fn init() -> Result<()> {
792 let ret = unsafe { bindings::ove_lvgl_init() };
793 Error::from_code(ret)
794}
795
796pub fn tick(ms: u32) {
798 unsafe { bindings::ove_lvgl_tick(ms) };
799}
800
801pub fn handler() {
803 unsafe { bindings::ove_lvgl_handler() };
804}
805
806pub fn lock() -> LvglGuard {
808 unsafe { bindings::ove_lvgl_lock() };
809 LvglGuard(())
810}
811
812pub fn screen_active() -> Obj {
814 let raw = unsafe { bindings::lv_screen_active() };
815 unsafe { Obj::from_raw(raw) }
816}