diff --git a/lv_misc/anim.c b/lv_misc/anim.c index fb7f2d708..52329652f 100644 --- a/lv_misc/anim.c +++ b/lv_misc/anim.c @@ -36,6 +36,12 @@ static void anim_ready_handler(anim_t * a); static ll_dsc_t anim_ll; static uint32_t last_task_run; +static anim_path_t anim_path_lin[] = + {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192}; + /********************** * MACROS **********************/ @@ -72,7 +78,70 @@ void anim_create(anim_t * anim_p) new_anim->fp(new_anim->var, new_anim->start); } +/** + * Delete an animation for a variable with a given animatior function + * @param var pointer to variable + * @param fp a function pointer which is animating 'var', + * or NULL to ignore it and delete all animation with 'var + * @return true: at least 1 animation is deleted, false: no animation is deleted + */ +bool anim_del(void * var, anim_fp_t fp) +{ + bool del = false; + anim_t * a; + anim_t * a_next; + a = ll_get_head(&anim_ll); + while(a != NULL) { + /*'a' might be deleted, so get the next object while 'a' is valid*/ + a_next = ll_get_next(&anim_ll, a); + if(a->var == var && (a->fp == fp || fp == NULL)) { + ll_rem(&anim_ll, a); + dm_free(a); + del = true; + } + + a = a_next; + } + + return del; +} + +/** + * Calculate the time of an animation with a given speed and the start and end values + * @param speed speed of animation in unit/sec + * @param start start value of the animation + * @param end end value of the animation + * @return the required time [ms] for the animation with the given parameters + */ +uint16_t anim_speed_to_time(uint16_t speed, int32_t start, int32_t end) +{ + int32_t d = abs((int32_t) start - end); + uint16_t time = (int32_t)((int32_t)(d * 1000) / speed); + + if(time == 0) { + time++; + } + + return time; +} + +/** + * Get a predefine animation path + * @param name name of the path from 'anim_path_name_t' + * @return pointer to the path array + */ +anim_path_t * anim_get_path(anim_path_name_t name) +{ + switch (name) { + case ANIM_PATH_LIN: + return anim_path_lin; + break; + default: + return NULL; + break; + } +} /********************** * STATIC FUNCTIONS **********************/ @@ -98,12 +167,15 @@ static void anim_task (void) /* Get the index of the path array based on the elapsed time*/ uint8_t path_i; - path_i = a->act_time * (ANIM_PATH_LENGTH - 1) / a->time; - + if(a->time != 0) { + path_i = a->act_time * (ANIM_PATH_LENGTH - 1) / a->time; + } else { + path_i = ANIM_PATH_LENGTH - 1; + } /* Get the new value which will be proportional to the current element of 'path_p' * and the 'start' and 'end' values*/ int32_t new_val; - new_val = (int32_t)(a->path_p[path_i] - ANIM_PATH_START) * (a->end - a->start); + new_val = (int32_t)(a->path[path_i] - ANIM_PATH_START) * (a->end - a->start); new_val = new_val >> ANIM_PATH_NORM_SHIFT; new_val += a->start; @@ -143,9 +215,12 @@ static void anim_ready_handler(anim_t * a) } /*If the animation is not deleted then restart it*/ else { - a->act_time = 0; /*Restart the animation*/ + a->act_time = - a->repeat_pause; /*Restart the animation*/ /*Swap the start and end values in play back mode*/ if(a->playback != 0) { + /*If now turning back use the 'playback_pause*/ + if(a->playback_now == 0) a->act_time = - a->playback_pause; + /*Toggle the play back state*/ a->playback_now = a->playback_now == 0 ? 1: 0; /*Swap the start and end values*/ diff --git a/lv_misc/anim.h b/lv_misc/anim.h index 63ef4d9f5..2d7f18f55 100644 --- a/lv_misc/anim.h +++ b/lv_misc/anim.h @@ -18,18 +18,28 @@ /********************** * TYPEDEFS **********************/ + +typedef enum +{ + ANIM_PATH_LIN, +}anim_path_name_t; + typedef uint8_t anim_path_t; +typedef void (*anim_fp_t)(void *, int32_t); + typedef struct { void * var; /*Variable to animate*/ - void (*fp) (void *, int32_t); /*Animator function*/ + anim_fp_t fp; /*Animator function*/ void (*end_cb) (void *); /*Call it when the animation is ready*/ - anim_path_t * path_p; /*An array with the steps of animations*/ + anim_path_t * path; /*An array with the steps of animations*/ int32_t start; /*Start value*/ int32_t end; /*End value*/ int16_t time; /*Animation time in ms*/ int16_t act_time; /*Current time in animation. Set to negative to make delay.*/ + uint16_t playback_pause; /*Wait before play back*/ + uint16_t repeat_pause; /*Wait before repeat*/ uint8_t playback :1; /*When the animation is ready play it back*/ uint8_t repeat :1; /*Repeat the animation infinitely*/ /*Animation system use these - user shouldn't set*/ @@ -41,6 +51,9 @@ typedef struct **********************/ void anim_init(void); void anim_create(anim_t * anim_p); +anim_path_t * anim_get_path(anim_path_name_t type); +bool anim_del(void * var, anim_fp_t fp); +uint16_t anim_speed_to_time(uint16_t speed, int32_t start, int32_t end); /********************** * MACROS diff --git a/lv_obj/lv_obj.c b/lv_obj/lv_obj.c index 3759d7202..3ca0d2bef 100644 --- a/lv_obj/lv_obj.c +++ b/lv_obj/lv_obj.c @@ -40,12 +40,6 @@ lv_objs_t lv_objs_def = {.color = COLOR_MAKE(0xa0, 0xc0, 0xe0), .transp = 0}; lv_objs_t lv_objs_scr = {.color = LV_OBJ_DEF_SCR_COLOR, .transp = 0}; lv_objs_t lv_objs_transp = {.transp = 1}; -anim_path_t anim_path_lin[] = - {64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192}; - /********************** * MACROS **********************/ @@ -283,6 +277,9 @@ void lv_obj_del(lv_obj_t * obj) i = i_next; } + /*Remove the animations from this object*/ + anim_del(obj, NULL); + /*Remove the object from parent's children list*/ lv_obj_t * par = lv_obj_get_parent(obj); if(par == NULL) { /*It is a screen*/ @@ -1014,6 +1011,11 @@ void lv_obj_anim(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t a.time = time; a.act_time = (int32_t)-delay; a.end_cb = (void(*)(void*))cb; + a.path = anim_get_path(ANIM_PATH_LIN); + a.playback_pause = 0; + a.repeat_pause = 0; + a.playback = 0; + a.repeat = 0; /*Init to ANIM_IN*/ switch(type) { @@ -1021,43 +1023,36 @@ void lv_obj_anim(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t a.fp = (void(*)(void *, int32_t))lv_obj_set_x; a.start = -lv_obj_get_width(obj); a.end = lv_obj_get_x(obj); - a.path_p = anim_path_lin; break; case LV_ANIM_FLOAT_RIGHT: a.fp = (void(*)(void *, int32_t))lv_obj_set_x; a.start = lv_obj_get_width(par); a.end = lv_obj_get_x(obj); - a.path_p = anim_path_lin; break; case LV_ANIM_FLOAT_TOP: a.fp = (void(*)(void * , int32_t))lv_obj_set_y; a.start = -lv_obj_get_height(obj); a.end = lv_obj_get_y(obj); - a.path_p = anim_path_lin; break; case LV_ANIM_FLOAT_BOTTOM: a.fp = (void(*)(void * , int32_t))lv_obj_set_y; a.start = lv_obj_get_height(par); a.end = lv_obj_get_y(obj); - a.path_p = anim_path_lin; break; case LV_ANIM_FADE: a.fp = (void(*)(void * , int32_t))lv_obj_set_opar; a.start = OPA_TRANSP; a.end = OPA_COVER; - a.path_p = anim_path_lin; break; case LV_ANIM_GROW_H: a.fp = (void(*)(void * , int32_t))lv_obj_set_width; a.start = 0; a.end = lv_obj_get_width(obj); - a.path_p = anim_path_lin; break; case LV_ANIM_GROW_V: a.fp = (void(*)(void * , int32_t))lv_obj_set_height; a.start = 0; a.end = lv_obj_get_height(obj); - a.path_p = anim_path_lin; break; default: break; diff --git a/lv_obj/lv_refr.c b/lv_obj/lv_refr.c index 24c3e22ee..40aa8094c 100644 --- a/lv_obj/lv_refr.c +++ b/lv_obj/lv_refr.c @@ -392,6 +392,7 @@ static void lv_refr_obj(lv_obj_t * obj, const area_t * mask_ori_p) /* Truncate the original mask to the coordinates of the parent * because the parent and its children are visible only here */ area_t obj_mask; + area_t obj_ext_mask; area_t obj_area; cord_t ext_size = obj->ext_size; lv_obj_get_cords(obj, &obj_area); @@ -399,41 +400,46 @@ static void lv_refr_obj(lv_obj_t * obj, const area_t * mask_ori_p) obj_area.y1 -= ext_size; obj_area.x2 += ext_size; obj_area.y2 += ext_size; - union_ok = area_union(&obj_mask, mask_ori_p, &obj_area); + union_ok = area_union(&obj_ext_mask, mask_ori_p, &obj_area); /*Draw the parent and its children only if they ore on 'mask_parent'*/ if(union_ok != false) { /* Redraw the object */ if(obj->opa != OPA_TRANSP && LV_SA(obj, lv_objs_t)->transp == 0) { - obj->design_f(obj, &obj_mask, LV_DESIGN_DRAW_MAIN); + obj->design_f(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN); } - area_t mask_child; /*Mask from obj and its child*/ - lv_obj_t * child_p; - area_t child_area; - LL_READ_BACK(obj->child_ll, child_p) - { - lv_obj_get_cords(child_p, &child_area); - ext_size = child_p->ext_size; - child_area.x1 -= ext_size; - child_area.y1 -= ext_size; - child_area.x2 += ext_size; - child_area.y2 += ext_size; - /* Get the union (common parts) of original mask (from obj) - * and its child */ - union_ok = area_union(&mask_child, &obj_mask, &child_area); + /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/ + lv_obj_get_cords(obj, &obj_area); + union_ok = area_union(&obj_mask, mask_ori_p, &obj_area); + if(union_ok != false) { + area_t mask_child; /*Mask from obj and its child*/ + lv_obj_t * child_p; + area_t child_area; + LL_READ_BACK(obj->child_ll, child_p) + { + lv_obj_get_cords(child_p, &child_area); + ext_size = child_p->ext_size; + child_area.x1 -= ext_size; + child_area.y1 -= ext_size; + child_area.x2 += ext_size; + child_area.y2 += ext_size; + /* Get the union (common parts) of original mask (from obj) + * and its child */ + union_ok = area_union(&mask_child, &obj_mask, &child_area); - /*If the parent and the child has common area then refresh the child */ - if(union_ok) { - /*Refresh the next children*/ - lv_refr_obj(child_p, &mask_child); - } + /*If the parent and the child has common area then refresh the child */ + if(union_ok) { + /*Refresh the next children*/ + lv_refr_obj(child_p, &mask_child); + } + } } - /* If all the children are redrawn call make 'post draw' design */ + /* If all the children are redrawn make 'post draw' design */ if(obj->opa != OPA_TRANSP && LV_SA(obj, lv_objs_t)->transp == 0) { - obj->design_f(obj, &obj_mask, LV_DESIGN_DRAW_POST); + obj->design_f(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST); } } } diff --git a/lv_objx/lv_label.c b/lv_objx/lv_label.c index 39d96d024..7b12ae3f7 100644 --- a/lv_objx/lv_label.c +++ b/lv_objx/lv_label.c @@ -14,6 +14,7 @@ #include "lv_label.h" #include "../lv_obj/lv_obj.h" #include "../lv_misc/text.h" +#include "../lv_misc/anim.h" #include "../lv_draw/lv_draw.h" /********************* @@ -23,6 +24,8 @@ #define LV_LABEL_DOT_END_INV 0xFFFF #define LV_LABEL_SCROLL_SPEED (50 * LV_DOWNSCALE) /*Hor, or ver. scroll speed (px/sec) in 'LV_LABEL_LONG_SCROLL' mode*/ #define LV_LABEL_SCROLL_SPEED_VER (10 * LV_DOWNSCALE) /*Ver. scroll speed if hor. scroll is applied too*/ +#define LV_LABEL_SCROLL_PLAYBACK_PAUSE 300 /*Wait before the scroll turns back in ms*/ +#define LV_LABEL_SCROLL_REPEAT_PAUSE 600 /*Wait before the scroll begins again in ms*/ /********************** * TYPEDEFS @@ -202,7 +205,45 @@ void lv_label_set_text(lv_obj_t * label, const char * text) /*Start scrolling if the label is greater then its parent*/ if(ext->long_mode == LV_LABEL_LONG_SCROLL) { - /*TODO create the animations*/ + lv_obj_t * parent = lv_obj_get_parent(label); + + /*Delete the potential previous scroller animations*/ + anim_del(label, (anim_fp_t) lv_obj_set_x); + anim_del(label, (anim_fp_t) lv_obj_set_y); + + anim_t anim; + anim.var = label; + anim.repeat = 1; + anim.playback = 1; + anim.start = font_get_width(font, ' '); + anim.act_time = 0; + anim.end_cb = NULL; + anim.path = anim_get_path(ANIM_PATH_LIN); + anim.time = 3000; + anim.playback_pause = LV_LABEL_SCROLL_PLAYBACK_PAUSE; + anim.repeat_pause = LV_LABEL_SCROLL_REPEAT_PAUSE; + + bool hor_anim = false; + if(lv_obj_get_width(label) > lv_obj_get_width(parent)) { + anim.end = lv_obj_get_width(parent) - lv_obj_get_width(label) - font_get_width(font, ' '); + anim.fp = (anim_fp_t) lv_obj_set_x; + anim.time = anim_speed_to_time(LV_LABEL_SCROLL_SPEED, anim.start, anim.end); + anim_create(&anim); + hor_anim = true; + } + + if(lv_obj_get_height(label) > lv_obj_get_height(parent)) { + anim.end = lv_obj_get_height(parent) - lv_obj_get_height(label) - font_get_height(font); + anim.fp = (anim_fp_t)lv_obj_set_y; + + /*Different animation speed if horizontal animation is created too*/ + if(hor_anim == false) { + anim.time = anim_speed_to_time(LV_LABEL_SCROLL_SPEED, anim.start, anim.end); + } else { + anim.time = anim_speed_to_time(LV_LABEL_SCROLL_SPEED_VER, anim.start, anim.end); + } + anim_create(&anim); + } } } /*In break mode only the height can change*/ @@ -216,18 +257,29 @@ void lv_label_set_text(lv_obj_t * label, const char * text) point.x = lv_obj_get_width(label) - 1; point.y = lv_obj_get_height(label) - 1; uint16_t index = lv_label_get_letter_on(label, &point); - printf("index: %d, letter: %c, %d\n", index, ext->txt[index], ext->txt[index]); if(index < strlen(text) - 1) { - uint8_t i; - for(i = 0; i < LV_LABEL_DOT_NUM; i++) { - ext->dot_tmp[i] = ext->txt[index - LV_LABEL_DOT_NUM + i]; - ext->txt[index - LV_LABEL_DOT_NUM + i] = '.'; - } - /*The last character is '\0'*/ - ext->dot_tmp[i] = ext->txt[index]; - ext->txt[index] = '\0'; + /* Change the last 'LV_LABEL_DOT_NUM' to dots + * (if there are at least 'LV_LABEL_DOT_NUM' characters*/ + if(index > LV_LABEL_DOT_NUM) { + uint8_t i; + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->dot_tmp[i] = ext->txt[index - LV_LABEL_DOT_NUM + i]; + ext->txt[index - LV_LABEL_DOT_NUM + i] = '.'; + } + /*The last character is '\0'*/ + ext->dot_tmp[i] = ext->txt[index]; + ext->txt[index] = '\0'; + } + /*Else with short text change all characters to dots*/ + else { + uint8_t i; + for(i = 0; i < LV_LABEL_DOT_NUM; i++) { + ext->txt[i] = '.'; + } + ext->txt[i] = '\0'; + } /*Save the dot end index*/ ext->dot_end = index; } @@ -254,6 +306,12 @@ void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode) } } + /*Delete the scroller animations*/ + if(ext->long_mode == LV_LABEL_LONG_SCROLL) { + anim_del(label, (anim_fp_t) lv_obj_set_x); + anim_del(label, (anim_fp_t) lv_obj_set_y); + } + ext->long_mode = long_mode; lv_label_set_text(label, NULL); } @@ -450,7 +508,7 @@ static bool lv_label_design(lv_obj_t * label, const area_t * mask, lv_design_mod if(mode == LV_DESIGN_COVER_CHK) return false; else if(mode == LV_DESIGN_DRAW_MAIN) { /*TEST: draw a background for the label*/ - lv_vfill(&label->cords, mask, COLOR_LIME, OPA_COVER); + //lv_vfill(&label->cords, mask, COLOR_LIME, OPA_COVER); area_t cords; lv_obj_get_cords(label, &cords); diff --git a/lv_objx/lv_label.h b/lv_objx/lv_label.h index cb60cdab6..4d09affa8 100644 --- a/lv_objx/lv_label.h +++ b/lv_objx/lv_label.h @@ -60,7 +60,7 @@ typedef struct /*New data for this type */ char * txt; lv_label_long_mode_t long_mode; - char dot_tmp[LV_LABEL_DOT_NUM + 1]; /*Store character which are replaced with dots*/ + char dot_tmp[LV_LABEL_DOT_NUM + 10]; /*Store character which are replaced with dots*/ uint16_t dot_end; /*The text end in dot mode*/ }lv_label_ext_t; diff --git a/lv_objx/lv_ta.c b/lv_objx/lv_ta.c index 4e84d43b8..927a595fc 100644 --- a/lv_objx/lv_ta.c +++ b/lv_objx/lv_ta.c @@ -83,7 +83,7 @@ lv_obj_t * lv_ta_create(lv_obj_t * par, lv_obj_t * copy) scrling_design_f = lv_obj_get_design_f(ext->page.scrolling); } lv_obj_set_design_f(ext->page.scrolling, lv_ta_scrling_design); - lv_label_set_fixw(ext->label, true); + lv_label_set_long_mode(ext->label, LV_LABEL_LONG_BREAK); lv_label_set_text(ext->label, "abc aaaa bbbb ccc\n123\nABC\nxyz\nwww\n007\nalma\n:)\naaaaaa"); lv_page_glue_obj(ext->label, true); lv_obj_set_click(ext->label, true);