Graphical objects

In the Littlev Graphics Library the basic building blocks of a user interface are the objects. For example:

  • Button
  • Label
  • Image
  • List
  • Chart
  • Text area

Click to check all the existing object types.

Object attributes

Basic attributes

The objects have basic attributes which are common independently from their type:

  • Position
  • Size
  • Parent
  • Drag enable
  • Click enable etc.

You can set/get this attributes with lv_obj_set_...and lv_obj_get_... functions. For example:

/*Set basic object attributes*/
lv_obj_set_size(btn1, 100, 50);						/*Button size*/
lv_obj_set_pos(btn1, 20,30);						/*Button position*/
To see all the available functions visit the Base object's documentation.

Specific attributes

The object types have special attributes. For example a slider have:

  • Min. max. values
  • Current value
  • Callback function for new value set
  • Styles

For these attributes every object type have unique API functions. For example for a slider:

/*Set slider specific attributes*/
lv_slider_set_range(slider1, 0, 100);			/*Set min. and max. values*/
lv_slider_set_value(slider1, 40);				/*Set the current value (position)*/
lv_slider_set_action(slider1, my_action);		/*Set a callback function*/

Object's working mechanisms

Parent-child structure

A parent can be considered as the container of its children. Every object has exactly one parent object (except screens) but a parent can have unlimited number of children. There is no limitation for the type of the parent but there typically parent (e.g. button) and typical child (e.g. label) objects.

Screen – the most basic parent

The screen is a special object which has no parent object. Always there is an active screen. By default the library creates and loads one. To get the currently active screen use the lv_scr_act() function.

A screen can be craeted with any object type, for example a basic object or an image to make a wallpaper.

Moving together

If the position of the parent is changed the children will move with the parent. Therefore all positions are relative to the parent. So the (0;0) coordinates means the objects will remain in the top left hand corner of the parent independently from the position of the parent.

Objects are moving togother 1
lv_obj_t * par = lv_obj_create(lv_scr_act(), NULL); 	/*Create a parent object on the current screen*/
lv_obj_set_size(par, 100, 80);		                /*Set the size of the parent*/

lv_obj_t * obj1 = lv_obj_create(par, NULL);	        /*Create an object on the previously created parent object*/
lv_obj_set_pos(obj1, 10, 10);				        /*Set the position of the new object*/

Modify the position of the parent:
Graphical objects are moving togother 2
lv_obj_set_pos(par, 50, 50);		/*Move the parent. The child will move with it.*/

Visibility only on parent

If a child partially or totally out of its parent then the parts outside will not be visible.
A graphical object is visible on its parent
lv_obj_set_x(obj1, -30);		/*Move the child a little bit of the parent*/

Create - delete objects

In the graphics library objects can be created and deleted dynamically in run-time. It means only the currently created objects consume RAM. For example if you need a chart you can create it only when it is required and delete after it is used.

Every objects type has its own create function with an uniformed prototype. It needs two parameters: a pointer the parent object and optionally a pointer to an other object with the same type. If the second parameter is not NULL then this objects will be copied to the new one. To create a screen give NULL as parent. The return value of the create function is a pointer to the created object. Independently from the object type a common variable type lv_obj_t is used. This pointer can be used later to set or get the attributes of the object. The create functions look like this:

lv_obj_t * lv_type_create(lv_obj_t * parent, lv_obj_t * copy);

There is a common delete function for all object types. It deletes the object and all of its children.

void lv_obj_del(lv_obj_t * obj);

You can delete only the children of an object but leave the object itself "alive":

void lv_obj_clean(lv_obj_t * obj);


The earlier created object (and its children) will drawn earlier (nearer to the background). In other words the lastly created object will be on the top among its siblings. It is very important, the order is calculated among the objects on the same level ("siblings").

Layers can be added easily by creating 2 objects (which can be transparent) firstly 'A' and secondly 'B'. 'A' and every object on it will be in the background and can be covered by 'B' and its children.

Creating graphical objects in Littlev Graphics Library
/*Create a screen*/
lv_obj_t * scr = lv_obj_create(NULL, NULL);
lv_scr_load(scr);       						    /*Load the screen*/

