Instantly share code, notes, and snippets.
Last active
May 18, 2019 01:27
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save lights0123/066a508bb7ae6d5d9a8baea86f6fc7e1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use alloc::boxed::Box; | |
use core::ptr::null_mut; | |
use cty::c_void; | |
use num_derive::FromPrimitive; | |
use num_traits::FromPrimitive; | |
use pros_sys::lv_obj_t; | |
use crate::lvgl::{LVGLObject, Object}; | |
use crate::lvgl::container::GenericContainer; | |
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, FromPrimitive)] | |
#[repr(u8)] | |
pub enum ButtonState { | |
/// Released state | |
Released, | |
/// Pressed state | |
Pressed, | |
/// Toggled released state (On state) | |
ToggleReleased, | |
/// Toggled pressed state (On pressed state) | |
TogglePressed, | |
/// Inactive state | |
Disabled, | |
} | |
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] | |
#[repr(u8)] | |
pub enum Action { | |
/// the button is released after pressing (clicked) or, when using keypad, after the key LV_GROUP_KEY_ENTER is released | |
Release, | |
/// the button is pressed | |
Press, | |
/// the button is long pressed | |
LongPress, | |
/// the button is long pressed and this action is triggered periodically | |
LongPressRepeat, | |
} | |
type LVGLButtonCallback = Fn() -> (); | |
#[derive(Default)] | |
struct Callbacks { | |
release: Option<Box<LVGLButtonCallback>>, | |
press: Option<Box<LVGLButtonCallback>>, | |
long_press: Option<Box<LVGLButtonCallback>>, | |
long_press_repeat: Option<Box<LVGLButtonCallback>>, | |
} | |
impl Callbacks { | |
fn action(&self, action: Action) -> Option<&LVGLButtonCallback> { | |
match action { | |
Action::Release => self.release.as_ref(), | |
Action::Press => self.press.as_ref(), | |
Action::LongPress => self.long_press.as_ref(), | |
Action::LongPressRepeat => self.long_press_repeat.as_ref(), | |
}.map(AsRef::as_ref) | |
} | |
fn set_action(&mut self, action: Action, cb: Box<LVGLButtonCallback>) { | |
match action { | |
Action::Release => self.release = Some(cb), | |
Action::Press => self.press = Some(cb), | |
Action::LongPress => self.long_press = Some(cb), | |
Action::LongPressRepeat => self.long_press_repeat = Some(cb), | |
} | |
} | |
fn clear_action(&mut self, action: Action) { | |
match action { | |
Action::Release => self.release = None, | |
Action::Press => self.press = None, | |
Action::LongPress => self.long_press = None, | |
Action::LongPressRepeat => self.long_press_repeat = None, | |
} | |
} | |
fn call(&self, action: Action) { | |
if let Some(cb) = self.action(action) { | |
cb(); | |
} | |
} | |
} | |
#[derive(Debug)] | |
pub struct Button { | |
obj: LVGLObject, | |
callbacks: *mut Callbacks, | |
} | |
unsafe fn generic_cb(obj: *mut lv_obj_t, cb_type: Action) -> u32 { | |
let ptr = pros_sys::lv_obj_get_free_ptr(obj) as *mut Callbacks; | |
if let Some(cb) = ptr.as_mut() { | |
cb.call(cb_type); | |
} | |
0 | |
} | |
unsafe extern "C" fn release_cb(obj: *mut lv_obj_t) -> u32 { | |
generic_cb(obj, Action::Release) | |
} | |
unsafe extern "C" fn press_cb(obj: *mut lv_obj_t) -> u32 { | |
generic_cb(obj, Action::Press) | |
} | |
unsafe extern "C" fn long_press_cb(obj: *mut lv_obj_t) -> u32 { | |
generic_cb(obj, Action::LongPress) | |
} | |
unsafe extern "C" fn long_press_repeat_cb(obj: *mut lv_obj_t) -> u32 { | |
generic_cb(obj, Action::LongPressRepeat) | |
} | |
impl Button { | |
pub fn new(parent: &impl Object) -> Self { | |
unsafe { | |
let obj = pros_sys::lv_btn_create(parent.as_obj(), null_mut()); | |
let mut btn = Button { | |
obj: LVGLObject::from_ptr(obj), | |
callbacks: Box::into_raw(Box::new(Default::default())), | |
}; | |
btn.attach_handlers(); | |
btn | |
} | |
} | |
pub fn new_as_clone(parent: &impl Object, other: &Button) -> Self { | |
unsafe { | |
let obj = pros_sys::lv_btn_create(parent.as_obj(), other.as_obj()); | |
let mut btn = Button { | |
obj: LVGLObject::from_ptr(obj), | |
callbacks: Box::into_raw(Box::new(Default::default())), | |
}; | |
btn.attach_handlers(); | |
btn | |
} | |
} | |
unsafe fn attach_handlers(&mut self) { | |
let obj = self.as_obj(); | |
pros_sys::lv_btn_set_action(obj, Action::Release as u32, Some(release_cb)); | |
pros_sys::lv_btn_set_action(obj, Action::Press as u32, Some(press_cb)); | |
pros_sys::lv_btn_set_action(obj, Action::LongPress as u32, Some(long_press_cb)); | |
pros_sys::lv_btn_set_action(obj, Action::LongPressRepeat as u32, Some(long_press_repeat_cb)); | |
pros_sys::lv_obj_set_free_ptr(obj, self.callbacks as *mut c_void) | |
} | |
pub fn set_action(&mut self, action: Action, cb: impl Fn() -> () + 'static) { | |
if let Some(callbacks) = unsafe { self.callbacks.as_mut() } { | |
callbacks.set_action(action, Box::new(cb)); | |
} | |
} | |
pub fn clear_action(&mut self, action: Action) { | |
if let Some(callbacks) = unsafe { self.callbacks.as_mut() } { | |
callbacks.clear_action(action); | |
} | |
} | |
pub fn set_toggle_mode(&mut self, toggle: bool) { | |
unsafe { pros_sys::lv_btn_set_toggle(self.as_obj(), toggle); } | |
} | |
pub fn toggle_mode(&self) -> bool { | |
unsafe { pros_sys::lv_btn_get_toggle(self.as_obj()) } | |
} | |
pub fn toggle(&self) { | |
unsafe { pros_sys::lv_btn_toggle(self.as_obj()) } | |
} | |
pub fn set_state(&self, state: ButtonState) { | |
unsafe { pros_sys::lv_btn_set_state(self.as_obj(), state as u32) } | |
} | |
pub fn state(&self) -> ButtonState { | |
FromPrimitive::from_u32(unsafe { pros_sys::lv_btn_get_state(self.as_obj()) }).unwrap_or(ButtonState::Disabled) | |
} | |
pub fn remove(self) { | |
self.obj.remove(); | |
if !self.callbacks.is_null() { unsafe { Box::from_raw(self.callbacks); } } | |
} | |
} | |
impl Object for Button { | |
fn as_obj(&self) -> *mut lv_obj_t { | |
self.obj.obj | |
} | |
} | |
impl GenericContainer for Button {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment