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