From 5015711141d25b9755e717148051c36975eeea15 Mon Sep 17 00:00:00 2001 From: Rafael Caricio Date: Thu, 4 Jun 2020 23:09:54 +0200 Subject: [PATCH] Add Gauge widget --- examples/Cargo.toml | 4 ++ examples/bar.rs | 6 +-- examples/button_click.rs | 4 +- examples/demo.rs | 6 +-- examples/gauge.rs | 108 +++++++++++++++++++++++++++++++++++++ lvgl-codegen/Cargo.toml | 1 + lvgl/src/lv_core/object.rs | 14 ++--- lvgl/src/lv_core/style.rs | 1 - lvgl/src/widgets/gauge.rs | 41 ++++++++++++++ lvgl/src/widgets/mod.rs | 2 + 10 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 examples/gauge.rs create mode 100644 lvgl/src/widgets/gauge.rs diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 0084cd4..3cd3713 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -22,3 +22,7 @@ path = "bar.rs" [[example]] name = "button_click" path = "button_click.rs" + +[[example]] +name = "gauge" +path = "gauge.rs" diff --git a/examples/bar.rs b/examples/bar.rs index 99aaac6..eff4aa7 100644 --- a/examples/bar.rs +++ b/examples/bar.rs @@ -5,7 +5,7 @@ use embedded_graphics_simulator::{ }; use lvgl::style::Style; use lvgl::widgets::{Bar, BarPart, Label, LabelAlign}; -use lvgl::{self, Align, Animation, Color, DisplayDriver, Event, ObjPart, Object, State, UI}; +use lvgl::{self, Align, Animation, Color, DisplayDriver, Event, Object, Part, State, UI}; use lvgl_sys; use std::sync::{mpsc, Arc, Mutex}; use std::thread::sleep; @@ -32,7 +32,7 @@ fn main() -> Result<(), String> { let mut screen_style = Style::default(); screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((255, 255, 255))); screen_style.set_radius(State::DEFAULT, 0); - screen.add_style(ObjPart::Main, screen_style); + screen.add_style(Part::Main, screen_style); // Create the bar object let mut bar = Bar::new(&mut screen); @@ -52,7 +52,7 @@ fn main() -> Result<(), String> { let mut loading_style = Style::default(); loading_style.set_text_color(State::DEFAULT, Color::from_rgb((0, 0, 0))); - loading_lbl.add_style(ObjPart::Main, loading_style); + loading_lbl.add_style(Part::Main, loading_style); let threaded_ui = Arc::new(Mutex::new(ui)); diff --git a/examples/button_click.rs b/examples/button_click.rs index 535eaf7..4460d52 100644 --- a/examples/button_click.rs +++ b/examples/button_click.rs @@ -5,7 +5,7 @@ use embedded_graphics_simulator::{ }; use lvgl::style::Style; use lvgl::widgets::{Button, Label}; -use lvgl::{self, Align, Color, DisplayDriver, Event, ObjPart, Object, State, UI}; +use lvgl::{self, Align, Color, DisplayDriver, Event, Object, Part, State, UI}; use lvgl_sys; use std::sync::{mpsc, Arc, Mutex}; use std::thread::sleep; @@ -31,7 +31,7 @@ fn main() -> Result<(), String> { let mut screen_style = Style::default(); screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((0, 0, 0))); - screen.add_style(ObjPart::Main, screen_style); + screen.add_style(Part::Main, screen_style); // Create the button let mut button = Button::new(&mut screen); diff --git a/examples/demo.rs b/examples/demo.rs index 92ad841..56335d8 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -6,7 +6,7 @@ use embedded_graphics_simulator::{ use lvgl; use lvgl::style::Style; use lvgl::widgets::{Label, LabelAlign}; -use lvgl::{Align, Color, ObjPart, Object, State, UI}; +use lvgl::{Align, Color, Object, Part, State, UI}; use lvgl_sys; use std::sync::{mpsc, Arc, Mutex}; use std::thread::sleep; @@ -36,13 +36,13 @@ fn main() -> Result<(), String> { 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); - screen.add_style(ObjPart::Main, screen_style); + screen.add_style(Part::Main, screen_style); let mut time = Label::new(&mut screen); let mut style_time = Style::default(); //style_time.set_text_font(font_noto_sans_numeric_28); style_time.set_text_color(State::DEFAULT, Color::from_rgb((255, 255, 255))); - time.add_style(ObjPart::Main, style_time); + time.add_style(Part::Main, style_time); time.set_align(&mut screen, Align::Center, 0, 0); time.set_text("20:46"); time.set_width(240); diff --git a/examples/gauge.rs b/examples/gauge.rs new file mode 100644 index 0000000..76c3d2e --- /dev/null +++ b/examples/gauge.rs @@ -0,0 +1,108 @@ +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::*; +use embedded_graphics_simulator::{ + OutputSettingsBuilder, SimulatorDisplay, SimulatorEvent, Window, +}; +use lvgl::style::{Opacity, Style}; +use lvgl::widgets::{Gauge, GaugePart}; +use lvgl::{self, Align, Color, DisplayDriver, Object, Part, State, UI}; +use lvgl_sys; +use std::sync::{mpsc, Arc, Mutex}; +use std::thread::sleep; +use std::time::Duration; + +fn main() -> Result<(), String> { + let mut display: SimulatorDisplay = SimulatorDisplay::new(Size::new( + lvgl_sys::LV_HOR_RES_MAX, + lvgl_sys::LV_VER_RES_MAX, + )); + + let output_settings = OutputSettingsBuilder::new().scale(2).build(); + let mut window = Window::new("Gauge Example", &output_settings); + + let mut ui = UI::init().unwrap(); + + // Implement and register your display: + let display_driver = DisplayDriver::new(&mut display); + ui.disp_drv_register(display_driver); + + // Create screen and widgets + let mut screen = ui.scr_act(); + + let mut screen_style = Style::default(); + screen_style.set_bg_color(State::DEFAULT, Color::from_rgb((0, 0, 0))); + screen.add_style(Part::Main, screen_style); + + // Create the gauge + let mut gauge_style = Style::default(); + // Set a background color and a radius + gauge_style.set_radius(State::DEFAULT, 5); + gauge_style.set_bg_opa(State::DEFAULT, Opacity::OPA_COVER); + gauge_style.set_bg_color(State::DEFAULT, Color::from_rgb((192, 192, 192))); + // Set some paddings + gauge_style.set_pad_inner(State::DEFAULT, 20); + gauge_style.set_pad_top(State::DEFAULT, 20); + gauge_style.set_pad_left(State::DEFAULT, 5); + gauge_style.set_pad_right(State::DEFAULT, 5); + + gauge_style.set_scale_end_color(State::DEFAULT, Color::from_rgb((255, 0, 0))); + gauge_style.set_line_color(State::DEFAULT, Color::from_rgb((255, 255, 255))); + gauge_style.set_scale_grad_color(State::DEFAULT, Color::from_rgb((0, 0, 255))); + gauge_style.set_line_width(State::DEFAULT, 2); + gauge_style.set_scale_end_line_width(State::DEFAULT, 4); + gauge_style.set_scale_end_border_width(State::DEFAULT, 4); + + let mut gauge = Gauge::new(&mut screen); + gauge.add_style(GaugePart::Main, gauge_style); + 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; + 'running: loop { + threaded_ui.lock().unwrap().task_handler(); + + window.update(&display); + for event in window.events() { + match event { + SimulatorEvent::MouseButtonUp { + mouse_btn: _, + point, + } => { + println!("Clicked on: {:?}", point); + } + SimulatorEvent::Quit => break 'running, + _ => {} + } + } + + sleep(Duration::from_millis(25)); + gauge.set_value(0, i); + + if i > 99 { + i = 0; + } else { + i = i + 1; + } + } + + stop_ch.send(true).unwrap(); + tick_thr.join().unwrap(); + + Ok(()) +} diff --git a/lvgl-codegen/Cargo.toml b/lvgl-codegen/Cargo.toml index a2781c0..37456d8 100644 --- a/lvgl-codegen/Cargo.toml +++ b/lvgl-codegen/Cargo.toml @@ -3,6 +3,7 @@ name = "lvgl-codegen" version = "0.1.0" authors = ["Rafael Caricio "] edition = "2018" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/lvgl/src/lv_core/object.rs b/lvgl/src/lv_core/object.rs index 7f77380..fed8b18 100644 --- a/lvgl/src/lv_core/object.rs +++ b/lvgl/src/lv_core/object.rs @@ -94,7 +94,7 @@ pub trait Object: NativeObject { impl Object for GenericObject { type SpecialEvent = (); - type Part = ObjPart; + type Part = Part; unsafe fn from_raw(raw: ptr::NonNull) -> Self { Self { raw: raw.as_ptr() } @@ -111,10 +111,10 @@ impl Default for GenericObject { macro_rules! define_object { ($item:ident) => { - define_object!($item, event = (), part = $crate::ObjPart); + define_object!($item, event = (), part = $crate::Part); }; ($item:ident, event = $event_type:ty) => { - define_object!($item, event = $event_type, part = $crate::ObjPart); + define_object!($item, event = $event_type, part = $crate::Part); }; ($item:ident, part = $part_type:ty) => { define_object!($item, event = (), part = $part_type); @@ -189,16 +189,16 @@ impl State { } } -pub enum ObjPart { +pub enum Part { Main, All, } -impl Into for ObjPart { +impl Into for Part { fn into(self) -> u8 { match self { - ObjPart::Main => lvgl_sys::LV_OBJ_PART_MAIN as u8, - ObjPart::All => lvgl_sys::LV_OBJ_PART_ALL as u8, + Part::Main => lvgl_sys::LV_OBJ_PART_MAIN as u8, + Part::All => lvgl_sys::LV_OBJ_PART_ALL as u8, } } } diff --git a/lvgl/src/lv_core/style.rs b/lvgl/src/lv_core/style.rs index 1024062..cda80e2 100644 --- a/lvgl/src/lv_core/style.rs +++ b/lvgl/src/lv_core/style.rs @@ -29,7 +29,6 @@ impl Style { let native_state: u32 = state.get_bits(); let string = CString::new(value).unwrap(); unsafe { - lvgl_sys::LV_OPA_COVER; lvgl_sys::_lv_style_set_ptr( self.raw.as_mut(), (lvgl_sys::LV_STYLE_VALUE_STR diff --git a/lvgl/src/widgets/gauge.rs b/lvgl/src/widgets/gauge.rs new file mode 100644 index 0000000..3e21714 --- /dev/null +++ b/lvgl/src/widgets/gauge.rs @@ -0,0 +1,41 @@ +use crate::{GenericObject, NativeObject, Object}; +use core::ptr; + +define_object!(Gauge, part = GaugePart); + +impl Gauge { + pub fn new(parent: &mut C) -> Self + where + C: NativeObject, + { + unsafe { + let ptr = lvgl_sys::lv_gauge_create(parent.raw().as_mut(), ptr::null_mut()); + let raw = ptr::NonNull::new_unchecked(ptr); + let core = GenericObject::from_raw(raw); + Self { core } + } + } + + /// Set a new value on the gauge + pub fn set_value(&mut self, needle_id: u8, value: i32) { + unsafe { + lvgl_sys::lv_gauge_set_value(self.core.raw().as_mut(), needle_id, value); + } + } +} + +pub enum GaugePart { + Main, + Major, + Needle, +} + +impl From for u8 { + fn from(part: GaugePart) -> Self { + match part { + GaugePart::Main => lvgl_sys::LV_GAUGE_PART_MAIN as u8, + GaugePart::Major => lvgl_sys::LV_GAUGE_PART_MAJOR as u8, + GaugePart::Needle => lvgl_sys::LV_GAUGE_PART_NEEDLE as u8, + } + } +} diff --git a/lvgl/src/widgets/mod.rs b/lvgl/src/widgets/mod.rs index 4a01bb4..b508e52 100644 --- a/lvgl/src/widgets/mod.rs +++ b/lvgl/src/widgets/mod.rs @@ -1,7 +1,9 @@ mod bar; mod button; +mod gauge; mod label; pub use self::bar::*; pub use self::button::*; +pub use self::gauge::*; pub use self::label::*;