acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_meter.c (27236B)

      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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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(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         part_draw_dsc.radius = r_out + indic->type_data.arc.r_mod;
    364         part_draw_dsc.sub_part_ptr = indic;
    365         part_draw_dsc.p1 = &scale_center;
    366 
    367         lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
    368         lv_draw_arc(draw_ctx, &arc_dsc, &scale_center, part_draw_dsc.radius, start_angle, end_angle);
    369         lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
    370     }
    371 }
    372 
    373 static void draw_ticks_and_labels(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area)
    374 {
    375     lv_meter_t * meter    = (lv_meter_t *)obj;
    376 
    377     lv_point_t p_center;
    378     lv_coord_t r_edge = LV_MIN(lv_area_get_width(scale_area) / 2, lv_area_get_height(scale_area) / 2);
    379     p_center.x = scale_area->x1 + r_edge;
    380     p_center.y = scale_area->y1 + r_edge;
    381 
    382     lv_draw_line_dsc_t line_dsc;
    383     lv_draw_line_dsc_init(&line_dsc);
    384     lv_obj_init_draw_line_dsc(obj, LV_PART_TICKS, &line_dsc);
    385     line_dsc.raw_end = 1;
    386 
    387     lv_draw_label_dsc_t label_dsc;
    388     lv_draw_label_dsc_init(&label_dsc);
    389     lv_obj_init_draw_label_dsc(obj, LV_PART_TICKS, &label_dsc);
    390 
    391     lv_meter_scale_t * scale;
    392 
    393     lv_draw_mask_radius_param_t inner_minor_mask;
    394     lv_draw_mask_radius_param_t inner_major_mask;
    395     lv_draw_mask_radius_param_t outer_mask;
    396 
    397     lv_obj_draw_part_dsc_t part_draw_dsc;
    398     lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx);
    399     part_draw_dsc.class_p = MY_CLASS;
    400     part_draw_dsc.part = LV_PART_TICKS;
    401     part_draw_dsc.type = LV_METER_DRAW_PART_TICK;
    402     part_draw_dsc.line_dsc = &line_dsc;
    403 
    404     _LV_LL_READ_BACK(&meter->scale_ll, scale) {
    405         part_draw_dsc.sub_part_ptr = scale;
    406 
    407         lv_coord_t r_out = r_edge + scale->r_mod;
    408         lv_coord_t r_in_minor = r_out - scale->tick_length;
    409         lv_coord_t r_in_major = r_out - scale->tick_major_length;
    410 
    411         lv_area_t area_inner_minor;
    412         area_inner_minor.x1 = p_center.x - r_in_minor;
    413         area_inner_minor.y1 = p_center.y - r_in_minor;
    414         area_inner_minor.x2 = p_center.x + r_in_minor;
    415         area_inner_minor.y2 = p_center.y + r_in_minor;
    416         lv_draw_mask_radius_init(&inner_minor_mask, &area_inner_minor, LV_RADIUS_CIRCLE, true);
    417 
    418         lv_area_t area_inner_major;
    419         area_inner_major.x1 = p_center.x - r_in_major;
    420         area_inner_major.y1 = p_center.y - r_in_major;
    421         area_inner_major.x2 = p_center.x + r_in_major - 1;
    422         area_inner_major.y2 = p_center.y + r_in_major - 1;
    423         lv_draw_mask_radius_init(&inner_major_mask, &area_inner_major, LV_RADIUS_CIRCLE, true);
    424 
    425         lv_area_t area_outer;
    426         area_outer.x1 = p_center.x - r_out;
    427         area_outer.y1 = p_center.y - r_out;
    428         area_outer.x2 = p_center.x + r_out - 1;
    429         area_outer.y2 = p_center.y + r_out - 1;
    430         lv_draw_mask_radius_init(&outer_mask, &area_outer, LV_RADIUS_CIRCLE, false);
    431         int16_t outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
    432 
    433         int16_t inner_act_mask_id = LV_MASK_ID_INV; /*Will be added later*/
    434 
    435         uint32_t minor_cnt = scale->tick_major_nth ? scale->tick_major_nth - 1 : 0xFFFF;
    436         uint16_t i;
    437         for(i = 0; i < scale->tick_cnt; i++) {
    438             minor_cnt++;
    439             bool major = false;
    440             if(minor_cnt == scale->tick_major_nth) {
    441                 minor_cnt = 0;
    442                 major = true;
    443             }
    444 
    445             int32_t value_of_line = lv_map(i, 0, scale->tick_cnt - 1, scale->min, scale->max);
    446             part_draw_dsc.value = value_of_line;
    447 
    448             lv_color_t line_color = major ? scale->tick_major_color : scale->tick_color;
    449             lv_color_t line_color_ori = line_color;
    450 
    451             lv_coord_t line_width_ori = major ? scale->tick_major_width : scale->tick_width;
    452             lv_coord_t line_width = line_width_ori;
    453 
    454             lv_meter_indicator_t * indic;
    455             _LV_LL_READ_BACK(&meter->indicator_ll, indic) {
    456                 if(indic->type != LV_METER_INDICATOR_TYPE_SCALE_LINES) continue;
    457                 if(value_of_line >= indic->start_value && value_of_line <= indic->end_value) {
    458                     line_width += indic->type_data.scale_lines.width_mod;
    459 
    460                     if(indic->type_data.scale_lines.color_start.full == indic->type_data.scale_lines.color_end.full) {
    461                         line_color = indic->type_data.scale_lines.color_start;
    462                     }
    463                     else {
    464                         lv_opa_t ratio;
    465                         if(indic->type_data.scale_lines.local_grad) {
    466                             ratio = lv_map(value_of_line, indic->start_value, indic->end_value, LV_OPA_TRANSP, LV_OPA_COVER);
    467                         }
    468                         else {
    469                             ratio = lv_map(value_of_line, scale->min, scale->max, LV_OPA_TRANSP, LV_OPA_COVER);
    470                         }
    471                         line_color = lv_color_mix(indic->type_data.scale_lines.color_end, indic->type_data.scale_lines.color_start, ratio);
    472                     }
    473                 }
    474             }
    475 
    476             /*`* 256` for extra precision*/
    477             int32_t angle_upscale = ((i * scale->angle_range) << 8) / (scale->tick_cnt - 1);
    478 
    479             int32_t angle_low = (angle_upscale >> 8);
    480             int32_t angle_high = angle_low + 1;
    481             int32_t angle_rem = angle_upscale & 0xFF;
    482 
    483             /*Interpolate sine and cos*/
    484             int32_t sin_low = lv_trigo_sin(angle_low + scale->rotation);
    485             int32_t sin_high = lv_trigo_sin(angle_high + scale->rotation);
    486             int32_t sin_mid = (sin_low * (256 - angle_rem) + sin_high * angle_rem) >> 8;
    487 
    488             int32_t cos_low = lv_trigo_cos(angle_low + scale->rotation);
    489             int32_t cos_high = lv_trigo_cos(angle_high + scale->rotation);
    490             int32_t cos_mid = (cos_low * (256 - angle_rem) + cos_high * angle_rem) >> 8;
    491 
    492             line_dsc.color = line_color;
    493             line_dsc.width = line_width;
    494             /*Use the interpolated angle to get the outer x and y coordinates.
    495              *Draw a little bit longer lines to be sure the mask will clip them correctly*/
    496             lv_point_t p_outer;
    497             p_outer.x = (int32_t)(((int32_t)cos_mid * (r_out + line_width) + 127) >> (LV_TRIGO_SHIFT)) + p_center.x;
    498             p_outer.y = (int32_t)(((int32_t)sin_mid * (r_out + line_width) + 127) >> (LV_TRIGO_SHIFT)) + p_center.y;
    499 
    500             part_draw_dsc.p1 = &p_outer;
    501             part_draw_dsc.p1 = &p_center;
    502             part_draw_dsc.id = i;
    503             part_draw_dsc.label_dsc = &label_dsc;
    504 
    505             /*Draw the text*/
    506             if(major) {
    507                 lv_draw_mask_remove_id(outer_mask_id);
    508                 uint32_t r_text = r_in_major - scale->label_gap;
    509                 lv_point_t p;
    510                 p.x = (int32_t)((int32_t)((int32_t)cos_mid * r_text + 127) >> LV_TRIGO_SHIFT) + p_center.x;
    511                 p.y = (int32_t)((int32_t)((int32_t)sin_mid * r_text + 127) >> LV_TRIGO_SHIFT) + p_center.y;
    512 
    513                 lv_draw_label_dsc_t label_dsc_tmp;
    514                 lv_memcpy(&label_dsc_tmp, &label_dsc, sizeof(label_dsc_tmp));
    515 
    516                 part_draw_dsc.label_dsc = &label_dsc_tmp;
    517                 char buf[16];
    518 
    519                 lv_snprintf(buf, sizeof(buf), "%" LV_PRId32, value_of_line);
    520                 part_draw_dsc.text = buf;
    521 
    522                 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
    523 
    524                 lv_point_t label_size;
    525                 lv_txt_get_size(&label_size, part_draw_dsc.text, label_dsc.font, label_dsc.letter_space, label_dsc.line_space,
    526                                 LV_COORD_MAX, LV_TEXT_FLAG_NONE);
    527 
    528                 lv_area_t label_cord;
    529                 label_cord.x1 = p.x - label_size.x / 2;
    530                 label_cord.y1 = p.y - label_size.y / 2;
    531                 label_cord.x2 = label_cord.x1 + label_size.x;
    532                 label_cord.y2 = label_cord.y1 + label_size.y;
    533 
    534                 lv_draw_label(draw_ctx, part_draw_dsc.label_dsc, &label_cord, part_draw_dsc.text, NULL);
    535 
    536                 outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
    537             }
    538             else {
    539                 part_draw_dsc.label_dsc = NULL;
    540                 part_draw_dsc.text = NULL;
    541                 lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
    542             }
    543 
    544             inner_act_mask_id = lv_draw_mask_add(major ? &inner_major_mask : &inner_minor_mask, NULL);
    545             lv_draw_line(draw_ctx, &line_dsc, &p_outer, &p_center);
    546             lv_draw_mask_remove_id(inner_act_mask_id);
    547             lv_event_send(obj, LV_EVENT_DRAW_MAIN_END, &part_draw_dsc);
    548 
    549             line_dsc.color = line_color_ori;
    550             line_dsc.width = line_width_ori;
    551 
    552         }
    553         lv_draw_mask_free_param(&inner_minor_mask);
    554         lv_draw_mask_free_param(&inner_major_mask);
    555         lv_draw_mask_free_param(&outer_mask);
    556         lv_draw_mask_remove_id(outer_mask_id);
    557     }
    558 }
    559 
    560 
    561 static void draw_needles(lv_obj_t * obj, lv_draw_ctx_t * draw_ctx, const lv_area_t * scale_area)
    562 {
    563     lv_meter_t * meter = (lv_meter_t *)obj;
    564 
    565     lv_coord_t r_edge = lv_area_get_width(scale_area) / 2;
    566     lv_point_t scale_center;
    567     scale_center.x = scale_area->x1 + r_edge;
    568     scale_center.y = scale_area->y1 + r_edge;
    569 
    570     lv_draw_line_dsc_t line_dsc;
    571     lv_draw_line_dsc_init(&line_dsc);
    572     lv_obj_init_draw_line_dsc(obj, LV_PART_ITEMS, &line_dsc);
    573 
    574     lv_draw_img_dsc_t img_dsc;
    575     lv_draw_img_dsc_init(&img_dsc);
    576     lv_obj_init_draw_img_dsc(obj, LV_PART_ITEMS, &img_dsc);
    577     lv_opa_t opa_main = lv_obj_get_style_opa(obj, LV_PART_MAIN);
    578 
    579     lv_obj_draw_part_dsc_t part_draw_dsc;
    580     lv_obj_draw_dsc_init(&part_draw_dsc, draw_ctx);
    581     part_draw_dsc.class_p = MY_CLASS;
    582     part_draw_dsc.p1 = &scale_center;
    583 
    584     lv_meter_indicator_t * indic;
    585     _LV_LL_READ_BACK(&meter->indicator_ll, indic) {
    586         lv_meter_scale_t * scale = indic->scale;
    587         part_draw_dsc.sub_part_ptr = indic;
    588 
    589         if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
    590             int32_t angle = lv_map(indic->end_value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
    591             lv_coord_t r_out = r_edge + scale->r_mod + indic->type_data.needle_line.r_mod;
    592             lv_point_t p_end;
    593             p_end.y = (lv_trigo_sin(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.y;
    594             p_end.x = (lv_trigo_cos(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.x;
    595             line_dsc.color = indic->type_data.needle_line.color;
    596             line_dsc.width = indic->type_data.needle_line.width;
    597             line_dsc.opa = indic->opa > LV_OPA_MAX ? opa_main : (opa_main * indic->opa) >> 8;
    598 
    599             part_draw_dsc.id = LV_METER_DRAW_PART_NEEDLE_LINE;
    600             part_draw_dsc.line_dsc = &line_dsc;
    601             part_draw_dsc.p2 = &p_end;
    602 
    603             lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
    604             lv_draw_line(draw_ctx, &line_dsc, &scale_center, &p_end);
    605             lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
    606         }
    607         else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG) {
    608             if(indic->type_data.needle_img.src == NULL) continue;
    609 
    610             int32_t angle = lv_map(indic->end_value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
    611             lv_img_header_t info;
    612             lv_img_decoder_get_info(indic->type_data.needle_img.src, &info);
    613             lv_area_t a;
    614             a.x1 = scale_center.x - indic->type_data.needle_img.pivot.x;
    615             a.y1 = scale_center.y - indic->type_data.needle_img.pivot.y;
    616             a.x2 = a.x1 + info.w - 1;
    617             a.y2 = a.y1 + info.h - 1;
    618 
    619             img_dsc.opa = indic->opa > LV_OPA_MAX ? opa_main : (opa_main * indic->opa) >> 8;
    620             img_dsc.pivot.x = indic->type_data.needle_img.pivot.x;
    621             img_dsc.pivot.y = indic->type_data.needle_img.pivot.y;
    622             angle = angle * 10;
    623             if(angle > 3600) angle -= 3600;
    624             img_dsc.angle = angle;
    625 
    626             part_draw_dsc.img_dsc = &img_dsc;
    627 
    628             lv_event_send(obj, LV_EVENT_DRAW_PART_BEGIN, &part_draw_dsc);
    629             lv_draw_img(draw_ctx, &img_dsc, &a, indic->type_data.needle_img.src);
    630             lv_event_send(obj, LV_EVENT_DRAW_PART_END, &part_draw_dsc);
    631         }
    632     }
    633 }
    634 
    635 static void inv_arc(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t old_value, int32_t new_value)
    636 {
    637     bool rounded = lv_obj_get_style_arc_rounded(obj, LV_PART_ITEMS);
    638 
    639     lv_area_t scale_area;
    640     lv_obj_get_content_coords(obj, &scale_area);
    641 
    642     lv_coord_t r_out = lv_area_get_width(&scale_area) / 2;
    643     lv_point_t scale_center;
    644     scale_center.x = scale_area.x1 + r_out;
    645     scale_center.y = scale_area.y1 + r_out;
    646 
    647     r_out += indic->type_data.arc.r_mod;
    648 
    649     lv_meter_scale_t * scale = indic->scale;
    650 
    651     int32_t start_angle = lv_map(old_value, scale->min, scale->max, scale->rotation, scale->angle_range + scale->rotation);
    652     int32_t end_angle = lv_map(new_value, scale->min, scale->max, scale->rotation, scale->angle_range + scale->rotation);
    653 
    654     lv_area_t a;
    655     lv_draw_arc_get_area(scale_center.x, scale_center.y, r_out, LV_MIN(start_angle, end_angle), LV_MAX(start_angle,
    656                                                                                                        end_angle), indic->type_data.arc.width, rounded, &a);
    657     lv_obj_invalidate_area(obj, &a);
    658 }
    659 
    660 
    661 static void inv_line(lv_obj_t * obj, lv_meter_indicator_t * indic, int32_t value)
    662 {
    663     lv_area_t scale_area;
    664     lv_obj_get_content_coords(obj, &scale_area);
    665 
    666     lv_coord_t r_out = lv_area_get_width(&scale_area) / 2;
    667     lv_point_t scale_center;
    668     scale_center.x = scale_area.x1 + r_out;
    669     scale_center.y = scale_area.y1 + r_out;
    670 
    671     lv_meter_scale_t * scale = indic->scale;
    672 
    673     if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_LINE) {
    674         int32_t angle = lv_map(value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
    675         r_out += scale->r_mod + indic->type_data.needle_line.r_mod;
    676         lv_point_t p_end;
    677         p_end.y = (lv_trigo_sin(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.y;
    678         p_end.x = (lv_trigo_cos(angle) * (r_out)) / LV_TRIGO_SIN_MAX + scale_center.x;
    679 
    680         lv_area_t a;
    681         a.x1 = LV_MIN(scale_center.x, p_end.x) - indic->type_data.needle_line.width - 2;
    682         a.y1 = LV_MIN(scale_center.y, p_end.y) - indic->type_data.needle_line.width - 2;
    683         a.x2 = LV_MAX(scale_center.x, p_end.x) + indic->type_data.needle_line.width + 2;
    684         a.y2 = LV_MAX(scale_center.y, p_end.y) + indic->type_data.needle_line.width + 2;
    685 
    686         lv_obj_invalidate_area(obj, &a);
    687     }
    688     else if(indic->type == LV_METER_INDICATOR_TYPE_NEEDLE_IMG) {
    689         int32_t angle = lv_map(value, scale->min, scale->max, scale->rotation, scale->rotation + scale->angle_range);
    690         lv_img_header_t info;
    691         lv_img_decoder_get_info(indic->type_data.needle_img.src, &info);
    692 
    693         angle = angle * 10;
    694         if(angle > 3600) angle -= 3600;
    695 
    696         scale_center.x -= indic->type_data.needle_img.pivot.x;
    697         scale_center.y -= indic->type_data.needle_img.pivot.y;
    698         lv_area_t a;
    699         _lv_img_buf_get_transformed_area(&a, info.w, info.h, angle, LV_IMG_ZOOM_NONE, &indic->type_data.needle_img.pivot);
    700         a.x1 += scale_center.x - 2;
    701         a.y1 += scale_center.y - 2;
    702         a.x2 += scale_center.x + 2;
    703         a.y2 += scale_center.y + 2;
    704 
    705         lv_obj_invalidate_area(obj, &a);
    706     }
    707 }
    708 #endif