How do you dynamically update a canvas via an event?

Important: unclear posts may not receive useful answers.

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 FAQ and read 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?

Simulator

What LVGL version are you using?

What do you want to achieve?

I’m tryng to create some rectanglular outlines (with shifted perspective) that fill with color to indicate things. I have the shapes working but not sure how to update the canvas after an event.

The plan is to fill these outlines with canvas polygons but I can’t get these to draw based on an event and also not sure how to remove them just leaving the outlines aswell.

I also can’t work out how to get click events via mouse detected using a simulator, using WSL2 on windows 11

What have you tried so far?

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.

lv_obj_t * layer_shape(lv_obj_t * parent){

  
   lv_draw_rect_dsc_t rect_dsc;
    lv_draw_rect_dsc_init(&rect_dsc);
    
  
   rect_dsc.bg_opa = LV_OPA_60;
   rect_dsc.bg_color = lv_color_black();//lv_palette_lighten(LV_PALETTE_RED, 4);
   rect_dsc.blend_mode = LV_BLEND_MODE_ADDITIVE;



    lv_draw_line_dsc_t draw_dsc_main, draw_dsc_outer, draw_dsc_inner;
lv_draw_line_dsc_init(&draw_dsc_main);
lv_draw_line_dsc_init(&draw_dsc_outer);
lv_draw_line_dsc_init(&draw_dsc_inner);
 
set_main_draw_line_style(&draw_dsc_main);
set_offset_draw_line_style(&draw_dsc_outer);
set_offset_draw_line_style(&draw_dsc_inner);


 static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, LAYER_SHAPE_HEIGHT + 5)];

    lv_obj_t * canvas = lv_canvas_create(parent);
    lv_obj_add_flag(canvas, LV_OBJ_FLAG_CLICKABLE);
    //lv_obj_set_click(canvas, true);
    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH ,LAYER_SHAPE_HEIGHT + 5, LV_IMG_CF_TRUE_COLOR_ALPHA);
    lv_canvas_fill_bg(canvas, lv_palette_darken(LV_PALETTE_GREY, 1), LV_OPA_TRANSP);
    //lv_obj_add_style(canvas, &main_draw_line_style, 0);
    
    //lv_obj_align(canvas, LV_ALIGN_RIGHT_MID,0 ,0);
  //  lv_canvas_draw_rect(canvas, 10, 10, 20, 20, &rect_dsc);
    lv_point_t left = {5, (LAYER_SHAPE_HEIGHT / 2)+ 2.5};
     lv_point_t  top = {(LAYER_SHAPE_WIDTH / 2 ) + 5,2.5};
     lv_point_t    right = {LAYER_SHAPE_WIDTH + 5,(LAYER_SHAPE_HEIGHT / 2)+ 2.5};
     lv_point_t    bottom = {(LAYER_SHAPE_WIDTH / 2 ) + 5,LAYER_SHAPE_HEIGHT + 2.5};

     const lv_point_t points[4] = {left, top, right,
     bottom};
     lv_canvas_draw_polygon(canvas, points, 4,&rect_dsc);
     const lv_point_t main_line_points[5] = {left,top,right,bottom,left};
       const lv_point_t outer_line_points[5] = {{left.x - LINE_OFFSET, left.y }, translate_point(top, 0, -LINE_OFFSET),translate_point(right,LINE_OFFSET, 0),
   translate_point(bottom,0,LINE_OFFSET) , {left.x - LINE_OFFSET, left.y }};
        const lv_point_t inner_line_points[5] = {translate_point(left,LINE_OFFSET,0), translate_point(top, 0, LINE_OFFSET),translate_point(right,-LINE_OFFSET, 0),
   translate_point(bottom,0,-LINE_OFFSET) , translate_point(left,LINE_OFFSET,0)};
   
    lv_canvas_draw_line(canvas, outer_line_points,5, &draw_dsc_outer);
     lv_canvas_draw_line(canvas, inner_line_points,5, &draw_dsc_inner);
      lv_canvas_draw_line(canvas, main_line_points, 5, &draw_dsc_main);
    lv_area_t blur_area = {
      4, 1, LAYER_SHAPE_WIDTH + 6, LAYER_SHAPE_HEIGHT + 4
    };
     
    lv_canvas_blur_hor(canvas, &blur_area, 1.5);
    lv_canvas_blur_ver(canvas, &blur_area, 1.5)
    
    lv_obj_add_flag(canvas, LV_OBJ_FLAG_EVENT_BUBBLE);
    return canvas;
}

