Impossibility of rotating the scale of any scale other than ROUND

I draw the base and round it off to serve as a background.

The code for this is:

void gauge_background(void)
{
  lv_obj_clear_flag(background, LV_OBJ_FLAG_SCROLLABLE);      /// Flags
  lv_obj_set_size(background, 360, 360);
  lv_obj_set_style_radius(background, LV_RADIUS_CIRCLE, 0); // display becomes ROUND
  lv_obj_set_style_bg_color(background, lv_color_hex(0x8B4513), LV_PART_MAIN | LV_STATE_DEFAULT);
  lv_obj_set_style_bg_opa(background, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
  lv_obj_center(background);
}

I draw a round scale.

The code for this is:
Don’t be confused by the name of the function horizontal_line, it is intended for a linear scale :grinning:

void horizontal_line(void)
{
    lv_obj_t * scale_horizon_line = lv_scale_create(lv_screen_active());
    // lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_HORIZONTAL_TOP);
    lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_ROUND_OUTER);
    lv_obj_set_size(scale_horizon_line, 360, 360);
    lv_obj_center(scale_horizon_line);
    lv_obj_set_pos(scale_horizon_line, 0, 0); // X->, Y-⌄
}

Turn the scale on on +200 degrees.

Moreover, the rotation is from the conditional starting point or coordinate, which is laid down in the main file:

To rotate the circular scale, you need to add one line to the code:

void horizontal_line(void)
{
    lv_obj_t * scale_horizon_line = lv_scale_create(lv_screen_active());
    // lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_HORIZONTAL_TOP);
    lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_ROUND_OUTER);
    lv_obj_set_size(scale_horizon_line, 360, 360);
    lv_obj_center(scale_horizon_line);
    lv_obj_set_pos(scale_horizon_line, 0, 0); // X->, Y-⌄
    lv_scale_set_rotation(scale_horizon_line, 200);
}

Now I’m trying to draw a linear scale.

The code for this is:

void horizontal_line(void)
{
    lv_obj_t * scale_horizon_line = lv_scale_create(lv_screen_active());
    lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_HORIZONTAL_TOP);
    // lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_ROUND_OUTER);
    lv_obj_set_size(scale_horizon_line, 360, 360);
    lv_obj_center(scale_horizon_line);
    lv_obj_set_pos(scale_horizon_line, 0, 0); // X->, Y-⌄
}

I try to rotate the linear scale on 80 degrees… and as you can see, nothing happens.

The code for this is:

void horizontal_line(void)
{
    lv_obj_t * scale_horizon_line = lv_scale_create(lv_screen_active());
    lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_HORIZONTAL_TOP);
    // lv_scale_set_mode(scale_horizon_line, LV_SCALE_MODE_ROUND_OUTER);
    lv_obj_set_size(scale_horizon_line, 360, 360);
    lv_obj_center(scale_horizon_line);
    lv_obj_set_pos(scale_horizon_line, 0, 0); // X->, Y-⌄
    lv_scale_set_rotation(scale_horizon_line, 80);
}

And another oddity, you specify the flag

LV_SCALE_MODE_HORIZONTAL_TOP

and the scale is drawn at the bottom, you specify the flag

LV_SCALE_MODE_HORIZONTAL_BOTTOM

and the scale is drawn at the top :rofl:

Similarly, rotation does not work for flags

LV_SCALE_MODE_VERTICAL_LEFT
LV_SCALE_MODE_VERTICAL_RIGHT

I also tried rotate a simple line, but that doesn’t work either, and created the line in two ways.

With just code:

    /*Create a line and apply the new style*/
    lv_obj_t * horizon_line;
    horizon_line = lv_line_create(lv_screen_active());
    lv_obj_set_style_length(horizon_line, 100, 0);
    lv_obj_set_style_line_width(horizon_line, 6, LV_PART_INDICATOR); // Setting the thickness
    lv_obj_set_style_line_color(horizon_line, lv_color_hex(0xFFFFFF), 0); // Set the line color to white
    lv_obj_center(horizon_line);

    lv_obj_set_style_transform_rotation(horizon_line, 1800, LV_PART_MAIN | LV_STATE_DEFAULT);

In this case, the line is not drawn at all :roll_eyes:

