Compare commits

..

No commits in common. "master" and "0.3.1" have entirely different histories.

29 changed files with 776 additions and 1777 deletions

View file

@ -1,33 +0,0 @@
name: Rust
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
CARGO_TERM_COLOR: always
DEP_LV_CONFIG_PATH: /home/runner/work/lvgl-rs/lvgl-rs/examples/include
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Update APT
run: sudo apt-get update
- name: Install SDL2
run: sudo apt install libsdl2-dev libsdl2-2.0-0
- uses: actions/checkout@v2
with:
submodules: true
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose

View file

@ -1,6 +1,7 @@
[workspace]
members = [
"lvgl",
"lvgl-codegen",
"lvgl-sys",
"lvgl-codegen",
"examples"
]

View file

@ -1,41 +1,24 @@
[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
<h1 align="center"> LittlevGL - Open-source Embedded GUI Library in Rust</h1>
<h1 align="center"> LVGL - Open-source Embedded GUI Library in Rust</h1>
![Original LVGL demo image](lv_demo.png)
![Original LittlevGL demo image](lv_demo.png)
<p align="center">
LVGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint.
LittlevGL provides everything you need to create a Graphical User Interface (GUI) on embedded systems with easy-to-use graphical elements, beautiful visual effects and low memory footprint.
</p>
<p align="center">
LVGL is compatible with <samp>#![no_std]</samp> environments by default.
LittlevGL is compatible with <samp>#![no_std]</samp> environments by default.
</p>
<h4 align="center">
<a href="https://github.com/rafaelcaricio/lvgl-rs-wasm">Rust to WASM demo</a> &middot;
<a href="https://lvgl.io/">Official LVGL Website </a> &middot;
<a href="https://lvgl.io/">Official LittlevGL Website </a> &middot;
<a href="https://github.com/littlevgl/lvgl">C library repository</a> &middot;
<a href="https://lvgl.io/demos">Official live demos</a>
<a href="https://lvgl.io/demos">Live demo</a>
</h4>
---
![Rust bindings usage demo code.](demo.png)
## System Build Dependencies
In order to build the `lvgl` project you will need the following system dependencies to be installed:
```
$ sudo apt install build-essential llvm clang
```
If you want to build the examples, then you will need to install SDL2 as well.
```
$ sudo apt install libsdl2-dev
```
## Usage
Edit your `Cargo.toml` file dependencies with:
@ -45,7 +28,7 @@ $ cargo add lvgl
The build requires the environment variable bellow to be set:
- `DEP_LV_CONFIG_PATH`: Path to the directory containing the `lv_conf.h` header file used for configuration of LVGL library.
- `DEP_LV_CONFIG_PATH`: Path to the directory containing the `lv_conf.h` header file used for configuration of LittlevGL library.
We recommend the `lv_conf.h` file to be in your project's root directory. If so, the command to build your project would be:
```shell script
@ -61,22 +44,16 @@ for `no_std`, so we need to use a workaround to build "lvgl-rs". The mainstrem i
```shell
$ DEP_LV_CONFIG_PATH=`pwd` cargo build -Zfeatures=build_dep
```
### LVGL Global Allocator
A [global allocator](https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html) for Rust leveraging the
[LVGL memory allocator](https://github.com/lvgl/lvgl/blob/master/src/misc/lv_mem.h) is provided, but not enabled
by default. Can be enabled by the feature `lvgl_alloc`. This will make all dynamic memory to be allocated by LVGL
internal memory manager.
#### Requirements / Limitations
LittlevGL C libary do allocate memory dynamically and we need to allocate memory on the heap in the Rust side as well
([`Box`](https://doc.rust-lang.org/beta/alloc/boxed/struct.Box.html)).
That is required, so we can safely provide Rust pointers through FFI. For that reason, we do require
[`alloc`](https://doc.rust-lang.org/alloc/) module to be available.
## Running the demo
**Hint for macOS users**: Before you run the demos you need to make sure you have [libsdl](https://www.libsdl.org)
installed on your machine. To install it, use HomeBrew:
```shell
$ brew install sdl2
```
[This project contains examples that can run in a desktop simulator.](./examples)
First, make sure to pull `lvgl-rs` submodules:
@ -88,7 +65,7 @@ $ git submodule update
Then run the `demo` example:
```shell
$ DEP_LV_CONFIG_PATH=`pwd`/examples/include cargo run --example demo --features="alloc"
$ DEP_LV_CONFIG_PATH=`pwd`/examples/include cargo run --example demo
```
## Feature Support

32
examples/Cargo.toml Normal file
View file

@ -0,0 +1,32 @@
[package]
name = "demo"
version = "0.1.0"
authors = ["Rafael Caricio <crates@caric.io>"]
edition = "2018"
publish = false
[dev-dependencies]
lvgl = { path = "../lvgl" }
lvgl-sys = { path = "../lvgl-sys" }
embedded-graphics = "0.6"
embedded-graphics-simulator = "0.2.0"
[[example]]
name = "demo"
path = "demo.rs"
[[example]]
name = "bar"
path = "bar.rs"
[[example]]
name = "button_click"
path = "button_click.rs"
[[example]]
name = "gauge"
path = "gauge.rs"
[[example]]
name = "arc"
path = "arc.rs"

View file

@ -1,42 +1,19 @@
use cstr_core::CString;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use lvgl::style::Style;
use lvgl::widgets::{Arc, Label, LabelAlign};
use lvgl::{self, Align, Color, Part, State, UI};
use lvgl::widgets::{Arc, ArcPart, Label, LabelAlign};
use lvgl::{self, Align, Color, DisplayDriver, Part, State, UI};
use lvgl::{LvError, Widget};
use lvgl_sys;
use std::time::Instant;
fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
let mut info = lvgl_sys::lv_mem_monitor_t {
total_size: 0,
free_cnt: 0,
free_size: 0,
free_biggest_size: 0,
used_cnt: 0,
max_used: 0,
used_pct: 0,
frag_pct: 0,
};
unsafe {
lvgl_sys::lv_mem_monitor(&mut info as *mut _);
}
info
}
use std::sync::{mpsc, Arc as StdArc, Mutex};
use std::thread::sleep;
use std::time::Duration;
fn main() -> Result<(), LvError> {
println!("meminfo init: {:?}", mem_info());
run_arc_demo()?;
println!("meminfo end: {:?}", mem_info());
Ok(())
}
fn run_arc_demo() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
));
@ -47,7 +24,8 @@ fn run_arc_demo() -> Result<(), LvError> {
let mut ui = UI::init()?;
// Implement and register your display:
ui.disp_drv_register(display)?;
let display_driver = DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act()?;
@ -65,7 +43,7 @@ fn run_arc_demo() -> Result<(), LvError> {
arc.set_end_angle(135)?;
let mut loading_lbl = Label::new(&mut screen)?;
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
loading_lbl.set_text("Loading...")?;
loading_lbl.set_align(&mut arc, Align::OutTopMid, 0, -10)?;
loading_lbl.set_label_align(LabelAlign::Center)?;
@ -73,23 +51,38 @@ fn run_arc_demo() -> Result<(), LvError> {
loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
loading_lbl.add_style(Part::Main, loading_style)?;
let threaded_ui = StdArc::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 {
let period = Duration::from_millis(10);
closure_ui.lock().unwrap().tick_inc(period);
sleep(period);
if read_ch.try_recv().is_ok() {
break;
}
});
let mut angle = 0;
let mut forward = true;
let mut i = 0;
let mut loop_started = Instant::now();
let mut i = 0;
'running: loop {
if i > 270 {
forward = if forward { false } else { true };
i = 1;
println!("meminfo running: {:?}", mem_info());
}
angle = if forward { angle + 1 } else { angle - 1 };
arc.set_end_angle(angle + 135)?;
i += 1;
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
sleep(Duration::from_millis(10));
threaded_ui.lock().unwrap().task_handler();
window.update(&display);
for event in window.events() {
match event {
@ -97,10 +90,10 @@ fn run_arc_demo() -> Result<(), LvError> {
_ => {}
}
}
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
}
stop_ch.send(true).unwrap();
tick_thr.join().unwrap();
Ok(())
}

View file

@ -1,17 +1,18 @@
use cstr_core::CString;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use lvgl::style::Style;
use lvgl::widgets::{Bar, Label, LabelAlign};
use lvgl::{self, Align, Animation, Color, Event, LvError, Part, State, Widget, UI};
use lvgl::widgets::{Bar, BarPart, Label, LabelAlign};
use lvgl::{self, Align, Animation, Color, DisplayDriver, Event, LvError, Part, State, Widget, UI};
use lvgl_sys;
use std::time::Instant;
use std::sync::{mpsc, Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;
fn main() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
));
@ -22,7 +23,8 @@ fn main() -> Result<(), LvError> {
let mut ui = UI::init()?;
// Implement and register your display:
ui.disp_drv_register(display).unwrap();
let display_driver = DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act()?;
@ -37,9 +39,6 @@ fn main() -> Result<(), LvError> {
bar.set_size(175, 20)?;
bar.set_align(&mut screen, Align::Center, 0, 10)?;
bar.set_range(0, 100)?;
bar.on_event(|_b, _e| {
println!("Completed!");
})?;
// // Set the indicator style for the bar object
let mut ind_style = Style::default();
@ -47,7 +46,7 @@ fn main() -> Result<(), LvError> {
bar.add_style(Part::All, ind_style)?;
let mut loading_lbl = Label::new(&mut screen)?;
loading_lbl.set_text(CString::new("Loading...").unwrap().as_c_str())?;
loading_lbl.set_text("Loading...")?;
loading_lbl.set_align(&mut bar, Align::OutTopMid, 0, -10)?;
loading_lbl.set_label_align(LabelAlign::Center)?;
@ -55,18 +54,37 @@ fn main() -> Result<(), LvError> {
loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
loading_lbl.add_style(Part::Main, loading_style)?;
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 {
let period = Duration::from_millis(5);
closure_ui.lock().unwrap().tick_inc(period);
sleep(period);
if read_ch.try_recv().is_ok() {
break;
}
});
let mut i = 0;
let mut loop_started = Instant::now();
'running: loop {
if i > 100 {
i = 0;
ui.event_send(&mut bar, Event::Clicked)?;
threaded_ui
.lock()
.unwrap()
.event_send(&mut loading_lbl, Event::Clicked)?
}
bar.set_value(i, Animation::ON)?;
bar.set_value(i, Animation::OFF)?;
i += 1;
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
sleep(Duration::from_millis(25));
threaded_ui.lock().unwrap().task_handler();
window.update(&display);
for event in window.events() {
match event {
@ -74,10 +92,10 @@ fn main() -> Result<(), LvError> {
_ => {}
}
}
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
}
stop_ch.send(true).unwrap();
tick_thr.join().unwrap();
Ok(())
}

View file

@ -1,4 +1,3 @@
use cstr_core::CString;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{
@ -6,12 +5,14 @@ use embedded_graphics_simulator::{
};
use lvgl::style::Style;
use lvgl::widgets::{Btn, Label};
use lvgl::{self, Align, Color, Event, LvError, Part, State, Widget, UI};
use lvgl::{self, Align, Color, DisplayDriver, Event, LvError, Part, State, Widget, UI};
use lvgl_sys;
use std::time::Instant;
use std::sync::{mpsc, Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;
fn main() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
));
@ -22,7 +23,8 @@ fn main() -> Result<(), LvError> {
let mut ui = UI::init()?;
// Implement and register your display:
ui.disp_drv_register(display)?;
let display_driver = DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act()?;
@ -36,29 +38,42 @@ fn main() -> Result<(), LvError> {
button.set_align(&mut screen, Align::InLeftMid, 30, 0)?;
button.set_size(180, 80)?;
let mut btn_lbl = Label::new(&mut button)?;
btn_lbl.set_text(CString::new("Click me!").unwrap().as_c_str())?;
btn_lbl.set_text("Click me!")?;
let mut btn_state = false;
button.on_event(|mut btn, event| {
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("Click me!").unwrap();
} else {
let nt = CString::new("Clicked!").unwrap();
btn_lbl.set_text(nt.as_c_str()).unwrap();
btn_lbl.set_text("Clicked!").unwrap();
}
btn_state = !btn_state;
println!("Clicked! Inner..");
println!("Clicked!");
btn.toggle().unwrap();
}
})?;
let mut loop_started = Instant::now();
'running: loop {
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
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 {
let period = Duration::from_millis(5);
// Needs to be called periodically for LittlevGL internal timing calculations.
closure_ui.lock().unwrap().tick_inc(period);
sleep(period);
if read_ch.try_recv().is_ok() {
break;
}
});
'running: loop {
threaded_ui.lock().unwrap().task_handler();
window.update(&display);
for event in window.events() {
match event {
SimulatorEvent::MouseButtonUp {
@ -67,16 +82,21 @@ fn main() -> Result<(), LvError> {
} => {
println!("Clicked on: {:?}", point);
// Send a event to the button directly
ui.event_send(&mut button, Event::Clicked)?;
threaded_ui
.lock()
.unwrap()
.event_send(&mut button, Event::Clicked)?;
}
SimulatorEvent::Quit => break 'running,
_ => {}
}
}
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
sleep(Duration::from_millis(5));
}
stop_ch.send(true).unwrap();
tick_thr.join().unwrap();
Ok(())
}

View file

@ -1,4 +1,3 @@
use cstr_core::CString;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::*;
use embedded_graphics_simulator::{
@ -9,11 +8,12 @@ use lvgl::style::Style;
use lvgl::widgets::{Label, LabelAlign};
use lvgl::{Align, Color, LvError, Part, State, Widget, UI};
use lvgl_sys;
use std::sync::{mpsc, Arc, Mutex};
use std::thread::sleep;
use std::time::{Duration, Instant};
use std::time::Duration;
fn main() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
));
@ -24,11 +24,15 @@ fn main() -> Result<(), LvError> {
let mut ui = UI::init()?;
// Implement and register your display:
ui.disp_drv_register(display).unwrap();
let display_driver = lvgl::DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act()?;
let font_roboto_28 = unsafe { &lvgl_sys::lv_theme_get_font_normal() };
let font_noto_sans_numeric_28 = unsafe { &noto_sans_numeric_80 };
let mut screen_style = Style::default();
screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((0, 0, 0)));
screen_style.set_radius(State::DEFAULT, 0);
@ -40,7 +44,7 @@ fn main() -> Result<(), LvError> {
style_time.set_text_color(State::DEFAULT, Color::from_rgb((255, 255, 255)));
time.add_style(Part::Main, style_time)?;
time.set_align(&mut screen, Align::Center, 0, 0)?;
time.set_text(CString::new("20:46").unwrap().as_c_str())?;
time.set_text("20:46")?;
time.set_width(240)?;
time.set_height(240)?;
@ -48,7 +52,7 @@ fn main() -> Result<(), LvError> {
bt.set_width(50)?;
bt.set_height(80)?;
bt.set_recolor(true)?;
bt.set_text(CString::new("#5794f2 \u{F293}#").unwrap().as_c_str())?;
bt.set_text("#5794f2 \u{F293}#")?;
bt.set_label_align(LabelAlign::Left)?;
bt.set_align(&mut screen, Align::InTopLeft, 0, 0)?;
@ -56,22 +60,37 @@ fn main() -> Result<(), LvError> {
power.set_recolor(true)?;
power.set_width(80)?;
power.set_height(20)?;
power.set_text(CString::new("#fade2a 20%#").unwrap().as_c_str())?;
power.set_text("#fade2a 20%#")?;
power.set_label_align(LabelAlign::Right)?;
power.set_align(&mut screen, 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 {
let period = Duration::from_millis(250);
closure_ui.lock().unwrap().tick_inc(period);
sleep(period);
if read_ch.try_recv().is_ok() {
break;
}
});
let mut i = 0;
let mut loop_started = Instant::now();
'running: loop {
if i > 59 {
i = 0;
}
let val = CString::new(format!("21:{:02}", i)).unwrap();
time.set_text(&val)?;
time.set_text(format!("21:{:02}", i).as_str())?;
i = 1 + i;
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
sleep(Duration::from_secs(1));
threaded_ui.lock().unwrap().task_handler();
window.update(&display);
for event in window.events() {
match event {
@ -79,16 +98,15 @@ fn main() -> Result<(), LvError> {
_ => {}
}
}
sleep(Duration::from_secs(1));
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
}
stop_ch.send(true).unwrap();
tick_thr.join().unwrap();
Ok(())
}
// Reference to native font for LVGL, defined in the file: "fonts_noto_sans_numeric_80.c"
// 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:
//

View file

@ -4,13 +4,15 @@ use embedded_graphics_simulator::{
OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window,
};
use lvgl::style::{Opacity, Style};
use lvgl::widgets::Gauge;
use lvgl::{self, Align, Color, LvError, Part, State, Widget, UI};
use lvgl::widgets::{Gauge, GaugePart};
use lvgl::{self, Align, Color, DisplayDriver, LvError, Part, State, Widget, UI};
use lvgl_sys;
use std::time::Instant;
use std::sync::{mpsc, Arc, Mutex};
use std::thread::sleep;
use std::time::Duration;
fn main() -> Result<(), LvError> {
let display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
let mut display: SimulatorDisplay<Rgb565> = SimulatorDisplay::new(Size::new(
lvgl_sys::LV_HOR_RES_MAX,
lvgl_sys::LV_VER_RES_MAX,
));
@ -21,7 +23,8 @@ fn main() -> Result<(), LvError> {
let mut ui = UI::init()?;
// Implement and register your display:
ui.disp_drv_register(display)?;
let display_driver = DisplayDriver::new(&mut display);
ui.disp_drv_register(display_driver);
// Create screen and widgets
let mut screen = ui.scr_act()?;
@ -54,14 +57,27 @@ fn main() -> Result<(), LvError> {
gauge.set_align(&mut screen, Align::Center, 0, 0)?;
gauge.set_value(0, 50)?;
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 {
let period = Duration::from_millis(5);
// Needs to be called periodically for LittlevGL internal timing calculations.
closure_ui.lock().unwrap().tick_inc(period);
sleep(period);
if read_ch.try_recv().is_ok() {
break;
}
});
let mut i = 0;
let mut loop_started = Instant::now();
'running: loop {
gauge.set_value(0, i)?;
ui.task_handler();
window.update(ui.get_display_ref().unwrap());
threaded_ui.lock().unwrap().task_handler();
window.update(&display);
for event in window.events() {
match event {
SimulatorEvent::MouseButtonUp {
@ -75,15 +91,18 @@ fn main() -> Result<(), LvError> {
}
}
sleep(Duration::from_millis(25));
gauge.set_value(0, i)?;
if i > 99 {
i = 0;
} else {
i = i + 1;
}
ui.tick_inc(loop_started.elapsed());
loop_started = Instant::now();
}
stop_ch.send(true).unwrap();
tick_thr.join().unwrap();
Ok(())
}

View file

@ -80,7 +80,7 @@ typedef int16_t lv_coord_t;
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
# define LV_MEM_SIZE (1048576U) // 1Mb
# define LV_MEM_SIZE (32U * 1024U)
/* Complier prefix for a big array declaration */
# define LV_MEM_ATTR

View file

@ -1,6 +1,6 @@
[package]
name = "lvgl-codegen"
version = "0.5.2"
version = "0.3.0"
description = "Code generation based on LVGL source code"
authors = ["Rafael Caricio <crates.lvgl@caric.io>"]
readme = "README.md"
@ -9,10 +9,11 @@ license = "MIT"
repository = "https://github.com/rafaelcaricio/lvgl-rs"
[dependencies]
regex = "1.4.3"
quote = "1.0.9"
regex = "1.3.9"
quote = "1.0.7"
lazy_static = "1.4.0"
proc-macro2 = "1.0.27"
itertools = "0.9.0"
proc-macro2 = "1.0.18"
Inflector = "0.11.4"
syn = { version = "1.0.72", features = ["full"]}
syn = { version = "1.0.31", features = ["full"]}

View file

@ -1,11 +1,12 @@
use inflector::cases::pascalcase::to_pascal_case;
use lazy_static::lazy_static;
use proc_macro2::{Ident, TokenStream};
use quote::format_ident;
use quote::quote;
use quote::{format_ident, ToTokens};
use regex::Regex;
use std::collections::HashMap;
use std::error::Error;
use syn::export::ToTokens;
use syn::{FnArg, ForeignItem, ForeignItemFn, Item, ReturnType};
type CGResult<T> = Result<T, Box<dyn Error>>;
@ -18,7 +19,7 @@ lazy_static! {
("i32", "i32"),
("u8", "u8"),
("bool", "bool"),
("* const cty :: c_char", "_"),
("* const cty :: c_char", "&str"),
]
.iter()
.cloned()
@ -49,7 +50,7 @@ impl Rusty for LvWidget {
fn code(&self, _parent: &Self::Parent) -> WrapperResult<TokenStream> {
// We don't generate for the generic Obj
if self.name.as_str().eq("obj") {
if self.name.eq("obj") {
return Err(WrapperError::Skip);
}
@ -78,7 +79,7 @@ impl LvFunc {
}
pub fn is_method(&self) -> bool {
if !self.args.is_empty() {
if self.args.len() > 0 {
let first_arg = &self.args[0];
return first_arg.typ.literal_name.contains("lv_obj_t");
}
@ -96,24 +97,19 @@ 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.eq("create") {
return Ok(quote! {
pub fn new<C>(parent: &mut C) -> crate::LvResult<Self>
where
C: crate::NativeObject,
{
unsafe {
let ptr = lvgl_sys::#original_func_name(parent.raw()?.as_mut(), core::ptr::null_mut());
if let Some(raw) = core::ptr::NonNull::new(ptr) {
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
} else {
Err(crate::LvError::InvalidReference)
}
let raw = core::ptr::NonNull::new(ptr)?;
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
}
}
});
}
@ -263,11 +259,17 @@ impl LvArg {
}
pub fn get_processing(&self) -> TokenStream {
let ident = self.get_name_ident();
// 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.typ.is_str() {
quote! {
let #ident = cstr_core::CString::new(#ident)?;
}
} else {
// No need to pre-process this type of argument
quote! {}
}
}
pub fn get_value_usage(&self) -> TokenStream {
@ -303,21 +305,21 @@ impl Rusty for LvArg {
#[derive(Clone)]
pub struct LvType {
literal_name: String,
_r_type: Option<Box<syn::Type>>,
r_type: Option<Box<syn::Type>>,
}
impl LvType {
pub fn new(literal_name: String) -> Self {
Self {
literal_name,
_r_type: None,
r_type: None,
}
}
pub fn from(r_type: Box<syn::Type>) -> Self {
Self {
literal_name: r_type.to_token_stream().to_string(),
_r_type: Some(r_type),
r_type: Some(r_type),
}
}
@ -337,7 +339,7 @@ impl Rusty for LvType {
match TYPE_MAPPINGS.get(self.literal_name.as_str()) {
Some(name) => {
let val = if self.is_str() {
quote!(&cstr_core::CStr)
quote!(&str)
} else {
let ident = format_ident!("{}", name);
quote!(#ident)
@ -373,7 +375,7 @@ impl CodeGen {
&self.widgets
}
fn extract_widgets(functions: &[LvFunc]) -> CGResult<Vec<LvWidget>> {
fn extract_widgets(functions: &Vec<LvFunc>) -> CGResult<Vec<LvWidget>> {
let widget_names = Self::get_widget_names(functions);
let widgets = functions.iter().fold(HashMap::new(), |mut ws, f| {
@ -394,25 +396,25 @@ impl CodeGen {
ws
});
Ok(widgets.values().cloned().collect())
Ok(widgets.values().map(|v| v.clone()).collect())
}
fn get_widget_names(functions: &[LvFunc]) -> Vec<String> {
fn get_widget_names(functions: &Vec<LvFunc>) -> Vec<String> {
let reg = format!("^{}([^_]+)_create$", LIB_PREFIX);
let create_func = Regex::new(reg.as_str()).unwrap();
functions
.iter()
.filter(|e| create_func.is_match(e.name.as_str()) && e.args.len() == 2)
.map(|f| {
String::from(
.filter_map(|f| {
Some(String::from(
create_func
.captures(f.name.as_str())
.unwrap()
.get(1)
.unwrap()
.as_str(),
)
))
})
.collect::<Vec<_>>()
}
@ -571,8 +573,8 @@ mod test {
let code = label_set_text.code(&parent_widget).unwrap();
let expected_code = quote! {
pub fn set_text(&mut self, text: &cstr_core::CStr) -> crate::LvResult<()> {
pub fn set_text(&mut self, text: &str) -> crate::LvResult<()> {
let text = cstr_core::CString::new(text)?;
unsafe {
lvgl_sys::lv_label_set_text(
self.core.raw()?.as_mut(),
@ -581,7 +583,6 @@ mod test {
}
Ok(())
}
};
assert_eq!(code.to_string(), expected_code.to_string());
@ -635,15 +636,11 @@ mod test {
where
C: crate::NativeObject,
{
unsafe {
let ptr = lvgl_sys::lv_arc_create(parent.raw()?.as_mut(), core::ptr::null_mut());
if let Some(raw) = core::ptr::NonNull::new(ptr) {
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
} else {
Err(crate::LvError::InvalidReference)
}
let raw = core::ptr::NonNull::new(ptr)?;
let core = <crate::Obj as crate::Widget>::from_raw(raw);
Ok(Self { core })
}
}
}

View file

@ -1,7 +1,7 @@
[package]
name = "lvgl-sys"
description = "Raw bindings to the LVGL C library."
version = "0.5.2"
description = "Raw bindings to the LittlevGL C library."
version = "0.3.1"
authors = ["Rafael Caricio <crates.lvgl-sys@caric.io>"]
edition = "2018"
license = "MIT"
@ -20,8 +20,5 @@ name = "lvgl_sys"
cty = "0.2.1"
[build-dependencies]
cc = "1.0.68"
bindgen = "0.59.2"
[features]
use-vendored-config = []
cc = "1.0.50"
bindgen = "0.54.0"

View file

@ -5,7 +5,7 @@ Rust raw bindings for LittlevGL library.
Build requires environment variables to be set:
- `DEP_LV_CONFIG_PATH`: Path to the directory containing the `lv_conf.h` header file used for configuration of LVGL library.
- `DEP_LV_CONFIG_PATH`: Path to the directory containing the `lv_conf.h` header file used for configuration of LittlevGL library.
We recommend the `lv_conf.h` file to be in your project's root directory. If so, the command to build your project would be:
```shell script

View file

@ -4,50 +4,36 @@ use std::{env, path::Path, path::PathBuf};
static CONFIG_NAME: &str = "DEP_LV_CONFIG_PATH";
fn main() {
let project_dir = canonicalize(PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()));
let project_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
.canonicalize()
.unwrap();
let shims_dir = project_dir.join("shims");
let vendor = project_dir.join("vendor");
let vendor_src = vendor.join("lvgl").join("src");
let lv_config_dir = {
let conf_path = env::var(CONFIG_NAME)
.map(PathBuf::from)
.unwrap_or_else(|_| {
match std::env::var("DOCS_RS") {
Ok(_) => {
// We've detected that we are building for docs.rs
// so let's use the vendored `lv_conf.h` file.
vendor.join("include")
}
Err(_) => {
#[cfg(not(feature = "use-vendored-config"))]
panic!(
"The environment variable {} is required to be defined",
CONFIG_NAME
);
#[cfg(feature = "use-vendored-config")]
vendor.join("include")
}
}
});
let raw_path = env::var(CONFIG_NAME).unwrap_or_else(|_| {
panic!(
"The environment variable {} is required to be defined",
CONFIG_NAME
);
});
let conf_path = PathBuf::from(raw_path);
if !conf_path.exists() {
panic!(
"Directory {} referenced by {} needs to exist",
conf_path.to_string_lossy(),
panic!(format!(
"Directory referenced by {} needs to exist",
CONFIG_NAME
);
));
}
if !conf_path.is_dir() {
panic!("{} needs to be a directory", CONFIG_NAME);
panic!(format!("{} needs to be a directory", CONFIG_NAME));
}
if !conf_path.join("lv_conf.h").exists() {
panic!(
"Directory {} referenced by {} needs to contain a file called lv_conf.h",
conf_path.to_string_lossy(),
panic!(format!(
"Directory referenced by {} needs to contain a file called lv_conf.h",
CONFIG_NAME
);
));
}
println!(
@ -76,58 +62,24 @@ fn main() {
.include(&lv_config_dir)
.compile("lvgl");
let mut cc_args = vec![
let cc_args = [
"-DLV_CONF_INCLUDE_SIMPLE=1",
"-I",
lv_config_dir.to_str().unwrap(),
"-I",
vendor.to_str().unwrap(),
"-fvisibility=default",
];
// Set correct target triple for bindgen when cross-compiling
let target = env::var("TARGET").expect("Cargo build scripts always have TARGET");
let host = env::var("HOST").expect("Cargo build scripts always have HOST");
if target != host {
cc_args.push("-target");
cc_args.push(target.as_str());
}
let mut additional_args = Vec::new();
if target.ends_with("emscripten") {
if let Ok(em_path) = env::var("EMSDK") {
additional_args.push("-I".to_string());
additional_args.push(format!(
"{}/upstream/emscripten/system/include/libc",
em_path
));
additional_args.push("-I".to_string());
additional_args.push(format!(
"{}/upstream/emscripten/system/lib/libc/musl/arch/emscripten",
em_path
));
additional_args.push("-I".to_string());
additional_args.push(format!(
"{}/upstream/emscripten/system/include/SDL",
em_path
));
}
}
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let bindings = bindgen::Builder::default()
bindgen::Builder::default()
.header(shims_dir.join("lvgl_sys.h").to_str().unwrap())
.generate_comments(false)
.layout_tests(false)
.use_core()
.rustfmt_bindings(true)
.ctypes_prefix("cty")
.clang_args(&cc_args)
.clang_args(&additional_args)
.generate()
.expect("Unable to generate bindings");
bindings
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Can't write bindings!");
}
@ -143,10 +95,3 @@ fn add_c_files(build: &mut cc::Build, path: impl AsRef<Path>) {
}
}
}
fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
let canonicalized = path.as_ref().canonicalize().unwrap();
let canonicalized = &*canonicalized.to_string_lossy();
PathBuf::from(canonicalized.strip_prefix(r"\\?\").unwrap_or(canonicalized))
}

View file

@ -22,11 +22,11 @@ mod tests {
unsafe {
lv_init();
let horizontal_resolution = lv_disp_get_hor_res(core::ptr::null_mut());
assert_eq!(horizontal_resolution, LV_HOR_RES_MAX as i16);
let horizontal_resolution = lv_disp_get_hor_res(std::ptr::null_mut());
assert_eq!(horizontal_resolution, 480);
let vertical_resolution = lv_disp_get_ver_res(core::ptr::null_mut());
assert_eq!(vertical_resolution, LV_VER_RES_MAX as i16);
let vertical_resolution = lv_disp_get_ver_res(std::ptr::null_mut());
assert_eq!(vertical_resolution, 320);
}
}
}

View file

@ -1,701 +0,0 @@
/**
* @file lv_conf.h
*
*/
/*
* COPY THIS FILE AS `lv_conf.h` NEXT TO the `lvgl` FOLDER
*/
#if 1 /*Set it to "1" to enable content*/
#ifndef LV_CONF_H
#define LV_CONF_H
/* clang-format off */
#include <stdint.h>
/*====================
Graphical settings
*====================*/
/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX (240)
#define LV_VER_RES_MAX (240)
/* Color depth:
* - 1: 1 byte per pixel
* - 8: RGB332
* - 16: RGB565
* - 32: ARGB8888
*/
#define LV_COLOR_DEPTH 16
/* Swap the 2 bytes of RGB565 color.
* Useful if the display has a 8 bit interface (e.g. SPI)*/
#define LV_COLOR_16_SWAP 0
/* 1: Enable screen transparency.
* Useful for OSD or other overlapping GUIs.
* Requires `LV_COLOR_DEPTH = 32` colors and the screen's style should be modified: `style.body.opa = ...`*/
#define LV_COLOR_SCREEN_TRANSP 0
/*Images pixels with this color will not be drawn (with chroma keying)*/
#define LV_COLOR_TRANSP LV_COLOR_LIME /*LV_COLOR_LIME: pure green*/
/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
#define LV_ANTIALIAS 1
/* Default display refresh period.
* Can be changed in the display driver (`lv_disp_drv_t`).*/
#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/
/* Dot Per Inch: used to initialize default sizes.
* E.g. a button with width = LV_DPI / 2 -> half inch wide
* (Not so important, you can adjust it to modify default sizes and spaces)*/
#define LV_DPI 130 /*[px]*/
/* The the real width of the display changes some default values:
* default object sizes, layout of examples, etc.
* According to the width of the display (hor. res. / dpi)
* the displays fall in 4 categories.
* The 4th is extra large which has no upper limit so not listed here
* The upper limit of the categories are set below in 0.1 inch unit.
*/
#define LV_DISP_SMALL_LIMIT 30
#define LV_DISP_MEDIUM_LIMIT 50
#define LV_DISP_LARGE_LIMIT 70
/* Type of coordinates. Should be `int16_t` (or `int32_t` for extreme cases) */
typedef int16_t lv_coord_t;
/*=========================
Memory manager settings
*=========================*/
/* LittelvGL's internal memory manager's settings.
* The graphical objects and other related data are stored here. */
/* 1: use custom malloc/free, 0: use the built-in `lv_mem_alloc` and `lv_mem_free` */
#define LV_MEM_CUSTOM 0
#if LV_MEM_CUSTOM == 0
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
# define LV_MEM_SIZE (32U * 1024U)
/* Complier prefix for a big array declaration */
# define LV_MEM_ATTR
/* Set an address for the memory pool instead of allocating it as an array.
* Can be in external SRAM too. */
# define LV_MEM_ADR 0
/* Automatically defrag. on free. Defrag. means joining the adjacent free cells. */
# define LV_MEM_AUTO_DEFRAG 1
#else /*LV_MEM_CUSTOM*/
# define LV_MEM_CUSTOM_INCLUDE <stdlib.h> /*Header for the dynamic memory function*/
# define LV_MEM_CUSTOM_ALLOC malloc /*Wrapper to malloc*/
# define LV_MEM_CUSTOM_FREE free /*Wrapper to free*/
#endif /*LV_MEM_CUSTOM*/
/* Garbage Collector settings
* Used if lvgl is binded to higher level language and the memory is managed by that language */
#define LV_ENABLE_GC 0
#if LV_ENABLE_GC != 0
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
# define LV_MEM_CUSTOM_REALLOC your_realloc /*Wrapper to realloc*/
# define LV_MEM_CUSTOM_GET_SIZE your_mem_get_size /*Wrapper to lv_mem_get_size*/
#endif /* LV_ENABLE_GC */
/*=======================
Input device settings
*=======================*/
/* Input device default settings.
* Can be changed in the Input device driver (`lv_indev_drv_t`)*/
/* Input device read period in milliseconds */
#define LV_INDEV_DEF_READ_PERIOD 30
/* Drag threshold in pixels */
#define LV_INDEV_DEF_DRAG_LIMIT 10
/* Drag throw slow-down in [%]. Greater value -> faster slow-down */
#define LV_INDEV_DEF_DRAG_THROW 10
/* Long press time in milliseconds.
* Time to send `LV_EVENT_LONG_PRESSSED`) */
#define LV_INDEV_DEF_LONG_PRESS_TIME 400
/* Repeated trigger period in long press [ms]
* Time between `LV_EVENT_LONG_PRESSED_REPEAT */
#define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100
/* Gesture threshold in pixels */
#define LV_INDEV_DEF_GESTURE_LIMIT 50
/* Gesture min velocity at release before swipe (pixels)*/
#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3
/*==================
* Feature usage
*==================*/
/*1: Enable the Animations */
#define LV_USE_ANIMATION 1
#if LV_USE_ANIMATION
/*Declare the type of the user data of animations (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_anim_user_data_t;
#endif
/* 1: Enable shadow drawing*/
#define LV_USE_SHADOW 1
#if LV_USE_SHADOW
/* Allow buffering some shadow calculation
* LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer,
* where shadow size is `shadow_width + radius`
* Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#define LV_SHADOW_CACHE_SIZE 0
#endif
/* 1: Use other blend modes than normal (`LV_BLEND_MODE_...`)*/
#define LV_USE_BLEND_MODES 1
/* 1: Use the `opa_scale` style property to set the opacity of an object and its children at once*/
#define LV_USE_OPA_SCALE 1
/* 1: Use image zoom and rotation*/
#define LV_USE_IMG_TRANSFORM 1
/* 1: Enable object groups (for keyboard/encoder navigation) */
#define LV_USE_GROUP 1
#if LV_USE_GROUP
typedef void * lv_group_user_data_t;
#endif /*LV_USE_GROUP*/
/* 1: Enable GPU interface*/
#define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */
#define LV_USE_GPU_STM32_DMA2D 0
/* 1: Enable file system (might be required for images */
#define LV_USE_FILESYSTEM 1
#if LV_USE_FILESYSTEM
/*Declare the type of the user data of file system drivers (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_fs_drv_user_data_t;
#endif
/*1: Add a `user_data` to drivers and objects*/
#define LV_USE_USER_DATA 1
/*1: Show CPU usage and FPS count in the right bottom corner*/
#define LV_USE_PERF_MONITOR 0
/*1: Use the functions and types from the older API if possible */
#define LV_USE_API_EXTENSION_V6 1
/*========================
* Image decoder and cache
*========================*/
/* 1: Enable indexed (palette) images */
#define LV_IMG_CF_INDEXED 1
/* 1: Enable alpha indexed images */
#define LV_IMG_CF_ALPHA 1
/* Default image cache size. Image caching keeps the images opened.
* If only the built-in image formats are used there is no real advantage of caching.
* (I.e. no new image decoder is added)
* With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
* However the opened images might consume additional RAM.
* LV_IMG_CACHE_DEF_SIZE must be >= 1 */
#define LV_IMG_CACHE_DEF_SIZE 1
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_img_decoder_user_data_t;
/*=====================
* Compiler settings
*====================*/
/* Define a custom attribute to `lv_tick_inc` function */
#define LV_ATTRIBUTE_TICK_INC
/* Define a custom attribute to `lv_task_handler` function */
#define LV_ATTRIBUTE_TASK_HANDLER
/* Define a custom attribute to `lv_disp_flush_ready` function */
#define LV_ATTRIBUTE_FLUSH_READY
/* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
* E.g. __attribute__((aligned(4))) */
#define LV_ATTRIBUTE_MEM_ALIGN
/* Attribute to mark large constant arrays for example
* font's bitmaps */
#define LV_ATTRIBUTE_LARGE_CONST
/* Prefix performance critical functions to place them into a faster memory (e.g RAM)
* Uses 15-20 kB extra memory */
#define LV_ATTRIBUTE_FAST_MEM
/* Export integer constant to binding.
* This macro is used with constants in the form of LV_<CONST> that
* should also appear on lvgl binding API such as Micropython
*
* The default value just prevents a GCC warning.
*/
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
/*===================
* HAL settings
*==================*/
/* 1: use a custom tick source.
* It removes the need to manually update the tick with `lv_tick_inc`) */
#define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE "something.h" /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current systime in ms*/
#endif /*LV_TICK_CUSTOM*/
typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
typedef void * lv_indev_drv_user_data_t; /*Type of user data in the input device driver*/
/*================
* Log settings
*===============*/
/*1: Enable the log module*/
#define LV_USE_LOG 0
#if LV_USE_LOG
/* How important log should be added:
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
* LV_LOG_LEVEL_INFO Log important events
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
* LV_LOG_LEVEL_NONE Do not log anything
*/
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
/* 1: Print the log with 'printf';
* 0: user need to register a callback with `lv_log_register_print_cb`*/
# define LV_LOG_PRINTF 0
#endif /*LV_USE_LOG*/
/*=================
* Debug settings
*================*/
/* If Debug is enabled LittelvGL validates the parameters of the functions.
* If an invalid parameter is found an error log message is printed and
* the MCU halts at the error. (`LV_USE_LOG` should be enabled)
* If you are debugging the MCU you can pause
* the debugger to see exactly where the issue is.
*
* The behavior of asserts can be overwritten by redefining them here.
* E.g. #define LV_ASSERT_MEM(p) <my_assert_code>
*/
#define LV_USE_DEBUG 1
#if LV_USE_DEBUG
/*Check if the parameter is NULL. (Quite fast) */
#define LV_USE_ASSERT_NULL 1
/*Checks is the memory is successfully allocated or no. (Quite fast)*/
#define LV_USE_ASSERT_MEM 1
/*Check the integrity of `lv_mem` after critical operations. (Slow)*/
#define LV_USE_ASSERT_MEM_INTEGRITY 0
/* Check the strings.
* Search for NULL, very long strings, invalid characters, and unnatural repetitions. (Slow)
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
#define LV_USE_ASSERT_STR 0
/* Check NULL, the object's type and existence (e.g. not deleted). (Quite slow)
* If disabled `LV_USE_ASSERT_NULL` will be performed instead (if it's enabled) */
#define LV_USE_ASSERT_OBJ 0
/*Check if the styles are properly initialized. (Fast)*/
#define LV_USE_ASSERT_STYLE 0
#endif /*LV_USE_DEBUG*/
/*==================
* FONT USAGE
*===================*/
/* The built-in fonts contains the ASCII range and some Symbols with 4 bit-per-pixel.
* The symbols are available via `LV_SYMBOL_...` defines
* More info about fonts: https://docs.lvgl.com/#Fonts
* To create a new font go to: https://lvgl.com/ttf-font-to-c-array
*/
/* Montserrat fonts with bpp = 4
* https://fonts.google.com/specimen/Montserrat */
#define LV_FONT_MONTSERRAT_12 0
#define LV_FONT_MONTSERRAT_14 0
#define LV_FONT_MONTSERRAT_16 1
#define LV_FONT_MONTSERRAT_18 0
#define LV_FONT_MONTSERRAT_20 0
#define LV_FONT_MONTSERRAT_22 0
#define LV_FONT_MONTSERRAT_24 0
#define LV_FONT_MONTSERRAT_26 0
#define LV_FONT_MONTSERRAT_28 0
#define LV_FONT_MONTSERRAT_30 0
#define LV_FONT_MONTSERRAT_32 0
#define LV_FONT_MONTSERRAT_34 0
#define LV_FONT_MONTSERRAT_36 0
#define LV_FONT_MONTSERRAT_38 0
#define LV_FONT_MONTSERRAT_40 0
#define LV_FONT_MONTSERRAT_42 0
#define LV_FONT_MONTSERRAT_44 0
#define LV_FONT_MONTSERRAT_46 0
#define LV_FONT_MONTSERRAT_48 0
/* Demonstrate special features */
#define LV_FONT_MONTSERRAT_12_SUBPX 0
#define LV_FONT_MONTSERRAT_28_COMPRESSED 0 /*bpp = 3*/
#define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, PErisan letters and all their forms*/
#define LV_FONT_SIMSUN_16_CJK 0 /*1000 most common CJK radicals*/
/*Pixel perfect monospace font
* http://pelulamu.net/unscii/ */
#define LV_FONT_UNSCII_8 0
/* Optionally declare your custom fonts here.
* You can use these fonts as default font too
* and they will be available globally. E.g.
* #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \
* LV_FONT_DECLARE(my_font_2)
*/
#define LV_FONT_CUSTOM_DECLARE
/* Enable it if you have fonts with a lot of characters.
* The limit depends on the font size, font face and bpp
* but with > 10,000 characters if you see issues probably you need to enable it.*/
#define LV_FONT_FMT_TXT_LARGE 0
/* Set the pixel order of the display.
* Important only if "subpx fonts" are used.
* With "normal" font it doesn't matter.
*/
#define LV_FONT_SUBPX_BGR 0
/*Declare the type of the user data of fonts (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_font_user_data_t;
/*================
* THEME USAGE
*================*/
/*Always enable at least on theme*/
/* No theme, you can apply your styles as you need
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_EMPTY 1
/*Simple to the create your theme based on it
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_TEMPLATE 1
/* A fast and impressive theme.
* Flags:
* LV_THEME_MATERIAL_FLAG_LIGHT: light theme
* LV_THEME_MATERIAL_FLAG_DARK: dark theme*/
#define LV_USE_THEME_MATERIAL 1
/* Mono-color theme for monochrome displays.
* If LV_THEME_DEFAULT_COLOR_PRIMARY is LV_COLOR_BLACK the
* texts and borders will be black and the background will be
* white. Else the colors are inverted.
* No flags. Set LV_THEME_DEFAULT_FLAG 0 */
#define LV_USE_THEME_MONO 1
#define LV_THEME_DEFAULT_INCLUDE <stdint.h> /*Include a header for the init. function*/
#define LV_THEME_DEFAULT_INIT lv_theme_material_init
#define LV_THEME_DEFAULT_COLOR_PRIMARY LV_COLOR_RED
#define LV_THEME_DEFAULT_COLOR_SECONDARY LV_COLOR_BLUE
#define LV_THEME_DEFAULT_FLAG LV_THEME_MATERIAL_FLAG_LIGHT
#define LV_THEME_DEFAULT_FONT_SMALL &lv_font_montserrat_16
#define LV_THEME_DEFAULT_FONT_NORMAL &lv_font_montserrat_16
#define LV_THEME_DEFAULT_FONT_SUBTITLE &lv_font_montserrat_16
#define LV_THEME_DEFAULT_FONT_TITLE &lv_font_montserrat_16
/*=================
* Text settings
*=================*/
/* Select a character encoding for strings.
* Your IDE or editor should have the same character encoding
* - LV_TXT_ENC_UTF8
* - LV_TXT_ENC_ASCII
* */
#define LV_TXT_ENC LV_TXT_ENC_UTF8
/*Can break (wrap) texts on these chars*/
#define LV_TXT_BREAK_CHARS " ,.;:-_"
/* If a word is at least this long, will break wherever "prettiest"
* To disable, set to a value <= 0 */
#define LV_TXT_LINE_BREAK_LONG_LEN 0
/* Minimum number of characters in a long word to put on a line before a break.
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
/* Minimum number of characters in a long word to put on a line after a break.
* Depends on LV_TXT_LINE_BREAK_LONG_LEN. */
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
/* The control character to use for signalling text recoloring. */
#define LV_TXT_COLOR_CMD "#"
/* Support bidirectional texts.
* Allows mixing Left-to-Right and Right-to-Left texts.
* The direction will be processed according to the Unicode Bidirectioanl Algorithm:
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
#define LV_USE_BIDI 0
#if LV_USE_BIDI
/* Set the default direction. Supported values:
* `LV_BIDI_DIR_LTR` Left-to-Right
* `LV_BIDI_DIR_RTL` Right-to-Left
* `LV_BIDI_DIR_AUTO` detect texts base direction */
#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO
#endif
/* Enable Arabic/Persian processing
* In these languages characters should be replaced with
* an other form based on their position in the text */
#define LV_USE_ARABIC_PERSIAN_CHARS 0
/*Change the built in (v)snprintf functions*/
#define LV_SPRINTF_CUSTOM 0
#if LV_SPRINTF_CUSTOM
# define LV_SPRINTF_INCLUDE <stdio.h>
# define lv_snprintf snprintf
# define lv_vsnprintf vsnprintf
#else /*!LV_SPRINTF_CUSTOM*/
# define LV_SPRINTF_DISABLE_FLOAT 1
#endif /*LV_SPRINTF_CUSTOM*/
/*===================
* LV_OBJ SETTINGS
*==================*/
#if LV_USE_USER_DATA
/*Declare the type of the user data of object (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_obj_user_data_t;
/*Provide a function to free user data*/
#define LV_USE_USER_DATA_FREE 0
#if LV_USE_USER_DATA_FREE
# define LV_USER_DATA_FREE_INCLUDE "something.h" /*Header for user data free function*/
/* Function prototype : void user_data_free(lv_obj_t * obj); */
# define LV_USER_DATA_FREE (user_data_free) /*Invoking for user data free function*/
#endif
#endif
/*1: enable `lv_obj_realaign()` based on `lv_obj_align()` parameters*/
#define LV_USE_OBJ_REALIGN 1
/* Enable to make the object clickable on a larger area.
* LV_EXT_CLICK_AREA_OFF or 0: Disable this feature
* LV_EXT_CLICK_AREA_TINY: The extra area can be adjusted horizontally and vertically (0..255 px)
* LV_EXT_CLICK_AREA_FULL: The extra area can be adjusted in all 4 directions (-32k..+32k px)
*/
#define LV_USE_EXT_CLICK_AREA LV_EXT_CLICK_AREA_TINY
/*==================
* LV OBJ X USAGE
*================*/
/*
* Documentation of the object types: https://docs.lvgl.com/#Object-types
*/
/*Arc (dependencies: -)*/
#define LV_USE_ARC 1
/*Bar (dependencies: -)*/
#define LV_USE_BAR 1
/*Button (dependencies: lv_cont*/
#define LV_USE_BTN 1
/*Button matrix (dependencies: -)*/
#define LV_USE_BTNMATRIX 1
/*Calendar (dependencies: -)*/
#define LV_USE_CALENDAR 1
/*Canvas (dependencies: lv_img)*/
#define LV_USE_CANVAS 1
/*Check box (dependencies: lv_btn, lv_label)*/
#define LV_USE_CHECKBOX 1
/*Chart (dependencies: -)*/
#define LV_USE_CHART 1
#if LV_USE_CHART
# define LV_CHART_AXIS_TICK_LABEL_MAX_LEN 256
#endif
/*Container (dependencies: -*/
#define LV_USE_CONT 1
/*Color picker (dependencies: -*/
#define LV_USE_CPICKER 1
/*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/
#define LV_USE_DROPDOWN 1
#if LV_USE_DROPDOWN != 0
/*Open and close default animation time [ms] (0: no animation)*/
# define LV_DROPDOWN_DEF_ANIM_TIME 200
#endif
/*Gauge (dependencies:lv_bar, lv_linemeter)*/
#define LV_USE_GAUGE 1
/*Image (dependencies: lv_label*/
#define LV_USE_IMG 1
/*Image Button (dependencies: lv_btn*/
#define LV_USE_IMGBTN 1
#if LV_USE_IMGBTN
/*1: The imgbtn requires left, mid and right parts and the width can be set freely*/
# define LV_IMGBTN_TILED 0
#endif
/*Keyboard (dependencies: lv_btnm)*/
#define LV_USE_KEYBOARD 1
/*Label (dependencies: -*/
#define LV_USE_LABEL 1
#if LV_USE_LABEL != 0
/*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_ROLL/ROLL_CIRC' mode*/
# define LV_LABEL_DEF_SCROLL_SPEED 25
/* Waiting period at beginning/end of animation cycle */
# define LV_LABEL_WAIT_CHAR_COUNT 3
/*Enable selecting text of the label */
# define LV_LABEL_TEXT_SEL 0
/*Store extra some info in labels (12 bytes) to speed up drawing of very long texts*/
# define LV_LABEL_LONG_TXT_HINT 0
#endif
/*LED (dependencies: -)*/
#define LV_USE_LED 1
#if LV_USE_LED
# define LV_LED_BRIGHT_MIN 120 /*Minimal brightness*/
# define LV_LED_BRIGHT_MAX 255 /*Maximal brightness*/
#endif
/*Line (dependencies: -*/
#define LV_USE_LINE 1
/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/
#define LV_USE_LIST 1
#if LV_USE_LIST != 0
/*Default animation time of focusing to a list element [ms] (0: no animation) */
# define LV_LIST_DEF_ANIM_TIME 100
#endif
/*Line meter (dependencies: *;)*/
#define LV_USE_LINEMETER 1
#if LV_USE_LINEMETER
/* Draw line more precisely at cost of performance.
* Useful if there are lot of lines any minor are visible
* 0: No extra precision
* 1: Some extra precision
* 2: Best precision
*/
# define LV_LINEMETER_PRECISE 0
#endif
/*Mask (dependencies: -)*/
#define LV_USE_OBJMASK 1
/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
#define LV_USE_MSGBOX 1
/*Page (dependencies: lv_cont)*/
#define LV_USE_PAGE 1
#if LV_USE_PAGE != 0
/*Focus default animation time [ms] (0: no animation)*/
# define LV_PAGE_DEF_ANIM_TIME 400
#endif
/*Preload (dependencies: lv_arc, lv_anim)*/
#define LV_USE_SPINNER 1
#if LV_USE_SPINNER != 0
# define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/
# define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/
# define LV_SPINNER_DEF_ANIM LV_SPINNER_TYPE_SPINNING_ARC
#endif
/*Roller (dependencies: lv_ddlist)*/
#define LV_USE_ROLLER 1
#if LV_USE_ROLLER != 0
/*Focus animation time [ms] (0: no animation)*/
# define LV_ROLLER_DEF_ANIM_TIME 200
/*Number of extra "pages" when the roller is infinite*/
# define LV_ROLLER_INF_PAGES 7
#endif
/*Slider (dependencies: lv_bar)*/
#define LV_USE_SLIDER 1
/*Spinbox (dependencies: lv_ta)*/
#define LV_USE_SPINBOX 1
/*Switch (dependencies: lv_slider)*/
#define LV_USE_SWITCH 1
/*Text area (dependencies: lv_label, lv_page)*/
#define LV_USE_TEXTAREA 1
#if LV_USE_TEXTAREA != 0
# define LV_TEXTAREA_DEF_CURSOR_BLINK_TIME 400 /*ms*/
# define LV_TEXTAREA_DEF_PWD_SHOW_TIME 1500 /*ms*/
#endif
/*Table (dependencies: lv_label)*/
#define LV_USE_TABLE 1
#if LV_USE_TABLE
# define LV_TABLE_COL_MAX 12
#endif
/*Tab (dependencies: lv_page, lv_btnm)*/
#define LV_USE_TABVIEW 1
# if LV_USE_TABVIEW != 0
/*Time of slide animation [ms] (0: no animation)*/
# define LV_TABVIEW_DEF_ANIM_TIME 300
#endif
/*Tileview (dependencies: lv_page) */
#define LV_USE_TILEVIEW 1
#if LV_USE_TILEVIEW
/*Time of slide animation [ms] (0: no animation)*/
# define LV_TILEVIEW_DEF_ANIM_TIME 300
#endif
/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
#define LV_USE_WIN 1
/*==================
* Non-user section
*==================*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /* Disable warnings for Visual Studio*/
# define _CRT_SECURE_NO_WARNINGS
#endif
/*--END OF LV_CONF_H--*/
#endif /*LV_CONF_H*/
#endif /*End of "Content enable"*/

@ -1 +1 @@
Subproject commit 524709472757405ac0eef8d6d002632526430df3
Subproject commit 1ca1934dbe8e826ef1ed1690005fb678fea3a1f3

View file

@ -1,7 +1,7 @@
[package]
name = "lvgl"
description = "LVGL bindings for Rust. A powerful and easy-to-use embedded GUI with many widgets, advanced visual effects (opacity, antialiasing, animations) and low memory requirements (16K RAM, 64K Flash)."
version = "0.5.2"
description = "LittlevGL bindings for Rust. A powerful and easy-to-use embedded GUI with many widgets, advanced visual effects (opacity, antialiasing, animations) and low memory requirements (16K RAM, 64K Flash)."
version = "0.3.1"
authors = ["Rafael Caricio <crates.lvgl@caric.io>"]
edition = "2018"
repository = "https://github.com/rafaelcaricio/lvgl-rs"
@ -12,47 +12,15 @@ keywords = ["littlevgl", "lvgl", "graphical_interfaces"]
build = "build.rs"
[dependencies]
lvgl-sys = { version = "0.5.2", path = "../lvgl-sys" }
lvgl-sys = { version = "0.3.1", path = "../lvgl-sys" }
cty = "0.2.1"
embedded-graphics = "0.7.1"
cstr_core = "0.2.3"
embedded-graphics = "0.6.2"
cstr_core = { version = "0.2.0", default-features = false, features = ["alloc"] }
bitflags = "1.2.1"
[features]
alloc = ["cstr_core/alloc"]
lvgl_alloc = ["alloc"]
use-vendored-config = ["lvgl-sys/use-vendored-config"]
[build-dependencies]
quote = "1.0.9"
proc-macro2 = "1.0.24"
lvgl-codegen = { version = "0.5.2", path = "../lvgl-codegen" }
lvgl-sys = { version = "0.5.2", path = "../lvgl-sys" }
quote = "1.0.7"
proc-macro2 = "1.0.18"
lvgl-codegen = { version = "0.3.0", path = "../lvgl-codegen" }
lvgl-sys = { version = "0.3.1", path = "../lvgl-sys" }
[dev-dependencies]
embedded-graphics-simulator = "0.3.0"
heapless = "0.7.13"
[[example]]
name = "demo"
path = "../examples/demo.rs"
required-features = ["alloc"]
[[example]]
name = "bar"
path = "../examples/bar.rs"
required-features = ["alloc"]
[[example]]
name = "button_click"
path = "../examples/button_click.rs"
required-features = ["alloc"]
[[example]]
name = "gauge"
path = "../examples/gauge.rs"
[[example]]
name = "arc"
path = "../examples/arc.rs"
required-features = ["lvgl_alloc"]

View file

@ -1,20 +0,0 @@
use core::alloc::{GlobalAlloc, Layout};
// Register the global allocator
#[global_allocator]
static ALLOCATOR: LvglAlloc = LvglAlloc;
pub struct LvglAlloc;
unsafe impl GlobalAlloc for LvglAlloc {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
// Make sure LVGL is initialized!
crate::lvgl_init();
lvgl_sys::lv_mem_alloc(layout.size() as lvgl_sys::size_t) as *mut u8
}
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
crate::lvgl_init();
lvgl_sys::lv_mem_free(ptr as *const cty::c_void)
}
}