lv_obj_t * layer_indicators(lv_obj_t * parent){

static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];

    lv_obj_t * canvas = lv_canvas_create(parent);
    lv_obj_add_flag(canvas, LV_OBJ_FLAG_CLICKABLE);
  
    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH ,CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED);
    lv_canvas_fill_bg(canvas, lv_color_black(), LV_OPA_100);
  

    lv_obj_align(canvas, LV_ALIGN_TOP_LEFT,4 ,4);
    lv_img_dsc_t * img ;
   img = lv_canvas_get_img(layer_shape(canvas));
      for(int i = 0;i < 5; i++){
          
         lv_canvas_transform(canvas, img,0,256, 0,(4 * 10) - ( i * 10),0 ,0, false);
      
      }
          static lv_color_t cbuf_tmp[CANVAS_WIDTH * CANVAS_HEIGHT];
    memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp)); 
    img->data = (void *)cbuf_tmp;
     lv_obj_add_event_cb(canvas, layer_change_cb,LV_EVENT_PRESSED, NULL );
     lv_obj_add_event_cb(canvas, layer_change_cb,LV_EVENT_CLICKED, NULL );
     
    return canvas;
}

1 Like

ok so this is the code once cleaned up

lv_obj_t * layer_shape(lv_obj_t * parent){
    lv_draw_rect_dsc_t rect_dsc;
    lv_draw_rect_dsc_init(&rect_dsc);

    rect_dsc.bg_opa = LV_OPA_60;
    rect_dsc.bg_color = lv_color_black();//lv_palette_lighten(LV_PALETTE_RED, 4);
    rect_dsc.blend_mode = LV_BLEND_MODE_ADDITIVE;

    lv_draw_line_dsc_t draw_dsc_main, draw_dsc_outer, draw_dsc_inner;
    lv_draw_line_dsc_init(&draw_dsc_main);
    lv_draw_line_dsc_init(&draw_dsc_outer);
    lv_draw_line_dsc_init(&draw_dsc_inner);

    set_main_draw_line_style(&draw_dsc_main);
    set_offset_draw_line_style(&draw_dsc_outer);
    set_offset_draw_line_style(&draw_dsc_inner);

    static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, LAYER_SHAPE_HEIGHT + 5)];

    lv_obj_t * canvas = lv_canvas_create(parent);
    lv_obj_add_flag(canvas, LV_OBJ_FLAG_CLICKABLE);
    //lv_obj_set_click(canvas, true);
    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH ,LAYER_SHAPE_HEIGHT + 5, LV_IMG_CF_TRUE_COLOR_ALPHA);
    lv_canvas_fill_bg(canvas, lv_palette_darken(LV_PALETTE_GREY, 1), LV_OPA_TRANSP);
    //lv_obj_add_style(canvas, &main_draw_line_style, 0);

    //lv_obj_align(canvas, LV_ALIGN_RIGHT_MID,0 ,0);
    //lv_canvas_draw_rect(canvas, 10, 10, 20, 20, &rect_dsc);
    lv_point_t left = {5, (LAYER_SHAPE_HEIGHT / 2) + 2.5};
    lv_point_t top = {(LAYER_SHAPE_WIDTH / 2 ) + 5, 2.5};
    lv_point_t right = {LAYER_SHAPE_WIDTH + 5, (LAYER_SHAPE_HEIGHT / 2) + 2.5};
    lv_point_t bottom = {(LAYER_SHAPE_WIDTH / 2 ) + 5, LAYER_SHAPE_HEIGHT + 2.5};

    const lv_point_t points[4] = {left, top, right, bottom};
    lv_canvas_draw_polygon(canvas, points, 4, &rect_dsc);
    const lv_point_t main_line_points[5] = {left,top,right,bottom,left};
    const lv_point_t outer_line_points[5] = {
        {left.x - LINE_OFFSET, left.y },
        translate_point(top, 0, -LINE_OFFSET),
        translate_point(right,LINE_OFFSET, 0),
        translate_point(bottom,0,LINE_OFFSET) ,
        {left.x - LINE_OFFSET, left.y }
    };
    const lv_point_t inner_line_points[5] = {
        translate_point(left,LINE_OFFSET,0),
        translate_point(top, 0, LINE_OFFSET),
        translate_point(right,-LINE_OFFSET, 0),
        translate_point(bottom,0,-LINE_OFFSET) ,
        translate_point(left,LINE_OFFSET,0)
    };

    lv_canvas_draw_line(canvas, outer_line_points, 5, &draw_dsc_outer);
    lv_canvas_draw_line(canvas, inner_line_points, 5, &draw_dsc_inner);
    lv_canvas_draw_line(canvas, main_line_points, 5, &draw_dsc_main);
    lv_area_t blur_area = {4, 1, LAYER_SHAPE_WIDTH + 6, LAYER_SHAPE_HEIGHT + 4};

    lv_canvas_blur_hor(canvas, &blur_area, 1.5);
    lv_canvas_blur_ver(canvas, &blur_area, 1.5)

    lv_obj_add_flag(canvas, LV_OBJ_FLAG_EVENT_BUBBLE);
    return canvas;
}