/*Create 2 buttons*/
lv_obj_t * btn1 = lv_btn_create(scr, NULL);         /*Create a button on the screen*/
lv_btn_set_fit(btn1, true, true);                   /*Enable to automatically set the size according to the content*/
lv_obj_set_pos(btn1, 60, 40);              		    /*Set the position of the button*/

lv_obj_t * btn2 = lv_btn_create(scr, btn1);         /*Copy the first button*/
lv_obj_set_pos(btn2, 180, 80);                 	    /*Set the position of the button*/

/*Add labels to the buttons*/
lv_obj_t * label1 = lv_label_create(btn1, NULL);	/*Create a label on the first button*/
lv_label_set_text(label1, "Button 1");          	/*Set the text of the label*/

lv_obj_t * label2 = lv_label_create(btn2, NULL);  	/*Create a label on the second button*/
lv_label_set_text(label2, "Button 2");            	/*Set the text of the label*/

/*Delete the second label*/


To set the appearance of the objects styles can be used. A style is a structure variable with attributes like colors, paddings, visibility and others. There is common style type: lv_style_t.

By setting the fields of an lv_style_t structure you can influence the appearance of the objects using that style.

The objects store only a pointer to a style so the style can not be a local variable which is destroyed after the function exists. You should use static, global or dynamically allocated variables.

Style properties

A style have 5 main parts: common, body, text, image and line. An object will use that fields which are relevant for it. For example Lines don't care about the letter_space. To see which fields are used by an object type see their documentation.

The fields of a style structure are the followings:

Common properties
  • glass 1: Do not inherit this style (see below)
Body style properties
Used by the rectangle-like objects
  • body.empty Do not fill the rectangle (just draw border and/or shadow)
  • body.main_color Main color (top color)
  • body.grad_color Gradient color (bottom color)
  • body.radius Corner radius
  • body.opa Opacity (0..255 or LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20 ... LV_OPA_COVER)
  • body.border.color Border color
  • body.border.width Border width
  • body.border.part Border parts (LV_BORDER_LEFT/RIGHT/TOP/BOTTOM/FULL or 'OR'ed values)
  • body.border.opa Border opacity
  • body.shadow.color Shadow color
  • body.shadow.width Shadow width
  • body.shadow.type Shadow type (LV_SHADOW_BOTTOM or LV_SHADOW_FULL)
  • body.padding.hor Horizontal padding
  • body.padding.ver Vertical padding
  • body.padding.inner Inner padding
Text style properties
Used by the objects which show texts
  • text.color Text color
  • text.font Pointer to a font
  • text.opa Text opacity (0..255 or LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20 ... LV_OPA_COVER)
  • text.letter_space Letter space
  • text.line_space Line space
Image style properties
Used by image-like objects or icons on objects
  • image.color Color for image re-coloring
  • image.intense Re-color intensity (0..255 or LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20 ... LV_OPA_COVER)
  • image.opa Image opacity (0..255 or LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20 ... LV_OPA_COVER)
Line style properties
Used by objects containing lines or line-like elements
  • line.color Line color
  • line.width Line width
  • line.opa Line opacity (0..255 or LV_OPA_TRANSP, LV_OPA_10, LV_OPA_20 ... LV_OPA_COVER)

Using styles

Every object type have a unique function to set its style or styles.

If the object has only one style - like a label - the lv_label_set_style(label1, &style) function can be used to set a new style.

If the object has more styles (like a button have 5 styles for each state) lv_btn_set_style(obj, LV_BTN_STYLE_..., &rel_style) function can be used to set a new style.

The styles and the style properties used by an object type are described in their documentation.

If you modify a style which is used by one or more objects then the objects have to be notified about the style is changed. You have two options to do that:

void lv_obj_refresh_style(lv_obj_t * obj);		/*Notify an object about its style is modified*/
void lv_obj_report_style_mod(void * style);		/*Notify all object if a style is modified.(NULL to notify all objects)*/

If the style of an object is NULL then its style will be inherited from its parent's style. It makes easier to create consistent design. Don't forget a style describes a lot of properties at the same time. So for example if you set a button's style and create a label on it with NULL style then the label will be rendered according to the buttons styles. In other words the button makes sure its children will look well on it.

Setting the glass style property will prevent inheriting that style. You should use it if the style is transparent so that its children use colors and others from its parent.

Built-in styles

There are several built-in styles in the library:

Built in styles in Littlev Embedded Graphics Library

As you can see there is a style for screens, for buttons, plain and pretty styles and transparent styles as well. The lv_style_transp, lv_style_transp_fit and lv_style_transp_tight differ only in paddings: for lv_style_transp_tight all padings are zero, for lv_style_transp_fit only hor and ver paddings are zero.

The built in styles are global lv_style_t variables so you can use them like: lv_btn_set_style(obj, LV_BTN_STYLE_REL, &lv_style_btn_rel)

You can modify the built-in styles or you can create new styles. When creating new styles it is recommended to firstly copy a built-in style to be sure all fields are initialized with a proper value. The lv_style_copy(&dest_style, &src_style) can be used to copy styles.

Style animations

You can animate styles using lv_style_anim_create(&anim). Before calling this function you have to initialize an lv_style_anim_t variable. The animation will fade a style_1 to style_2

lv_style_anim_t a;    /*Will be copied, can be local variable*/
a.style_anim = & style_to_anim;     /*Pointer to style to animate*/
a.style_start = & style_1;          /*Pointer to the initial style (only pointer saved) */
a.style_end = & style_2;            /*Pointer to the target style (only pointer saved) */
a.act_time = 0;                     /*Set negative to make a delay*/
a.time = 1000;                      /*Time of animation in milliseconds*/
a.playback = 0;                     /*1: play the animation backward too*/
a.playback_pause = 0;               /*Wait before playback [ms]*/
a.repeat = 0;                       /*1: repeat the animation*/
a.repeat_pause = 0;                 /*Wait before repeat [ms]*/
a.end_cb = NULL;                    /*Call this function when the animation ready*/

Style example

The example below demonstrates the above described style usage.

Styles usage example in Littlev Embedded Graphics Library
/*Create a style*/
static lv_style_t style1;
lv_style_copy(&style1, &lv_style_plain);    /*Copy a built-in style to initialize the new style*/
style1.body.main_color = LV_COLOR_WHITE;
style1.body.grad_color = LV_COLOR_BLUE;
style1.body.radius = 10;
style1.body.border.color = LV_COLOR_GRAY;
style1.body.border.width = 2;
style1.body.border.opa = LV_OPA_50;
style1.body.padding.hor = 5;            /*Horizontal padding, used by the bar indicator below*/
style1.body.padding.ver = 5;            /*Vertical padding, used by the bar indicator below*/
style1.text.color = LV_COLOR_RED;

/*Create a simple object*/
lv_obj_t *obj1 = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(obj1, &style1);                        /*Apply the created style*/
lv_obj_set_pos(obj1, 20, 20);                           /*Set the position*/

/*Create a label on the object. The label's style is NULL by default*/
lv_obj_t *label = lv_label_create(obj1, NULL);
lv_obj_align(label, NULL, LV_ALIGN_CENTER, 0, 0);       /*Align the label to the middle*/

/*Create a bar*/
lv_obj_t *bar1 = lv_bar_create(lv_scr_act(), NULL);
lv_bar_set_style(bar1, LV_BAR_STYLE_INDIC, &style1);    /*Modify the indicator's style*/
lv_bar_set_value(bar1, 70);                             /*Set the bar's value*/


To create styles for your GUI is challenging because you need a deeper understanding of the library and you need to have some designer skills. In addition it takes a lot of time to create so much styles.

To speed up the design part themes are introduced. A theme is a style collection which contains the required styles for every object type. For example 5 styles for buttons to describe their 5 possible states.
Check the Existing themes.

To be more specific a theme is a structure variable which contains a lot of lv_style_t * fields. For buttons:

theme.btn.rel       /*Released button style*/        /*Pressed button style*/
theme.btn.tgl_rel   /*Toggled released button style*/
theme.btn.tgl_pr    /*Toggled pressed button style*/
theme.btn.ina       /*Inactive button style*/

A theme can initialized by: lv_theme_xxx_init(hue, font). Where xxx is the name of the theme, hue is a hue value from HSV color space (0..360) and font is the font applied in the theme (NULL to use the LV_FONT_DEFAULT default font)

When a theme is initialized its styles can be used like this:

Theme usage example in Littlev Embedded Graphics Library
/*Create a default slider*/
lv_obj_t *slider = lv_slider_create(lv_scr_act(), NULL);
lv_slider_set_value(slider, 70);
lv_obj_set_pos(slider, 10, 10);