138
lvgl/src/display.rs Normal file
View file

@ -0,0 +1,138 @@
use crate::Color;
use alloc::boxed::Box;
use core::mem::MaybeUninit;
use embedded_graphics::prelude::*;
use embedded_graphics::{drawable, DrawTarget};
pub struct DisplayDriver {
pub(crate) raw: lvgl_sys::lv_disp_drv_t,
}
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 {
// Declare a buffer for the refresh rate
// TODO: Make this an external configuration
const REFRESH_BUFFER_LEN: usize = 2;
let refresh_buffer1 = vec![
Color::from_rgb((0, 0, 0)).raw;
lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN
];
let refresh_buffer2 = vec![
Color::from_rgb((0, 0, 0)).raw;
lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN
];
// Create a display buffer for LittlevGL
let mut display_buffer = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
// Initialize the display buffer
lvgl_sys::lv_disp_buf_init(
display_buffer.as_mut_ptr(),
Box::into_raw(refresh_buffer1.into_boxed_slice()) as *mut cty::c_void,
Box::into_raw(refresh_buffer2.into_boxed_slice()) as *mut cty::c_void,
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
);
let display_buffer = Box::new(display_buffer.assume_init());
// Basic initialization of the display driver
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit();
lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr());
let mut disp_drv = disp_drv.assume_init();
// 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
// Safety: `user_data` is set to NULL in C code.
disp_drv.user_data = device as *mut _ as *mut cty::c_void;
disp_drv
};
Self { raw: disp_drv }
}
}
// 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!()
// }
// }
// 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,
area: *const lvgl_sys::lv_area_t,
color_p: *mut lvgl_sys::lv_color_t,
) where
T: DrawTarget<C>,
C: PixelColor + From<Color>,
{
// In the `std` world we would make sure to capture panics here and make them not escape across
// the FFI boundary. Since this library is focused on embedded platforms, we don't
// have an standard unwinding mechanism to rely upon.
let display_driver = *disp_drv;
// Rust code closure reference
if !display_driver.user_data.is_null() {
let device = &mut *(display_driver.user_data as *mut T);
let x1 = (*area).x1;
let x2 = (*area).x2;
let y1 = (*area).y1;
let y2 = (*area).y2;
// TODO: Can we do anything when there is a error while flushing?
let _ = display_flush(device, (x1, x2), (y1, y2), color_p);
}
// Indicate to LittlevGL that we are ready with the flushing
lvgl_sys::lv_disp_flush_ready(disp_drv);
}
// We separate this display flush function to reduce the amount of unsafe code we need to write.
// This also provides a good separation of concerns, what is necessary from LittlevGL to work and
// what is the lvgl-rs wrapper responsibility.
fn display_flush<T, C>(
display: &mut T,
(x1, x2): (i16, i16),
(y1, y2): (i16, i16),
color_p: *mut lvgl_sys::lv_color_t,
) -> Result<(), T::Error>
where
T: DrawTarget<C>,
C: PixelColor + From<Color>,
{
let ys = y1..=y2;
let xs = (x1..=x2).enumerate();
let x_len = (x2 - x1 + 1) as usize;
// We use iterators here to ensure that the Rust compiler can apply all possible
// optimizations at compile time.
let pixels = ys
.enumerate()
.map(|(iy, y)| {
xs.clone().map(move |(ix, x)| {
let color_len = x_len * iy + ix;
let lv_color = unsafe { *color_p.add(color_len) };
let raw_color = Color::from_raw(lv_color);
drawable::Pixel(Point::new(x as i32, y as i32), raw_color.into())
})
})
.flatten();
Ok(display.draw_iter(pixels)?)
}

