Drawing line circle or some other shape on top of another widget

I have a chart widget which have 3 signals. When there is an interrupt for example to show high pressure, I want to place a mark like a vertical line on the buttom of the chart. The graph is circular and so I dont want to make another widget on top of my chart, since I want the line to be dissapeared when the last place where the line was redrawn. There might happen to appear periodic interrupt every other second.
In the case of making widget, i should remove it when the last place is gowing to be redrawn. I dont think making and omitting dynamically would be a good idea for this case.

No one to help :disappointed_relieved:

I thought about this when I first read it and could not come up with anything other than just making an extra widget and placing that on top of your chart. You could set the HIDDEN flag when necessary so you don’t have to keep creating and deleting this object.

I don’t want to create objects, I just want to draw shapes. Since it might happen I need to generate no object or maybe 300 objects, and this may cause a memory leakage on low-memory devices. And obviously, They are not the main part of GUI, to worth creating object for.

In that case I suspect a canvas is the only way forward: Canvas (lv_canvas) — LVGL documentation.

I have no idea how this works but it does allow you to draw pixels directly on an area.You will have to manually define the shapes you want somewhere in order to copy them to the canvas, or use images and copy those.

@Tinus Still Canvas is an object, I want a non-object method.

Everything in LVGL is based on objects! A canvas is only one object to draw multiples things over your whole screen.

If you really do not want any objects you will have to use your display’s native drawing functionality without LVGL in between.

I’m not sure how many objects will be created, and I want them to be removed during the redraw of the cyclic graph. Because of this uncertainty, I can’t know in advance if I’ve marked a particular point. The graph widget clears its previous lines when redrawing automatically, so I’d like to know if it’s possible to intervene in the drawing process to add a line or circle below the graph manually. This is why I prefer relying on the graph widget itself, rather than creating another widget on top and managing it manually.
And why should I stick to LCD routines? while LVGL has routines to draw many type of shapes?

@Tinus @kisvegabor
I am looking for some solution like this

void event_cb(lv_event_t * e)
{
    lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e); 
    lv_draw_line_dsc_t line_dsc_default;

    // Initialize the line drawing descriptor
    lv_draw_line_dsc_init(&line_dsc_default);
    lv_obj_init_draw_line_dsc(chartL, LV_PART_ITEMS, &line_dsc_default);

    // Define the points for the line
    lv_point_t p1, p2;

    // Set coordinates for the line (adjust as necessary)
    p1.x = dsc->p1->x; // Use the x-coordinate from the part descriptor
    p2.x = dsc->p1->x; // This should be the same x-coordinate for a vertical line

    // Adjust y-coordinates as necessary
    // Here, ensure the y values are set according to your chart's range
    p1.y = 10; // Set this to the desired y position
    p2.y = 20; // Set this to another desired y position

    // Check if the part being drawn is the main part
    if (dsc->part == LV_PART_MAIN)
    {
        if (event_occured == true)
{
             lv_draw_line(dsc->draw_ctx, &line_dsc_default, &p1, &p2);
event_occured = false;
}
    }
}

lv_obj_add_event_cb(chartL, pace_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);

But it doesnt work unfortunately. I want draw of this line happen on the latest point that is going to be (re)drawn, if the gpio interrupt has been activated.

What abut a chart cursor?

@kisvegabor I don’t know fully but I think the cursor of chart is also an object, which means it is not deleted on the data redrawn, My data is displayed online, which means only last 5 seconds data is only displayed and then the recent data is displayed, and I should emphasize that I should use that the chart in circular mode. the chart is not updated at once, but every other 100ms. And new data come in 10ms period. which means each time 10 data is pushed into the chart.

I think don’t fully understand how it should work. Could you send a simple drawing about the expected result?

The cursor is not a widget, it’s just drawn based on some data.

@kisvegabor Here is what I want


What I need is a way to display those interrupt pulses, like a simple line that disappears during redrawing as if it never existed. My issue with creating widgets is that I’m uncertain about how many interrupts might occur, and constantly creating and deleting objects could result in unwanted memory leaks.

