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