1 
2 
3 /**
4  * @file lv_bar.c
5  *
6  */
7 
8 /*********************
9  *      INCLUDES
10  *********************/
11 #include "lv_bar.h"
12 #if LV_USE_BAR != 0
13 
14 #include "../lv_misc/lv_debug.h"
15 #include "../lv_draw/lv_draw.h"
16 #include "../lv_themes/lv_theme.h"
17 #include "../lv_misc/lv_anim.h"
18 #include "../lv_misc/lv_math.h"
19 #include <stdio.h>
20 
21 /*********************
22  *      DEFINES
23  *********************/
24 #define LV_OBJX_NAME "lv_bar"
25 
26 #define LV_BAR_SIZE_MIN  4   /*hor. pad and ver. pad cannot make the indicator smaller then this [px]*/
27 
28 #if LV_USE_ANIMATION
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 #else
32     #define LV_BAR_GET_ANIM_VALUE(orig_value, anim_struct) (orig_value)
33 #endif
34 /**********************
35  *      TYPEDEFS
36  **********************/
37 
38 /**********************
39  *  STATIC PROTOTYPES
40  **********************/
41 static lv_design_res_t lv_bar_design(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode);
42 static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param);
43 static lv_style_list_t * lv_bar_get_style(lv_obj_t * bar, uint8_t part);
44 
45 static void draw_bg(lv_obj_t * bar, const lv_area_t * clip_area);
46 static void draw_indic(lv_obj_t * bar, const lv_area_t * clip_area);
47 
48 #if LV_USE_ANIMATION
49 static void lv_bar_set_value_with_anim(lv_obj_t * bar, int16_t new_value, int16_t * value_ptr,
50                                        lv_bar_anim_t * anim_info, lv_anim_enable_t en);
51 static void lv_bar_init_anim(lv_obj_t * bar, lv_bar_anim_t * bar_anim);
52 static void lv_bar_anim(lv_bar_anim_t * bar, lv_anim_value_t value);
53 static void lv_bar_anim_ready(lv_anim_t * a);
54 #endif
55 
56 /**********************
57  *  STATIC VARIABLES
58  **********************/
59 static lv_design_cb_t ancestor_design_f;
60 static lv_signal_cb_t ancestor_signal;
61 
62 /**********************
63  *      MACROS
64  **********************/
65 
66 /**********************
67  *   GLOBAL FUNCTIONS
68  **********************/
69 
70 /**
71  * Create a bar objects
72  * @param par pointer to an object, it will be the parent of the new bar
73  * @param copy pointer to a bar object, if not NULL then the new object will be copied from it
74  * @return pointer to the created bar
75  */
lv_bar_create(lv_obj_t * par,const lv_obj_t * copy)76 lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
77 {
78     LV_LOG_TRACE("lv_bar create started");
79 
80     /*Create the ancestor basic object*/
81     lv_obj_t * bar = lv_obj_create(par, copy);
82     LV_ASSERT_MEM(bar);
83     if(bar == NULL) return NULL;
84 
85     if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(bar);
86     if(ancestor_design_f == NULL) ancestor_design_f = lv_obj_get_design_cb(bar);
87 
88     /*Allocate the object type specific extended data*/
89     lv_bar_ext_t * ext = lv_obj_allocate_ext_attr(bar, sizeof(lv_bar_ext_t));
90     LV_ASSERT_MEM(ext);
91     if(ext == NULL) {
92         lv_obj_del(bar);
93         return NULL;
94     }
95 
96     ext->min_value = 0;
97     ext->start_value = 0;
98     ext->max_value = 100;
99     ext->cur_value = 0;
100 #if LV_USE_ANIMATION
101     ext->anim_time  = 200;
102     lv_bar_init_anim(bar, &ext->cur_value_anim);
103     lv_bar_init_anim(bar, &ext->start_value_anim);
104 #endif
105     ext->type         = LV_BAR_TYPE_NORMAL;
106 
107     lv_style_list_init(&ext->style_indic);
108 
109     lv_obj_set_signal_cb(bar, lv_bar_signal);
110     lv_obj_set_design_cb(bar, lv_bar_design);
111 
112 
113     /*Init the new  bar object*/
114     if(copy == NULL) {
115 
116         lv_obj_set_click(bar, false);
117         lv_obj_set_size(bar, LV_DPI * 2, LV_DPI / 10);
118         lv_bar_set_value(bar, ext->cur_value, false);
119 
120         lv_theme_apply(bar, LV_THEME_BAR);
121     }
122     else {
123         lv_bar_ext_t * ext_copy = lv_obj_get_ext_attr(copy);
124         ext->min_value          = ext_copy->min_value;
125         ext->start_value        = ext_copy->start_value;
126         ext->max_value          = ext_copy->max_value;
127         ext->cur_value          = ext_copy->cur_value;
128         ext->type                = ext_copy->type;
129 
130         lv_style_list_copy(&ext->style_indic, &ext_copy->style_indic);
131 
132         /*Refresh the style with new signal function*/
133         lv_obj_refresh_style(bar, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
134 
135         lv_bar_set_value(bar, ext->cur_value, LV_ANIM_OFF);
136     }
137 
138     LV_LOG_INFO("bar created");
139 
140     return bar;
141 }
142 
143 /*=====================
144  * Setter functions
145  *====================*/
146 
147 /**
148  * Set a new value on the bar
149  * @param bar pointer to a bar object
150  * @param value new value
151  * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately
152  */
lv_bar_set_value(lv_obj_t * bar,int16_t value,lv_anim_enable_t anim)153 void lv_bar_set_value(lv_obj_t * bar, int16_t value, lv_anim_enable_t anim)
154 {
155     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
156 
157     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
158     if(ext->cur_value == value) return;
159 
160     int16_t new_value;
161     new_value = value > ext->max_value ? ext->max_value : value;
162     new_value = new_value < ext->min_value ? ext->min_value : new_value;
163 
164     if(ext->cur_value == new_value) return;
165 #if LV_USE_ANIMATION == 0
166     LV_UNUSED(anim);
167     ext->cur_value = new_value;
168     lv_obj_invalidate(bar);
169 #else
170     lv_bar_set_value_with_anim(bar, new_value, &ext->cur_value, &ext->cur_value_anim, anim);
171 #endif
172 }
173 
174 /**
175  * Set a new start value on the bar
176  * @param bar pointer to a bar object
177  * @param value new start value
178  * @param anim LV_ANIM_ON: set the value with an animation; LV_ANIM_OFF: change the value immediately
179  */
lv_bar_set_start_value(lv_obj_t * bar,int16_t start_value,lv_anim_enable_t anim)180 void lv_bar_set_start_value(lv_obj_t * bar, int16_t start_value, lv_anim_enable_t anim)
181 {
182     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
183 
184     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
185     if(ext->start_value == start_value) return;
186 
187     int16_t new_value;
188     new_value = start_value > ext->max_value ? ext->max_value : start_value;
189     new_value = new_value < ext->min_value ? ext->min_value : start_value;
190 
191     if(ext->start_value == new_value) return;
192 #if LV_USE_ANIMATION == 0
193     LV_UNUSED(anim);
194     ext->start_value = new_value;
195 #else
196     lv_bar_set_value_with_anim(bar, new_value, &ext->start_value, &ext->start_value_anim, anim);
197 #endif
198 }
199 
200 /**
201  * Set minimum and the maximum values of a bar
202  * @param bar pointer to the bar object
203  * @param min minimum value
204  * @param max maximum value
205  */
lv_bar_set_range(lv_obj_t * bar,int16_t min,int16_t max)206 void lv_bar_set_range(lv_obj_t * bar, int16_t min, int16_t max)
207 {
208     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
209 
210     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
211     if(ext->min_value == min && ext->max_value == max) return;
212 
213     ext->max_value = max;
214     ext->min_value = min;
215 
216     if(lv_bar_get_type(bar) != LV_BAR_TYPE_CUSTOM)
217         ext->start_value = min;
218 
219     if(ext->cur_value > max) {
220         ext->cur_value = max;
221         lv_bar_set_value(bar, ext->cur_value, false);
222     }
223     if(ext->cur_value < min) {
224         ext->cur_value = min;
225         lv_bar_set_value(bar, ext->cur_value, false);
226     }
227     lv_obj_invalidate(bar);
228 }
229 
230 /**
231  * Set the type of bar.
232  * @param bar pointer to bar object
233  * @param type bar type
234  */
lv_bar_set_type(lv_obj_t * bar,lv_bar_type_t type)235 void lv_bar_set_type(lv_obj_t * bar, lv_bar_type_t type)
236 {
237     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
238 
239     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
240     ext->type = type;
241     if(ext->type != LV_BAR_TYPE_CUSTOM)
242         ext->start_value = ext->min_value;
243 
244     lv_obj_invalidate(bar);
245 }
246 
247 /**
248  * Set the animation time of the bar
249  * @param bar pointer to a bar object
250  * @param anim_time the animation time in milliseconds.
251  */
lv_bar_set_anim_time(lv_obj_t * bar,uint16_t anim_time)252 void lv_bar_set_anim_time(lv_obj_t * bar, uint16_t anim_time)
253 {
254     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
255 
256 #if LV_USE_ANIMATION
257     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
258     ext->anim_time     = anim_time;
259 #else
260     (void)bar;       /*Unused*/
261     (void)anim_time; /*Unused*/
262 #endif
263 }
264 
265 /*=====================
266  * Getter functions
267  *====================*/
268 
269 /**
270  * Get the value of a bar
271  * @param bar pointer to a bar object
272  * @return the value of the bar
273  */
lv_bar_get_value(const lv_obj_t * bar)274 int16_t lv_bar_get_value(const lv_obj_t * bar)
275 {
276     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
277 
278     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
279     return LV_BAR_GET_ANIM_VALUE(ext->cur_value, ext->cur_value_anim);
280 }
281 
282 /**
283  * Get the start value of a bar
284  * @param bar pointer to a bar object
285  * @return the start value of the bar
286  */
lv_bar_get_start_value(const lv_obj_t * bar)287 int16_t lv_bar_get_start_value(const lv_obj_t * bar)
288 {
289     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
290 
291     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
292 
293     if(ext->type != LV_BAR_TYPE_CUSTOM) return ext->min_value;
294 
295     return LV_BAR_GET_ANIM_VALUE(ext->start_value, ext->start_value_anim);
296 }
297 
298 /**
299  * Get the minimum value of a bar
300  * @param bar pointer to a bar object
301  * @return the minimum value of the bar
302  */
lv_bar_get_min_value(const lv_obj_t * bar)303 int16_t lv_bar_get_min_value(const lv_obj_t * bar)
304 {
305     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
306 
307     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
308     return ext->min_value;
309 }
310 
311 /**
312  * Get the maximum value of a bar
313  * @param bar pointer to a bar object
314  * @return the maximum value of the bar
315  */
lv_bar_get_max_value(const lv_obj_t * bar)316 int16_t lv_bar_get_max_value(const lv_obj_t * bar)
317 {
318     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
319 
320     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
321     return ext->max_value;
322 }
323 
324 /**
325  * Get the type of bar.
326  * @param bar pointer to bar object
327  * @return bar type
328  */
lv_bar_get_type(lv_obj_t * bar)329 lv_bar_type_t lv_bar_get_type(lv_obj_t * bar)
330 {
331     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
332 
333     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
334     return ext->type;
335 }
336 
337 /**
338  * Get the animation time of the bar
339  * @param bar pointer to a bar object
340  * @return the animation time in milliseconds.
341  */
lv_bar_get_anim_time(const lv_obj_t * bar)342 uint16_t lv_bar_get_anim_time(const lv_obj_t * bar)
343 {
344     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
345 
346 #if LV_USE_ANIMATION
347     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
348     return ext->anim_time;
349 #else
350     (void)bar;       /*Unused*/
351     return 0;
352 #endif
353 }
354 
355 
356 /**********************
357  *   STATIC FUNCTIONS
358  **********************/
359 
360 /**
361  * Handle the drawing related tasks of the bars
362  * @param bar pointer to an object
363  * @param clip_area the object will be drawn only in this area
364  * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
365  *                                  (return 'true' if yes)
366  *             LV_DESIGN_DRAW: draw the object (always return 'true')
367  *             LV_DESIGN_DRAW_POST: drawing after every children are drawn
368  * @param return an element of `lv_design_res_t`
369  */
lv_bar_design(lv_obj_t * bar,const lv_area_t * clip_area,lv_design_mode_t mode)370 static lv_design_res_t lv_bar_design(lv_obj_t * bar, const lv_area_t * clip_area, lv_design_mode_t mode)
371 {
372     if(mode == LV_DESIGN_COVER_CHK) {
373         /*Return false if the object is not covers the mask area*/
374         return ancestor_design_f(bar, clip_area, mode);
375     }
376     else if(mode == LV_DESIGN_DRAW_MAIN) {
377         draw_bg(bar, clip_area);
378         draw_indic(bar, clip_area);
379 
380         /*Get the value and draw it after the indicator*/
381         lv_draw_rect_dsc_t draw_dsc;
382         lv_draw_rect_dsc_init(&draw_dsc);
383         draw_dsc.bg_opa = LV_OPA_TRANSP;
384         draw_dsc.border_opa = LV_OPA_TRANSP;
385         draw_dsc.shadow_opa = LV_OPA_TRANSP;
386         draw_dsc.pattern_opa = LV_OPA_TRANSP;
387         draw_dsc.outline_opa = LV_OPA_TRANSP;
388         lv_obj_init_draw_rect_dsc(bar, LV_BAR_PART_BG, &draw_dsc);
389         lv_draw_rect(&bar->coords, clip_area, &draw_dsc);
390     }
391     else if(mode == LV_DESIGN_DRAW_POST) {
392         /*If the border is drawn later disable loading other properties*/
393         if(lv_obj_get_style_border_post(bar, LV_OBJ_PART_MAIN)) {
394             lv_draw_rect_dsc_t draw_dsc;
395             lv_draw_rect_dsc_init(&draw_dsc);
396             draw_dsc.bg_opa = LV_OPA_TRANSP;
397             draw_dsc.pattern_opa = LV_OPA_TRANSP;
398             draw_dsc.outline_opa = LV_OPA_TRANSP;
399             draw_dsc.shadow_opa = LV_OPA_TRANSP;
400             draw_dsc.value_opa = LV_OPA_TRANSP;
401             lv_obj_init_draw_rect_dsc(bar, LV_OBJ_PART_MAIN, &draw_dsc);
402 
403             lv_draw_rect(&bar->coords, clip_area, &draw_dsc);
404         }
405     }
406     return LV_DESIGN_RES_OK;
407 }
408 
draw_bg(lv_obj_t * bar,const lv_area_t * clip_area)409 static void draw_bg(lv_obj_t * bar, const lv_area_t * clip_area)
410 {
411     /*Simply draw the background*/
412     lv_draw_rect_dsc_t draw_dsc;
413     lv_draw_rect_dsc_init(&draw_dsc);
414     /*If the border is drawn later disable loading its properties*/
415     if(lv_obj_get_style_border_post(bar, LV_BAR_PART_BG)) {
416         draw_dsc.border_opa = LV_OPA_TRANSP;
417     }
418 
419     /*value will be drawn later*/
420     draw_dsc.value_opa = LV_OPA_TRANSP;
421     lv_obj_init_draw_rect_dsc(bar, LV_BAR_PART_BG, &draw_dsc);
422     lv_draw_rect(&bar->coords, clip_area, &draw_dsc);
423 
424 }
425 
draw_indic(lv_obj_t * bar,const lv_area_t * clip_area)426 static void draw_indic(lv_obj_t * bar, const lv_area_t * clip_area)
427 {
428     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
429     lv_bidi_dir_t base_dir = lv_obj_get_base_dir(bar);
430 
431     lv_coord_t objw = lv_obj_get_width(bar);
432     lv_coord_t objh = lv_obj_get_height(bar);
433     int32_t range = ext->max_value - ext->min_value;
434     bool hor = objw >= objh ? true : false;
435     bool sym = false;
436     if(ext->type == LV_BAR_TYPE_SYMMETRICAL && ext->min_value < 0 && ext->max_value > 0 &&
437        ext->start_value == ext->min_value) sym = true;
438 
439     /*Calculate the indicator area*/
440     lv_style_int_t bg_left = lv_obj_get_style_pad_left(bar,     LV_BAR_PART_BG);
441     lv_style_int_t bg_right = lv_obj_get_style_pad_right(bar,   LV_BAR_PART_BG);
442     lv_style_int_t bg_top = lv_obj_get_style_pad_top(bar,       LV_BAR_PART_BG);
443     lv_style_int_t bg_bottom = lv_obj_get_style_pad_bottom(bar, LV_BAR_PART_BG);
444 
445     /*Respect padding and minimum width/height too*/
446     lv_area_copy(&ext->indic_area, &bar->coords);
447     ext->indic_area.x1 += bg_left;
448     ext->indic_area.x2 -= bg_right;
449     ext->indic_area.y1 += bg_top;
450     ext->indic_area.y2 -= bg_bottom;
451 
452     if(hor && lv_area_get_height(&ext->indic_area) < LV_BAR_SIZE_MIN) {
453         ext->indic_area.y1 = bar->coords.y1 + (objh / 2) - (LV_BAR_SIZE_MIN / 2);
454         ext->indic_area.y2 = ext->indic_area.y1 + LV_BAR_SIZE_MIN;
455     }
456     else if(!hor && lv_area_get_width(&ext->indic_area) < LV_BAR_SIZE_MIN) {
457         ext->indic_area.x1 = bar->coords.x1 + (objw / 2) - (LV_BAR_SIZE_MIN / 2);
458         ext->indic_area.x2 = ext->indic_area.x1 + LV_BAR_SIZE_MIN;
459     }
460 
461     lv_coord_t indicw = lv_area_get_width(&ext->indic_area);
462     lv_coord_t indich = lv_area_get_height(&ext->indic_area);
463 
464     /*Calculate the indicator length*/
465     lv_coord_t anim_length = hor ? indicw : indich;
466 
467     lv_coord_t anim_cur_value_x, anim_start_value_x;
468 
469     lv_coord_t * axis1, * axis2;
470     lv_coord_t (*indic_length_calc)(const lv_area_t * area);
471 
472     if(hor) {
473         axis1 = &ext->indic_area.x1;
474         axis2 = &ext->indic_area.x2;
475         indic_length_calc = lv_area_get_width;
476     }
477     else {
478         axis1 = &ext->indic_area.y1;
479         axis2 = &ext->indic_area.y2;
480         indic_length_calc = lv_area_get_height;
481     }
482 
483 #if LV_USE_ANIMATION
484     if(LV_BAR_IS_ANIMATING(ext->start_value_anim)) {
485         lv_coord_t anim_start_value_start_x =
486             (int32_t)((int32_t)anim_length * (ext->start_value_anim.anim_start - ext->min_value)) / range;
487         lv_coord_t anim_start_value_end_x =
488             (int32_t)((int32_t)anim_length * (ext->start_value_anim.anim_end - ext->min_value)) / range;
489 
490         anim_start_value_x = (((anim_start_value_end_x - anim_start_value_start_x) * ext->start_value_anim.anim_state) /
491                               LV_BAR_ANIM_STATE_END);
492 
493         anim_start_value_x += anim_start_value_start_x;
494     }
495     else
496 #endif
497     {
498         anim_start_value_x = (int32_t)((int32_t)anim_length * (ext->start_value - ext->min_value)) / range;
499     }
500 
501 #if LV_USE_ANIMATION
502     if(LV_BAR_IS_ANIMATING(ext->cur_value_anim)) {
503         lv_coord_t anim_cur_value_start_x =
504             (int32_t)((int32_t)anim_length * (ext->cur_value_anim.anim_start - ext->min_value)) / range;
505         lv_coord_t anim_cur_value_end_x =
506             (int32_t)((int32_t)anim_length * (ext->cur_value_anim.anim_end - ext->min_value)) / range;
507 
508         anim_cur_value_x = anim_cur_value_start_x + (((anim_cur_value_end_x - anim_cur_value_start_x) *
509                                                       ext->cur_value_anim.anim_state) /
510                                                      LV_BAR_ANIM_STATE_END);
511     }
512     else
513 #endif
514     {
515         anim_cur_value_x = (int32_t)((int32_t)anim_length * (ext->cur_value - ext->min_value)) / range;
516     }
517 
518     if(hor && base_dir == LV_BIDI_DIR_RTL) {
519         /* Swap axes */
520         lv_coord_t * tmp;
521         tmp = axis1;
522         axis1 = axis2;
523         axis2 = tmp;
524         anim_cur_value_x = -anim_cur_value_x;
525         anim_start_value_x = -anim_start_value_x;
526     }
527 
528     /* Set the indicator length */
529     if(hor) {
530         *axis2 = *axis1 + anim_cur_value_x;
531         *axis1 += anim_start_value_x;
532     }
533     else {
534         *axis1 = *axis2 - anim_cur_value_x;
535         *axis2 -= anim_start_value_x;
536     }
537     if(sym) {
538         lv_coord_t zero;
539         zero = *axis1 + (-ext->min_value * anim_length) / range;
540         if(*axis2 > zero)
541             *axis1 = zero;
542         else {
543             *axis1 = *axis2;
544             *axis2 = zero;
545         }
546     }
547 
548     /*Draw the indicator*/
549 
550     /*Do not draw a zero length indicator*/
551     if(!sym && indic_length_calc(&ext->indic_area) <= 1) return;
552 
553     uint16_t bg_radius = lv_obj_get_style_radius(bar, LV_BAR_PART_BG);
554     lv_coord_t short_side = LV_MATH_MIN(objw, objh);
555     if(bg_radius > short_side >> 1) bg_radius = short_side >> 1;
556 
557     lv_draw_rect_dsc_t draw_indic_dsc;
558     lv_draw_rect_dsc_init(&draw_indic_dsc);
559     lv_obj_init_draw_rect_dsc(bar, LV_BAR_PART_INDIC, &draw_indic_dsc);
560 
561     /* Draw only the shadow if the indicator is long enough.
562      * The radius of the bg and the indicator can make a strange shape where
563      * it'd be very difficult to draw shadow. */
564     if((hor && lv_area_get_width(&ext->indic_area) > bg_radius * 2) ||
565        (!hor && lv_area_get_height(&ext->indic_area) > bg_radius * 2)) {
566         lv_opa_t bg_opa = draw_indic_dsc.bg_opa;
567         lv_opa_t border_opa = draw_indic_dsc.border_opa;
568         lv_opa_t value_opa = draw_indic_dsc.value_opa;
569         const void * pattern_src = draw_indic_dsc.pattern_image;
570         draw_indic_dsc.bg_opa = LV_OPA_TRANSP;
571         draw_indic_dsc.border_opa = LV_OPA_TRANSP;
572         draw_indic_dsc.value_opa = LV_OPA_TRANSP;
573         draw_indic_dsc.pattern_image = NULL;
574         lv_draw_rect(&ext->indic_area, clip_area, &draw_indic_dsc);
575         draw_indic_dsc.bg_opa = bg_opa;
576         draw_indic_dsc.border_opa = border_opa;
577         draw_indic_dsc.value_opa = value_opa;
578         draw_indic_dsc.pattern_image = pattern_src;
579 
580     }
581 
582     lv_draw_mask_radius_param_t mask_bg_param;
583     lv_draw_mask_radius_init(&mask_bg_param, &bar->coords, bg_radius, false);
584     int16_t mask_bg_id = lv_draw_mask_add(&mask_bg_param, NULL);
585 
586     /*Draw_only the background and the pattern*/
587     lv_opa_t shadow_opa = draw_indic_dsc.shadow_opa;
588     lv_opa_t border_opa = draw_indic_dsc.border_opa;
589     lv_opa_t value_opa = draw_indic_dsc.value_opa;
590     draw_indic_dsc.border_opa = LV_OPA_TRANSP;
591     draw_indic_dsc.shadow_opa = LV_OPA_TRANSP;
592     draw_indic_dsc.value_opa = LV_OPA_TRANSP;
593 
594     /*Get the max possible indicator area. The gradient should be applied on this*/
595     lv_area_t mask_indic_max_area;
596     lv_area_copy(&mask_indic_max_area, &bar->coords);
597     mask_indic_max_area.x1 += bg_left;
598     mask_indic_max_area.y1 += bg_top;
599     mask_indic_max_area.x2 -= bg_right;
600     mask_indic_max_area.y2 -= bg_bottom;
601     if(hor && lv_area_get_height(&mask_indic_max_area) < LV_BAR_SIZE_MIN) {
602         mask_indic_max_area.y1 = bar->coords.y1 + (objh / 2) - (LV_BAR_SIZE_MIN / 2);
603         mask_indic_max_area.y2 = mask_indic_max_area.y1 + LV_BAR_SIZE_MIN;
604     }
605     else if(!hor && lv_area_get_width(&mask_indic_max_area) < LV_BAR_SIZE_MIN) {
606         mask_indic_max_area.x1 = bar->coords.x1 + (objw / 2) - (LV_BAR_SIZE_MIN / 2);
607         mask_indic_max_area.x2 = mask_indic_max_area.x1 + LV_BAR_SIZE_MIN;
608     }
609 
610     /*Create a mask to the current indicator area to see only this part from the whole gradient.*/
611     lv_draw_mask_radius_param_t mask_indic_param;
612     lv_draw_mask_radius_init(&mask_indic_param, &ext->indic_area, draw_indic_dsc.radius, false);
613     int16_t mask_indic_id = lv_draw_mask_add(&mask_indic_param, NULL);
614 
615     lv_draw_rect(&mask_indic_max_area, clip_area, &draw_indic_dsc);
616     draw_indic_dsc.border_opa = border_opa;
617     draw_indic_dsc.shadow_opa = shadow_opa;
618     draw_indic_dsc.value_opa = value_opa;
619 
620     /*Draw the border*/
621     draw_indic_dsc.bg_opa = LV_OPA_TRANSP;
622     draw_indic_dsc.shadow_opa = LV_OPA_TRANSP;
623     draw_indic_dsc.value_opa = LV_OPA_TRANSP;
624     draw_indic_dsc.pattern_image = NULL;
625     lv_draw_rect(&ext->indic_area, clip_area, &draw_indic_dsc);
626 
627     lv_draw_mask_remove_id(mask_indic_id);
628     lv_draw_mask_remove_id(mask_bg_id);
629 
630     /*When not masks draw the value*/
631     draw_indic_dsc.value_opa = value_opa;
632     draw_indic_dsc.border_opa = LV_OPA_TRANSP;
633     lv_draw_rect(&ext->indic_area, clip_area, &draw_indic_dsc);
634 
635 }
636 
637 /**
638  * Signal function of the bar
639  * @param bar pointer to a bar object
640  * @param sign a signal type from lv_signal_t enum
641  * @param param pointer to a signal specific variable
642  * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
643  */
lv_bar_signal(lv_obj_t * bar,lv_signal_t sign,void * param)644 static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)
645 {
646     lv_res_t res;
647 
648     if(sign == LV_SIGNAL_GET_STYLE) {
649         lv_get_style_info_t * info = param;
650         info->result = lv_bar_get_style(bar, info->part);
651         if(info->result != NULL) return LV_RES_OK;
652         else return ancestor_signal(bar, sign, param);
653     }
654 
655     /* Include the ancient signal function */
656     res = ancestor_signal(bar, sign, param);
657     if(res != LV_RES_OK) return res;
658     if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
659 
660     if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) {
661 
662         lv_coord_t indic_size;
663         indic_size = lv_obj_get_draw_rect_ext_pad_size(bar, LV_BAR_PART_INDIC);
664 
665         /*Bg size is handled by lv_obj*/
666         bar->ext_draw_pad = LV_MATH_MAX(bar->ext_draw_pad, indic_size);
667 
668     }
669     if(sign == LV_SIGNAL_CLEANUP) {
670         lv_obj_clean_style_list(bar, LV_BAR_PART_INDIC);
671 #if LV_USE_ANIMATION
672         lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
673         lv_anim_del(&ext->cur_value_anim, NULL);
674         lv_anim_del(&ext->start_value_anim, NULL);
675 #endif
676     }
677 
678     return res;
679 }
680 
lv_bar_get_style(lv_obj_t * bar,uint8_t part)681 static lv_style_list_t * lv_bar_get_style(lv_obj_t * bar, uint8_t part)
682 {
683     LV_ASSERT_OBJ(bar, LV_OBJX_NAME);
684 
685     lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
686     lv_style_list_t * style_dsc_p;
687 
688     switch(part) {
689         case LV_BAR_PART_BG:
690             style_dsc_p = &bar->style_list;
691             break;
692         case LV_BAR_PART_INDIC:
693             style_dsc_p = &ext->style_indic;
694             break;
695         default:
696             style_dsc_p = NULL;
697     }
698 
699     return style_dsc_p;
700 }
701 
702 #if LV_USE_ANIMATION
lv_bar_anim(lv_bar_anim_t * var,lv_anim_value_t value)703 static void lv_bar_anim(lv_bar_anim_t * var, lv_anim_value_t value)
704 {
705     var->anim_state    = value;
706     lv_obj_invalidate(var->bar);
707 }
708 
lv_bar_anim_ready(lv_anim_t * a)709 static void lv_bar_anim_ready(lv_anim_t * a)
710 {
711     lv_bar_anim_t * var = a->var;
712     lv_bar_ext_t * ext = lv_obj_get_ext_attr(var->bar);
713     var->anim_state = LV_BAR_ANIM_STATE_INV;
714     if(var == &ext->cur_value_anim)
715         ext->cur_value = var->anim_end;
716     else if(var == &ext->start_value_anim)
717         ext->start_value = var->anim_end;
718     lv_obj_invalidate(var->bar);
719 }
720 
lv_bar_set_value_with_anim(lv_obj_t * bar,int16_t new_value,int16_t * value_ptr,lv_bar_anim_t * anim_info,lv_anim_enable_t en)721 static void lv_bar_set_value_with_anim(lv_obj_t * bar, int16_t new_value, int16_t * value_ptr,
722                                        lv_bar_anim_t * anim_info, lv_anim_enable_t en)
723 {
724     if(en == LV_ANIM_OFF) {
725         *value_ptr = new_value;
726         lv_obj_invalidate(bar);
727     }
728     else {
729         lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
730         /*No animation in progress -> simply set the values*/
731         if(anim_info->anim_state == LV_BAR_ANIM_STATE_INV) {
732             anim_info->anim_start = *value_ptr;
733             anim_info->anim_end   = new_value;
734         }
735         /*Animation in progress. Start from the animation end value*/
736         else {
737             anim_info->anim_start = anim_info->anim_end;
738             anim_info->anim_end   = new_value;
739         }
740         *value_ptr = new_value;
741         /* Stop the previous animation if it exists */
742         lv_anim_del(anim_info, NULL);
743 
744         lv_anim_t a;
745         lv_anim_init(&a);
746         lv_anim_set_var(&a, anim_info);
747         lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_bar_anim);
748         lv_anim_set_values(&a, LV_BAR_ANIM_STATE_START, LV_BAR_ANIM_STATE_END);
749         lv_anim_set_ready_cb(&a, lv_bar_anim_ready);
750         lv_anim_set_time(&a, ext->anim_time);
751         lv_anim_start(&a);
752     }
753 }
754 
lv_bar_init_anim(lv_obj_t * bar,lv_bar_anim_t * bar_anim)755 static void lv_bar_init_anim(lv_obj_t * bar, lv_bar_anim_t * bar_anim)
756 {
757     bar_anim->bar = bar;
758     bar_anim->anim_start = 0;
759     bar_anim->anim_end = 0;
760     bar_anim->anim_state = LV_BAR_ANIM_STATE_INV;
761 }
762 #endif
763 
764 #endif
765