You can create and delete char cursors dynamically.

When there is an interrupt, you can create the cursor, and you when you update the point again, just delete the cursor.

Dear @kisvegabor
After searching through the library and using ChatGPT :smile:, I found a solution. However, there’s one issue: while it does draw the rectangle wider and clears some parts, it achieves what I need, which is to remove the rectangle shape from the chart when a point in the series needs to be redrawn.

	lv_event_code_t code = lv_event_get_code(e);
    if((code == LV_EVENT_DRAW_MAIN) &(pulseActive == true))
    {
        lv_obj_t * obj = lv_event_get_target(e);

        lv_draw_rect_dsc_t rect_dsc;
        lv_draw_rect_dsc_init(&rect_dsc);
        lv_obj_init_draw_rect_dsc(obj, LV_PART_MAIN, &rect_dsc);

        rect_dsc.bg_color = lv_color_white();
        lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);

        lv_area_t new_clip_area;
        new_clip_area.x1 = draw_ctx->clip_area->x1; // Keep original x1
        new_clip_area.y1 = 430; // Set new y1
        new_clip_area.x2 = draw_ctx->clip_area->x2; // Keep original x2
        new_clip_area.y2 = 440; // Set new y2

        draw_ctx->clip_area = &new_clip_area;
        lv_point_t p1={draw_ctx->clip_area->x1,430};
        lv_point_t p2={draw_ctx->clip_area->x1,440};
        lv_draw_rect(draw_ctx, &rect_dsc, &obj->coords);
//        lv_draw_line(draw_ctx, &rect_dsc, &p1, &p2);
        pulseActive = false;
    }

Now I wonder why it doesnt draw anything if I comment lv_draw_rect(draw_ctx, &rect_dsc, &obj->coords); and uncomment // lv_draw_line(draw_ctx, &rect_dsc, &p1, &p2); or at least i connot see anything on lcd if it draw and clears it instantly.

Nice!

For the line you need an lv_draw_line_dsc_t. :slight_smile:

Thank You
Great @kisvegabor and great LVGL

Here is the final working code on my side

static void event_cb(lv_event_t *e)
{
	lv_event_code_t code = lv_event_get_code(e);
    if((code == LV_EVENT_DRAW_MAIN) &(pulseActive == true))
    {
        lv_obj_t * obj = lv_event_get_target(e);
        lv_draw_line_dsc_t line_dsc;
        lv_draw_line_dsc_init(&line_dsc);
        lv_obj_init_draw_line_dsc(obj, LV_PART_MAIN, &line_dsc);

        line_dsc.color = lv_color_white();
        lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);

        lv_area_t new_clip_area;
        new_clip_area.x1 = draw_ctx->clip_area->x1;
        new_clip_area.y1 = 430;
        new_clip_area.x2 = draw_ctx->clip_area->x1;
        new_clip_area.y2 = 440;

        draw_ctx->clip_area = &new_clip_area;
        lv_point_t p1={draw_ctx->clip_area->x1,430};
        lv_point_t p2={draw_ctx->clip_area->x1,440};
        lv_draw_line(draw_ctx, &line_dsc, &p1, &p2);
        pulseActive = false;
    }
}

and in the creation of widget,

lv_obj_add_event_cb(chart,event_cb ,
			LV_EVENT_DRAW_MAIN, NULL);
1 Like

@kisvegabor
My solution is based on event, Is there any way that one fill the lv_draw_ctx_t * draw_ctx outside an event, since drawing lines need this variable?

I don’t get it. The draw_ctx exists only during drawing (in draw events).

What I’m trying to say is that managing events isn’t straightforward. For example, I want to add data to a chart and, in the same function, also draw lines on the chart. However, adding data is done in the main loop, while drawing additional lines needs to happen within the event. What I mean is that I want to draw the lines within the same operation, without using objects. In comparison, this functionality is available in EMWIN but not in LVGL.