1 /**
2 * @file lv_meter.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_meter.h"
10 #if LV_USE_METER != 0
11
12 #include "../../../misc/lv_assert.h"
13
14 /*********************
15 * DEFINES
16 *********************/
17 #define MY_CLASS &lv_meter_class
18
19 /**********************
20 * TYPEDEFS
21 **********************/
22
23 /**********************
24 * STATIC PROTOTYPES
25 **********************/
26 static void lv_meter_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
27 static void lv_meter_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
28 static void lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e);
29 static void draw_arcs(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area);
30 static void draw_ticks_and_labels(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area);
31 static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area);
32 static void inv_arc(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t old_value, int32_t new_value);
33 static void inv_line(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value);
34
35 /**********************
36 * STATIC VARIABLES
37 **********************/
38 const lv_obj_class_t lv_meter_class = {
39 .constructor_cb = lv_meter_constructor,
40 .destructor_cb = lv_meter_destructor,
41 .event_cb = lv_meter_event,
42 .instance_size = sizeof(lv_meter_t),
43 .base_class = &lv_obj_class
44 };
45
46 /**********************
47 * MACROS
48 **********************/
49
50 /**********************
51 * GLOBAL FUNCTIONS
52 **********************/
53
lv_meter_create(lv_obj_t * parent)54 lv_obj_t * lv_meter_create(lv_obj_t * parent)
55 {
56 LV_LOG_INFO("begin");
57 lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
58 lv_obj_class_init_obj(obj);
59 return obj;
60 }
61
62 /*=====================
63 * Add scale
64 *====================*/
65
lv_meter_add_scale(lv_obj_t * obj)66 lv_meter_scale_t * lv_meter_add_scale(lv_obj_t * obj)
67 {
68 LV_ASSERT_OBJ(obj, MY_CLASS);
69 lv_meter_t * meter = (lv_meter_t *)obj;
70
71 lv_meter_scale_t * scale = _lv_ll_ins_head(&meter->scale_ll);
72 LV_ASSERT_MALLOC(scale);
73 lv_memset_00(scale, sizeof(lv_meter_scale_t));
74
75 scale->angle_range = 270;
76 scale->rotation = 90 + (360 - scale->angle_range) / 2;
77 scale->min = 0;
78 scale->max = 100;
79 scale->tick_cnt = 6;
80 scale->tick_length = 8;
81 scale->tick_width = 2;
82 scale->label_gap = 2;
83
84 return scale;
85 }
86
lv_meter_set_scale_ticks(lv_obj_t * obj,lv_meter_scale_t * scale,uint16_t cnt,uint16_t width,uint16_t len,lv_color_t color)87 void lv_meter_set_scale_ticks(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t cnt, uint16_t width, uint16_t len,
88 lv_color_t color)
89 {
90 scale->tick_cnt = cnt;
91 scale->tick_width = width;
92 scale->tick_length = len;
93 scale->tick_color = color;
94 lv_obj_invalidate(obj);
95 }
96
lv_meter_set_scale_major_ticks(lv_obj_t * obj,lv_meter_scale_t * scale,uint16_t nth,uint16_t width,uint16_t len,lv_color_t color,int16_t label_gap)97 void lv_meter_set_scale_major_ticks(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t nth, uint16_t width,
98 uint16_t len, lv_color_t color, int16_t label_gap)
99 {
100 scale->tick_major_nth = nth;
101 scale->tick_major_width = width;
102 scale->tick_major_length = len;
103 scale->tick_major_color = color;
104 scale->label_gap = label_gap;
105 lv_obj_invalidate(obj);
106 }
107
lv_meter_set_scale_range(lv_obj_t * obj,lv_meter_scale_t * scale,int32_t min,int32_t max,uint32_t angle_range,uint32_t rotation)108 void lv_meter_set_scale_range(lv_obj_t * obj, lv_meter_scale_t * scale, int32_t min, int32_t max, uint32_t angle_range,
109 uint32_t rotation)
110 {
111 scale->min = min;
112 scale->max = max;
113 scale->angle_range = angle_range;
114 scale->rotation = rotation;
115 lv_obj_invalidate(obj);
116 }
117
118 /*=====================
119 * Add indicator
120 *====================*/
121
lv_meter_add_needle_line(lv_obj_t * obj,lv_meter_scale_t * scale,uint16_t width,lv_color_t color,int16_t r_mod)122 lv_meter_indicator_t * lv_meter_add_needle_line(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t width,
123 lv_color_t color, int16_t r_mod)
124 {
125 LV_ASSERT_OBJ(obj, MY_CLASS);
126 lv_meter_t * meter = (lv_meter_t *)obj;
127 lv_meter_indicator_t * indic = _lv_ll_ins_head(&meter->indicator_ll);
128 LV_ASSERT_MALLOC(indic);
129 lv_memset_00(indic, sizeof(lv_meter_indicator_t));
130 indic->scale = scale;
131 indic->opa = LV_OPA_COVER;
132
133 indic->type = LV_METER_INDICATOR_TYPE_NEEDLE_LINE;
134 indic->type_data.needle_line.width = width;
135 indic->type_data.needle_line.color = color;
136 indic->type_data.needle_line.r_mod = r_mod;
137 lv_obj_invalidate(obj);
138
139 return indic;
140 }
141
lv_meter_add_needle_img(lv_obj_t * obj,lv_meter_scale_t * scale,const void * src,lv_coord_t pivot_x,lv_coord_t pivot_y)142 lv_meter_indicator_t * lv_meter_add_needle_img(lv_obj_t * obj, lv_meter_scale_t * scale, const void * src,
143 lv_coord_t pivot_x, lv_coord_t pivot_y)
144 {
145 LV_ASSERT_OBJ(obj, MY_CLASS);
146 lv_meter_t * meter = (lv_meter_t *)obj;
147 lv_meter_indicator_t * indic = _lv_ll_ins_head(&meter->indicator_ll);
148 LV_ASSERT_MALLOC(indic);
149 lv_memset_00(indic, sizeof(lv_meter_indicator_t));
150 indic->scale = scale;
151 indic->opa = LV_OPA_COVER;
152
153 indic->type = LV_METER_INDICATOR_TYPE_NEEDLE_IMG;
154 indic->type_data.needle_img.src = src;
155 indic->type_data.needle_img.pivot.x = pivot_x;
156 indic->type_data.needle_img.pivot.y = pivot_y;
157 lv_obj_invalidate(obj);
158
159 return indic;
160 }
161
lv_meter_add_arc(lv_obj_t * obj,lv_meter_scale_t * scale,uint16_t width,lv_color_t color,int16_t r_mod)162 lv_meter_indicator_t * lv_meter_add_arc(lv_obj_t * obj, lv_meter_scale_t * scale, uint16_t width, lv_color_t color,
163 int16_t r_mod)
164 {
165 LV_ASSERT_OBJ(obj, MY_CLASS);
166 lv_meter_t * meter = (lv_meter_t *)obj;
167 lv_meter_indicator_t * indic = _lv_ll_ins_head(&meter->indicator_ll);
168 LV_ASSERT_MALLOC(indic);
169 lv_memset_00(indic, sizeof(lv_meter_indicator_t));
170 indic->scale = scale;
171 indic->opa = LV_OPA_COVER;
172
173 indic->type = LV_METER_INDICATOR_TYPE_ARC;
174 indic->type_data.arc.width = width;
175 indic->type_data.arc.color = color;
176 indic->type_data.arc.r_mod = r_mod;
177
178 lv_obj_invalidate(obj);
179 return indic;
180 }
181
lv_meter_add_scale_lines(lv_obj_t * obj,lv_meter_scale_t * scale,lv_color_t color_start,lv_color_t color_end,bool local,int16_t width_mod)182 lv_meter_indicator_t * lv_meter_add_scale_lines(lv_obj_t * obj, lv_meter_scale_t * scale, lv_color_t color_start,
183 lv_color_t color_end, bool local, int16_t width_mod)
184 {
185 LV_ASSERT_OBJ(obj, MY_CLASS);
186 lv_meter_t * meter = (lv_meter_t *)obj;
187 lv_meter_indicator_t * indic = _lv_ll_ins_head(&meter->indicator_ll);
188 LV_ASSERT_MALLOC(indic);
189 lv_memset_00(indic, sizeof(lv_meter_indicator_t));
190 indic->scale = scale;
191 indic->opa = LV_OPA_COVER;
192
193 indic->type = LV_METER_INDICATOR_TYPE_SCALE_LINES;
194 indic->type_data.scale_lines.color_start = color_start;
195 indic->type_data.scale_lines.color_end = color_end;
196 indic->type_data.scale_lines.local_grad = local;
197 indic->type_data.scale_lines.width_mod = width_mod;
198
199 lv_obj_invalidate(obj);
200 return indic;
201 }
202
203 /*=====================
204 * Set indicator value
205 *====================*/
206
lv_meter_set_indicator_value(lv_obj_t * obj,lv_meter_indicator_t * indic,int32_t value)207 void lv_meter_set_indicator_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value)
208 {
209 int32_t old_start = indic->start_value;
210 int32_t old_end = indic->end_value;
211 indic->start_value = value;
212 indic->end_value = value;
213
214 if(indic->type == LV_METER_INDICATOR_TYPE_ARC) {
215 inv_arc(obj, indic, old_start, value);
216 inv_arc(obj, indic, old_end, value);
217 }
218 else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG || indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
219 inv_line(obj, indic, old_start);
220 inv_line(obj, indic, old_end);
221 inv_line(obj, indic, value);
222 }
223 else {
224 lv_obj_invalidate(obj);
225 }
226 }
227
lv_meter_set_indicator_start_value(lv_obj_t * obj,lv_meter_indicator_t * indic,int32_t value)228 void lv_meter_set_indicator_start_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value)
229 {
230 int32_t old_value = indic->start_value;
231 indic->start_value = value;
232
233 if(indic->type == LV_METER_INDICATOR_TYPE_ARC) {
234 inv_arc(obj, indic, old_value, value);
235 }
236 else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG || indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
237 inv_line(obj, indic, old_value);
238 inv_line(obj, indic, value);
239 }
240 else {
241 lv_obj_invalidate(obj);
242 }
243 }
244
lv_meter_set_indicator_end_value(lv_obj_t * obj,lv_meter_indicator_t * indic,int32_t value)245 void lv_meter_set_indicator_end_value(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value)
246 {
247 int32_t old_value = indic->end_value;
248 indic->end_value = value;
249
250 if(indic->type == LV_METER_INDICATOR_TYPE_ARC) {
251 inv_arc(obj, indic, old_value, value);
252 }
253 else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG || indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
254 inv_line(obj, indic, old_value);
255 inv_line(obj, indic, value);
256 }
257 else {
258 lv_obj_invalidate(obj);
259 }
260 }
261
262 /**********************
263 * STATIC FUNCTIONS
264 **********************/
265
lv_meter_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)266 static void lv_meter_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
267 {
268 LV_UNUSED(class_p);
269 LV_TRACE_OBJ_CREATE("begin");
270
271 lv_meter_t * meter = (lv_meter_t *)obj;
272
273 _lv_ll_init(&meter->scale_ll, sizeof(lv_meter_scale_t));
274 _lv_ll_init(&meter->indicator_ll, sizeof(lv_meter_indicator_t));
275
276 LV_TRACE_OBJ_CREATE("finished");
277 }
278
lv_meter_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)279 static void lv_meter_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
280 {
281 LV_UNUSED(class_p);
282 LV_ASSERT_OBJ(obj, MY_CLASS);
283 lv_meter_t * meter = (lv_meter_t *)obj;
284 _lv_ll_clear(&meter->indicator_ll);
285 _lv_ll_clear(&meter->scale_ll);
286
287 }
288
lv_meter_event(const lv_obj_class_t * class_p,lv_event_t * e)289 static void lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e)
290 {
291 LV_UNUSED(class_p);
292
293 lv_res_t res = lv_obj_event_base(MY_CLASS, e);
294 if(res != LV_RES_OK) return;
295
296 lv_event_code_t code = lv_event_get_code(e);
297 lv_obj_t * obj = lv_event_get_target(e);
298 if(code == LV_EVENT_DRAW_MAIN) {
299 lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
300 lv_area_t scale_area;
301 lv_obj_get_content_coords(obj, &scale_area);
302
303 draw_arcs(obj, draw_ctx, &scale_area);
304 draw_ticks_and_labels(obj, draw_ctx, &scale_area);
305 draw_needles(obj, draw_ctx, &scale_area);
306
307 lv_coord_t r_edge = lv_area_get_width(&scale_area) / 2;
308 lv_point_t scale_center;
309 scale_center.x = scale_area.x1 + r_edge;
310 scale_center.y = scale_area.y1 + r_edge;
311
312 lv_draw_rect_dsc_t mid_dsc;
313 lv_draw_rect_dsc_init(&mid_dsc);
314 lv_obj_init_draw_rect_dsc(obj, LV_PART_INDICATOR, &mid_dsc);
315 lv_coord_t w = lv_obj_get_style_width(obj, LV_PART_INDICATOR) / 2;
316 lv_coord_t h = lv_obj_get_style_height(obj, LV_PART_INDICATOR) / 2;
317 lv_area_t nm_cord;
318 nm_cord.x1 = scale_center.x - w;
319 nm_cord.y1 = scale_center.y - h;
320 nm_cord.x2 = scale_center.x + w;
321 nm_cord.y2 = scale_center.y + h;
322 lv_draw_rect(draw_ctx, &mid_dsc, &nm_cord);
323 }
324 }
325
draw_arcs(lv_obj_t * obj,lv_draw_ctx_t * draw_ctx,const lv_area_t * scale_area)326 static void draw_arcs(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area)
327 {
328 lv_meter_t * meter = (lv_meter_t *)obj;
329
330 lv_draw_arc_dsc_t arc_dsc;
331 lv_draw_arc_dsc_init(&arc_dsc);
332 arc_dsc.rounded = lv_obj_get_style_arc_rounded(obj, LV_PART_ITEMS);
333
334 lv_coord_t r_out = lv_area_get_width(scale_area) / 2 ;
335 lv_point_t scale_center;
336 scale_center.x = scale_area->x1 + r_out;
337 scale_center.y = scale_area->y1 + r_out;
338
339 lv_opa_t opa_main = lv_obj_get_style_opa_recursive(obj, LV_PART_MAIN);
340 lv_meter_indicator_t * indic;
341
342 lv_obj_draw_part_dsc_t part_draw_dsc;
343 lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx);
344 part_draw_dsc.arc_dsc = &arc_dsc;
345 part_draw_dsc.part = LV_PART_INDICATOR;
346 part_draw_dsc.class_p = MY_CLASS;
347 part_draw_dsc.type = LV_METER_DRAW_PART_ARC;
348
349 _LV_LL_READ_BACK(&meter->indicator_ll, indic) {
350 if(indic->type != LV_METER_INDICATOR_TYPE_ARC) continue;
351
352 arc_dsc.color = indic->type_data.arc.color;
353 arc_dsc.width = indic->type_data.arc.width;
354 arc_dsc.opa = indic->opa > LV_OPA_MAX ? opa_main : (opa_main * indic->opa) >> 8;
355
356 lv_meter_scale_t * scale = indic->scale;
357
358 int32_t start_angle = lv_map(indic->start_value, scale->min, scale->max, scale->rotation,
359 scale->rotation + scale->angle_range);
360 int32_t end_angle = lv_map(indic->end_value, scale->min, scale->max, scale->rotation,
361 scale->rotation + scale->angle_range);
362
363 arc_dsc.start_angle = start_angle;
364 arc_dsc.end_angle = end_angle;
365 part_draw_dsc.radius = r_out + indic->type_data.arc.r_mod;
366 part_draw_dsc.sub_part_ptr = indic;
367 part_draw_dsc.p1 = &scale_center;
368
369 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
370 lv_draw_arc(draw_ctx, &arc_dsc, &scale_center, part_draw_dsc.radius, start_angle, end_angle);
371 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
372 }
373 }
374
draw_ticks_and_labels(lv_obj_t * obj,lv_draw_ctx_t * draw_ctx,const lv_area_t * scale_area)375 static void draw_ticks_and_labels(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area)
376 {
377 lv_meter_t * meter = (lv_meter_t *)obj;
378
379 lv_point_t p_center;
380 lv_coord_t r_edge = LV_MIN(lv_area_get_width(scale_area) / 2, lv_area_get_height(scale_area) / 2);
381 p_center.x = scale_area->x1 + r_edge;
382 p_center.y = scale_area->y1 + r_edge;
383
384 lv_draw_line_dsc_t line_dsc;
385 lv_draw_line_dsc_init(&line_dsc);
386 lv_obj_init_draw_line_dsc(obj, LV_PART_TICKS, &line_dsc);
387 line_dsc.raw_end = 1;
388
389 lv_draw_label_dsc_t label_dsc;
390 lv_draw_label_dsc_init(&label_dsc);
391 lv_obj_init_draw_label_dsc(obj, LV_PART_TICKS, &label_dsc);
392
393 lv_meter_scale_t * scale;
394
395 lv_draw_mask_radius_param_t inner_minor_mask;
396 lv_draw_mask_radius_param_t inner_major_mask;
397 lv_draw_mask_radius_param_t outer_mask;
398
399 lv_obj_draw_part_dsc_t part_draw_dsc;
400 lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx);
401 part_draw_dsc.class_p = MY_CLASS;
402 part_draw_dsc.part = LV_PART_TICKS;
403 part_draw_dsc.type = LV_METER_DRAW_PART_TICK;
404 part_draw_dsc.line_dsc = &line_dsc;
405
406 _LV_LL_READ_BACK(&meter->scale_ll, scale) {
407 part_draw_dsc.sub_part_ptr = scale;
408
409 lv_coord_t r_out = r_edge;
410 lv_coord_t r_in_minor = r_out - scale->tick_length;
411 lv_coord_t r_in_major = r_out - scale->tick_major_length;
412
413 lv_area_t area_inner_minor;
414 area_inner_minor.x1 = p_center.x - r_in_minor;
415 area_inner_minor.y1 = p_center.y - r_in_minor;
416 area_inner_minor.x2 = p_center.x + r_in_minor;
417 area_inner_minor.y2 = p_center.y + r_in_minor;
418 lv_draw_mask_radius_init(&inner_minor_mask, &area_inner_minor, LV_RADIUS_CIRCLE, true);
419
420 lv_area_t area_inner_major;
421 area_inner_major.x1 = p_center.x - r_in_major;
422 area_inner_major.y1 = p_center.y - r_in_major;
423 area_inner_major.x2 = p_center.x + r_in_major - 1;
424 area_inner_major.y2 = p_center.y + r_in_major - 1;
425 lv_draw_mask_radius_init(&inner_major_mask, &area_inner_major, LV_RADIUS_CIRCLE, true);
426
427 lv_area_t area_outer;
428 area_outer.x1 = p_center.x - r_out;
429 area_outer.y1 = p_center.y - r_out;
430 area_outer.x2 = p_center.x + r_out - 1;
431 area_outer.y2 = p_center.y + r_out - 1;
432 lv_draw_mask_radius_init(&outer_mask, &area_outer, LV_RADIUS_CIRCLE, false);
433 int16_t outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
434
435 int16_t inner_act_mask_id = LV_MASK_ID_INV; /*Will be added later*/
436
437 uint32_t minor_cnt = scale->tick_major_nth ? scale->tick_major_nth - 1 : 0xFFFF;
438 uint16_t i;
439 for(i = 0; i < scale->tick_cnt; i++) {
440 minor_cnt++;
441 bool major = false;
442 if(minor_cnt == scale->tick_major_nth) {
443 minor_cnt = 0;
444 major = true;
445 }
446
447 int32_t value_of_line = lv_map(i, 0, scale->tick_cnt - 1, scale->min, scale->max);
448 part_draw_dsc.value = value_of_line;
449
450 lv_color_t line_color = major ? scale->tick_major_color : scale->tick_color;
451 lv_color_t line_color_ori = line_color;
452
453 lv_coord_t line_width_ori = major ? scale->tick_major_width : scale->tick_width;
454 lv_coord_t line_width = line_width_ori;
455
456 lv_meter_indicator_t * indic;
457 _LV_LL_READ_BACK(&meter->indicator_ll, indic) {
458 if(indic->type != LV_METER_INDICATOR_TYPE_SCALE_LINES) continue;
459 if(value_of_line >= indic->start_value && value_of_line <= indic->end_value) {
460 line_width += indic->type_data.scale_lines.width_mod;
461
462 if(indic->type_data.scale_lines.color_start.full == indic->type_data.scale_lines.color_end.full) {
463 line_color = indic->type_data.scale_lines.color_start;
464 }
465 else {
466 lv_opa_t ratio;
467 if(indic->type_data.scale_lines.local_grad) {
468 ratio = lv_map(value_of_line, indic->start_value, indic->end_value, LV_OPA_TRANSP, LV_OPA_COVER);
469 }
470 else {
471 ratio = lv_map(value_of_line, scale->min, scale->max, LV_OPA_TRANSP, LV_OPA_COVER);
472 }
473 line_color = lv_color_mix(indic->type_data.scale_lines.color_end, indic->type_data.scale_lines.color_start, ratio);
474 }
475 }
476 }
477
478 int32_t angle_upscale = ((i * scale->angle_range) * 10) / (scale->tick_cnt - 1) + + scale->rotation * 10;
479
480 line_dsc.color = line_color;
481 line_dsc.width = line_width;
482
483 /*Draw a little bit longer lines to be sure the mask will clip them correctly
484 *and to get a better precision*/
485 lv_point_t p_outer;
486 p_outer.x = p_center.x + r_out + LV_MAX(LV_DPI_DEF, r_out);
487 p_outer.y = p_center.y;
488 lv_point_transform(&p_outer, angle_upscale, 256, &p_center);
489
490 part_draw_dsc.p1 = &p_center;
491 part_draw_dsc.p2 = &p_outer;
492 part_draw_dsc.id = i;
493 part_draw_dsc.label_dsc = &label_dsc;
494
495 /*Draw the text*/
496 if(major) {
497 lv_draw_mask_remove_id(outer_mask_id);
498 uint32_t r_text = r_in_major - scale->label_gap;
499 lv_point_t p;
500 p.x = p_center.x + r_text;
501 p.y = p_center.y;
502 lv_point_transform(&p, angle_upscale, 256, &p_center);
503
504 lv_draw_label_dsc_t label_dsc_tmp;
505 lv_memcpy(&label_dsc_tmp, &label_dsc, sizeof(label_dsc_tmp));
506
507 part_draw_dsc.label_dsc = &label_dsc_tmp;
508 char buf[16];
509
510 lv_snprintf(buf, sizeof(buf), "%" LV_PRId32, value_of_line);
511 part_draw_dsc.text = buf;
512
513 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
514
515 lv_point_t label_size;
516 lv_txt_get_size(&label_size, part_draw_dsc.text, label_dsc_tmp.font, label_dsc_tmp.letter_space,
517 label_dsc_tmp.line_space,
518 LV_COORD_MAX, LV_TEXT_FLAG_NONE);
519
520 lv_area_t label_cord;
521 label_cord.x1 = p.x - label_size.x / 2;
522 label_cord.y1 = p.y - label_size.y / 2;
523 label_cord.x2 = label_cord.x1 + label_size.x;
524 label_cord.y2 = label_cord.y1 + label_size.y;
525
526 lv_draw_label(draw_ctx, part_draw_dsc.label_dsc, &label_cord, part_draw_dsc.text, NULL);
527
528 outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
529 }
530 else {
531 part_draw_dsc.label_dsc = NULL;
532 part_draw_dsc.text = NULL;
533 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
534 }
535
536 inner_act_mask_id = lv_draw_mask_add(major ? &inner_major_mask : &inner_minor_mask, NULL);
537 lv_draw_line(draw_ctx, &line_dsc, &p_outer, &p_center);
538 lv_draw_mask_remove_id(inner_act_mask_id);
539 lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, &part_draw_dsc);
540
541 line_dsc.color = line_color_ori;
542 line_dsc.width = line_width_ori;
543
544 }
545 lv_draw_mask_free_param(&inner_minor_mask);
546 lv_draw_mask_free_param(&inner_major_mask);
547 lv_draw_mask_free_param(&outer_mask);
548 lv_draw_mask_remove_id(outer_mask_id);
549 }
550 }
551
draw_needles(lv_obj_t * obj,lv_draw_ctx_t * draw_ctx,const lv_area_t * scale_area)552 static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area)
553 {
554 lv_meter_t * meter = (lv_meter_t *)obj;
555
556 lv_coord_t r_edge = lv_area_get_width(scale_area) / 2;
557 lv_point_t scale_center;
558 scale_center.x = scale_area->x1 + r_edge;
559 scale_center.y = scale_area->y1 + r_edge;
560
561 lv_draw_line_dsc_t line_dsc;
562 lv_draw_line_dsc_init(&line_dsc);
563 lv_obj_init_draw_line_dsc(obj, LV_PART_ITEMS, &line_dsc);
564
565 lv_draw_img_dsc_t img_dsc;
566 lv_draw_img_dsc_init(&img_dsc);
567 lv_obj_init_draw_img_dsc(obj, LV_PART_ITEMS, &img_dsc);
568 lv_opa_t opa_main = lv_obj_get_style_opa_recursive(obj, LV_PART_MAIN);
569
570 lv_obj_draw_part_dsc_t part_draw_dsc;
571 lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx);
572 part_draw_dsc.class_p = MY_CLASS;
573 part_draw_dsc.p1 = &scale_center;
574 part_draw_dsc.part = LV_PART_INDICATOR;
575
576 lv_meter_indicator_t * indic;
577 _LV_LL_READ_BACK(&meter->indicator_ll, indic) {
578 lv_meter_scale_t * scale = indic->scale;
579 part_draw_dsc.sub_part_ptr = indic;
580
581 if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
582 int32_t angle = lv_map(indic->end_value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
583 lv_coord_t r_out = r_edge + scale->r_mod + indic->type_data.needle_line.r_mod;
584 lv_point_t p_end;
585 p_end.y = (lv_trigo_sin(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.y;
586 p_end.x = (lv_trigo_cos(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.x;
587 line_dsc.color = indic->type_data.needle_line.color;
588 line_dsc.width = indic->type_data.needle_line.width;
589 line_dsc.opa = indic->opa > LV_OPA_MAX ? opa_main : (opa_main * indic->opa) >> 8;
590
591 part_draw_dsc.type = LV_METER_DRAW_PART_NEEDLE_LINE;
592 part_draw_dsc.line_dsc = &line_dsc;
593 part_draw_dsc.p2 = &p_end;
594 part_draw_dsc.p1 = &scale_center;
595 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
596 lv_draw_line(draw_ctx, &line_dsc, part_draw_dsc.p1, &p_end);
597 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
598 }
599 else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG) {
600 if(indic->type_data.needle_img.src == NULL) continue;
601
602 int32_t angle = lv_map(indic->end_value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
603 lv_img_header_t info;
604 lv_img_decoder_get_info(indic->type_data.needle_img.src, &info);
605 lv_area_t a;
606 a.x1 = scale_center.x - indic->type_data.needle_img.pivot.x;
607 a.y1 = scale_center.y - indic->type_data.needle_img.pivot.y;
608 a.x2 = a.x1 + info.w - 1;
609 a.y2 = a.y1 + info.h - 1;
610
611 img_dsc.opa = indic->opa > LV_OPA_MAX ? opa_main : (opa_main * indic->opa) >> 8;
612 img_dsc.pivot.x = indic->type_data.needle_img.pivot.x;
613 img_dsc.pivot.y = indic->type_data.needle_img.pivot.y;
614 angle = angle * 10;
615 if(angle > 3600) angle -= 3600;
616 img_dsc.angle = angle;
617
618 part_draw_dsc.type = LV_METER_DRAW_PART_NEEDLE_IMG;
619 part_draw_dsc.img_dsc = &img_dsc;
620
621 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
622 lv_draw_img(draw_ctx, &img_dsc, &a, indic->type_data.needle_img.src);
623 lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
624 }
625 }
626 }
627
inv_arc(lv_obj_t * obj,lv_meter_indicator_t * indic,int32_t old_value,int32_t new_value)628 static void inv_arc(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t old_value, int32_t new_value)
629 {
630 bool rounded = lv_obj_get_style_arc_rounded(obj, LV_PART_ITEMS);
631
632 lv_area_t scale_area;
633 lv_obj_get_content_coords(obj, &scale_area);
634
635 lv_coord_t r_out = lv_area_get_width(&scale_area) / 2;
636 lv_point_t scale_center;
637 scale_center.x = scale_area.x1 + r_out;
638 scale_center.y = scale_area.y1 + r_out;
639
640 r_out += indic->type_data.arc.r_mod;
641
642 lv_meter_scale_t * scale = indic->scale;
643
644 int32_t start_angle = lv_map(old_value, scale->min, scale->max, scale->rotation, scale->angle_range + scale->rotation);
645 int32_t end_angle = lv_map(new_value, scale->min, scale->max, scale->rotation, scale->angle_range + scale->rotation);
646
647 lv_area_t a;
648 lv_draw_arc_get_area(scale_center.x, scale_center.y, r_out, LV_MIN(start_angle, end_angle), LV_MAX(start_angle,
649 end_angle), indic->type_data.arc.width, rounded, &a);
650 lv_obj_invalidate_area(obj, &a);
651 }
652
inv_line(lv_obj_t * obj,lv_meter_indicator_t * indic,int32_t value)653 static void inv_line(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value)
654 {
655 lv_area_t scale_area;
656 lv_obj_get_content_coords(obj, &scale_area);
657
658 lv_coord_t r_out = lv_area_get_width(&scale_area) / 2;
659 lv_point_t scale_center;
660 scale_center.x = scale_area.x1 + r_out;
661 scale_center.y = scale_area.y1 + r_out;
662
663 lv_meter_scale_t * scale = indic->scale;
664
665 if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
666 int32_t angle = lv_map(value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
667 r_out += scale->r_mod + indic->type_data.needle_line.r_mod;
668 lv_point_t p_end;
669 p_end.y = (lv_trigo_sin(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.y;
670 p_end.x = (lv_trigo_cos(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.x;
671
672 lv_area_t a;
673 a.x1 = LV_MIN(scale_center.x, p_end.x) - indic->type_data.needle_line.width - 2;
674 a.y1 = LV_MIN(scale_center.y, p_end.y) - indic->type_data.needle_line.width - 2;
675 a.x2 = LV_MAX(scale_center.x, p_end.x) + indic->type_data.needle_line.width + 2;
676 a.y2 = LV_MAX(scale_center.y, p_end.y) + indic->type_data.needle_line.width + 2;
677
678 lv_obj_invalidate_area(obj, &a);
679 }
680 else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG) {
681 int32_t angle = lv_map(value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
682 lv_img_header_t info;
683 lv_img_decoder_get_info(indic->type_data.needle_img.src, &info);
684
685 angle = angle * 10;
686 if(angle > 3600) angle -= 3600;
687
688 scale_center.x -= indic->type_data.needle_img.pivot.x;
689 scale_center.y -= indic->type_data.needle_img.pivot.y;
690 lv_area_t a;
691 _lv_img_buf_get_transformed_area(&a, info.w, info.h, angle, LV_IMG_ZOOM_NONE, &indic->type_data.needle_img.pivot);
692 a.x1 += scale_center.x - 2;
693 a.y1 += scale_center.y - 2;
694 a.x2 += scale_center.x + 2;
695 a.y2 += scale_center.y + 2;
696
697 lv_obj_invalidate_area(obj, &a);
698 }
699 }
700 #endif
701