/*Initialize the alien theme with a redish hue*/
lv_theme_t *th = lv_theme_alien_init(10, NULL);

/*Create a new slider and apply the themes styles*/
slider = lv_slider_create(lv_scr_act(), NULL);
lv_slider_set_value(slider, 70);
lv_obj_set_pos(slider, 10, 50);
lv_slider_set_style(slider, LV_SLIDER_STYLE_BG, th->;
lv_slider_set_style(slider, LV_SLIDER_STYLE_INDIC, th->slider.indic);
lv_slider_set_style(slider, LV_SLIDER_STYLE_KNOB, th->slider.knob);

You can force the library to apply the styles from a theme when you create new objects. To do this use lv_theme_set_current(th);


The color module handles all color related functions like: changing color depth, creating colors from hex code, conversation between color depths, mixing colors etc.

The following variable types are defined by the color module:

  • lv_color1_t Store monochrome color. For compatibility it also has R,G,B fields but they are always the same (1 byte)
  • lv_color8_t A structure to store R (3 bit),G (3 bit),B (2 bit) components for 8 bit colors (1 byte)
  • lv_color16_t A structure to store R (5 bit),G (6 bit),B (5 bit) components for 16 bit colors (2 byte)
  • lv_color24_t A structure to store R (8 bit),G (8 bit), B (8 bit) components for 24 bit colors (4 byte)
  • lv_color_t Equal to color1/8/16/24_t according to color depth settings
  • lv_color_int_t uint8_t, uint16_t or uint32_t according to color depth setting. Used to build color arrays from plain numbers.
  • lv_opa_t A simple uint8_t type to describe opacity.

The lv_color_t, lv_color1_t lv_color8_t, lv_color16_t and lv_color24_t types have got four fields:

  • red red channel
  • green green channel
  • blue blue channel
  • full red + green + blue as one number

You can set the current color depth in lv_conf.h by setting the LV_COLOR_DEPTH define to 1 (monochrome), 8, 16 or 24.

You can convert a color from the current color depth to an other. The converter functions return with a number so you have to use the full field:

lv_color_t c;   = 0x38; = 0x70;  = 0xCC;

lv_color1_t c1;
c1.full = lv_color_to1(c);		/*Return 1 for light colors, 0 for dark colors*/

lv_color8_t c8;
c8.full = lv_color_to8(c);		/*Give a 8 bit number with the converted color*/ 

lv_color16_t c16;
c16.full = lv_color_to16(c); 	/*Give a 16 bit number with the converted color*/

lv_color24_t c24;
c24.full = lv_color_to24(c);	/*Give a 32 bit number with the converted color*/

You can create a color with the current color depth using the LV_COLOR_MAKE macro. It takes 3 arguments (red, green, blue) as 8 bit numbers. For example to create light red color: my_color = COLOR_MAKE(0xFF, 0x80, 0x80)

Colors can be created from HEX codes too: my_color = LV_COLOR_HEX(0xFF8080) or my_color = LV_COLOR_HEX3(0xF88)

Mixing two colors is possible with mixed_color = lv_color_mix(color1, color2, ratio). Ration can be 0..255. 0 results fully color2, 255 result fully color1.

To describe opacity the lv_opa_t type is created as wrapper to uint8_t. Some defines are also introduced:

  • LV_OPA_TRANSP Value: 0, means the opacity makes the color fully transparent
  • LV_OPA_10 Value: 25, means the color covers only a little
  • LV_OPA_20 ... OPA_80 come logically
  • LV_OPA_90 Value: 229, means the color near fully covers
  • LV_OPA_COVER Value: 255, means the color fully covers

You can also use the LV_OPA_* defines in lv_color_mix() as ratio.

The color module defines the most basic colors:


In LittlevGL fonts are bitmaps and other descriptors to store the images of the letters (glyph) and some additional information. A font is stored in a lv_font_t variable and can be set it in style's text.font field.

The fonts have a bpp (Bit-Per-Pixel) propertiy. It shows how much bit is used to describe a pixel in the font. The value stored for a pixel determines the pixel's opacity. This way the image of the letters (especially on the edges) can be smooth and even. The possible bpp values are 1, 2, 4 and 8 (higher value means better quaility). The bpp also affescts the required memory size to store the font. E.g. bpp = 4 makes the font's memory size 4 times greater compared to bpp = 1.

Built-in fonts

There are several built-in fonts which can be enabled in lv_conf.h by USE_LV_FONT_... defines. There are built-in fonts in different sizes:

  • 10 px
  • 20 px
  • 30 px
  • 40 px
You can enbale the fonts with 1, 2, 4 or 8 values to set its bpp (e.g. USE_LV_FONT_DEJAVU_20 4).

The built-in fonts exist with multiply character-sets in each size:

  • ASCII (Unicode 32..126)
  • Latin supplement (Unicode 160..255)
  • Cyrillic (Unicode 1024..1279)

The built-in fonts uses the Dejavu font.

The built-in fonts are global variables with names like:

  • lv_font_dejavu_20 (20 px ASCII font)
  • lv_font_dejavu_20_latin_sup (20 px Latin supplement font)
  • lv_font_dejavu_20_cyrillic (20 px Cyrillic font)

Unicode support

The LittlevGL supports Unicode letter from UTF-8 coded characters. You need to configure your editor to save your code/text as UTF-8 (usually this the default) and enable LV_TXT_UTF8 in lv_conf.h. Without enabled LV_TXT_UTF8 only ASCII fonts and symbols can be used (see the symbols below)

After it the texts will be decoded to determine the Unicode values. To display the letters your font needs to contain the image (glyph) of the characters. As the built-in fonts show the fonts are stored modularly but you can assign more fonts to create a larger character-set. To do this choose a base font (typically the ASCII font) and add the extensions to it: lv_font_add(child, parent). Only fonts with same height can be assigned.

The built-in fonts are already added to the same sized ASCII font. For example if USE_LV_FONT_DEJAVU_20 and USE_LV_FONT_DEJAVU_20_LATIN_SUP are enabled in lv_conf.h then the "abcÁÖÜ" text can be rendered when using lv_font_dejavu_20

Symbol fonts

The symbol fonts are special fonts which contain symbols instead of letters. There are built-in symbol fonts as well and they are also assigned to the ASCII font with the same size. In a text a symbol can be referenced like SYMBOL_LEFT, SYMBOL_RIGHT etc. You can mix these symbol names with strings: lv_label_set_text(label1, "Right "SYMBOL_RIGHT);

The symbols can be used without Unicode support as well. (LV_TXT_UTF8 0)

The list aboce shows the existing symbols:

Basic symbols

Add new font

If you want to add new fonts to the library you can use the Online Font Converter Tool. It can create a C array from a TTF file which can be copied copy to your project. You can specify the height, the range of characters and the bpp. Optionally you can enumerate the characters to include only them into the final font. To use the gnerated font declare it with LV_FONT_DECLAER(my_font_name). After that the font can be used as the built-in fonts.

Font example

Fonts example
/*Create a new style for the label*/
static lv_style_t style;
lv_style_copy(&style, &lv_style_plain);
style.text.color = LV_COLOR_BLUE;
style.text.font = &lv_font_dejavu_40;   /*Unicode and symbol fonts already assigned by the library*/

lv_obj_t *label;

/*Use ASCII and Unicode letters*/
label = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(label, 20, 20);
lv_label_set_style(label, &style);
lv_label_set_text(label, "aeuois\n"

/*Mix text and symbols*/
label = lv_label_create(lv_scr_act(), NULL);
lv_obj_set_pos(label, 20, 100);
lv_label_set_style(label, &style);
lv_label_set_text(label, "Right "SYMBOL_RIGHT);


You can automatically change the value (animate) of a variable between a start and an end value using an animator function with void func(void * var, int32_t value) prototype. The animation will happen by periodical calling of the animator function with the the corresponding value parameter.

To create an animation you have to initializes an lv_anim_t variable (there is a template in lv_anim.h):

lv_anim_t a;								
a.var = button1;							 /*Variable to animate*/						
a.start = 100;								 /*Start value*/
a.end = 300;								 /*End value*/
a.fp = (anim_fp_t)lv_obj_set_height;		 /*Function to be used to animate*/
a.path = lv_anim_path_linear;                /*Path of animation*/
a.end_cb = NULL; 						 	 /*Callback when the animation is ready*/
a.act_time = 0;								 /*Set < 0 to make a delay [ms]*/
a.time = 200;								 /*Animation length [ms]*/
a.playback = 0;								 /*1: animate in reverse direction too when the normal is ready*/
a.playback_pause = 0;						 /*Wait before palyback [ms]*/
a.repeat = 0;								 /*1: Repeat the animation (with or without playback)*/
a.repeat_pause = 0;							 /*Wait before repeate [ms]*/

lv_anim_create(&a);                          /*Start the animation*/

The anim_create(&a) will register the animation and immediately applies the start value regardless to the set delay.

You can determinate the path of animation. In most simple case it is linear which means the current value between start and end is changed linearly. A path is function which calculates the next value to set based on the current state of the animation. Currently there are two built in paths:

  • lv_anim_path_linear linear animation
  • lv_anim_path_step change in one step at the end

By default you can set the animation time. But in some cases the animation speed is more practical. The lv_anim_speed_to_time(speed, start, end) function calculates the required time in milliseconds to reach the end value from a start value with the given speed. The speed is interpreted in unit/sec dimension. For example anim_speed_to_time(20, 0, 100) will give 5000 milliseconds

You can apply multiple different animations on the same variable at the same time. (For example animate the x and y coordinates with lv_obj_set_x end lv_obj_set_y). But only one animation can exist with a given variable and function pair. Therefore the lv_anim_create() function will delete the already existing variable-function animations.

You can delete an animation by lv_anim_del(var, func) with providing the animated variable and its animator function.

Input devices

To iteract with the created object Input devices are required. For example Touch pad, Mouse, Keyboard or even an Encoder. To learn how to add an input device read the Porting guide.

When you register an input device driver the library adds some extra information to it to describe the state of the input device in more detail. When a user action (e.g. a button press) happens and an action (callback) function is triggered always there is an input device which triggered that action. You can get this input device with lv_indev_t *indev = lv_indev_get_act(). It might be important when you need to know some special information about the input device like the currently pressed point, or dragging an object or not etc.

The input devices have a very simple API:

/*Get the last point on a display input*/
void lv_indev_get_point(lv_indev_t * indev, point_t * point);

/*Check if there is dragging on input device or not */
bool lv_indev_is_dragging(lv_indev_t * indev);

/*Get the vector of dragging on a input device*/
void lv_indev_get_vect(lv_indev_t * indev, point_t * point);

/*Do nothing until the next release*/
void lv_indev_wait_release(lv_indev_t * indev);

/*Do nothing until the next release*/
void lv_indev_wait_release(lv_indev_t * indev);

/*Reset one or all (use NULL) input devices*/
void lv_indev_reset(lv_indev_t * indev);

/*Reset the long pressed state of an input device*/
void lv_indev_reset_lpr(lv_indev_t * indev);

/*Set a cursor for a pointer input device*/
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj);

/*Set a destination group for a keypad input device*/
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group);

