diff --git a/src/lv_misc/lv_anim.c b/src/lv_misc/lv_anim.c index 55e155109..cb46da69e 100644 --- a/src/lv_misc/lv_anim.c +++ b/src/lv_misc/lv_anim.c @@ -106,7 +106,6 @@ void lv_anim_start(lv_anim_t * a) if(new_anim == NULL) return; /*Initialize the animation descriptor*/ - a->playback_now = 0; a->time_orig = a->time; memcpy(new_anim, a, sizeof(lv_anim_t)); @@ -153,6 +152,25 @@ bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb) return del; } +/** + * Get the animation of a variable and its `exec_cb`. + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', + * or NULL to delete all the animations of 'var' + * @return pointer to the animation. + */ +lv_anim_t * lv_anim_get(void * var, lv_anim_exec_xcb_t exec_cb) +{ + lv_anim_t * a; + LV_LL_READ(LV_GC_ROOT(_lv_anim_ll), a) { + if(a->var == var && a->exec_cb == exec_cb) { + return a; + } + } + + return NULL; +} + /** * Get the number of currently running animations * @return the number of running animations diff --git a/src/lv_misc/lv_anim.h b/src/lv_misc/lv_anim.h index 6b45652da..c9583810e 100644 --- a/src/lv_misc/lv_anim.h +++ b/src/lv_misc/lv_anim.h @@ -279,6 +279,16 @@ static inline int32_t lv_anim_get_delay(lv_anim_t * a) */ bool lv_anim_del(void * var, lv_anim_exec_xcb_t exec_cb); + +/** + * Get the animation of a variable and its `exec_cb`. + * @param var pointer to variable + * @param exec_cb a function pointer which is animating 'var', + * or NULL to delete all the animations of 'var' + * @return pointer to the animation. + */ +lv_anim_t * lv_anim_get(void * var, lv_anim_exec_xcb_t exec_cb); + /** * Delete an animation by getting the animated variable from `a`. * Only animations with `exec_cb` will be deleted. diff --git a/src/lv_misc/lv_utils.c b/src/lv_misc/lv_utils.c index 1939af6f9..c8f44ec87 100644 --- a/src/lv_misc/lv_utils.c +++ b/src/lv_misc/lv_utils.c @@ -10,6 +10,8 @@ #include "lv_utils.h" #include "lv_math.h" +#include "lv_printf.h" +#include "lv_txt.h" /********************* * DEFINES @@ -26,6 +28,7 @@ /********************** * STATIC VARIABLES **********************/ +static char decimal_separator[2] = "."; /********************** * MACROS @@ -72,6 +75,31 @@ char * lv_utils_num_to_str(int32_t num, char * buf) return buf; } +/** + * Convert a fixed point number to string + * @param num a number + * @param decimals number of digits after decimal point + * @param buf pointer to a `char` buffer + * @param bufsize length of buffer + * @return same as `buf` (just for convenience) + */ +char * lv_utils_num_to_str_fixed(int32_t num, int32_t decimals, char * buf, size_t bufsize) +{ + lv_snprintf(buf, bufsize, "%0*d", decimals+1, num); + if(decimals > 0) + lv_txt_ins(buf, strlen(buf) - decimals, decimal_separator); + return buf; +} + +/** + * Set the decimal separator character used by lv_utils_num_to_str_fixed + * @param separator the decimal separator char + */ +void lv_utils_set_decimal_separator(char separator) +{ + decimal_separator[0] = separator; +} + /** Searches base[0] to base[n - 1] for an item that matches *key. * * @note The function cmp must return negative if its first diff --git a/src/lv_misc/lv_utils.h b/src/lv_misc/lv_utils.h index 6eed79501..e2a61d6ee 100644 --- a/src/lv_misc/lv_utils.h +++ b/src/lv_misc/lv_utils.h @@ -35,6 +35,22 @@ extern "C" { */ char * lv_utils_num_to_str(int32_t num, char * buf); +/** + * Convert a fixed point number to string + * @param num a number + * @param decimals number of digits after decimal point + * @param buf pointer to a `char` buffer + * @param bufsize length of buffer + * @return same as `buf` (just for convenience) + */ +char * lv_utils_num_to_str_fixed(int32_t num, int32_t decimals, char * buf, size_t bufsize); + +/** + * Set the decimal separator character used by lv_utils_num_to_str_fixed + * @param separator the decimal separator char + */ +void lv_utils_set_decimal_separator(char separator); + /** Searches base[0] to base[n - 1] for an item that matches *key. * * @note The function cmp must return negative if its first diff --git a/src/lv_widgets/lv_dropdown.c b/src/lv_widgets/lv_dropdown.c index 99194fc94..48cd12936 100644 --- a/src/lv_widgets/lv_dropdown.c +++ b/src/lv_widgets/lv_dropdown.c @@ -332,6 +332,8 @@ void lv_dropdown_add_option(lv_obj_t * ddlist, const char * option, uint16_t pos lv_mem_buf_release(ins_buf); ext->option_cnt++; + + lv_obj_invalidate(ddlist); } /** diff --git a/src/lv_widgets/lv_gauge.c b/src/lv_widgets/lv_gauge.c index 2ecbb4494..746a2aad5 100644 --- a/src/lv_widgets/lv_gauge.c +++ b/src/lv_widgets/lv_gauge.c @@ -84,6 +84,7 @@ lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy) ext->values = NULL; ext->needle_colors = NULL; ext->label_count = LV_GAUGE_DEF_LABEL_COUNT; + ext->format_cb = NULL; ext->needle_img = 0; ext->needle_img_pivot.x = 0; @@ -118,6 +119,7 @@ lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy) ext->values[i] = copy_ext->values[i]; } ext->label_count = copy_ext->label_count; + ext->format_cb = copy_ext->format_cb; /*Refresh the style with new signal function*/ lv_obj_refresh_style(new_gauge, LV_STYLE_PROP_ALL); @@ -173,7 +175,7 @@ void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_co * @param needle_id the id of the needle * @param value the new value */ -void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value) +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int32_t value) { LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); @@ -237,6 +239,20 @@ void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivo lv_obj_invalidate(gauge); } +/** + * Assign a function to format gauge values + * @param gauge pointer to a gauge object + * @param format_cb pointer to function of lv_gauge_format_cb_t + */ +void lv_gauge_set_formatter_cb(lv_obj_t * gauge, lv_gauge_format_cb_t format_cb) +{ + LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); + + lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge); + + ext->format_cb = format_cb; +} + /*===================== * Getter functions *====================*/ @@ -247,7 +263,7 @@ void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivo * @param needle the id of the needle * @return the value of the needle [min,max] */ -int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle) +int32_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle) { LV_ASSERT_OBJ(gauge, LV_OBJX_NAME); @@ -454,8 +470,8 @@ static void lv_gauge_draw_labels(lv_obj_t * gauge, const lv_area_t * mask) int16_t scale_angle = lv_linemeter_get_scale_angle(gauge); uint16_t label_num = ext->label_count; int16_t angle_ofs = 90 + (360 - scale_angle) / 2; - int16_t min = lv_gauge_get_min_value(gauge); - int16_t max = lv_gauge_get_max_value(gauge); + int32_t min = lv_gauge_get_min_value(gauge); + int32_t max = lv_gauge_get_max_value(gauge); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); @@ -472,10 +488,13 @@ static void lv_gauge_draw_labels(lv_obj_t * gauge, const lv_area_t * mask) lv_coord_t x = (int32_t)((int32_t)lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX; x += x_ofs; - int16_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1); + int32_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1); scale_act += min; - lv_utils_num_to_str(scale_act, scale_txt); - + if(ext->format_cb == NULL) + lv_utils_num_to_str(scale_act, scale_txt); + else + ext->format_cb(gauge, scale_txt, sizeof(scale_txt), scale_act); + lv_area_t label_cord; lv_point_t label_size; lv_txt_get_size(&label_size, scale_txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, diff --git a/src/lv_widgets/lv_gauge.h b/src/lv_widgets/lv_gauge.h index 436fefb0b..1c26f4078 100644 --- a/src/lv_widgets/lv_gauge.h +++ b/src/lv_widgets/lv_gauge.h @@ -35,11 +35,13 @@ extern "C" { * TYPEDEFS **********************/ +typedef void (*lv_gauge_format_cb_t)(lv_obj_t * gauge, char buf[], int bufsize, int32_t value); + /*Data of gauge*/ typedef struct { lv_linemeter_ext_t lmeter; /*Ext. of ancestor*/ /*New data for this type */ - int16_t * values; /*Array of the set values (for needles) */ + int32_t * values; /*Array of the set values (for needles) */ const lv_color_t * needle_colors; /*Color of the needles (lv_color_t my_colors[needle_num])*/ const void * needle_img; lv_point_t needle_img_pivot; @@ -47,6 +49,7 @@ typedef struct { lv_style_list_t style_strong; uint8_t needle_count; /*Number of needles*/ uint8_t label_count; /*Number of labels on the scale*/ + lv_gauge_format_cb_t format_cb; } lv_gauge_ext_t; /*Styles*/ @@ -89,7 +92,7 @@ void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_co * @param needle_id the id of the needle * @param value the new value */ -void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); +void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int32_t value); /** * Set minimum and the maximum values of a gauge @@ -97,7 +100,7 @@ void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int16_t value); * @param min minimum value * @param max maximum value */ -static inline void lv_gauge_set_range(lv_obj_t * gauge, int16_t min, int16_t max) +static inline void lv_gauge_set_range(lv_obj_t * gauge, int32_t min, int32_t max) { lv_linemeter_set_range(gauge, min, max); } @@ -107,7 +110,7 @@ static inline void lv_gauge_set_range(lv_obj_t * gauge, int16_t min, int16_t max * @param gauge pointer to a gauge object * @param value the critical value */ -static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int16_t value) +static inline void lv_gauge_set_critical_value(lv_obj_t * gauge, int32_t value) { lv_linemeter_set_value(gauge, value); } @@ -144,6 +147,13 @@ static inline void lv_gauge_set_angle_offset(lv_obj_t * gauge, uint16_t angle) */ void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y); +/** + * Assign a function to format gauge values + * @param gauge pointer to a gauge object + * @param format_cb pointer to function of lv_gauge_format_cb_t + */ +void lv_gauge_set_formatter_cb(lv_obj_t * gauge, lv_gauge_format_cb_t format_cb); + /*===================== * Getter functions *====================*/ @@ -154,7 +164,7 @@ void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivo * @param needle the id of the needle * @return the value of the needle [min,max] */ -int16_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); +int32_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle); /** * Get the count of needles on a gauge @@ -168,7 +178,7 @@ uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge); * @param gauge pointer to a gauge object * @return the minimum value of the gauge */ -static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) +static inline int32_t lv_gauge_get_min_value(const lv_obj_t * lmeter) { return lv_linemeter_get_min_value(lmeter); } @@ -178,7 +188,7 @@ static inline int16_t lv_gauge_get_min_value(const lv_obj_t * lmeter) * @param gauge pointer to a gauge object * @return the maximum value of the gauge */ -static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) +static inline int32_t lv_gauge_get_max_value(const lv_obj_t * lmeter) { return lv_linemeter_get_max_value(lmeter); } @@ -188,7 +198,7 @@ static inline int16_t lv_gauge_get_max_value(const lv_obj_t * lmeter) * @param gauge pointer to a gauge object * @return the critical value */ -static inline int16_t lv_gauge_get_critical_value(const lv_obj_t * gauge) +static inline int32_t lv_gauge_get_critical_value(const lv_obj_t * gauge) { return lv_linemeter_get_value(gauge); } diff --git a/src/lv_widgets/lv_label.c b/src/lv_widgets/lv_label.c index 0b9775701..e03528514 100644 --- a/src/lv_widgets/lv_label.c +++ b/src/lv_widgets/lv_label.c @@ -1220,6 +1220,27 @@ static void lv_label_refr_text(lv_obj_t * label) lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_label_set_offset_x); lv_anim_set_time(&a, lv_anim_speed_to_time(ext->anim_speed, a.start, a.end)); lv_anim_set_playback_time(&a, a.time); + + lv_anim_t * anim_cur = lv_anim_get(label, (lv_anim_exec_xcb_t)lv_label_set_offset_x); + uint32_t act_time = 0; + bool playback_now = false; + if(anim_cur) { + act_time = anim_cur->act_time; + playback_now = anim_cur->playback_now; + } + if(act_time < a.time) { + a.act_time = act_time; /*To keep the old position*/ + a.early_apply = 0; + if(playback_now) { + a.playback_now = 1; + /*Swap the start and end values*/ + int32_t tmp; + tmp = a.start; + a.start = a.end; + a.end = tmp; + } + } + lv_anim_start(&a); hor_anim = true; } @@ -1234,6 +1255,27 @@ static void lv_label_refr_text(lv_obj_t * label) lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_label_set_offset_y); lv_anim_set_time(&a, lv_anim_speed_to_time(ext->anim_speed, a.start, a.end)); lv_anim_set_playback_time(&a, a.time); + + lv_anim_t * anim_cur = lv_anim_get(label, (lv_anim_exec_xcb_t)lv_label_set_offset_y); + uint32_t act_time = 0; + bool playback_now = false; + if(anim_cur) { + act_time = anim_cur->act_time; + playback_now = anim_cur->playback_now; + } + if(act_time < a.time) { + a.act_time = act_time; /*To keep the old position*/ + a.early_apply = 0; + if(playback_now) { + a.playback_now = 1; + /*Swap the start and end values*/ + int32_t tmp; + tmp = a.start; + a.start = a.end; + a.end = tmp; + } + } + lv_anim_start(&a); } else { @@ -1250,16 +1292,20 @@ static void lv_label_refr_text(lv_obj_t * label) lv_anim_init(&a); lv_anim_set_var(&a, label); lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINIT); - uint32_t delay = (((lv_font_get_glyph_width(font, ' ', ' ') + letter_space) * 1000) / - ext->anim_speed) * - LV_LABEL_WAIT_CHAR_COUNT; - lv_anim_set_delay(&a, delay); bool hor_anim = false; if(size.x > lv_area_get_width(&txt_coords)) { lv_anim_set_values(&a, 0, -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT); lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_label_set_offset_x); lv_anim_set_time(&a, lv_anim_speed_to_time(ext->anim_speed, a.start, a.end)); + + lv_anim_t * anim_cur = lv_anim_get(label, (lv_anim_exec_xcb_t)lv_label_set_offset_x); + uint32_t act_time = anim_cur ? anim_cur->act_time : 0; + if(act_time < a.time) { + a.act_time = act_time; /*To keep the old position*/ + a.early_apply = 0; + } + lv_anim_start(&a); hor_anim = true; } @@ -1273,6 +1319,14 @@ static void lv_label_refr_text(lv_obj_t * label) lv_anim_set_values(&a, 0, -size.y - (lv_font_get_line_height(font))); lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_label_set_offset_y); lv_anim_set_time(&a, lv_anim_speed_to_time(ext->anim_speed, a.start, a.end)); + + lv_anim_t * anim_cur = lv_anim_get(label, (lv_anim_exec_xcb_t)lv_label_set_offset_y); + uint32_t act_time = anim_cur ? anim_cur->act_time : 0; + if(act_time < a.time) { + a.act_time = act_time; /*To keep the old position*/ + a.early_apply = 0; + } + lv_anim_start(&a); } else { diff --git a/src/lv_widgets/lv_linemeter.c b/src/lv_widgets/lv_linemeter.c index 95c47cbde..4c543618c 100644 --- a/src/lv_widgets/lv_linemeter.c +++ b/src/lv_widgets/lv_linemeter.c @@ -113,7 +113,7 @@ lv_obj_t * lv_linemeter_create(lv_obj_t * par, const lv_obj_t * copy) * @param lmeter pointer to a line meter object * @param value new value */ -void lv_linemeter_set_value(lv_obj_t * lmeter, int16_t value) +void lv_linemeter_set_value(lv_obj_t * lmeter, int32_t value) { LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME); @@ -131,7 +131,7 @@ void lv_linemeter_set_value(lv_obj_t * lmeter, int16_t value) * @param min minimum value * @param max maximum value */ -void lv_linemeter_set_range(lv_obj_t * lmeter, int16_t min, int16_t max) +void lv_linemeter_set_range(lv_obj_t * lmeter, int32_t min, int32_t max) { LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME); @@ -194,7 +194,7 @@ void lv_linemeter_set_angle_offset(lv_obj_t * lmeter, uint16_t angle) * @param lmeter pointer to a line meter object * @return the value of the line meter */ -int16_t lv_linemeter_get_value(const lv_obj_t * lmeter) +int32_t lv_linemeter_get_value(const lv_obj_t * lmeter) { LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME); @@ -207,7 +207,7 @@ int16_t lv_linemeter_get_value(const lv_obj_t * lmeter) * @param lmeter pointer to a line meter object * @return the minimum value of the line meter */ -int16_t lv_linemeter_get_min_value(const lv_obj_t * lmeter) +int32_t lv_linemeter_get_min_value(const lv_obj_t * lmeter) { LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME); @@ -220,7 +220,7 @@ int16_t lv_linemeter_get_min_value(const lv_obj_t * lmeter) * @param lmeter pointer to a line meter object * @return the maximum value of the line meter */ -int16_t lv_linemeter_get_max_value(const lv_obj_t * lmeter) +int32_t lv_linemeter_get_max_value(const lv_obj_t * lmeter) { LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME); diff --git a/src/lv_widgets/lv_linemeter.h b/src/lv_widgets/lv_linemeter.h index 27691ea38..592b5adbd 100644 --- a/src/lv_widgets/lv_linemeter.h +++ b/src/lv_widgets/lv_linemeter.h @@ -33,9 +33,9 @@ typedef struct { uint16_t scale_angle; /*Angle of the scale in deg. (0..360)*/ uint16_t angle_ofs; uint16_t line_cnt; /*Count of lines */ - int16_t cur_value; - int16_t min_value; - int16_t max_value; + int32_t cur_value; + int32_t min_value; + int32_t max_value; } lv_linemeter_ext_t; /*Styles*/ @@ -68,7 +68,7 @@ lv_obj_t * lv_linemeter_create(lv_obj_t * par, const lv_obj_t * copy); * @param lmeter pointer to a line meter object * @param value new value */ -void lv_linemeter_set_value(lv_obj_t * lmeter, int16_t value); +void lv_linemeter_set_value(lv_obj_t * lmeter, int32_t value); /** * Set minimum and the maximum values of a line meter @@ -76,7 +76,7 @@ void lv_linemeter_set_value(lv_obj_t * lmeter, int16_t value); * @param min minimum value * @param max maximum value */ -void lv_linemeter_set_range(lv_obj_t * lmeter, int16_t min, int16_t max); +void lv_linemeter_set_range(lv_obj_t * lmeter, int32_t min, int32_t max); /** * Set the scale settings of a line meter @@ -102,21 +102,21 @@ void lv_linemeter_set_angle_offset(lv_obj_t * lmeter, uint16_t angle); * @param lmeter pointer to a line meter object * @return the value of the line meter */ -int16_t lv_linemeter_get_value(const lv_obj_t * lmeter); +int32_t lv_linemeter_get_value(const lv_obj_t * lmeter); /** * Get the minimum value of a line meter * @param lmeter pointer to a line meter object * @return the minimum value of the line meter */ -int16_t lv_linemeter_get_min_value(const lv_obj_t * lmeter); +int32_t lv_linemeter_get_min_value(const lv_obj_t * lmeter); /** * Get the maximum value of a line meter * @param lmeter pointer to a line meter object * @return the maximum value of the line meter */ -int16_t lv_linemeter_get_max_value(const lv_obj_t * lmeter); +int32_t lv_linemeter_get_max_value(const lv_obj_t * lmeter); /** * Get the scale number of a line meter