diff --git a/README.md b/README.md index 191d8bbe0..b79396c25 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ In the simplest case you need 5 things: 3. Register a function which can **read an input device**. (E.g. touch pad) 4. Copy `lv_conf_templ.h` as `lv_conf.h` and set at least `LV_HOR_RES`, `LV_VER_RES` and `LV_COLOR_DEPTH`. 5. Call `lv_task_handler()` periodically every few milliseconds. -For a detailed description visit https://littlevgl.com/porting +For a detailed description visit https://github.com/littlevgl/lvgl/wiki/Porting Or check the [Porting tutorial](https://github.com/littlevgl/lv_examples/blob/master/lv_tutorial/0_porting/lv_tutorial_porting.c) ## Project set-up diff --git a/lv_conf_templ.h b/lv_conf_templ.h index 7239e4f28..1cf4903a9 100644 --- a/lv_conf_templ.h +++ b/lv_conf_templ.h @@ -262,6 +262,7 @@ #if USE_LV_PRELOAD != 0 #define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/ #define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ +#define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC #endif /************************* diff --git a/lv_core/lv_refr.c b/lv_core/lv_refr.c index 93a81c34c..766c6e2e9 100644 --- a/lv_core/lv_refr.c +++ b/lv_core/lv_refr.c @@ -515,10 +515,9 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) /* Redraw the object */ lv_style_t * style = lv_obj_get_style(obj); - if(style->body.opa != LV_OPA_TRANSP) { - obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN); - //tick_wait_ms(100); /*DEBUG: Wait after every object draw to see the order of drawing*/ - } + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN); + //tick_wait_ms(100); /*DEBUG: Wait after every object draw to see the order of drawing*/ + /*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/ lv_obj_get_coords(obj, &obj_area); @@ -547,8 +546,7 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p) } /* If all the children are redrawn make 'post draw' design */ - if(style->body.opa != LV_OPA_TRANSP) { - obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST); - } + obj->design_func(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST); + } } diff --git a/lv_draw/lv_draw_rect.c b/lv_draw/lv_draw_rect.c index b62ccab51..5b4ef1665 100644 --- a/lv_draw/lv_draw_rect.c +++ b/lv_draw/lv_draw_rect.c @@ -71,7 +71,7 @@ void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_sty lv_draw_shadow(coords, mask, style, opa_scale); } #endif - if(style->body.empty == 0) { + if(style->body.empty == 0 && style->body.opa >= LV_OPA_MIN) { lv_draw_rect_main_mid(coords, mask, style, opa_scale); if(style->body.radius != 0) { @@ -79,7 +79,7 @@ void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_sty } } - if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE) { + if(style->body.border.width != 0 && style->body.border.part != LV_BORDER_NONE && style->body.border.opa >= LV_OPA_MIN) { lv_draw_rect_border_straight(coords, mask, style, opa_scale); if(style->body.radius != 0) { diff --git a/lv_misc/lv_anim.c b/lv_misc/lv_anim.c index ca0d4b63d..fd7aa6878 100644 --- a/lv_misc/lv_anim.c +++ b/lv_misc/lv_anim.c @@ -196,6 +196,30 @@ int32_t lv_anim_path_ease_in_out(const lv_anim_t * a) return new_value; } +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a) +{ + /*Calculate the current step*/ + + uint32_t t; + if(a->time == a->act_time) t = 1024; + else t = (uint32_t)((uint32_t)a->act_time * 1024) / a->time; + + int32_t step = lv_bezier3(t, 0, 600, 1300, 1024); + + int32_t new_value; + new_value = (int32_t) step * (a->end - a->start); + new_value = new_value >> 10; + new_value += a->start; + + + return new_value; +} + /** * Calculate the current value of an animation applying step characteristic. * (Set end value on the end of the animation) diff --git a/lv_misc/lv_anim.h b/lv_misc/lv_anim.h index aaf1c6bff..71ffa930f 100644 --- a/lv_misc/lv_anim.h +++ b/lv_misc/lv_anim.h @@ -129,6 +129,13 @@ int32_t lv_anim_path_linear(const lv_anim_t *a); */ int32_t lv_anim_path_ease_in_out(const lv_anim_t *a); +/** + * Calculate the current value of an animation with overshoot at the end + * @param a pointer to an animation + * @return the current value to set + */ +int32_t lv_anim_path_overshoot(const lv_anim_t * a); + /** * Calculate the current value of an animation applying step characteristic. * (Set end value on the end of the animation) diff --git a/lv_objx/lv_btnm.c b/lv_objx/lv_btnm.c index 3326f2e96..73a96e39d 100644 --- a/lv_objx/lv_btnm.c +++ b/lv_objx/lv_btnm.c @@ -340,16 +340,27 @@ lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm) return ext->action; } +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm) +{ + lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); + return ext->btn_id_pr; +} + /** * Get the toggled button * @param btnm pointer to button matrix object - * @return index of the currently toggled button (0: if unset) + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) */ uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm) { lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); - if(ext->toggle == 0) return 0; + if(ext->toggle == 0) return LV_BTNM_PR_NONE; else return ext->btn_id_tgl; } @@ -581,7 +592,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param) } #if USE_LV_GROUP - /*Leave the clicked button as pressed if this the focused object in a group*/ + /*Leave the clicked button when releases if this not the focused object in a group*/ lv_group_t * g = lv_obj_get_group(btnm); if(lv_group_get_focused(g) != btnm) { ext->btn_id_pr = LV_BTNM_PR_NONE; diff --git a/lv_objx/lv_btnm.h b/lv_objx/lv_btnm.h index 91214e40f..a1c7c2097 100644 --- a/lv_objx/lv_btnm.h +++ b/lv_objx/lv_btnm.h @@ -147,11 +147,17 @@ const char ** lv_btnm_get_map(const lv_obj_t * btnm); */ lv_btnm_action_t lv_btnm_get_action(const lv_obj_t * btnm); +/** + * Get the pressed button + * @param btnm pointer to button matrix object + * @return index of the currently pressed button (LV_BTNM_PR_NONE: if unset) + */ +uint16_t lv_btnm_get_pressed(const lv_obj_t * btnm); /** * Get the toggled button * @param btnm pointer to button matrix object - * @return index of the currently toggled button (0: if unset) + * @return index of the currently toggled button (LV_BTNM_PR_NONE: if unset) */ uint16_t lv_btnm_get_toggled(const lv_obj_t * btnm); diff --git a/lv_objx/lv_chart.c b/lv_objx/lv_chart.c index e21c8ca35..d0f7c4d67 100644 --- a/lv_objx/lv_chart.c +++ b/lv_objx/lv_chart.c @@ -34,6 +34,7 @@ static void lv_chart_draw_div(lv_obj_t * chart, const lv_area_t * mask); static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask); static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask); static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask); +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask); /********************** * STATIC VARIABLES @@ -460,6 +461,7 @@ static bool lv_chart_design(lv_obj_t * chart, const lv_area_t * mask, lv_design_ if(ext->type & LV_CHART_TYPE_LINE) lv_chart_draw_lines(chart, mask); if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_draw_cols(chart, mask); if(ext->type & LV_CHART_TYPE_POINT) lv_chart_draw_points(chart, mask); + if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_draw_vertical_lines(chart, mask); } return true; } @@ -718,4 +720,79 @@ static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask) } } } + +/** + * Draw the data lines as vertical lines on a chart if there is only 1px between point + * @param obj pointer to chart object + */ +static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask) +{ + lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart); + + uint16_t i; + lv_point_t p1; + lv_point_t p2; + lv_coord_t w = lv_obj_get_width(chart); + lv_coord_t h = lv_obj_get_height(chart); + lv_coord_t x_ofs = chart->coords.x1; + lv_coord_t y_ofs = chart->coords.y1; + int32_t y_tmp; + lv_chart_series_t * ser; + lv_opa_t opa_scale = lv_obj_get_opa_scale(chart); + lv_style_t style; + lv_style_copy(&style, &lv_style_plain); + style.line.opa = ext->series.opa; + style.line.width = ext->series.width; + + /*Go through all data lines*/ + LL_READ_BACK(ext->series_ll, ser) { + style.line.color = ser->color; + + p1.x = 0 + x_ofs; + p2.x = 0 + x_ofs; + y_tmp = (int32_t)((int32_t) ser->points[0] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(ext->point_cnt == w) + { + for(i = 0; i < ext->point_cnt; i++) + { + + y_tmp = (int32_t)((int32_t) ser->points[i] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(p1.y == p2.y) + { + p2.x++; + } + + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + p1.x = p2.x; + p1.y = p2.y; + } + } + else + { + for(i = 1; i < ext->point_cnt; i ++) { + p1.x = p2.x; + p1.y = p2.y; + + p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs; + + y_tmp = (int32_t)((int32_t) ser->points[i] - ext->ymin) * h; + y_tmp = y_tmp / (ext->ymax - ext->ymin); + p2.y = h - y_tmp + y_ofs; + + if(ser->points[i - 1] >= 0 && ser->points[i] >= 0) + { + lv_draw_line(&p1, &p2, mask, &style, opa_scale); + } + } + } + } +} #endif diff --git a/lv_objx/lv_chart.h b/lv_objx/lv_chart.h index 0567648df..2f1a43b37 100644 --- a/lv_objx/lv_chart.h +++ b/lv_objx/lv_chart.h @@ -49,7 +49,7 @@ typedef struct uint8_t hdiv_cnt; /*Number of horizontal division lines*/ uint8_t vdiv_cnt; /*Number of vertical division lines*/ uint16_t point_cnt; /*Point number in a data line*/ - uint8_t type :3; /*Line, column or point chart (from 'lv_chart_type_t')*/ + uint8_t type :4; /*Line, column or point chart (from 'lv_chart_type_t')*/ struct { lv_coord_t width; /*Line width or point radius*/ uint8_t num; /*Number of data lines in dl_ll*/ @@ -64,6 +64,7 @@ enum LV_CHART_TYPE_LINE = 0x01, LV_CHART_TYPE_COLUMN = 0x02, LV_CHART_TYPE_POINT = 0x04, + LV_CHART_TYPE_VERTICAL_LINE = 0x08, }; typedef uint8_t lv_chart_type_t; diff --git a/lv_objx/lv_preload.c b/lv_objx/lv_preload.c index 2d189740c..1700a4dab 100644 --- a/lv_objx/lv_preload.c +++ b/lv_objx/lv_preload.c @@ -24,6 +24,12 @@ #ifndef LV_PRELOAD_DEF_SPIN_TIME # define LV_PRELOAD_DEF_SPIN_TIME 1000 /*[ms]*/ #endif + +#ifndef LV_PRELOAD_DEF_ANIM +# define LV_PRELOAD_DEF_ANIM LV_PRELOAD_TYPE_SPINNING_ARC /*animation type*/ +#endif + + /********************** * TYPEDEFS **********************/ @@ -73,26 +79,12 @@ lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy) /*Initialize the allocated 'ext' */ ext->arc_length = LV_PRELOAD_DEF_ARC_LENGTH; + ext->anim_type = LV_PRELOAD_DEF_ANIM; /*The signal and design functions are not copied so set them here*/ lv_obj_set_signal_func(new_preload, lv_preload_signal); lv_obj_set_design_func(new_preload, lv_preload_design); -#if USE_LV_ANIMATION - lv_anim_t a; - a.var = new_preload; - a.start = 0; - a.end = 360; - a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; - a.path = lv_anim_path_ease_in_out; - a.end_cb = NULL; - a.act_time = 0; - a.time = LV_PRELOAD_DEF_SPIN_TIME; - a.playback = 0; - a.playback_pause = 0; - a.repeat = 1; - a.repeat_pause = 0; - lv_anim_create(&a); -#endif + /*Init the new pre loader pre loader*/ if(copy == NULL) { @@ -106,6 +98,8 @@ lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_set_style(new_preload, &lv_style_pretty_color); } + ext->time = LV_PRELOAD_DEF_SPIN_TIME; + } /*Copy an existing pre loader*/ else { @@ -116,6 +110,8 @@ lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy) lv_obj_refresh_style(new_preload); } + lv_preload_set_animation_type(new_preload, ext->anim_type); + LV_LOG_INFO("preload created"); @@ -148,22 +144,7 @@ void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time) lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); ext->time = time; -#if USE_LV_ANIMATION - lv_anim_t a; - a.var = preload; - a.start = 0; - a.end = 360; - a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; - a.path = lv_anim_path_ease_in_out; - a.end_cb = NULL; - a.act_time = 0; - a.time = time; - a.playback = 0; - a.playback_pause = 0; - a.repeat = 1; - a.repeat_pause = 0; - lv_anim_create(&a); -#endif + lv_preload_set_animation_type(preload, ext->anim_type); } /*===================== * Setter functions @@ -178,12 +159,85 @@ void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time) void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t * style) { switch(type) { - case LV_PRELOAD_STYLE_MAIN: - lv_arc_set_style(preload, LV_ARC_STYLE_MAIN, style); - break; + case LV_PRELOAD_STYLE_MAIN: + lv_arc_set_style(preload, LV_ARC_STYLE_MAIN, style); + break; } } +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type) +{ +#if USE_LV_ANIMATION + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + + /*delete previous animation*/ + //lv_anim_del(preload, NULL); + switch(type) + { + case LV_PRELOAD_TYPE_FILLSPIN_ARC: + { + ext->anim_type = LV_PRELOAD_TYPE_FILLSPIN_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_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; + b.start = ext->arc_length; + b.end = 360 - ext->arc_length; + b.fp = (lv_anim_fp_t)lv_preload_set_arc_length; + b.path = lv_anim_path_ease_in_out; + b.end_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_PRELOAD_TYPE_SPINNING_ARC: + default: + { + ext->anim_type = LV_PRELOAD_TYPE_SPINNING_ARC; + lv_anim_t a; + a.var = preload; + a.start = 0; + a.end = 360; + a.fp = (lv_anim_fp_t)lv_preload_spinner_animation; + a.path = lv_anim_path_ease_in_out; + a.end_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; + } + } + +#endif //USE_LV_ANIMATION +} + /*===================== * Getter functions *====================*/ @@ -220,17 +274,28 @@ lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t t lv_style_t * style = NULL; switch(type) { - case LV_PRELOAD_STYLE_MAIN: - style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); - break; - default: - style = NULL; - break; + case LV_PRELOAD_STYLE_MAIN: + style = lv_arc_get_style(preload, LV_ARC_STYLE_MAIN); + break; + default: + style = NULL; + break; } return style; } +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload) +{ + lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload); + return ext->anim_type; +} + /*===================== * Other functions *====================*/ diff --git a/lv_objx/lv_preload.h b/lv_objx/lv_preload.h index 393eea8e7..4f12f0221 100644 --- a/lv_objx/lv_preload.h +++ b/lv_objx/lv_preload.h @@ -43,6 +43,7 @@ extern "C" { enum { LV_PRELOAD_TYPE_SPINNING_ARC, + LV_PRELOAD_TYPE_FILLSPIN_ARC, }; typedef uint8_t lv_preloader_type_t; @@ -52,6 +53,7 @@ typedef struct { /*New data for this type */ uint16_t arc_length; /*Length of the spinning indicator in degree*/ uint16_t time; /*Time of one round*/ + lv_preloader_type_t anim_type; /*Type of the arc animation*/ } lv_preload_ext_t; @@ -103,6 +105,13 @@ void lv_preload_set_spin_time(lv_obj_t * preload, uint16_t time); * */ void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, lv_style_t *style); +/** + * Set the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @param type animation type of the preload + * */ +void lv_preload_set_animation_type(lv_obj_t * preload, lv_preloader_type_t type); + /*===================== * Getter functions *====================*/ @@ -127,6 +136,13 @@ uint16_t lv_preload_get_spin_time(const lv_obj_t * preload); * */ lv_style_t * lv_preload_get_style(const lv_obj_t * preload, lv_preload_style_t type); +/** + * Get the animation type of a preloadeer. + * @param preload pointer to pre loader object + * @return animation type + * */ +lv_preloader_type_t lv_preload_get_animation_type(lv_obj_t * preload); + /*===================== * Other functions *====================*/ diff --git a/lv_objx/lv_sw.c b/lv_objx/lv_sw.c index 83c084fa0..570a6c4f4 100644 --- a/lv_objx/lv_sw.c +++ b/lv_objx/lv_sw.c @@ -16,13 +16,12 @@ #endif #include "../lv_themes/lv_theme.h" +#include "../lv_misc/lv_math.h" /********************* * DEFINES *********************/ -#define LV_SWITCH_SLIDER_ANIM_MAX 1000 - /********************** * TYPEDEFS **********************/ @@ -31,6 +30,7 @@ * STATIC PROTOTYPES **********************/ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param); +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value); /********************** * STATIC VARIABLES @@ -81,6 +81,7 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy) lv_slider_set_range(new_sw, 0, 1); lv_obj_set_size(new_sw, 2 * LV_DPI / 3, LV_DPI / 3); lv_slider_set_knob_in(new_sw, true); + lv_slider_set_range(new_sw, 0, LV_SWITCH_SLIDER_ANIM_MAX); /*Set the default styles*/ lv_theme_t * th = lv_theme_get_current(); @@ -99,9 +100,12 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy) lv_sw_ext_t * copy_ext = lv_obj_get_ext_attr(copy); ext->style_knob_off = copy_ext->style_knob_off; ext->style_knob_on = copy_ext->style_knob_on; + ext->anim_time = copy_ext->anim_time; if(lv_sw_get_state(new_sw)) lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); else lv_slider_set_style(new_sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); + + /*Refresh the style with new signal function*/ lv_obj_refresh_style(new_sw); } @@ -115,44 +119,15 @@ lv_obj_t * lv_sw_create(lv_obj_t * par, const lv_obj_t * copy) * Setter functions *====================*/ -static void lv_sw_clear_anim(lv_obj_t *sw) -{ - lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); - ext->anim_act = 0; -} - /** * Turn ON the switch * @param sw pointer to a switch object */ void lv_sw_on(lv_obj_t * sw) { - if(lv_sw_get_state(sw)) return; /*Do nothing is already turned on*/ - lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); -#if USE_LV_ANIMATION - if(lv_sw_get_anim_time(sw) > 0) { - if(ext->anim_act) { - lv_anim_del(sw, NULL); - ext->anim_act = 0; - } - ext->cur_anim.var = sw; - ext->cur_anim.start = lv_slider_get_value(sw); - ext->cur_anim.end = LV_SWITCH_SLIDER_ANIM_MAX; - ext->cur_anim.fp = (lv_anim_fp_t)lv_slider_set_value; - ext->cur_anim.path = lv_anim_path_linear; - ext->cur_anim.end_cb = (lv_anim_cb_t)lv_sw_clear_anim; - ext->cur_anim.act_time = 0; - ext->cur_anim.time = lv_sw_get_anim_time(sw); - ext->cur_anim.playback = 0; - ext->cur_anim.playback_pause = 0; - ext->cur_anim.repeat = 0; - ext->cur_anim.repeat_pause = 0; - ext->anim_act = 1; - lv_anim_create(&ext->cur_anim); - } else /* continues below if statement */ -#endif - lv_slider_set_value(sw, 1); + lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); } @@ -162,10 +137,36 @@ void lv_sw_on(lv_obj_t * sw) */ void lv_sw_off(lv_obj_t * sw) { - if(!lv_sw_get_state(sw)) return; /*Do nothing is already turned off*/ - lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); lv_slider_set_value(sw, 0); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); +} + +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + + if(lv_sw_get_anim_time(sw) > 0) lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + else lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); +} + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw) +{ + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + if(lv_sw_get_anim_time(sw) > 0) lv_sw_anim_to_value(sw, 0); + else lv_slider_set_value(sw, 0); + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); } @@ -197,15 +198,13 @@ void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, lv_style_t * style) } } - void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time) { +#if USE_LV_ANIMATION == 0 + anim_time = 0; +#endif lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); - ext->anim_time = anim_time; - if(anim_time > 0) { - lv_slider_set_range(sw, 0, LV_SWITCH_SLIDER_ANIM_MAX); - } else - lv_slider_set_range(sw, 0, 1); + ext->anim_time = anim_time; } /*===================== @@ -246,8 +245,13 @@ lv_style_t * lv_sw_get_style(const lv_obj_t * sw, lv_sw_style_t type) uint16_t lv_sw_get_anim_time(const lv_obj_t *sw) { + +#if USE_LV_ANIMATION lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); return ext->anim_time; +#else + return 0; +#endif } /********************** @@ -271,13 +275,6 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param) if(sign == LV_SIGNAL_PRESSING) old_val = ext->slider.drag_value; else old_val = lv_slider_get_value(sw); -#if USE_LV_ANIMATION - if(lv_sw_get_anim_time(sw) > 0) { - /* Overwrite old_val */ - old_val = lv_sw_get_state(sw) ? LV_SWITCH_SLIDER_ANIM_MAX : 0; - } -#endif - /*Do not let the slider to call the callback. The Switch will do it if required*/ lv_action_t slider_action = ext->slider.action; ext->slider.action = NULL; @@ -289,58 +286,80 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param) if(sign == LV_SIGNAL_CLEANUP) { /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/ - } else if(sign == LV_SIGNAL_PRESSING) { - int16_t act_val = ext->slider.drag_value; - if(act_val != old_val) ext->changed = 1; -#if USE_LV_ANIMATION - if(lv_sw_get_anim_time(sw) > 0) { - /* Keep forcing the slider to old_val */ - lv_slider_set_value(sw, old_val); + } + else if(sign == LV_SIGNAL_PRESSED) { + + /*Save the x coordinate of the pressed point to see if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p; + lv_indev_get_point(indev, &p); + ext->start_x = p.x; } -#endif - } else if(sign == LV_SIGNAL_PRESS_LOST) { + ext->slided = 0; ext->changed = 0; - if(lv_sw_get_state(sw)) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); - else lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); - } else if(sign == LV_SIGNAL_RELEASED) { + } + else if(sign == LV_SIGNAL_PRESSING) { + /*See if the switch was slid*/ + lv_indev_t * indev = lv_indev_get_act(); + if(indev) { + lv_point_t p = {0,0}; + lv_indev_get_point(indev, &p); + if(LV_MATH_ABS(p.x - ext->start_x) > LV_INDEV_DRAG_LIMIT) ext->slided = 1; + } + + /*If didn't slide then revert the min/max value. So click without slide won't move the switch as a slider*/ + if(ext->slided == 0) { + if(lv_sw_get_state(sw)) ext->slider.drag_value = LV_SWITCH_SLIDER_ANIM_MAX; + else ext->slider.drag_value = 0; + } + + /*If explicitly changed (by slide) don't need to be toggled on release*/ + int16_t threshold = LV_SWITCH_SLIDER_ANIM_MAX / 2; + if((old_val < threshold && ext->slider.drag_value > threshold) || + (old_val > threshold && ext->slider.drag_value < threshold)) + { + ext->changed = 1; + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + if(lv_sw_get_state(sw)) { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); + lv_sw_anim_to_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); + } + else { + lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); + lv_sw_anim_to_value(sw, 0); + } + } + else if(sign == LV_SIGNAL_RELEASED) { + /*If not dragged then toggle the switch*/ if(ext->changed == 0) { + if(lv_sw_get_state(sw)) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); + } + /*If the switch was dragged then calculate the new state based on the current position*/ + else { int16_t v = lv_slider_get_value(sw); - if(v == 0) lv_slider_set_value(sw, 1); - else lv_slider_set_value(sw, 0); + if(v > LV_SWITCH_SLIDER_ANIM_MAX / 2) lv_sw_on_anim(sw); + else lv_sw_off_anim(sw); + + if(slider_action != NULL) res = slider_action(sw); } -#if USE_LV_ANIMATION - else if(lv_sw_get_anim_time(sw) > 0) { - if(old_val == 0) { - lv_slider_set_value(sw, 0); - lv_bar_set_value(sw, 0); - lv_sw_on(sw); - } else { - lv_slider_set_value(sw, LV_SWITCH_SLIDER_ANIM_MAX); - lv_sw_off(sw); - } - } -#endif - - if(lv_sw_get_state(sw)) lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_on); - else lv_slider_set_style(sw, LV_SLIDER_STYLE_KNOB, ext->style_knob_off); - - ext->changed = 0; - - if(slider_action != NULL) res = slider_action(sw); } else if(sign == LV_SIGNAL_CONTROLL) { char c = *((char *)param); if(c == LV_GROUP_KEY_ENTER) { - if(old_val) lv_sw_off(sw); - else lv_sw_on(sw); + if(old_val) lv_sw_off_anim(sw); + else lv_sw_on_anim(sw); if(slider_action) res = slider_action(sw); } else if(c == LV_GROUP_KEY_UP || c == LV_GROUP_KEY_RIGHT) { - lv_sw_on(sw); + lv_sw_on_anim(sw); if(slider_action) res = slider_action(sw); } else if(c == LV_GROUP_KEY_DOWN || c == LV_GROUP_KEY_LEFT) { - lv_sw_off(sw); + lv_sw_off_anim(sw); if(slider_action) res = slider_action(sw); } } else if(sign == LV_SIGNAL_GET_EDITABLE) { @@ -361,4 +380,24 @@ static lv_res_t lv_sw_signal(lv_obj_t * sw, lv_signal_t sign, void * param) return res; } + +static void lv_sw_anim_to_value(lv_obj_t * sw, int16_t value) +{ + lv_anim_t a; + lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw); + a.var = sw; + a.start = ext->slider.bar.cur_value; + a.end = value; + a.fp = (lv_anim_fp_t)lv_slider_set_value; + a.path = lv_anim_path_linear; + a.end_cb = NULL; + a.act_time = 0; + a.time = lv_sw_get_anim_time(sw); + a.playback = 0; + a.playback_pause = 0; + a.repeat = 0; + a.repeat_pause = 0; + lv_anim_create(&a); +} + #endif diff --git a/lv_objx/lv_sw.h b/lv_objx/lv_sw.h index 58f6d3f30..1eee3a50e 100644 --- a/lv_objx/lv_sw.h +++ b/lv_objx/lv_sw.h @@ -32,6 +32,7 @@ extern "C" { /********************* * DEFINES *********************/ +#define LV_SWITCH_SLIDER_ANIM_MAX 1000 /********************** * TYPEDEFS @@ -41,13 +42,13 @@ typedef struct { lv_slider_ext_t slider; /*Ext. of ancestor*/ /*New data for this type */ - lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ - lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ - uint8_t changed :1; /*Indicates the switch explicitly changed by drag*/ + lv_style_t *style_knob_off; /*Style of the knob when the switch is OFF*/ + lv_style_t *style_knob_on; /*Style of the knob when the switch is ON (NULL to use the same as OFF)*/ + lv_coord_t start_x; + uint8_t changed :1; /*Indicates the switch state explicitly changed by drag*/ + uint8_t slided :1; #if USE_LV_ANIMATION uint16_t anim_time; /*switch animation time */ - lv_anim_t cur_anim; /*current active animation */ - uint8_t anim_act :1; #endif } lv_sw_ext_t; @@ -87,6 +88,18 @@ void lv_sw_on(lv_obj_t *sw); */ void lv_sw_off(lv_obj_t *sw); +/** + * Turn ON the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_on_anim(lv_obj_t * sw); + +/** + * Turn OFF the switch with an animation + * @param sw pointer to a switch object + */ +void lv_sw_off_anim(lv_obj_t * sw); + /** * Set a function which will be called when the switch is toggled by the user * @param sw pointer to switch object @@ -126,7 +139,7 @@ void lv_sw_set_anim_time(lv_obj_t *sw, uint16_t anim_time); */ static inline bool lv_sw_get_state(const lv_obj_t *sw) { - return lv_bar_get_value(sw) == 0 ? false : true; + return lv_bar_get_value(sw) < LV_SWITCH_SLIDER_ANIM_MAX / 2 ? false : true; } /**