Make it possible to define event callbacks
This commit is contained in:
parent
2dd59d212d
commit
0349f1c77a
|
@ -45,6 +45,12 @@ fn main() -> Result<(), String> {
|
||||||
loading_lbl.set_text("Loading...");
|
loading_lbl.set_text("Loading...");
|
||||||
loading_lbl.set_align(&mut bar, Align::OutTopMid, 0, -10);
|
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();
|
let mut loading_style = Style::new();
|
||||||
loading_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
loading_style.set_text_color(Color::from_rgb((255, 255, 255)));
|
||||||
loading_lbl.set_style(loading_style);
|
loading_lbl.set_style(loading_style);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{DisplayDriver, ObjectX};
|
use crate::{DisplayDriver, Object, ObjectX};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
|
@ -1,30 +1,34 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
use core::convert::{TryFrom, TryInto};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
use core::ptr::NonNull;
|
||||||
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
use embedded_graphics::pixelcolor::{Rgb565, Rgb888};
|
||||||
use lvgl_sys;
|
use lvgl_sys;
|
||||||
|
|
||||||
|
/// Represents a native LittlevGL object
|
||||||
pub trait NativeObject {
|
pub trait NativeObject {
|
||||||
|
/// Provide common way to access to the underlying native object pointer.
|
||||||
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
|
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Stores the native LittlevGL raw pointer
|
||||||
pub struct ObjectX {
|
pub struct ObjectX {
|
||||||
raw: ptr::NonNull<lvgl_sys::lv_obj_t>,
|
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 {
|
impl NativeObject for ObjectX {
|
||||||
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
|
fn raw(&self) -> ptr::NonNull<lvgl_sys::lv_obj_t> {
|
||||||
unsafe { ptr::NonNull::new_unchecked(self.raw.as_ptr()) }
|
unsafe { ptr::NonNull::new_unchecked(self.raw.as_ptr()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A wrapper for all LittlevGL common operations on generic objects.
|
||||||
pub trait Object: NativeObject {
|
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) {
|
fn set_pos(&mut self, x: i16, y: i16) {
|
||||||
unsafe {
|
unsafe {
|
||||||
lvgl_sys::lv_obj_set_pos(
|
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 {
|
macro_rules! define_object {
|
||||||
($item:ident) => {
|
($item:ident) => {
|
||||||
|
@ -111,13 +121,84 @@ macro_rules! define_object {
|
||||||
core: $crate::support::ObjectX,
|
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 {
|
impl $crate::support::NativeObject for $item {
|
||||||
fn raw(&self) -> core::ptr::NonNull<lvgl_sys::lv_obj_t> {
|
fn raw(&self) -> core::ptr::NonNull<lvgl_sys::lv_obj_t> {
|
||||||
self.core.raw()
|
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 {
|
pub enum Align {
|
||||||
Center,
|
Center,
|
||||||
InTopLeft,
|
InTopLeft,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::support::Animation;
|
use crate::support::Animation;
|
||||||
use crate::support::{NativeObject, ObjectX};
|
use crate::support::{NativeObject, ObjectX};
|
||||||
|
use crate::Object;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use lvgl_sys;
|
use lvgl_sys;
|
||||||
|
|
||||||
|
@ -10,12 +11,12 @@ impl Bar {
|
||||||
where
|
where
|
||||||
C: NativeObject,
|
C: NativeObject,
|
||||||
{
|
{
|
||||||
let raw = unsafe {
|
unsafe {
|
||||||
let ptr = lvgl_sys::lv_bar_create(parent.raw().as_mut(), ptr::null_mut());
|
let ptr = lvgl_sys::lv_bar_create(parent.raw().as_mut(), ptr::null_mut());
|
||||||
ptr::NonNull::new_unchecked(ptr)
|
let raw = ptr::NonNull::new_unchecked(ptr);
|
||||||
};
|
let core = ObjectX::from_raw(raw);
|
||||||
let core = ObjectX::from_raw(raw);
|
Self { core }
|
||||||
Self { core }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set minimum and the maximum values of the bar
|
/// Set minimum and the maximum values of the bar
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{NativeObject, ObjectX};
|
use crate::{NativeObject, Object, ObjectX};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
define_object!(Button);
|
define_object!(Button);
|
||||||
|
@ -8,11 +8,11 @@ impl Button {
|
||||||
where
|
where
|
||||||
C: NativeObject,
|
C: NativeObject,
|
||||||
{
|
{
|
||||||
let raw = unsafe {
|
unsafe {
|
||||||
let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut());
|
let ptr = lvgl_sys::lv_btn_create(parent.raw().as_mut(), ptr::null_mut());
|
||||||
ptr::NonNull::new_unchecked(ptr)
|
let raw = ptr::NonNull::new_unchecked(ptr);
|
||||||
};
|
let core = ObjectX::from_raw(raw);
|
||||||
let core = ObjectX::from_raw(raw);
|
Self { core }
|
||||||
Self { core }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{NativeObject, ObjectX};
|
use crate::{NativeObject, Object, ObjectX};
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use cstr_core::CString;
|
use cstr_core::CString;
|
||||||
|
|
||||||
|
@ -16,12 +16,12 @@ impl Label {
|
||||||
where
|
where
|
||||||
C: NativeObject,
|
C: NativeObject,
|
||||||
{
|
{
|
||||||
let raw = unsafe {
|
unsafe {
|
||||||
let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut());
|
let ptr = lvgl_sys::lv_label_create(parent.raw().as_mut(), ptr::null_mut());
|
||||||
ptr::NonNull::new_unchecked(ptr)
|
let raw = ptr::NonNull::new_unchecked(ptr);
|
||||||
};
|
let core = ObjectX::from_raw(raw);
|
||||||
let core = ObjectX::from_raw(raw);
|
Self { core }
|
||||||
Self { core }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_text(&mut self, text: &str) {
|
pub fn set_text(&mut self, text: &str) {
|
||||||
|
|
Loading…
Reference in a new issue