lv_obj_t * layer_indicators(lv_obj_t * parent){

    static lv_color_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];

    lv_obj_t * canvas = lv_canvas_create(parent);
    lv_obj_add_flag(canvas, LV_OBJ_FLAG_CLICKABLE);

    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH ,CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED);
    lv_canvas_fill_bg(canvas, lv_color_black(), LV_OPA_100);

    lv_obj_align(canvas, LV_ALIGN_TOP_LEFT,4 ,4);
    lv_img_dsc_t * img ;
    img = lv_canvas_get_img(layer_shape(canvas));
    for(int i = 0;i < 5; i++){
        lv_canvas_transform(canvas, img,0,256, 0,(4 * 10) - ( i * 10),0 ,0, false);
    }
    static lv_color_t cbuf_tmp[CANVAS_WIDTH * CANVAS_HEIGHT];
    memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp));
    img->data = (void *)cbuf_tmp;
    lv_obj_add_event_cb(canvas, layer_change_cb, LV_EVENT_PRESSED, NULL );
    lv_obj_add_event_cb(canvas, layer_change_cb, LV_EVENT_CLICKED, NULL );

    return canvas;
}

Where is the rest of the code? You have 2 functions and there is nothing calling those functions so I am unsure of what you are attempting to do. You have 2 events registered to a nonexistent function. You are calling a function translate_point which is not seen in the code. You have references to draw_dsc_main, draw_dsc_outer and draw_dsc_inner but their declaration is not seen anywhere in the code. You are creating a buffer using LV_CANVAS_BUF_SIZE_TRUE_COLOR and then setting the buffer to the canvas using the color format LV_IMG_CF_TRUE_COLOR_ALPHA

The canvas does not support transparency and you are setting the background color to a transparency using LV_OPA_TRANSP.

You are setting floats to structure fields that only take integer values specifically uint8_t or uint16_t depending on whaat you have LVGL set up to do. You are not using the f specifier after the float value.

You are calling functions that are a WIP and do not do anything lv_canvas_blur_hor and lv_canvas_blur_ver

You are also calling layer_shape passing a canvas object in which that object gets used as the parent for another canvas object. Not sure what the intention is there.

Yh not gonna lie this is my first time using lvgl hence the many mistakes, didn’t copy all the code as this was I felt this was a general question and I had some irrelevant parts including failed attempts and other parts of the ui.

Basically what I want to know is, if I have a shape with an outline (using lv_canvas_draw_line)after the canvas receives an event how can I then fill that shape with a colour (using lv_canvas_draw_polygon) and then also remove it later (would lv_canvas_draw_polygon with the original bg color work?. I can post the rest of the code if needed but it’s a mess as i’m basically protyping atm.

Screenshot 2023-07-19 232135
vs
Screenshot 2023-07-19 234136

Also not sure what you mean about not supporting transparency because changing that value gave me the effect I wanted, and the blur functions also work. The declarations are also all there on one line?

But yh thankyou for the rest of the pointers

lv_point_t translate_point(lv_poin

t_t point, int16_t x, int16_t y)
{
  lv_point_t final_point = {point.x + x, point.y + y};
  return final_point;
}