Touchad-less navigation

The objects can be grouped in order to easily control them without touch pad or mouse. It allows you to use

  • Keyboard or keypad
  • Hardware buttons
  • Encoder

to navigate among objects.

Littlev graphics library encoder control (no touchpad)

Firstly you have to create an object group with lv_groupt_t *group = lv_group_create() and add objects to it with lv_group_add_obj(group, obj). In a group always there is a focused object. All the button press will be "sent" to the currently focused obejct.

To navigate among the objects in a group (change the focused obejct) and iteract with them an LV_INDEV_TYPE_KEYPAD typed input device is required. In its read function you can tell the library which key is pressed or released. To learn how to add an input device read the Porting guide.

Besides you have to assign the group to the input device with lv_indev_set_group(indev, group)

There are some special control characters which can be used in the read function:

  • LV_GROUP_KEY_NEXT Focus on the next obejct
  • LV_GROUP_KEY_PREV Focus on the previous object
  • LV_GROUP_KEY_UP Increment the value, move up or click the focused object (move up means e.g. select an upper list element)
  • LV_GROUP_KEY_DOWN Decrement the value or move down on the focused object (move down means e.g. select a lower list element)
  • LV_GROUP_KEY_RIGHT Increment the value or click the focused object
  • LV_GROUP_KEY_LEFT Decrement the value of the focused object
  • LV_GROUP_KEY_ENTER Click the focused obejct or a selected element (e.g. list element)
  • LV_GROUP_KEY_ESC Close the object (e.g. drop down list)

