Skip to content

Instantly share code, notes, and snippets.

@lights0123
Last active May 18, 2019 01:27
Show Gist options
  • Save lights0123/066a508bb7ae6d5d9a8baea86f6fc7e1 to your computer and use it in GitHub Desktop.
Save lights0123/066a508bb7ae6d5d9a8baea86f6fc7e1 to your computer and use it in GitHub Desktop.
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