How to make a curved progress bar?

Important: unclear posts may not receive useful answers.

I want to make a curved progress bar. Which one can I apply?

Before posting

  • Get familiar with Markdown to format and structure your post
  • Be sure to update lvgl from the latest version from the master branch.
  • Be sure you have checked the relevant part of the documentation.
  • If applicable use the Simulator to eliminate hardware related issues.

Delete this section if you read and applied the mentioned points.

Description

What MCU/Processor/Board and compiler are you using?

What LVGL version are you using? Ver 8.0

What do you want to achieve? I want to do it like the video below. But the code in this video is not efficient.

What have you tried so far?

Bar: Unbent
line: cannot be parent

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.

The code block(s) should be formatted like:

/*You code here*/

Please advise.

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.
video

Do you need to generate the curved path runtime? If not, you can use ARGB image on which the line to fill is a hole (transparent) and put a red object below it and increase the size of that object as the process progresses.

You can also draw the path to an LV_IMG_CF_ALPHA_8BIT canvas and use it as mask on similarly to the ARGB image before.

Or the path can be created from many short lines and you can change the colors of the line segments as the time passes (I can show an example for it.)

@kisvegabor do you have some example? I search all website can not find any lv_objmask example for v8.3, in the document only a few word mention mask. And in the internet the example:
4 void lv_ex_objmask_1(void)
5 {
6
7 /Set a very visible color for the screen to clearly see what happens/
8 lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex3(0xf33));
9
10 lv_obj_t * om = lv_objmask_create(lv_scr_act(), NULL);
11 lv_obj_set_size(om, 200, 200);
12 lv_obj_align(om, NULL, LV_ALIGN_CENTER, 0, 0);
13 lv_obj_t * label = lv_label_create(om, NULL);
14 lv_label_set_long_mode(label, LV_LABEL_LONG_BREAK);
15 lv_label_set_align(label, LV_LABEL_ALIGN_CENTER);

BUT in v8.3 does not have lv_objmask_create function.

Could you show me some example? Please.

Hi,

You can find a masking example in v8 here: Roller (lv_roller) — LVGL documentation

Thanks a lot, I made it. But after I add the mask, it will like window-shades.
I want to get:


But I got:
微信图片_20240825175920

This is my code:

/*********************
 *      DEFINES
 *********************/
const lv_coord_t mask_width = 792;
const lv_coord_t mask_height = 202;
/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void hal_init(void);
static int tick_thread(void *data);

/**********************
 *  STATIC VARIABLES
 **********************/
lv_ui guider_ui;
/**********************
 *      MACROS
 **********************/
 /* Create the mask of a text by drawing it to a canvas*/
lv_color_t mask_map[LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(792,202)];
static void mask_event_cb(lv_event_t * e);
/**********************
 *   GLOBAL FUNCTIONS
 **********************/
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int nCmdShow)
{
    int i;
    /*Initialize LittlevGL*/
    lv_init();

    /*Initialize the HAL for LittlevGL*/
    lv_win32_init(hInstance, SW_SHOWNORMAL, 800, 480, NULL);

    /*Output prompt information to the console, you can also use printf() to print directly*/
    LV_LOG_USER("LVGL initialization completed!");

    /*Run the demo*/
    //lv_demo_widgets();
    setup_ui(&guider_ui);

    lv_obj_add_event_cb(guider_ui.screen_img_1, mask_event_cb, LV_EVENT_ALL, guider_ui.screen_img_1);

    while(!lv_win32_quit_signal) {
        /* Periodically call the lv_task handler.
         * It could be done in a timer interrupt or an OS task too.*/
        lv_task_handler();
        usleep(10000);       /*Just to let the system breath*/

    }
    return 0;
}

static void mask_event_cb(lv_event_t * e) {
    static lv_draw_mask_map_param_t m;
    static int16_t mask_id;
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t* obj = lv_event_get_target(e);

    if (code == LV_EVENT_COVER_CHECK) {
        lv_event_set_cover_res(e, LV_COVER_RES_MASKED);
    }
    else if (code == LV_EVENT_DRAW_MAIN_BEGIN) {
        /*Create a "8 bit alpha" canvas and clear it*/
        lv_obj_t* canvas = lv_canvas_create(lv_scr_act());
        lv_canvas_set_buffer(canvas, mask_map, mask_width, mask_height, LV_IMG_CF_TRUE_COLOR_ALPHA);
        lv_canvas_fill_bg(canvas, lv_color_black(), LV_OPA_TRANSP);

        /*Draw a label to the canvas. The result "image" will be used as mask*/
        lv_draw_rect_dsc_t  rect_dsc;
        lv_draw_rect_dsc_init(&rect_dsc);
        rect_dsc.radius = 0;
        rect_dsc.bg_opa = LV_OPA_COVER;
        rect_dsc.bg_color = lv_color_white();
        rect_dsc.bg_grad.dir = LV_GRAD_DIR_NONE;
        rect_dsc.border_width = 0;
        lv_canvas_draw_rect(canvas, 0, 0, 150, 100, &rect_dsc);
        /*The mask is reads the canvas is not required anymore*/
        lv_obj_del(canvas);
        /* Create an object from where the text will be masked out.
        * Now it's a rectangle with a gradient but it could be an image too*/
        lv_draw_mask_map_init(&m, &obj->coords, mask_map);
        mask_id = lv_draw_mask_add(&m, NULL);
    }
    else if (code == LV_EVENT_DRAW_MAIN_END) {
        lv_draw_mask_free_param(&m);
        lv_draw_mask_remove_id(mask_id);
    }
}

Probably it’s not causing the issue, but you shouldn’t create widgets in LV_EVENT_DRAW_* events.

In order to test it I need a more complete example. I suggest using a Simulator where you create an image and try to mask it.

Note that, you don’t need a mask to clip the right side of the image. Just make the image shorter with lv_obj_set_width.

Thanks for reply. I have tried to put the canvas to the main function, but the result is same. And my progress bar is L type


I want to use mask to make the animation. I use codeblocks simulator. And I found I draw a rectangle on canvas also like windows-shades. And another strange thing, the image width is 792, but if I set the rectangle width is 200, the mask will full of the image.

I check the code, lv_draw_mask_map_init(lv_draw_mask_map_param_t * param, const lv_area_t * coords, const lv_opa_t * map)
the map point is lv_opa_t, but my buffer is lv_color_t.
Is this problem? @kisvegabor

@kisvegabor
I know the problem, mask only use lv_opa_t array, so you can not draw rectangle on it. you must change the array by yourself.