In some cases (e.g. when a pop up window appears) it is useful to freeze the focus on an object. It means the LV_GROUP_KEY_NEXT/PREV will be ignored. You can do it with lv_group_focus_freeze(group, true).

The style of the object in focus is modified by a function. By default it make the object's colors orangish but you can also specify your own style updater function in each group with void lv_group_set_style_mod_cb(group, style_mod_cb). The style_mod_cb waits an lv_style_t * parameter which is a copy of the focused object's style. In the callback you can mix some colors to the current ones, and modify parameters but is not permitted to set attributes which modifiy the size (like letter_space, padding etc.)

Drawing and rendering

In LittlevGL you can think in graphical objects and don't care about how the drawing happens. You can set the size, position or any attribute of the object an the library will refresh the old (invalid) areas and redraw the new ones. However you should know the basic drawing methods to know which one you should choose.

Buffered and unbuffered drawing

Unbuffered drawing

The unbuffered drawing puts the pixels directly to the display (frame buffer). Therefore during the drawing process some flickering might be visible because firstly the background has to be drawn and then the objects on it. For this reason this type is not suitable when scrolling, dragging and animations are used. On the other hand it has the smallest memory footprint because no extra graphics buffer is required.
To use unbuffered drawing set LV_VDB_SIZE to 0 in lv_conf.h and register the disp_map and disp_fillfunctions. Here you can learn more about Porting

