/** * @file lv_preload.c * */ /********************* * INCLUDES *********************/ #include "lv_spinner.h" #if LV_USE_SPINNER != 0 #include "../lv_core/lv_debug.h" #include "../lv_misc/lv_math.h" #include "../lv_draw/lv_draw_rect.h" #include "../lv_draw/lv_draw_arc.h" #include "../lv_themes/lv_theme.h" /********************* * DEFINES *********************/ #define LV_OBJX_NAME "lv_spinner" #ifndef LV_SPINNER_DEF_ARC_LENGTH #define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/ #endif #ifndef LV_SPINNER_DEF_SPIN_TIME #define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/ #endif #ifndef LV_SPINNER_DEF_ANIM #define LV_SPINNER_DEF_ANIM LV_SPINNER_TYPE_SPINNING_ARC /*animation type*/ #endif /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static lv_res_t lv_spinner_signal(lv_obj_t * preload, lv_signal_t sign, void * param); /********************** * STATIC VARIABLES **********************/ static lv_signal_cb_t ancestor_signal; static lv_design_cb_t ancestor_design; /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ /** * Create a pre loader object * @param par pointer to an object, it will be the parent of the new pre loader * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from * it * @return pointer to the created pre loader */ lv_obj_t * lv_spinner_create(lv_obj_t * par, const lv_obj_t * copy) { LV_LOG_TRACE("preload create started"); /*Create the ancestor of pre loader*/ lv_obj_t * preload = lv_arc_create(par, copy); LV_ASSERT_MEM(preload); if(preload == NULL) return NULL; /*Allocate the pre loader type specific extended data*/ lv_spinner_ext_t * ext = lv_obj_allocate_ext_attr(preload, sizeof(lv_spinner_ext_t)); LV_ASSERT_MEM(ext); if(ext == NULL) { lv_obj_del(preload); return NULL; } if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(preload); if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(preload); /*Initialize the allocated 'ext' */ ext->arc_length = LV_SPINNER_DEF_ARC_LENGTH; ext->anim_type = LV_SPINNER_DEF_ANIM; ext->anim_dir = LV_SPINNER_DIR_FORWARD; ext->time = LV_SPINNER_DEF_SPIN_TIME; /*The signal and design functions are not copied so set them here*/ lv_obj_set_signal_cb(preload, lv_spinner_signal); /*Init the new spinner spinner*/ if(copy == NULL) { ext->arc.bg_angle_start = 0; ext->arc.bg_angle_end = 360; lv_obj_set_size(preload, LV_DPI, LV_DPI); lv_theme_apply(preload, LV_THEME_SPINNER); } /*Copy an existing spinner*/ else { lv_spinner_ext_t * copy_ext = lv_obj_get_ext_attr(copy); ext->arc_length = copy_ext->arc_length; ext->time = copy_ext->time; ext->anim_dir = copy_ext->anim_dir; /*Refresh the style with new signal function*/ lv_obj_refresh_style(preload); } lv_spinner_set_type(preload, ext->anim_type); LV_LOG_INFO("preload created"); return preload; } /*====================== * Add/remove functions *=====================*/ /** * Set the length of the spinning arc in degrees * @param preload pointer to a preload object * @param deg length of the arc */ void lv_spinner_set_arc_length(lv_obj_t * preload, lv_anim_value_t deg) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); ext->arc_length = deg; } /** * Set the spin time of the arc * @param preload pointer to a preload object * @param time time of one round in milliseconds */ void lv_spinner_set_spin_time(lv_obj_t * preload, uint16_t time) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); ext->time = time; lv_spinner_set_type(preload, ext->anim_type); } /*===================== * Setter functions *====================*/ /** * Set the animation type of a preloadeer. * @param preload pointer to pre loader object * @param type animation type of the preload * */ void lv_spinner_set_type(lv_obj_t * preload, lv_spinner_type_t type) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); /*delete previous animation*/ lv_anim_del(preload, NULL); switch(type) { case LV_SPINNER_TYPE_FILLSPIN_ARC: { ext->anim_type = LV_SPINNER_TYPE_FILLSPIN_ARC; lv_anim_t a; a.var = preload; if(ext->anim_dir == LV_SPINNER_DIR_FORWARD) { /* Clockwise */ a.start = 0; a.end = 360; } else { a.start = 360; a.end = 0; } a.exec_cb = (lv_anim_exec_xcb_t)lv_spinner_spinner_anim; a.path_cb = lv_anim_path_ease_in_out; a.ready_cb = NULL; a.act_time = 0; a.time = ext->time; a.playback = 0; a.playback_pause = 0; a.repeat = 1; a.repeat_pause = 0; lv_anim_create(&a); lv_anim_t b; b.var = preload; if(ext->anim_dir == LV_SPINNER_DIR_FORWARD) { /* Clockwise */ b.start = ext->arc_length; b.end = 360 - ext->arc_length; } else { b.start = 360 - ext->arc_length; b.end = ext->arc_length; } b.exec_cb = (lv_anim_exec_xcb_t)lv_spinner_set_arc_length; b.path_cb = lv_anim_path_ease_in_out; b.ready_cb = NULL; b.act_time = 0; b.time = ext->time; b.playback = 1; b.playback_pause = 0; b.repeat = 1; b.repeat_pause = 0; lv_anim_create(&b); break; } case LV_SPINNER_TYPE_CONSTANT_ARC: case LV_SPINNER_TYPE_SPINNING_ARC: default: { ext->anim_type = type; lv_anim_t a; a.var = preload; if(ext->anim_dir == LV_SPINNER_DIR_FORWARD) { /* Clockwise */ a.start = 0; a.end = 360; } else { a.start = 360; a.end = 0; } a.exec_cb = (lv_anim_exec_xcb_t)lv_spinner_spinner_anim; a.path_cb = (LV_SPINNER_TYPE_CONSTANT_ARC == type ? lv_anim_path_linear : lv_anim_path_ease_in_out); a.ready_cb = NULL; a.act_time = 0; a.time = ext->time; a.playback = 0; a.playback_pause = 0; a.repeat = 1; a.repeat_pause = 0; lv_anim_create(&a); break; } } } void lv_spinner_set_dir(lv_obj_t * preload, lv_spinner_dir_t dir) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); ext->anim_dir = dir; lv_spinner_set_type(preload, ext->anim_type); } /*===================== * Getter functions *====================*/ /** * Get the arc length [degree] of the a pre loader * @param preload pointer to a pre loader object */ lv_anim_value_t lv_spinner_get_arc_length(const lv_obj_t * preload) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); return ext->arc_length; } /** * Get the spin time of the arc * @param preload pointer to a pre loader object [milliseconds] */ uint16_t lv_spinner_get_spin_time(const lv_obj_t * preload) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); return ext->time; } /** * Get the animation type of a preloadeer. * @param preload pointer to pre loader object * @return animation type * */ lv_spinner_type_t lv_spinner_get_type(lv_obj_t * preload) { LV_ASSERT_OBJ(preload, LV_OBJX_NAME); lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); return ext->anim_type; } lv_spinner_dir_t lv_spinner_get_dir(lv_obj_t * preload) { lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); return ext->anim_dir; } /*===================== * Other functions *====================*/ /** * Animator function (exec_cb) to rotate the arc of spinner. * @param ptr pointer to spinner * @param val the current desired value [0..360] */ void lv_spinner_spinner_anim(void * ptr, lv_anim_value_t val) { lv_obj_t * preload = ptr; lv_spinner_ext_t * ext = lv_obj_get_ext_attr(preload); int16_t angle_start = val - ext->arc_length / 2 - 90; if(angle_start < 0) angle_start += 360; int16_t angle_end = angle_start + ext->arc_length; angle_start = angle_start % 360; angle_end = angle_end % 360; lv_arc_set_angles(preload, angle_start, angle_end); } /********************** * STATIC FUNCTIONS **********************/ /** * Signal function of the pre loader * @param preload pointer to a pre loader object * @param sign a signal type from lv_signal_t enum * @param param pointer to a signal specific variable * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted */ static lv_res_t lv_spinner_signal(lv_obj_t * preload, lv_signal_t sign, void * param) { lv_res_t res; /* Include the ancient signal function */ res = ancestor_signal(preload, sign, param); if(res != LV_RES_OK) return res; if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); if(sign == LV_SIGNAL_CLEANUP) { /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ } return res; } #endif