1 /**
2 * @file lv_linemeter.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_linemeter.h"
10 #if LV_USE_LINEMETER != 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_core/lv_group.h"
16 #include "../lv_misc/lv_math.h"
17
18 /*********************
19 * DEFINES
20 *********************/
21 #define LV_OBJX_NAME "lv_linemeter"
22
23 /**********************
24 * TYPEDEFS
25 **********************/
26
27 /**********************
28 * STATIC PROTOTYPES
29 **********************/
30 static lv_design_res_t lv_linemeter_design(lv_obj_t * lmeter, const lv_area_t * clip_area, lv_design_mode_t mode);
31 static lv_res_t lv_linemeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param);
32
33 /**********************
34 * STATIC VARIABLES
35 **********************/
36 static lv_signal_cb_t ancestor_signal;
37
38 /**********************
39 * MACROS
40 **********************/
41
42 /**********************
43 * GLOBAL FUNCTIONS
44 **********************/
45
46 /**
47 * Create a line meter objects
48 * @param par pointer to an object, it will be the parent of the new line meter
49 * @param copy pointer to a line meter object, if not NULL then the new object will be copied from
50 * it
51 * @return pointer to the created line meter
52 */
lv_linemeter_create(lv_obj_t * par,const lv_obj_t * copy)53 lv_obj_t * lv_linemeter_create(lv_obj_t * par, const lv_obj_t * copy)
54 {
55 LV_LOG_TRACE("line meter create started");
56
57 /*Create the ancestor of line meter*/
58 lv_obj_t * linemeter = lv_obj_create(par, copy);
59 LV_ASSERT_MEM(linemeter);
60 if(linemeter == NULL) return NULL;
61
62 if(ancestor_signal == NULL) ancestor_signal = lv_obj_get_signal_cb(linemeter);
63
64 /*Allocate the line meter type specific extended data*/
65 lv_linemeter_ext_t * ext = lv_obj_allocate_ext_attr(linemeter, sizeof(lv_linemeter_ext_t));
66 LV_ASSERT_MEM(ext);
67 if(ext == NULL) {
68 lv_obj_del(linemeter);
69 return NULL;
70 }
71
72 /*Initialize the allocated 'ext' */
73 ext->min_value = 0;
74 ext->max_value = 100;
75 ext->cur_value = 0;
76 ext->line_cnt = 18;
77 ext->scale_angle = 240;
78 ext->angle_ofs = 0;
79 ext->mirrored = 0;
80
81 /*The signal and design functions are not copied so set them here*/
82 lv_obj_set_signal_cb(linemeter, lv_linemeter_signal);
83 lv_obj_set_design_cb(linemeter, lv_linemeter_design);
84
85 /*Init the new line meter line meter*/
86 if(copy == NULL) {
87 lv_obj_set_size(linemeter, 3 * LV_DPI / 2, 3 * LV_DPI / 2);
88 lv_theme_apply(linemeter, LV_THEME_LINEMETER);
89 }
90 /*Copy an existing line meter*/
91 else {
92 lv_linemeter_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
93 ext->scale_angle = copy_ext->scale_angle;
94 ext->line_cnt = copy_ext->line_cnt;
95 ext->min_value = copy_ext->min_value;
96 ext->max_value = copy_ext->max_value;
97 ext->cur_value = copy_ext->cur_value;
98
99 /*Refresh the style with new signal function*/
100 lv_obj_refresh_style(linemeter, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL);
101 }
102
103 LV_LOG_INFO("line meter created");
104
105 return linemeter;
106 }
107
108 /*=====================
109 * Setter functions
110 *====================*/
111
112 /**
113 * Set a new value on the line meter
114 * @param lmeter pointer to a line meter object
115 * @param value new value
116 */
lv_linemeter_set_value(lv_obj_t * lmeter,int32_t value)117 void lv_linemeter_set_value(lv_obj_t * lmeter, int32_t value)
118 {
119 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
120
121 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
122 if(ext->cur_value == value) return;
123
124 int32_t old_value = ext->cur_value;
125
126 ext->cur_value = value > ext->max_value ? ext->max_value : value;
127 ext->cur_value = ext->cur_value < ext->min_value ? ext->min_value : ext->cur_value;
128
129 int16_t level_old =
130 (int32_t)((int32_t)(old_value - ext->min_value) * (ext->line_cnt - 1)) / (ext->max_value - ext->min_value);
131 int16_t level_new =
132 (int32_t)((int32_t)(ext->cur_value - ext->min_value) * (ext->line_cnt - 1)) / (ext->max_value - ext->min_value);
133
134 if(level_new == level_old) {
135 return;
136 }
137
138 lv_style_int_t left = lv_obj_get_style_pad_left(lmeter, LV_LINEMETER_PART_MAIN);
139 lv_style_int_t right = lv_obj_get_style_pad_right(lmeter, LV_LINEMETER_PART_MAIN);
140 lv_style_int_t top = lv_obj_get_style_pad_top(lmeter, LV_LINEMETER_PART_MAIN);
141 lv_style_int_t bottom = lv_obj_get_style_pad_bottom(lmeter, LV_LINEMETER_PART_MAIN);
142
143 lv_coord_t r_out = (lv_obj_get_width(lmeter) - left - right) / 2 ;
144 lv_coord_t r_in = r_out - lv_obj_get_style_scale_width(lmeter, LV_LINEMETER_PART_MAIN);
145 if(r_in < 1) r_in = 1;
146
147 lv_coord_t x_ofs = lmeter->coords.x1 + r_out + left;
148 lv_coord_t y_ofs = lmeter->coords.y1 + r_out + top;
149 int16_t angle_ofs = ext->angle_ofs + 90 + (360 - ext->scale_angle) / 2;
150
151 lv_style_int_t line_width = lv_obj_get_style_scale_end_line_width(lmeter, LV_LINEMETER_PART_MAIN);
152 lv_style_int_t end_line_width = lv_obj_get_style_scale_end_line_width(lmeter, LV_LINEMETER_PART_MAIN);
153 line_width = LV_MATH_MAX(line_width, end_line_width);
154
155 int32_t angle_old = (level_old * ext->scale_angle) / (ext->line_cnt - 1);
156
157 /*Use smaller clip area only around the visible line*/
158 int32_t y_in_old = (int32_t)((int32_t)_lv_trigo_sin(angle_old + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
159 int32_t x_in_old = (int32_t)((int32_t)_lv_trigo_sin(angle_old + 90 + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
160
161
162 int32_t y_out_old = (int32_t)((int32_t)_lv_trigo_sin(angle_old + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
163 int32_t x_out_old = (int32_t)((int32_t)_lv_trigo_sin(angle_old + 90 + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
164
165
166
167 int32_t angle_new = (level_new * ext->scale_angle) / (ext->line_cnt - 1);
168
169 /*Use smaller clip area only around the visible line*/
170 int32_t y_in_new = (int32_t)((int32_t)_lv_trigo_sin(angle_new + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
171 int32_t x_in_new = (int32_t)((int32_t)_lv_trigo_sin(angle_new + 90 + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
172
173
174 int32_t y_out_new = (int32_t)((int32_t)_lv_trigo_sin(angle_new + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
175 int32_t x_out_new = (int32_t)((int32_t)_lv_trigo_sin(angle_new + 90 + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
176
177 lv_area_t a;
178 if(x_out_old < 0 && x_out_new < 0) {
179 a.x1 = lmeter->coords.x1 + left - line_width;
180 a.y1 = LV_MATH_MIN4(y_out_old, y_out_new, y_in_old, y_in_new) + y_ofs - line_width;
181 a.x2 = LV_MATH_MAX(x_in_old, x_in_new) + x_ofs + line_width;
182 a.y2 = LV_MATH_MAX4(y_out_old, y_out_new, y_in_old, y_in_new) + y_ofs + line_width;
183 }
184 else if(x_out_old > 0 && x_out_new > 0) {
185 a.x1 = LV_MATH_MIN(x_in_old, x_in_new) + x_ofs - line_width;
186 a.y1 = LV_MATH_MIN4(y_out_old, y_out_new, y_in_old, y_in_new) + y_ofs - line_width;
187 a.x2 = lmeter->coords.x2 - right + line_width;
188 a.y2 = LV_MATH_MAX4(y_out_old, y_out_new, y_in_old, y_in_new) + y_ofs + line_width;
189 }
190 else if(y_out_old < 0 && y_out_new < 0) {
191 a.x1 = LV_MATH_MIN4(x_out_old, x_out_new, x_in_old, x_in_new) + x_ofs - line_width;
192 a.y1 = lmeter->coords.y1 + top - line_width;
193 a.x2 = LV_MATH_MAX4(x_out_old, x_out_new, x_in_old, x_in_new) + x_ofs + line_width;
194 a.y2 = LV_MATH_MAX(y_in_old, y_in_new) + y_ofs + line_width;
195 }
196 else if(y_out_old > 0 && y_out_new > 0) {
197 a.x1 = LV_MATH_MIN4(x_out_old, x_out_new, x_in_old, x_in_new) + x_ofs - line_width;
198 a.y1 = LV_MATH_MIN(y_in_old, y_in_new) + y_ofs - line_width;
199 a.x2 = LV_MATH_MAX4(x_out_old, x_out_new, x_in_old, x_in_new) + x_ofs + line_width;
200 a.y2 = lmeter->coords.y2 - bottom + line_width;
201 }
202 else {
203 a.x1 = lmeter->coords.x1 + left - line_width;
204 a.y1 = lmeter->coords.y1 + top - line_width;
205 a.x2 = lmeter->coords.x2 - right + line_width;
206 a.y2 = lmeter->coords.y2 - bottom + line_width;
207 }
208
209 lv_obj_invalidate_area(lmeter, &a);
210
211 }
212
213 /**
214 * Set minimum and the maximum values of a line meter
215 * @param lmeter pointer to he line meter object
216 * @param min minimum value
217 * @param max maximum value
218 */
lv_linemeter_set_range(lv_obj_t * lmeter,int32_t min,int32_t max)219 void lv_linemeter_set_range(lv_obj_t * lmeter, int32_t min, int32_t max)
220 {
221 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
222
223 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
224 if(ext->min_value == min && ext->max_value == max) return;
225
226 ext->max_value = max;
227 ext->min_value = min;
228 if(ext->cur_value > max) {
229 ext->cur_value = max;
230 lv_linemeter_set_value(lmeter, ext->cur_value);
231 }
232 if(ext->cur_value < min) {
233 ext->cur_value = min;
234 lv_linemeter_set_value(lmeter, ext->cur_value);
235 }
236 lv_obj_invalidate(lmeter);
237 }
238
239 /**
240 * Set the scale settings of a line meter
241 * @param lmeter pointer to a line meter object
242 * @param angle angle of the scale (0..360)
243 * @param line_cnt number of lines
244 */
lv_linemeter_set_scale(lv_obj_t * lmeter,uint16_t angle,uint16_t line_cnt)245 void lv_linemeter_set_scale(lv_obj_t * lmeter, uint16_t angle, uint16_t line_cnt)
246 {
247 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
248
249 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
250 if(ext->scale_angle == angle && ext->line_cnt == line_cnt) return;
251
252 ext->scale_angle = angle;
253 ext->line_cnt = line_cnt;
254
255 lv_obj_invalidate(lmeter);
256 }
257
258 /**
259 * Set the set an offset for the line meter's angles to rotate it.
260 * @param lmeter pointer to a line meter object
261 * @param angle angle where the meter will be facing (with its center)
262 */
lv_linemeter_set_angle_offset(lv_obj_t * lmeter,uint16_t angle)263 void lv_linemeter_set_angle_offset(lv_obj_t * lmeter, uint16_t angle)
264 {
265 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
266 if(ext->angle_ofs == angle) return;
267
268 ext->angle_ofs = angle;
269
270 lv_obj_invalidate(lmeter);
271 }
272
273 /**
274 * Set the orientation of the meter growth, clockwise or counterclockwise (mirrored)
275 * @param lmeter pointer to a line meter object
276 * @param mirror mirror setting
277 */
lv_linemeter_set_mirror(lv_obj_t * lmeter,bool mirror)278 void lv_linemeter_set_mirror(lv_obj_t * lmeter, bool mirror)
279 {
280 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
281 if(ext->mirrored == mirror) return;
282
283 ext->mirrored = mirror;
284
285 lv_obj_invalidate(lmeter);
286 }
287
288 /*=====================
289 * Getter functions
290 *====================*/
291
292 /**
293 * Get the value of a line meter
294 * @param lmeter pointer to a line meter object
295 * @return the value of the line meter
296 */
lv_linemeter_get_value(const lv_obj_t * lmeter)297 int32_t lv_linemeter_get_value(const lv_obj_t * lmeter)
298 {
299 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
300
301 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
302 return ext->cur_value;
303 }
304
305 /**
306 * Get the minimum value of a line meter
307 * @param lmeter pointer to a line meter object
308 * @return the minimum value of the line meter
309 */
lv_linemeter_get_min_value(const lv_obj_t * lmeter)310 int32_t lv_linemeter_get_min_value(const lv_obj_t * lmeter)
311 {
312 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
313
314 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
315 return ext->min_value;
316 }
317
318 /**
319 * Get the maximum value of a line meter
320 * @param lmeter pointer to a line meter object
321 * @return the maximum value of the line meter
322 */
lv_linemeter_get_max_value(const lv_obj_t * lmeter)323 int32_t lv_linemeter_get_max_value(const lv_obj_t * lmeter)
324 {
325 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
326
327 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
328 return ext->max_value;
329 }
330
331 /**
332 * Get the scale number of a line meter
333 * @param lmeter pointer to a line meter object
334 * @return number of the scale units
335 */
lv_linemeter_get_line_count(const lv_obj_t * lmeter)336 uint16_t lv_linemeter_get_line_count(const lv_obj_t * lmeter)
337 {
338 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
339
340 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
341 return ext->line_cnt;
342 }
343
344 /**
345 * Get the scale angle of a line meter
346 * @param lmeter pointer to a line meter object
347 * @return angle_ofs of the scale
348 */
lv_linemeter_get_scale_angle(const lv_obj_t * lmeter)349 uint16_t lv_linemeter_get_scale_angle(const lv_obj_t * lmeter)
350 {
351 LV_ASSERT_OBJ(lmeter, LV_OBJX_NAME);
352
353 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
354 return ext->scale_angle;
355 }
356
357 /**
358 * Get the offset for the line meter.
359 * @param lmeter pointer to a line meter object
360 * @return angle offset (0..360)
361 */
lv_linemeter_get_angle_offset(lv_obj_t * lmeter)362 uint16_t lv_linemeter_get_angle_offset(lv_obj_t * lmeter)
363 {
364 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
365
366 return ext->angle_ofs;
367 }
368
369 /**
370 * get the mirror setting for the line meter
371 * @param lmeter pointer to a line meter object
372 * @return mirror (true or false)
373 */
lv_linemeter_get_mirror(lv_obj_t * lmeter)374 bool lv_linemeter_get_mirror(lv_obj_t * lmeter)
375 {
376 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
377
378 return ext->mirrored;
379 }
380
lv_linemeter_draw_scale(lv_obj_t * lmeter,const lv_area_t * clip_area,uint8_t part)381 void lv_linemeter_draw_scale(lv_obj_t * lmeter, const lv_area_t * clip_area, uint8_t part)
382 {
383 lv_linemeter_ext_t * ext = lv_obj_get_ext_attr(lmeter);
384
385 lv_style_int_t left = lv_obj_get_style_pad_left(lmeter, LV_LINEMETER_PART_MAIN);
386 lv_style_int_t right = lv_obj_get_style_pad_right(lmeter, LV_LINEMETER_PART_MAIN);
387 lv_style_int_t top = lv_obj_get_style_pad_top(lmeter, LV_LINEMETER_PART_MAIN);
388
389 lv_coord_t r_out = (lv_obj_get_width(lmeter) - left - right) / 2 ;
390 lv_coord_t r_in = r_out - lv_obj_get_style_scale_width(lmeter, part);
391 if(r_in < 1) r_in = 1;
392
393 lv_coord_t x_ofs = lmeter->coords.x1 + r_out + left;
394 lv_coord_t y_ofs = lmeter->coords.y1 + r_out + top;
395 int16_t angle_ofs = ext->angle_ofs + 90 + (360 - ext->scale_angle) / 2;
396 int16_t level = ext->mirrored ?
397 (int32_t)((int32_t)(ext->max_value - ext->cur_value) * (ext->line_cnt - 1)) / (ext->max_value - ext->min_value) :
398 (int32_t)((int32_t)(ext->cur_value - ext->min_value) * (ext->line_cnt - 1)) / (ext->max_value - ext->min_value);
399 uint8_t i;
400
401 lv_color_t main_color = lv_obj_get_style_line_color(lmeter, part);
402 lv_color_t grad_color = lv_obj_get_style_scale_grad_color(lmeter, part);
403 lv_color_t end_color = lv_obj_get_style_scale_end_color(lmeter, part);
404
405 lv_draw_line_dsc_t line_dsc;
406 lv_draw_line_dsc_init(&line_dsc);
407 lv_obj_init_draw_line_dsc(lmeter, part, &line_dsc);
408 #if LV_LINEMETER_PRECISE == 2
409 line_dsc.raw_end = 1;
410 #endif
411
412 lv_style_int_t end_line_width = lv_obj_get_style_scale_end_line_width(lmeter, part);
413
414 #if LV_LINEMETER_PRECISE > 0
415 lv_area_t mask_area;
416 mask_area.x1 = x_ofs - r_in;
417 mask_area.x2 = x_ofs + r_in - 1;
418 mask_area.y1 = y_ofs - r_in;
419 mask_area.y2 = y_ofs + r_in - 1;
420
421 lv_draw_mask_radius_param_t mask_in_param;
422 lv_draw_mask_radius_init(&mask_in_param, &mask_area, LV_RADIUS_CIRCLE, true);
423 int16_t mask_in_id = lv_draw_mask_add(&mask_in_param, 0);
424 #endif
425
426
427 #if LV_LINEMETER_PRECISE > 1
428 mask_area.x1 = x_ofs - r_out;
429 mask_area.x2 = x_ofs + r_out - 1;
430 mask_area.y1 = y_ofs - r_out;
431 mask_area.y2 = y_ofs + r_out - 1;
432 lv_draw_mask_radius_param_t mask_out_param;
433 lv_draw_mask_radius_init(&mask_out_param, &mask_area, LV_RADIUS_CIRCLE, false);
434 int16_t mask_out_id = lv_draw_mask_add(&mask_out_param, 0);
435 /*In calculation use a larger radius to avoid rounding errors */
436 lv_coord_t r_out_extra = r_out + LV_DPI;
437 #else
438 lv_coord_t r_out_extra = r_out;
439 #endif
440
441 for(i = 0; i < ext->line_cnt; i++) {
442 /* `* 256` for extra precision*/
443 int32_t angle_upscale = (i * ext->scale_angle * 256) / (ext->line_cnt - 1);
444 int32_t angle_normal = angle_upscale >> 8;
445
446 int32_t angle_low = (angle_upscale >> 8);
447 int32_t angle_high = angle_low + 1;
448 int32_t angle_rem = angle_upscale & 0xFF;
449
450 /*Interpolate sine and cos*/
451 int32_t sin_low = _lv_trigo_sin(angle_low + angle_ofs);
452 int32_t sin_high = _lv_trigo_sin(angle_high + angle_ofs);
453 int32_t sin_mid = (sin_low * (256 - angle_rem) + sin_high * angle_rem) >> 8;
454
455 int32_t cos_low = _lv_trigo_sin(angle_low + 90 + angle_ofs);
456 int32_t cos_high = _lv_trigo_sin(angle_high + 90 + angle_ofs);
457 int32_t cos_mid = (cos_low * (256 - angle_rem) + cos_high * angle_rem) >> 8;
458
459 /*Use the interpolated values to get x and y coordinates*/
460 int32_t y_out_extra = (int32_t)((int32_t)sin_mid * r_out_extra) >> (LV_TRIGO_SHIFT - 8);
461 int32_t x_out_extra = (int32_t)((int32_t)cos_mid * r_out_extra) >> (LV_TRIGO_SHIFT - 8);
462
463 /*Rounding*/
464 if(x_out_extra > 0) x_out_extra = (x_out_extra + 127) >> 8;
465 else x_out_extra = (x_out_extra - 127) >> 8;
466
467 if(y_out_extra > 0) y_out_extra = (y_out_extra + 127) >> 8;
468 else y_out_extra = (y_out_extra - 127) >> 8;
469
470 x_out_extra += x_ofs;
471 y_out_extra += y_ofs;
472
473 /*With no extra precision use the coordinates on the inner radius*/
474 #if LV_LINEMETER_PRECISE == 0
475 /*Use the interpolated values to get x and y coordinates*/
476 int32_t y_in_extra = (int32_t)((int32_t)sin_mid * r_in) >> (LV_TRIGO_SHIFT - 8);
477 int32_t x_in_extra = (int32_t)((int32_t)cos_mid * r_in) >> (LV_TRIGO_SHIFT - 8);
478
479 /*Rounding*/
480 if(x_in_extra > 0) x_in_extra = (x_in_extra + 127) >> 8;
481 else x_in_extra = (x_in_extra - 127) >> 8;
482
483 if(y_in_extra > 0) y_in_extra = (y_in_extra + 127) >> 8;
484 else y_in_extra = (y_in_extra - 127) >> 8;
485
486 x_in_extra += x_ofs;
487 y_in_extra += y_ofs;
488 #else
489 int32_t x_in_extra = x_ofs;
490 int32_t y_in_extra = y_ofs;
491 #endif
492
493 /*Use smaller clip area only around the visible line*/
494 int32_t y_in = (int32_t)((int32_t)_lv_trigo_sin(angle_normal + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
495 int32_t x_in = (int32_t)((int32_t)_lv_trigo_sin(angle_normal + 90 + angle_ofs) * r_in) >> LV_TRIGO_SHIFT;
496
497 x_in += x_ofs;
498 y_in += y_ofs;
499
500 int32_t y_out = (int32_t)((int32_t)_lv_trigo_sin(angle_normal + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
501 int32_t x_out = (int32_t)((int32_t)_lv_trigo_sin(angle_normal + 90 + angle_ofs) * r_out) >> LV_TRIGO_SHIFT;
502
503 x_out += x_ofs;
504 y_out += y_ofs;
505
506 lv_area_t clip_sub;
507 clip_sub.x1 = LV_MATH_MIN(x_in, x_out) - line_dsc.width;
508 clip_sub.x2 = LV_MATH_MAX(x_in, x_out) + line_dsc.width;
509 clip_sub.y1 = LV_MATH_MIN(y_in, y_out) - line_dsc.width;
510 clip_sub.y2 = LV_MATH_MAX(y_in, y_out) + line_dsc.width;
511
512 if(_lv_area_intersect(&clip_sub, &clip_sub, clip_area) == false) continue;
513
514 lv_point_t p1;
515 lv_point_t p2;
516
517 p2.x = x_in_extra;
518 p2.y = y_in_extra;
519
520 p1.x = x_out_extra;
521 p1.y = y_out_extra;
522
523 /* Set the color of the lines */
524 if((!ext->mirrored && i >= level) || (ext->mirrored && i <= level)) {
525 line_dsc.color = end_color;
526 line_dsc.width = end_line_width;
527 }
528 else {
529 line_dsc.color = lv_color_mix(grad_color, main_color, (255 * i) / ext->line_cnt);
530 }
531
532 lv_draw_line(&p1, &p2, &clip_sub, &line_dsc);
533 }
534
535 #if LV_LINEMETER_PRECISE > 0
536 lv_draw_mask_remove_id(mask_in_id);
537 #endif
538
539 #if LV_LINEMETER_PRECISE > 1
540 lv_draw_mask_remove_id(mask_out_id);
541 #endif
542
543 if(part == LV_LINEMETER_PART_MAIN && level < ext->line_cnt - 1) {
544 lv_style_int_t border_width = lv_obj_get_style_scale_border_width(lmeter, part);
545 lv_style_int_t end_border_width = lv_obj_get_style_scale_end_border_width(lmeter, part);
546
547 if(border_width || end_border_width) {
548 int16_t end_angle = ((level) * ext->scale_angle) / (ext->line_cnt - 1) + angle_ofs;
549 lv_draw_line_dsc_t arc_dsc;
550 lv_draw_line_dsc_init(&arc_dsc);
551 lv_obj_init_draw_line_dsc(lmeter, part, &arc_dsc);
552
553 if(border_width) {
554 arc_dsc.width = border_width;
555 arc_dsc.color = main_color;
556 lv_draw_arc(x_ofs, y_ofs, r_out, angle_ofs, end_angle, clip_area, &arc_dsc);
557 }
558
559 if(end_border_width) {
560 arc_dsc.width = end_border_width;
561 arc_dsc.color = end_color;
562 lv_draw_arc(x_ofs, y_ofs, r_out, end_angle, (angle_ofs + ext->scale_angle) % 360, clip_area, &arc_dsc);
563 }
564 }
565 }
566
567
568 }
569
570 /**********************
571 * STATIC FUNCTIONS
572 **********************/
573
574 /**
575 * Handle the drawing related tasks of the line meters
576 * @param lmeter pointer to an object
577 * @param clip_area the object will be drawn only in this area
578 * @param mode LV_DESIGN_COVER_CHK: only check if the object fully covers the 'mask_p' area
579 * (return 'true' if yes)
580 * LV_DESIGN_DRAW: draw the object (always return 'true')
581 * LV_DESIGN_DRAW_POST: drawing after every children are drawn
582 * @param return an element of `lv_design_res_t`
583 */
lv_linemeter_design(lv_obj_t * lmeter,const lv_area_t * clip_area,lv_design_mode_t mode)584 static lv_design_res_t lv_linemeter_design(lv_obj_t * lmeter, const lv_area_t * clip_area, lv_design_mode_t mode)
585 {
586 /*Return false if the object is not covers the mask_p area*/
587 if(mode == LV_DESIGN_COVER_CHK) {
588 return LV_DESIGN_RES_NOT_COVER;
589 }
590 /*Draw the object*/
591 else if(mode == LV_DESIGN_DRAW_MAIN) {
592 lv_draw_rect_dsc_t bg_dsc;
593 lv_draw_rect_dsc_init(&bg_dsc);
594 lv_obj_init_draw_rect_dsc(lmeter, LV_LINEMETER_PART_MAIN, &bg_dsc);
595 lv_draw_rect(&lmeter->coords, clip_area, &bg_dsc);
596 lv_linemeter_draw_scale(lmeter, clip_area, LV_LINEMETER_PART_MAIN);
597 }
598 /*Post draw when the children are drawn*/
599 else if(mode == LV_DESIGN_DRAW_POST) {
600 }
601
602 return LV_DESIGN_RES_OK;
603 }
604
605 /**
606 * Signal function of the line meter
607 * @param lmeter pointer to a line meter object
608 * @param sign a signal type from lv_signal_t enum
609 * @param param pointer to a signal specific variable
610 * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted
611 */
lv_linemeter_signal(lv_obj_t * lmeter,lv_signal_t sign,void * param)612 static lv_res_t lv_linemeter_signal(lv_obj_t * lmeter, lv_signal_t sign, void * param)
613 {
614 lv_res_t res;
615
616 /* Include the ancient signal function */
617 res = ancestor_signal(lmeter, sign, param);
618 if(res != LV_RES_OK) return res;
619 if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME);
620
621 if(sign == LV_SIGNAL_CLEANUP) {
622 /*Nothing to cleanup. (No dynamically allocated memory in 'ext')*/
623 }
624 else if(sign == LV_SIGNAL_STYLE_CHG) {
625 lv_obj_refresh_ext_draw_pad(lmeter);
626 lv_obj_invalidate(lmeter);
627 }
628
629 return res;
630 }
631 #endif
632