Make it possible to define event callbacks

This commit is contained in:
Rafael Caricio 2020-05-31 18:48:17 +02:00
parent 2dd59d212d
commit 0349f1c77a
6 changed files with 208 additions and 26 deletions

View file

@ -45,6 +45,12 @@ fn main() -> Result<(), String> {
loading_lbl.set_text("Loading...");
loading_lbl.set_align(&mut bar, Align::OutTopMid, 0, -10);
loading_lbl.on_event(|mut this, event| {
if let lvgl::Event::Clicked = event {
this.set_text("Clicked!");
}
});
let mut loading_style = Style::new();
loading_style.set_text_color(Color::from_rgb((255, 255, 255)));
loading_lbl.set_style(loading_style);

View file

@ -1,4 +1,4 @@
use crate::{DisplayDriver, ObjectX};
use crate::{DisplayDriver, Object, ObjectX};
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::ptr;

View file

@ -1,30 +1,34 @@
use alloc::boxed::Box;
use core::convert::{TryFrom, TryInto};
use core::mem;
use core::ptr;
use core::ptr::NonNull;
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
use lvgl_sys;
/// Represents a native LittlevGL object
pub trait NativeObject {
/// Provide common way to access to the underlying native object pointer.
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
}
/// Stores the native LittlevGL raw pointer
pub struct ObjectX {
raw: ptr::NonNull<lvgl_sys::lv_obj_t>,
}
impl ObjectX {
pub(crate) fn from_raw(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self { raw }
}
}
impl NativeObject for ObjectX {
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
unsafe { ptr::NonNull::new_unchecked(self.raw.as_ptr()) }
}
}
/// A wrapper for all LittlevGL common operations on generic objects.
pub trait Object: NativeObject {
type SpecialEvent;
unsafe fn from_raw(raw_pointer: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self;
fn set_pos(&mut self, x: i16, y: i16) {
unsafe {
lvgl_sys::lv_obj_set_pos(
@ -103,7 +107,13 @@ pub trait Object: NativeObject {
}
}
impl Object for ObjectX {}
impl Object for ObjectX {
type SpecialEvent = ();
unsafe fn from_raw(raw: ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self { raw }
}
}
macro_rules! define_object {
($item:ident) => {
@ -111,13 +121,84 @@ macro_rules! define_object {
core: $crate::support::ObjectX,
}
impl $item {
pub fn on_event<F>(&mut self, f: F)
where
F: FnMut(
alloc::boxed::Box<Self>,
$crate::support::Event<<Self as $crate::support::Object>::SpecialEvent>,
),
{
unsafe {
let mut raw = self.raw();
let obj = raw.as_mut();
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>),
);
}
}
}
impl $crate::support::NativeObject for $item {
fn raw(&self) -> core::ptr::NonNull<lvgl_sys::lv_obj_t> {
self.core.raw()
}
}
impl $crate::support::Object for $item {}
impl $crate::support::Object for $item {
type SpecialEvent = ();
unsafe fn from_raw(raw_pointer: core::ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self {
core: $crate::support::ObjectX::from_raw(raw_pointer),
}
}
}
};
($item:ident, $event_type:ident) => {
pub struct $item {
core: $crate::support::ObjectX,
}
impl $item {
pub fn on_event<F, S>(&mut self, f: F)
where
F: FnMut(
Box<Self>,
$crate::support::Event<<Self as $crate::support::Object>::SpecialEvent>,
),
{
unsafe {
let mut raw = self.raw();
let obj = raw.as_mut();
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>),
);
}
}
}
impl $crate::support::NativeObject for $item {
fn raw(&self) -> core::ptr::NonNull<lvgl_sys::lv_obj_t> {
self.core.raw()
}
}
impl $crate::support::Object for $item {
type SpecialEvent = $event_type;
unsafe fn from_raw(raw_pointer: core::ptr::NonNull<lvgl_sys::lv_obj_t>) -> Self {
Self {
core: $crate::support::ObjectX::from_raw(raw_pointer),
}
}
}
};
}
@ -225,6 +306,100 @@ impl From<Color> for Rgb565 {
}
}
/// Events are triggered in LittlevGL when something happens which might be interesting to
/// the user, e.g. if an object:
/// - is clicked
/// - is dragged
/// - its value has changed, etc.
///
/// All objects (such as Buttons/Labels/Sliders etc.) receive these generic events
/// regardless of their type.
pub enum Event<T> {
/// The object has been pressed
Pressed,
/// The object is being pressed (sent continuously while pressing)
Pressing,
/// The input device is still being pressed but is no longer on the object
PressLost,
/// Released before `long_press_time` config time. Not called if dragged.
ShortClicked,
/// Called on release if not dragged (regardless to long press)
Clicked,
/// Pressing for `long_press_time` config time. Not called if dragged.
LongPressed,
/// Called after `long_press_time` config in every `long_press_rep_time` ms. Not
/// called if dragged.
LongPressedRepeat,
/// Called in every case when the object has been released even if it was dragged. Not called
/// if slid from the object while pressing and released outside of the object. In this
/// case, `Event<_>::PressLost` is sent.
Released,
/// Pointer-like input devices events (E.g. mouse or touchpad)
Pointer(PointerEvent),
/// Special event for the object type
Special(T),
}
impl<S> TryFrom<lvgl_sys::lv_event_t> for Event<S> {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value as u32 {
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(())
// }
// }
}
}
}
/// These events are sent only by pointer-like input devices (E.g. mouse or touchpad)
pub enum PointerEvent {
DragBegin,
DragEnd,
DragThrowBegin,
}
pub(crate) unsafe extern "C" fn event_callback<T, F>(
obj: *mut lvgl_sys::lv_obj_t,
event: lvgl_sys::lv_event_t,
) where
T: Object + Sized,
F: FnMut(Box<T>, Event<T::SpecialEvent>),
{
// convert the lv_event_t to lvgl-rs Event type
if let Ok(event) = event.try_into() {
if let Some(obj_ptr) = NonNull::new(obj) {
let object = Box::new(T::from_raw(obj_ptr));
// get the pointer from the Rust callback closure FnMut provided by users
let user_closure = &mut *((*obj).user_data as *mut F);
// call user callback closure
user_closure(object, event);
}
}
}
pub enum Align {
Center,
InTopLeft,

View file

@ -1,5 +1,6 @@
use crate::support::Animation;
use crate::support::{NativeObject, ObjectX};
use crate::Object;
use core::ptr;
use lvgl_sys;
@ -10,12 +11,12 @@ impl Bar {
where
C: NativeObject,
{
let raw = unsafe {
unsafe {
let ptr = lvgl_sys::lv_bar_create(parent.raw().as_mut(), ptr::null_mut());
ptr::NonNull::new_unchecked(ptr)
};
let core = ObjectX::from_raw(raw);
Self { core }
let raw = ptr::NonNull::new_unchecked(ptr);
let core = ObjectX::from_raw(raw);
Self { core }
}
}
/// Set minimum and the maximum values of the bar

View file

@ -1,4 +1,4 @@
use crate::{NativeObject, ObjectX};
use crate::{NativeObject, Object, ObjectX};
use core::ptr;
define_object!(Button);
@ -8,11 +8,11 @@ impl Button {
where
C: NativeObject,
{
let raw = unsafe {
unsafe {
let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut());
ptr::NonNull::new_unchecked(ptr)
};
let core = ObjectX::from_raw(raw);
Self { core }
let raw = ptr::NonNull::new_unchecked(ptr);
let core = ObjectX::from_raw(raw);
Self { core }
}
}
}

View file

@ -1,4 +1,4 @@
use crate::{NativeObject, ObjectX};
use crate::{NativeObject, Object, ObjectX};
use core::ptr;
use cstr_core::CString;
@ -16,12 +16,12 @@ impl Label {
where
C: NativeObject,
{
let raw = unsafe {
unsafe {
let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut());
ptr::NonNull::new_unchecked(ptr)
};
let core = ObjectX::from_raw(raw);
Self { core }
let raw = ptr::NonNull::new_unchecked(ptr);
let core = ObjectX::from_raw(raw);
Self { core }
}
}
pub fn set_text(&mut self, text: &str) {