72
lvgl/src/global.rs Normal file
View file

@ -0,0 +1,72 @@
use crate::{DisplayDriver, Event, LvError, LvResult, Obj, Widget};
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);
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() -> LvResult<Self> {
if !LVGL_IN_USE.compare_and_swap(false, true, Ordering::SeqCst) {
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) -> LvResult<Obj> {
unsafe {
let screen = lvgl_sys::lv_disp_get_scr_act(ptr::null_mut());
Ok(Obj::from_raw(NonNull::new(screen)?))
}
}
pub fn event_send<T>(&mut self, obj: &mut T, event: Event<T::SpecialEvent>) -> LvResult<()>
where
T: Widget,
{
unsafe {
lvgl_sys::lv_event_send(obj.raw()?.as_mut(), event.into(), ptr::null_mut());
}
Ok(())
}
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();
}
}
}

View file

@ -1,68 +1,19 @@
//! [![github]](https://github.com/rafaelcaricio/lvgl-rs)&ensp;[![crates-io]](https://crates.io/crates/lvgl)&ensp;[![docs-rs]](crate)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
//!
//! <br>
//!
//! [LVGL][1] bindings for Rust. A powerful and easy-to-use embedded GUI with many widgets, advanced visual effects, and
//! low memory footprint. This crate is compatible with `#![no_std]` environments by default.
//!
//! [1]: https://docs.lvgl.io/v7/en/html/get-started/quick-overview.html
//!
#![cfg_attr(not(test), no_std)]
#![feature(try_trait)]
#![no_std]
#[macro_use]
extern crate alloc;
#[macro_use]
extern crate bitflags;
#[cfg(feature = "lvgl_alloc")]
extern crate alloc;
// We can ONLY use `alloc::boxed::Box` if `lvgl_alloc` is enabled.
// That is because we use `Box` to send memory references to LVGL. Since the global allocator, when
// `lvgl_alloc` feature is enabled, is the LVGL memory manager then everything is in LVGL
// managed memory anyways. In that case we can use the Rust's provided Box definition.
//
#[cfg(feature = "lvgl_alloc")]
use ::alloc::boxed::Box;
#[cfg(feature = "lvgl_alloc")]
mod allocator;
mod display;
mod global;
mod support;
mod ui;
#[macro_use]
mod lv_core;
pub mod widgets;
#[cfg(not(feature = "lvgl_alloc"))]
pub(crate) mod mem;
// When LVGL allocator is not used on the Rust code, we need a way to add objects to the LVGL
// managed memory. We implement a very simple `Box` that has the minimal features to copy memory
// safely to the LVGL managed memory.
//
#[cfg(not(feature = "lvgl_alloc"))]
use crate::mem::Box;
pub use display::DisplayDriver;
pub use global::UI;
pub use lv_core::*;
pub use support::*;
pub use ui::*;
use core::sync::atomic::{AtomicBool, Ordering};
// Initialize LVGL only once.
static LVGL_INITIALIZED: AtomicBool = AtomicBool::new(false);
pub(crate) fn lvgl_init() {
if LVGL_INITIALIZED
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
unsafe {
lvgl_sys::lv_init();
}
}
}

