1 /**
2 * @file lv_gauge.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_gauge.h"
10 #if LV_USE_GAUGE != 0
11
12 #include "../lv_misc/lv_debug.h"
13 #include "../lv_draw/lv_draw.h"
14 #include "../lv_themes/lv_theme.h"
15 #include "../lv_misc/lv_txt.h"
16 #include "../lv_misc/lv_math.h"
17 #include "../lv_misc/lv_utils.h"
18 #include "lv_img.h"
19 #include <stdio.h>
20 #include <string.h>
21
22 /*********************
23 * DEFINES
24 *********************/
25 #define LV_OBJX_NAME "lv_gauge"
26
27 #define LV_GAUGE_DEF_NEEDLE_COLOR LV_COLOR_RED
28 #define LV_GAUGE_DEF_LABEL_COUNT 6
29 #define LV_GAUGE_DEF_LINE_COUNT 21 /*Should be: ((label_cnt - 1) * internal_lines) + 1*/
30 #define LV_GAUGE_DEF_ANGLE 270
31
32 /**********************
33 * TYPEDEFS
34 **********************/
35
36 /**********************
37 * STATIC PROTOTYPES
38 **********************/
39 static lv_design_res_t lv_gauge_design(lv_obj_t * gauge, const lv_area_t * clip_area, lv_design_mode_t mode);
40 static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param);
41 static lv_style_list_t * lv_gauge_get_style(lv_obj_t * gauge, uint8_t part);
42 static void lv_gauge_draw_labels(lv_obj_t * gauge, const lv_area_t * mask);
43 static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * clip_area);
44
45 /**********************
46 * STATIC VARIABLES
47 **********************/
48 static lv_design_cb_t ancestor_design;
49 static lv_signal_cb_t ancestor_signal;
50
51 /**********************
52 * MACROS
53 **********************/
54
55 /**********************
56 * GLOBAL FUNCTIONS
57 **********************/
58
59 /**
60 * Create a gauge objects
61 * @param par pointer to an object, it will be the parent of the new gauge
62 * @param copy pointer to a gauge object, if not NULL then the new object will be copied from it
63 * @return pointer to the created gauge
64 */
lv_gauge_create(lv_obj_t * par,const lv_obj_t * copy)65 lv_obj_t * lv_gauge_create(lv_obj_t * par, const lv_obj_t * copy)
66 {
67 LV_LOG_TRACE("gauge create started");
68
69 /*Create the ancestor gauge*/
70 lv_obj_t * gauge = lv_linemeter_create(par, copy);
71 LV_ASSERT_MEM(gauge);
72 if(gauge == NULL) return NULL;
73
74 /*Allocate the gauge type specific extended data*/
75 lv_gauge_ext_t * ext = lv_obj_allocate_ext_attr(gauge, sizeof(lv_gauge_ext_t));
76 LV_ASSERT_MEM(ext);
77 if(ext == NULL) {
78 lv_obj_del(gauge);
79 return NULL;
80 }
81
82 /*Initialize the allocated 'ext' */
83 ext->needle_count = 0;
84 ext->values = NULL;
85 ext->needle_colors = NULL;
86 ext->label_count = LV_GAUGE_DEF_LABEL_COUNT;
87 ext->format_cb = NULL;
88
89 ext->needle_img = 0;
90 ext->needle_img_pivot.x = 0;
91 ext->needle_img_pivot.y = 0;
92 if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(gauge);
93 if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(gauge);
94
95 lv_style_list_init(&ext->style_strong);
96 lv_style_list_init(&ext->style_needle);
97
98 /*The signal and design functions are not copied so set them here*/
99 lv_obj_set_signal_cb(gauge, lv_gauge_signal);
100 lv_obj_set_design_cb(gauge, lv_gauge_design);
101
102 /*Init the new gauge gauge*/
103 if(copy == NULL) {
104 lv_gauge_set_scale(gauge, LV_GAUGE_DEF_ANGLE, LV_GAUGE_DEF_LINE_COUNT, LV_GAUGE_DEF_LABEL_COUNT);
105 lv_gauge_set_needle_count(gauge, 1, NULL);
106 lv_gauge_set_critical_value(gauge, 80);
107
108 lv_theme_apply(gauge, LV_THEME_GAUGE);
109
110 }
111 /*Copy an existing gauge*/
112 else {
113 lv_gauge_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
114 lv_gauge_set_needle_count(gauge, copy_ext->needle_count, copy_ext->needle_colors);
115
116 lv_style_list_copy(&ext->style_strong, ©_ext->style_strong);
117 lv_style_list_copy(&ext->style_needle, ©_ext->style_needle);
118
119 uint8_t i;
120 for(i = 0; i < ext->needle_count; i++) {
121 ext->values[i] = copy_ext->values[i];
122 }
123 ext->label_count = copy_ext->label_count;
124 ext->format_cb = copy_ext->format_cb;
125
126 /*Refresh the style with new signal function*/
127 lv_obj_refresh_style(gauge, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
128 }
129
130 LV_LOG_INFO("gauge created");
131
132 return gauge;
133 }
134
135 /*=====================
136 * Setter functions
137 *====================*/
138
139 /**
140 * Set the number of needles
141 * @param gauge pointer to gauge object
142 * @param needle_cnt new count of needles
143 * @param colors an array of colors for needles (with 'num' elements)
144 */
lv_gauge_set_needle_count(lv_obj_t * gauge,uint8_t needle_cnt,const lv_color_t colors[])145 void lv_gauge_set_needle_count(lv_obj_t * gauge, uint8_t needle_cnt, const lv_color_t colors[])
146 {
147 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
148
149 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
150
151 if(ext->needle_count != needle_cnt) {
152 if(ext->values != NULL) {
153 lv_mem_free(ext->values);
154 ext->values = NULL;
155 }
156
157 ext->values = lv_mem_realloc(ext->values, needle_cnt * sizeof(ext->values[0]));
158 LV_ASSERT_MEM(ext->values);
159 if(ext->values == NULL) return;
160
161 int16_t min = lv_gauge_get_min_value(gauge);
162 uint8_t n;
163 for(n = ext->needle_count; n < needle_cnt; n++) {
164 ext->values[n] = min;
165 }
166
167 ext->needle_count = needle_cnt;
168 }
169
170 ext->needle_colors = colors;
171 lv_obj_invalidate(gauge);
172 }
173
174 /**
175 * Set the value of a needle
176 * @param gauge pointer to a gauge
177 * @param needle_id the id of the needle
178 * @param value the new value
179 */
lv_gauge_set_value(lv_obj_t * gauge,uint8_t needle_id,int32_t value)180 void lv_gauge_set_value(lv_obj_t * gauge, uint8_t needle_id, int32_t value)
181 {
182 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
183
184 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
185
186 if(needle_id >= ext->needle_count) return;
187 if(ext->values[needle_id] == value) return;
188
189 int16_t min = lv_gauge_get_min_value(gauge);
190 int16_t max = lv_gauge_get_max_value(gauge);
191
192 if(value > max)
193 value = max;
194 else if(value < min)
195 value = min;
196
197 int32_t old_value = ext->values[needle_id];
198 ext->values[needle_id] = value;
199
200 // lv_obj_invalidate(gauge);
201
202 lv_style_int_t pad = lv_obj_get_style_pad_inner(gauge, LV_GAUGE_PART_NEEDLE);
203 lv_style_int_t left = lv_obj_get_style_pad_left(gauge, LV_GAUGE_PART_MAIN);
204 lv_style_int_t right = lv_obj_get_style_pad_right(gauge, LV_GAUGE_PART_MAIN);
205 lv_style_int_t top = lv_obj_get_style_pad_top(gauge, LV_GAUGE_PART_MAIN);
206 lv_coord_t r = (lv_obj_get_width(gauge) - left - right) / 2 - pad;
207 lv_coord_t x_ofs = gauge->coords.x1 + r + left + pad;
208 lv_coord_t y_ofs = gauge->coords.y1 + r + top + pad;
209 uint16_t angle = lv_linemeter_get_scale_angle(gauge);
210 int16_t angle_ofs = 90 + (360 - angle) / 2 + lv_gauge_get_angle_offset(gauge);
211 lv_point_t p_mid;
212 lv_point_t p_end;
213 lv_coord_t needle_w;
214
215 if(ext->needle_img) {
216 lv_img_header_t info;
217 lv_img_decoder_get_info(ext->needle_img, &info);
218 needle_w = info.h;
219 }
220 else {
221 needle_w = lv_obj_get_style_line_width(gauge, LV_GAUGE_PART_NEEDLE);
222 }
223
224 p_mid.x = x_ofs;
225 p_mid.y = y_ofs;
226 /*Calculate the end point of a needle*/
227 int16_t needle_angle = (old_value - min) * angle / (max - min) + angle_ofs;
228
229 p_end.y = (_lv_trigo_sin(needle_angle) * r) / LV_TRIGO_SIN_MAX + y_ofs;
230 p_end.x = (_lv_trigo_sin(needle_angle + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;
231
232 lv_area_t a;
233 a.x1 = LV_MATH_MIN(p_mid.x, p_end.x) - needle_w;
234 a.y1 = LV_MATH_MIN(p_mid.y, p_end.y) - needle_w;
235 a.x2 = LV_MATH_MAX(p_mid.x, p_end.x) + needle_w;
236 a.y2 = LV_MATH_MAX(p_mid.y, p_end.y) + needle_w;
237 lv_obj_invalidate_area(gauge, &a);
238
239 needle_angle = (value - min) * angle / (max - min) + angle_ofs;
240 p_end.y = (_lv_trigo_sin(needle_angle) * r) / LV_TRIGO_SIN_MAX + y_ofs;
241 p_end.x = (_lv_trigo_sin(needle_angle + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;
242
243 a.x1 = LV_MATH_MIN(p_mid.x, p_end.x) - needle_w;
244 a.y1 = LV_MATH_MIN(p_mid.y, p_end.y) - needle_w;
245 a.x2 = LV_MATH_MAX(p_mid.x, p_end.x) + needle_w;
246 a.y2 = LV_MATH_MAX(p_mid.y, p_end.y) + needle_w;
247 lv_obj_invalidate_area(gauge, &a);
248
249
250 }
251
252 /**
253 * Set the scale settings of a gauge
254 * @param gauge pointer to a gauge object
255 * @param angle angle of the scale (0..360)
256 * @param line_cnt count of scale lines.
257 * To get a given "subdivision" lines between labels:
258 * `line_cnt = (sub_div + 1) * (label_cnt - 1) + 1 `
259 * @param label_cnt count of scale labels.
260 */
lv_gauge_set_scale(lv_obj_t * gauge,uint16_t angle,uint8_t line_cnt,uint8_t label_cnt)261 void lv_gauge_set_scale(lv_obj_t * gauge, uint16_t angle, uint8_t line_cnt, uint8_t label_cnt)
262 {
263 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
264
265 lv_linemeter_set_scale(gauge, angle, line_cnt);
266
267 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
268 ext->label_count = label_cnt;
269 lv_obj_invalidate(gauge);
270 }
271
272 /**
273 * Set an image to display as needle(s).
274 * The needle image should be horizontal and pointing to the right (`--->`).
275 * @param gauge pointer to a gauge object
276 * @param img_src pointer to an `lv_img_dsc_t` variable or a path to an image
277 * (not an `lv_img` object)
278 * @param pivot_x the X coordinate of rotation center of the image
279 * @param pivot_y the Y coordinate of rotation center of the image
280 */
lv_gauge_set_needle_img(lv_obj_t * gauge,const void * img,lv_coord_t pivot_x,lv_coord_t pivot_y)281 void lv_gauge_set_needle_img(lv_obj_t * gauge, const void * img, lv_coord_t pivot_x, lv_coord_t pivot_y)
282 {
283 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
284
285 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
286
287 ext->needle_img = img;
288 ext->needle_img_pivot.x = pivot_x;
289 ext->needle_img_pivot.y = pivot_y;
290
291 lv_obj_invalidate(gauge);
292 }
293
294 /**
295 * Assign a function to format gauge values
296 * @param gauge pointer to a gauge object
297 * @param format_cb pointer to function of lv_gauge_format_cb_t
298 */
lv_gauge_set_formatter_cb(lv_obj_t * gauge,lv_gauge_format_cb_t format_cb)299 void lv_gauge_set_formatter_cb(lv_obj_t * gauge, lv_gauge_format_cb_t format_cb)
300 {
301 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
302
303 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
304
305 ext->format_cb = format_cb;
306 }
307
308 /*=====================
309 * Getter functions
310 *====================*/
311
312 /**
313 * Get the value of a needle
314 * @param gauge pointer to gauge object
315 * @param needle the id of the needle
316 * @return the value of the needle [min,max]
317 */
lv_gauge_get_value(const lv_obj_t * gauge,uint8_t needle)318 int32_t lv_gauge_get_value(const lv_obj_t * gauge, uint8_t needle)
319 {
320 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
321
322 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
323 int16_t min = lv_gauge_get_min_value(gauge);
324
325 if(needle >= ext->needle_count) return min;
326
327 return ext->values[needle];
328 }
329
330 /**
331 * Get the count of needles on a gauge
332 * @param gauge pointer to gauge
333 * @return count of needles
334 */
lv_gauge_get_needle_count(const lv_obj_t * gauge)335 uint8_t lv_gauge_get_needle_count(const lv_obj_t * gauge)
336 {
337 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
338
339 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
340 return ext->needle_count;
341 }
342
343 /**
344 * Set the number of labels (and the thicker lines too)
345 * @param gauge pointer to a gauge object
346 * @return count of labels
347 */
lv_gauge_get_label_count(const lv_obj_t * gauge)348 uint8_t lv_gauge_get_label_count(const lv_obj_t * gauge)
349 {
350 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
351
352 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
353 return ext->label_count;
354 }
355
356 /**
357 * Get an image to display as needle(s).
358 * @param gauge pointer to a gauge object
359 * @return pointer to an `lv_img_dsc_t` variable or a path to an image
360 * (not an `lv_img` object). `NULL` if not used.
361 */
lv_gauge_get_needle_img(lv_obj_t * gauge)362 const void * lv_gauge_get_needle_img(lv_obj_t * gauge)
363 {
364 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
365
366 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
367
368 return ext->needle_img;
369 }
370
371 /**
372 * Get the X coordinate of the rotation center of the needle image
373 * @param gauge pointer to a gauge object
374 * @return the X coordinate of rotation center of the image
375 */
lv_gauge_get_needle_img_pivot_x(lv_obj_t * gauge)376 lv_coord_t lv_gauge_get_needle_img_pivot_x(lv_obj_t * gauge)
377 {
378 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
379
380 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
381
382 return ext->needle_img_pivot.x;
383 }
384
385 /**
386 * Get the Y coordinate of the rotation center of the needle image
387 * @param gauge pointer to a gauge object
388 * @return the X coordinate of rotation center of the image
389 */
lv_gauge_get_needle_img_pivot_y(lv_obj_t * gauge)390 lv_coord_t lv_gauge_get_needle_img_pivot_y(lv_obj_t * gauge)
391 {
392 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
393
394 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
395
396 return ext->needle_img_pivot.y;
397 }
398
399
400 /**********************
401 * STATIC FUNCTIONS
402 **********************/
403
404 /**
405 * Handle the drawing related tasks of the gauges
406 * @param gauge pointer to an object
407 * @param clip_area the object will be drawn only in this area
408 * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
409 * (return 'true' if yes)
410 * LV_DESIGN_DRAW: draw the object (always return 'true')
411 * LV_DESIGN_DRAW_POST: drawing after every children are drawn
412 * @param return an element of `lv_design_res_t`
413 */
lv_gauge_design(lv_obj_t * gauge,const lv_area_t * clip_area,lv_design_mode_t mode)414 static lv_design_res_t lv_gauge_design(lv_obj_t * gauge, const lv_area_t * clip_area, lv_design_mode_t mode)
415 {
416 /*Return false if the object is not covers the mask_p area*/
417 if(mode == LV_DESIGN_COVER_CHK) {
418 return LV_DESIGN_RES_NOT_COVER;
419 }
420 /*Draw the object*/
421 else if(mode == LV_DESIGN_DRAW_MAIN) {
422 ancestor_design(gauge, clip_area, mode);
423
424 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
425 lv_gauge_draw_labels(gauge, clip_area);
426
427 /*Add the strong lines*/
428 uint16_t line_cnt_tmp = ext->lmeter.line_cnt;
429 ext->lmeter.line_cnt = ext->label_count; /*Only to labels*/
430 lv_linemeter_draw_scale(gauge, clip_area, LV_GAUGE_PART_MAJOR);
431 ext->lmeter.line_cnt = line_cnt_tmp; /*Restore the parameters*/
432
433 lv_gauge_draw_needle(gauge, clip_area);
434 }
435 /*Post draw when the children are drawn*/
436 else if(mode == LV_DESIGN_DRAW_POST) {
437 ancestor_design(gauge, clip_area, mode);
438 }
439
440 return LV_DESIGN_RES_OK;
441 }
442
443 /**
444 * Signal function of the gauge
445 * @param gauge pointer to a gauge object
446 * @param sign a signal type from lv_signal_t enum
447 * @param param pointer to a signal specific variable
448 * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
449 */
lv_gauge_signal(lv_obj_t * gauge,lv_signal_t sign,void * param)450 static lv_res_t lv_gauge_signal(lv_obj_t * gauge, lv_signal_t sign, void * param)
451 {
452 lv_res_t res;
453 if(sign == LV_SIGNAL_GET_STYLE) {
454 lv_get_style_info_t * info = param;
455 info->result = lv_gauge_get_style(gauge, info->part);
456 if(info->result != NULL) return LV_RES_OK;
457 else return ancestor_signal(gauge, sign, param);
458 }
459
460 /* Include the ancient signal function */
461 res = ancestor_signal(gauge, sign, param);
462 if(res != LV_RES_OK) return res;
463 if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
464
465 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
466 if(sign == LV_SIGNAL_CLEANUP) {
467 lv_mem_free(ext->values);
468 ext->values = NULL;
469 lv_obj_clean_style_list(gauge, LV_GAUGE_PART_NEEDLE);
470 lv_obj_clean_style_list(gauge, LV_GAUGE_PART_MAJOR);
471 }
472
473 return res;
474 }
475 /**
476 * Get the style descriptor of a part of the object
477 * @param page pointer the object
478 * @param part the part from `lv_gauge_part_t`. (LV_GAUGE_PART_...)
479 * @return pointer to the style descriptor of the specified part
480 */
lv_gauge_get_style(lv_obj_t * gauge,uint8_t part)481 static lv_style_list_t * lv_gauge_get_style(lv_obj_t * gauge, uint8_t part)
482 {
483 LV_ASSERT_OBJ(gauge, LV_OBJX_NAME);
484
485 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
486 lv_style_list_t * style_dsc_p;
487
488 switch(part) {
489 case LV_GAUGE_PART_MAIN:
490 style_dsc_p = &gauge->style_list;
491 break;
492 case LV_GAUGE_PART_MAJOR:
493 style_dsc_p = &ext->style_strong;
494 break;
495 case LV_GAUGE_PART_NEEDLE:
496 style_dsc_p = &ext->style_needle;
497 break;
498 default:
499 style_dsc_p = NULL;
500 }
501
502 return style_dsc_p;
503 }
504 /**
505 * Draw the scale on a gauge
506 * @param gauge pointer to gauge object
507 * @param mask mask of drawing
508 */
lv_gauge_draw_labels(lv_obj_t * gauge,const lv_area_t * mask)509 static void lv_gauge_draw_labels(lv_obj_t * gauge, const lv_area_t * mask)
510 {
511 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
512 lv_style_int_t scale_width = lv_obj_get_style_scale_width(gauge, LV_GAUGE_PART_MAJOR);
513 lv_style_int_t left = lv_obj_get_style_pad_left(gauge, LV_GAUGE_PART_MAIN);
514 lv_style_int_t right = lv_obj_get_style_pad_right(gauge, LV_GAUGE_PART_MAIN);
515 lv_style_int_t top = lv_obj_get_style_pad_top(gauge, LV_GAUGE_PART_MAIN);
516 lv_style_int_t txt_pad = lv_obj_get_style_pad_inner(gauge, LV_GAUGE_PART_MAIN);
517 lv_coord_t r = (lv_obj_get_width(gauge) - left - right) / 2 - scale_width - txt_pad;
518 lv_coord_t x_ofs = gauge->coords.x1 + r + left + scale_width + txt_pad;
519 lv_coord_t y_ofs = gauge->coords.y1 + r + top + scale_width + txt_pad;
520 int16_t scale_angle = lv_linemeter_get_scale_angle(gauge);
521 uint16_t label_num = ext->label_count;
522 int16_t angle_ofs = 90 + (360 - scale_angle) / 2 + lv_gauge_get_angle_offset(gauge);
523 int32_t min = lv_gauge_get_min_value(gauge);
524 int32_t max = lv_gauge_get_max_value(gauge);
525
526 lv_draw_label_dsc_t label_dsc;
527 lv_draw_label_dsc_init(&label_dsc);
528 lv_obj_init_draw_label_dsc(gauge, LV_GAUGE_PART_MAJOR, &label_dsc);
529
530 uint8_t i;
531 for(i = 0; i < label_num; i++) {
532 /*Calculate the position a scale label*/
533 int16_t angle = (i * scale_angle) / (label_num - 1) + angle_ofs;
534
535 lv_coord_t y = (int32_t)((int32_t)_lv_trigo_sin(angle) * r) / LV_TRIGO_SIN_MAX;
536 y += y_ofs;
537
538 lv_coord_t x = (int32_t)((int32_t)_lv_trigo_sin(angle + 90) * r) / LV_TRIGO_SIN_MAX;
539 x += x_ofs;
540
541 int32_t scale_act = (int32_t)((int32_t)(max - min) * i) / (label_num - 1);
542 scale_act += min;
543 char scale_txt[16];
544 if(ext->format_cb == NULL)
545 _lv_utils_num_to_str(scale_act, scale_txt);
546 else
547 ext->format_cb(gauge, scale_txt, sizeof(scale_txt), scale_act);
548
549 lv_area_t label_cord;
550 lv_point_t label_size;
551 _lv_txt_get_size(&label_size, scale_txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space,
552 LV_COORD_MAX, LV_TXT_FLAG_NONE);
553
554 /*Draw the label*/
555 label_cord.x1 = x - label_size.x / 2;
556 label_cord.y1 = y - label_size.y / 2;
557 label_cord.x2 = label_cord.x1 + label_size.x;
558 label_cord.y2 = label_cord.y1 + label_size.y;
559
560 lv_draw_label(&label_cord, mask, &label_dsc, scale_txt, NULL);
561 }
562 }
563 /**
564 * Draw the needles of a gauge
565 * @param gauge pointer to gauge object
566 * @param mask mask of drawing
567 */
lv_gauge_draw_needle(lv_obj_t * gauge,const lv_area_t * clip_area)568 static void lv_gauge_draw_needle(lv_obj_t * gauge, const lv_area_t * clip_area)
569 {
570 lv_gauge_ext_t * ext = lv_obj_get_ext_attr(gauge);
571
572 lv_style_int_t pad = lv_obj_get_style_pad_inner(gauge, LV_GAUGE_PART_NEEDLE);
573 lv_style_int_t left = lv_obj_get_style_pad_left(gauge, LV_GAUGE_PART_MAIN);
574 lv_style_int_t right = lv_obj_get_style_pad_right(gauge, LV_GAUGE_PART_MAIN);
575 lv_style_int_t top = lv_obj_get_style_pad_top(gauge, LV_GAUGE_PART_MAIN);
576
577 lv_coord_t r = (lv_obj_get_width(gauge) - left - right) / 2 - pad;
578 lv_coord_t x_ofs = gauge->coords.x1 + r + left + pad;
579 lv_coord_t y_ofs = gauge->coords.y1 + r + top + pad;
580 uint16_t angle = lv_linemeter_get_scale_angle(gauge);
581 int16_t angle_ofs = 90 + (360 - angle) / 2 + lv_gauge_get_angle_offset(gauge);
582 int16_t min = lv_gauge_get_min_value(gauge);
583 int16_t max = lv_gauge_get_max_value(gauge);
584 lv_point_t p_mid;
585 lv_point_t p_end;
586 uint8_t i;
587
588 lv_draw_line_dsc_t line_dsc;
589 lv_draw_line_dsc_init(&line_dsc);
590 lv_obj_init_draw_line_dsc(gauge, LV_GAUGE_PART_NEEDLE, &line_dsc);
591
592 p_mid.x = x_ofs;
593 p_mid.y = y_ofs;
594 for(i = 0; i < ext->needle_count; i++) {
595 /*Calculate the end point of a needle*/
596 int16_t needle_angle =
597 (ext->values[i] - min) * angle / (max - min) + angle_ofs;
598
599 /*Draw line*/
600 if(ext->needle_img == NULL) {
601 p_end.y = (_lv_trigo_sin(needle_angle) * r) / LV_TRIGO_SIN_MAX + y_ofs;
602 p_end.x = (_lv_trigo_sin(needle_angle + 90) * r) / LV_TRIGO_SIN_MAX + x_ofs;
603
604 /*Draw the needle with the corresponding color*/
605 if(ext->needle_colors != NULL) line_dsc.color = ext->needle_colors[i];
606
607 lv_draw_line(&p_mid, &p_end, clip_area, &line_dsc);
608 }
609 /*Draw image*/
610 else {
611 lv_img_header_t info;
612 lv_img_decoder_get_info(ext->needle_img, &info);
613
614 lv_area_t a;
615 a.x1 = gauge->coords.x1 + lv_area_get_width(&gauge->coords) / 2 - ext->needle_img_pivot.x;
616 a.y1 = gauge->coords.y1 + lv_area_get_height(&gauge->coords) / 2 - ext->needle_img_pivot.y;
617 a.x2 = a.x1 + info.w - 1;
618 a.y2 = a.y1 + info.h - 1;
619 lv_draw_img_dsc_t img_dsc;
620 lv_draw_img_dsc_init(&img_dsc);
621 lv_obj_init_draw_img_dsc(gauge, LV_GAUGE_PART_MAIN, &img_dsc);
622 img_dsc.pivot.x = ext->needle_img_pivot.x;
623 img_dsc.pivot.y = ext->needle_img_pivot.y;
624
625 if(ext->needle_colors != NULL)
626 img_dsc.recolor = ext->needle_colors[i];
627
628 needle_angle = (needle_angle * 10);
629 if(needle_angle > 3600) needle_angle -= 3600;
630 img_dsc.angle = needle_angle;
631 lv_draw_img(&a, clip_area, ext->needle_img, &img_dsc);
632 }
633 }
634
635 lv_draw_rect_dsc_t mid_dsc;
636 lv_draw_rect_dsc_init(&mid_dsc);
637 lv_obj_init_draw_rect_dsc(gauge, LV_GAUGE_PART_NEEDLE, &mid_dsc);
638 lv_style_int_t size = lv_obj_get_style_size(gauge, LV_GAUGE_PART_NEEDLE) / 2;
639 lv_area_t nm_cord;
640 nm_cord.x1 = x_ofs - size;
641 nm_cord.y1 = y_ofs - size;
642 nm_cord.x2 = x_ofs + size;
643 nm_cord.y2 = y_ofs + size;
644 lv_draw_rect(&nm_cord, clip_area, &mid_dsc);
645 }
646
647 #endif
648