1 /**
2 * @file lv_arc.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_arc.h"
10 #if LV_USE_ARC != 0
11
12 #include "../lv_core/lv_group.h"
13 #include "../lv_core/lv_indev.h"
14 #include "../lv_misc/lv_debug.h"
15 #include "../lv_misc/lv_math.h"
16 #include "../lv_draw/lv_draw_arc.h"
17 #include "../lv_themes/lv_theme.h"
18
19 /*********************
20 * DEFINES
21 *********************/
22 #define LV_OBJX_NAME "lv_arc"
23
24 /**********************
25 * TYPEDEFS
26 **********************/
27
28 /**********************
29 * STATIC PROTOTYPES
30 **********************/
31 static lv_design_res_t lv_arc_design(lv_obj_t * arc, const lv_area_t * clip_area, lv_design_mode_t mode);
32 static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param);
33 static lv_style_list_t * lv_arc_get_style(lv_obj_t * arc, uint8_t part);
34 static void inv_arc_area(lv_obj_t * arc, uint16_t start_angle, uint16_t end_angle, lv_arc_part_t part);
35 static void get_center(lv_obj_t * arc, lv_point_t * center, lv_coord_t * arc_r);
36 static void get_knob_area(lv_obj_t * arc, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area);
37 static void value_update(lv_obj_t * arc);
38
39 /**********************
40 * STATIC VARIABLES
41 **********************/
42 static lv_signal_cb_t ancestor_signal;
43 static lv_design_cb_t ancestor_design;
44
45 /**********************
46 * MACROS
47 **********************/
48
49 /**********************
50 * GLOBAL FUNCTIONS
51 **********************/
52
53 /**
54 * Create a arc object
55 * @param par pointer to an object, it will be the parent of the new arc
56 * @param copy pointer to a arc object, if not NULL then the new object will be copied from it
57 * @return pointer to the created arc
58 */
lv_arc_create(lv_obj_t * par,const lv_obj_t * copy)59 lv_obj_t * lv_arc_create(lv_obj_t * par, const lv_obj_t * copy)
60 {
61
62 LV_LOG_TRACE("arc create started");
63
64 /*Create the ancestor of arc*/
65 lv_obj_t * arc = lv_obj_create(par, copy);
66 LV_ASSERT_MEM(arc);
67 if(arc == NULL) return NULL;
68
69 /*Allocate the arc type specific extended data*/
70 lv_arc_ext_t * ext = lv_obj_allocate_ext_attr(arc, sizeof(lv_arc_ext_t));
71 LV_ASSERT_MEM(ext);
72 if(ext == NULL) {
73 lv_obj_del(arc);
74 return NULL;
75 }
76
77 if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(arc);
78 if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(arc);
79
80 /*Initialize the allocated 'ext' */
81 ext->rotation_angle = 0;
82 ext->bg_angle_start = 135;
83 ext->bg_angle_end = 45;
84 ext->arc_angle_start = 135;
85 ext->arc_angle_end = 270;
86 ext->type = LV_ARC_TYPE_NORMAL;
87 ext->cur_value = -1;
88 ext->min_value = 0;
89 ext->max_value = 100;
90 ext->dragging = false;
91 ext->adjustable = false;
92 ext->chg_rate = 540;
93 ext->last_tick = lv_tick_get();
94 ext->last_angle = ext->arc_angle_end;
95 lv_style_list_init(&ext->style_arc);
96 lv_style_list_init(&ext->style_knob);
97
98 lv_obj_set_size(arc, LV_DPI, LV_DPI);
99
100 /*The signal and design functions are not copied so set them here*/
101 lv_obj_set_signal_cb(arc, lv_arc_signal);
102 lv_obj_set_design_cb(arc, lv_arc_design);
103
104 /*Init the new arc arc*/
105 if(copy == NULL) {
106 lv_obj_set_click(arc, true);
107 lv_obj_add_protect(arc, LV_PROTECT_PRESS_LOST);
108 lv_obj_set_ext_click_area(arc, LV_DPI / 10, LV_DPI / 10, LV_DPI / 10, LV_DPI / 10);
109 lv_arc_set_value(arc, ext->min_value);
110 lv_theme_apply(arc, LV_THEME_ARC);
111 }
112 /*Copy an existing arc*/
113 else {
114 lv_arc_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
115 ext->arc_angle_start = copy_ext->arc_angle_start;
116 ext->arc_angle_end = copy_ext->arc_angle_end;
117 ext->bg_angle_start = copy_ext->bg_angle_start;
118 ext->bg_angle_end = copy_ext->bg_angle_end;
119 ext->type = copy_ext->type;
120 ext->cur_value = copy_ext->cur_value;
121 ext->min_value = copy_ext->min_value;
122 ext->max_value = copy_ext->max_value;
123 ext->dragging = copy_ext->dragging;
124 ext->adjustable = copy_ext->adjustable;
125 ext->chg_rate = copy_ext->chg_rate;
126 ext->last_tick = copy_ext->last_tick;
127 ext->last_angle = copy_ext->last_angle;
128 lv_style_list_copy(&ext->style_knob, ©_ext->style_knob);
129 lv_style_list_copy(&ext->style_arc, ©_ext->style_arc);
130
131 /*Refresh the style with new signal function*/
132 lv_obj_refresh_style(arc, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
133 }
134
135 LV_LOG_INFO("arc created");
136
137 return arc;
138 }
139
140 /*======================
141 * Add/remove functions
142 *=====================*/
143
144 /*
145 * New object specific "add" or "remove" functions come here
146 */
147
148 /*=====================
149 * Setter functions
150 *====================*/
151
152 /**
153 * Set the start angle of an arc. 0 deg: right, 90 bottom, etc.
154 * @param arc pointer to an arc object
155 * @param start the start angle [0..360]
156 */
lv_arc_set_start_angle(lv_obj_t * arc,uint16_t start)157 void lv_arc_set_start_angle(lv_obj_t * arc, uint16_t start)
158 {
159 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
160
161 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
162
163 if(start > 360) start -= 360;
164
165 /*Too large move, the whole arc need to be invalidated anyway*/
166 if(LV_MATH_ABS(start - ext->arc_angle_start) >= 180) {
167 lv_obj_invalidate(arc);
168 }
169 /*Only a smaller incremental move*/
170 else if(ext->arc_angle_start > ext->arc_angle_end && start > ext->arc_angle_end) {
171 inv_arc_area(arc, LV_MATH_MIN(ext->arc_angle_start, start), LV_MATH_MAX(ext->arc_angle_start, start),
172 LV_ARC_PART_INDIC);
173 }
174 /*Only a smaller incremental move*/
175 else if(ext->arc_angle_start < ext->arc_angle_end && start < ext->arc_angle_end) {
176 inv_arc_area(arc, LV_MATH_MIN(ext->arc_angle_start, start), LV_MATH_MAX(ext->arc_angle_start, start),
177 LV_ARC_PART_INDIC);
178 }
179 /*Crossing the start angle makes the whole arc change*/
180 else {
181 lv_obj_invalidate(arc);
182 }
183
184 ext->arc_angle_start = start;
185 }
186
187 /**
188 * Set the start angle of an arc. 0 deg: right, 90 bottom, etc.
189 * @param arc pointer to an arc object
190 * @param start the start angle [0..360]
191 */
lv_arc_set_end_angle(lv_obj_t * arc,uint16_t end)192 void lv_arc_set_end_angle(lv_obj_t * arc, uint16_t end)
193 {
194 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
195
196 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
197
198 if(end > (ext->arc_angle_start + 360)) end = ext->arc_angle_start + 360;
199
200 /*Too large move, the whole arc need to be invalidated anyway*/
201 if(LV_MATH_ABS(end - ext->arc_angle_end) >= 180) {
202 lv_obj_invalidate(arc);
203 }
204 /*Only a smaller incremental move*/
205 else if(ext->arc_angle_end > ext->arc_angle_start && end > ext->arc_angle_start) {
206 inv_arc_area(arc, LV_MATH_MIN(ext->arc_angle_end, end), LV_MATH_MAX(ext->arc_angle_end, end), LV_ARC_PART_INDIC);
207 }
208 /*Only a smaller incremental move*/
209 else if(ext->arc_angle_end < ext->arc_angle_start && end < ext->arc_angle_start) {
210 inv_arc_area(arc, LV_MATH_MIN(ext->arc_angle_end, end), LV_MATH_MAX(ext->arc_angle_end, end), LV_ARC_PART_INDIC);
211 }
212 /*Crossing the end angle makes the whole arc change*/
213 else {
214 lv_obj_invalidate(arc);
215 }
216
217 ext->arc_angle_end = end;
218 }
219
220
221 /**
222 * Set the start and end angles
223 * @param arc pointer to an arc object
224 * @param start the start angle
225 * @param end the end angle
226 */
lv_arc_set_angles(lv_obj_t * arc,uint16_t start,uint16_t end)227 void lv_arc_set_angles(lv_obj_t * arc, uint16_t start, uint16_t end)
228 {
229 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
230
231 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
232
233 if(start > 360) start -= 360;
234 if(end > (start + 360)) end = start + 360;
235
236 inv_arc_area(arc, ext->arc_angle_start, ext->arc_angle_end, LV_ARC_PART_INDIC);
237
238 ext->arc_angle_start = start;
239 ext->arc_angle_end = end;
240
241 inv_arc_area(arc, ext->arc_angle_start, ext->arc_angle_end, LV_ARC_PART_INDIC);
242 }
243
244 /**
245 * Set the start angle of an arc background. 0 deg: right, 90 bottom, etc.
246 * @param arc pointer to an arc object
247 * @param start the start angle
248 */
lv_arc_set_bg_start_angle(lv_obj_t * arc,uint16_t start)249 void lv_arc_set_bg_start_angle(lv_obj_t * arc, uint16_t start)
250 {
251 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
252
253 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
254
255 if(start > 360) start -= 360;
256
257 /*Too large move, the whole arc need to be invalidated anyway*/
258 if(LV_MATH_ABS(start - ext->bg_angle_start) >= 180) {
259 lv_obj_invalidate(arc);
260 }
261 /*Only a smaller incremental move*/
262 else if(ext->bg_angle_start > ext->bg_angle_end && start > ext->bg_angle_end) {
263 inv_arc_area(arc, LV_MATH_MIN(ext->bg_angle_start, start), LV_MATH_MAX(ext->bg_angle_start, start), LV_ARC_PART_BG);
264 }
265 /*Only a smaller incremental move*/
266 else if(ext->bg_angle_start < ext->bg_angle_end && start < ext->bg_angle_end) {
267 inv_arc_area(arc, LV_MATH_MIN(ext->bg_angle_start, start), LV_MATH_MAX(ext->bg_angle_start, start), LV_ARC_PART_BG);
268 }
269 /*Crossing the start angle makes the whole arc change*/
270 else {
271 lv_obj_invalidate(arc);
272 }
273
274 ext->bg_angle_start = start;
275 }
276
277 /**
278 * Set the start angle of an arc background. 0 deg: right, 90 bottom etc.
279 * @param arc pointer to an arc object
280 * @param end the end angle
281 */
lv_arc_set_bg_end_angle(lv_obj_t * arc,uint16_t end)282 void lv_arc_set_bg_end_angle(lv_obj_t * arc, uint16_t end)
283 {
284 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
285
286 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
287
288 if(end > (ext->bg_angle_start + 360)) end = ext->bg_angle_start + 360;
289
290 /*Too large move, the whole arc need to be invalidated anyway*/
291 if(LV_MATH_ABS(end - ext->bg_angle_end) >= 180) {
292 lv_obj_invalidate(arc);
293 }
294 /*Only a smaller incremental move*/
295 else if(ext->bg_angle_end > ext->bg_angle_start && end > ext->bg_angle_start) {
296 inv_arc_area(arc, LV_MATH_MIN(ext->bg_angle_end, end), LV_MATH_MAX(ext->bg_angle_end, end), LV_ARC_PART_BG);
297 }
298 /*Only a smaller incremental move*/
299 else if(ext->bg_angle_end < ext->bg_angle_start && end < ext->bg_angle_start) {
300 inv_arc_area(arc, LV_MATH_MIN(ext->bg_angle_end, end), LV_MATH_MAX(ext->bg_angle_end, end), LV_ARC_PART_BG);
301 }
302 /*Crossing the end angle makes the whole arc change*/
303 else {
304 lv_obj_invalidate(arc);
305 }
306
307 ext->bg_angle_end = end;
308 }
309
310 /**
311 * Set the start and end angles of the arc background
312 * @param arc pointer to an arc object
313 * @param start the start angle
314 * @param end the end angle
315 */
lv_arc_set_bg_angles(lv_obj_t * arc,uint16_t start,uint16_t end)316 void lv_arc_set_bg_angles(lv_obj_t * arc, uint16_t start, uint16_t end)
317 {
318 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
319
320 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
321
322 if(start > 360) start -= 360;
323 if(end > (start + 360)) end = start + 360;
324
325 inv_arc_area(arc, ext->bg_angle_start, ext->bg_angle_end, LV_ARC_PART_BG);
326
327 ext->bg_angle_start = start;
328 ext->bg_angle_end = end;
329
330 inv_arc_area(arc, ext->bg_angle_start, ext->bg_angle_end, LV_ARC_PART_BG);
331 }
332
333 /**
334 * Set the rotation for the whole arc
335 * @param arc pointer to an arc object
336 * @param rotation_angle rotation angle
337 */
lv_arc_set_rotation(lv_obj_t * arc,uint16_t rotation_angle)338 void lv_arc_set_rotation(lv_obj_t * arc, uint16_t rotation_angle)
339 {
340 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
341
342 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
343
344 ext->rotation_angle = rotation_angle;
345
346 lv_obj_invalidate(arc);
347 }
348
349
350 /**
351 * Set the type of arc.
352 * @param arc pointer to arc object
353 * @param type arc type
354 */
lv_arc_set_type(lv_obj_t * arc,lv_arc_type_t type)355 void lv_arc_set_type(lv_obj_t * arc, lv_arc_type_t type)
356 {
357 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
358
359 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
360 int16_t val = ext->cur_value;
361
362 ext->type = type;
363 ext->cur_value = -1; /** Force set_value handling*/
364
365 int16_t bg_midpoint, bg_end = ext->bg_angle_end;
366 if(ext->bg_angle_end < ext->bg_angle_start) bg_end = ext->bg_angle_end + 360;
367
368 switch(ext->type) {
369 case LV_ARC_TYPE_SYMMETRIC:
370 bg_midpoint = (ext->bg_angle_start + bg_end) / 2;
371 lv_arc_set_start_angle(arc, bg_midpoint);
372 lv_arc_set_end_angle(arc, bg_midpoint);
373 break;
374 case LV_ARC_TYPE_REVERSE:
375 lv_arc_set_end_angle(arc, ext->bg_angle_end);
376 break;
377 default: /** LV_ARC_TYPE_NORMAL*/
378 lv_arc_set_start_angle(arc, ext->bg_angle_start);
379 }
380
381 lv_arc_set_value(arc, val);
382 }
383
384 /**
385 * Set a new value on the arc
386 * @param arc pointer to a arc object
387 * @param value new value
388 */
lv_arc_set_value(lv_obj_t * arc,int16_t value)389 void lv_arc_set_value(lv_obj_t * arc, int16_t value)
390 {
391 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
392
393 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
394 if(ext->cur_value == value) return;
395
396 int16_t new_value;
397 new_value = value > ext->max_value ? ext->max_value : value;
398 new_value = new_value < ext->min_value ? ext->min_value : new_value;
399
400 if(ext->cur_value == new_value) return;
401 ext->cur_value = new_value;
402
403 value_update(arc);
404 }
405
406 /**
407 * Set minimum and the maximum values of a arc
408 * @param arc pointer to the arc object
409 * @param min minimum value
410 * @param max maximum value
411 */
lv_arc_set_range(lv_obj_t * arc,int16_t min,int16_t max)412 void lv_arc_set_range(lv_obj_t * arc, int16_t min, int16_t max)
413 {
414 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
415
416 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
417 if(ext->min_value == min && ext->max_value == max) return;
418
419 ext->min_value = min;
420 ext->max_value = max;
421
422 if(ext->cur_value < min) {
423 ext->cur_value = min;
424 }
425 if(ext->cur_value > max) {
426 ext->cur_value = max;
427 }
428
429 value_update(arc); /* value has changed relative to the new range */
430 }
431
432 /**
433 * Set the threshold of arc knob increments
434 * position.
435 * @param arc pointer to a arc object
436 * @param threshold increment threshold
437 */
lv_arc_set_chg_rate(lv_obj_t * arc,uint16_t rate)438 void lv_arc_set_chg_rate(lv_obj_t * arc, uint16_t rate)
439 {
440 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
441
442 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
443 ext->chg_rate = rate;
444 }
445
446 /**
447 * Set whether the arc is adjustable.
448 * @param arc pointer to a arc object
449 * @param adjustable whether the arc has a knob that can be dragged
450 */
lv_arc_set_adjustable(lv_obj_t * arc,bool adjustable)451 void lv_arc_set_adjustable(lv_obj_t * arc, bool adjustable)
452 {
453 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
454
455 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
456 if(ext->adjustable == adjustable)
457 return;
458
459 ext->adjustable = adjustable;
460 if(!adjustable)
461 ext->dragging = false;
462 lv_obj_invalidate(arc);
463 }
464
465 /*=====================
466 * Getter functions
467 *====================*/
468
469 /**
470 * Get the start angle of an arc.
471 * @param arc pointer to an arc object
472 * @return the start angle [0..360]
473 */
lv_arc_get_angle_start(lv_obj_t * arc)474 uint16_t lv_arc_get_angle_start(lv_obj_t * arc)
475 {
476 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
477
478 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
479
480 return ext->arc_angle_start;
481 }
482
483 /**
484 * Get the end angle of an arc.
485 * @param arc pointer to an arc object
486 * @return the end angle [0..360]
487 */
lv_arc_get_angle_end(lv_obj_t * arc)488 uint16_t lv_arc_get_angle_end(lv_obj_t * arc)
489 {
490 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
491
492 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
493
494 return ext->arc_angle_end;
495 }
496
497 /**
498 * Get the start angle of an arc background.
499 * @param arc pointer to an arc object
500 * @return the start angle [0..360]
501 */
lv_arc_get_bg_angle_start(lv_obj_t * arc)502 uint16_t lv_arc_get_bg_angle_start(lv_obj_t * arc)
503 {
504 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
505
506 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
507
508 return ext->bg_angle_start;
509 }
510
511 /**
512 * Get the end angle of an arc background.
513 * @param arc pointer to an arc object
514 * @return the end angle [0..360]
515 */
lv_arc_get_bg_angle_end(lv_obj_t * arc)516 uint16_t lv_arc_get_bg_angle_end(lv_obj_t * arc)
517 {
518 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
519
520 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
521
522 return ext->bg_angle_end;
523 }
524
525
526 /**
527 * Get the value of a arc
528 * @param arc pointer to a arc object
529 * @return the value of the arc
530 */
lv_arc_get_value(const lv_obj_t * arc)531 int16_t lv_arc_get_value(const lv_obj_t * arc)
532 {
533 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
534
535 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
536 return ext->cur_value;
537 }
538
539 /**
540 * Get the minimum value of a arc
541 * @param arc pointer to a arc object
542 * @return the minimum value of the arc
543 */
lv_arc_get_min_value(const lv_obj_t * arc)544 int16_t lv_arc_get_min_value(const lv_obj_t * arc)
545 {
546 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
547
548 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
549 return ext->min_value;
550 }
551
552 /**
553 * Get the maximum value of a arc
554 * @param arc pointer to a arc object
555 * @return the maximum value of the arc
556 */
lv_arc_get_max_value(const lv_obj_t * arc)557 int16_t lv_arc_get_max_value(const lv_obj_t * arc)
558 {
559 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
560
561 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
562 return ext->max_value;
563 }
564
565 /**
566 * Give the arc is being dragged or not
567 * @param arc pointer to a arc object
568 * @return true: drag in progress false: not dragged
569 */
lv_arc_is_dragged(const lv_obj_t * arc)570 bool lv_arc_is_dragged(const lv_obj_t * arc)
571 {
572 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
573
574 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
575 return ext->dragging;
576 }
577
578 /**
579 * Get whether the arc is type or not.
580 * @param arc pointer to a arc object
581 * @return arc type
582 */
lv_arc_get_type(const lv_obj_t * arc)583 lv_arc_type_t lv_arc_get_type(const lv_obj_t * arc)
584 {
585 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
586
587 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
588 return ext->type;
589 }
590
591 /**
592 * Get whether the arc is adjustable.
593 * @param arc pointer to a arc object
594 * @return whether the arc has a knob that can be dragged
595 */
lv_arc_get_adjustable(lv_obj_t * arc)596 bool lv_arc_get_adjustable(lv_obj_t * arc)
597 {
598 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
599
600 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
601 return ext->adjustable;
602 }
603
604 /*=====================
605 * Other functions
606 *====================*/
607
608 /*
609 * New object specific "other" functions come here
610 */
611
612 /**********************
613 * STATIC FUNCTIONS
614 **********************/
615
616 /**
617 * Handle the drawing related tasks of the arcs
618 * @param arc pointer to an object
619 * @param clip_area the object will be drawn only in this area
620 * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
621 * (return 'true' if yes)
622 * LV_DESIGN_DRAW: draw the object (always return 'true')
623 * LV_DESIGN_DRAW_POST: drawing after every children are drawn
624 * @param return an element of `lv_design_res_t`
625 */
lv_arc_design(lv_obj_t * arc,const lv_area_t * clip_area,lv_design_mode_t mode)626 static lv_design_res_t lv_arc_design(lv_obj_t * arc, const lv_area_t * clip_area, lv_design_mode_t mode)
627 {
628 /*Return false if the object is not covers the mask_p area*/
629 if(mode == LV_DESIGN_COVER_CHK) {
630 return LV_DESIGN_RES_NOT_COVER;
631 }
632 /*Draw the object*/
633 else if(mode == LV_DESIGN_DRAW_MAIN) {
634 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
635
636 lv_draw_rect_dsc_t bg_dsc;
637 lv_draw_rect_dsc_init(&bg_dsc);
638 lv_obj_init_draw_rect_dsc(arc, LV_ARC_PART_BG, &bg_dsc);
639
640 lv_draw_rect(&arc->coords, clip_area, &bg_dsc);
641
642 lv_point_t center;
643 lv_coord_t arc_r;
644 get_center(arc, ¢er, &arc_r);
645
646 /*Draw the background arc*/
647 lv_draw_line_dsc_t arc_dsc;
648 if(arc_r > 0) {
649 lv_draw_line_dsc_init(&arc_dsc);
650 lv_obj_init_draw_line_dsc(arc, LV_ARC_PART_BG, &arc_dsc);
651
652 lv_draw_arc(center.x, center.y, arc_r, ext->bg_angle_start + ext->rotation_angle,
653 ext->bg_angle_end + ext->rotation_angle, clip_area,
654 &arc_dsc);
655 }
656
657
658 /*make the indicator arc smaller or larger according to its greatest padding value*/
659 lv_coord_t left_indic = lv_obj_get_style_pad_left(arc, LV_ARC_PART_INDIC);
660 lv_coord_t right_indic = lv_obj_get_style_pad_right(arc, LV_ARC_PART_INDIC);
661 lv_coord_t top_indic = lv_obj_get_style_pad_top(arc, LV_ARC_PART_INDIC);
662 lv_coord_t bottom_indic = lv_obj_get_style_pad_bottom(arc, LV_ARC_PART_INDIC);
663 lv_coord_t indic_r = arc_r - LV_MATH_MAX4(left_indic, right_indic, top_indic, bottom_indic);
664
665 if(indic_r > 0) {
666 lv_draw_line_dsc_init(&arc_dsc);
667 lv_obj_init_draw_line_dsc(arc, LV_ARC_PART_INDIC, &arc_dsc);
668
669 lv_draw_arc(center.x, center.y, indic_r, ext->arc_angle_start + ext->rotation_angle,
670 ext->arc_angle_end + ext->rotation_angle, clip_area,
671 &arc_dsc);
672 }
673
674 if(ext->adjustable) {
675 lv_area_t knob_area;
676 get_knob_area(arc, ¢er, arc_r, &knob_area);
677
678 lv_draw_rect_dsc_t knob_rect_dsc;
679 lv_draw_rect_dsc_init(&knob_rect_dsc);
680 lv_obj_init_draw_rect_dsc(arc, LV_ARC_PART_KNOB, &knob_rect_dsc);
681
682 lv_draw_rect(&knob_area, clip_area, &knob_rect_dsc);
683 }
684
685 }
686 /*Post draw when the children are drawn*/
687 else if(mode == LV_DESIGN_DRAW_POST) {
688 }
689
690 return LV_DESIGN_RES_OK;
691 }
692
693 /**
694 * Signal function of the arc
695 * @param arc pointer to a arc object
696 * @param sign a signal type from lv_signal_t enum
697 * @param param pointer to a signal specific variable
698 * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
699 */
lv_arc_signal(lv_obj_t * arc,lv_signal_t sign,void * param)700 static lv_res_t lv_arc_signal(lv_obj_t * arc, lv_signal_t sign, void * param)
701 {
702 lv_res_t res;
703 if(sign == LV_SIGNAL_GET_STYLE) {
704 lv_get_style_info_t * info = param;
705 info->result = lv_arc_get_style(arc, info->part);
706 if(info->result != NULL) return LV_RES_OK;
707 else return ancestor_signal(arc, sign, param);
708 }
709
710 /* Include the ancient signal function */
711 res = ancestor_signal(arc, sign, param);
712 if(res != LV_RES_OK) return res;
713
714 if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
715
716 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
717
718 if(sign == LV_SIGNAL_PRESSING) {
719 /* Only adjustable arcs can be dragged */
720 if(!ext->adjustable) return res;
721
722 lv_indev_t * indev = lv_indev_get_act();
723 if(indev == NULL) return res;
724
725 /*Handle only pointers here*/
726 lv_indev_type_t indev_type = lv_indev_get_type(indev);
727 if(indev_type != LV_INDEV_TYPE_POINTER) return res;
728
729 lv_point_t p;
730 lv_indev_get_point(indev, &p);
731
732 /*Make point relative to the arc's center*/
733 lv_point_t center;
734 lv_coord_t r;
735 get_center(arc, ¢er, &r);
736
737 p.x -= center.x;
738 p.y -= center.y;
739
740 /*Enter dragging mode if pressed out of the knob*/
741 if(ext->dragging == false) {
742 lv_coord_t indic_width = lv_obj_get_style_line_width(arc, LV_ARC_PART_INDIC);
743 r -= indic_width;
744 r -= r / 2; /*Add some more sensitive area*/
745 if(p.x * p.x + p.y * p.y > r * r) {
746 ext->dragging = true;
747 ext->last_tick = lv_tick_get(); /*Capture timestamp at dragging start*/
748 }
749 }
750
751 /*It must be in "dragging" mode to turn the arc*/
752 if(ext->dragging == false) return res;
753
754 /*Calculate the angle of the pressed point*/
755 int16_t angle;
756 int16_t bg_end = ext->bg_angle_end;
757 if(ext->bg_angle_end < ext->bg_angle_start) {
758 bg_end = ext->bg_angle_end + 360;
759 }
760
761 angle = 360 - _lv_atan2(p.x, p.y) + 90; /*Some transformation is required*/
762 angle -= ext->rotation_angle;
763 if(angle < ext->bg_angle_start) angle = ext->bg_angle_start;
764 if(angle > bg_end) angle = bg_end;
765
766 /*Calculate the slew rate limited angle based on change rate (degrees/sec)*/
767 int16_t delta_angle = angle - ext->last_angle;
768 uint32_t delta_tick = lv_tick_elaps(ext->last_tick);
769 int16_t delta_angle_max = (ext->chg_rate * delta_tick) / 1000;
770
771 if(delta_angle > delta_angle_max) {
772 delta_angle = delta_angle_max;
773 }
774 else if(delta_angle < -delta_angle_max) {
775 delta_angle = -delta_angle_max;
776 }
777
778 angle = ext->last_angle + delta_angle; /*Apply the limited angle change*/
779
780 /*Rounding for symmetry*/
781 int32_t round = ((bg_end - ext->bg_angle_start) * 8) / (ext->max_value - ext->min_value);
782 round = (round + 4) >> 4;
783 angle += round;
784
785 /*Set the new value*/
786 int16_t old_value = ext->cur_value;
787 int16_t new_value = _lv_map(angle, ext->bg_angle_start, bg_end, ext->min_value, ext->max_value);
788 if(new_value != lv_arc_get_value(arc)) {
789 ext->last_tick = lv_tick_get(); /*Cache timestamp for the next iteration*/
790 lv_arc_set_value(arc, new_value); /*set_value caches the last_angle for the next iteration*/
791 if(new_value != old_value) {
792 res = lv_event_send(arc, LV_EVENT_VALUE_CHANGED, NULL);
793 if(res != LV_RES_OK) return res;
794 }
795 }
796
797 /*Don1't let the elapsed time to big while sitting on an end point*/
798 if(new_value == ext->min_value || new_value == ext->max_value) {
799 ext->last_tick = lv_tick_get(); /*Cache timestamp for the next iteration*/
800 }
801 }
802 else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) {
803 ext->dragging = false;
804
805 #if LV_USE_GROUP
806 /*Leave edit mode if released. (No need to wait for LONG_PRESS) */
807 lv_group_t * g = lv_obj_get_group(arc);
808 bool editing = lv_group_get_editing(g);
809 lv_indev_type_t indev_type = lv_indev_get_type(lv_indev_get_act());
810 if(indev_type == LV_INDEV_TYPE_ENCODER) {
811 if(editing) lv_group_set_editing(g, false);
812 }
813 #endif
814
815 }
816 else if(sign == LV_SIGNAL_CONTROL) {
817 if(!ext->adjustable) return res;
818
819 char c = *((char *)param);
820
821 int16_t old_value = ext->cur_value;
822 if(c == LV_KEY_RIGHT || c == LV_KEY_UP) {
823 lv_arc_set_value(arc, lv_arc_get_value(arc) + 1);
824 }
825 else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) {
826 lv_arc_set_value(arc, lv_arc_get_value(arc) - 1);
827 }
828
829 if(old_value != ext->cur_value) {
830 res = lv_event_send(arc, LV_EVENT_VALUE_CHANGED, NULL);
831 if(res != LV_RES_OK) return res;
832 }
833 }
834 else if(sign == LV_SIGNAL_CLEANUP) {
835 lv_obj_clean_style_list(arc, LV_ARC_PART_KNOB);
836 lv_obj_clean_style_list(arc, LV_ARC_PART_INDIC);
837 }
838
839 return res;
840 }
841
842 /**
843 * Get the style descriptor of a part of the object
844 * @param arc pointer the object
845 * @param part the part of the object. (LV_ARC_PART_...)
846 * @return pointer to the style descriptor of the specified part
847 */
lv_arc_get_style(lv_obj_t * arc,uint8_t part)848 static lv_style_list_t * lv_arc_get_style(lv_obj_t * arc, uint8_t part)
849 {
850 LV_ASSERT_OBJ(arc, LV_OBJX_NAME);
851
852 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
853
854 lv_style_list_t * style_dsc_p;
855
856 switch(part) {
857 case LV_ARC_PART_BG:
858 style_dsc_p = &arc->style_list;
859 break;
860 case LV_ARC_PART_INDIC:
861 style_dsc_p = &ext->style_arc;
862 break;
863 case LV_ARC_PART_KNOB:
864 style_dsc_p = &ext->style_knob;
865 break;
866 default:
867 style_dsc_p = NULL;
868 }
869
870 return style_dsc_p;
871 }
872
inv_arc_area(lv_obj_t * arc,uint16_t start_angle,uint16_t end_angle,lv_arc_part_t part)873 static void inv_arc_area(lv_obj_t * arc, uint16_t start_angle, uint16_t end_angle, lv_arc_part_t part)
874 {
875 /*Skip this complicated invalidation if the arc is not visible*/
876 if(lv_obj_is_visible(arc) == false) return;
877
878 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
879
880 start_angle += ext->rotation_angle;
881 end_angle += ext->rotation_angle;
882
883 if(start_angle >= 360) start_angle -= 360;
884 if(end_angle >= 360) end_angle -= 360;
885
886 uint8_t start_quarter = start_angle / 90;
887 uint8_t end_quarter = end_angle / 90;
888
889 lv_coord_t left = lv_obj_get_style_pad_left(arc, LV_ARC_PART_BG);
890 lv_coord_t right = lv_obj_get_style_pad_right(arc, LV_ARC_PART_BG);
891 lv_coord_t top = lv_obj_get_style_pad_top(arc, LV_ARC_PART_BG);
892 lv_coord_t bottom = lv_obj_get_style_pad_bottom(arc, LV_ARC_PART_BG);
893 lv_coord_t rout = (LV_MATH_MIN(lv_obj_get_width(arc) - left - right, lv_obj_get_height(arc) - top - bottom)) / 2;
894 lv_coord_t x = arc->coords.x1 + rout + left;
895 lv_coord_t y = arc->coords.y1 + rout + top;
896 lv_style_int_t w = lv_obj_get_style_line_width(arc, part);
897 lv_style_int_t rounded = lv_obj_get_style_line_rounded(arc, part);
898 lv_coord_t rin = rout - w;
899 lv_coord_t extra_area = 0;
900
901 extra_area = rounded ? w / 2 + 2 : 0;
902
903 if(part == LV_ARC_PART_INDIC && lv_style_list_get_style(&ext->style_knob, 0) != NULL) {
904 lv_coord_t knob_extra_size = lv_obj_get_draw_rect_ext_pad_size(arc, LV_ARC_PART_KNOB);
905
906 lv_coord_t knob_left = lv_obj_get_style_pad_left(arc, LV_ARC_PART_KNOB);
907 lv_coord_t knob_right = lv_obj_get_style_pad_right(arc, LV_ARC_PART_KNOB);
908 lv_coord_t knob_top = lv_obj_get_style_pad_top(arc, LV_ARC_PART_KNOB);
909 lv_coord_t knob_bottom = lv_obj_get_style_pad_bottom(arc, LV_ARC_PART_KNOB);
910
911 knob_extra_size += LV_MATH_MAX4(knob_left, knob_right, knob_top, knob_bottom);
912
913 extra_area = LV_MATH_MAX(extra_area, w / 2 + 2 + knob_extra_size);
914
915 }
916
917 lv_area_t inv_area;
918
919 if(start_quarter == end_quarter && start_angle <= end_angle) {
920 if(start_quarter == 0) {
921 inv_area.y1 = y + ((_lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) - extra_area;
922 inv_area.x2 = x + ((_lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
923
924 inv_area.y2 = y + ((_lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
925 inv_area.x1 = x + ((_lv_trigo_sin(end_angle + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
926
927 lv_obj_invalidate_area(arc, &inv_area);
928 }
929 else if(start_quarter == 1) {
930 inv_area.y2 = y + ((_lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
931 inv_area.x2 = x + ((_lv_trigo_sin(start_angle + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
932
933 inv_area.y1 = y + ((_lv_trigo_sin(end_angle) * rin) >> LV_TRIGO_SHIFT) - extra_area;
934 inv_area.x1 = x + ((_lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
935
936 lv_obj_invalidate_area(arc, &inv_area);
937 }
938 else if(start_quarter == 2) {
939 inv_area.x1 = x + ((_lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
940 inv_area.y2 = y + ((_lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
941
942 inv_area.y1 = y + ((_lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
943 inv_area.x2 = x + ((_lv_trigo_sin(end_angle + 90) * rin) >> LV_TRIGO_SHIFT) + extra_area;
944
945 lv_obj_invalidate_area(arc, &inv_area);
946 }
947 else if(start_quarter == 3) {
948 /*Small arc here*/
949 inv_area.x1 = x + ((_lv_trigo_sin(start_angle + 90) * rin) >> LV_TRIGO_SHIFT) - extra_area;
950 inv_area.y1 = y + ((_lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
951
952 inv_area.x2 = x + ((_lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
953 inv_area.y2 = y + ((_lv_trigo_sin(end_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
954
955 lv_obj_invalidate_area(arc, &inv_area);
956 }
957
958 }
959 else if(start_quarter == 0 && end_quarter == 1) {
960 inv_area.x1 = x + ((_lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
961 inv_area.y1 = y + ((LV_MATH_MIN(_lv_trigo_sin(end_angle),
962 _lv_trigo_sin(start_angle)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
963 inv_area.x2 = x + ((_lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
964 inv_area.y2 = y + rout + extra_area;
965 lv_obj_invalidate_area(arc, &inv_area);
966 }
967 else if(start_quarter == 1 && end_quarter == 2) {
968 inv_area.x1 = x - rout - extra_area;
969 inv_area.y1 = y + ((_lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
970 inv_area.x2 = x + ((LV_MATH_MAX(_lv_trigo_sin(start_angle + 90),
971 _lv_trigo_sin(end_angle + 90)) * rin) >> LV_TRIGO_SHIFT) + extra_area;
972 inv_area.y2 = y + ((_lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
973 lv_obj_invalidate_area(arc, &inv_area);
974 }
975 else if(start_quarter == 2 && end_quarter == 3) {
976 inv_area.x1 = x + ((_lv_trigo_sin(start_angle + 90) * rout) >> LV_TRIGO_SHIFT) - extra_area;
977 inv_area.y1 = y - rout - extra_area;
978 inv_area.x2 = x + ((_lv_trigo_sin(end_angle + 90) * rout) >> LV_TRIGO_SHIFT) + extra_area;
979 inv_area.y2 = y + (LV_MATH_MAX(_lv_trigo_sin(end_angle) * rin,
980 _lv_trigo_sin(start_angle) * rin) >> LV_TRIGO_SHIFT) + extra_area;
981 lv_obj_invalidate_area(arc, &inv_area);
982 }
983 else if(start_quarter == 3 && end_quarter == 0) {
984 inv_area.x1 = x + ((LV_MATH_MIN(_lv_trigo_sin(end_angle + 90),
985 _lv_trigo_sin(start_angle + 90)) * rin) >> LV_TRIGO_SHIFT) - extra_area;
986 inv_area.y1 = y + ((_lv_trigo_sin(start_angle) * rout) >> LV_TRIGO_SHIFT) - extra_area;
987 inv_area.x2 = x + rout + extra_area;
988 inv_area.y2 = y + ((_lv_trigo_sin(end_angle) * rout) >> LV_TRIGO_SHIFT) + extra_area;
989
990 lv_obj_invalidate_area(arc, &inv_area);
991 }
992 else {
993 lv_obj_invalidate(arc);
994 }
995 }
996
get_center(lv_obj_t * arc,lv_point_t * center,lv_coord_t * arc_r)997 static void get_center(lv_obj_t * arc, lv_point_t * center, lv_coord_t * arc_r)
998 {
999 lv_coord_t left_bg = lv_obj_get_style_pad_left(arc, LV_ARC_PART_BG);
1000 lv_coord_t right_bg = lv_obj_get_style_pad_right(arc, LV_ARC_PART_BG);
1001 lv_coord_t top_bg = lv_obj_get_style_pad_top(arc, LV_ARC_PART_BG);
1002 lv_coord_t bottom_bg = lv_obj_get_style_pad_bottom(arc, LV_ARC_PART_BG);
1003
1004 lv_coord_t r = (LV_MATH_MIN(lv_obj_get_width(arc) - left_bg - right_bg,
1005 lv_obj_get_height(arc) - top_bg - bottom_bg)) / 2;
1006
1007 *arc_r = r;
1008 center->x = arc->coords.x1 + r + left_bg;
1009 center->y = arc->coords.y1 + r + top_bg;
1010
1011
1012 lv_coord_t indic_width = lv_obj_get_style_line_width(arc, LV_ARC_PART_INDIC);
1013 r -= indic_width;
1014 }
1015
get_knob_area(lv_obj_t * arc,const lv_point_t * center,lv_coord_t r,lv_area_t * knob_area)1016 static void get_knob_area(lv_obj_t * arc, const lv_point_t * center, lv_coord_t r, lv_area_t * knob_area)
1017 {
1018 lv_arc_ext_t * ext = lv_obj_get_ext_attr(arc);
1019
1020 lv_coord_t indic_width = lv_obj_get_style_line_width(arc, LV_ARC_PART_INDIC);
1021 lv_coord_t indic_width_half = indic_width / 2;
1022 r -= indic_width_half;
1023
1024 uint16_t angle = ext->rotation_angle;
1025 if(ext->type == LV_ARC_TYPE_NORMAL) {
1026 angle += ext->arc_angle_end;
1027 }
1028 else if(ext->type == LV_ARC_TYPE_REVERSE) {
1029 angle += ext->arc_angle_start;
1030 }
1031 else if(ext->type == LV_ARC_TYPE_SYMMETRIC) {
1032 int32_t range_midpoint = (int32_t)(ext->min_value + ext->max_value) / 2;
1033 if(ext->cur_value < range_midpoint) angle += ext->arc_angle_start;
1034 else angle += ext->arc_angle_end;
1035 }
1036 lv_coord_t knob_x = (r * _lv_trigo_sin(angle + 90)) >> LV_TRIGO_SHIFT;
1037 lv_coord_t knob_y = (r * _lv_trigo_sin(angle)) >> LV_TRIGO_SHIFT;
1038
1039 lv_coord_t left_knob = lv_obj_get_style_pad_left(arc, LV_ARC_PART_KNOB);
1040 lv_coord_t right_knob = lv_obj_get_style_pad_right(arc, LV_ARC_PART_KNOB);
1041 lv_coord_t top_knob = lv_obj_get_style_pad_top(arc, LV_ARC_PART_KNOB);
1042 lv_coord_t bottom_knob = lv_obj_get_style_pad_bottom(arc, LV_ARC_PART_KNOB);
1043
1044 knob_area->x1 = center->x + knob_x - left_knob - indic_width_half;
1045 knob_area->x2 = center->x + knob_x + right_knob + indic_width_half;
1046 knob_area->y1 = center->y + knob_y - top_knob - indic_width_half;
1047 knob_area->y2 = center->y + knob_y + bottom_knob + indic_width_half;
1048 }
1049
1050 /**
1051 * Used internally to update arc angles after a value change
1052 * @param arc pointer to a arc object
1053 */
value_update(lv_obj_t * arc)1054 static void value_update(lv_obj_t * arc)
1055 {
1056 lv_arc_ext_t * ext = (lv_arc_ext_t *)lv_obj_get_ext_attr(arc);
1057
1058 int16_t bg_midpoint, range_midpoint, bg_end = ext->bg_angle_end;
1059 if(ext->bg_angle_end < ext->bg_angle_start) bg_end = ext->bg_angle_end + 360;
1060
1061 int16_t angle;
1062 switch(ext->type) {
1063 case LV_ARC_TYPE_SYMMETRIC:
1064 bg_midpoint = (ext->bg_angle_start + bg_end) / 2;
1065 range_midpoint = (int32_t)(ext->min_value + ext->max_value) / 2;
1066
1067 if(ext->cur_value < range_midpoint) {
1068 angle = _lv_map(ext->cur_value, ext->min_value, range_midpoint, ext->bg_angle_start, bg_midpoint);
1069 lv_arc_set_start_angle(arc, angle);
1070 lv_arc_set_end_angle(arc, bg_midpoint);
1071 }
1072 else {
1073 angle = _lv_map(ext->cur_value, range_midpoint, ext->max_value, bg_midpoint, bg_end);
1074 lv_arc_set_start_angle(arc, bg_midpoint);
1075 lv_arc_set_end_angle(arc, angle);
1076 }
1077 break;
1078 case LV_ARC_TYPE_REVERSE:
1079 angle = _lv_map(ext->cur_value, ext->min_value, ext->max_value, ext->bg_angle_start, bg_end);
1080 lv_arc_set_start_angle(arc, angle);
1081 break;
1082 default: /** LV_ARC_TYPE_NORMAL*/
1083 angle = _lv_map(ext->cur_value, ext->min_value, ext->max_value, ext->bg_angle_start, bg_end);
1084 lv_arc_set_end_angle(arc, angle);
1085 lv_arc_set_start_angle(arc, ext->bg_angle_start);
1086 }
1087 ext->last_angle = angle; /*Cache angle for slew rate limiting*/
1088 }
1089
1090 #endif
1091