View file

@ -1,9 +1,9 @@
use crate::lv_core::style::Style;
use crate::Box;
use crate::{Align, LvError, LvResult};
use alloc::boxed::Box;
use core::ptr;
/// Represents a native LVGL object
/// Represents a native LittlevGL object
pub trait NativeObject {
/// Provide common way to access to the underlying native object pointer.
fn raw(&self) -> LvResult<ptr::NonNull<lvgl_sys::lv_obj_t>>;
@ -28,7 +28,7 @@ impl NativeObject for Obj {
}
}
/// A wrapper for all LVGL common operations on generic objects.
/// A wrapper for all LittlevGL common operations on generic objects.
pub trait Widget: NativeObject {
type SpecialEvent;
type Part: Into<u8>;
@ -40,7 +40,7 @@ pub trait Widget: NativeObject {
///
unsafe fn from_raw(raw_pointer: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self;
fn add_style(&self, part: Self::Part, style: Style) -> LvResult<()> {
fn add_style(&mut self, part: Self::Part, style: Style) -> LvResult<()> {
unsafe {
lvgl_sys::lv_obj_add_style(self.raw()?.as_mut(), part.into(), Box::into_raw(style.raw));
};
@ -146,8 +146,8 @@ macro_rules! define_object {
unsafe {
let mut raw = self.raw()?;
let obj = raw.as_mut();
let user_closure = $crate::Box::new(f);
obj.user_data = $crate::Box::into_raw(user_closure) as *mut cty::c_void;
let user_closure = alloc::boxed::Box::new(f);
obj.user_data = alloc::boxed::Box::into_raw(user_closure) as *mut cty::c_void;
lvgl_sys::lv_obj_set_event_cb(
obj,
lvgl_sys::lv_event_cb_t::Some($crate::support::event_callback::<Self, F>),
@ -179,19 +179,19 @@ macro_rules! define_object {
bitflags! {
pub struct State: u32 {
/// Normal, released
const DEFAULT = lvgl_sys::LV_STATE_DEFAULT as u32;
const DEFAULT = lvgl_sys::LV_STATE_DEFAULT;
/// Toggled or checked
const CHECKED = lvgl_sys::LV_STATE_CHECKED as u32;
const CHECKED = lvgl_sys::LV_STATE_CHECKED;
/// Focused via keypad or encoder or clicked via touchpad/mouse
const FOCUSED = lvgl_sys::LV_STATE_FOCUSED as u32;
const FOCUSED = lvgl_sys::LV_STATE_FOCUSED;
/// Edit by an encoder
const EDITED = lvgl_sys::LV_STATE_EDITED as u32;
const EDITED = lvgl_sys::LV_STATE_EDITED;
/// Hovered by mouse (not supported now)
const HOVERED = lvgl_sys::LV_STATE_HOVERED as u32;
const HOVERED = lvgl_sys::LV_STATE_HOVERED;
/// Pressed
const PRESSED = lvgl_sys::LV_STATE_PRESSED as u32;
const PRESSED = lvgl_sys::LV_STATE_PRESSED;
/// Disabled or inactive
const DISABLED = lvgl_sys::LV_STATE_DISABLED as u32;
const DISABLED = lvgl_sys::LV_STATE_DISABLED;
}
}
@ -206,9 +206,9 @@ pub enum Part {
All,
}
impl From<Part> for u8 {
fn from(self_: Part) -> u8 {
match self_ {
impl Into<u8> for Part {
fn into(self) -> u8 {
match self {
Part::Main => lvgl_sys::LV_OBJ_PART_MAIN as u8,
Part::All => lvgl_sys::LV_OBJ_PART_ALL as u8,
}

View file

@ -1,26 +1,26 @@
use crate::Box;
use crate::{Color, LvResult, State};
use alloc::boxed::Box;
use core::mem;
use cstr_core::CStr;
use cstr_core::CString;
pub enum Themes {
Pretty,
}
#[derive(Clone)]
pub struct Style {
pub(crate) raw: Box<lvgl_sys::lv_style_t>,
}
impl Style {
pub fn set_value_str(&mut self, state: State, value: &CStr) -> LvResult<()> {
pub fn set_value_str(&mut self, state: State, value: &str) -> LvResult<()> {
let native_state: u32 = state.get_bits();
let string = CString::new(value)?;
unsafe {
lvgl_sys::_lv_style_set_ptr(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_STR as u32
(lvgl_sys::LV_STYLE_VALUE_STR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.as_ptr() as *mut cty::c_void,
string.into_raw() as *mut cty::c_void,
);
}
Ok(())
@ -40,122 +40,122 @@ impl Default for Style {
bitflags! {
pub struct Opacity: u32 {
const OPA_TRANSP = lvgl_sys::LV_OPA_TRANSP as u32;
const OPA_0 = lvgl_sys::LV_OPA_0 as u32;
const OPA_10 = lvgl_sys::LV_OPA_10 as u32;
const OPA_20 = lvgl_sys::LV_OPA_20 as u32;
const OPA_30 = lvgl_sys::LV_OPA_30 as u32;
const OPA_40 = lvgl_sys::LV_OPA_40 as u32;
const OPA_50 = lvgl_sys::LV_OPA_50 as u32;
const OPA_60 = lvgl_sys::LV_OPA_60 as u32;
const OPA_70 = lvgl_sys::LV_OPA_70 as u32;
const OPA_80 = lvgl_sys::LV_OPA_80 as u32;
const OPA_90 = lvgl_sys::LV_OPA_90 as u32;
const OPA_100 = lvgl_sys::LV_OPA_100 as u32;
const OPA_COVER = lvgl_sys::LV_OPA_COVER as u32;
const OPA_TRANSP = lvgl_sys::LV_OPA_TRANSP;
const OPA_0 = lvgl_sys::LV_OPA_0;
const OPA_10 = lvgl_sys::LV_OPA_10;
const OPA_20 = lvgl_sys::LV_OPA_20;
const OPA_30 = lvgl_sys::LV_OPA_30;
const OPA_40 = lvgl_sys::LV_OPA_40;
const OPA_50 = lvgl_sys::LV_OPA_50;
const OPA_60 = lvgl_sys::LV_OPA_60;
const OPA_70 = lvgl_sys::LV_OPA_70;
const OPA_80 = lvgl_sys::LV_OPA_80;
const OPA_90 = lvgl_sys::LV_OPA_90;
const OPA_100 = lvgl_sys::LV_OPA_100;
const OPA_COVER = lvgl_sys::LV_OPA_COVER;
}
}
impl From<Opacity> for u8 {
fn from(self_: Opacity) -> u8 {
self_.bits as u8
impl Into<u8> for Opacity {
fn into(self) -> u8 {
self.bits as u8
}
}
bitflags! {
pub struct StyleProp: u32 {
const RADIUS = lvgl_sys::LV_STYLE_RADIUS as u32;
const CLIP_CORNER = lvgl_sys::LV_STYLE_CLIP_CORNER as u32;
const SIZE = lvgl_sys::LV_STYLE_SIZE as u32;
const TRANSFORM_WIDTH = lvgl_sys::LV_STYLE_TRANSFORM_WIDTH as u32;
const TRANSFORM_HEIGHT = lvgl_sys::LV_STYLE_TRANSFORM_HEIGHT as u32;
const TRANSFORM_ANGLE = lvgl_sys::LV_STYLE_TRANSFORM_ANGLE as u32;
const TRANSFORM_ZOOM = lvgl_sys::LV_STYLE_TRANSFORM_ZOOM as u32;
const OPA_SCALE = lvgl_sys::LV_STYLE_OPA_SCALE as u32;
const PAD_TOP = lvgl_sys::LV_STYLE_PAD_TOP as u32;
const PAD_BOTTOM = lvgl_sys::LV_STYLE_PAD_BOTTOM as u32;
const PAD_LEFT = lvgl_sys::LV_STYLE_PAD_LEFT as u32;
const PAD_RIGHT = lvgl_sys::LV_STYLE_PAD_RIGHT as u32;
const PAD_INNER = lvgl_sys::LV_STYLE_PAD_INNER as u32;
const MARGIN_TOP = lvgl_sys::LV_STYLE_MARGIN_TOP as u32;
const MARGIN_BOTTOM = lvgl_sys::LV_STYLE_MARGIN_BOTTOM as u32;
const MARGIN_LEFT = lvgl_sys::LV_STYLE_MARGIN_LEFT as u32;
const MARGIN_RIGHT = lvgl_sys::LV_STYLE_MARGIN_RIGHT as u32;
const BG_BLEND_MODE = lvgl_sys::LV_STYLE_BG_BLEND_MODE as u32;
const BG_MAIN_STOP = lvgl_sys::LV_STYLE_BG_MAIN_STOP as u32;
const BG_GRAD_STOP = lvgl_sys::LV_STYLE_BG_GRAD_STOP as u32;
const BG_GRAD_DIR = lvgl_sys::LV_STYLE_BG_GRAD_DIR as u32;
const BG_COLOR = lvgl_sys::LV_STYLE_BG_COLOR as u32;
const BG_GRAD_COLOR = lvgl_sys::LV_STYLE_BG_GRAD_COLOR as u32;
const BG_OPA = lvgl_sys::LV_STYLE_BG_OPA as u32;
const BORDER_WIDTH = lvgl_sys::LV_STYLE_BORDER_WIDTH as u32;
const BORDER_SIDE = lvgl_sys::LV_STYLE_BORDER_SIDE as u32;
const BORDER_BLEND_MODE = lvgl_sys::LV_STYLE_BORDER_BLEND_MODE as u32;
const BORDER_POST = lvgl_sys::LV_STYLE_BORDER_POST as u32;
const BORDER_COLOR = lvgl_sys::LV_STYLE_BORDER_COLOR as u32;
const BORDER_OPA = lvgl_sys::LV_STYLE_BORDER_OPA as u32;
const OUTLINE_WIDTH = lvgl_sys::LV_STYLE_OUTLINE_WIDTH as u32;
const OUTLINE_PAD = lvgl_sys::LV_STYLE_OUTLINE_PAD as u32;
const OUTLINE_BLEND_MODE = lvgl_sys::LV_STYLE_OUTLINE_BLEND_MODE as u32;
const OUTLINE_COLOR = lvgl_sys::LV_STYLE_OUTLINE_COLOR as u32;
const OUTLINE_OPA = lvgl_sys::LV_STYLE_OUTLINE_OPA as u32;
const SHADOW_WIDTH = lvgl_sys::LV_STYLE_SHADOW_WIDTH as u32;
const SHADOW_OFS_X = lvgl_sys::LV_STYLE_SHADOW_OFS_X as u32;
const SHADOW_OFS_Y = lvgl_sys::LV_STYLE_SHADOW_OFS_Y as u32;
const SHADOW_SPREAD = lvgl_sys::LV_STYLE_SHADOW_SPREAD as u32;
const SHADOW_BLEND_MODE = lvgl_sys::LV_STYLE_SHADOW_BLEND_MODE as u32;
const SHADOW_COLOR = lvgl_sys::LV_STYLE_SHADOW_COLOR as u32;
const SHADOW_OPA = lvgl_sys::LV_STYLE_SHADOW_OPA as u32;
const PATTERN_BLEND_MODE = lvgl_sys::LV_STYLE_PATTERN_BLEND_MODE as u32;
const PATTERN_REPEAT = lvgl_sys::LV_STYLE_PATTERN_REPEAT as u32;
const PATTERN_RECOLOR = lvgl_sys::LV_STYLE_PATTERN_RECOLOR as u32;
const PATTERN_OPA = lvgl_sys::LV_STYLE_PATTERN_OPA as u32;
const PATTERN_RECOLOR_OPA = lvgl_sys::LV_STYLE_PATTERN_RECOLOR_OPA as u32;
const PATTERN_IMAGE = lvgl_sys::LV_STYLE_PATTERN_IMAGE as u32;
const VALUE_LETTER_SPACE = lvgl_sys::LV_STYLE_VALUE_LETTER_SPACE as u32;
const VALUE_LINE_SPACE = lvgl_sys::LV_STYLE_VALUE_LINE_SPACE as u32;
const VALUE_BLEND_MODE = lvgl_sys::LV_STYLE_VALUE_BLEND_MODE as u32;
const VALUE_OFS_X = lvgl_sys::LV_STYLE_VALUE_OFS_X as u32;
const VALUE_OFS_Y = lvgl_sys::LV_STYLE_VALUE_OFS_Y as u32;
const VALUE_ALIGN = lvgl_sys::LV_STYLE_VALUE_ALIGN as u32;
const VALUE_COLOR = lvgl_sys::LV_STYLE_VALUE_COLOR as u32;
const VALUE_OPA = lvgl_sys::LV_STYLE_VALUE_OPA as u32;
const VALUE_FONT = lvgl_sys::LV_STYLE_VALUE_FONT as u32;
const VALUE_STR = lvgl_sys::LV_STYLE_VALUE_STR as u32;
const TEXT_LETTER_SPACE = lvgl_sys::LV_STYLE_TEXT_LETTER_SPACE as u32;
const TEXT_LINE_SPACE = lvgl_sys::LV_STYLE_TEXT_LINE_SPACE as u32;
const TEXT_DECOR = lvgl_sys::LV_STYLE_TEXT_DECOR as u32;
const TEXT_BLEND_MODE = lvgl_sys::LV_STYLE_TEXT_BLEND_MODE as u32;
const TEXT_COLOR = lvgl_sys::LV_STYLE_TEXT_COLOR as u32;
const TEXT_SEL_COLOR = lvgl_sys::LV_STYLE_TEXT_SEL_COLOR as u32;
const TEXT_OPA = lvgl_sys::LV_STYLE_TEXT_OPA as u32;
const TEXT_FONT = lvgl_sys::LV_STYLE_TEXT_FONT as u32;
const LINE_WIDTH = lvgl_sys::LV_STYLE_LINE_WIDTH as u32;
const LINE_BLEND_MODE = lvgl_sys::LV_STYLE_LINE_BLEND_MODE as u32;
const LINE_DASH_WIDTH = lvgl_sys::LV_STYLE_LINE_DASH_WIDTH as u32;
const LINE_DASH_GAP = lvgl_sys::LV_STYLE_LINE_DASH_GAP as u32;
const LINE_ROUNDED = lvgl_sys::LV_STYLE_LINE_ROUNDED as u32;
const LINE_COLOR = lvgl_sys::LV_STYLE_LINE_COLOR as u32;
const LINE_OPA = lvgl_sys::LV_STYLE_LINE_OPA as u32;
const IMAGE_BLEND_MODE = lvgl_sys::LV_STYLE_IMAGE_BLEND_MODE as u32;
const IMAGE_RECOLOR = lvgl_sys::LV_STYLE_IMAGE_RECOLOR as u32;
const IMAGE_OPA = lvgl_sys::LV_STYLE_IMAGE_OPA as u32;
const IMAGE_RECOLOR_OPA = lvgl_sys::LV_STYLE_IMAGE_RECOLOR_OPA as u32;
const TRANSITION_TIME = lvgl_sys::LV_STYLE_TRANSITION_TIME as u32;
const TRANSITION_DELAY = lvgl_sys::LV_STYLE_TRANSITION_DELAY as u32;
const TRANSITION_PROP_1 = lvgl_sys::LV_STYLE_TRANSITION_PROP_1 as u32;
const TRANSITION_PROP_2 = lvgl_sys::LV_STYLE_TRANSITION_PROP_2 as u32;
const TRANSITION_PROP_3 = lvgl_sys::LV_STYLE_TRANSITION_PROP_3 as u32;
const TRANSITION_PROP_4 = lvgl_sys::LV_STYLE_TRANSITION_PROP_4 as u32;
const TRANSITION_PROP_5 = lvgl_sys::LV_STYLE_TRANSITION_PROP_5 as u32;
const TRANSITION_PROP_6 = lvgl_sys::LV_STYLE_TRANSITION_PROP_6 as u32;
const TRANSITION_PATH = lvgl_sys::LV_STYLE_TRANSITION_PATH as u32;
const SCALE_WIDTH = lvgl_sys::LV_STYLE_SCALE_WIDTH as u32;
const SCALE_BORDER_WIDTH = lvgl_sys::LV_STYLE_SCALE_BORDER_WIDTH as u32;
const SCALE_END_BORDER_WIDTH = lvgl_sys::LV_STYLE_SCALE_END_BORDER_WIDTH as u32;
const SCALE_END_LINE_WIDTH = lvgl_sys::LV_STYLE_SCALE_END_LINE_WIDTH as u32;
const SCALE_GRAD_COLOR = lvgl_sys::LV_STYLE_SCALE_GRAD_COLOR as u32;
const SCALE_END_COLOR = lvgl_sys::LV_STYLE_SCALE_END_COLOR as u32;
const RADIUS = lvgl_sys::LV_STYLE_RADIUS;
const CLIP_CORNER = lvgl_sys::LV_STYLE_CLIP_CORNER;
const SIZE = lvgl_sys::LV_STYLE_SIZE;
const TRANSFORM_WIDTH = lvgl_sys::LV_STYLE_TRANSFORM_WIDTH;
const TRANSFORM_HEIGHT = lvgl_sys::LV_STYLE_TRANSFORM_HEIGHT;
const TRANSFORM_ANGLE = lvgl_sys::LV_STYLE_TRANSFORM_ANGLE;
const TRANSFORM_ZOOM = lvgl_sys::LV_STYLE_TRANSFORM_ZOOM;
const OPA_SCALE = lvgl_sys::LV_STYLE_OPA_SCALE;
const PAD_TOP = lvgl_sys::LV_STYLE_PAD_TOP;
const PAD_BOTTOM = lvgl_sys::LV_STYLE_PAD_BOTTOM;
const PAD_LEFT = lvgl_sys::LV_STYLE_PAD_LEFT;
const PAD_RIGHT = lvgl_sys::LV_STYLE_PAD_RIGHT;
const PAD_INNER = lvgl_sys::LV_STYLE_PAD_INNER;
const MARGIN_TOP = lvgl_sys::LV_STYLE_MARGIN_TOP;
const MARGIN_BOTTOM = lvgl_sys::LV_STYLE_MARGIN_BOTTOM;
const MARGIN_LEFT = lvgl_sys::LV_STYLE_MARGIN_LEFT;
const MARGIN_RIGHT = lvgl_sys::LV_STYLE_MARGIN_RIGHT;
const BG_BLEND_MODE = lvgl_sys::LV_STYLE_BG_BLEND_MODE;
const BG_MAIN_STOP = lvgl_sys::LV_STYLE_BG_MAIN_STOP;
const BG_GRAD_STOP = lvgl_sys::LV_STYLE_BG_GRAD_STOP;
const BG_GRAD_DIR = lvgl_sys::LV_STYLE_BG_GRAD_DIR;
const BG_COLOR = lvgl_sys::LV_STYLE_BG_COLOR;
const BG_GRAD_COLOR = lvgl_sys::LV_STYLE_BG_GRAD_COLOR;
const BG_OPA = lvgl_sys::LV_STYLE_BG_OPA;
const BORDER_WIDTH = lvgl_sys::LV_STYLE_BORDER_WIDTH;
const BORDER_SIDE = lvgl_sys::LV_STYLE_BORDER_SIDE;
const BORDER_BLEND_MODE = lvgl_sys::LV_STYLE_BORDER_BLEND_MODE;
const BORDER_POST = lvgl_sys::LV_STYLE_BORDER_POST;
const BORDER_COLOR = lvgl_sys::LV_STYLE_BORDER_COLOR;
const BORDER_OPA = lvgl_sys::LV_STYLE_BORDER_OPA;
const OUTLINE_WIDTH = lvgl_sys::LV_STYLE_OUTLINE_WIDTH;
const OUTLINE_PAD = lvgl_sys::LV_STYLE_OUTLINE_PAD;
const OUTLINE_BLEND_MODE = lvgl_sys::LV_STYLE_OUTLINE_BLEND_MODE;
const OUTLINE_COLOR = lvgl_sys::LV_STYLE_OUTLINE_COLOR;
const OUTLINE_OPA = lvgl_sys::LV_STYLE_OUTLINE_OPA;
const SHADOW_WIDTH = lvgl_sys::LV_STYLE_SHADOW_WIDTH;
const SHADOW_OFS_X = lvgl_sys::LV_STYLE_SHADOW_OFS_X;
const SHADOW_OFS_Y = lvgl_sys::LV_STYLE_SHADOW_OFS_Y;
const SHADOW_SPREAD = lvgl_sys::LV_STYLE_SHADOW_SPREAD;
const SHADOW_BLEND_MODE = lvgl_sys::LV_STYLE_SHADOW_BLEND_MODE;
const SHADOW_COLOR = lvgl_sys::LV_STYLE_SHADOW_COLOR;
const SHADOW_OPA = lvgl_sys::LV_STYLE_SHADOW_OPA;
const PATTERN_BLEND_MODE = lvgl_sys::LV_STYLE_PATTERN_BLEND_MODE;
const PATTERN_REPEAT = lvgl_sys::LV_STYLE_PATTERN_REPEAT;
const PATTERN_RECOLOR = lvgl_sys::LV_STYLE_PATTERN_RECOLOR;
const PATTERN_OPA = lvgl_sys::LV_STYLE_PATTERN_OPA;
const PATTERN_RECOLOR_OPA = lvgl_sys::LV_STYLE_PATTERN_RECOLOR_OPA;
const PATTERN_IMAGE = lvgl_sys::LV_STYLE_PATTERN_IMAGE;
const VALUE_LETTER_SPACE = lvgl_sys::LV_STYLE_VALUE_LETTER_SPACE;
const VALUE_LINE_SPACE = lvgl_sys::LV_STYLE_VALUE_LINE_SPACE;
const VALUE_BLEND_MODE = lvgl_sys::LV_STYLE_VALUE_BLEND_MODE;
const VALUE_OFS_X = lvgl_sys::LV_STYLE_VALUE_OFS_X;
const VALUE_OFS_Y = lvgl_sys::LV_STYLE_VALUE_OFS_Y;
const VALUE_ALIGN = lvgl_sys::LV_STYLE_VALUE_ALIGN;
const VALUE_COLOR = lvgl_sys::LV_STYLE_VALUE_COLOR;
const VALUE_OPA = lvgl_sys::LV_STYLE_VALUE_OPA;
const VALUE_FONT = lvgl_sys::LV_STYLE_VALUE_FONT;
const VALUE_STR = lvgl_sys::LV_STYLE_VALUE_STR;
const TEXT_LETTER_SPACE = lvgl_sys::LV_STYLE_TEXT_LETTER_SPACE;
const TEXT_LINE_SPACE = lvgl_sys::LV_STYLE_TEXT_LINE_SPACE;
const TEXT_DECOR = lvgl_sys::LV_STYLE_TEXT_DECOR;
const TEXT_BLEND_MODE = lvgl_sys::LV_STYLE_TEXT_BLEND_MODE;
const TEXT_COLOR = lvgl_sys::LV_STYLE_TEXT_COLOR;
const TEXT_SEL_COLOR = lvgl_sys::LV_STYLE_TEXT_SEL_COLOR;
const TEXT_OPA = lvgl_sys::LV_STYLE_TEXT_OPA;
const TEXT_FONT = lvgl_sys::LV_STYLE_TEXT_FONT;
const LINE_WIDTH = lvgl_sys::LV_STYLE_LINE_WIDTH;
const LINE_BLEND_MODE = lvgl_sys::LV_STYLE_LINE_BLEND_MODE;
const LINE_DASH_WIDTH = lvgl_sys::LV_STYLE_LINE_DASH_WIDTH;
const LINE_DASH_GAP = lvgl_sys::LV_STYLE_LINE_DASH_GAP;
const LINE_ROUNDED = lvgl_sys::LV_STYLE_LINE_ROUNDED;
const LINE_COLOR = lvgl_sys::LV_STYLE_LINE_COLOR;
const LINE_OPA = lvgl_sys::LV_STYLE_LINE_OPA;
const IMAGE_BLEND_MODE = lvgl_sys::LV_STYLE_IMAGE_BLEND_MODE;
const IMAGE_RECOLOR = lvgl_sys::LV_STYLE_IMAGE_RECOLOR;
const IMAGE_OPA = lvgl_sys::LV_STYLE_IMAGE_OPA;
const IMAGE_RECOLOR_OPA = lvgl_sys::LV_STYLE_IMAGE_RECOLOR_OPA;
const TRANSITION_TIME = lvgl_sys::LV_STYLE_TRANSITION_TIME;
const TRANSITION_DELAY = lvgl_sys::LV_STYLE_TRANSITION_DELAY;
const TRANSITION_PROP_1 = lvgl_sys::LV_STYLE_TRANSITION_PROP_1;
const TRANSITION_PROP_2 = lvgl_sys::LV_STYLE_TRANSITION_PROP_2;
const TRANSITION_PROP_3 = lvgl_sys::LV_STYLE_TRANSITION_PROP_3;
const TRANSITION_PROP_4 = lvgl_sys::LV_STYLE_TRANSITION_PROP_4;
const TRANSITION_PROP_5 = lvgl_sys::LV_STYLE_TRANSITION_PROP_5;
const TRANSITION_PROP_6 = lvgl_sys::LV_STYLE_TRANSITION_PROP_6;
const TRANSITION_PATH = lvgl_sys::LV_STYLE_TRANSITION_PATH;
const SCALE_WIDTH = lvgl_sys::LV_STYLE_SCALE_WIDTH;
const SCALE_BORDER_WIDTH = lvgl_sys::LV_STYLE_SCALE_BORDER_WIDTH;
const SCALE_END_BORDER_WIDTH = lvgl_sys::LV_STYLE_SCALE_END_BORDER_WIDTH;
const SCALE_END_LINE_WIDTH = lvgl_sys::LV_STYLE_SCALE_END_LINE_WIDTH;
const SCALE_GRAD_COLOR = lvgl_sys::LV_STYLE_SCALE_GRAD_COLOR;
const SCALE_END_COLOR = lvgl_sys::LV_STYLE_SCALE_END_COLOR;
}
}
@ -166,8 +166,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_RADIUS as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
(lvgl_sys::LV_STYLE_RADIUS | (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32))
as u16,
value,
);
}
@ -178,7 +178,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_CLIP_CORNER as u32
(lvgl_sys::LV_STYLE_CLIP_CORNER
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -190,8 +190,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SIZE as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
(lvgl_sys::LV_STYLE_SIZE | (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32))
as u16,
value,
);
}
@ -202,7 +202,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSFORM_WIDTH as u32
(lvgl_sys::LV_STYLE_TRANSFORM_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -214,7 +214,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSFORM_HEIGHT as u32
(lvgl_sys::LV_STYLE_TRANSFORM_HEIGHT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -226,7 +226,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSFORM_ANGLE as u32
(lvgl_sys::LV_STYLE_TRANSFORM_ANGLE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -238,7 +238,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSFORM_ZOOM as u32
(lvgl_sys::LV_STYLE_TRANSFORM_ZOOM
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -250,7 +250,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OPA_SCALE as u32
(lvgl_sys::LV_STYLE_OPA_SCALE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -262,8 +262,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PAD_TOP as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
(lvgl_sys::LV_STYLE_PAD_TOP | (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32))
as u16,
value,
);
}
@ -274,7 +274,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PAD_BOTTOM as u32
(lvgl_sys::LV_STYLE_PAD_BOTTOM
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -286,7 +286,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PAD_LEFT as u32
(lvgl_sys::LV_STYLE_PAD_LEFT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -298,7 +298,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PAD_RIGHT as u32
(lvgl_sys::LV_STYLE_PAD_RIGHT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -310,7 +310,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PAD_INNER as u32
(lvgl_sys::LV_STYLE_PAD_INNER
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -322,7 +322,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_MARGIN_TOP as u32
(lvgl_sys::LV_STYLE_MARGIN_TOP
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -334,7 +334,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_MARGIN_BOTTOM as u32
(lvgl_sys::LV_STYLE_MARGIN_BOTTOM
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -346,7 +346,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_MARGIN_LEFT as u32
(lvgl_sys::LV_STYLE_MARGIN_LEFT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -358,7 +358,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_MARGIN_RIGHT as u32
(lvgl_sys::LV_STYLE_MARGIN_RIGHT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -370,7 +370,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_BG_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -382,7 +382,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_MAIN_STOP as u32
(lvgl_sys::LV_STYLE_BG_MAIN_STOP
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -394,7 +394,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_GRAD_STOP as u32
(lvgl_sys::LV_STYLE_BG_GRAD_STOP
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -406,7 +406,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_GRAD_DIR as u32
(lvgl_sys::LV_STYLE_BG_GRAD_DIR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -418,7 +418,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_COLOR as u32
(lvgl_sys::LV_STYLE_BG_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -430,7 +430,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_GRAD_COLOR as u32
(lvgl_sys::LV_STYLE_BG_GRAD_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -442,8 +442,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BG_OPA as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
(lvgl_sys::LV_STYLE_BG_OPA | (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32))
as u16,
value.into(),
);
}
@ -454,7 +454,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_WIDTH as u32
(lvgl_sys::LV_STYLE_BORDER_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -466,7 +466,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_SIDE as u32
(lvgl_sys::LV_STYLE_BORDER_SIDE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -478,7 +478,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_BORDER_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -490,7 +490,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_POST as u32
(lvgl_sys::LV_STYLE_BORDER_POST
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -502,7 +502,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_COLOR as u32
(lvgl_sys::LV_STYLE_BORDER_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -514,7 +514,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_BORDER_OPA as u32
(lvgl_sys::LV_STYLE_BORDER_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -526,7 +526,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OUTLINE_WIDTH as u32
(lvgl_sys::LV_STYLE_OUTLINE_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -538,7 +538,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OUTLINE_PAD as u32
(lvgl_sys::LV_STYLE_OUTLINE_PAD
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -550,7 +550,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OUTLINE_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_OUTLINE_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -562,7 +562,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OUTLINE_COLOR as u32
(lvgl_sys::LV_STYLE_OUTLINE_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -574,7 +574,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_OUTLINE_OPA as u32
(lvgl_sys::LV_STYLE_OUTLINE_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -586,7 +586,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_WIDTH as u32
(lvgl_sys::LV_STYLE_SHADOW_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -598,7 +598,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_OFS_X as u32
(lvgl_sys::LV_STYLE_SHADOW_OFS_X
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -610,7 +610,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_OFS_Y as u32
(lvgl_sys::LV_STYLE_SHADOW_OFS_Y
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -622,7 +622,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_SPREAD as u32
(lvgl_sys::LV_STYLE_SHADOW_SPREAD
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -634,7 +634,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_SHADOW_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -646,7 +646,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_COLOR as u32
(lvgl_sys::LV_STYLE_SHADOW_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -658,7 +658,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SHADOW_OPA as u32
(lvgl_sys::LV_STYLE_SHADOW_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -670,7 +670,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PATTERN_REPEAT as u32
(lvgl_sys::LV_STYLE_PATTERN_REPEAT
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -682,7 +682,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PATTERN_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_PATTERN_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -694,7 +694,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PATTERN_RECOLOR as u32
(lvgl_sys::LV_STYLE_PATTERN_RECOLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -706,7 +706,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PATTERN_OPA as u32
(lvgl_sys::LV_STYLE_PATTERN_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -718,7 +718,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_PATTERN_RECOLOR_OPA as u32
(lvgl_sys::LV_STYLE_PATTERN_RECOLOR_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -730,7 +730,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_LETTER_SPACE as u32
(lvgl_sys::LV_STYLE_VALUE_LETTER_SPACE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -742,7 +742,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_LINE_SPACE as u32
(lvgl_sys::LV_STYLE_VALUE_LINE_SPACE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -754,7 +754,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_VALUE_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -766,7 +766,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_OFS_X as u32
(lvgl_sys::LV_STYLE_VALUE_OFS_X
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -778,7 +778,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_OFS_Y as u32
(lvgl_sys::LV_STYLE_VALUE_OFS_Y
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -790,7 +790,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_ALIGN as u32
(lvgl_sys::LV_STYLE_VALUE_ALIGN
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -802,7 +802,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_COLOR as u32
(lvgl_sys::LV_STYLE_VALUE_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -814,7 +814,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_VALUE_OPA as u32
(lvgl_sys::LV_STYLE_VALUE_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -826,7 +826,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_LETTER_SPACE as u32
(lvgl_sys::LV_STYLE_TEXT_LETTER_SPACE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -838,7 +838,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_LINE_SPACE as u32
(lvgl_sys::LV_STYLE_TEXT_LINE_SPACE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -850,7 +850,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_DECOR as u32
(lvgl_sys::LV_STYLE_TEXT_DECOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -862,7 +862,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_TEXT_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -874,7 +874,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_COLOR as u32
(lvgl_sys::LV_STYLE_TEXT_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -886,7 +886,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_SEL_COLOR as u32
(lvgl_sys::LV_STYLE_TEXT_SEL_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -898,7 +898,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TEXT_OPA as u32
(lvgl_sys::LV_STYLE_TEXT_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -910,7 +910,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_WIDTH as u32
(lvgl_sys::LV_STYLE_LINE_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -922,7 +922,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_LINE_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -934,7 +934,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_DASH_WIDTH as u32
(lvgl_sys::LV_STYLE_LINE_DASH_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -946,7 +946,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_DASH_GAP as u32
(lvgl_sys::LV_STYLE_LINE_DASH_GAP
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -958,7 +958,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_ROUNDED as u32
(lvgl_sys::LV_STYLE_LINE_ROUNDED
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -970,7 +970,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_COLOR as u32
(lvgl_sys::LV_STYLE_LINE_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -982,7 +982,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_LINE_OPA as u32
(lvgl_sys::LV_STYLE_LINE_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -994,7 +994,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_IMAGE_BLEND_MODE as u32
(lvgl_sys::LV_STYLE_IMAGE_BLEND_MODE
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1006,7 +1006,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_IMAGE_RECOLOR as u32
(lvgl_sys::LV_STYLE_IMAGE_RECOLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
@ -1018,7 +1018,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_IMAGE_OPA as u32
(lvgl_sys::LV_STYLE_IMAGE_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -1030,7 +1030,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_opa(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_IMAGE_RECOLOR_OPA as u32
(lvgl_sys::LV_STYLE_IMAGE_RECOLOR_OPA
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.into(),
);
@ -1042,7 +1042,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_TIME as u32
(lvgl_sys::LV_STYLE_TRANSITION_TIME
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1054,7 +1054,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_DELAY as u32
(lvgl_sys::LV_STYLE_TRANSITION_DELAY
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1066,7 +1066,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_1 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_1
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1078,7 +1078,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_2 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_2
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1090,7 +1090,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_3 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_3
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1102,7 +1102,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_4 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_4
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1114,7 +1114,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_5 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_5
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1126,7 +1126,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_TRANSITION_PROP_6 as u32
(lvgl_sys::LV_STYLE_TRANSITION_PROP_6
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1138,7 +1138,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_WIDTH as u32
(lvgl_sys::LV_STYLE_SCALE_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1150,7 +1150,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_BORDER_WIDTH as u32
(lvgl_sys::LV_STYLE_SCALE_BORDER_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1162,7 +1162,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_END_BORDER_WIDTH as u32
(lvgl_sys::LV_STYLE_SCALE_END_BORDER_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1174,7 +1174,7 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_int(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_END_LINE_WIDTH as u32
(lvgl_sys::LV_STYLE_SCALE_END_LINE_WIDTH
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value,
);
@ -1186,8 +1186,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_GRAD_COLOR as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS)) as u16,
(lvgl_sys::LV_STYLE_SCALE_GRAD_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
}
@ -1198,8 +1198,8 @@ impl Style {
unsafe {
lvgl_sys::_lv_style_set_color(
self.raw.as_mut(),
(lvgl_sys::LV_STYLE_SCALE_END_COLOR as u32
| (native_state << lvgl_sys::LV_STYLE_STATE_POS)) as u16,
(lvgl_sys::LV_STYLE_SCALE_END_COLOR
| (native_state << lvgl_sys::LV_STYLE_STATE_POS as u32)) as u16,
value.raw,
);
}

View file

@ -1,174 +0,0 @@
use core::mem;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
/// Places a sized `T` into LVGL memory.
///
/// This is useful for cases when we need to allocate memory on Rust side
/// and handover the management of that memory to LVGL. May also be used in cases we
/// want to use dynamic memory in the Rust side.
pub(crate) struct Box<T>(NonNull<T>);
impl<T> Box<T> {
/// Allocate memory using LVGL memory API and place `T` in the LVGL tracked memory.
pub fn new(value: T) -> Box<T> {
let size = mem::size_of::<T>();
let inner = unsafe {
let ptr = lvgl_sys::lv_mem_alloc(size as lvgl_sys::size_t) as *mut T;
// LVGL should align the memory address for us!
assert_eq!(
ptr as usize % mem::align_of::<T>(),
0,
"Memory address not aligned!"
);
NonNull::new(ptr)
.map(|p| {
p.as_ptr().write(value);
p
})
.unwrap_or_else(|| {
panic!("Could not allocate memory {} bytes", size);
})
};
Box(inner)
}
pub fn into_raw(self) -> *mut T {
let b = mem::ManuallyDrop::new(self);
b.0.as_ptr()
}
}
impl<T> Drop for Box<T> {
fn drop(&mut self) {
unsafe {
lvgl_sys::lv_mem_free(self.0.as_ptr() as *const cty::c_void);
}
}
}
impl<T> DerefMut for Box<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl<T> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.0.as_ref() }
}
}
impl<T> AsMut<T> for Box<T> {
fn as_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() }
}
}
impl<T: Clone> Clone for Box<T> {
fn clone(&self) -> Self {
unsafe { Self::new(self.0.as_ref().clone()) }
}
}
#[cfg(test)]
mod test {
use super::*;
use std::vec::Vec;
#[test]
fn place_value_in_lv_mem() {
crate::lvgl_init();
let v = Box::new(5);
drop(v);
let v = Box::new(10);
drop(v);
}
#[test]
fn place_complex_value_in_lv_mem() {
crate::lvgl_init();
#[repr(C)]
#[derive(Debug)]
struct Point {
x: u64,
y: i8,
t: i32,
disp: i32,
}
let initial_mem_info = mem_info();
let mut keep = Vec::new();
for i in 0..100 {
let p = Point {
x: i,
y: 42,
t: 0,
disp: -100,
};
println!("{:?}", p);
let mut b = Box::new(p);
println!("memory address is {:p}", b.as_mut());
let point = b.as_mut();
if point.x != i {
println!("{:?}", point);
}
assert_eq!(point.x, i);
let info = mem_info();
println!("mem info: {:?}", &info);
keep.push(b);
}
drop(keep);
unsafe {
lvgl_sys::lv_mem_defrag();
}
let final_info = mem_info();
println!("mem info: {:?}", &final_info);
// If this fails, we are leaking memory! BOOM! \o/
assert_eq!(initial_mem_info.free_size, final_info.free_size)
}
#[test]
fn clone_object_in_lv_mem() {
crate::lvgl_init();
let v1 = Box::new(5);
let v2 = v1.clone();
// Ensure that the two objects have identical values.
assert_eq!(*v1, *v2);
// They should have different memory addresses, however.
assert_ne!(v1.into_raw() as usize, v2.into_raw() as usize);
}
fn mem_info() -> lvgl_sys::lv_mem_monitor_t {
let mut info = lvgl_sys::lv_mem_monitor_t {
total_size: 0,
free_cnt: 0,
free_size: 0,
free_biggest_size: 0,
used_cnt: 0,
max_used: 0,
used_pct: 0,
frag_pct: 0,
};
unsafe {
lvgl_sys::lv_mem_monitor(&mut info as *mut _);
}
info
}
}

View file

@ -1,6 +1,8 @@
use crate::Widget;
use bitflags::_core::option::NoneError;
use core::convert::{TryFrom, TryInto};
use core::ptr::NonNull;
use cstr_core::NulError;
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
pub type LvResult<T> = Result<T, LvError>;
@ -9,10 +11,22 @@ pub type LvResult<T> = Result<T, LvError>;
pub enum LvError {
InvalidReference,
Uninitialized,
LvOOMemory,
InvalidNulByteString,
AlreadyInUse,
}
impl From<NoneError> for LvError {
fn from(_: NoneError) -> Self {
LvError::InvalidReference
}
}
impl From<NulError> for LvError {
fn from(_: NulError) -> Self {
LvError::InvalidNulByteString
}
}
#[derive(Clone)]
pub struct Color {
pub(crate) raw: lvgl_sys::lv_color_t,
@ -27,18 +41,6 @@ impl Color {
pub fn from_raw(raw: lvgl_sys::lv_color_t) -> Self {
Self { raw }
}
pub fn r(&self) -> u8 {
unsafe { lvgl_sys::_LV_COLOR_GET_R(self.raw) as u8 }
}
pub fn g(&self) -> u8 {
unsafe { lvgl_sys::_LV_COLOR_GET_G(self.raw) as u8 }
}
pub fn b(&self) -> u8 {
unsafe { lvgl_sys::_LV_COLOR_GET_B(self.raw) as u8 }
}
}
impl From<Color> for Rgb888 {
@ -65,7 +67,7 @@ impl From<Color> for Rgb565 {
}
}
/// Events are triggered in LVGL when something happens which might be interesting to
/// Events are triggered in LittlevGL when something happens which might be interesting to
/// the user, e.g. if an object:
/// - is clicked
/// - is dragged
@ -112,25 +114,23 @@ impl<S> TryFrom<lvgl_sys::lv_event_t> for Event<S> {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
const LV_EVENT_PRESSED: u32 = lvgl_sys::LV_EVENT_PRESSED as u32;
const LV_EVENT_PRESSING: u32 = lvgl_sys::LV_EVENT_PRESSING as u32;
const LV_EVENT_PRESS_LOST: u32 = lvgl_sys::LV_EVENT_PRESS_LOST as u32;
const LV_EVENT_SHORT_CLICKED: u32 = lvgl_sys::LV_EVENT_SHORT_CLICKED as u32;
const LV_EVENT_CLICKED: u32 = lvgl_sys::LV_EVENT_CLICKED as u32;
const LV_EVENT_LONG_PRESSED: u32 = lvgl_sys::LV_EVENT_LONG_PRESSED as u32;
const LV_EVENT_LONG_PRESSED_REPEAT: u32 = lvgl_sys::LV_EVENT_LONG_PRESSED_REPEAT as u32;
const LV_EVENT_RELEASED: u32 = lvgl_sys::LV_EVENT_RELEASED as u32;
match value as u32 {
LV_EVENT_PRESSED => Ok(Event::Pressed),
LV_EVENT_PRESSING => Ok(Event::Pressing),
LV_EVENT_PRESS_LOST => Ok(Event::PressLost),
LV_EVENT_SHORT_CLICKED => Ok(Event::ShortClicked),
LV_EVENT_CLICKED => Ok(Event::Clicked),
LV_EVENT_LONG_PRESSED => Ok(Event::LongPressed),
LV_EVENT_LONG_PRESSED_REPEAT => Ok(Event::LongPressedRepeat),
LV_EVENT_RELEASED => Ok(Event::Released),
lvgl_sys::LV_EVENT_PRESSED => Ok(Event::Pressed),
lvgl_sys::LV_EVENT_PRESSING => Ok(Event::Pressing),
lvgl_sys::LV_EVENT_PRESS_LOST => Ok(Event::PressLost),
lvgl_sys::LV_EVENT_SHORT_CLICKED => Ok(Event::ShortClicked),
lvgl_sys::LV_EVENT_CLICKED => Ok(Event::Clicked),
lvgl_sys::LV_EVENT_LONG_PRESSED => Ok(Event::LongPressed),
lvgl_sys::LV_EVENT_LONG_PRESSED_REPEAT => Ok(Event::LongPressedRepeat),
lvgl_sys::LV_EVENT_RELEASED => Ok(Event::Released),
_ => Err(()),
// _ => {
// if let Ok(special_event_type) = S::try_from(value) {
// Ok(Event::Special(special_event_type))
// } else {
// Err(())
// }
// }
}
}
}
@ -203,9 +203,9 @@ pub enum Align {
OutRightBottom,
}
impl From<Align> for u8 {
fn from(self_: Align) -> u8 {
let native = match self_ {
impl Into<u8> for Align {
fn into(self) -> u8 {
let native = match self {
Align::Center => lvgl_sys::LV_ALIGN_CENTER,
Align::InTopLeft => lvgl_sys::LV_ALIGN_IN_TOP_LEFT,
Align::InTopMid => lvgl_sys::LV_ALIGN_IN_TOP_MID,
@ -245,23 +245,3 @@ impl From<Animation> for lvgl_sys::lv_anim_enable_t {
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn color_properties_accessible() {
let color = Color::from_rgb((206, 51, 255));
if lvgl_sys::LV_COLOR_DEPTH == 32 {
assert_eq!(color.r(), 206);
assert_eq!(color.g(), 51);
assert_eq!(color.b(), 255);
} else if lvgl_sys::LV_COLOR_DEPTH == 16 {
assert_eq!(color.r(), 25);
assert_eq!(color.g(), 12);
assert_eq!(color.b(), 31);
}
}
}

View file

@ -1,200 +0,0 @@
use crate::Box;
use crate::{Color, Event, LvError, LvResult, Obj, Widget};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ptr;
use core::ptr::NonNull;
use core::sync::atomic::{AtomicBool, Ordering};
use core::time::Duration;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::prelude::*;
use embedded_graphics::{pixelcolor::PixelColor, Pixel};
// There can only be a single reference to LVGL library.
static LVGL_IN_USE: AtomicBool = AtomicBool::new(false);
// TODO: Make this an external configuration
const REFRESH_BUFFER_LEN: usize = 2;
// Declare a buffer for the refresh rate
pub(crate) const BUF_SIZE: usize = lvgl_sys::LV_HOR_RES_MAX as usize * REFRESH_BUFFER_LEN;
pub struct UI<T, C>
where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
// LVGL is not thread-safe by default.
_not_sync: PhantomData<*mut ()>,
// Later we can add possibility to have multiple displays by using `heapless::Vec`
display_data: Option<DisplayUserData<T, C>>,
}
// LVGL does not use thread locals.
unsafe impl<T, C> Send for UI<T, C>
where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
}
impl<T, C> UI<T, C>
where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
pub fn init() -> LvResult<Self> {
if LVGL_IN_USE
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
.is_ok()
{
crate::lvgl_init();
Ok(Self {
_not_sync: PhantomData,
display_data: None,
})
} else {
Err(LvError::AlreadyInUse)
}
}
pub fn disp_drv_register(&mut self, display: T) -> LvResult<()> {
self.display_data = Some(DisplayUserData {
display,
phantom: PhantomData,
});
let refresh_buffer1 = [Color::from_rgb((0, 0, 0)).raw; BUF_SIZE];
let refresh_buffer2 = [Color::from_rgb((0, 0, 0)).raw; BUF_SIZE];
let mut disp_buf = MaybeUninit::<lvgl_sys::lv_disp_buf_t>::uninit();
let mut disp_drv = MaybeUninit::<lvgl_sys::lv_disp_drv_t>::uninit();
unsafe {
// Initialize the display buffer
lvgl_sys::lv_disp_buf_init(
disp_buf.as_mut_ptr(),
Box::into_raw(Box::new(refresh_buffer1)) as *mut cty::c_void,
Box::into_raw(Box::new(refresh_buffer2)) as *mut cty::c_void,
lvgl_sys::LV_HOR_RES_MAX * REFRESH_BUFFER_LEN as u32,
);
// Basic initialization of the display driver
lvgl_sys::lv_disp_drv_init(disp_drv.as_mut_ptr());
let mut disp_drv = Box::new(disp_drv.assume_init());
// Assign the buffer to the display
disp_drv.buffer = Box::into_raw(Box::new(disp_buf.assume_init()));
// Set your driver function
disp_drv.flush_cb = Some(display_callback_wrapper::<T, C>);
disp_drv.user_data = &mut self.display_data as *mut _ as *mut cty::c_void;
// We need to remember to deallocate the `disp_drv` memory when dropping UI
lvgl_sys::lv_disp_drv_register(Box::into_raw(disp_drv));
};
Ok(())
}
pub fn get_display_ref(&self) -> Option<&T> {
match self.display_data.as_ref() {
None => None,
Some(v) => Some(&v.display),
}
}
pub fn scr_act(&self) -> LvResult<Obj> {
unsafe {
let screen = lvgl_sys::lv_disp_get_scr_act(ptr::null_mut());
if let Some(v) = NonNull::new(screen) {
Ok(Obj::from_raw(v))
} else {
Err(LvError::InvalidReference)
}
}
}
pub fn event_send<W>(&mut self, obj: &mut W, event: Event<W::SpecialEvent>) -> LvResult<()>
where
W: Widget,
{
unsafe {
lvgl_sys::lv_event_send(obj.raw()?.as_mut(), event.into(), ptr::null_mut());
}
Ok(())
}
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();
}
}
}
pub(crate) struct DisplayUserData<T, C>
where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
display: T,
phantom: PhantomData<C>,
}
unsafe extern "C" fn display_callback_wrapper<T, C>(
disp_drv: *mut lvgl_sys::lv_disp_drv_t,
area: *const lvgl_sys::lv_area_t,
color_p: *mut lvgl_sys::lv_color_t,
) where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
// In the `std` world we would make sure to capture panics here and make them not escape across
// the FFI boundary. Since this library is focused on embedded platforms, we don't
// have an standard unwinding mechanism to rely upon.
let display_driver = *disp_drv;
// Rust code closure reference
if !display_driver.user_data.is_null() {
let user_data = &mut *(display_driver.user_data as *mut DisplayUserData<T, C>);
let x1 = (*area).x1;
let x2 = (*area).x2;
let y1 = (*area).y1;
let y2 = (*area).y2;
// TODO: Can we do anything when there is a error while flushing?
let _ = display_flush(&mut user_data.display, (x1, x2), (y1, y2), color_p);
}
// Indicate to LVGL that we are ready with the flushing
lvgl_sys::lv_disp_flush_ready(disp_drv);
}
// We separate this display flush function to reduce the amount of unsafe code we need to write.
// This also provides a good separation of concerns, what is necessary from LVGL to work and
// what is the lvgl-rs wrapper responsibility.
fn display_flush<T, C>(
display: &mut T,
(x1, x2): (i16, i16),
(y1, y2): (i16, i16),
color_p: *mut lvgl_sys::lv_color_t,
) -> Result<(), T::Error>
where
T: DrawTarget<Color = C>,
C: PixelColor + From<Color>,
{
let ys = y1..=y2;
let xs = (x1..=x2).enumerate();
let x_len = (x2 - x1 + 1) as usize;
// We use iterators here to ensure that the Rust compiler can apply all possible
// optimizations at compile time.
let pixels = ys.enumerate().flat_map(|(iy, y)| {
xs.clone().map(move |(ix, x)| {
let color_len = x_len * iy + ix;
let lv_color = unsafe { *color_p.add(color_len) };
let raw_color = Color::from_raw(lv_color);
Pixel(Point::new(x as i32, y as i32), raw_color.into())
})
});
display.draw_iter(pixels)
}

View file

@ -5,7 +5,7 @@ mod label;
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
use crate::NativeObject;
use crate::{NativeObject, Widget};
pub use arc::*;
pub use bar::*;
pub use gauge::*;