API re-design (#9)
* New API test using std/alloc objects * Use RefCell to create multiple mut refs * UI saves display obj, makes possible for global call to active display * Reflect restrictions of LvGL * No need for manual nul byte * Fix typo
This commit is contained in:
parent
63a160d54e
commit
893f0054c8
7 changed files with 229 additions and 148 deletions
|
@ -1,13 +1,14 @@
|
|||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics_simulator::{
|
||||
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
|
||||
};
|
||||
use lvgl;
|
||||
use lvgl::Object;
|
||||
use lvgl::{Object, UI};
|
||||
use lvgl_sys;
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Arc, Mutex};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use embedded_graphics::pixelcolor::{Rgb565};
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
|
||||
|
@ -16,17 +17,16 @@ fn main() -> Result<(), String> {
|
|||
));
|
||||
|
||||
let output_settings = OutputSettingsBuilder::new().scale(4).build();
|
||||
let mut window = Window::new("Hello World", &output_settings);
|
||||
let mut window = Window::new("PineTime", &output_settings);
|
||||
|
||||
unsafe {
|
||||
lvgl_sys::lv_init();
|
||||
}
|
||||
let mut ui = UI::init().unwrap();
|
||||
|
||||
// Implement and register your display:
|
||||
let mut display_driver = lvgl::DisplayDriver::new(&mut display);
|
||||
let display_driver = lvgl::DisplayDriver::new(&mut display);
|
||||
ui.disp_drv_register(display_driver);
|
||||
|
||||
// Create screen and widgets
|
||||
let mut screen = display_driver.get_active_screen();
|
||||
let mut screen = ui.scr_act();
|
||||
|
||||
let font_roboto_28 = unsafe { &lvgl_sys::lv_font_roboto_28 };
|
||||
let font_noto_sans_numeric_28 = unsafe { ¬o_sans_numeric_80 };
|
||||
|
@ -34,45 +34,48 @@ fn main() -> Result<(), String> {
|
|||
let mut screen_style = lvgl::Style::new();
|
||||
screen_style.set_body_main_color(lvgl::Color::from_rgb((0, 0, 0)));
|
||||
screen_style.set_body_grad_color(lvgl::Color::from_rgb((0, 0, 0)));
|
||||
screen.set_style(&mut screen_style);
|
||||
screen.set_style(screen_style);
|
||||
|
||||
let mut time = lvgl::Label::new(&mut screen);
|
||||
let mut style_time = lvgl::Style::new();
|
||||
style_time.set_text_font(font_noto_sans_numeric_28);
|
||||
style_time.set_text_color(lvgl::Color::from_rgb((255, 255, 255)));
|
||||
time.set_style(&mut style_time);
|
||||
time.set_style(style_time);
|
||||
time.set_align(&mut screen, lvgl::Align::InLeftMid, 20, 0);
|
||||
time.set_text("20:46\0");
|
||||
time.set_text("20:46");
|
||||
time.set_width(240);
|
||||
time.set_height(240);
|
||||
|
||||
let mut bt = lvgl::Label::new(&mut screen);
|
||||
let mut style_bt = lvgl::Style::new();
|
||||
style_bt.set_text_font(font_roboto_28);
|
||||
let mut style_power = style_bt.clone();
|
||||
bt.set_style(&mut style_bt);
|
||||
let style_power = style_bt.clone();
|
||||
bt.set_style(style_bt);
|
||||
bt.set_width(50);
|
||||
bt.set_height(80);
|
||||
bt.set_recolor(true);
|
||||
bt.set_text("#5794f2 \u{F293}#\0");
|
||||
bt.set_text("#5794f2 \u{F293}#");
|
||||
bt.set_label_align(lvgl::LabelAlign::Left);
|
||||
bt.set_align(&mut screen, lvgl::Align::InTopLeft, 0, 0);
|
||||
|
||||
let mut power = lvgl::Label::new(&mut screen);
|
||||
power.set_style(&mut style_power);
|
||||
power.set_style(style_power);
|
||||
power.set_recolor(true);
|
||||
power.set_width(80);
|
||||
power.set_height(20);
|
||||
power.set_text("#fade2a 20%#\0");
|
||||
power.set_text("#fade2a 20%#");
|
||||
power.set_label_align(lvgl::LabelAlign::Right);
|
||||
power.set_align(&mut screen, lvgl::Align::InTopRight, 0, 0);
|
||||
|
||||
let threaded_ui = Arc::new(Mutex::new(ui));
|
||||
|
||||
let (stop_ch, read_ch) = mpsc::channel();
|
||||
let closure_ui = threaded_ui.clone();
|
||||
let tick_thr = std::thread::spawn(move || loop {
|
||||
::std::thread::sleep(Duration::from_millis(5));
|
||||
unsafe {
|
||||
lvgl_sys::lv_tick_inc(5);
|
||||
}
|
||||
let period = Duration::from_millis(5);
|
||||
closure_ui.lock().unwrap().tick_inc(period);
|
||||
|
||||
sleep(period);
|
||||
if read_ch.try_recv().is_ok() {
|
||||
break;
|
||||
}
|
||||
|
@ -83,16 +86,14 @@ fn main() -> Result<(), String> {
|
|||
if i > 59 {
|
||||
i = 0;
|
||||
}
|
||||
time.set_text(format!("21:{:02}\0", i).as_str());
|
||||
time.set_text(format!("21:{:02}", i).as_str());
|
||||
i = 1 + i;
|
||||
|
||||
::std::thread::sleep(Duration::from_millis(
|
||||
sleep(Duration::from_millis(
|
||||
lvgl_sys::LV_DISP_DEF_REFR_PERIOD as u64,
|
||||
));
|
||||
|
||||
unsafe {
|
||||
lvgl_sys::lv_task_handler();
|
||||
}
|
||||
threaded_ui.lock().unwrap().task_handler();
|
||||
|
||||
window.update(&display);
|
||||
|
||||
|
@ -111,6 +112,13 @@ fn main() -> Result<(), String> {
|
|||
}
|
||||
|
||||
// Reference to native font for LittlevGL, defined in the file: "fonts_noto_sans_numeric_80.c"
|
||||
// TODO: Create a macro for defining a safe wrapper for fonts.
|
||||
// Maybe sometihng like:
|
||||
//
|
||||
// font! {
|
||||
// NotoSansNumeric80 = noto_sans_numeric_80;
|
||||
// };
|
||||
//
|
||||
extern "C" {
|
||||
pub static mut noto_sans_numeric_80: lvgl_sys::lv_font_t;
|
||||
}
|
||||
|
|
|
@ -16,3 +16,4 @@ keywords = ["littlevgl", "lvgl", "graphical_interfaces"]
|
|||
lvgl-sys = {path="../lvgl-sys", version="0.1"}
|
||||
cty = "0.2"
|
||||
embedded-graphics = "0.6"
|
||||
cstr_core = { version = "0.2", default-features = false, features = ["alloc"] }
|
||||
|
|
|
@ -1,105 +1,84 @@
|
|||
use crate::objx::ObjectX;
|
||||
use core::marker::PhantomData;
|
||||
use crate::Color;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr;
|
||||
use embedded_graphics;
|
||||
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
||||
use embedded_graphics::prelude::*;
|
||||
use embedded_graphics::{drawable, DrawTarget};
|
||||
use lvgl_sys::lv_color_t;
|
||||
|
||||
pub struct DisplayDriver<'a, T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<ColorRgb>
|
||||
{
|
||||
raw: lvgl_sys::lv_disp_drv_t,
|
||||
display_buffer: MaybeUninit<lvgl_sys::lv_disp_buf_t>,
|
||||
refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>; lvgl_sys::LV_HOR_RES_MAX as usize * 10],
|
||||
phantom: &'a PhantomData<T>,
|
||||
phantom2: PhantomData<C>,
|
||||
pub struct DisplayDriver {
|
||||
pub(crate) raw: lvgl_sys::lv_disp_drv_t,
|
||||
}
|
||||
|
||||
impl<'a, T, C> DisplayDriver<'a, T, C>
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<ColorRgb>
|
||||
{
|
||||
pub fn new(device: &'a mut T) -> Self {
|
||||
// Create a display buffer for LittlevGL
|
||||
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
|
||||
// Declare a buffer for 10 lines
|
||||
let mut refresh_buffer: [MaybeUninit<lvgl_sys::lv_color_t>;
|
||||
lvgl_sys::LV_HOR_RES_MAX as usize * 10] =
|
||||
unsafe { MaybeUninit::uninit().assume_init() };
|
||||
// Initialize the display buffer
|
||||
unsafe {
|
||||
impl DisplayDriver {
|
||||
// we should accept a Rc<RefCell<T>> and throw it in a box and add to the user_data of the callback handler function
|
||||
pub fn new<T, C>(device: &mut T) -> Self
|
||||
where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
let disp_drv = unsafe {
|
||||
// Create a display buffer for LittlevGL
|
||||
let mut display_buffer =
|
||||
Box::new(MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit().assume_init());
|
||||
|
||||
// Declare a buffer for the refresh rate
|
||||
let refresh_buffer = Box::new(
|
||||
MaybeUninit::<
|
||||
[MaybeUninit<lvgl_sys::lv_color_t>; lvgl_sys::LV_HOR_RES_MAX as usize * 10],
|
||||
>::uninit()
|
||||
.assume_init(),
|
||||
);
|
||||
|
||||
// Initialize the display buffer
|
||||
lvgl_sys::lv_disp_buf_init(
|
||||
display_buffer.as_mut_ptr(),
|
||||
refresh_buffer.as_mut_ptr() as *mut cty::c_void,
|
||||
display_buffer.as_mut(),
|
||||
Box::into_raw(refresh_buffer) as *mut cty::c_void,
|
||||
core::ptr::null_mut(),
|
||||
(lvgl_sys::LV_HOR_RES_MAX * 10) as u32,
|
||||
);
|
||||
}
|
||||
let mut disp_drv = unsafe {
|
||||
|
||||
// Descriptor of a display driver
|
||||
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit().assume_init();
|
||||
|
||||
// Basic initialization
|
||||
lvgl_sys::lv_disp_drv_init(&mut disp_drv);
|
||||
|
||||
// Assign the buffer to the display
|
||||
disp_drv.buffer = Box::into_raw(display_buffer);
|
||||
|
||||
// Set your driver function
|
||||
disp_drv.flush_cb = Some(display_callback_wrapper::<T, C>);
|
||||
|
||||
// TODO: DrawHandler type here
|
||||
disp_drv.user_data = device as *mut _ as *mut cty::c_void;
|
||||
|
||||
disp_drv
|
||||
};
|
||||
// Assign the buffer to the display
|
||||
disp_drv.buffer = display_buffer.as_mut_ptr();
|
||||
// Finally register the driver
|
||||
unsafe {
|
||||
lvgl_sys::lv_disp_drv_register(&mut disp_drv);
|
||||
}
|
||||
Self {
|
||||
raw: disp_drv,
|
||||
display_buffer,
|
||||
refresh_buffer,
|
||||
phantom: &PhantomData,
|
||||
phantom2: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_active_screen(&mut self) -> ObjectX<'static> {
|
||||
get_active_screen()
|
||||
Self { raw: disp_drv }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ColorRgb(lv_color_t);
|
||||
// We need to keep a reference to the DisplayDriver in UI if we implement Drop
|
||||
// impl Drop for DisplayDriver {
|
||||
// fn drop(&mut self) {
|
||||
// // grab the user data and deref the DrawHandler to free the instance for dealloc in the Rust universe.
|
||||
// unimplemented!()
|
||||
// }
|
||||
// }
|
||||
|
||||
impl From<ColorRgb> for Rgb888 {
|
||||
fn from(color: ColorRgb) -> Self {
|
||||
// Convert Lvgl to embedded-graphics color
|
||||
let raw_color = color.0;
|
||||
unsafe {
|
||||
Rgb888::new(
|
||||
lvgl_sys::_LV_COLOR_GET_R(raw_color) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_G(raw_color) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_B(raw_color) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ColorRgb> for Rgb565 {
|
||||
fn from(color: ColorRgb) -> Self {
|
||||
// Convert Lvgl to embedded-graphics color
|
||||
let raw_color = color.0;
|
||||
unsafe {
|
||||
Rgb565::new(
|
||||
lvgl_sys::_LV_COLOR_GET_R(raw_color) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_G(raw_color) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_B(raw_color) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// a reference is kept to the external drawing target (T)
|
||||
// the reference is kept in the callback function of the drawing handler
|
||||
// we need a reference counter for the drawing target and free the ref counter when the display is
|
||||
// destroyed.
|
||||
type DrawHandler = Rc<RefCell<u8>>;
|
||||
//
|
||||
// impl Drop for DrawHandler {
|
||||
// fn drop(&mut self) {
|
||||
// unimplemented!()
|
||||
// }
|
||||
// }
|
||||
|
||||
unsafe extern "C" fn display_callback_wrapper<T, C>(
|
||||
disp_drv: *mut lvgl_sys::lv_disp_drv_t,
|
||||
|
@ -107,7 +86,7 @@ unsafe extern "C" fn display_callback_wrapper<T, C>(
|
|||
color_p: *mut lvgl_sys::lv_color_t,
|
||||
) where
|
||||
T: DrawTarget<C>,
|
||||
C: PixelColor + From<ColorRgb>
|
||||
C: PixelColor + From<Color>,
|
||||
{
|
||||
// We need to make sure panics can't escape across the FFI boundary.
|
||||
//let _ = std::panic::catch_unwind(|| {
|
||||
|
@ -121,10 +100,13 @@ unsafe extern "C" fn display_callback_wrapper<T, C>(
|
|||
//let image_buffer =
|
||||
for y in (*area).y1..=(*area).y2 {
|
||||
for x in (*area).x1..=(*area).x2 {
|
||||
let raw_color = ColorRgb(*color_p.add(i));
|
||||
let raw_color = Color::from_raw(*color_p.add(i));
|
||||
i = i + 1;
|
||||
// TODO: Use device.draw_iter
|
||||
let _ = device.draw_pixel(drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into()));
|
||||
let _ = device.draw_pixel(drawable::Pixel(
|
||||
Point::new(x as i32, y as i32),
|
||||
raw_color.into(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,9 +114,3 @@ unsafe extern "C" fn display_callback_wrapper<T, C>(
|
|||
lvgl_sys::lv_disp_flush_ready(disp_drv);
|
||||
//}); // end of panic::catch_unwind
|
||||
}
|
||||
|
||||
pub fn get_active_screen() -> ObjectX<'static> {
|
||||
let raw =
|
||||
unsafe { ptr::NonNull::new_unchecked(lvgl_sys::lv_disp_get_scr_act(ptr::null_mut())) };
|
||||
ObjectX::new(raw)
|
||||
}
|
||||
|
|
68
lvgl/src/global.rs
Normal file
68
lvgl/src/global.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use crate::{DisplayDriver, ObjectX};
|
||||
use alloc::boxed::Box;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::time::Duration;
|
||||
|
||||
// There can only be a single reference to LittlevGL library.
|
||||
static LVGL_IN_USE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
|
||||
pub enum LvError {
|
||||
Uninitialized,
|
||||
AlreadyInUse,
|
||||
}
|
||||
|
||||
pub struct UI {
|
||||
// LittlevGL is not thread-safe by default.
|
||||
_not_sync: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
// LittlevGL does not use thread locals.
|
||||
unsafe impl Send for UI {}
|
||||
|
||||
impl UI {
|
||||
pub fn init() -> Result<Self, LvError> {
|
||||
if LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) == false {
|
||||
unsafe {
|
||||
lvgl_sys::lv_init();
|
||||
}
|
||||
Ok(Self {
|
||||
_not_sync: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(LvError::AlreadyInUse)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn disp_drv_register(&mut self, display: DisplayDriver) {
|
||||
// Throw display driver into a box and add to user data (if we need to get the display back)
|
||||
// or simply forget the display pointer/object to prevent Drop to be called
|
||||
// register it
|
||||
unsafe {
|
||||
let boxed = Box::new(display.raw);
|
||||
lvgl_sys::lv_disp_drv_register(Box::into_raw(boxed));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scr_act(&self) -> ObjectX {
|
||||
unsafe {
|
||||
let screen = lvgl_sys::lv_disp_get_scr_act(ptr::null_mut());
|
||||
ObjectX::from_raw(NonNull::new_unchecked(screen))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick_inc(&mut self, tick_period: Duration) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_tick_inc(tick_period.as_millis() as u32);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn task_handler(&mut self) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_task_handler();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
#![no_std]
|
||||
|
||||
pub mod display;
|
||||
mod objx;
|
||||
extern crate alloc;
|
||||
|
||||
mod global;
|
||||
mod display;
|
||||
mod support;
|
||||
mod widgets;
|
||||
|
||||
pub use global::{UI, LvError};
|
||||
pub use display::DisplayDriver;
|
||||
pub use objx::*;
|
||||
pub use support::*;
|
||||
|
|
|
@ -1,30 +1,31 @@
|
|||
use alloc::boxed::Box;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use cty;
|
||||
use cstr_core::CString;
|
||||
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
||||
use lvgl_sys;
|
||||
|
||||
pub trait NativeObject {
|
||||
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
|
||||
}
|
||||
|
||||
pub struct ObjectX<'a> {
|
||||
pub struct ObjectX {
|
||||
raw: ptr::NonNull<lvgl_sys::lv_obj_t>,
|
||||
style: Option<&'a mut Style>,
|
||||
}
|
||||
|
||||
impl<'a> ObjectX<'a> {
|
||||
pub(crate) fn new(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
|
||||
Self { raw, style: None }
|
||||
impl ObjectX {
|
||||
pub(crate) fn from_raw(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
|
||||
Self { raw }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NativeObject for ObjectX<'a> {
|
||||
impl NativeObject for ObjectX {
|
||||
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
|
||||
unsafe { ptr::NonNull::new_unchecked(self.raw.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Object<'a>: NativeObject {
|
||||
pub trait Object: NativeObject {
|
||||
fn set_pos(&mut self, x: i16, y: i16) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_set_pos(
|
||||
|
@ -95,36 +96,36 @@ pub trait Object<'a>: NativeObject {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_style(&mut self, style: &'a mut Style);
|
||||
fn set_style(&mut self, style: Style);
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> for ObjectX<'a> {
|
||||
fn set_style(&mut self, style: &'a mut Style) {
|
||||
impl Object for ObjectX {
|
||||
fn set_style(&mut self, style: Style) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw());
|
||||
let boxed = Box::new(style.raw);
|
||||
lvgl_sys::lv_obj_set_style(self.raw().as_mut(), Box::into_raw(boxed));
|
||||
};
|
||||
self.style = Some(style);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_object {
|
||||
($item:ident) => {
|
||||
pub struct $item<'a> {
|
||||
core: ObjectX<'a>,
|
||||
pub struct $item {
|
||||
core: ObjectX,
|
||||
}
|
||||
|
||||
impl<'a> NativeObject for $item<'a> {
|
||||
impl NativeObject for $item {
|
||||
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
|
||||
self.core.raw()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Object<'a> for $item<'a> {
|
||||
fn set_style(&mut self, style: &'a mut Style) {
|
||||
impl Object for $item {
|
||||
fn set_style(&mut self, style: Style) {
|
||||
unsafe {
|
||||
lvgl_sys::lv_obj_set_style(self.raw().as_mut(), style.raw());
|
||||
let boxed = Box::new(style.raw);
|
||||
lvgl_sys::lv_obj_set_style(self.raw().as_mut(), Box::into_raw(boxed));
|
||||
};
|
||||
self.core.style = Some(style);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -132,7 +133,7 @@ macro_rules! define_object {
|
|||
|
||||
define_object!(Button);
|
||||
|
||||
impl<'a> Button<'a> {
|
||||
impl Button {
|
||||
pub fn new<C>(parent: &mut C) -> Self
|
||||
where
|
||||
C: NativeObject,
|
||||
|
@ -141,7 +142,7 @@ impl<'a> Button<'a> {
|
|||
let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut());
|
||||
ptr::NonNull::new_unchecked(ptr)
|
||||
};
|
||||
let core = ObjectX::new(raw);
|
||||
let core = ObjectX::from_raw(raw);
|
||||
Self { core }
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +156,7 @@ pub enum LabelAlign {
|
|||
|
||||
define_object!(Label);
|
||||
|
||||
impl<'a> Label<'a> {
|
||||
impl Label {
|
||||
pub fn new<C>(parent: &mut C) -> Self
|
||||
where
|
||||
C: NativeObject,
|
||||
|
@ -164,16 +165,14 @@ impl<'a> Label<'a> {
|
|||
let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut());
|
||||
ptr::NonNull::new_unchecked(ptr)
|
||||
};
|
||||
let core = ObjectX::new(raw);
|
||||
let core = ObjectX::from_raw(raw);
|
||||
Self { core }
|
||||
}
|
||||
|
||||
pub fn set_text(&mut self, text: &str) {
|
||||
let text = CString::new(text).unwrap();
|
||||
unsafe {
|
||||
lvgl_sys::lv_label_set_text(
|
||||
self.core.raw().as_mut(),
|
||||
text.as_ptr() as *const cty::c_char,
|
||||
);
|
||||
lvgl_sys::lv_label_set_text(self.core.raw().as_mut(), text.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,10 +232,6 @@ impl Style {
|
|||
pub fn set_text_font(&mut self, font: &lvgl_sys::lv_font_t) {
|
||||
self.raw.text.font = font;
|
||||
}
|
||||
|
||||
fn raw(&mut self) -> *const lvgl_sys::lv_style_t {
|
||||
&mut self.raw
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Style {
|
||||
|
@ -264,6 +259,34 @@ impl Color {
|
|||
let raw = unsafe { lvgl_sys::_LV_COLOR_MAKE(r, g, b) };
|
||||
Self { raw }
|
||||
}
|
||||
|
||||
pub fn from_raw(raw: lvgl_sys::lv_color_t) -> Self {
|
||||
Self { raw }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for Rgb888 {
|
||||
fn from(color: Color) -> Self {
|
||||
unsafe {
|
||||
Rgb888::new(
|
||||
lvgl_sys::_LV_COLOR_GET_R(color.raw) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_G(color.raw) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_B(color.raw) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for Rgb565 {
|
||||
fn from(color: Color) -> Self {
|
||||
unsafe {
|
||||
Rgb565::new(
|
||||
lvgl_sys::_LV_COLOR_GET_R(color.raw) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_G(color.raw) as u8,
|
||||
lvgl_sys::_LV_COLOR_GET_B(color.raw) as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Align {
|
0
lvgl/src/widgets.rs
Normal file
0
lvgl/src/widgets.rs
Normal file
Loading…
Reference in a new issue