With added style:

    /*Create a line and apply the new style*/
    lv_obj_t * horizon_line;
    horizon_line = lv_line_create(lv_screen_active());

    static lv_point_precise_t line_points[] = { {0, 0}, {360, 0}};
    // /*Create style*/
    
    static lv_style_t style_line;
    lv_style_init(&style_line);
    lv_style_set_line_width(&style_line, 4); // Setting the thickness
    // lv_style_set_line_color(&style_line, lv_palette_main(LV_PALETTE_YELLOW));
    lv_style_set_line_color(&style_line, lv_color_hex(0xFFFFFF)); // Set the line color to white
    lv_line_set_points(horizon_line, line_points, 2);     /*Set the points*/
    lv_obj_add_style(horizon_line, &style_line, 0);
    lv_obj_center(horizon_line);

    lv_style_set_transform_rotation(&style_line, 20);

The line is drawn, but there is no rotation.

On the this forum and on github there were questions about where the meter from lvgl 8.3 disappeared to, it was much more convenient and productive and solved some problems.

Now the use of one widget has replaced everything, but behind the universality hides the impossibility of creating simple things :face_with_monocle:

Which LVGL Version are you using?

Regarding the scale rotation lv_scale_set_rotation, it seems to be only applicable in case the scale is set to round.

To rotate a linear scale is required to use lv_obj_set_style_transform_rotation(obj, -450, LV_PART_MAIN | LV_STATE_DEFAULT); to define the angle, and it seems that is necessary also to adjust the lv_obj_set_style_transform_pivot_x and lv_obj_set_style_transform_pivot_y to put in a correct “place”.

Regarding the line, this code seems to work