Buffered drawing

The buffered drawing is similar to double buffering when two screen sized buffers are used (one for rendering and an other to display the last ready frame). However LittlevGL's buffered drawing algorithm uses only one frame buffer and a small graphical buffer called Virtual Display Buffer (VDB). For VDB size ~1/10 screen size is typically enough. For a 320 × 240 screen with 16 bit colors it means only 15 kB extra RAM.
With buffered drawing there is no flickering because the image is created firstly in the memory (VDB), therefore scrolling, dragging and animations can be used. In addition it enables the use of other graphical effects like anti-aliasing, transparency (opacity) and shadows.
To use buffered drawing set LV_VDB_SIZE to > LV_HOR_RES in lv_conf.h and register a disp_flush function.

In buffered mode you can use double VDB to parallelly execute rendering into one VDB and coping pixels to your frame buffer from an other. The copy should use DMA or other hardware acceleration to work in the background to let the CPU to do other things. In lv_conf.h the LV_VDB_DOUBLE 1 enables this feature.

Buffered vs Unbuffered drawing

Keep in mind it's not sure that the unbuffered drawing is faster. During the rendering process a pixel is overwritten multiple times (e.g. background, button, text are above each other). This way in unbuffered mode the library needs to access the external memory or display controller several times which is slower then writing/reading the internal RAM.

The following table summarizes the differences between the two drawing methods:

Unbuffered drawing Buffered drawing
Memory usage No extra >~1/10 screen
Quality Flickering Flawless
Antialaissing Not supported Supported
Transparency Not supported Supperted
Shadows Not supported Supperted


In lv_conf.h you can enable the anti-aliasing with LV_ANTIALIAS 1. The anti-aliasing is supported only in buffered mode (LV_VDB_SIZE > LV_HOR_RES).

The antia-laising algorytihm puts some translucent pixels (pixels with opacity) to make lines and curves (including corners with radius) smooth and even. Because it only puts some extra pixels anti-alaising requires only a few extra computational power(~1,1x extra time compared to not anti-alaised configuration)

As described in Font section the fonts can be anti-alaised by using a different font with higher bpp (Bit-Per-Pixel). This way the pixels of a font can be not only 0 or 1 but can be translucent. The supported bpp-s are 1, 2, 4 and 8. Keep in mind a font with higher bpp requires more ROM.

Continue with the documentation of the object types Object Types

LittlevGL - Open-source Embedded GUI Library

LittlevGL is a free and open-source graphics library providing everything you need to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint.

If you like LittlevGL, please
support its deveopment!

The founder of Littlev Graphics Library (LittlevGL) and related software modules is:
Gábor Kiss-Vámosi
All Rights Reserved ©  2018 Hungary