Draw simple line given a parent panel

Description

Hi all, i would like to ask how to correctly draw a simple line from point a to point b, given a parent that will cointain the line.
With the code i have tried the line won’t show up.

What LVGL version are you using?

8.2.0

What do you want to achieve?

Draw line

What have you tried so far?

i have tried this code, this takes the size of the parent object and decides the two points

void draw_line_relative(lv_obj_t *obj, int16_t start_x, int16_t start_y, int16_t end_x, int16_t end_y, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) {
	
	lv_area_t obj_coords;
	lv_obj_get_coords(obj, &obj_coords);

	int16_t obj_width = lv_area_get_width(&obj_coords);
	int16_t obj_height = lv_area_get_height(&obj_coords);

	int16_t center_x = obj_coords.x1 + obj_width / 2;
	int16_t center_y = obj_coords.y1 + obj_height / 2;

	int16_t line_start_x = center_x + start_x * obj_width / 200;
	int16_t line_start_y = center_y + start_y * obj_height / 200;
	int16_t line_end_x = center_x + end_x * obj_width / 200;
	int16_t line_end_y = center_y + end_y * obj_height / 200;

	lv_point_t point1 = { line_start_x, line_start_y };
	lv_point_t point2 = { line_end_x, line_end_y };
	
	static lv_point_t line_points[2];
	
	line_points[0] = point1;
	line_points[1] = point2;
	
	/*Create style*/
	static lv_style_t style_line;
	lv_style_init(&style_line);
	lv_style_set_line_width(&style_line, 1);
	lv_style_set_line_color(&style_line, color);
	lv_style_set_line_rounded(&style_line, false);

	
	lv_obj_t * line1;
	line1 = lv_line_create(obj);
	lv_obj_add_style(line1, &style_line, LV_PART_ANY);  
	lv_obj_set_pos(line1, 20, 220);
	lv_line_set_points(line1, line_points, 2); /*Set the points*/
	
}

void init_phasor()
{
	lv_color_t red_color = LV_COLOR_MAKE(255, 0, 0);
	draw_line_relative(ui_PhasorDiagramContainer, -50, 0, 50, 0, red_color, LV_OPA_COVER, LV_BLEND_MODE_NORMAL);

}

Hi @Alberto_Pesce ,

I am not certain of what you want to achieve here, it looks like your wanting to plot a line which is scaled in some way, in an object with the centre of the object as the origin. I think in the code you have shown there could be a couple of errors to fix:

The first is the style should use LV_PART_MAIN for the colouring to take affect.
The second issue which will potentially make the line draw off screen somewhere is the call I have commented out below ( lv_obj_set_pos(line1, 20, 220);) With the code as below I get a horizontal red line in the centre of the parent container when I run it in the simulator.

void draw_line_relative(lv_obj_t *obj, int16_t start_x, int16_t start_y, int16_t end_x, int16_t end_y, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) {

	lv_area_t obj_coords;
	lv_obj_get_coords(obj, &obj_coords);

	int16_t obj_width = lv_area_get_width(&obj_coords);
	int16_t obj_height = lv_area_get_height(&obj_coords);

	int16_t center_x = obj_coords.x1 + obj_width / 2;
	int16_t center_y = obj_coords.y1 + obj_height / 2;

	int16_t line_start_x = center_x + start_x * obj_width / 200;
	int16_t line_start_y = center_y + start_y * obj_height / 200;
	int16_t line_end_x = center_x + end_x * obj_width / 200;
	int16_t line_end_y = center_y + end_y * obj_height / 200;

	lv_point_t point1 = { line_start_x, line_start_y };
	lv_point_t point2 = { line_end_x, line_end_y };

	static lv_point_t line_points[2];

	line_points[0] = point1;
	line_points[1] = point2;

	/*Create style*/
	static lv_style_t style_line;
	lv_style_init(&style_line);
	lv_style_set_line_width(&style_line, 1);
	lv_style_set_line_color(&style_line, color);
	lv_style_set_line_rounded(&style_line, false);


	lv_obj_t * line1;
	line1 = lv_line_create(obj);
	lv_obj_add_style(line1, &style_line, LV_PART_MAIN);
//	lv_obj_set_pos(line1, 20, 220);
	lv_line_set_points(line1, line_points, 2); /*Set the points*/

}

void init_phasor( lv_obj_t *parent )
{
	lv_color_t red_color = LV_COLOR_MAKE(255, 0, 0);
	draw_line_relative(parent, -50, 0, 50, 0, red_color, LV_OPA_COVER, LV_BLEND_MODE_NORMAL);

}

