1 /**
2  * @file lv_bar.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_bar_private.h"
10 #include "../../misc/lv_area_private.h"
11 #include "../../draw/lv_draw_mask_private.h"
12 #include "../../core/lv_obj_private.h"
13 #include "../../core/lv_obj_class_private.h"
14 #if LV_USE_BAR != 0
15 
16 #include "../../draw/lv_draw.h"
17 #include "../../misc/lv_assert.h"
18 #include "../../misc/lv_anim_private.h"
19 #include "../../misc/lv_math.h"
20 
21 /*********************
22  *      DEFINES
23  *********************/
24 #define MY_CLASS (&lv_bar_class)
25 
26 /** hor. pad and ver. pad cannot make the indicator smaller than this [px]*/
27 #define LV_BAR_SIZE_MIN  4
28 
29 #define LV_BAR_IS_ANIMATING(anim_struct) (((anim_struct).anim_state) != LV_BAR_ANIM_STATE_INV)
30 #define LV_BAR_GET_ANIM_VALUE(orig_value, anim_struct) (LV_BAR_IS_ANIMATING(anim_struct) ? ((anim_struct).anim_end) : (orig_value))
31 
32 /** Bar animation start value. (Not the real value of the Bar just indicates process animation)*/
33 #define LV_BAR_ANIM_STATE_START 0
34 
35 /** Bar animation end value.  (Not the real value of the Bar just indicates process animation)*/
36 #define LV_BAR_ANIM_STATE_END   256
37 
38 /** Mark no animation is in progress*/
39 #define LV_BAR_ANIM_STATE_INV   -1
40 
41 /** log2(LV_BAR_ANIM_STATE_END) used to normalize data*/
42 #define LV_BAR_ANIM_STATE_NORM  8
43 
44 /**********************
45  *      TYPEDEFS
46  **********************/
47 
48 /**********************
49  *  STATIC PROTOTYPES
50  **********************/
51 static void lv_bar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
52 static void lv_bar_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
53 static void lv_bar_event(const lv_obj_class_t * class_p, lv_event_t * e);
54 static void draw_indic(lv_event_t * e);
55 static void lv_bar_set_value_with_anim(lv_obj_t * obj, int32_t new_value, int32_t * value_ptr,
56                                        lv_bar_anim_t * anim_info, lv_anim_enable_t en);
57 static void lv_bar_init_anim(lv_obj_t * bar, lv_bar_anim_t * bar_anim);
58 static void lv_bar_anim(void * bar, int32_t value);
59 static void lv_bar_anim_completed(lv_anim_t * a);
60 
61 /**********************
62  *  STATIC VARIABLES
63  **********************/
64 const lv_obj_class_t lv_bar_class = {
65     .constructor_cb = lv_bar_constructor,
66     .destructor_cb = lv_bar_destructor,
67     .event_cb = lv_bar_event,
68     .width_def = LV_DPI_DEF * 2,
69     .height_def = LV_DPI_DEF / 10,
70     .instance_size = sizeof(lv_bar_t),
71     .base_class = &lv_obj_class,
72     .name = "bar",
73 };
74 
75 /**********************
76  *      MACROS
77  **********************/
78 
79 /**********************
80  *   GLOBAL FUNCTIONS
81  **********************/
82 
lv_bar_create(lv_obj_t * parent)83 lv_obj_t * lv_bar_create(lv_obj_t * parent)
84 {
85     LV_LOG_INFO("begin");
86     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
87     lv_obj_class_init_obj(obj);
88     return obj;
89 }
90 
91 /*=====================
92  * Setter functions
93  *====================*/
94 
lv_bar_set_value(lv_obj_t * obj,int32_t value,lv_anim_enable_t anim)95 void lv_bar_set_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim)
96 {
97     LV_ASSERT_OBJ(obj, MY_CLASS);
98     lv_bar_t * bar = (lv_bar_t *)obj;
99 
100     if(bar->cur_value == value) return;
101 
102     value = LV_CLAMP(bar->min_value, value, bar->max_value);
103     value = value < bar->start_value ? bar->start_value : value; /*Can't be smaller than the left value*/
104 
105     if(bar->cur_value == value) return;
106 
107     lv_bar_set_value_with_anim(obj, value, &bar->cur_value, &bar->cur_value_anim, anim);
108 }
109 
lv_bar_set_start_value(lv_obj_t * obj,int32_t value,lv_anim_enable_t anim)110 void lv_bar_set_start_value(lv_obj_t * obj, int32_t value, lv_anim_enable_t anim)
111 {
112     LV_ASSERT_OBJ(obj, MY_CLASS);
113 
114     lv_bar_t * bar = (lv_bar_t *)obj;
115 
116     if(bar->mode != LV_BAR_MODE_RANGE) {
117         return;
118     }
119 
120     value = LV_CLAMP(bar->min_value, value, bar->max_value);
121     value = value > bar->cur_value ? bar->cur_value : value; /*Can't be greater than the right value*/
122 
123     if(bar->start_value == value) return;
124 
125     lv_bar_set_value_with_anim(obj, value, &bar->start_value, &bar->start_value_anim, anim);
126 }
127 
lv_bar_set_range(lv_obj_t * obj,int32_t min,int32_t max)128 void lv_bar_set_range(lv_obj_t * obj, int32_t min, int32_t max)
129 {
130     LV_ASSERT_OBJ(obj, MY_CLASS);
131 
132     lv_bar_t * bar = (lv_bar_t *)obj;
133 
134     bar->val_reversed = min > max;
135 
136     int32_t real_min = bar->val_reversed ? max : min;
137     int32_t real_max = bar->val_reversed ? min : max;
138     if(bar->min_value == real_min && bar->max_value == real_max) return;
139 
140     bar->max_value = real_max;
141     bar->min_value = real_min;
142 
143     if(lv_bar_get_mode(obj) != LV_BAR_MODE_RANGE)
144         bar->start_value = real_min;
145 
146     if(bar->cur_value > real_max) {
147         bar->cur_value = real_max;
148         lv_bar_set_value(obj, bar->cur_value, LV_ANIM_OFF);
149     }
150     if(bar->cur_value < real_min) {
151         bar->cur_value = real_min;
152         lv_bar_set_value(obj, bar->cur_value, LV_ANIM_OFF);
153     }
154 
155     lv_obj_invalidate(obj);
156 }
157 
lv_bar_set_mode(lv_obj_t * obj,lv_bar_mode_t mode)158 void lv_bar_set_mode(lv_obj_t * obj, lv_bar_mode_t mode)
159 {
160     LV_ASSERT_OBJ(obj, MY_CLASS);
161     lv_bar_t * bar = (lv_bar_t *)obj;
162 
163     bar->mode = mode;
164     if(bar->mode != LV_BAR_MODE_RANGE) {
165         bar->start_value = bar->min_value;
166     }
167 
168     lv_obj_invalidate(obj);
169 }
170 
lv_bar_set_orientation(lv_obj_t * obj,lv_bar_orientation_t orientation)171 void lv_bar_set_orientation(lv_obj_t * obj, lv_bar_orientation_t orientation)
172 {
173     LV_ASSERT_OBJ(obj, MY_CLASS);
174     lv_bar_t * bar = (lv_bar_t *)obj;
175 
176     bar->orientation = orientation;
177     lv_obj_invalidate(obj);
178 }
179 
180 /*=====================
181  * Getter functions
182  *====================*/
183 
lv_bar_get_value(const lv_obj_t * obj)184 int32_t lv_bar_get_value(const lv_obj_t * obj)
185 {
186     LV_ASSERT_OBJ(obj, MY_CLASS);
187     lv_bar_t * bar = (lv_bar_t *)obj;
188 
189     return LV_BAR_GET_ANIM_VALUE(bar->cur_value, bar->cur_value_anim);
190 }
191 
lv_bar_get_start_value(const lv_obj_t * obj)192 int32_t lv_bar_get_start_value(const lv_obj_t * obj)
193 {
194     LV_ASSERT_OBJ(obj, MY_CLASS);
195     lv_bar_t * bar = (lv_bar_t *)obj;
196 
197     if(bar->mode != LV_BAR_MODE_RANGE) return bar->min_value;
198 
199     return LV_BAR_GET_ANIM_VALUE(bar->start_value, bar->start_value_anim);
200 }
201 
lv_bar_get_min_value(const lv_obj_t * obj)202 int32_t lv_bar_get_min_value(const lv_obj_t * obj)
203 {
204     LV_ASSERT_OBJ(obj, MY_CLASS);
205     lv_bar_t * bar = (lv_bar_t *)obj;
206     return bar->val_reversed ? bar->max_value : bar->min_value;
207 }
208 
lv_bar_get_max_value(const lv_obj_t * obj)209 int32_t lv_bar_get_max_value(const lv_obj_t * obj)
210 {
211     LV_ASSERT_OBJ(obj, MY_CLASS);
212     lv_bar_t * bar = (lv_bar_t *)obj;
213 
214     return bar->val_reversed ? bar->min_value : bar->max_value;
215 }
216 
lv_bar_get_mode(lv_obj_t * obj)217 lv_bar_mode_t lv_bar_get_mode(lv_obj_t * obj)
218 {
219     LV_ASSERT_OBJ(obj, MY_CLASS);
220     lv_bar_t * bar = (lv_bar_t *)obj;
221 
222     return bar->mode;
223 }
224 
lv_bar_get_orientation(lv_obj_t * obj)225 lv_bar_orientation_t lv_bar_get_orientation(lv_obj_t * obj)
226 {
227     LV_ASSERT_OBJ(obj, MY_CLASS);
228     lv_bar_t * bar = (lv_bar_t *)obj;
229 
230     return bar->orientation;
231 }
232 
lv_bar_is_symmetrical(lv_obj_t * obj)233 bool lv_bar_is_symmetrical(lv_obj_t * obj)
234 {
235     LV_ASSERT_OBJ(obj, MY_CLASS);
236     lv_bar_t * bar = (lv_bar_t *)obj;
237 
238     return  bar->mode == LV_BAR_MODE_SYMMETRICAL && bar->min_value < 0 && bar->max_value > 0 &&
239             bar->start_value == bar->min_value;
240 }
241 
242 /**********************
243  *   STATIC FUNCTIONS
244  **********************/
245 
lv_bar_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)246 static void lv_bar_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
247 {
248     LV_UNUSED(class_p);
249     LV_TRACE_OBJ_CREATE("begin");
250 
251     lv_bar_t * bar = (lv_bar_t *)obj;
252     bar->min_value = 0;
253     bar->max_value = 100;
254     bar->start_value = 0;
255     bar->cur_value = 0;
256     bar->indic_area.x1 = 0;
257     bar->indic_area.x2 = 0;
258     bar->indic_area.y1 = 0;
259     bar->indic_area.y2 = 0;
260     bar->mode = LV_BAR_MODE_NORMAL;
261     bar->orientation = LV_BAR_ORIENTATION_AUTO;
262     bar->val_reversed = false;
263 
264     lv_bar_init_anim(obj, &bar->cur_value_anim);
265     lv_bar_init_anim(obj, &bar->start_value_anim);
266 
267     lv_obj_remove_flag(obj, LV_OBJ_FLAG_CHECKABLE);
268     lv_obj_remove_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
269     lv_bar_set_value(obj, 0, LV_ANIM_OFF);
270 
271     LV_TRACE_OBJ_CREATE("finished");
272 }
273 
lv_bar_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)274 static void lv_bar_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
275 {
276     LV_UNUSED(class_p);
277     lv_bar_t * bar = (lv_bar_t *)obj;
278 
279     lv_anim_delete(&bar->cur_value_anim, NULL);
280     lv_anim_delete(&bar->start_value_anim, NULL);
281 }
282 
draw_indic(lv_event_t * e)283 static void draw_indic(lv_event_t * e)
284 {
285     lv_obj_t * obj = lv_event_get_current_target(e);
286     lv_bar_t * bar = (lv_bar_t *)obj;
287 
288     lv_layer_t * layer = lv_event_get_layer(e);
289 
290     lv_area_t bar_coords;
291     lv_obj_get_coords(obj, &bar_coords);
292 
293     int32_t transf_w = lv_obj_get_style_transform_width(obj, LV_PART_MAIN);
294     int32_t transf_h = lv_obj_get_style_transform_height(obj, LV_PART_MAIN);
295     lv_area_increase(&bar_coords, transf_w, transf_h);
296     int32_t barw = lv_area_get_width(&bar_coords);
297     int32_t barh = lv_area_get_height(&bar_coords);
298     int32_t range = bar->max_value - bar->min_value;
299 
300     /*Prevent division by 0*/
301     if(range == 0) {
302         range = 1;
303     }
304 
305     bool hor = false;
306     switch(bar->orientation) {
307         case LV_BAR_ORIENTATION_HORIZONTAL:
308             hor = true;
309             break;
310         case LV_BAR_ORIENTATION_VERTICAL:
311             hor = false;
312             break;
313         case LV_BAR_ORIENTATION_AUTO:
314         default:
315             hor = (barw >= barh);
316             break;
317     }
318 
319     bool sym = lv_bar_is_symmetrical(obj);
320 
321     /*Calculate the indicator area*/
322     int32_t bg_left = lv_obj_get_style_pad_left(obj,     LV_PART_MAIN);
323     int32_t bg_right = lv_obj_get_style_pad_right(obj,   LV_PART_MAIN);
324     int32_t bg_top = lv_obj_get_style_pad_top(obj,       LV_PART_MAIN);
325     int32_t bg_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
326 
327     /*Respect padding and minimum width/height too*/
328     lv_area_copy(&bar->indic_area, &bar_coords);
329     bar->indic_area.x1 += bg_left;
330     bar->indic_area.x2 -= bg_right;
331     bar->indic_area.y1 += bg_top;
332     bar->indic_area.y2 -= bg_bottom;
333 
334     if(hor && lv_area_get_height(&bar->indic_area) < LV_BAR_SIZE_MIN) {
335         bar->indic_area.y1 = obj->coords.y1 + (barh / 2) - (LV_BAR_SIZE_MIN / 2);
336         bar->indic_area.y2 = bar->indic_area.y1 + LV_BAR_SIZE_MIN;
337     }
338     else if(!hor && lv_area_get_width(&bar->indic_area) < LV_BAR_SIZE_MIN) {
339         bar->indic_area.x1 = obj->coords.x1 + (barw / 2) - (LV_BAR_SIZE_MIN / 2);
340         bar->indic_area.x2 = bar->indic_area.x1 + LV_BAR_SIZE_MIN;
341     }
342     int32_t indic_max_w = lv_area_get_width(&bar->indic_area);
343     int32_t indic_max_h = lv_area_get_height(&bar->indic_area);
344 
345     /*Calculate the indicator length*/
346     int32_t anim_length = hor ? indic_max_w : indic_max_h;
347 
348     int32_t anim_cur_value_x, anim_start_value_x;
349 
350     int32_t * axis1, * axis2;
351     int32_t (*indic_length_calc)(const lv_area_t * area);
352 
353     if(hor) {
354         axis1 = &bar->indic_area.x1;
355         axis2 = &bar->indic_area.x2;
356         indic_length_calc = lv_area_get_width;
357     }
358     else {
359         axis1 = &bar->indic_area.y1;
360         axis2 = &bar->indic_area.y2;
361         indic_length_calc = lv_area_get_height;
362     }
363 
364     if(LV_BAR_IS_ANIMATING(bar->start_value_anim)) {
365         int32_t anim_start_value_start_x =
366             (int32_t)((int32_t)anim_length * (bar->start_value_anim.anim_start - bar->min_value)) / range;
367         int32_t anim_start_value_end_x =
368             (int32_t)((int32_t)anim_length * (bar->start_value_anim.anim_end - bar->min_value)) / range;
369 
370         anim_start_value_x = (((anim_start_value_end_x - anim_start_value_start_x) * bar->start_value_anim.anim_state) /
371                               LV_BAR_ANIM_STATE_END);
372 
373         anim_start_value_x += anim_start_value_start_x;
374     }
375     else {
376         anim_start_value_x = (int32_t)((int32_t)anim_length * (bar->start_value - bar->min_value)) / range;
377     }
378 
379     if(LV_BAR_IS_ANIMATING(bar->cur_value_anim)) {
380         int32_t anim_cur_value_start_x =
381             (int32_t)((int32_t)anim_length * (bar->cur_value_anim.anim_start - bar->min_value)) / range;
382         int32_t anim_cur_value_end_x =
383             (int32_t)((int32_t)anim_length * (bar->cur_value_anim.anim_end - bar->min_value)) / range;
384 
385         anim_cur_value_x = anim_cur_value_start_x + (((anim_cur_value_end_x - anim_cur_value_start_x) *
386                                                       bar->cur_value_anim.anim_state) /
387                                                      LV_BAR_ANIM_STATE_END);
388     }
389     else {
390         anim_cur_value_x = (int32_t)((int32_t)anim_length * (bar->cur_value - bar->min_value)) / range;
391     }
392 
393     /**
394      * The drawing direction of the bar can be reversed only when one of the two conditions(value inversion
395      * or horizontal direction base dir is LV_BASE_DIR_RTL) is met.
396     */
397     lv_base_dir_t base_dir = lv_obj_get_style_base_dir(obj, LV_PART_MAIN);
398     bool hor_need_reversed = hor && base_dir == LV_BASE_DIR_RTL;
399     bool reversed = bar->val_reversed ^ hor_need_reversed;
400 
401     if(reversed) {
402         /*Swap axes*/
403         int32_t * tmp;
404         tmp = axis1;
405         axis1 = axis2;
406         axis2 = tmp;
407         anim_cur_value_x = -anim_cur_value_x;
408         anim_start_value_x = -anim_start_value_x;
409     }
410 
411     /*Set the indicator length*/
412     if(hor) {
413         *axis2 = *axis1 + anim_cur_value_x;
414         *axis1 += anim_start_value_x;
415     }
416     else {
417         *axis1 = *axis2 - anim_cur_value_x + 1;
418         *axis2 -= anim_start_value_x;
419     }
420 
421     if(sym) {
422         int32_t zero, shift;
423         shift = (-bar->min_value * anim_length) / range;
424 
425         if(hor) {
426             int32_t * left = reversed ? axis2 : axis1;
427             int32_t * right = reversed ? axis1 : axis2;
428             if(reversed)
429                 zero = *axis1 - shift + 1;
430             else
431                 zero = *axis1 + shift;
432 
433             if(*axis2 > zero) {
434                 *right = *axis2;
435                 *left = zero;
436             }
437             else {
438                 *left = *axis2;
439                 *right = zero;
440             }
441         }
442         else {
443             int32_t * top = reversed ? axis2 : axis1;
444             int32_t * bottom = reversed ? axis1 : axis2;
445             if(reversed)
446                 zero = *axis2 + shift;
447             else
448                 zero = *axis2 - shift + 1;
449 
450             if(*axis1 > zero) {
451                 *bottom = *axis1;
452                 *top = zero;
453             }
454             else {
455                 *top = *axis1;
456                 *bottom = zero;
457             }
458         }
459     }
460 
461     /*Do not draw a zero length indicator but at least call the draw task event*/
462     if(!sym && indic_length_calc(&bar->indic_area) <= 1) {
463         lv_obj_send_event(obj, LV_EVENT_DRAW_TASK_ADDED, NULL);
464         return;
465     }
466 
467     lv_area_t indic_area;
468     lv_area_copy(&indic_area, &bar->indic_area);
469 
470     lv_draw_rect_dsc_t draw_rect_dsc;
471     lv_draw_rect_dsc_init(&draw_rect_dsc);
472     draw_rect_dsc.base.layer = layer;
473     lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &draw_rect_dsc);
474 
475     int32_t bg_radius = lv_obj_get_style_radius(obj, LV_PART_MAIN);
476     int32_t short_side = LV_MIN(barw, barh);
477     if(bg_radius > short_side >> 1) bg_radius = short_side >> 1;
478 
479     int32_t indic_radius = draw_rect_dsc.radius;
480     short_side = LV_MIN(lv_area_get_width(&bar->indic_area), lv_area_get_height(&bar->indic_area));
481     if(indic_radius > short_side >> 1) indic_radius = short_side >> 1;
482 
483     /*Cases:
484      * Simple:
485      *   - indicator area is the same or smaller then the bg
486      *   - indicator has the same or larger radius than the bg
487      *   - what to do? just draw the indicator
488      * Radius issue:
489      *   - indicator area is the same or smaller then bg
490      *   - indicator has smaller radius than the bg and the indicator overflows on the corners
491      *   - what to do? draw the indicator on a layer and clip to bg radius
492      * Larger indicator:
493      *   - indicator area is the larger then the bg
494      *   - radius doesn't matter
495      *   - shadow doesn't matter
496      *   - what to do? just draw the indicator
497      * Shadow:
498      *   - indicator area is the same or smaller then the bg
499      *   - indicator has the same or larger radius than the bg (shadow needs to be drawn on strange clipped shape)
500      *   - what to do? don't draw the shadow if the indicator is too small has strange shape
501      * Gradient:
502      *   - the indicator has a gradient
503      *   - what to do? draw it on a bg sized layer clip the indicator are from the gradient
504      *
505      */
506 
507     bool mask_needed = false;
508     if(hor && draw_rect_dsc.bg_grad.dir == LV_GRAD_DIR_HOR) mask_needed = true;
509     else if(!hor && draw_rect_dsc.bg_grad.dir == LV_GRAD_DIR_VER) mask_needed = true;
510 
511     if(draw_rect_dsc.bg_image_src) mask_needed = true;
512 
513     bool radius_issue = true;
514     /*The indicator is fully drawn if it's larger than the bg*/
515     if((bg_left < 0 || bg_right < 0 || bg_top < 0 || bg_bottom < 0)) radius_issue = false;
516     else if(indic_radius >= bg_radius) radius_issue = false;
517     else if(lv_area_is_in(&indic_area, &bar_coords, bg_radius)) radius_issue = false;
518 
519     if(radius_issue || mask_needed) {
520         if(!radius_issue) {
521             /*Draw only the shadow*/
522             lv_draw_rect_dsc_t draw_tmp_dsc = draw_rect_dsc;
523             draw_tmp_dsc.border_opa = 0;
524             draw_tmp_dsc.outline_opa = 0;
525             draw_tmp_dsc.bg_opa = 0;
526             draw_tmp_dsc.bg_image_opa = 0;
527             lv_draw_rect(layer, &draw_tmp_dsc, &indic_area);
528         }
529         else {
530             draw_rect_dsc.border_opa = 0;
531             draw_rect_dsc.outline_opa = 0;
532         }
533         draw_rect_dsc.shadow_opa = 0;
534 
535         /*If clipped for any reason cannot the border, outline, and shadow
536          *as they would be clipped and looked ugly*/
537         lv_draw_rect_dsc_t draw_tmp_dsc = draw_rect_dsc;
538         draw_tmp_dsc.border_opa = 0;
539         draw_tmp_dsc.outline_opa = 0;
540         draw_tmp_dsc.shadow_opa = 0;
541         lv_area_t indic_draw_area = indic_area;
542         if(mask_needed) {
543             if(hor) {
544                 indic_draw_area.x1 = bar_coords.x1 + bg_left;
545                 indic_draw_area.x2 = bar_coords.x2 - bg_right;
546             }
547             else {
548                 indic_draw_area.y1 = bar_coords.y1 + bg_top;
549                 indic_draw_area.y2 = bar_coords.y2 - bg_bottom;
550             }
551             draw_tmp_dsc.radius = 0;
552         }
553 
554         lv_layer_t * layer_indic = lv_draw_layer_create(layer, LV_COLOR_FORMAT_ARGB8888, &indic_draw_area);
555 
556         lv_draw_rect(layer_indic, &draw_tmp_dsc, &indic_draw_area);
557 
558         lv_draw_mask_rect_dsc_t mask_dsc;
559         lv_draw_mask_rect_dsc_init(&mask_dsc);
560         if(radius_issue) {
561             mask_dsc.area = bar_coords;
562             mask_dsc.radius = bg_radius;
563             lv_draw_mask_rect(layer_indic, &mask_dsc);
564         }
565 
566         if(mask_needed) {
567             mask_dsc.area = indic_area;
568             mask_dsc.radius = indic_radius;
569             lv_draw_mask_rect(layer_indic, &mask_dsc);
570         }
571 
572         lv_draw_image_dsc_t layer_draw_dsc;
573         lv_draw_image_dsc_init(&layer_draw_dsc);
574         layer_draw_dsc.src = layer_indic;
575         lv_draw_layer(layer, &layer_draw_dsc, &indic_draw_area);
576 
577         /*Add the border, outline, and shadow only to the indicator area.
578          *They might have disabled if there is a radius_issue*/
579         draw_tmp_dsc = draw_rect_dsc;
580         draw_tmp_dsc.bg_opa = 0;
581         draw_tmp_dsc.bg_image_opa = 0;
582         lv_draw_rect(layer, &draw_tmp_dsc, &indic_area);
583     }
584     else {
585         lv_draw_rect(layer, &draw_rect_dsc, &indic_area);
586     }
587 }
588 
lv_bar_event(const lv_obj_class_t * class_p,lv_event_t * e)589 static void lv_bar_event(const lv_obj_class_t * class_p, lv_event_t * e)
590 {
591     LV_UNUSED(class_p);
592 
593     lv_result_t res;
594 
595     /*Call the ancestor's event handler*/
596     res = lv_obj_event_base(MY_CLASS, e);
597     if(res != LV_RESULT_OK) return;
598 
599     lv_event_code_t code = lv_event_get_code(e);
600     lv_obj_t * obj = lv_event_get_current_target(e);
601 
602     if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
603         int32_t indic_size;
604         indic_size = lv_obj_calculate_ext_draw_size(obj, LV_PART_INDICATOR);
605 
606         /*Bg size is handled by lv_obj*/
607         int32_t * s = lv_event_get_param(e);
608         *s = LV_MAX(*s, indic_size);
609 
610         /*Calculate the indicator area*/
611         int32_t bg_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
612         int32_t bg_right = lv_obj_get_style_pad_right(obj, LV_PART_MAIN);
613         int32_t bg_top = lv_obj_get_style_pad_top(obj, LV_PART_MAIN);
614         int32_t bg_bottom = lv_obj_get_style_pad_bottom(obj, LV_PART_MAIN);
615 
616         int32_t pad = LV_MIN4(bg_left, bg_right, bg_top, bg_bottom);
617         if(pad < 0) {
618             *s = *s - pad;
619         }
620     }
621     else if(code == LV_EVENT_PRESSED || code == LV_EVENT_RELEASED) {
622         lv_bar_t * bar = (lv_bar_t *)obj;
623         lv_obj_invalidate_area(obj, &bar->indic_area);
624     }
625     else if(code == LV_EVENT_DRAW_MAIN) {
626         draw_indic(e);
627     }
628 }
629 
lv_bar_anim(void * var,int32_t value)630 static void lv_bar_anim(void * var, int32_t value)
631 {
632     lv_bar_anim_t * bar_anim = var;
633     bar_anim->anim_state    = value;
634     lv_obj_invalidate(bar_anim->bar);
635 }
636 
lv_bar_anim_completed(lv_anim_t * a)637 static void lv_bar_anim_completed(lv_anim_t * a)
638 {
639     lv_bar_anim_t * var = a->var;
640     lv_obj_t * obj = (lv_obj_t *)var->bar;
641     lv_bar_t * bar = (lv_bar_t *)obj;
642 
643     var->anim_state = LV_BAR_ANIM_STATE_INV;
644     if(var == &bar->cur_value_anim)
645         bar->cur_value = var->anim_end;
646     else if(var == &bar->start_value_anim)
647         bar->start_value = var->anim_end;
648     lv_obj_invalidate(var->bar);
649 }
650 
lv_bar_set_value_with_anim(lv_obj_t * obj,int32_t new_value,int32_t * value_ptr,lv_bar_anim_t * anim_info,lv_anim_enable_t en)651 static void lv_bar_set_value_with_anim(lv_obj_t * obj, int32_t new_value, int32_t * value_ptr,
652                                        lv_bar_anim_t * anim_info, lv_anim_enable_t en)
653 {
654     if(en == LV_ANIM_OFF) {
655         lv_anim_delete(anim_info, NULL);
656         anim_info->anim_state = LV_BAR_ANIM_STATE_INV;
657         *value_ptr = new_value;
658         lv_obj_invalidate((lv_obj_t *)obj);
659 
660         /*Stop the previous animation if it exists*/
661         lv_anim_delete(anim_info, NULL);
662         /*Reset animation state*/
663         lv_bar_init_anim(obj, anim_info);
664     }
665     else {
666         /*No animation in progress -> simply set the values*/
667         if(anim_info->anim_state == LV_BAR_ANIM_STATE_INV) {
668             anim_info->anim_start = *value_ptr;
669             anim_info->anim_end   = new_value;
670         }
671         /*Animation in progress. Start from the animation end value*/
672         else {
673             anim_info->anim_start = anim_info->anim_end;
674             anim_info->anim_end   = new_value;
675         }
676         *value_ptr = new_value;
677         /*Stop the previous animation if it exists*/
678         lv_anim_delete(anim_info, NULL);
679 
680         lv_anim_t a;
681         lv_anim_init(&a);
682         lv_anim_set_var(&a, anim_info);
683         lv_anim_set_exec_cb(&a, lv_bar_anim);
684         lv_anim_set_values(&a, LV_BAR_ANIM_STATE_START, LV_BAR_ANIM_STATE_END);
685         lv_anim_set_completed_cb(&a, lv_bar_anim_completed);
686         lv_anim_set_duration(&a, lv_obj_get_style_anim_duration(obj, LV_PART_MAIN));
687         lv_anim_start(&a);
688     }
689 }
690 
lv_bar_init_anim(lv_obj_t * obj,lv_bar_anim_t * bar_anim)691 static void lv_bar_init_anim(lv_obj_t * obj, lv_bar_anim_t * bar_anim)
692 {
693     bar_anim->bar = obj;
694     bar_anim->anim_start = 0;
695     bar_anim->anim_end = 0;
696     bar_anim->anim_state = LV_BAR_ANIM_STATE_INV;
697 }
698 
699 #endif
700