Using lv_meter_create to rotate the scale

It is necessary to rotate the scale, I thought of using a meter

  ui_hdg_scale = lv_meter_create(approach_screen);

  lv_obj_set_pos(ui_hdg_scale, -158, 29);
  lv_obj_set_size(ui_hdg_scale, 800, 800);
  lv_obj_set_style_radius(ui_hdg_scale, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
  lv_obj_set_style_text_font(ui_hdg_scale, &lv_font_montserrat_26, LV_PART_MAIN | LV_STATE_DEFAULT);
  lv_obj_set_style_text_color(ui_hdg_scale, lv_color_hex(0xff0f710a), LV_PART_MAIN | LV_STATE_DEFAULT);
  lv_obj_set_style_bg_opa(ui_hdg_scale, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
  
  lv_meter_scale_t *scale = lv_meter_add_scale(ui_hdg_scale);
  lv_meter_set_scale_ticks(ui_hdg_scale, scale, 72, 3, 10, lv_color_hex(0xff0f710a));
  lv_meter_set_scale_major_ticks(ui_hdg_scale, scale, 6, 5, 10, lv_color_hex(0xff0f710a), 15);
  lv_meter_set_scale_range(ui_hdg_scale, scale, 0, 36, 355, 270);
  // lv_meter_set_scale_range(ui_hdg_scale, scale, 0, 36, 355, -(HDG - 270));


but apparently it is not designed for rotation.

Please tell me how to delete the previous scale, or is it possible to use another method?

How do you try to rotate it?

If it’s an option I suggest updating to v9 as lv_scale (replacement of meter) is much more powerful.

1 Like

I really appreciate your help, and forgive me if I ask stupid questions🙂

First I draw the scale and then I try to rotate it using the parameter rotation

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,
                              uint32_t rotation)

In code it looks like this:

ui_hdg_scale = lv_meter_create(approach_screen); // Create a new lv_meter
// lv_obj_clean(ui_hdg_scale); // Removes all children, including the old scale
lv_obj_set_pos(ui_hdg_scale, -158, 29);
lv_obj_set_size(ui_hdg_scale, 800, 800);
lv_obj_set_style_radius(ui_hdg_scale, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(ui_hdg_scale, &lv_font_montserrat_26, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(ui_hdg_scale, lv_color_hex(0xff0f710a), LV_PART_MAIN | LV_STATE_DEFAULT); 
lv_obj_set_style_bg_opa(ui_hdg_scale, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 
// hides the white bar at the top 
lv_obj_set_style_border_opa(ui_hdg_scale, 0, LV_PART_MAIN | LV_STATE_DEFAULT); 
// Remove the circle from the middle 
lv_obj_remove_style(ui_hdg_scale, NULL, LV_PART_INDICATOR); 

lv_meter_scale_t *scale = lv_meter_add_scale(ui_hdg_scale); 
// scale0 = scale; 
lv_meter_set_scale_ticks(ui_hdg_scale, scale, 72, 3, 10, lv_color_hex(0xff0f710a)); 
lv_meter_set_scale_major_ticks(ui_hdg_scale, scale, 6, 5, 10, lv_color_hex(0xff0f710a), 15); 
lv_meter_set_scale_range(ui_hdg_scale, scale, 0, 36, 355, 270);

Hello, I ran the example code in this simulator - using version LVGL 9.3.0

GitHub - lvgl/lv_platformio: PlatformIO project example for LVGL

It all looks like this, but I would like to rotate the scale - is this possible?

Don’t just turn and draw, but do it constantly so that the scale rotates continuously.

Attached the project code for the platformio.

lv_platformio.zip (159.4 KB)

Thank you for your work :slightly_smiling_face:

Hello @kisvegabor
I need your help into :roll_eyes:

There is a zero division error in lv_scale · Issue #7591 · lvgl/lvgl

1 Like

Thank you for your participation🙂
I wrote a c++ class based on your code, but unfortunately I don’t get the scale rotation in the simulator.

class ColorScale {
public:
    ColorScale(lv_obj_t* parent, int pos_x, int pos_y, int size_x, int size_y);
    static void draw_event_cb(lv_event_t* e);
    static void color_anim_cb(void* var, int32_t v);
    void start_color_animation();

private:
    static int32_t angle_offset;  // Make angle_offset static
    lv_obj_t* scale_loader;
};

int32_t ColorScale::angle_offset = 0;  // Initializing a static member

ColorScale::ColorScale(lv_obj_t* parent, int pos_x, int pos_y, int size_x, int size_y) {
    scale_loader = lv_scale_create(parent);
    lv_scale_set_mode(scale_loader, LV_SCALE_MODE_ROUND_INNER);
    lv_obj_set_size(scale_loader, size_x, size_y);
    lv_obj_set_pos(scale_loader, pos_x, pos_y);
    
    lv_scale_set_total_tick_count(scale_loader, 37);
    lv_scale_set_major_tick_every(scale_loader, 3);
    lv_scale_set_angle_range(scale_loader, 360);

    static const char * hdg_ticks[] = {"0", "3", "6", "9", "12", "15", "18", "21", "24", "27", "30", "33", NULL};
    lv_scale_set_text_src(scale_loader, hdg_ticks);
    
    static lv_style_t section_minor_tick_style;
    static lv_style_t section_major_line_style;

    lv_style_init(&section_minor_tick_style);
    lv_style_init(&section_major_line_style);

    lv_style_set_length(&section_minor_tick_style, 20); /* tick length */
    // lv_style_set_line_width(&section_major_line_style, 4U); /* Tick width */
    lv_style_set_line_width(&section_major_line_style, 5); /* Tick width */

    lv_scale_section_t* section = lv_scale_add_section(scale_loader);
    lv_scale_section_set_range(section, 0, 100);
    lv_scale_section_set_style(section, LV_PART_ITEMS, &section_minor_tick_style);
    lv_scale_section_set_style(section, LV_PART_INDICATOR, &section_major_line_style);
    
    lv_obj_add_event_cb(scale_loader, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
    lv_obj_add_flag(scale_loader, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);
    
    start_color_animation();
}

void ColorScale::draw_event_cb(lv_event_t* e) {
    lv_obj_t* obj = (lv_obj_t*)lv_event_get_target(e);
    lv_draw_task_t* draw_task = lv_event_get_draw_task(e);
    lv_draw_dsc_base_t* base_dsc = (lv_draw_dsc_base_t*)lv_draw_task_get_draw_dsc(draw_task);
    lv_draw_line_dsc_t* line_draw_dsc = lv_draw_task_get_line_dsc(draw_task);
    
    if (base_dsc->part == LV_PART_ITEMS && line_draw_dsc) {
        int32_t tick_idx = base_dsc->id1;
        int32_t static_angle = lv_map(tick_idx, 0, 36, 0, 360);
        int32_t dynamic_angle = (static_angle + angle_offset) % 360;

        int32_t ratio = lv_map(dynamic_angle, 0, 360, LV_OPA_TRANSP, LV_OPA_COVER);
        line_draw_dsc->color = lv_color_mix(
            lv_color_make(0x2B, 0xFE, 0xE4), 
            lv_color_make(0xFD, 0x2B, 0xFB), 
            ratio
        );
    }
}

void ColorScale::color_anim_cb(void* var, int32_t v) {
    ColorScale* instance = static_cast<ColorScale*>(var);
    instance->angle_offset = v;
    lv_obj_invalidate(instance->scale_loader);
}

void ColorScale::start_color_animation() {
    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, this);
    lv_anim_set_exec_cb(&a, color_anim_cb);
    lv_anim_set_values(&a, 0, 360);
    lv_anim_set_time(&a, 10000);
    lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
    lv_anim_set_path_cb(&a, lv_anim_path_linear);
    lv_anim_start(&a);
}

Usage

ColorScale meter1(lv_scr_act(), 50, 50, 400, 400);

Could you please see what I’m doing wrong?

can you test this code?it work well in my vs2019 simulator

static void scale_cb(void* var, int32_t v)
{
lv_scale_set_rotation(var, v);
}

void lv_example_scale_8(void)
{
lv_obj_t* scale_loader = lv_scale_create(lv_screen_active());
lv_obj_set_size(scale_loader, 300, 300);
lv_scale_set_mode(scale_loader, LV_SCALE_MODE_ROUND_INNER);
lv_obj_center(scale_loader);

lv_obj_set_style_length(scale_loader, 10, LV_PART_ITEMS);
lv_scale_set_total_tick_count(scale_loader, 100);
lv_scale_set_angle_range(scale_loader, 360);

lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, scale_loader);
lv_anim_set_exec_cb(&a, scale_cb);
lv_anim_set_values(&a, 0, 360);
lv_anim_set_time(&a, 10000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_path_cb(&a, lv_anim_path_linear);
lv_anim_start(&a);

}
scale_video.zip (459.6 KB)

1 Like

Yes, I’ll try your code now, but I also got something :grinning:

class Hdg_rotate {
public:
    Hdg_rotate(lv_obj_t* parent, int x, int y, int width, int height);
    void start_color_animation();
    void set_rotation(int angle); // Method for setting the rotation angle

private:
    lv_obj_t* scale_loader; // Scale object
};

// Callback function for drawing
static void draw_event_cb(lv_event_t* e) {
    lv_obj_t* obj = static_cast<lv_obj_t*>(lv_event_get_target(e)); // Explicit type casting
    lv_draw_task_t* draw_task = lv_event_get_draw_task(e);
    lv_draw_dsc_base_t* base_dsc = static_cast<lv_draw_dsc_base_t*>(lv_draw_task_get_draw_dsc(draw_task)); // Explicit type casting
    lv_draw_line_dsc_t* line_draw_dsc = lv_draw_task_get_line_dsc(draw_task);

    if (base_dsc->part == LV_PART_ITEMS) {
        if (line_draw_dsc) {
            int32_t value_of_line = lv_map(base_dsc->id1, 0, 100, 0, 360);
            int32_t ratio = lv_map(value_of_line, 0, 360, LV_OPA_TRANSP, LV_OPA_COVER);
            line_draw_dsc->color = lv_color_mix(lv_color_make(13, 195, 253), lv_color_make(37, 57, 115), ratio);
        }
    }
}

// Callback function for rotation
static void time_cb(lv_timer_t* t) {
    lv_obj_t* scale_loader = static_cast<lv_obj_t*>(lv_timer_get_user_data(t));
    static int i = 0;
    i = (i + 1) % 36;
    lv_scale_set_rotation(scale_loader, 10 * i);
}

// Implementation of methods
Hdg_rotate::Hdg_rotate(lv_obj_t* parent, int x, int y, int width, int height) {
    scale_loader = lv_scale_create(parent); // Create scale
    lv_scale_set_mode(scale_loader, LV_SCALE_MODE_ROUND_INNER);
    lv_scale_set_label_show(scale_loader, true);
    lv_obj_set_size(scale_loader, width, height);
    lv_obj_set_pos(scale_loader, x, y);

    lv_obj_set_style_arc_opa(scale_loader, LV_OPA_TRANSP, LV_PART_MAIN);
    lv_obj_set_style_length(scale_loader, 10, LV_PART_ITEMS);
    
    lv_scale_set_total_tick_count(scale_loader, 37);
    lv_scale_set_major_tick_every(scale_loader, 3);
    lv_scale_set_angle_range(scale_loader, 360);

    static const char * hdg_ticks[] = {"0", "3", "6", "9", "12", "15", "18", "21", "24", "27", "30", "33", NULL};
    lv_scale_set_text_src(scale_loader, hdg_ticks);

    static lv_style_t section_minor_tick_style;
    static lv_style_t section_major_line_style;

    lv_style_init(&section_minor_tick_style);
    lv_style_init(&section_major_line_style);

    lv_style_set_length(&section_minor_tick_style, 20); /* tick length */
    // lv_style_set_line_width(&section_major_line_style, 4U); /* Tick width */
    lv_style_set_line_width(&section_major_line_style, 5); /* Tick width */
    
    lv_scale_section_t* section = lv_scale_add_section(scale_loader);
    lv_scale_section_set_range(section, 0, 100);
    lv_scale_section_set_style(section, LV_PART_ITEMS, &section_minor_tick_style);
    lv_scale_section_set_style(section, LV_PART_INDICATOR, &section_major_line_style);
    
    lv_obj_add_event_cb(scale_loader, draw_event_cb, LV_EVENT_DRAW_TASK_ADDED, NULL);
    lv_obj_add_flag(scale_loader, LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS);

    // Create a timer to rotate the scale
    lv_timer_create(time_cb, 100, scale_loader);
}

void Hdg_rotate::set_rotation(int angle) {
    lv_scale_set_rotation(scale_loader, angle);
}

Usage

  Hdg_rotate hdg_rotate1(lv_screen_active(), 30, 30, 200, 200);
  Hdg_rotate hdg_rotate2(lv_screen_active(), 30, 270, 200, 200);
  Hdg_rotate hdg_rotate3(lv_screen_active(), 270, 30, 200, 200);
  Hdg_rotate hdg_rotate4(lv_screen_active(), 270, 270, 200, 200);

The plans include programming a C++ class to set rotation values ​​to the desired angle not using the built-in LVGL animation, but by the desired angle in degrees.

Hello @kisvegabor
Please add to the examples with the scale

Scale (lv_scale) - LVGL 9.3 documentation

Widget for rotating the external scale.
Thank you :grinning:

Nice! Thank you!
@fbiego if you have a little bit of free time, can you add an example based on this?

2 Likes

@fbiego
I corrected the code a little, please add it :grinning:

static void scale_cb(void* var, int32_t v)
{
lv_scale_set_rotation((lv_obj_t *)var, v);
}
void lv_example_scale_12(void)
{
lv_obj_t* scale_loader = lv_scale_create(lv_screen_active());
lv_obj_set_size(scale_loader, 300, 300);
lv_scale_set_mode(scale_loader, LV_SCALE_MODE_ROUND_INNER);
lv_obj_center(scale_loader);
lv_obj_set_style_length(scale_loader, 10, LV_PART_ITEMS);
lv_scale_set_total_tick_count(scale_loader, 100);
lv_scale_set_angle_range(scale_loader, 360);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, scale_loader);
lv_anim_set_exec_cb(&a, scale_cb);
lv_anim_set_values(&a, 0, 360);
lv_anim_set_time(&a, 10000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_path_cb(&a, lv_anim_path_linear);
lv_anim_start(&a);
}