I hope that helps…

Kind Regards,

Pete

@pete-pjb thank you, i’ll try this tomorrow!

1 Like

@pete-pjb still not showing… i don’t know why, i paste here also the label i am creating

ui_PhasorDiagramContainer = lv_obj_create(ui_PhasorScreen);
    lv_obj_set_width(ui_PhasorDiagramContainer, lv_pct(52));
    lv_obj_set_height(ui_PhasorDiagramContainer, lv_pct(77));
    lv_obj_set_x(ui_PhasorDiagramContainer, lv_pct(18));
    lv_obj_set_y(ui_PhasorDiagramContainer, lv_pct(10));
    lv_obj_set_align(ui_PhasorDiagramContainer, LV_ALIGN_TOP_MID);
    lv_obj_clear_flag(ui_PhasorDiagramContainer,
                      LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_CLICK_FOCUSABLE | LV_OBJ_FLAG_GESTURE_BUBBLE | LV_OBJ_FLAG_SCROLLABLE |
                      LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_CHAIN);     /// Flags
    lv_obj_set_style_radius(ui_PhasorDiagramContainer, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(ui_PhasorDiagramContainer, lv_color_hex(0x1B1B1B), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_PhasorDiagramContainer, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_PhasorDiagramContainer, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_left(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_right(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_top(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_bottom(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_row(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_column(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);

and

void draw_line_relative(lv_obj_t *obj, int16_t start_x, int16_t start_y, int16_t end_x, int16_t end_y, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) {

	lv_area_t obj_coords;
	lv_obj_get_coords(obj, &obj_coords);

	int16_t obj_width = lv_area_get_width(&obj_coords);
	int16_t obj_height = lv_area_get_height(&obj_coords);

	int16_t center_x = obj_coords.x1 + obj_width / 2;
	int16_t center_y = obj_coords.y1 + obj_height / 2;

	int16_t line_start_x = center_x + start_x * obj_width / 200;
	int16_t line_start_y = center_y + start_y * obj_height / 200;
	int16_t line_end_x = center_x + end_x * obj_width / 200;
	int16_t line_end_y = center_y + end_y * obj_height / 200;

	lv_point_t point1 = { line_start_x, line_start_y };
	lv_point_t point2 = { line_end_x, line_end_y };

	static lv_point_t line_points[2];

	line_points[0] = point1;
	line_points[1] = point2;

	/*Create style*/
	static lv_style_t style_line;
	lv_style_init(&style_line);
	lv_style_set_line_width(&style_line, 1);
	lv_style_set_line_color(&style_line, color);
	lv_style_set_line_rounded(&style_line, false);


	lv_obj_t * line1;
	line1 = lv_line_create(obj);
	lv_obj_add_style(line1, &style_line, LV_PART_MAIN);
	//	lv_obj_set_pos(line1, 20, 220);
	lv_line_set_points(line1, line_points, 2); /*Set the points*/

}

void init_phasor(lv_obj_t *parent)
{
	lv_color_t red_color = LV_COLOR_MAKE(255, 0, 0);
	draw_line_relative(parent, -50, 0, 50, 0, red_color, LV_OPA_COVER, LV_BLEND_MODE_NORMAL);

}

at this point i am trying to draw a simple line on a label :sweat_smile: i am calling this function from main, maybe is that wrong?

i also tried to call the function using
“lv_obj_add_event_cb”

i see with the debugger that the code gets executed but the line not drawed

Hi @Alberto_Pesce ,

Can you share with me a complete example which does not work for you so I can test it in the simulator.

Also I see in your draw_line_relative() function you are doing some scaling may be, with center_x + start_x * obj_width / 200, can you explain the purpose of this please? :slight_smile:

Kind Regards,

Pete

I am scaling because i want the line to be sized proportionally to the container, however the code is as simple as you see, so: create a panel that will be the container, and draw a line given coordinates from -100 to 100 of our container, so for example.

at the center the coordinates will be 0,0
at the right top the coordinates will be 100,100,
a the left bottom the coordinates will be -100, -100 and so on

Hi @Alberto_Pesce ,

Okay I get you want to scale the line relative to the parent but do you need to when you are drawing the line on the parent and providing all the coordinates? I think you just need to move the points so they work around a central origin without any transformation like this:

    int16_t line_start_x = center_x + start_x;
	int16_t line_start_y = center_y + start_y;
	int16_t line_end_x = center_x + end_x;
	int16_t line_end_y = center_y + end_y;

What do you think? Or maybe I am missing something :slight_smile:
Also if you can post the simple line on the label example you have mentioned in your previous post so I can see the code fully as I may be mis-understanding something…

Kind Regards,

Pete

Yes you are right, i was doing the wrong calculations because i made some tries with that :sweat_smile:
however, here is the full code:

void prova(lv_event_t * e)
{
	lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e);

	if (dsc->id == LV_PART_MAIN) {
		init_phasor(ui_PhasorDiagramContainer);
	}
}

lv_obj_add_event_cb(ui_PhasorDiagramContainer, prova, LV_EVENT_DRAW_PART_BEGIN, NULL);


void draw_line_relative(lv_obj_t *obj, int16_t start_x, int16_t start_y, int16_t end_x, int16_t end_y, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode) {

	lv_area_t obj_coords;
	lv_obj_get_coords(obj, &obj_coords);

	int16_t obj_width = lv_area_get_width(&obj_coords);
	int16_t obj_height = lv_area_get_height(&obj_coords);

	int16_t center_x = obj_coords.x1 + obj_width / 2;
	int16_t center_y = obj_coords.y1 + obj_height / 2;

	int16_t line_start_x = center_x + start_x * obj_width / 200;
	int16_t line_start_y = center_y + start_y * obj_height / 200;
	int16_t line_end_x = center_x + end_x * obj_width / 200;
	int16_t line_end_y = center_y + end_y * obj_height / 200;

	lv_point_t point1 = { line_start_x, line_start_y };
	lv_point_t point2 = { line_end_x, line_end_y };

	static lv_point_t line_points[2];

	line_points[0] = point1;
	line_points[1] = point2;

	/*Create style*/
	static lv_style_t style_line;
	lv_style_init(&style_line);
	lv_style_set_line_width(&style_line, 1);
	lv_style_set_line_color(&style_line, color);
	lv_style_set_line_rounded(&style_line, false);


	lv_obj_t * line1;
	line1 = lv_line_create(obj);
	lv_obj_add_style(line1, &style_line, LV_PART_MAIN);
	//	lv_obj_set_pos(line1, 20, 220);
	lv_line_set_points(line1, line_points, 2); /*Set the points*/

}

void init_phasor(lv_obj_t *parent)
{
	lv_color_t red_color = LV_COLOR_MAKE(255, 0, 0);
	draw_line_relative(parent, -50, 0, 50, 0, red_color, LV_OPA_COVER, LV_BLEND_MODE_NORMAL);

}

here there is some dummy passing of variables and etc because im doing some tries…

here is the code of the phasor container, generated by Squareline

ui_PhasorDiagramContainer = lv_obj_create(ui_PhasorScreen);
    lv_obj_set_width(ui_PhasorDiagramContainer, lv_pct(52));
    lv_obj_set_height(ui_PhasorDiagramContainer, lv_pct(77));
    lv_obj_set_x(ui_PhasorDiagramContainer, lv_pct(18));
    lv_obj_set_y(ui_PhasorDiagramContainer, lv_pct(10));
    lv_obj_set_align(ui_PhasorDiagramContainer, LV_ALIGN_TOP_MID);
    lv_obj_clear_flag(ui_PhasorDiagramContainer,
                      LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_CLICK_FOCUSABLE | LV_OBJ_FLAG_GESTURE_BUBBLE | LV_OBJ_FLAG_SCROLLABLE |
                      LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_CHAIN);     /// Flags
    lv_obj_set_style_radius(ui_PhasorDiagramContainer, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(ui_PhasorDiagramContainer, lv_color_hex(0x1B1B1B), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_PhasorDiagramContainer, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_PhasorDiagramContainer, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_left(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_right(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_top(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_bottom(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_row(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_column(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);

Hi @Alberto_Pesce ,

Looking through your code there are a few issues here…

  1. It seems you are drawing the line from the LV_EVENT_DRAW_PART_BEGIN callback for the parent this is not really a good idea as this is called many times throughout the life of the application every time the screen is refreshed, this will create a large CPU load, quickly use up much memory and generally cause many problems as the line is repeatedly created, most likely ending up in a crash not long after start-up. You can create the lines during the initialisation process or add them asynchronously from other events like a button click or something… See example below…
    Also in my own experience I have observed, after creating containers, before adding children to them; it’s a good idea to call the lv_obj_update_layout() function which forces the parent to update all its parameters correctly.

  2. The line object needs to keep a copy of its points in a static location for it’s life so I would suggest creating a data type structure to hold the line object and it’s points and pass a newly declared one to the line function each time you want to draw a line.

  3. When you create a line or any object inside another parent object it’s coordinates are relative to the borders of the parent object and not to your full screen so your scaling and coordinate calculations are incorrect as they are relative to the whole screen.

  4. Optionally to save some memory you can use the ```lv_obj_set_style_xxxxx()` functions to set the lines style properties this uses the internal style of the line as opposed to having an extra external style assigned for it. You then don’t need to save the static style separately, if that makes sense… I have included this in the example below also.

Based on the points above here is a full example of how to implement the proposed methodology, hopefully this will work well for you.

static lv_obj_t *ui_PhasorDiagramContainer;

typedef struct _my_line_def {
	lv_obj_t		*line;
	lv_point_t 	points[2];
} my_line_def_t;

// Function to draw a line relative to it's parent object based on the x and y cordinate of (0, 0) being the centre of the object
void draw_line_relative(lv_obj_t *obj, lv_coord_t start_x, lv_coord_t start_y, lv_coord_t end_x, lv_coord_t end_y, lv_coord_t width, lv_color_t color, lv_opa_t opa, my_line_def_t *line_def ) {

	int16_t obj_width = lv_obj_get_width(obj);		// Get the width of the parent object
	int16_t obj_height = lv_obj_get_height(obj);	// Get the height of the parent object

	int16_t center_x = obj_width / 2;				// Find the centre of the parent width
	int16_t center_y = obj_height / 2;				// Find the centre of the parent height

	int16_t line_start_x = center_x + start_x;		// Calculate the points about the centre
	int16_t line_start_y = center_y + start_y;
	int16_t line_end_x = center_x + end_x;
	int16_t line_end_y = center_y + end_y;

	lv_point_t point0 = { line_start_x, line_start_y };
	lv_point_t point1 = { line_end_x, line_end_y };
	line_def->points[0] = point0;
	line_def->points[1] = point1;

	line_def->line = lv_line_create(obj);
	lv_obj_set_style_line_width(line_def->line, width, LV_PART_MAIN);
	lv_obj_set_style_line_color(line_def->line, color, LV_PART_MAIN);
	lv_obj_set_style_line_opa(line_def->line, opa, LV_PART_MAIN);
	lv_obj_set_style_line_rounded(line_def->line, false, LV_PART_MAIN);
	lv_line_set_points(line_def->line, line_def->points, 2);
}

void test( lv_obj_t *parent ) {
	ui_PhasorDiagramContainer = lv_obj_create(parent);
    lv_obj_set_width(ui_PhasorDiagramContainer, lv_pct(52));
    lv_obj_set_height(ui_PhasorDiagramContainer, lv_pct(77));
    lv_obj_set_x(ui_PhasorDiagramContainer, lv_pct(18));
    lv_obj_set_y(ui_PhasorDiagramContainer, lv_pct(10));
    lv_obj_set_align(ui_PhasorDiagramContainer, LV_ALIGN_TOP_MID);
    lv_obj_clear_flag(ui_PhasorDiagramContainer,
                      LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_CLICK_FOCUSABLE | LV_OBJ_FLAG_GESTURE_BUBBLE | LV_OBJ_FLAG_SCROLLABLE |
                      LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_CHAIN);     /// Flags
    lv_obj_set_style_radius(ui_PhasorDiagramContainer, 5, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_color(ui_PhasorDiagramContainer, lv_color_hex(0x1B1B1B), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_PhasorDiagramContainer, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_PhasorDiagramContainer, lv_color_hex(0x00ff00), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_width(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_left(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_right(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_top(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_bottom(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_row(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_pad_column(ui_PhasorDiagramContainer, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    //lv_obj_add_event_cb(ui_PhasorDiagramContainer, prova, LV_EVENT_DRAW_PART_BEGIN, NULL);
    lv_obj_update_layout(ui_PhasorDiagramContainer);
    static my_line_def_t phasor1;
    draw_line_relative(ui_PhasorDiagramContainer, -50, 0, 50, 0, 1, lv_palette_main(LV_PALETTE_RED), LV_OPA_COVER, &phasor1 );
    static my_line_def_t phasor2;
    draw_line_relative(ui_PhasorDiagramContainer, 0, -50, 0, 50, 1, lv_palette_main(LV_PALETTE_GREEN), LV_OPA_COVER,  &phasor2 );
}

test( lv_scr_act() );

Here is the output from the simulator for the above code.

I hope this all makes sense.

Kind Regards,

Pete