// line_example
            lv_obj_t *obj = lv_line_create(parent_obj);
            objects.line_example = obj;
            lv_obj_set_pos(obj, 59, 51);
            lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
            static lv_point_precise_t line_points[] = {
                { 0, 0 },
                { 0, 50 }
            };
            lv_line_set_points(obj, line_points, 2);
            lv_obj_set_style_transform_rotation(obj, 900, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_line_width(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_line_color(obj, lv_color_hex(0xffda0000), LV_PART_MAIN | LV_STATE_DEFAULT);

Although is not using a dedicated style for the line…

To rotate the line 90º, and red color…

1 Like

Yes, your example really draws a line and applies color to it without adding styles :grinning:
Also, we rotate the line to the desired angle - degree * 100
I have a question - how to rotate a line not from the beginning or end, but around the center of the line?
Do I need to specify a pivot?

9.3

I was able to catch the center of the line :grinning:

Line was rotate

The code for this is:

void rotate_line(void)
{
    // line_example
    lv_obj_t *obj = lv_line_create(lv_scr_act());
    lv_obj_center(obj);
    static lv_point_precise_t line_points[] = {
    { 0, 0 },
    { 360, 0 }
    };
    lv_line_set_points(obj, line_points, 2);

    lv_obj_set_style_transform_pivot_x(obj, 180, 0);
    // lv_obj_set_style_transform_pivot_y(obj, 90, 0);

    lv_obj_set_style_transform_rotation(obj, 450, 0);
    lv_obj_set_style_line_width(obj, 10, 0);
    lv_obj_set_style_line_color(obj, lv_palette_main(LV_PALETTE_RED), 0);
}

I couldn’t find the rotation center for half an hour until I commented out the line

lv_obj_set_style_transform_pivot_y

1 Like

Hello @arturv2000 :grinning:
Could you also help with advice on how to correctly shift these pivots?
I wrote such functions:

// drawing scale lines dynamically
void create_line(lv_obj_t **line_obj, lv_point_precise_t *line_points, int pos_y, int deg) {
    *line_obj = lv_line_create(lv_scr_act());
    lv_obj_center(*line_obj); // Centering the line
    lv_obj_set_pos(*line_obj, 0, pos_y); // Setting Y position

    lv_line_set_points(*line_obj, line_points, 2);     /* Setting points */
    static lv_style_t style_line;
    lv_style_init(&style_line);
    lv_style_set_line_width(&style_line, 2); // Setting the thickness
    lv_style_set_line_color(&style_line, lv_color_hex(0xFFFFFF)); // Set line color to white
    lv_obj_add_style(*line_obj, &style_line, 0);

    lv_obj_set_style_transform_pivot_x(*line_obj, line_points[1].x / 2, 0); // Setting the X-axis offset
    lv_obj_set_style_transform_pivot_y(*line_obj, line_points[1].x / 2, 0); //Setting Y-axis offset
    lv_obj_set_style_transform_rotation(*line_obj, -deg * 10, 0); // Setting the rotation angle
}
void scale_v2(int deg)
{
    // arrays of lines of different lengths
    static lv_point_precise_t line_5[] = { {0, 0}, {50, 0}};    // 5
    static lv_point_precise_t line_10[] = { {0, 0}, {100, 0}};  // 10

    lv_obj_t *pitch_line_10_positive;
    create_line(&pitch_line_10_positive, line_10, -80, deg);
    
    lv_obj_t *pitch_line_5_positive;
    create_line(&pitch_line_5_positive, line_5, -40, deg);

    lv_obj_t *pitch_line_5_negative;
    create_line(&pitch_line_5_negative, line_5, 40, deg);

    lv_obj_t *pitch_line_10_negative;
    create_line(&pitch_line_10_negative, line_10, 80, deg);
}

If the rotation angle is zero, then everything is fine.

If I rotate the lines by an angle of, say, 20 degrees, then everything immediately goes bad.

My idea is for the scale lines to rotate and be perpendicular to the yellow line :roll_eyes:

Just some ideias…

  1. Recalculate the value to set new origin point for the lines or pivot points. Should be doable…
  2. Use an image with the required scale (designed in Paint, Photoshop, whatever) and rotate the image, the image should eventually be png to allow transparency. Depending on what is supposed to be/do and objects on top/bottom may be a little heavy calculation side…
  3. Use a container, by default is fully transparent…, add the lines of the scale inside the container set the lines at correct position for rotation 0º, and rotate just the container and the lines will rotate automatically…

Code generated via EEZ-Studio, so is not copy-paste directly…

lv_obj_t *obj = lv_obj_create(0);
    objects.teste1 = obj;
    lv_obj_set_pos(obj, 0, 0);
    lv_obj_set_size(obj, 600, 450);
    {
        lv_obj_t *parent_obj = obj;
        {
            // Scale_Lines_Container
            lv_obj_t *obj = lv_obj_create(parent_obj);
            objects.scale_lines_container = obj;
            lv_obj_set_pos(obj, 0, 0);
            lv_obj_set_size(obj, 300, 300);
            lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE);
            lv_obj_set_style_border_color(obj, lv_color_hex(0xff4268a6), LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_border_opa(obj, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_transform_pivot_y(obj, 150, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_transform_rotation(obj, 250, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_transform_pivot_x(obj, 150, LV_PART_MAIN | LV_STATE_DEFAULT);
            lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
            {
                lv_obj_t *parent_obj = obj;
                {
                    // line1
                    lv_obj_t *obj = lv_line_create(parent_obj);
                    objects.line1 = obj;
                    lv_obj_set_pos(obj, 50, 150);
                    lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
                    static lv_point_precise_t line_points[] = {
                        { 0, 0 },
                        { 200, 0 }
                    };
                    lv_line_set_points(obj, line_points, 2);
                    lv_obj_set_style_line_width(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
                    lv_obj_set_style_line_color(obj, lv_color_hex(0xffdc1e1e), LV_PART_MAIN | LV_STATE_DEFAULT);
                }
                {
                    // line2
                    lv_obj_t *obj = lv_line_create(parent_obj);
                    objects.line2 = obj;
                    lv_obj_set_pos(obj, 100, 100);
                    lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
                    static lv_point_precise_t line_points[] = {
                        { 0, 0 },
                        { 100, 0 }
                    };
                    lv_line_set_points(obj, line_points, 2);
                    lv_obj_set_style_line_width(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
                    lv_obj_set_style_line_color(obj, lv_color_hex(0xffc01515), LV_PART_MAIN | LV_STATE_DEFAULT);
                }
                {
                    // line3
                    lv_obj_t *obj = lv_line_create(parent_obj);
                    objects.line3 = obj;
                    lv_obj_set_pos(obj, 100, 200);
                    lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
                    static lv_point_precise_t line_points[] = {
                        { 0, 0 },
                        { 100, 0 }
                    };
                    lv_line_set_points(obj, line_points, 2);
                    lv_obj_set_style_line_width(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
                    lv_obj_set_style_line_color(obj, lv_color_hex(0xffc81212), LV_PART_MAIN | LV_STATE_DEFAULT);
                }
            }
        }
    }

Just an example, the screen size was 600 x 450, and the container is center on the screen, the container size is 300x300 and the pivot points needed to be defined to 150,150…

Rotation to 45Âş: lv_image_set_rotation(obj, 450);
image

Rotation to 25Âş lv_image_set_rotation(obj, 250);

The container has border set, but was just to help visualize the data…

Just an ideia… depending on the scale/details required I would go probably with pre-generated image and rotate the image, unless if exist performance / Flash / Ram considerations…

1 Like

With what you are doing I am going to recommend not using any widgets other than the canvas widget and using circle math to handle rendering the curved gauges.

You also are going to want to create multiple canvas widgets setting the background to fully transparent and then you will be able to layer the canvas widgets one on top of each other. This will allow you to rotate the portions of your UI that you need to be able to rotate while keeping the rest of the UI static.

so render the lines straight onto a canvas and then rotate the canvas and not the lines.

1 Like