From b00c3c35ed994dc8ecb2e7e7a904476079cf2374 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 12 Apr 2025 18:46:14 +0200 Subject: [PATCH 01/19] Fix examples --- examples/animation.rs | 6 +++--- examples/arc.rs | 4 ++-- examples/bar.rs | 4 ++-- examples/button_click.rs | 6 +++--- examples/rust_timer.rs | 20 ++++++++++---------- examples/sdl.rs | 6 +++--- lvgl/src/functions.rs | 4 ++-- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/animation.rs b/examples/animation.rs index 3d15f1f7..d21963cf 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -52,7 +52,7 @@ fn main() -> Result<(), LvError> { button.set_align(Align::LeftMid, 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; - btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str())?; + btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); let mut btn_state = false; @@ -66,10 +66,10 @@ fn main() -> Result<(), LvError> { if let lvgl::Event::Clicked = event { if btn_state { let nt = CString::new("Click me!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } else { let nt = CString::new("Clicked!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } btn_state = !btn_state; } diff --git a/examples/arc.rs b/examples/arc.rs index 8e10b86a..e9b98944 100644 --- a/examples/arc.rs +++ b/examples/arc.rs @@ -62,7 +62,7 @@ fn main() -> Result<(), LvError> { arc.set_end_angle(135); let mut loading_lbl = Label::create(&mut screen)?; - loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?; + loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); loading_lbl.set_align(Align::OutTopMid, 0, 0); //loading_lbl.set_label_align(LabelAlign::Center)?; @@ -82,7 +82,7 @@ fn main() -> Result<(), LvError> { println!("mem info running: {:?}", mem_info()); } angle = if forward { angle + 1 } else { angle - 1 }; - arc.set_end_angle(angle + 135)?; + arc.set_end_angle(angle + 135); i += 1; lvgl::task_handler(); diff --git a/examples/bar.rs b/examples/bar.rs index 9012f599..ca202f93 100644 --- a/examples/bar.rs +++ b/examples/bar.rs @@ -39,7 +39,7 @@ fn main() -> Result<(), LvError> { let mut bar = Bar::create(&mut screen)?; bar.set_size(175, 20); bar.set_align(Align::Center, 0, 10); - bar.set_range(0, 100)?; + bar.set_range(0, 100); bar.on_event(|_b, _e| { println!("Completed!"); })?; @@ -50,7 +50,7 @@ fn main() -> Result<(), LvError> { bar.add_style(Part::Any, &mut ind_style); let mut loading_lbl = Label::create(&mut screen)?; - loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?; + loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); loading_lbl.set_align(Align::OutTopMid, 0, 0); let mut loading_style = Style::default(); diff --git a/examples/button_click.rs b/examples/button_click.rs index 30c0a4c1..f57e2566 100644 --- a/examples/button_click.rs +++ b/examples/button_click.rs @@ -51,7 +51,7 @@ fn main() -> Result<(), LvError> { button.set_align(Align::LeftMid, 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; - btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str())?; + btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); let mut btn_state = false; button.on_event(|_btn, event| { @@ -59,10 +59,10 @@ fn main() -> Result<(), LvError> { if let lvgl::Event::Clicked = event { if btn_state { let nt = CString::new("Click me!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } else { let nt = CString::new("Clicked!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } btn_state = !btn_state; } diff --git a/examples/rust_timer.rs b/examples/rust_timer.rs index 6a26464b..7265aaf4 100644 --- a/examples/rust_timer.rs +++ b/examples/rust_timer.rs @@ -53,13 +53,13 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((255, 255, 255))); screen_style.set_radius(0); - screen.add_style(Part::Main, &mut screen_style)?; + screen.add_style(Part::Main, &mut screen_style); // Create the bar object let mut bar = Bar::create(&mut screen)?; - bar.set_size(175, 20)?; - bar.set_align(Align::Center, 0, 10)?; - bar.set_range(0, 100)?; + bar.set_size(175, 20); + bar.set_align(Align::Center, 0, 10); + bar.set_range(0, 100); bar.on_event(|_b, _e| { println!("Completed!"); })?; @@ -67,24 +67,24 @@ fn main() -> Result<(), LvError> { // Set the indicator style for the bar object let mut ind_style = Style::default(); ind_style.set_bg_color(Color::from_rgb((100, 245, 100))); - bar.add_style(Part::Any, &mut ind_style)?; + bar.add_style(Part::Any, &mut ind_style); let mut loading_lbl = Label::create(&mut screen)?; - loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?; - loading_lbl.set_align(Align::OutTopMid, 0, 0)?; + loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); + loading_lbl.set_align(Align::OutTopMid, 0, 0); let mut loading_style = Style::default(); loading_style.set_text_color(Color::from_rgb((0, 0, 0))); - loading_lbl.add_style(Part::Main, &mut loading_style)?; + loading_lbl.add_style(Part::Main, &mut loading_style); let mut i = 0; let clock = Clock::default(); 'running: loop { if i > 100 { i = 0; - lvgl::event_send(&mut bar, Event::Clicked)?; + lvgl::event_send(&mut bar, Event::Clicked); } - bar.set_value(i, AnimationState::ON)?; + bar.set_value(i, AnimationState::ON); i += 1; lvgl::task_handler(); diff --git a/examples/sdl.rs b/examples/sdl.rs index 1c14f1a6..b6723aff 100644 --- a/examples/sdl.rs +++ b/examples/sdl.rs @@ -34,7 +34,7 @@ fn main() -> LvResult<()> { button.set_align(Align::LeftMid, 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; - btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str())?; + btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); let mut btn_state = false; button.on_event(|_btn, event| { @@ -42,10 +42,10 @@ fn main() -> LvResult<()> { if let lvgl::Event::Clicked = event { if btn_state { let nt = CString::new("Click me!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } else { let nt = CString::new("Clicked!").unwrap(); - btn_lbl.set_text(nt.as_c_str()).unwrap(); + btn_lbl.set_text(nt.as_c_str()); } btn_state = !btn_state; } diff --git a/lvgl/src/functions.rs b/lvgl/src/functions.rs index e2a622c5..5d8cd461 100644 --- a/lvgl/src/functions.rs +++ b/lvgl/src/functions.rs @@ -69,9 +69,9 @@ pub fn task_handler() { /// Directly send an event to a specific widget. #[inline] -pub fn event_send Widget<'a>>( +pub fn event_send<'a, W: Widget<'a>>( obj: &mut W, - event: Event<>::SpecialEvent>, + event: Event<>::SpecialEvent>, ) { unsafe { lvgl_sys::lv_event_send(obj.raw().as_mut(), event.into(), ptr::null_mut()); From fb2ba23568d009fd6dc23bbc6095b012a618f6a2 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 13:55:21 +0200 Subject: [PATCH 02/19] add new argument types --- lvgl-codegen/src/lib.rs | 42 +++++++++++++++++++++++++++++++++++- lvgl/build.rs | 1 + lvgl/src/widgets/keyboard.rs | 12 +---------- lvgl/src/widgets/table.rs | 6 ------ 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 432f87cf..0554ce92 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -18,9 +18,12 @@ lazy_static! { static ref TYPE_MAPPINGS: HashMap<&'static str, &'static str> = [ ("u16", "u16"), ("i32", "i32"), + ("i16", "i16"), ("u8", "u8"), ("bool", "bool"), ("* const cty :: c_char", "_"), + ("* mut lv_obj_t", "lv_obj_t"), + ("lv_coord_t", "i16") ] .iter() .cloned() @@ -386,7 +389,10 @@ impl Rusty for LvType { Some(name) => { let val = if self.is_str() { quote!(&cstr_core::CStr) - } else if self.literal_name.contains("lv_") { + } else if self.literal_name.contains("* mut") { + let ident = format_ident!("{}", name); + quote!(&mut #ident) + } else if self.literal_name.contains("*") { let ident = format_ident!("{}", name); quote!(&#ident) } else { @@ -665,6 +671,40 @@ mod test { } } }; + assert_eq!(code.to_string(), expected_code.to_string()); + } + + #[test] + fn generate_method_wrapper_with_pointer_parameter() { + let bindgen_code = quote! { + extern "C" { + pub fn lv_arc_rotate_obj_to_angle( + obj: *const lv_obj_t, + obj_to_rotate: *mut lv_obj_t, + r_offset: lv_coord_t, + ); + } + }; + let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap(); + + let arc_rotate_obj_to_angle = cg.get(0).unwrap().clone(); + let parent_widget = LvWidget { + name: "arc".to_string(), + methods: vec![], + }; + + let code = arc_rotate_obj_to_angle.code(&parent_widget).unwrap(); + let expected_code = quote! { + pub fn rotate_obj_to_angle(&mut self, obj_to_rotate: &mut lv_obj_t, r_offset: i16) -> () { + unsafe { + lvgl_sys::lv_arc_rotate_obj_to_angle( + self.core.raw().as_mut(), + obj_to_rotate, + r_offset + ); + } + } + }; assert_eq!(code.to_string(), expected_code.to_string()); } diff --git a/lvgl/build.rs b/lvgl/build.rs index 0630c6a3..ba7532b3 100644 --- a/lvgl/build.rs +++ b/lvgl/build.rs @@ -20,6 +20,7 @@ fn main() { .collect(); let code = quote! { + use lvgl_sys::lv_obj_t; #(#widgets_impl)* }; diff --git a/lvgl/src/widgets/keyboard.rs b/lvgl/src/widgets/keyboard.rs index ebdaf050..8afbc7bc 100644 --- a/lvgl/src/widgets/keyboard.rs +++ b/lvgl/src/widgets/keyboard.rs @@ -1,14 +1,4 @@ use crate::widgets::{Keyboard, Textarea}; use crate::NativeObject; -impl Keyboard<'_> { - /// Associates a given `Textarea` to the keyboard. - pub fn set_textarea(&mut self, textarea: &mut Textarea) { - unsafe { - lvgl_sys::lv_keyboard_set_textarea( - self.raw().as_mut() as *mut lvgl_sys::lv_obj_t, - textarea.raw().as_mut() as *mut lvgl_sys::lv_obj_t, - ) - } - } -} +impl Keyboard<'_> {} diff --git a/lvgl/src/widgets/table.rs b/lvgl/src/widgets/table.rs index cda81588..d50dfbc1 100644 --- a/lvgl/src/widgets/table.rs +++ b/lvgl/src/widgets/table.rs @@ -3,12 +3,6 @@ use crate::widgets::Table; use core::mem::MaybeUninit; impl Table<'_> { - /// Sets the column width. Row height cannot be set manually and is - /// calculated by LVGL based on styling parameters. - pub fn set_col_width(&mut self, column: u16, width: i16) { - unsafe { lvgl_sys::lv_table_set_col_width(self.core.raw().as_ptr(), column, width) } - } - /// Returns the selected cell as a tuple of (row, column). pub fn get_selected_cell(&self) -> (u16, u16) { let mut row = MaybeUninit::::uninit(); From b675b258e0e67f1df4152d7deb73d8394009389e Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:12:59 +0200 Subject: [PATCH 03/19] impl NativeObject --- lvgl-codegen/src/lib.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 0554ce92..83457218 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -222,6 +222,9 @@ impl Rusty for LvFunc { .fold(quote!(), |args_accumulator, (arg_idx, arg)| { let next_arg = if arg_idx == 0 { quote!(self.core.raw().as_mut()) + } else if arg.typ.is_mut_native_object() { + let var = arg.get_value_usage(); + quote! {#var.raw().as_mut()} } else { let var = arg.get_value_usage(); quote!(#var) @@ -379,6 +382,10 @@ impl LvType { pub fn is_str(&self) -> bool { self.literal_name.ends_with("* const cty :: c_char") } + + pub fn is_mut_native_object(&self) -> bool { + self.literal_name == "* mut lv_obj_t" + } } impl Rusty for LvType { @@ -389,10 +396,12 @@ impl Rusty for LvType { Some(name) => { let val = if self.is_str() { quote!(&cstr_core::CStr) - } else if self.literal_name.contains("* mut") { + } else if self.is_mut_native_object() { + quote!(&mut impl NativeObject) + } else if self.literal_name.starts_with("* mut") { let ident = format_ident!("{}", name); quote!(&mut #ident) - } else if self.literal_name.contains("*") { + } else if self.literal_name.starts_with("*") { let ident = format_ident!("{}", name); quote!(&#ident) } else { @@ -675,7 +684,7 @@ mod test { } #[test] - fn generate_method_wrapper_with_pointer_parameter() { + fn generate_method_wrapper_with_mut_obj_parameter() { let bindgen_code = quote! { extern "C" { pub fn lv_arc_rotate_obj_to_angle( @@ -695,11 +704,11 @@ mod test { let code = arc_rotate_obj_to_angle.code(&parent_widget).unwrap(); let expected_code = quote! { - pub fn rotate_obj_to_angle(&mut self, obj_to_rotate: &mut lv_obj_t, r_offset: i16) -> () { + pub fn rotate_obj_to_angle(&mut self, obj_to_rotate: &mut impl NativeObject, r_offset: lvgl_sys::lv_coord_t) -> () { unsafe { lvgl_sys::lv_arc_rotate_obj_to_angle( self.core.raw().as_mut(), - obj_to_rotate, + obj_to_rotate.raw().as_mut(), r_offset ); } From 7fd0de4f2e675ada62ec28f25dd28d3546f1b7ba Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:13:40 +0200 Subject: [PATCH 04/19] TypePath instead of Ident --- lvgl-codegen/src/lib.rs | 20 +++++++++++--------- lvgl/build.rs | 1 - 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 83457218..f41d49f2 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -8,7 +8,7 @@ use quote::{format_ident, ToTokens}; use regex::Regex; use std::collections::HashMap; use std::error::Error; -use syn::{FnArg, ForeignItem, ForeignItemFn, Item, ReturnType}; +use syn::{parse_str, FnArg, ForeignItem, ForeignItemFn, Item, ReturnType, TypePath}; type CGResult = Result>; @@ -22,8 +22,10 @@ lazy_static! { ("u8", "u8"), ("bool", "bool"), ("* const cty :: c_char", "_"), - ("* mut lv_obj_t", "lv_obj_t"), - ("lv_coord_t", "i16") + ("* mut lv_obj_t", "_"), + ("lv_coord_t", "lvgl_sys::lv_coord_t"), + ("lv_img_size_mode_t","lvgl_sys::lv_img_size_mode_t"), + ("lv_point_t","lv_sys::lvgl_point_t"), ] .iter() .cloned() @@ -399,14 +401,14 @@ impl Rusty for LvType { } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) } else if self.literal_name.starts_with("* mut") { - let ident = format_ident!("{}", name); - quote!(&mut #ident) + let ty: TypePath = parse_str(name).unwrap(); + quote!(&mut #ty) } else if self.literal_name.starts_with("*") { - let ident = format_ident!("{}", name); - quote!(&#ident) + let ty: TypePath = parse_str(name).unwrap(); + quote!(&#ty) } else { - let ident = format_ident!("{}", name); - quote!(#ident) + let ty: TypePath = parse_str(name).unwrap(); + quote!(#ty) }; Ok(quote! { #val diff --git a/lvgl/build.rs b/lvgl/build.rs index ba7532b3..0630c6a3 100644 --- a/lvgl/build.rs +++ b/lvgl/build.rs @@ -20,7 +20,6 @@ fn main() { .collect(); let code = quote! { - use lvgl_sys::lv_obj_t; #(#widgets_impl)* }; From da63dc8728885dc373a9dca1c46779f3eeb33a17 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 17:36:49 +0200 Subject: [PATCH 05/19] handle all parameter types except mutable string --- lvgl-codegen/src/lib.rs | 63 +++++++++++++++++++++++---------------- lvgl/build.rs | 1 + lvgl/src/widgets/bar.rs | 24 +++++++-------- lvgl/src/widgets/label.rs | 4 +-- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index f41d49f2..f14fd0c5 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -6,6 +6,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use quote::{format_ident, ToTokens}; use regex::Regex; +use syn::token::Type; use std::collections::HashMap; use std::error::Error; use syn::{parse_str, FnArg, ForeignItem, ForeignItemFn, Item, ReturnType, TypePath}; @@ -13,6 +14,7 @@ use syn::{parse_str, FnArg, ForeignItem, ForeignItemFn, Item, ReturnType, TypePa type CGResult = Result>; const LIB_PREFIX: &str = "lv_"; +const TYPE_POSTFIX: &str = "_t"; lazy_static! { static ref TYPE_MAPPINGS: HashMap<&'static str, &'static str> = [ @@ -20,12 +22,9 @@ lazy_static! { ("i32", "i32"), ("i16", "i16"), ("u8", "u8"), + ("i8", "i8"), ("bool", "bool"), ("* const cty :: c_char", "_"), - ("* mut lv_obj_t", "_"), - ("lv_coord_t", "lvgl_sys::lv_coord_t"), - ("lv_img_size_mode_t","lvgl_sys::lv_img_size_mode_t"), - ("lv_point_t","lv_sys::lvgl_point_t"), ] .iter() .cloned() @@ -394,28 +393,40 @@ impl Rusty for LvType { type Parent = LvArg; fn code(&self, _parent: &Self::Parent) -> WrapperResult { - match TYPE_MAPPINGS.get(self.literal_name.as_str()) { - Some(name) => { - let val = if self.is_str() { - quote!(&cstr_core::CStr) - } else if self.is_mut_native_object() { - quote!(&mut impl NativeObject) - } else if self.literal_name.starts_with("* mut") { - let ty: TypePath = parse_str(name).unwrap(); - quote!(&mut #ty) - } else if self.literal_name.starts_with("*") { - let ty: TypePath = parse_str(name).unwrap(); - quote!(&#ty) - } else { - let ty: TypePath = parse_str(name).unwrap(); - quote!(#ty) - }; - Ok(quote! { - #val - }) + if self.literal_name.starts_with("* mut * const"){ + // TODO: Handle mutable strings like "* mut * const i8" + return Err(WrapperError::Skip); + } + let val = if self.is_str() { + quote!(&cstr_core::CStr) + } else if self.is_mut_native_object() { + quote!(&mut impl NativeObject) + } else{ + let literal_name = self.literal_name.as_str(); + let ty: TypePath = match TYPE_MAPPINGS.get(literal_name) { + Some(name)=> parse_str(name).expect(&format!("Cannot parse {name} to a type")), + None =>{ + if literal_name.contains(LIB_PREFIX) && literal_name.ends_with(TYPE_POSTFIX){ + let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); + parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")) + }else{ + println!("Skipping {literal_name}"); + return Err(WrapperError::Skip); + } + } + }; + if self.literal_name.starts_with("* mut") { + quote!(&mut #ty) + } else if self.literal_name.starts_with("*") { + quote!(&#ty) + }else{ + quote!(#ty) } - None => Err(WrapperError::Skip), - } + + }; + + Ok(quote! {#val}) + } } @@ -706,7 +717,7 @@ mod test { let code = arc_rotate_obj_to_angle.code(&parent_widget).unwrap(); let expected_code = quote! { - pub fn rotate_obj_to_angle(&mut self, obj_to_rotate: &mut impl NativeObject, r_offset: lvgl_sys::lv_coord_t) -> () { + pub fn rotate_obj_to_angle(&mut self, obj_to_rotate: &mut impl NativeObject, r_offset: lv_coord_t) -> () { unsafe { lvgl_sys::lv_arc_rotate_obj_to_angle( self.core.raw().as_mut(), diff --git a/lvgl/build.rs b/lvgl/build.rs index 0630c6a3..bb429ab2 100644 --- a/lvgl/build.rs +++ b/lvgl/build.rs @@ -20,6 +20,7 @@ fn main() { .collect(); let code = quote! { + use lvgl_sys::*; #(#widgets_impl)* }; diff --git a/lvgl/src/widgets/bar.rs b/lvgl/src/widgets/bar.rs index be7ae2ff..f34b4b59 100644 --- a/lvgl/src/widgets/bar.rs +++ b/lvgl/src/widgets/bar.rs @@ -3,20 +3,20 @@ use crate::widgets::Bar; use crate::NativeObject; impl Bar<'_> { - /// Set minimum and the maximum values of the bar - //pub fn set_range(&mut self, min: i16, max: i16) -> LvResult<()> { + /*/// Set minimum and the maximum values of the bar + pub fn set_range(&mut self, min: i16, max: i16) -> LvResult<()> { + unsafe { + lvgl_sys::lv_bar_set_range(self.core.raw()?.as_mut(), min, max); + } + Ok(()) + }*/ + + /*/// Set a new value on the bar + //pub fn set_value(&mut self, value: i32, anim: AnimationState) { // unsafe { - // lvgl_sys::lv_bar_set_range(self.core.raw()?.as_mut(), min, max); + // lvgl_sys::lv_bar_set_value(self.core.raw().as_mut(), value, anim.into()); // } - // Ok(()) - //} - - /// Set a new value on the bar - pub fn set_value(&mut self, value: i32, anim: AnimationState) { - unsafe { - lvgl_sys::lv_bar_set_value(self.core.raw().as_mut(), value, anim.into()); - } - } + //}*/ } /* /// The different parts, of a bar object. diff --git a/lvgl/src/widgets/label.rs b/lvgl/src/widgets/label.rs index fa5142fd..7a9da041 100644 --- a/lvgl/src/widgets/label.rs +++ b/lvgl/src/widgets/label.rs @@ -32,11 +32,11 @@ mod alloc_imp { } impl Label<'_> { - pub fn set_long_mode(&mut self, long_mode: LabelLongMode) { + /*pub fn set_long_mode(&mut self, long_mode: LabelLongMode) { unsafe { lvgl_sys::lv_label_set_long_mode(self.raw().as_mut(), long_mode.into()); } - } + }*/ pub fn get_long_mode(&self) -> u8 { unsafe { lvgl_sys::lv_label_get_long_mode(self.raw().as_ref()) } From a42054efae9c58fb08224f048e894a60ef86792e Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 18:18:18 +0200 Subject: [PATCH 06/19] handle mutable strings --- lvgl-codegen/src/lib.rs | 61 ++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index f14fd0c5..4f39e7ae 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -6,7 +6,6 @@ use proc_macro2::{Ident, TokenStream}; use quote::quote; use quote::{format_ident, ToTokens}; use regex::Regex; -use syn::token::Type; use std::collections::HashMap; use std::error::Error; use syn::{parse_str, FnArg, ForeignItem, ForeignItemFn, Item, ReturnType, TypePath}; @@ -19,12 +18,14 @@ const TYPE_POSTFIX: &str = "_t"; lazy_static! { static ref TYPE_MAPPINGS: HashMap<&'static str, &'static str> = [ ("u16", "u16"), + ("u32", "u32"), ("i32", "i32"), ("i16", "i16"), ("u8", "u8"), ("i8", "i8"), ("bool", "bool"), ("* const cty :: c_char", "_"), + ("* mut * const cty :: c_char", "_"), ] .iter() .cloned() @@ -327,10 +328,14 @@ impl LvArg { pub fn get_value_usage(&self) -> TokenStream { let ident = self.get_name_ident(); - if self.typ.is_str() { + if self.typ.is_const_str() { quote! { #ident.as_ptr() } + }else if self.typ.is_mut_str() { + quote! { + &mut #ident.as_ptr() + } } else { quote! { #ident @@ -380,8 +385,12 @@ impl LvType { self.literal_name.starts_with("const ") } - pub fn is_str(&self) -> bool { - self.literal_name.ends_with("* const cty :: c_char") + pub fn is_const_str(&self) -> bool { + self.literal_name == "* const cty :: c_char" + } + + pub fn is_mut_str(&self) -> bool { + self.literal_name == "* mut * const cty :: c_char" } pub fn is_mut_native_object(&self) -> bool { @@ -393,12 +402,10 @@ impl Rusty for LvType { type Parent = LvArg; fn code(&self, _parent: &Self::Parent) -> WrapperResult { - if self.literal_name.starts_with("* mut * const"){ - // TODO: Handle mutable strings like "* mut * const i8" - return Err(WrapperError::Skip); - } - let val = if self.is_str() { + let val = if self.is_const_str() { quote!(&cstr_core::CStr) + }else if self.is_mut_str() { + quote!(&mut cstr_core::CStr) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) } else{ @@ -407,10 +414,12 @@ impl Rusty for LvType { Some(name)=> parse_str(name).expect(&format!("Cannot parse {name} to a type")), None =>{ if literal_name.contains(LIB_PREFIX) && literal_name.ends_with(TYPE_POSTFIX){ + // LVGL types let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")) }else{ - println!("Skipping {literal_name}"); + // Other types, for example "*mut cty::c_void" + println!("Unknown type {literal_name}"); return Err(WrapperError::Skip); } } @@ -664,6 +673,38 @@ mod test { assert_eq!(code.to_string(), expected_code.to_string()); } + #[test] + fn generate_method_wrapper_for_mut_str_types_as_argument() { + let bindgen_code = quote! { + extern "C" { + pub fn lv_btnmatrix_set_map(obj: *mut lv_obj_t, map: *mut *const cty::c_char); + } + }; + let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap(); + + let btnmatrix_set_map = cg.get(0).unwrap().clone(); + let parent_widget = LvWidget { + name: "btnmatrix".to_string(), + methods: vec![], + }; + + let code = btnmatrix_set_map.code(&parent_widget).unwrap(); + let expected_code = quote! { + + pub fn set_map(&mut self, map: &mut cstr_core::CStr) -> () { + unsafe { + lvgl_sys::lv_btnmatrix_set_map( + self.core.raw().as_mut(), + &mut map.as_ptr() + ); + } + } + + }; + + assert_eq!(code.to_string(), expected_code.to_string()); + } + #[test] fn generate_method_wrapper_for_void_return() { let bindgen_code = quote! { From c3834422e0269dd22fbfad4fb2c22b31f6da136c Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 20:05:55 +0200 Subject: [PATCH 07/19] always borrow immutable CStr --- lvgl-codegen/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 4f39e7ae..1580d9ae 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -402,10 +402,8 @@ impl Rusty for LvType { type Parent = LvArg; fn code(&self, _parent: &Self::Parent) -> WrapperResult { - let val = if self.is_const_str() { + let val = if self.is_const_str() || self.is_mut_str() { quote!(&cstr_core::CStr) - }else if self.is_mut_str() { - quote!(&mut cstr_core::CStr) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) } else{ @@ -691,7 +689,7 @@ mod test { let code = btnmatrix_set_map.code(&parent_widget).unwrap(); let expected_code = quote! { - pub fn set_map(&mut self, map: &mut cstr_core::CStr) -> () { + pub fn set_map(&mut self, map: &cstr_core::CStr) -> () { unsafe { lvgl_sys::lv_btnmatrix_set_map( self.core.raw().as_mut(), From 19bf586ef9e3c9f2c06204bfc1296cfb3c8e3d4b Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:39:16 +0200 Subject: [PATCH 08/19] fix examples --- examples/bar.rs | 2 +- examples/rust_timer.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/bar.rs b/examples/bar.rs index ca202f93..7cc90515 100644 --- a/examples/bar.rs +++ b/examples/bar.rs @@ -67,7 +67,7 @@ fn main() -> Result<(), LvError> { // - implementation of `Widget` is not general enough // lvgl::event_send(&mut bar, Event::Clicked); } - bar.set_value(i, AnimationState::ON); + bar.set_value(i, AnimationState::ON.into()); i += 1; lvgl::task_handler(); diff --git a/examples/rust_timer.rs b/examples/rust_timer.rs index 7265aaf4..0978e1f4 100644 --- a/examples/rust_timer.rs +++ b/examples/rust_timer.rs @@ -84,7 +84,7 @@ fn main() -> Result<(), LvError> { i = 0; lvgl::event_send(&mut bar, Event::Clicked); } - bar.set_value(i, AnimationState::ON); + bar.set_value(i, AnimationState::ON.into()); i += 1; lvgl::task_handler(); From 9fbb2081c77aeefcea0973edbfa5872c759f9ab1 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 21:39:52 +0200 Subject: [PATCH 09/19] simplify LvType::code() --- lvgl-codegen/src/lib.rs | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 1580d9ae..990df655 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -406,34 +406,24 @@ impl Rusty for LvType { quote!(&cstr_core::CStr) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) - } else{ + } else { let literal_name = self.literal_name.as_str(); - let ty: TypePath = match TYPE_MAPPINGS.get(literal_name) { - Some(name)=> parse_str(name).expect(&format!("Cannot parse {name} to a type")), - None =>{ - if literal_name.contains(LIB_PREFIX) && literal_name.ends_with(TYPE_POSTFIX){ - // LVGL types - let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); - parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")) - }else{ - // Other types, for example "*mut cty::c_void" - println!("Unknown type {literal_name}"); - return Err(WrapperError::Skip); - } - } - }; + let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); + if raw_name == "cty :: c_void" { + println!("Void pointers are not yet supported ({literal_name})"); + return Err(WrapperError::Skip); + } + let ty: TypePath = parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")); if self.literal_name.starts_with("* mut") { quote!(&mut #ty) } else if self.literal_name.starts_with("*") { quote!(&#ty) - }else{ + } else { quote!(#ty) } - }; Ok(quote! {#val}) - } } From 47b92340cf9a165fc702e9c3ee53b522f3874543 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 13 Apr 2025 22:01:28 +0200 Subject: [PATCH 10/19] auto-parse return values --- lvgl-codegen/src/lib.rs | 23 ++++++++++------------- lvgl/src/widgets/label.rs | 4 ++-- lvgl/src/widgets/table.rs | 4 ++-- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 990df655..07ba1013 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -13,7 +13,6 @@ use syn::{parse_str, FnArg, ForeignItem, ForeignItemFn, Item, ReturnType, TypePa type CGResult = Result>; const LIB_PREFIX: &str = "lv_"; -const TYPE_POSTFIX: &str = "_t"; lazy_static! { static ref TYPE_MAPPINGS: HashMap<&'static str, &'static str> = [ @@ -24,8 +23,6 @@ lazy_static! { ("u8", "u8"), ("i8", "i8"), ("bool", "bool"), - ("* const cty :: c_char", "_"), - ("* mut * const cty :: c_char", "_"), ] .iter() .cloned() @@ -141,15 +138,11 @@ impl Rusty for LvFunc { // function returns something _ => { let return_value: &LvType = self.ret.as_ref().unwrap(); - match return_value.literal_name.as_str() { - "bool" => quote!(bool), - "u32" => quote!(u32), - "i32" => quote!(i32), - "u16" => quote!(u16), - "i16" => quote!(i16), - "u8" => quote!(u8), - "i8" => quote!(i8), - _ => return Err(WrapperError::Skip) + if !return_value.is_pointer(){ + parse_str(&return_value.literal_name).expect(&format!("Cannot parse {} as type",return_value.literal_name)) + }else{ + println!("Return value is pointer ({})", return_value.literal_name); + return Err(WrapperError::Skip); } } }; @@ -396,6 +389,10 @@ impl LvType { pub fn is_mut_native_object(&self) -> bool { self.literal_name == "* mut lv_obj_t" } + + pub fn is_pointer(&self) -> bool { + self.literal_name.starts_with('*') + } } impl Rusty for LvType { @@ -410,7 +407,7 @@ impl Rusty for LvType { let literal_name = self.literal_name.as_str(); let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); if raw_name == "cty :: c_void" { - println!("Void pointers are not yet supported ({literal_name})"); + println!("Void pointer as argument ({literal_name})"); return Err(WrapperError::Skip); } let ty: TypePath = parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")); diff --git a/lvgl/src/widgets/label.rs b/lvgl/src/widgets/label.rs index 7a9da041..d1b71451 100644 --- a/lvgl/src/widgets/label.rs +++ b/lvgl/src/widgets/label.rs @@ -38,7 +38,7 @@ impl Label<'_> { } }*/ - pub fn get_long_mode(&self) -> u8 { + /*pub fn get_long_mode(&self) -> u8 { unsafe { lvgl_sys::lv_label_get_long_mode(self.raw().as_ref()) } - } + }*/ } diff --git a/lvgl/src/widgets/table.rs b/lvgl/src/widgets/table.rs index d50dfbc1..9cdbb33d 100644 --- a/lvgl/src/widgets/table.rs +++ b/lvgl/src/widgets/table.rs @@ -3,7 +3,7 @@ use crate::widgets::Table; use core::mem::MaybeUninit; impl Table<'_> { - /// Returns the selected cell as a tuple of (row, column). + /*/// Returns the selected cell as a tuple of (row, column). pub fn get_selected_cell(&self) -> (u16, u16) { let mut row = MaybeUninit::::uninit(); let mut col = MaybeUninit::::uninit(); @@ -16,5 +16,5 @@ impl Table<'_> { // The values get initialised by LVGL (row.assume_init(), col.assume_init()) } - } + }*/ } From 4229224587c9c0ee5a762edb61b16369a298c013 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Mon, 14 Apr 2025 00:40:04 +0200 Subject: [PATCH 11/19] implement mutable string parameters --- lvgl-codegen/src/lib.rs | 93 ++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 07ba1013..ccaa51fe 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -181,7 +181,7 @@ impl Rusty for LvFunc { } }); - let args_processing = self + let args_preprocessing = self .args .iter() .enumerate() @@ -190,7 +190,31 @@ impl Rusty for LvFunc { let next_arg = if i == 0 { quote!() } else { - let var = arg.get_processing(); + let var = arg.get_preprocessing(); + quote!(#var) + }; + if args.is_empty() { + quote! { + #next_arg + } + } else { + quote! { + #args + #next_arg + } + } + }); + + let args_postprocessing = self + .args + .iter() + .enumerate() + .fold(quote!(), |args, (i, arg)| { + // if first arg is `const`, then it should be immutable + let next_arg = if i == 0 { + quote!() + } else { + let var = arg.get_postprocessiong(); quote!(#var) }; if args.is_empty() { @@ -251,12 +275,12 @@ impl Rusty for LvFunc { Ok(quote! { pub fn #func_name(#args_decl) -> #return_type { - #args_processing unsafe { + #args_preprocessing lvgl_sys::#original_func_name(#ffi_args)#optional_semicolon + #args_postprocessing + #explicit_ok } - - #explicit_ok } }) } @@ -311,12 +335,31 @@ impl LvArg { .unwrap_or_else(|_| format_ident!("r#{}", self.name.as_str())) } - pub fn get_processing(&self) -> TokenStream { + pub fn get_preprocessing(&self) -> TokenStream { // TODO: A better way to handle this, instead of `is_sometype()`, is using the Rust // type system itself. - // No need to pre-process this type of argument - quote! {} + if self.get_type().is_mut_str(){ + // Convert CString to *mut i8 + let name = format_ident!("{}",&self.name); + quote! { + let raw_c_str = #name.clone().into_raw(); + } + }else{ + quote! {} + } + } + + pub fn get_postprocessiong(&self) -> TokenStream{ + if self.get_type().is_mut_str(){ + // Convert *mut i8 back to CString + let name = format_ident!("{}",&self.name); + quote! { + *#name = cstr_core::CString::from_raw(raw_c_str); + } + }else{ + quote! {} + } } pub fn get_value_usage(&self) -> TokenStream { @@ -327,7 +370,7 @@ impl LvArg { } }else if self.typ.is_mut_str() { quote! { - &mut #ident.as_ptr() + raw_c_str } } else { quote! { @@ -383,7 +426,7 @@ impl LvType { } pub fn is_mut_str(&self) -> bool { - self.literal_name == "* mut * const cty :: c_char" + self.literal_name == "* mut cty :: c_char" } pub fn is_mut_native_object(&self) -> bool { @@ -393,16 +436,25 @@ impl LvType { pub fn is_pointer(&self) -> bool { self.literal_name.starts_with('*') } + + pub fn is_array(&self) -> bool { + self.literal_name.starts_with("* mut *") + } } impl Rusty for LvType { type Parent = LvArg; fn code(&self, _parent: &Self::Parent) -> WrapperResult { - let val = if self.is_const_str() || self.is_mut_str() { + let val = if self.is_const_str() { quote!(&cstr_core::CStr) + }else if self.is_mut_str() { + quote!(&mut cstr_core::CString) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) + }else if self.is_array() { + println!("Array as argument ({})", self.literal_name); + return Err(WrapperError::Skip); } else { let literal_name = self.literal_name.as_str(); let raw_name = literal_name.replace("* const ", "").replace("* mut ", ""); @@ -420,7 +472,7 @@ impl Rusty for LvType { } }; - Ok(quote! {#val}) + Ok(val) } } @@ -662,26 +714,29 @@ mod test { fn generate_method_wrapper_for_mut_str_types_as_argument() { let bindgen_code = quote! { extern "C" { - pub fn lv_btnmatrix_set_map(obj: *mut lv_obj_t, map: *mut *const cty::c_char); + pub fn lv_dropdown_get_selected_str(obj: *const lv_obj_t, buf: *mut cty::c_char, buf_size: u32); } }; let cg = CodeGen::load_func_defs(bindgen_code.to_string().as_str()).unwrap(); - let btnmatrix_set_map = cg.get(0).unwrap().clone(); + let dropdown_get_selected_str = cg.get(0).unwrap().clone(); let parent_widget = LvWidget { - name: "btnmatrix".to_string(), + name: "dropdown".to_string(), methods: vec![], }; - let code = btnmatrix_set_map.code(&parent_widget).unwrap(); + let code = dropdown_get_selected_str.code(&parent_widget).unwrap(); let expected_code = quote! { - pub fn set_map(&mut self, map: &cstr_core::CStr) -> () { + pub fn get_selected_str(&mut self, buf: &mut cstr_core::CString, buf_size:u32) -> () { unsafe { - lvgl_sys::lv_btnmatrix_set_map( + let raw_c_str = buf.clone().into_raw(); + lvgl_sys::lv_dropdown_get_selected_str( self.core.raw().as_mut(), - &mut map.as_ptr() + raw_c_str, + buf_size ); + *buf = CString::from_raw(raw_c_str); } } From ab30e3f7a0b0056f4aff19754fdce85e6f2b6f27 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Fri, 18 Apr 2025 22:47:40 +0200 Subject: [PATCH 12/19] cstring dynamic name --- lvgl-codegen/src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index ccaa51fe..2180ef6f 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -342,8 +342,9 @@ impl LvArg { if self.get_type().is_mut_str(){ // Convert CString to *mut i8 let name = format_ident!("{}",&self.name); + let name_raw = format_ident!("{}_raw",&self.name); quote! { - let raw_c_str = #name.clone().into_raw(); + let #name_raw = #name.clone().into_raw(); } }else{ quote! {} @@ -354,8 +355,9 @@ impl LvArg { if self.get_type().is_mut_str(){ // Convert *mut i8 back to CString let name = format_ident!("{}",&self.name); + let name_raw = format_ident!("{}_raw",&self.name); quote! { - *#name = cstr_core::CString::from_raw(raw_c_str); + *#name = cstr_core::CString::from_raw(#name_raw); } }else{ quote! {} @@ -369,8 +371,9 @@ impl LvArg { #ident.as_ptr() } }else if self.typ.is_mut_str() { + let ident_raw = format_ident!("{}_raw",&ident); quote! { - raw_c_str + #ident_raw } } else { quote! { @@ -730,13 +733,13 @@ mod test { pub fn get_selected_str(&mut self, buf: &mut cstr_core::CString, buf_size:u32) -> () { unsafe { - let raw_c_str = buf.clone().into_raw(); + let buf_raw = buf.clone().into_raw(); lvgl_sys::lv_dropdown_get_selected_str( self.core.raw().as_mut(), - raw_c_str, + buf_raw, buf_size ); - *buf = CString::from_raw(raw_c_str); + *buf = cstr_core::CString::from_raw(buf_raw); } } From d5abeeec031bbfa82381efb7b3930bd34e0ffabf Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sat, 19 Apr 2025 14:42:12 +0200 Subject: [PATCH 13/19] format lib.rs --- lvgl-codegen/src/lib.rs | 132 +++++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 2180ef6f..9e6d0e9d 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -138,9 +138,12 @@ impl Rusty for LvFunc { // function returns something _ => { let return_value: &LvType = self.ret.as_ref().unwrap(); - if !return_value.is_pointer(){ - parse_str(&return_value.literal_name).expect(&format!("Cannot parse {} as type",return_value.literal_name)) - }else{ + if !return_value.is_pointer() { + parse_str(&return_value.literal_name).expect(&format!( + "Cannot parse {} as type", + return_value.literal_name + )) + } else { println!("Return value is pointer ({})", return_value.literal_name); return Err(WrapperError::Skip); } @@ -156,30 +159,30 @@ impl Rusty for LvFunc { // // - Iif the first argument (of the C function) is const then we require a &self immutable reference, otherwise an &mut self reference // - The arguments will be appended to the accumulator (args_accumulator) as they are generated in the closure - let args_decl = self - .args - .iter() - .enumerate() - .fold(quote!(), |args_accumulator, (arg_idx, arg)| { - let next_arg = if arg_idx == 0 { - if arg.get_type().is_const() { - quote!(&self) + let args_decl = + self.args + .iter() + .enumerate() + .fold(quote!(), |args_accumulator, (arg_idx, arg)| { + let next_arg = if arg_idx == 0 { + if arg.get_type().is_const() { + quote!(&self) + } else { + quote!(&mut self) + } } else { - quote!(&mut self) - } - } else { - arg.code(self).unwrap() - }; + arg.code(self).unwrap() + }; - // If the accummulator is empty then we call quote! only with the next_arg content - if args_accumulator.is_empty() { - quote! {#next_arg} - } - // Otherwise we append next_arg at the end of the accumulator - else { - quote! {#args_accumulator, #next_arg} - } - }); + // If the accummulator is empty then we call quote! only with the next_arg content + if args_accumulator.is_empty() { + quote! {#next_arg} + } + // Otherwise we append next_arg at the end of the accumulator + else { + quote! {#args_accumulator, #next_arg} + } + }); let args_preprocessing = self .args @@ -234,30 +237,30 @@ impl Rusty for LvFunc { // - The first argument will be always self.core.raw().as_mut() (see quote! when arg_idx == 0), it's most likely a pointer to lv_obj_t // TODO: When handling getters this should be self.raw().as_ptr() instead, this also requires updating args_decl // - The arguments will be appended to the accumulator (args_accumulator) as they are generated in the closure - let ffi_args = self - .args - .iter() - .enumerate() - .fold(quote!(), |args_accumulator, (arg_idx, arg)| { - let next_arg = if arg_idx == 0 { - quote!(self.core.raw().as_mut()) - } else if arg.typ.is_mut_native_object() { - let var = arg.get_value_usage(); - quote! {#var.raw().as_mut()} - } else { - let var = arg.get_value_usage(); - quote!(#var) - }; + let ffi_args = + self.args + .iter() + .enumerate() + .fold(quote!(), |args_accumulator, (arg_idx, arg)| { + let next_arg = if arg_idx == 0 { + quote!(self.core.raw().as_mut()) + } else if arg.typ.is_mut_native_object() { + let var = arg.get_value_usage(); + quote! {#var.raw().as_mut()} + } else { + let var = arg.get_value_usage(); + quote!(#var) + }; - // If the accummulator is empty then we call quote! only with the next_arg content - if args_accumulator.is_empty() { - quote! {#next_arg} - } - // Otherwise we append next_arg at the end of the accumulator - else { - quote! {#args_accumulator, #next_arg} - } - }); + // If the accummulator is empty then we call quote! only with the next_arg content + if args_accumulator.is_empty() { + quote! {#next_arg} + } + // Otherwise we append next_arg at the end of the accumulator + else { + quote! {#args_accumulator, #next_arg} + } + }); // NOTE: When the function returns something we can 'avoid' placing an Ok() at the end. let explicit_ok = if return_type.is_empty() { @@ -268,9 +271,9 @@ impl Rusty for LvFunc { // Append a semicolon at the end of the unsafe code only if there's no return value. // Otherwise we should remove it - let optional_semicolon= match self.ret { + let optional_semicolon = match self.ret { None => quote!(;), - _ => quote!() + _ => quote!(), }; Ok(quote! { @@ -339,27 +342,27 @@ impl LvArg { // TODO: A better way to handle this, instead of `is_sometype()`, is using the Rust // type system itself. - if self.get_type().is_mut_str(){ + if self.get_type().is_mut_str() { // Convert CString to *mut i8 - let name = format_ident!("{}",&self.name); - let name_raw = format_ident!("{}_raw",&self.name); + let name = format_ident!("{}", &self.name); + let name_raw = format_ident!("{}_raw", &self.name); quote! { let #name_raw = #name.clone().into_raw(); } - }else{ + } else { quote! {} } } - pub fn get_postprocessiong(&self) -> TokenStream{ - if self.get_type().is_mut_str(){ + pub fn get_postprocessiong(&self) -> TokenStream { + if self.get_type().is_mut_str() { // Convert *mut i8 back to CString - let name = format_ident!("{}",&self.name); - let name_raw = format_ident!("{}_raw",&self.name); + let name = format_ident!("{}", &self.name); + let name_raw = format_ident!("{}_raw", &self.name); quote! { *#name = cstr_core::CString::from_raw(#name_raw); } - }else{ + } else { quote! {} } } @@ -370,8 +373,8 @@ impl LvArg { quote! { #ident.as_ptr() } - }else if self.typ.is_mut_str() { - let ident_raw = format_ident!("{}_raw",&ident); + } else if self.typ.is_mut_str() { + let ident_raw = format_ident!("{}_raw", &ident); quote! { #ident_raw } @@ -451,11 +454,11 @@ impl Rusty for LvType { fn code(&self, _parent: &Self::Parent) -> WrapperResult { let val = if self.is_const_str() { quote!(&cstr_core::CStr) - }else if self.is_mut_str() { + } else if self.is_mut_str() { quote!(&mut cstr_core::CString) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) - }else if self.is_array() { + } else if self.is_array() { println!("Array as argument ({})", self.literal_name); return Err(WrapperError::Skip); } else { @@ -465,7 +468,8 @@ impl Rusty for LvType { println!("Void pointer as argument ({literal_name})"); return Err(WrapperError::Skip); } - let ty: TypePath = parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")); + let ty: TypePath = + parse_str(&raw_name).expect(&format!("Cannot parse {raw_name} to a type")); if self.literal_name.starts_with("* mut") { quote!(&mut #ty) } else if self.literal_name.starts_with("*") { From 2b205a2caae75417c5c8a87b5e6796b14ce8869d Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:27:11 +0200 Subject: [PATCH 14/19] fix tests --- lvgl/src/misc/anim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lvgl/src/misc/anim.rs b/lvgl/src/misc/anim.rs index 206e9a93..7d85fd7e 100644 --- a/lvgl/src/misc/anim.rs +++ b/lvgl/src/misc/anim.rs @@ -115,7 +115,7 @@ where // yes, we have to do it this way. Casting `obj` directly to `&mut Obj` segfaults let obj = (*(obj as *mut T)).raw(); if !anim.as_ref().user_data.is_null() { - let callback = &mut *(obj.as_ref().user_data as *mut F); + let callback = &mut *(anim.as_ref().user_data as *mut F); let mut obj_nondrop = Obj::from_raw(obj).unwrap(); callback(&mut obj_nondrop, val); mem::forget(obj_nondrop) From bd5a268be62bd4b1a726ea7be1bc01a915c1caa4 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:32:38 +0200 Subject: [PATCH 15/19] fix typo --- lvgl-codegen/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 9e6d0e9d..53616815 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -217,7 +217,7 @@ impl Rusty for LvFunc { let next_arg = if i == 0 { quote!() } else { - let var = arg.get_postprocessiong(); + let var = arg.get_postprocessing(); quote!(#var) }; if args.is_empty() { @@ -354,7 +354,7 @@ impl LvArg { } } - pub fn get_postprocessiong(&self) -> TokenStream { + pub fn get_postprocessing(&self) -> TokenStream { if self.get_type().is_mut_str() { // Convert *mut i8 back to CString let name = format_ident!("{}", &self.name); From fedc9604ab47b9c14cd59272d08ceddd9209a77d Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 27 Apr 2025 17:07:52 +0200 Subject: [PATCH 16/19] implement lv_obj... functions --- lvgl-codegen/src/lib.rs | 75 +++++++++++++++++++++++++------------- lvgl/src/functions.rs | 3 +- lvgl/src/lv_core/obj.rs | 12 +++--- lvgl/src/lv_core/screen.rs | 2 +- lvgl/src/lv_core/style.rs | 6 +++ lvgl/src/misc/anim.rs | 2 +- lvgl/src/support.rs | 3 +- 7 files changed, 67 insertions(+), 36 deletions(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 53616815..06cd5501 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -58,20 +58,28 @@ impl Rusty for LvWidget { type Parent = (); fn code(&self, _parent: &Self::Parent) -> WrapperResult { - // We don't generate for the generic Obj - if self.name.as_str().eq("obj") { - return Err(WrapperError::Skip); - } - let widget_name = format_ident!("{}", self.pascal_name()); let methods: Vec = self.methods.iter().flat_map(|m| m.code(self)).collect(); - Ok(quote! { - define_object!(#widget_name); + if self.name.as_str().eq("obj") { + Ok(quote! { + pub trait Widget<'a>: NativeObject + Sized + 'a { + type SpecialEvent; + type Part: Into; - impl<'a> #widget_name<'a> { - #(#methods)* - } - }) + unsafe fn from_raw(raw_pointer: core::ptr::NonNull) -> Option; + + #(#methods)* + } + }) + } else { + Ok(quote! { + define_object!(#widget_name); + + impl<'a> #widget_name<'a> { + #(#methods)* + } + }) + } } } @@ -106,7 +114,7 @@ impl Rusty for LvFunc { let original_func_name = format_ident!("{}", self.name.as_str()); // generate constructor - if new_name.as_str().eq("create") { + if new_name.as_str().eq("create") && parent.name != "obj" { return Ok(quote! { pub fn create(parent: &mut impl crate::NativeObject) -> crate::LvResult { @@ -115,7 +123,7 @@ impl Rusty for LvFunc { parent.raw().as_mut(), ); if let Some(raw) = core::ptr::NonNull::new(ptr) { - let core = ::from_raw(raw).unwrap(); + let core = ::from_raw(raw).unwrap(); Ok(Self { core }) } else { Err(crate::LvError::InvalidReference) @@ -243,7 +251,11 @@ impl Rusty for LvFunc { .enumerate() .fold(quote!(), |args_accumulator, (arg_idx, arg)| { let next_arg = if arg_idx == 0 { - quote!(self.core.raw().as_mut()) + if parent.name == "obj" { + quote!(self.raw().as_mut()) + } else { + quote!(self.core.raw().as_mut()) + } } else if arg.typ.is_mut_native_object() { let var = arg.get_value_usage(); quote! {#var.raw().as_mut()} @@ -275,17 +287,30 @@ impl Rusty for LvFunc { None => quote!(;), _ => quote!(), }; - - Ok(quote! { - pub fn #func_name(#args_decl) -> #return_type { - unsafe { - #args_preprocessing - lvgl_sys::#original_func_name(#ffi_args)#optional_semicolon - #args_postprocessing - #explicit_ok + if parent.name == "obj" { + // pub keyword cannot be used in traits + Ok(quote! { + fn #func_name(#args_decl) -> #return_type { + unsafe { + #args_preprocessing + lvgl_sys::#original_func_name(#ffi_args)#optional_semicolon + #args_postprocessing + #explicit_ok + } } - } - }) + }) + } else { + Ok(quote! { + pub fn #func_name(#args_decl) -> #return_type { + unsafe { + #args_preprocessing + lvgl_sys::#original_func_name(#ffi_args)#optional_semicolon + #args_postprocessing + #explicit_ok + } + } + }) + } } } @@ -927,7 +952,7 @@ mod test { parent.raw().as_mut(), ); if let Some(raw) = core::ptr::NonNull::new(ptr) { - let core = ::from_raw(raw).unwrap(); + let core = ::from_raw(raw).unwrap(); Ok(Self { core }) } else { Err(crate::LvError::InvalidReference) diff --git a/lvgl/src/functions.rs b/lvgl/src/functions.rs index 5d8cd461..ff2a20a2 100644 --- a/lvgl/src/functions.rs +++ b/lvgl/src/functions.rs @@ -1,6 +1,7 @@ use crate::display::{Display, DisplayDriver}; use crate::input_device::InputDriver; -use crate::{Event, LvError, LvResult, Obj, Widget}; +use crate::widgets::Widget; +use crate::{Event, LvError, LvResult, Obj}; use core::ptr::NonNull; #[cfg(not(feature = "rust_timer"))] use core::time::Duration; diff --git a/lvgl/src/lv_core/obj.rs b/lvgl/src/lv_core/obj.rs index 433ca537..2ab46aa5 100644 --- a/lvgl/src/lv_core/obj.rs +++ b/lvgl/src/lv_core/obj.rs @@ -5,8 +5,8 @@ //! are special in that they do not have a parent object but do still implement //! `NativeObject`. -use crate::lv_core::style::Style; -use crate::{Align, LvError, LvResult}; +use crate::widgets::Widget; +use crate::{LvError, LvResult}; use core::fmt::{self, Debug}; use core::marker::PhantomData; use core::ptr::{self, NonNull}; @@ -78,7 +78,7 @@ impl NativeObject for Obj<'_> { } /// A wrapper for all LVGL common operations on generic objects. -pub trait Widget<'a>: NativeObject + Sized + 'a { +/*pub trait Widget<'a>: NativeObject + Sized + 'a { type SpecialEvent; type Part: Into; @@ -149,7 +149,7 @@ pub trait Widget<'a>: NativeObject + Sized + 'a { ); } } -} +}*/ impl<'a> Widget<'a> for Obj<'a> { type SpecialEvent = u32; @@ -185,7 +185,7 @@ macro_rules! define_object { impl<'a> $item<'a> { pub fn on_event(&mut self, f: F) -> $crate::LvResult<()> where - F: FnMut(Self, $crate::support::Event<>::SpecialEvent>), + F: FnMut(Self, $crate::support::Event<>::SpecialEvent>), { use $crate::NativeObject; unsafe { @@ -210,7 +210,7 @@ macro_rules! define_object { } } - impl<'a> $crate::Widget<'a> for $item<'a> { + impl<'a> Widget<'a> for $item<'a> { type SpecialEvent = $event_type; type Part = $part_type; diff --git a/lvgl/src/lv_core/screen.rs b/lvgl/src/lv_core/screen.rs index ef87065b..4bc94986 100644 --- a/lvgl/src/lv_core/screen.rs +++ b/lvgl/src/lv_core/screen.rs @@ -1,4 +1,4 @@ -use crate::{LvError, LvResult, NativeObject, Obj, Part, Widget}; +use crate::{widgets::Widget, LvError, LvResult, NativeObject, Obj, Part}; /// An LVGL screen. #[derive(Debug)] diff --git a/lvgl/src/lv_core/style.rs b/lvgl/src/lv_core/style.rs index f37a34a4..2d1e9de1 100644 --- a/lvgl/src/lv_core/style.rs +++ b/lvgl/src/lv_core/style.rs @@ -33,6 +33,12 @@ pub struct Style { pub(crate) raw: Box, } +impl Style { + pub fn into_raw(self) -> &'static mut lvgl_sys::lv_style_t { + unsafe { self.raw.into_raw().as_mut().unwrap() } + } +} + impl Debug for Style { // TODO: Decode and dump style values fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/lvgl/src/misc/anim.rs b/lvgl/src/misc/anim.rs index 7d85fd7e..4f26d6dc 100644 --- a/lvgl/src/misc/anim.rs +++ b/lvgl/src/misc/anim.rs @@ -1,4 +1,4 @@ -use crate::{Box, LvResult, Obj, Widget}; +use crate::{widgets::Widget, Box, LvResult, Obj}; use core::{ mem::{self, MaybeUninit}, num::TryFromIntError, diff --git a/lvgl/src/support.rs b/lvgl/src/support.rs index a85cba6a..3f1366b7 100644 --- a/lvgl/src/support.rs +++ b/lvgl/src/support.rs @@ -1,5 +1,4 @@ -use crate::display::DisplayError; -use crate::Widget; +use crate::{display::DisplayError, widgets::Widget}; use core::convert::{TryFrom, TryInto}; #[cfg(feature = "nightly")] use core::error::Error; From 5581ac4f1a7637e5fbcbbfaebbfe4c70b57ebcf5 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 27 Apr 2025 17:55:05 +0200 Subject: [PATCH 17/19] fix examples --- examples/animation.rs | 10 +++++----- examples/arc.rs | 12 ++++++------ examples/bar.rs | 14 +++++++------- examples/button_click.rs | 8 ++++---- examples/demo.rs | 16 ++++++++-------- examples/rust_timer.rs | 14 +++++++------- examples/sdl.rs | 7 ++++--- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/examples/animation.rs b/examples/animation.rs index d21963cf..f6d2f74c 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -12,8 +12,8 @@ use lvgl::input_device::{ }; use lvgl::misc::anim::{AnimRepeatCount, Animation}; use lvgl::style::Style; -use lvgl::widgets::{Btn, Label}; -use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, Widget}; +use lvgl::widgets::{Btn, Label, Widget}; +use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; @@ -46,10 +46,10 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the button let mut button = Btn::create(&mut screen)?; - button.set_align(Align::LeftMid, 30, 0); + button.align(Align::LeftMid.into(), 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); @@ -57,7 +57,7 @@ fn main() -> Result<(), LvError> { let mut btn_state = false; let mut anim = Animation::new(&mut button, Duration::from_secs(1), 0, 60, |obj, val| { - obj.set_align(Align::LeftMid, val, 0) + obj.align(Align::LeftMid.into(), val as i16, 0) })?; anim.set_repeat_count(AnimRepeatCount::Infinite); anim.start(); diff --git a/examples/arc.rs b/examples/arc.rs index e9b98944..cc89a607 100644 --- a/examples/arc.rs +++ b/examples/arc.rs @@ -6,8 +6,8 @@ use embedded_graphics_simulator::{ }; use lvgl; use lvgl::style::Style; -use lvgl::widgets::{Arc, Label}; -use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, Widget}; +use lvgl::widgets::{Arc, Label, Widget}; +use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part}; use lvgl_sys; use std::thread::sleep; use std::time::Duration; @@ -52,23 +52,23 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((255, 255, 255))); screen_style.set_radius(0); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the arc object let mut arc = Arc::create(&mut screen)?; arc.set_size(150, 150); - arc.set_align(Align::Center, 0, 10); + arc.align(Align::Center.into(), 0, 10); arc.set_start_angle(135); arc.set_end_angle(135); let mut loading_lbl = Label::create(&mut screen)?; loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); - loading_lbl.set_align(Align::OutTopMid, 0, 0); + loading_lbl.align(Align::OutTopMid.into(), 0, 0); //loading_lbl.set_label_align(LabelAlign::Center)?; let mut loading_style = Style::default(); loading_style.set_text_color(Color::from_rgb((0, 0, 0))); - loading_lbl.add_style(Part::Main, &mut loading_style); + loading_lbl.add_style(loading_style.into_raw(), Part::Main.into()); let mut angle = 0; let mut forward = true; diff --git a/examples/bar.rs b/examples/bar.rs index 7cc90515..fd20743b 100644 --- a/examples/bar.rs +++ b/examples/bar.rs @@ -6,8 +6,8 @@ use embedded_graphics_simulator::{ }; use lvgl; use lvgl::style::Style; -use lvgl::widgets::{Bar, Label}; -use lvgl::{Align, AnimationState, Color, Display, DrawBuffer, Event, LvError, Part, Widget}; +use lvgl::widgets::{Bar, Label, Widget}; +use lvgl::{Align, AnimationState, Color, Display, DrawBuffer, Event, LvError, Part}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; @@ -33,12 +33,12 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((255, 255, 255))); screen_style.set_radius(0); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the bar object let mut bar = Bar::create(&mut screen)?; bar.set_size(175, 20); - bar.set_align(Align::Center, 0, 10); + bar.align(Align::Center.into(), 0, 10); bar.set_range(0, 100); bar.on_event(|_b, _e| { println!("Completed!"); @@ -47,15 +47,15 @@ fn main() -> Result<(), LvError> { // Set the indicator style for the bar object let mut ind_style = Style::default(); ind_style.set_bg_color(Color::from_rgb((100, 245, 100))); - bar.add_style(Part::Any, &mut ind_style); + bar.add_style(ind_style.into_raw(), Part::Any.into()); let mut loading_lbl = Label::create(&mut screen)?; loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); - loading_lbl.set_align(Align::OutTopMid, 0, 0); + loading_lbl.align(Align::OutTopMid.into(), 0, 0); let mut loading_style = Style::default(); loading_style.set_text_color(Color::from_rgb((0, 0, 0))); - loading_lbl.add_style(Part::Main, &mut loading_style); + loading_lbl.add_style(loading_style.into_raw(), Part::Main.into()); let mut i = 0; 'running: loop { diff --git a/examples/button_click.rs b/examples/button_click.rs index f57e2566..99b33fc1 100644 --- a/examples/button_click.rs +++ b/examples/button_click.rs @@ -11,8 +11,8 @@ use lvgl::input_device::{ InputDriver, }; use lvgl::style::Style; -use lvgl::widgets::{Btn, Label}; -use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, Widget}; +use lvgl::widgets::{Btn, Label, Widget}; +use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; @@ -45,10 +45,10 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the button let mut button = Btn::create(&mut screen)?; - button.set_align(Align::LeftMid, 30, 0); + button.align(Align::LeftMid.into(), 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); diff --git a/examples/demo.rs b/examples/demo.rs index 21537c8e..d542153d 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -7,8 +7,8 @@ use embedded_graphics_simulator::{ use lvgl; use lvgl::font::Font; use lvgl::style::Style; -use lvgl::widgets::Label; -use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, TextAlign, Widget}; +use lvgl::widgets::{Label, Widget}; +use lvgl::{Align, Color, Display, DrawBuffer, LvError, Part, TextAlign}; use lvgl_sys; use std::thread::sleep; use std::time::Duration; @@ -35,14 +35,14 @@ fn main() -> Result<(), LvError> { // Create screen and widgets let binding = display?; - let screen = binding.get_scr_act(); + let mut screen = binding.get_scr_act()?; println!("Before all widgets: {:?}", mem_info()); let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); screen_style.set_radius(0); - screen?.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); let mut time = Label::from("20:46"); let mut style_time = Style::default(); @@ -52,8 +52,8 @@ fn main() -> Result<(), LvError> { // See font module documentation for an explanation of the unsafe block style_time.set_text_font(unsafe { Font::new_raw(lvgl_sys::noto_sans_numeric_80) }); - time.add_style(Part::Main, &mut style_time); - time.set_align(Align::Center, 0, 90); + time.add_style(style_time.into_raw(), Part::Main.into()); + time.align(Align::Center.into(), 0, 90); time.set_width(240); time.set_height(240); @@ -61,13 +61,13 @@ fn main() -> Result<(), LvError> { bt.set_width(50); bt.set_height(80); let _ = bt.set_recolor(true); - bt.set_align(Align::TopLeft, 0, 0); + bt.align(Align::TopLeft.into(), 0, 0); let mut power: Label = "#fade2a 20%#".into(); let _ = power.set_recolor(true); power.set_width(80); power.set_height(20); - power.set_align(Align::TopRight, 40, 0); + power.align(Align::TopRight.into(), 40, 0); let mut i = 0; 'running: loop { diff --git a/examples/rust_timer.rs b/examples/rust_timer.rs index 0978e1f4..5c647c83 100644 --- a/examples/rust_timer.rs +++ b/examples/rust_timer.rs @@ -6,8 +6,8 @@ use embedded_graphics_simulator::{ }; use lvgl; use lvgl::style::Style; -use lvgl::widgets::{Bar, Label}; -use lvgl::{Align, AnimationState, Color, Display, DrawBuffer, Event, LvError, Part, Widget}; +use lvgl::widgets::{Bar, Label, Widget}; +use lvgl::{Align, AnimationState, Color, Display, DrawBuffer, Event, LvError, Part}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; @@ -53,12 +53,12 @@ fn main() -> Result<(), LvError> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((255, 255, 255))); screen_style.set_radius(0); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the bar object let mut bar = Bar::create(&mut screen)?; bar.set_size(175, 20); - bar.set_align(Align::Center, 0, 10); + bar.align(Align::Center.into(), 0, 10); bar.set_range(0, 100); bar.on_event(|_b, _e| { println!("Completed!"); @@ -67,15 +67,15 @@ fn main() -> Result<(), LvError> { // Set the indicator style for the bar object let mut ind_style = Style::default(); ind_style.set_bg_color(Color::from_rgb((100, 245, 100))); - bar.add_style(Part::Any, &mut ind_style); + bar.add_style(ind_style.into_raw(), Part::Main.into()); let mut loading_lbl = Label::create(&mut screen)?; loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str()); - loading_lbl.set_align(Align::OutTopMid, 0, 0); + loading_lbl.align(Align::OutTopMid.into(), 0, 0); let mut loading_style = Style::default(); loading_style.set_text_color(Color::from_rgb((0, 0, 0))); - loading_lbl.add_style(Part::Main, &mut loading_style); + loading_lbl.add_style(loading_style.into_raw(), Part::Main.into()); let mut i = 0; let clock = Clock::default(); diff --git a/examples/sdl.rs b/examples/sdl.rs index b6723aff..cdf447d7 100644 --- a/examples/sdl.rs +++ b/examples/sdl.rs @@ -8,9 +8,10 @@ use lvgl::input_device::InputDriver; use lvgl::lv_drv_disp_sdl; use lvgl::lv_drv_input_pointer_sdl; use lvgl::style::Style; +use lvgl::widgets::Widget; use lvgl::widgets::{Btn, Label}; use lvgl::LvResult; -use lvgl::{Align, Color, DrawBuffer, Part, Widget}; +use lvgl::{Align, Color, DrawBuffer, Part}; use std::thread::sleep; use std::time::Duration; use std::time::Instant; @@ -28,10 +29,10 @@ fn main() -> LvResult<()> { let mut screen_style = Style::default(); screen_style.set_bg_color(Color::from_rgb((0, 0, 0))); - screen.add_style(Part::Main, &mut screen_style); + screen.add_style(screen_style.into_raw(), Part::Main.into()); // Create the button let mut button = Btn::create(&mut screen)?; - button.set_align(Align::LeftMid, 30, 0); + button.align(Align::LeftMid.into(), 30, 0); button.set_size(180, 80); let mut btn_lbl = Label::create(&mut button)?; btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str()); From 54f1437ff4c0b6195faec20508a4f0c28ddb9b72 Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Sun, 27 Apr 2025 18:20:32 +0200 Subject: [PATCH 18/19] update style doc --- lvgl/src/lv_core/style.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lvgl/src/lv_core/style.rs b/lvgl/src/lv_core/style.rs index 2d1e9de1..9bb639fc 100644 --- a/lvgl/src/lv_core/style.rs +++ b/lvgl/src/lv_core/style.rs @@ -3,13 +3,13 @@ //! Objects in LVGL can have associated styling information. After a `Style` is //! created and configured, it can be added to any object or widget: //! ``` -//! use lvgl::{Color, Widget}; +//! use lvgl::{Color, Part}; //! use lvgl::style::Style; //! //! let mut my_style = Style::default(); //! my_style.set_text_color(Color::from_rgb((0, 0, 0))); //! -//! //my_widget.add_style(Part::Main, &mut my_style).unwrap(); +//! // my_widget.add_style(my_style.into_raw(), Part::Main.into()); //! // ... //! ``` //! All methods on the `Style` type directly lower to their C LVGL From 9849f2dedd39f7e1180450c927c0fd6b602f4f5b Mon Sep 17 00:00:00 2001 From: Sakii <13037299+SakiiCode@users.noreply.github.com> Date: Mon, 28 Apr 2025 03:07:31 +0200 Subject: [PATCH 19/19] fix lv_obj_t alias --- lvgl-codegen/src/lib.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lvgl-codegen/src/lib.rs b/lvgl-codegen/src/lib.rs index 06cd5501..ca52f718 100644 --- a/lvgl-codegen/src/lib.rs +++ b/lvgl-codegen/src/lib.rs @@ -259,6 +259,9 @@ impl Rusty for LvFunc { } else if arg.typ.is_mut_native_object() { let var = arg.get_value_usage(); quote! {#var.raw().as_mut()} + }else if arg.typ.is_const_native_object() { + let var = arg.get_value_usage(); + quote! {#var.raw().as_ref()} } else { let var = arg.get_value_usage(); quote!(#var) @@ -460,8 +463,14 @@ impl LvType { self.literal_name == "* mut cty :: c_char" } + pub fn is_const_native_object(&self) -> bool { + self.literal_name == "* const lv_obj_t" || + self.literal_name == "* const _lv_obj_t" + } + pub fn is_mut_native_object(&self) -> bool { - self.literal_name == "* mut lv_obj_t" + self.literal_name == "* mut lv_obj_t" || + self.literal_name == "* mut _lv_obj_t" } pub fn is_pointer(&self) -> bool { @@ -481,6 +490,8 @@ impl Rusty for LvType { quote!(&cstr_core::CStr) } else if self.is_mut_str() { quote!(&mut cstr_core::CString) + }else if self.is_const_native_object() { + quote!(&impl NativeObject) } else if self.is_mut_native_object() { quote!(&mut impl NativeObject) } else if self.is_array() {