LVGL
LVGL
LVGL community
1 Introduction 2
1.1 Key features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Repository layout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.5 Release policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.6 FAQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2 Examples 8
2.1 Get started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.2 Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.4 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.5 Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.6 Scrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.7 Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
4 Porting 254
4.1 Set up a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
4.2 Display interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
4.3 Input device interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
4.4 Tick interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
4.5 Timer Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
4.6 Sleep management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
4.7 Operating system and interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
4.8 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
4.9 Add custom GPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
5 Overview 288
5.1 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
5.2 Positions, sizes, and layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
5.3 Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
5.4 Style properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
5.5 Scroll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
i
5.6 Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
5.7 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
5.8 Input devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
5.9 Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
5.10 Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
5.11 Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
5.12 Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
5.13 File system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
5.14 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
5.15 Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
5.16 Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466
5.17 Renderers and GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
5.18 New widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
6 Widgets 474
6.1 Base object (lv_obj) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
6.2 Core widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
6.3 Extra widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
7 Layouts 789
7.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 789
7.2 Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802
9 Others 843
9.1 Snapshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
9.2 Monkey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
9.3 Grid navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851
9.4 Fragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
9.5 Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 869
9.6 Image font (imgfont) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
9.7 Pinyin IME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
10 Contributing 890
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 890
10.2 Pull request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891
10.3 Developer Certification of Origin (DCO) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 893
10.4 Ways to contribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894
11 Changelog 898
11.1 v8.3.11 6 December 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898
11.2 v8.3.10 20 September 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 899
11.3 v8.3.9 6 August 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 900
11.4 v8.3.8 5 July 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 901
ii
11.5 v8.3.7 3 May 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 902
11.6 v8.3.6 3 April 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 903
11.7 v8.3.5 7 February 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
11.8 v8.3.4 15 December 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
11.9 v8.3.3 06 October 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905
11.10 v8.3.2 27 September 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 905
11.11 v8.3.1 25 July 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906
11.12 v8.3.0 6 July 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 907
11.13 v8.2.0 31 January 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 915
11.14 v8.1.0 10 November 2021 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 922
11.15 v8.0.2 (16.07.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 939
11.16 v8.0.1 (14.06.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 940
11.17 v8.0.0 (01.06.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 942
11.18 v7.11.0 (16.03.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
11.19 v7.10.1 (16.02.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 944
11.20 v7.10.0 (02.02.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945
11.21 v7.9.1 (19.01.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945
11.22 v7.9.0 (05.01.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 945
11.23 v7.8.1 (15.12.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
11.24 v7.8.0 (01.12.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
11.25 v7.7.2 (17.11.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
11.26 v7.7.1 (03.11.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
11.27 v7.7.0 (20.10.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 947
11.28 v7.6.1 (06.10.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948
11.29 v7.6.0 (22.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 948
11.30 v7.5.0 (15.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949
11.31 v7.4.0 (01.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 949
11.32 v7.3.1 (18.08.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950
11.33 v7.3.0 (04.08.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 950
11.34 v7.2.0 (21.07.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 951
11.35 v7.1.0 (07.07.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 952
11.36 v7.0.2 (16.06.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
11.37 v7.0.1 (01.06.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 953
11.38 v7.0.0 (18.05.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 954
12 Roadmap 958
12.1 v8.2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 958
12.2 Ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 958
Index 959
iii
LVGL Documentation 8.3
CONTENTS 1
CHAPTER
ONE
INTRODUCTION
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need
to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.
• Powerful building blocks such as buttons, charts, lists, sliders, images, etc.
• Advanced graphics with animations, anti-aliasing, opacity, smooth scrolling
• Various input devices such as touchpad, mouse, keyboard, encoder, etc.
• Multi-language support with UTF-8 encoding
• Multi-display support, i.e. use multiple TFT, monochrome displays simultaneously
• Fully customizable graphic elements with CSS-like styles
• Hardware independent: use with any microcontroller or display
• Scalable: able to operate with little memory (64 kB Flash, 16 kB RAM)
• OS, external memory and GPU are supported but not required
• Single frame buffer operation even with advanced graphic effects
• Written in C for maximal compatibility (C++ compatible)
• Simulator to start embedded GUI design on a PC without embedded hardware
• Binding to MicroPython
• Tutorials, examples, themes for rapid GUI design
• Documentation is available online and as PDF
• Free and open-source under MIT license
2
LVGL Documentation 8.3
1.2 Requirements
Basically, every modern controller which is able to drive a display is suitable to run LVGL. The minimal requirements
are:
1.3 License
The LVGL project (including all repositories) is licensed under MIT license. This means you can use it even in commercial
projects.
It's not mandatory, but we highly appreciate it if you write a few words about your project in the My projects category of
the forum or a private message to lvgl.io.
Although you can get LVGL for free there is a massive amount of work behind it. It's created by a group of volunteers
who made it available for you in their free time.
To make the LVGL project sustainable, please consider contributing to the project. You can choose from many different
ways of contributing such as simply writing a tweet about you using LVGL, fixing bugs, translating the documentation, or
even becoming a maintainer.
1.2. Requirements 3
LVGL Documentation 8.3
1.5.2 Branches
1.5.3 Changelog
Before v8 the last minor release of each major series was supported for 1 year. Starting from v8, every minor release is
supported for 1 year.
1.6 FAQ
Every MCU which is capable of driving a display via parallel port, SPI, RGB interface or anything else and fulfills the
Requirements is supported by LVGL.
This includes:
• "Common" MCUs like STM32F, STM32H, NXP Kinetis, LPC, iMX, dsPIC33, PIC32, SWM341 etc.
• Bluetooth, GSM, Wi-Fi modules like Nordic NRF and Espressif ESP32
• Linux with frame buffer device such as /dev/fb0. This includes Single-board computers like the Raspberry Pi
• Anything else with a strong enough MCU and a peripheral to drive a display
1.6. FAQ 4
LVGL Documentation 8.3
LVGL needs just one simple driver function to copy an array of pixels into a given area of the display. If you can do this
with your display then you can use it with LVGL.
Some examples of the supported display types:
• TFTs with 16 or 32 bit color depth
• Monitors with an HDMI port
• Small monochrome displays
• Gray-scale displays
• even LED matrices
• or any other display where you can control the color/state of the pixels
See the Porting section to learn more.
1.6.4 LVGL doesn't start, randomly crashes or nothing is drawn on the display.
What can be the problem?
Be sure you are calling lv_tick_inc(x) in an interrupt and lv_timer_handler() in your main while(1).
Learn more in the Tick and Timer handler sections.
1.6.6 Why is the display driver called only once? Only the upper part of the display
is refreshed.
Be sure you are calling lv_disp_flush_ready(drv) at the end of your "display flush callback".
1.6. FAQ 5
LVGL Documentation 8.3
Probably there a bug in your display driver. Try the following code without using LVGL. You should see a square with
red-blue gradient.
#define BUF_W 20
#define BUF_H 10
lv_area_t a;
a.x1 = 10;
a.y1 = 40;
a.x2 = a.x1 + BUF_W - 1;
a.y2 = a.y1 + BUF_H - 1;
my_flush_cb(NULL, &a, buf);
Probably LVGL's color format is not compatible with your display's color format. Check LV_COLOR_DEPTH in
lv_conf.h.
If you are using 16-bit colors with SPI (or another byte-oriented interface) you probably need to set
LV_COLOR_16_SWAP 1 in lv_conf.h. It swaps the upper and lower bytes of the pixels.
1.6. FAQ 6
LVGL Documentation 8.3
You can disable all the unused features (such as animations, file system, GPU etc.) and object types in lv_conf.h.
If you are using GCC/CLANG you can add -fdata-sections -ffunction-sections compiler flags and
--gc-sections linker flag to remove unused functions and variables from the final binary. If possible, add the
-flto compiler flag to enable link-time-optimisation together with -Os for GCC or -Oz for CLANG.
To work with an operating system where tasks can interrupt each other (preemptively) you should protect LVGL related
function calls with a mutex. See the Operating system and interrupts section to learn more.
1.6. FAQ 7
CHAPTER
TWO
EXAMPLES
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN
/*Get the first child of the button which is the label and change its text*/
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
/**
* Create a button with a label and react on click event.
*/
void lv_example_get_started_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current␣
,→screen*/
#endif
8
LVGL Documentation 8.3
class CounterBtn():
def __init__(self):
self.cnt = 0
#
# Create a button with a label and react on click event.
#
def btn_event_cb(self,evt):
code = evt.get_code()
btn = evt.get_target()
if code == lv.EVENT.CLICKED:
self.cnt += 1
# Get the first child of the button which is the label and change its text
label = btn.get_child(0)
label.set_text("Button: " + str(self.cnt))
counterBtn = CounterBtn()
#include "../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
{
LV_UNUSED(dsc);
return lv_color_darken(color, opa);
}
lv_style_set_border_color(&style_btn, lv_color_black());
lv_style_set_border_opa(&style_btn, LV_OPA_20);
lv_style_set_border_width(&style_btn, 2);
lv_style_set_text_color(&style_btn, lv_color_black());
/**
* Create styles from scratch for buttons.
*/
void lv_example_get_started_2(void)
{
/*Initialize the style*/
style_init();
label = lv_label_create(btn2);
lv_label_set_text(label, "Button 2");
lv_obj_center(label);
}
#endif
#
# Create styles from scratch for buttons.
#
style_btn = lv.style_t()
style_btn_red = lv.style_t()
style_btn_pressed = lv.style_t()
# Add a border
style_btn.set_border_color(lv.color_white())
style_btn.set_border_opa(lv.OPA._70)
style_btn.set_border_width(2)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SLIDER
/**
* Create a slider and write its value on a label.
*/
void lv_example_get_started_3(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_set_width(slider, 200); /*Set the width*/
lv_obj_center(slider); /*Align to the center of␣
,→the parent (screen)*/
#endif
def slider_event_cb(evt):
slider = evt.get_target()
#
# Create a slider and write its value on a label.
#
2.2 Styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using the Size, Position and Padding style properties
*/
void lv_example_style_1(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
/*Make a gradient*/
lv_style_set_width(&style, 150);
lv_style_set_height(&style, LV_SIZE_CONTENT);
lv_style_set_pad_ver(&style, 20);
lv_style_set_pad_left(&style, 5);
lv_style_set_x(&style, lv_pct(50));
lv_style_set_y(&style, 80);
2.2. Styles 13
LVGL Documentation 8.3
#endif
#
# Using the Size, Position and Padding style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
# Make a gradient
style.set_width(150)
style.set_height(lv.SIZE.CONTENT)
style.set_pad_ver(20)
style.set_pad_left(5)
style.set_x(lv.pct(50))
style.set_y(80)
label = lv.label(obj)
label.set_text("Hello")
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the background style properties
*/
void lv_example_style_2(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
/*Make a gradient*/
lv_style_set_bg_opa(&style, LV_OPA_COVER);
static lv_grad_dsc_t grad;
grad.dir = LV_GRAD_DIR_VER;
grad.stops_count = 2;
grad.stops[0].color = lv_palette_lighten(LV_PALETTE_GREY, 1);
grad.stops[1].color = lv_palette_main(LV_PALETTE_BLUE);
(continues on next page)
2.2. Styles 14
LVGL Documentation 8.3
lv_style_set_bg_grad(&style, &grad);
#endif
#
# Using the background style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
# Make a gradient
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 1))
style.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_bg_grad_dir(lv.GRAD_DIR.VER)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the border style properties
*/
void lv_example_style_3(void)
{
static lv_style_t style;
lv_style_init(&style);
2.2. Styles 15
LVGL Documentation 8.3
#endif
#
# Using the border style properties
#
style = lv.style_t()
style.init()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the outline style properties
*/
void lv_example_style_4(void)
{
static lv_style_t style;
lv_style_init(&style);
2.2. Styles 16
LVGL Documentation 8.3
/*Add outline*/
lv_style_set_outline_width(&style, 2);
lv_style_set_outline_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_outline_pad(&style, 8);
#endif
#
# Using the outline style properties
#
style = lv.style_t()
style.init()
# Add outline
style.set_outline_width(2)
style.set_outline_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_outline_pad(8)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the Shadow style properties
*/
void lv_example_style_5(void)
{
static lv_style_t style;
lv_style_init(&style);
2.2. Styles 17
LVGL Documentation 8.3
/*Add a shadow*/
lv_style_set_shadow_width(&style, 55);
lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_BLUE));
// lv_style_set_shadow_ofs_x(&style, 10);
// lv_style_set_shadow_ofs_y(&style, 20);
#endif
#
# Using the Shadow style properties
#
style = lv.style_t()
style.init()
# Add a shadow
style.set_shadow_width(8)
style.set_shadow_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_shadow_ofs_x(10)
style.set_shadow_ofs_y(20)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using the Image style properties
*/
void lv_example_style_6(void)
{
static lv_style_t style;
lv_style_init(&style);
2.2. Styles 18
LVGL Documentation 8.3
lv_style_set_img_recolor(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_img_recolor_opa(&style, LV_OPA_50);
lv_style_set_transform_angle(&style, 300);
LV_IMG_DECLARE(img_cogwheel_argb);
lv_img_set_src(obj, &img_cogwheel_argb);
lv_obj_center(obj);
}
#endif
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Using the Image style properties
#
style = lv.style_t()
style.init()
style.set_img_recolor(lv.palette_main(lv.PALETTE.BLUE))
style.set_img_recolor_opa(lv.OPA._50)
# style.set_transform_angle(300)
2.2. Styles 19
LVGL Documentation 8.3
obj.set_src(img_cogwheel_argb)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LABEL
/**
* Using the text style properties
*/
void lv_example_style_8(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
lv_style_set_bg_opa(&style, LV_OPA_COVER);
lv_style_set_bg_color(&style, lv_palette_lighten(LV_PALETTE_GREY, 2));
lv_style_set_border_width(&style, 2);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_pad_all(&style, 10);
lv_style_set_text_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_text_letter_space(&style, 5);
lv_style_set_text_line_space(&style, 20);
lv_style_set_text_decor(&style, LV_TEXT_DECOR_UNDERLINE);
lv_obj_center(obj);
}
#endif
#
# Using the text style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 3))
(continues on next page)
2.2. Styles 20
LVGL Documentation 8.3
style.set_text_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_text_letter_space(5)
style.set_text_line_space(20)
style.set_text_decor(lv.TEXT_DECOR.UNDERLINE)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LINE
/**
* Using the line style properties
*/
void lv_example_style_9(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_line_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_line_width(&style, 6);
lv_style_set_line_rounded(&style, true);
lv_obj_center(obj);
}
#endif
#
# Using the line style properties
#
style = lv.style_t()
style.init()
2.2. Styles 21
LVGL Documentation 8.3
obj.set_points(p, 3)
obj.center()
2.2.9 Transition
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Creating a transition
*/
void lv_example_style_10(void)
{
static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, LV_STYLE_BORDER_COLOR,␣
,→LV_STYLE_BORDER_WIDTH, 0};
/* A default transition
* Make it fast (100ms) and start with some delay (200 ms)*/
static lv_style_transition_dsc_t trans_def;
lv_style_transition_dsc_init(&trans_def, props, lv_anim_path_linear, 100, 200,␣
,→NULL);
2.2. Styles 22
LVGL Documentation 8.3
lv_obj_center(obj);
}
#endif
#
# Creating a transition
#
# A default transition
# Make it fast (100ms) and start with some delay (200 ms)
trans_def = lv.style_transition_dsc_t()
trans_def.init(props, lv.anim_t.path_linear, 100, 200, None)
trans_pr = lv.style_transition_dsc_t()
trans_pr.init(props, lv.anim_t.path_linear, 500, 0, None)
style_def = lv.style_t()
style_def.init()
style_def.set_transition(trans_def)
style_pr = lv.style_t()
style_pr.init()
style_pr.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_pr.set_border_width(6)
style_pr.set_border_color(lv.palette_darken(lv.PALETTE.RED, 3))
style_pr.set_transition(trans_pr)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using multiple styles
*/
void lv_example_style_11(void)
{
/*A base style*/
static lv_style_t style_base;
(continues on next page)
2.2. Styles 23
LVGL Documentation 8.3
lv_style_set_border_width(&style_base, 2);
lv_style_set_radius(&style_base, 10);
lv_style_set_shadow_width(&style_base, 10);
lv_style_set_shadow_ofs_y(&style_base, 5);
lv_style_set_shadow_opa(&style_base, LV_OPA_50);
lv_style_set_text_color(&style_base, lv_color_white());
lv_style_set_width(&style_base, 100);
lv_style_set_height(&style_base, LV_SIZE_CONTENT);
/*Create another object with the base style and earnings style too*/
lv_obj_t * obj_warning = lv_obj_create(lv_scr_act());
lv_obj_add_style(obj_warning, &style_base, 0);
lv_obj_add_style(obj_warning, &style_warning, 0);
lv_obj_align(obj_warning, LV_ALIGN_RIGHT_MID, -20, 0);
label = lv_label_create(obj_warning);
lv_label_set_text(label, "Warning");
lv_obj_center(label);
}
#endif
#
# Using multiple styles
#
# A base style
style_base = lv.style_t()
style_base.init()
style_base.set_bg_color(lv.palette_main(lv.PALETTE.LIGHT_BLUE))
style_base.set_border_color(lv.palette_darken(lv.PALETTE.LIGHT_BLUE, 3))
style_base.set_border_width(2)
style_base.set_radius(10)
style_base.set_shadow_width(10)
style_base.set_shadow_ofs_y(5)
(continues on next page)
2.2. Styles 24
LVGL Documentation 8.3
label = lv.label(obj_base)
label.set_text("Base")
label.center()
# Create another object with the base style and earnings style too
obj_warning = lv.obj(lv.scr_act())
obj_warning.add_style(style_base, 0)
obj_warning.add_style(style_warning, 0)
obj_warning.align(lv.ALIGN.RIGHT_MID, -20, 0)
label = lv.label(obj_warning)
label.set_text("Warning")
label.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Local styles
*/
void lv_example_style_12(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_GREEN));
lv_style_set_border_color(&style, lv_palette_lighten(LV_PALETTE_GREEN, 3));
lv_style_set_border_width(&style, 3);
lv_obj_center(obj);
(continues on next page)
2.2. Styles 25
LVGL Documentation 8.3
#endif
#
# Local styles
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.palette_main(lv.PALETTE.GREEN))
style.set_border_color(lv.palette_lighten(lv.PALETTE.GREEN, 3))
style.set_border_width(3)
obj = lv.obj(lv.scr_act())
obj.add_style(style, 0)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Add styles to parts and states
*/
void lv_example_style_13(void)
{
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_color(&style_indic, lv_palette_lighten(LV_PALETTE_RED, 3));
lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_HOR);
#endif
2.2. Styles 26
LVGL Documentation 8.3
#
# Add styles to parts and states
#
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_color(lv.palette_lighten(lv.PALETTE.RED, 3))
style_indic.set_bg_grad_color(lv.palette_main(lv.PALETTE.RED))
style_indic.set_bg_grad_dir(lv.GRAD_DIR.HOR)
style_indic_pr = lv.style_t()
style_indic_pr.init()
style_indic_pr.set_shadow_color(lv.palette_main(lv.PALETTE.RED))
style_indic_pr.set_shadow_width(10)
style_indic_pr.set_shadow_spread(3)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/*Will be called when the styles of the base theme are already added
to add new styles*/
static void new_theme_apply_cb(lv_theme_t * th, lv_obj_t * obj)
{
LV_UNUSED(th);
if(lv_obj_check_type(obj, &lv_btn_class)) {
lv_obj_add_style(obj, &style_btn, 0);
}
}
/*Set the parent theme and the style apply callback for the new theme*/
(continues on next page)
2.2. Styles 27
LVGL Documentation 8.3
/**
* Extending the current theme
*/
void lv_example_style_14(void)
{
lv_obj_t * btn;
lv_obj_t * label;
btn = lv_btn_create(lv_scr_act());
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 20);
label = lv_label_create(btn);
lv_label_set_text(label, "Original theme");
new_theme_init_and_set();
btn = lv_btn_create(lv_scr_act());
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -20);
label = lv_label_create(btn);
lv_label_set_text(label, "New theme");
}
#endif
# Will be called when the styles of the base theme are already added
# to add new styles
class NewTheme(lv.theme_t):
def __init__(self):
super().__init__()
# Initialize the styles
self.style_btn = lv.style_t()
self.style_btn.init()
self.style_btn.set_bg_color(lv.palette_main(lv.PALETTE.GREEN))
self.style_btn.set_border_color(lv.palette_darken(lv.PALETTE.GREEN, 3))
self.style_btn.set_border_width(3)
class ExampleStyle_14:
def __init__(self):
#
(continues on next page)
2.2. Styles 28
LVGL Documentation 8.3
btn = lv.btn(lv.scr_act())
btn.align(lv.ALIGN.TOP_MID, 0, 20)
label = lv.label(btn)
label.set_text("Original theme")
self.new_theme_init_and_set()
btn = lv.btn(lv.scr_act())
btn.align(lv.ALIGN.BOTTOM_MID, 0, -20)
label = lv.label(btn)
label.set_text("New theme")
def new_theme_init_and_set(self):
print("new_theme_init_and_set")
# Initialize the new theme from the current theme
self.th_new = NewTheme()
self.th_new.set_apply_cb(self.new_theme_apply_cb)
lv.disp_get_default().set_theme(self.th_new)
exampleStyle_14 = ExampleStyle_14()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN && LV_USE_LABEL
/**
* Opacity and Transformations
*/
void lv_example_style_15(void)
{
lv_obj_t * btn;
lv_obj_t * label;
/*Normal button*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, -70);
label = lv_label_create(btn);
lv_label_set_text(label, "Normal");
lv_obj_center(label);
2.2. Styles 29
LVGL Documentation 8.3
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_set_style_opa(btn, LV_OPA_50, 0);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 0);
label = lv_label_create(btn);
lv_label_set_text(label, "Opa:50%");
lv_obj_center(label);
/*Set transformations
*The button and the label is rendered to a layer first and that layer is␣
,→transformed*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_set_style_transform_angle(btn, 150, 0); /*15 deg*/
lv_obj_set_style_transform_zoom(btn, 256 + 64, 0); /*1.25x*/
lv_obj_set_style_transform_pivot_x(btn, 50, 0);
lv_obj_set_style_transform_pivot_y(btn, 20, 0);
lv_obj_set_style_opa(btn, LV_OPA_50, 0);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 70);
label = lv_label_create(btn);
lv_label_set_text(label, "Transf.");
lv_obj_center(label);
}
#endif
2.3 Animations
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
if(lv_obj_has_state(sw, LV_STATE_CHECKED)) {
lv_anim_t a;
(continues on next page)
2.3. Animations 30
LVGL Documentation 8.3
/**
* Start animation on an event
*/
void lv_example_anim_1(void)
{
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello animations!");
lv_obj_set_pos(label, 100, 10);
lv_obj_t * sw = lv_switch_create(lv_scr_act());
lv_obj_center(sw);
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, sw_event_cb, LV_EVENT_VALUE_CHANGED, label);
}
#endif
def sw_event_cb(e,label):
sw = e.get_target()
if sw.has_state(lv.STATE.CHECKED):
a = lv.anim_t()
a.init()
a.set_var(label)
a.set_values(label.get_x(), 100)
a.set_time(500)
a.set_path_cb(lv.anim_t.path_overshoot)
a.set_custom_exec_cb(lambda a,val: anim_x_cb(label,val))
lv.anim_t.start(a)
else:
a = lv.anim_t()
a.init()
(continues on next page)
2.3. Animations 31
LVGL Documentation 8.3
#
# Start animation on an event
#
label = lv.label(lv.scr_act())
label.set_text("Hello animations!")
label.set_pos(100, 10)
sw = lv.switch(lv.scr_act())
sw.center()
sw.add_state(lv.STATE.CHECKED)
sw.add_event_cb(lambda e: sw_event_cb(e,label), lv.EVENT.VALUE_CHANGED, None)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
/**
* Create a playback animation
*/
void lv_example_anim_2(void)
{
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, obj);
(continues on next page)
2.3. Animations 32
LVGL Documentation 8.3
lv_anim_set_exec_cb(&a, anim_size_cb);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, anim_x_cb);
lv_anim_set_values(&a, 10, 240);
lv_anim_start(&a);
}
#endif
#
# Create a playback animation
#
obj = lv.obj(lv.scr_act())
obj.set_style_bg_color(lv.palette_main(lv.PALETTE.RED), 0)
obj.set_style_radius(lv.RADIUS.CIRCLE, 0)
obj.align(lv.ALIGN.LEFT_MID, 10, 0)
a1 = lv.anim_t()
a1.init()
a1.set_var(obj)
a1.set_values(10, 50)
a1.set_time(1000)
a1.set_playback_delay(100)
a1.set_playback_time(300)
a1.set_repeat_delay(500)
a1.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a1.set_path_cb(lv.anim_t.path_ease_in_out)
a1.set_custom_exec_cb(lambda a1,val: anim_size_cb(obj,val))
lv.anim_t.start(a1)
a2 = lv.anim_t()
a2.init()
a2.set_var(obj)
a2.set_values(10, 240)
a2.set_time(1000)
a2.set_playback_delay(100)
a2.set_playback_time(300)
a2.set_repeat_delay(500)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a2.set_path_cb(lv.anim_t.path_ease_in_out)
(continues on next page)
2.3. Animations 33
LVGL Documentation 8.3
#include "../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
lv_anim_t a2;
lv_anim_init(&a2);
lv_anim_set_var(&a2, obj1);
lv_anim_set_values(&a2, 0, obj_height);
lv_anim_set_early_apply(&a2, false);
lv_anim_set_exec_cb(&a2, (lv_anim_exec_xcb_t)set_height);
lv_anim_set_path_cb(&a2, lv_anim_path_ease_out);
lv_anim_set_time(&a2, 300);
/* obj2 */
lv_anim_t a3;
lv_anim_init(&a3);
lv_anim_set_var(&a3, obj2);
lv_anim_set_values(&a3, 0, obj_width);
lv_anim_set_early_apply(&a3, false);
(continues on next page)
2.3. Animations 34
LVGL Documentation 8.3
lv_anim_t a4;
lv_anim_init(&a4);
lv_anim_set_var(&a4, obj2);
lv_anim_set_values(&a4, 0, obj_height);
lv_anim_set_early_apply(&a4, false);
lv_anim_set_exec_cb(&a4, (lv_anim_exec_xcb_t)set_height);
lv_anim_set_path_cb(&a4, lv_anim_path_ease_out);
lv_anim_set_time(&a4, 300);
/* obj3 */
lv_anim_t a5;
lv_anim_init(&a5);
lv_anim_set_var(&a5, obj3);
lv_anim_set_values(&a5, 0, obj_width);
lv_anim_set_early_apply(&a5, false);
lv_anim_set_exec_cb(&a5, (lv_anim_exec_xcb_t)set_width);
lv_anim_set_path_cb(&a5, lv_anim_path_overshoot);
lv_anim_set_time(&a5, 300);
lv_anim_t a6;
lv_anim_init(&a6);
lv_anim_set_var(&a6, obj3);
lv_anim_set_values(&a6, 0, obj_height);
lv_anim_set_early_apply(&a6, false);
lv_anim_set_exec_cb(&a6, (lv_anim_exec_xcb_t)set_height);
lv_anim_set_path_cb(&a6, lv_anim_path_ease_out);
lv_anim_set_time(&a6, 300);
if(!anim_timeline) {
anim_timeline_create();
}
2.3. Animations 35
LVGL Documentation 8.3
if(!anim_timeline) {
anim_timeline_create();
}
/**
* Create an animation timeline
*/
void lv_example_anim_timeline_1(void)
{
lv_obj_t * par = lv_scr_act();
lv_obj_set_flex_flow(par, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(par, LV_FLEX_ALIGN_SPACE_AROUND, LV_FLEX_ALIGN_CENTER, LV_
,→FLEX_ALIGN_CENTER);
/* create btn_start */
lv_obj_t * btn_start = lv_btn_create(par);
lv_obj_add_event_cb(btn_start, btn_start_event_handler, LV_EVENT_VALUE_CHANGED,␣
,→NULL);
lv_obj_add_flag(btn_start, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_add_flag(btn_start, LV_OBJ_FLAG_CHECKABLE);
lv_obj_align(btn_start, LV_ALIGN_TOP_MID, -100, 20);
/* create btn_del */
lv_obj_t * btn_del = lv_btn_create(par);
lv_obj_add_event_cb(btn_del, btn_del_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_add_flag(btn_del, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_align(btn_del, LV_ALIGN_TOP_MID, 0, 20);
2.3. Animations 36
LVGL Documentation 8.3
/* create btn_stop */
lv_obj_t * btn_stop = lv_btn_create(par);
lv_obj_add_event_cb(btn_stop, btn_stop_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_add_flag(btn_stop, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_align(btn_stop, LV_ALIGN_TOP_MID, 100, 20);
/* create slider_prg */
lv_obj_t * slider_prg = lv_slider_create(par);
lv_obj_add_event_cb(slider_prg, slider_prg_event_handler, LV_EVENT_VALUE_CHANGED,␣
,→NULL);
lv_obj_add_flag(slider_prg, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_align(slider_prg, LV_ALIGN_BOTTOM_MID, 0, -20);
lv_slider_set_range(slider_prg, 0, 65535);
/* create 3 objects */
obj1 = lv_obj_create(par);
lv_obj_set_size(obj1, obj_width, obj_height);
obj2 = lv_obj_create(par);
lv_obj_set_size(obj2, obj_width, obj_height);
obj3 = lv_obj_create(par);
lv_obj_set_size(obj3, obj_width, obj_height);
}
#endif
class LV_ExampleAnimTimeline_1(object):
def __init__(self):
self.obj_width = 120
self.obj_height = 150
#
# Create an animation timeline
#
self.par = lv.scr_act()
self.par.set_flex_flow(lv.FLEX_FLOW.ROW)
self.par.set_flex_align(lv.FLEX_ALIGN.SPACE_AROUND, lv.FLEX_ALIGN.CENTER, lv.
,→FLEX_ALIGN.CENTER)
self.btn_run = lv.btn(self.par)
self.btn_run.add_event_cb(self.btn_run_event_handler, lv.EVENT.VALUE_CHANGED,␣
,→ None)
self.btn_run.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.btn_run.add_flag(lv.obj.FLAG.CHECKABLE)
self.btn_run.align(lv.ALIGN.TOP_MID, -50, 20)
self.label_run = lv.label(self.btn_run)
self.label_run.set_text("Run")
(continues on next page)
2.3. Animations 37
LVGL Documentation 8.3
self.btn_del = lv.btn(self.par)
self.btn_del.add_event_cb(self.btn_del_event_handler, lv.EVENT.CLICKED, None)
self.btn_del.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.btn_del.align(lv.ALIGN.TOP_MID, 50, 20)
self.label_del = lv.label(self.btn_del)
self.label_del.set_text("Stop")
self.label_del.center()
self.slider = lv.slider(self.par)
self.slider.add_event_cb(self.slider_prg_event_handler, lv.EVENT.VALUE_
,→CHANGED, None)
self.slider.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.slider.align(lv.ALIGN.BOTTOM_RIGHT, -20, -20)
self.slider.set_range(0, 65535)
self.obj1 = lv.obj(self.par)
self.obj1.set_size(self.obj_width, self.obj_height)
self.obj2 = lv.obj(self.par)
self.obj2.set_size(self.obj_width, self.obj_height)
self.obj3 = lv.obj(self.par)
self.obj3.set_size(self.obj_width, self.obj_height)
self.anim_timeline = None
def anim_timeline_create(self):
# obj1
self.a1 = lv.anim_t()
self.a1.init()
self.a1.set_values(0, self.obj_width)
self.a1.set_early_apply(False)
self.a1.set_custom_exec_cb(lambda a,v: self.set_width(self.obj1,v))
self.a1.set_path_cb(lv.anim_t.path_overshoot)
self.a1.set_time(300)
self.a2 = lv.anim_t()
self.a2.init()
self.a2.set_values(0, self.obj_height)
self.a2.set_early_apply(False)
self.a2.set_custom_exec_cb(lambda a,v: self.set_height(self.obj1,v))
self.a2.set_path_cb(lv.anim_t.path_ease_out)
self.a2.set_time(300)
# obj2
self.a3=lv.anim_t()
self.a3.init()
self.a3.set_values(0, self.obj_width)
(continues on next page)
2.3. Animations 38
LVGL Documentation 8.3
self.a4 = lv.anim_t()
self.a4.init()
self.a4.set_values(0, self.obj_height)
self.a4.set_early_apply(False)
self.a4.set_custom_exec_cb(lambda a,v: self.set_height(self.obj2,v))
self.a4.set_path_cb(lv.anim_t.path_ease_out)
self.a4.set_time(300)
# obj3
self.a5 = lv.anim_t()
self.a5.init()
self.a5.set_values(0, self.obj_width)
self.a5.set_early_apply(False)
self.a5.set_custom_exec_cb(lambda a,v: self.set_width(self.obj3,v))
self.a5.set_path_cb(lv.anim_t.path_overshoot)
self.a5.set_time(300)
self.a6 = lv.anim_t()
self.a6.init()
self.a6.set_values(0, self.obj_height)
self.a6.set_early_apply(False)
self.a6.set_custom_exec_cb(lambda a,v: self.set_height(self.obj3,v))
self.a6.set_path_cb(lv.anim_t.path_ease_out)
self.a6.set_time(300)
def slider_prg_event_handler(self,e):
slider = e.get_target()
if not self.anim_timeline:
self.anim_timeline_create()
progress = slider.get_value()
lv.anim_timeline_set_progress(self.anim_timeline, progress)
def btn_run_event_handler(self,e):
btn = e.get_target()
if not self.anim_timeline:
self.anim_timeline_create()
reverse = btn.has_state(lv.STATE.CHECKED)
lv.anim_timeline_set_reverse(self.anim_timeline,reverse)
(continues on next page)
2.3. Animations 39
LVGL Documentation 8.3
def btn_del_event_handler(self,e):
if self.anim_timeline:
lv.anim_timeline_del(self.anim_timeline)
self.anim_timeline = None
lv_example_anim_timeline_1 = LV_ExampleAnimTimeline_1()
2.4 Events
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
/**
* Add click event to a button
*/
void lv_example_event_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);
#endif
class Event_1():
def __init__(self):
self.cnt = 1
#
# Add click event to a button
#
btn = lv.btn(lv.scr_act())
(continues on next page)
2.4. Events 40
LVGL Documentation 8.3
label = lv.label(btn)
label.set_text("Click me!")
label.center()
def event_cb(self,e):
print("Clicked")
btn = e.get_target()
label = btn.get_child(0)
label.set_text(str(self.cnt))
self.cnt += 1
evt1 = Event_1()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
switch(code) {
case LV_EVENT_PRESSED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_PRESSED");
break;
case LV_EVENT_CLICKED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_CLICKED");
break;
case LV_EVENT_LONG_PRESSED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED");
break;
case LV_EVENT_LONG_PRESSED_REPEAT:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED_
,→REPEAT");
break;
default:
break;
}
}
/**
* Handle multiple events
*/
void lv_example_event_2(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
(continues on next page)
2.4. Events 41
LVGL Documentation 8.3
#endif
def event_cb(e,label):
code = e.get_code()
if code == lv.EVENT.PRESSED:
label.set_text("The last button event:\nLV_EVENT_PRESSED")
elif code == lv.EVENT.CLICKED:
label.set_text("The last button event:\nLV_EVENT_CLICKED")
elif code == lv.EVENT.LONG_PRESSED:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED")
elif code == lv.EVENT.LONG_PRESSED_REPEAT:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED_REPEAT")
btn = lv.btn(lv.scr_act())
btn.set_size(100, 50)
btn.center()
btn_label = lv.label(btn)
btn_label.set_text("Click me!")
btn_label.center()
info_label = lv.label(lv.scr_act())
info_label.set_text("The last button event:\nNone")
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
/*The current target is always the container as the event is added to it*/
lv_obj_t * cont = lv_event_get_current_target(e);
2.4. Events 42
LVGL Documentation 8.3
/**
* Demonstrate event bubbling
*/
void lv_example_event_3(void)
{
uint32_t i;
for(i = 0; i < 30; i++) {
lv_obj_t * btn = lv_btn_create(cont);
lv_obj_set_size(btn, 80, 50);
lv_obj_add_flag(btn, LV_OBJ_FLAG_EVENT_BUBBLE);
#endif
def event_cb(e):
# The original target of the event. Can be the buttons or the container
target = e.get_target()
# print(type(target))
#
# Demonstrate event bubbling
#
cont = lv.obj(lv.scr_act())
cont.set_size(320, 200)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(30):
btn = lv.btn(cont)
btn.set_size(80, 50)
btn.add_flag(lv.obj.FLAG.EVENT_BUBBLE)
(continues on next page)
2.4. Events 43
LVGL Documentation 8.3
label = lv.label(btn)
label.set_text(str(i))
label.center()
2.5 Layouts
2.5.1 Flex
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* A simple row and a column layout with flexbox
*/
void lv_example_flex_1(void)
{
/*Create a container with ROW flex direction*/
lv_obj_t * cont_row = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_row, 300, 75);
lv_obj_align(cont_row, LV_ALIGN_TOP_MID, 0, 5);
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * obj;
lv_obj_t * label;
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
(continues on next page)
2.5. Layouts 44
LVGL Documentation 8.3
#endif
#
# A simple row and a column layout with flexbox
#
for i in range(10):
# Add items to the row
obj = lv.btn(cont_row)
obj.set_size(100, lv.pct(100))
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Arrange items in rows with wrap and place the items to get even space around them.
*/
void lv_example_flex_2(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_flex_flow(&style, LV_FLEX_FLOW_ROW_WRAP);
lv_style_set_flex_main_place(&style, LV_FLEX_ALIGN_SPACE_EVENLY);
lv_style_set_layout(&style, LV_LAYOUT_FLEX);
(continues on next page)
2.5. Layouts 45
LVGL Documentation 8.3
uint32_t i;
for(i = 0; i < 8; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
#endif
#
# Arrange items in rows with wrap and place the items to get even space around them.
#
style = lv.style_t()
style.init()
style.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
style.set_flex_main_place(lv.FLEX_ALIGN.SPACE_EVENLY)
style.set_layout(lv.LAYOUT_FLEX.value)
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.add_style(style, 0)
for i in range(8):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text("{:d}".format(i))
label.center()
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate flex grow.
*/
void lv_example_flex_3(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
(continues on next page)
2.5. Layouts 46
LVGL Documentation 8.3
lv_obj_t * obj;
obj = lv_obj_create(cont);
lv_obj_set_size(obj, 40, 40); /*Fix size*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 1); /*1 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 2); /*2 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, 40, 40); /*Fix size. It is flushed to the right by␣
,→the "grow" items*/
#endif
#
# Demonstrate flex grow.
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW)
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(1) # 1 portion from the free space
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(2) # 2 portion from the free space
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size. It is flushed to the right by the "grow"␣
,→items
2.5. Layouts 47
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Reverse the order of flex items
*/
void lv_example_flex_4(void)
{
uint32_t i;
for(i = 0; i < 6; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 100, 50);
#endif
#
# Reverse the order of flex items
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.COLUMN_REVERSE)
for i in range(6):
obj = lv.obj(cont)
obj.set_size(100, 50)
label = lv.label(obj)
label.set_text("Item: " + str(i))
label.center()
2.5. Layouts 48
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate the effect of column and row gap style properties
*/
void lv_example_flex_5(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
uint32_t i;
for(i = 0; i < 9; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, cont);
lv_anim_set_values(&a, 0, 10);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, row_gap_anim);
lv_anim_set_time(&a, 500);
lv_anim_set_playback_time(&a, 500);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, column_gap_anim);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
2.5. Layouts 49
LVGL Documentation 8.3
#
# Demonstrate the effect of column and row gap style properties
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(9):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
label.center()
a_row = lv.anim_t()
a_row.init()
a_row.set_var(cont)
a_row.set_values(0, 10)
a_row.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_row.set_time(500)
a_row.set_playback_time(500)
a_row.set_custom_exec_cb(lambda a,val: row_gap_anim(cont,val))
lv.anim_t.start(a_row)
a_col = lv.anim_t()
a_col.init()
a_col.set_var(cont)
a_col.set_values(0, 10)
a_col.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_col.set_time(3000)
a_col.set_playback_time(3000)
a_col.set_custom_exec_cb(lambda a,val: column_gap_anim(cont,val))
lv.anim_t.start(a_col)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* RTL base direction changes order of the items.
* Also demonstrate how horizontal scrolling works with RTL.
*/
void lv_example_flex_6(void)
(continues on next page)
2.5. Layouts 50
LVGL Documentation 8.3
uint32_t i;
for(i = 0; i < 20; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
#
# RTL base direction changes order of the items.
# Also demonstrate how horizontal scrolling works with RTL.
#
cont = lv.obj(lv.scr_act())
cont.set_style_base_dir(lv.BASE_DIR.RTL,0)
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(20):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
label.center()
2.5.2 Grid
A simple grid
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* A simple grid
*/
void lv_example_grid_1(void)
{
static lv_coord_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};
2.5. Layouts 51
LVGL Documentation 8.3
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_btn_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "c%d, r%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# A simple grid
#
for i in range(9):
col = i % 3
row = i // 3
obj = lv.btn(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
(continues on next page)
2.5. Layouts 52
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate cell placement and span
*/
void lv_example_grid_2(void)
{
static lv_coord_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};
lv_obj_t * label;
lv_obj_t * obj;
/*Cell to 0;0 and align to to the start (left/top) horizontally and vertically␣
,→ too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 0, 1,
LV_GRID_ALIGN_START, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c0, r0");
/*Cell to 1;0 and align to to the start (left) horizontally and center vertically␣
,→ too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 1, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c1, r0");
/*Cell to 2;0 and align to to the start (left) horizontally and end (bottom)␣
,→ vertically too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 2, 1,
LV_GRID_ALIGN_END, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c2, r0");
/*Cell to 1;1 but 2 column wide (span = 2).Set width and height to stretched.*/
obj = lv_obj_create(cont);
(continues on next page)
2.5. Layouts 53
LVGL Documentation 8.3
/*Cell to 0;1 but 2 rows tall (span = 2).Set width and height to stretched.*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 0, 1,
LV_GRID_ALIGN_STRETCH, 1, 2);
label = lv_label_create(obj);
lv_label_set_text(label, "c0\nr1-2");
}
#endif
#
# Demonstrate cell placement and span
#
# Cell to 0;0 and align to the start (left/top) horizontally and vertically too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 0, 1,
lv.GRID_ALIGN.START, 0, 1)
label = lv.label(obj)
label.set_text("c0, r0")
# Cell to 1;0 and align to the start (left) horizontally and center vertically too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 1, 1,
lv.GRID_ALIGN.CENTER, 0, 1)
label = lv.label(obj)
label.set_text("c1, r0")
# Cell to 2;0 and align to the start (left) horizontally and end (bottom) vertically␣
,→too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 2, 1,
lv.GRID_ALIGN.END, 0, 1)
label = lv.label(obj)
label.set_text("c2, r0")
# Cell to 1;1 but 2 column wide (span = 2).Set width and height to stretched.
(continues on next page)
2.5. Layouts 54
LVGL Documentation 8.3
# Cell to 0;1 but 2 rows tall (span = 2).Set width and height to stretched.
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, 0, 1,
lv.GRID_ALIGN.STRETCH, 1, 2)
label = lv.label(obj)
label.set_text("c0\nr1-2")
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate grid's "free unit"
*/
void lv_example_grid_3(void)
{
/*Column 1: fix width 60 px
*Column 2: 1 unit from the remaining free space
*Column 3: 2 unit from the remaining free space*/
static lv_coord_t col_dsc[] = {60, LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_
,→LAST};
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_obj_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
2.5. Layouts 55
LVGL Documentation 8.3
#endif
#
# Demonstrate grid's "free unit"
#
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("%d,%d"%(col, row))
label.center()
2.5. Layouts 56
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate track placement
*/
void lv_example_grid_4(void)
{
static lv_coord_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};
/*Add space between the columns and move the rows to the bottom (end)*/
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_obj_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# Demonstrate track placement
#
# Add space between the columns and move the rows to the bottom (end)
2.5. Layouts 57
LVGL Documentation 8.3
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("{:d}{:d}".format(col, row))
label.center()
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate column and row gap
*/
void lv_example_grid_5(void)
{
/*60x60 cells*/
static lv_coord_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
(continues on next page)
2.5. Layouts 58
LVGL Documentation 8.3
obj = lv_obj_create(cont);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, cont);
lv_anim_set_values(&a, 0, 10);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, row_gap_anim);
lv_anim_set_time(&a, 500);
lv_anim_set_playback_time(&a, 500);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, column_gap_anim);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
#
# Demonstrate column and row gap
#
# 60x60 cells
col_dsc = [60, 60, 60, lv.GRID_TEMPLATE.LAST]
row_dsc = [40, 40, 40, lv.GRID_TEMPLATE.LAST]
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
(continues on next page)
2.5. Layouts 59
LVGL Documentation 8.3
a_row = lv.anim_t()
a_row.init()
a_row.set_var(cont)
a_row.set_values(0, 10)
a_row.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_row.set_time(500)
a_row.set_playback_time(500)
a_row. set_custom_exec_cb(lambda a,val: row_gap_anim(cont,val))
lv.anim_t.start(a_row)
a_col = lv.anim_t()
a_col.init()
a_col.set_var(cont)
a_col.set_values(0, 10)
a_col.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_col.set_time(500)
a_col.set_playback_time(500)
a_col. set_custom_exec_cb(lambda a,val: column_gap_anim(cont,val))
lv.anim_t.start(a_col)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate RTL direction on grid
*/
void lv_example_grid_6(void)
{
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
2.5. Layouts 60
LVGL Documentation 8.3
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# Demonstrate RTL direction on grid
#
col_dsc = [60, 60, 60, lv.GRID_TEMPLATE.LAST]
row_dsc = [40, 40, 40, lv.GRID_TEMPLATE.LAST]
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("{:d},{:d}".format(col, row))
label.center()
2.6 Scrolling
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Demonstrate how scrolling appears automatically
*/
void lv_example_scroll_1(void)
(continues on next page)
2.6. Scrolling 61
LVGL Documentation 8.3
lv_obj_t * child;
lv_obj_t * label;
child = lv_obj_create(panel);
lv_obj_set_pos(child, 0, 0);
lv_obj_set_size(child, 70, 70);
label = lv_label_create(child);
lv_label_set_text(label, "Zero");
lv_obj_center(label);
child = lv_obj_create(panel);
lv_obj_set_pos(child, 160, 80);
lv_obj_set_size(child, 80, 80);
label = lv_label_create(child2);
lv_label_set_text(label, "Right");
lv_obj_center(label);
child = lv_obj_create(panel);
lv_obj_set_pos(child, 40, 160);
lv_obj_set_size(child, 100, 70);
label = lv_label_create(child);
lv_label_set_text(label, "Bottom");
lv_obj_center(label);
}
#endif
#
# Demonstrate how scrolling appears automatically
#
# Create an object with the new style
panel = lv.obj(lv.scr_act())
panel.set_size(200, 200)
panel.center()
child = lv.obj(panel)
child.set_pos(0, 0)
label = lv.label(child)
label.set_text("Zero")
label.center()
child = lv.obj(panel)
child.set_pos(-40, 100)
label = lv.label(child)
label.set_text("Left")
label.center()
(continues on next page)
2.6. Scrolling 62
LVGL Documentation 8.3
child = lv.obj(panel)
child.set_pos(90, -30)
label = lv.label(child)
label.set_text("Top")
label.center()
child = lv.obj(panel)
child.set_pos(150, 80)
label = lv.label(child)
label.set_text("Right")
label.center()
child = lv.obj(panel)
child.set_pos(60, 170)
label = lv.label(child)
label.set_text("Bottom")
label.center()
2.6.2 Snapping
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_t * list = lv_event_get_user_data(e);
/**
* Show an example to scroll snap
*/
void lv_example_scroll_2(void)
{
lv_obj_t * panel = lv_obj_create(lv_scr_act());
lv_obj_set_size(panel, 280, 120);
lv_obj_set_scroll_snap_x(panel, LV_SCROLL_SNAP_CENTER);
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW);
lv_obj_align(panel, LV_ALIGN_CENTER, 0, 20);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * btn = lv_btn_create(panel);
lv_obj_set_size(btn, 150, lv_pct(100));
(continues on next page)
2.6. Scrolling 63
LVGL Documentation 8.3
lv_obj_center(label);
}
lv_obj_update_snap(panel, LV_ANIM_ON);
#if LV_USE_SWITCH
/*Switch between "One scroll" and "Normal scroll" mode*/
lv_obj_t * sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_TOP_RIGHT, -20, 10);
lv_obj_add_event_cb(sw, sw_event_cb, LV_EVENT_ALL, panel);
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "One scroll");
lv_obj_align_to(label, sw, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
#endif
}
#endif
def sw_event_cb(e,panel):
code = e.get_code()
sw = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
if sw.has_state(lv.STATE.CHECKED):
panel.add_flag(lv.obj.FLAG.SCROLL_ONE)
else:
panel.clear_flag(lv.obj.FLAG.SCROLL_ONE)
#
# Show an example to scroll snap
#
panel = lv.obj(lv.scr_act())
panel.set_size(280, 150)
panel.set_scroll_snap_x(lv.SCROLL_SNAP.CENTER)
panel.set_flex_flow(lv.FLEX_FLOW.ROW)
panel.center()
for i in range(10):
btn = lv.btn(panel)
btn.set_size(150, 100)
label = lv.label(btn)
if i == 3:
(continues on next page)
2.6. Scrolling 64
LVGL Documentation 8.3
panel.update_snap(lv.ANIM.ON)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LIST
if(code == LV_EVENT_CLICKED) {
lv_obj_t * list = lv_event_get_user_data(e);
char buf[32];
lv_snprintf(buf, sizeof(buf), "Track %d", (int)btn_cnt);
lv_obj_t * list_btn = lv_list_add_btn(list, LV_SYMBOL_AUDIO, buf);
btn_cnt++;
lv_obj_move_foreground(float_btn);
lv_obj_scroll_to_view(list_btn, LV_ANIM_ON);
}
}
/**
* Create a list with a floating button
*/
void lv_example_scroll_3(void)
{
lv_obj_t * list = lv_list_create(lv_scr_act());
lv_obj_set_size(list, 280, 220);
lv_obj_center(list);
2.6. Scrolling 65
LVGL Documentation 8.3
#endif
class ScrollExample_3():
def __init__(self):
self.btn_cnt = 1
#
# Create a list with a floating button
#
list = lv.list(lv.scr_act())
list.set_size(280, 220)
list.center()
float_btn = lv.btn(list)
float_btn.set_size(50, 50)
float_btn.add_flag(lv.obj.FLAG.FLOATING)
float_btn.align(lv.ALIGN.BOTTOM_RIGHT, 0, -list.get_style_pad_right(lv.PART.
,→ MAIN))
float_btn.add_event_cb(lambda evt: self.float_btn_event_cb(evt,list), lv.
,→ EVENT.ALL, None)
float_btn.set_style_radius(lv.RADIUS.CIRCLE, 0)
float_btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
float_btn.set_style_text_font(lv.theme_get_font_large(float_btn), 0)
def float_btn_event_cb(self,e,list):
code = e.get_code()
float_btn = e.get_target()
if code == lv.EVENT.CLICKED:
list_btn = list.add_btn(lv.SYMBOL.AUDIO, "Track {:d}".format(self.btn_
,→ cnt))
self.btn_cnt += 1
float_btn.move_foreground()
list_btn.scroll_to_view(lv.ANIM.ON)
2.6. Scrolling 66
LVGL Documentation 8.3
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LIST
/**
* Styling the scrollbars
*/
void lv_example_scroll_4(void)
{
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj, 200, 100);
lv_obj_center(obj);
lv_style_set_radius(&style, 2);
lv_style_set_bg_opa(&style, LV_OPA_70);
(continues on next page)
2.6. Scrolling 67
LVGL Documentation 8.3
lv_style_set_transition(&style, &trans);
/*Make the scrollbars wider and use 100% opacity when scrolled*/
static lv_style_t style_scrolled;
lv_style_init(&style_scrolled);
lv_style_set_width(&style_scrolled, 8);
lv_style_set_bg_opa(&style_scrolled, LV_OPA_COVER);
#endif
#
# Styling the scrollbars
#
obj = lv.obj(lv.scr_act())
obj.set_size(200, 100)
obj.center()
label = lv.label(obj)
label.set_text(
"""
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Etiam dictum, tortor vestibulum lacinia laoreet, mi neque consectetur neque, vel␣
,→mattis odio dolor egestas ligula.
2.6. Scrolling 68
LVGL Documentation 8.3
style.set_radius(2)
style.set_bg_opa(lv.OPA._70)
style.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_border_color(lv.palette_darken(lv.PALETTE.BLUE, 3))
style.set_border_width(2)
style.set_shadow_width(8)
style.set_shadow_spread(2)
style.set_shadow_color(lv.palette_darken(lv.PALETTE.BLUE, 1))
style.set_transition(trans)
# Make the scrollbars wider and use 100% opacity when scrolled
style_scrolled = lv.style_t()
style_scrolled.init()
style_scrolled.set_width(8)
style_scrolled.set_bg_opa(lv.OPA.COVER)
obj.add_style(style, lv.PART.SCROLLBAR)
obj.add_style(style_scrolled, lv.PART.SCROLLBAR | lv.STATE.SCROLLED)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_FONT_DEJAVU_16_PERSIAN_HEBREW
/**
* Scrolling with Right To Left base direction
*/
void lv_example_scroll_5(void)
{
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_set_style_base_dir(obj, LV_BASE_DIR_RTL, 0);
lv_obj_set_size(obj, 200, 100);
lv_obj_center(obj);
,→ کنترل را دیگر ابزارهای تنهایی به میتواند. یک دیگر عبارت به کند،␣مدار میکروکنترلر
,→ یک از که است کوچکی مجتمعCPU مانند دیگری اجزای و کوچک،␣خروجی و ورودی درگاههای تایمر
lv_obj_set_width(label, 400);
(continues on next page)
2.6. Scrolling 69
LVGL Documentation 8.3
#endif
#
# Scrolling with Right To Left base direction
#
obj = lv.obj(lv.scr_act())
obj.set_style_base_dir(lv.BASE_DIR.RTL, 0)
obj.set_size(200, 100)
obj.center()
label = lv.label(obj)
label.set_text("ُکنترولر )به میکرو: انگلیسیMicrocontroller) ␣که است ریزپردازنده گونهای
,→ٔه دارای
( تصادفی دسترسی حافظRAM) ٔه و
( فقطخواندنی حافظROM)، ،␣و ورودی پورتهای تایمر
,→( خروجیI/O) ( ترتیبی درگاه وSerial Port پورت،( تراشه خود درون سریال،␣میتواند و است
,→ کنترل را دیگر ابزارهای تنهایی به. یک دیگر عبارت به کند،␣مجتمع مدار میکروکنترلر
,→ یک از که است کوچکیCPU مانند دیگری اجزای و کوچک،␣خروجی و ورودی درگاههای تایمر
label.set_width(400)
label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
lv_area_t cont_a;
lv_obj_get_coords(cont, &cont_a);
lv_coord_t cont_y_center = cont_a.y1 + lv_area_get_height(&cont_a) / 2;
2.6. Scrolling 70
LVGL Documentation 8.3
/**
* Translate the object as they scroll
*/
void lv_example_scroll_6(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 200, 200);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
lv_obj_add_event_cb(cont, scroll_event_cb, LV_EVENT_SCROLL, NULL);
lv_obj_set_style_radius(cont, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_clip_corner(cont, true, 0);
lv_obj_set_scroll_dir(cont, LV_DIR_VER);
lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF);
uint32_t i;
for(i = 0; i < 20; i++) {
lv_obj_t * btn = lv_btn_create(cont);
lv_obj_set_width(btn, lv_pct(100));
#endif
def scroll_event_cb(e):
2.6. Scrolling 71
LVGL Documentation 8.3
cont_a = lv.area_t()
cont.get_coords(cont_a)
cont_y_center = cont_a.y1 + cont_a.get_height() // 2
r = cont.get_height() * 7 // 10
child_cnt = cont.get_child_cnt()
for i in range(child_cnt):
child = cont.get_child(i)
child_a = lv.area_t()
child.get_coords(child_a)
# If diff_y is out of the circle use the last point of the circle (the radius)
if diff_y >= r:
x = r
else:
# Use Pythagoras theorem to get x from radius and y
x_sqr = r * r - diff_y * diff_y
res = lv.sqrt_res_t()
lv.sqrt(x_sqr, res, 0x8000) # Use lvgl's built in sqrt root function
x = r - res.i
#
# Translate the object as they scroll
#
cont = lv.obj(lv.scr_act())
cont.set_size(200, 200)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.COLUMN)
cont.add_event_cb(scroll_event_cb, lv.EVENT.SCROLL, None)
cont.set_style_radius(lv.RADIUS.CIRCLE, 0)
cont.set_style_clip_corner(True, 0)
cont.set_scroll_dir(lv.DIR.VER)
cont.set_scroll_snap_y(lv.SCROLL_SNAP.CENTER)
cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
for i in range(20):
btn = lv.btn(cont)
btn.set_width(lv.pct(100))
2.6. Scrolling 72
LVGL Documentation 8.3
2.7 Widgets
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
void lv_example_obj_1(void)
{
lv_obj_t * obj1;
obj1 = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj1, 100, 50);
lv_obj_align(obj1, LV_ALIGN_CENTER, -60, -30);
lv_obj_t * obj2;
obj2 = lv_obj_create(lv_scr_act());
lv_obj_add_style(obj2, &style_shadow, 0);
lv_obj_align(obj2, LV_ALIGN_CENTER, 60, 30);
}
#endif
obj1 = lv.obj(lv.scr_act())
obj1.set_size(100, 50)
obj1.align(lv.ALIGN.CENTER, -60, -30)
style_shadow = lv.style_t()
style_shadow.init()
style_shadow.set_shadow_width(10)
style_shadow.set_shadow_spread(5)
style_shadow.set_shadow_color(lv.palette_main(lv.PALETTE.BLUE))
obj2 = lv.obj(lv.scr_act())
obj2.add_style(style_shadow, 0)
obj2.align(lv.ALIGN.CENTER, 60, 30)
2.7. Widgets 73
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
lv_point_t vect;
lv_indev_get_vect(indev, &vect);
/**
* Make an object dragable.
*/
void lv_example_obj_2(void)
{
lv_obj_t * obj;
obj = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj, 150, 100);
lv_obj_add_event_cb(obj, drag_event_handler, LV_EVENT_PRESSING, NULL);
}
#endif
def drag_event_handler(e):
obj = e.get_target()
indev = lv.indev_get_act()
vect = lv.point_t()
indev.get_vect(vect)
x = obj.get_x() + vect.x
y = obj.get_y() + vect.y
obj.set_pos(x, y)
#
# Make an object dragable.
#
obj = lv.obj(lv.scr_act())
obj.set_size(150, 100)
obj.add_event_cb(drag_event_handler, lv.EVENT.PRESSING, None)
(continues on next page)
2.7. Widgets 74
LVGL Documentation 8.3
label = lv.label(obj)
label.set_text("Drag me")
label.center()
2.7.2 Arc
Simple Arc
#include "../../lv_examples.h"
void lv_example_arc_1(void)
{
lv_obj_t * label = lv_label_create(lv_scr_act());
/*Create an Arc*/
lv_obj_t * arc = lv_arc_create(lv_scr_act());
lv_obj_set_size(arc, 150, 150);
lv_arc_set_rotation(arc, 135);
lv_arc_set_bg_angles(arc, 0, 270);
lv_arc_set_value(arc, 10);
lv_obj_center(arc);
lv_obj_add_event_cb(arc, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, label);
#endif
# Create an Arc
arc = lv.arc(lv.scr_act())
arc.set_end_angle(200)
arc.set_size(150, 150)
arc.center()
2.7. Widgets 75
LVGL Documentation 8.3
#include "../../lv_examples.h"
/**
* Create an arc which acts as a loader.
*/
void lv_example_arc_2(void)
{
/*Create an Arc*/
lv_obj_t * arc = lv_arc_create(lv_scr_act());
lv_arc_set_rotation(arc, 270);
lv_arc_set_bg_angles(arc, 0, 360);
lv_obj_remove_style(arc, NULL, LV_PART_KNOB); /*Be sure the knob is not␣
,→displayed*/
lv_obj_center(arc);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, arc);
lv_anim_set_exec_cb(&a, set_angle);
lv_anim_set_time(&a, 1000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); /*Just for the demo*/
lv_anim_set_repeat_delay(&a, 500);
lv_anim_set_values(&a, 0, 100);
lv_anim_start(&a);
#endif
#
# An `lv_timer` to call periodically to set the angles of the arc
#
class ArcLoader():
def __init__(self):
self.a = 270
def arc_loader_cb(self,tim,arc):
# print(tim,arc)
self.a += 5
arc.set_end_angle(self.a)
2.7. Widgets 76
LVGL Documentation 8.3
# Create an Arc
arc = lv.arc(lv.scr_act())
arc.set_bg_angles(0, 360)
arc.set_angles(270, 270)
arc.center()
timer = lv.timer_create_basic()
timer.set_period(20)
timer.set_cb(lambda src: arc_loader.arc_loader_cb(timer,arc))
2.7.3 Bar
Simple Bar
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
void lv_example_bar_1(void)
{
lv_obj_t * bar1 = lv_bar_create(lv_scr_act());
lv_obj_set_size(bar1, 200, 20);
lv_obj_center(bar1);
lv_bar_set_value(bar1, 70, LV_ANIM_OFF);
}
#endif
bar1 = lv.bar(lv.scr_act())
bar1.set_size(200, 20)
bar1.center()
bar1.set_value(70, lv.ANIM.OFF)
2.7. Widgets 77
LVGL Documentation 8.3
Styling a bar
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Example of styling the bar
*/
void lv_example_bar_2(void)
{
static lv_style_t style_bg;
static lv_style_t style_indic;
lv_style_init(&style_bg);
lv_style_set_border_color(&style_bg, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_border_width(&style_bg, 2);
lv_style_set_pad_all(&style_bg, 6); /*To make the indicator smaller*/
lv_style_set_radius(&style_bg, 6);
lv_style_set_anim_time(&style_bg, 1000);
lv_style_init(&style_indic);
lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);
lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_radius(&style_indic, 3);
#endif
#
# Example of styling the bar
#
style_bg = lv.style_t()
style_indic = lv.style_t()
style_bg.init()
style_bg.set_border_color(lv.palette_main(lv.PALETTE.BLUE))
style_bg.set_border_width(2)
style_bg.set_pad_all(6) # To make the indicator smaller
style_bg.set_radius(6)
style_bg.set_anim_time(1000)
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_radius(3)
bar = lv.bar(lv.scr_act())
bar.remove_style_all() # To have a clean start
(continues on next page)
2.7. Widgets 78
LVGL Documentation 8.3
bar.set_size(200, 20)
bar.center()
bar.set_value(100, lv.ANIM.ON)
Temperature meter
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* A temperature meter example
*/
void lv_example_bar_3(void)
{
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);
lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_VER);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_exec_cb(&a, set_temp);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 3000);
lv_anim_set_var(&a, bar);
lv_anim_set_values(&a, -20, 40);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
}
#endif
#
(continues on next page)
2.7. Widgets 79
LVGL Documentation 8.3
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_indic.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_bg_grad_dir(lv.GRAD_DIR.VER)
bar = lv.bar(lv.scr_act())
bar.add_style(style_indic, lv.PART.INDICATOR)
bar.set_size(20, 200)
bar.center()
bar.set_range(-20, 40)
a = lv.anim_t()
a.init()
a.set_time(3000)
a.set_playback_time(3000)
a.set_var(bar)
a.set_values(-20, 40)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a.set_custom_exec_cb(lambda a, val: set_temp(bar,val))
lv.anim_t.start(a)
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Bar with stripe pattern and ranged value
*/
void lv_example_bar_4(void)
{
LV_IMG_DECLARE(img_skew_strip);
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_img_src(&style_indic, &img_skew_strip);
lv_style_set_bg_img_tiled(&style_indic, true);
lv_style_set_bg_img_opa(&style_indic, LV_OPA_30);
2.7. Widgets 80
LVGL Documentation 8.3
#endif
#
# get an icon
#
def get_icon(filename,xres,yres):
try:
sdl_filename = "../../assets/" + filename + "_" + str(xres) + "x" + str(yres)␣
,→+ "_argb8888.fnt"
icon_dsc = lv.img_dsc_t(
{
"header": {"always_zero": 0, "w": xres, "h": yres, "cf": lv.img.CF.TRUE_
,→COLOR_ALPHA},
"data": icon_data,
"data_size": len(icon_data),
}
)
return icon_dsc
#
# Bar with stripe pattern and ranged value
#
img_skew_strip_dsc = get_icon("img_skew_strip",80,20)
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_img_src(img_skew_strip_dsc)
style_indic.set_bg_img_tiled(True)
style_indic.set_bg_img_opa(lv.OPA._30)
bar = lv.bar(lv.scr_act())
bar.add_style(style_indic, lv.PART.INDICATOR)
bar.set_size(260, 20)
bar.center()
bar.set_mode(lv.bar.MODE.RANGE)
bar.set_value(90, lv.ANIM.OFF)
bar.set_start_value(20, lv.ANIM.OFF)
2.7. Widgets 81
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Bar with LTR and RTL base direction
*/
void lv_example_bar_5(void)
{
lv_obj_t * label;
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Left to Right base direction");
lv_obj_align_to(label, bar_ltr, LV_ALIGN_OUT_TOP_MID, 0, -5);
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Right to Left base direction");
lv_obj_align_to(label, bar_rtl, LV_ALIGN_OUT_TOP_MID, 0, -5);
}
#endif
#
# Bar with LTR and RTL base direction
#
bar_ltr = lv.bar(lv.scr_act())
bar_ltr.set_size(200, 20)
bar_ltr.set_value(70, lv.ANIM.OFF)
bar_ltr.align(lv.ALIGN.CENTER, 0, -30)
label = lv.label(lv.scr_act())
label.set_text("Left to Right base direction")
label.align_to(bar_ltr, lv.ALIGN.OUT_TOP_MID, 0, -5)
bar_rtl = lv.bar(lv.scr_act())
bar_rtl.set_style_base_dir(lv.BASE_DIR.RTL,0)
bar_rtl.set_size(200, 20)
bar_rtl.set_value(70, lv.ANIM.OFF)
bar_rtl.align(lv.ALIGN.CENTER, 0, 30)
label = lv.label(lv.scr_act())
label.set_text("Right to Left base direction")
label.align_to(bar_rtl, lv.ALIGN.OUT_TOP_MID, 0, -5)
2.7. Widgets 82
LVGL Documentation 8.3
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.font = LV_FONT_DEFAULT;
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d", (int)lv_bar_get_value(obj));
lv_point_t txt_size;
lv_txt_get_size(&txt_size, buf, label_dsc.font, label_dsc.letter_space, label_dsc.
,→line_space, LV_COORD_MAX,
label_dsc.flag);
lv_area_t txt_area;
/*If the indicator is long enough put the text inside on the right*/
if(lv_area_get_width(dsc->draw_area) > txt_size.x + 20) {
txt_area.x2 = dsc->draw_area->x2 - 5;
txt_area.x1 = txt_area.x2 - txt_size.x + 1;
label_dsc.color = lv_color_white();
}
/*If the indicator is still short put the text out of it on the right*/
else {
txt_area.x1 = dsc->draw_area->x2 + 5;
txt_area.x2 = txt_area.x1 + txt_size.x - 1;
label_dsc.color = lv_color_black();
}
/**
* Custom drawer on the bar to display the current value
*/
void lv_example_bar_6(void)
{
lv_obj_t * bar = lv_bar_create(lv_scr_act());
lv_obj_add_event_cb(bar, event_cb, LV_EVENT_DRAW_PART_END, NULL);
(continues on next page)
2.7. Widgets 83
LVGL Documentation 8.3
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, bar);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_exec_cb(&a, set_value);
lv_anim_set_time(&a, 2000);
lv_anim_set_playback_time(&a, 2000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
#endif
def event_cb(e):
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if dsc.part != lv.PART.INDICATOR:
return
obj= e.get_target()
label_dsc = lv.draw_label_dsc_t()
label_dsc.init()
# label_dsc.font = LV_FONT_DEFAULT;
value_txt = str(obj.get_value())
txt_size = lv.point_t()
lv.txt_get_size(txt_size, value_txt, label_dsc.font, label_dsc.letter_space,␣
,→label_dsc.line_space, lv.COORD.MAX, label_dsc.flag)
txt_area = lv.area_t()
# If the indicator is long enough put the text inside on the right
if dsc.draw_area.get_width() > txt_size.x + 20:
txt_area.x2 = dsc.draw_area.x2 - 5
txt_area.x1 = txt_area.x2 - txt_size.x + 1
label_dsc.color = lv.color_white()
# If the indicator is still short put the text out of it on the right*/
else:
txt_area.x1 = dsc.draw_area.x2 + 5
txt_area.x2 = txt_area.x1 + txt_size.x - 1
label_dsc.color = lv.color_black()
#
# Custom drawer on the bar to display the current value
#
(continues on next page)
2.7. Widgets 84
LVGL Documentation 8.3
bar = lv.bar(lv.scr_act())
bar.add_event_cb(event_cb, lv.EVENT.DRAW_PART_END, None)
bar.set_size(200, 20)
bar.center()
a = lv.anim_t()
a.init()
a.set_var(bar)
a.set_values(0, 100)
a.set_custom_exec_cb(lambda a,val: set_value(bar,val))
a.set_time(2000)
a.set_playback_time(2000)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a)
2.7.4 Button
Simple Buttons
#include "../../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
if(code == LV_EVENT_CLICKED) {
LV_LOG_USER("Clicked");
}
else if(code == LV_EVENT_VALUE_CHANGED) {
LV_LOG_USER("Toggled");
}
}
void lv_example_btn_1(void)
{
lv_obj_t * label;
label = lv_label_create(btn1);
lv_label_set_text(label, "Button");
lv_obj_center(label);
2.7. Widgets 85
LVGL Documentation 8.3
def event_handler(evt):
code = evt.get_code()
if code == lv.EVENT.CLICKED:
print("Clicked event seen")
elif code == lv.EVENT.VALUE_CHANGED:
print("Value changed seen")
btn1.align(lv.ALIGN.CENTER,0,-40)
label=lv.label(btn1)
label.set_text("Button")
btn2.align(lv.ALIGN.CENTER,0,40)
btn2.add_flag(lv.obj.FLAG.CHECKABLE)
btn2.set_height(lv.SIZE.CONTENT)
label=lv.label(btn2)
label.set_text("Toggle")
label.center()
Styling buttons
#include "../../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
/**
* Style a button from scratch
*/
void lv_example_btn_2(void)
{
/*Init the style for the default state*/
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 3);
(continues on next page)
2.7. Widgets 86
LVGL Documentation 8.3
lv_style_set_bg_opa(&style, LV_OPA_100);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_bg_grad_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 2));
lv_style_set_bg_grad_dir(&style, LV_GRAD_DIR_VER);
lv_style_set_border_opa(&style, LV_OPA_40);
lv_style_set_border_width(&style, 2);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_shadow_width(&style, 8);
lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_shadow_ofs_y(&style, 8);
lv_style_set_outline_opa(&style, LV_OPA_COVER);
lv_style_set_outline_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_text_color(&style, lv_color_white());
lv_style_set_pad_all(&style, 10);
lv_style_set_translate_y(&style_pr, 5);
lv_style_set_shadow_ofs_y(&style_pr, 3);
lv_style_set_bg_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 2));
lv_style_set_bg_grad_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 4));
lv_style_set_transition(&style_pr, &trans);
2.7. Widgets 87
LVGL Documentation 8.3
#
# Style a button from scratch
#
style.set_radius(3)
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_bg_grad_color(lv.palette_darken(lv.PALETTE.BLUE, 2))
style.set_bg_grad_dir(lv.GRAD_DIR.VER)
style.set_border_opa(lv.OPA._40)
style.set_border_width(2)
style.set_border_color(lv.palette_main(lv.PALETTE.GREY))
style.set_shadow_width(8)
style.set_shadow_color(lv.palette_main(lv.PALETTE.GREY))
style.set_shadow_ofs_y(8)
style.set_outline_opa(lv.OPA.COVER)
style.set_outline_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_text_color(lv.color_white())
style.set_pad_all(10)
style_pr.set_translate_y(5)
style_pr.set_shadow_ofs_y(3)
style_pr.set_bg_color(lv.palette_darken(lv.PALETTE.BLUE, 2))
style_pr.set_bg_grad_color(lv.palette_darken(lv.PALETTE.BLUE, 4))
style_pr.set_transition(trans)
btn1 = lv.btn(lv.scr_act())
btn1.remove_style_all() # Remove the style coming from the␣
,→theme
btn1.add_style(style, 0)
btn1.add_style(style_pr, lv.STATE.PRESSED)
btn1.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
btn1.center()
2.7. Widgets 88
LVGL Documentation 8.3
Gummy button
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN
/**
* Create a style transition on a button to act like a gum when clicked
*/
void lv_example_btn_3(void)
{
/*Properties to transition*/
static lv_style_prop_t props[] = {
LV_STYLE_TRANSFORM_WIDTH, LV_STYLE_TRANSFORM_HEIGHT, LV_STYLE_TEXT_LETTER_
,→SPACE, 0
};
2.7. Widgets 89
LVGL Documentation 8.3
#
# Create a style transition on a button to act like a gum when clicked
#
# Properties to transition
props = [lv.STYLE.TRANSFORM_WIDTH, lv.STYLE.TRANSFORM_HEIGHT, lv.STYLE.TEXT_LETTER_
,→SPACE, 0]
transition_dsc_def = lv.style_transition_dsc_t()
transition_dsc_def.init(props, lv.anim_t.path_overshoot, 250, 100, None)
btn1 = lv.btn(lv.scr_act())
btn1.align(lv.ALIGN.CENTER, 0, -80)
btn1.add_style(style_pr, lv.STATE.PRESSED)
btn1.add_style(style_def, 0)
label = lv.label(btn1)
label.set_text("Gum")
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
2.7. Widgets 90
LVGL Documentation 8.3
static const char * btnm_map[] = {"1", "2", "3", "4", "5", "\n",
"6", "7", "8", "9", "0", "\n",
"Action1", "Action2", ""
};
void lv_example_btnmatrix_1(void)
{
lv_obj_t * btnm1 = lv_btnmatrix_create(lv_scr_act());
lv_btnmatrix_set_map(btnm1, btnm_map);
lv_btnmatrix_set_btn_width(btnm1, 10, 2); /*Make "Action1" twice as wide␣
,→as "Action2"*/
#endif
def event_handler(evt):
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.VALUE_CHANGED :
id = obj.get_selected_btn()
txt = obj.get_btn_text(id)
btnm1 = lv.btnmatrix(lv.scr_act())
btnm1.set_map(btnm_map)
btnm1.set_btn_width(10, 2) # Make "Action1" twice as wide as "Action2"
btnm1.set_btn_ctrl(10, lv.btnmatrix.CTRL.CHECKABLE)
btnm1.set_btn_ctrl(11, lv.btnmatrix.CTRL.CHECKED)
btnm1.align(lv.ALIGN.CENTER, 0, 0)
btnm1.add_event_cb(event_handler, lv.EVENT.ALL, None)
#endif
2.7. Widgets 91
LVGL Documentation 8.3
Custom buttons
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
dsc->rect_dsc->shadow_width = 6;
dsc->rect_dsc->shadow_ofs_x = 3;
dsc->rect_dsc->shadow_ofs_y = 3;
dsc->label_dsc->color = lv_color_white();
}
/*Change the draw descriptor of the 3rd button*/
else if(dsc->id == 2) {
dsc->rect_dsc->radius = LV_RADIUS_CIRCLE;
if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) dsc->rect_dsc->bg_
,→color = lv_palette_darken(LV_PALETTE_RED, 3);
dsc->label_dsc->color = lv_color_white();
}
else if(dsc->id == 3) {
dsc->label_dsc->opa = LV_OPA_TRANSP; /*Hide the text if any*/
}
}
}
if(code == LV_EVENT_DRAW_PART_END) {
lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
lv_area_t a;
a.x1 = dsc->draw_area->x1 + (lv_area_get_width(dsc->draw_area) -␣
,→ header.w) / 2;
(continues on next page)
2.7. Widgets 92
LVGL Documentation 8.3
lv_draw_img_dsc_t img_draw_dsc;
lv_draw_img_dsc_init(&img_draw_dsc);
img_draw_dsc.recolor = lv_color_black();
if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) img_draw_dsc.
,→recolor_opa = LV_OPA_30;
/**
* Add custom drawer to the button matrix to customize buttons one by one
*/
void lv_example_btnmatrix_2(void)
{
lv_obj_t * btnm = lv_btnmatrix_create(lv_scr_act());
lv_obj_add_event_cb(btnm, event_cb, LV_EVENT_ALL, NULL);
lv_obj_center(btnm);
}
#endif
img_star_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def event_cb(e):
code = e.get_code()
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if code == lv.EVENT.DRAW_PART_BEGIN:
# Change the draw descriptor the 2nd button
if dsc.id == 1:
(continues on next page)
2.7. Widgets 93
LVGL Documentation 8.3
dsc.rect_dsc.shadow_width = 6
dsc.rect_dsc.shadow_ofs_x = 3
dsc.rect_dsc.shadow_ofs_y = 3
dsc.label_dsc.color = lv.color_white()
elif dsc.id == 2:
dsc.rect_dsc.radius = lv.RADIUS.CIRCLE
if obj.get_selected_btn() == dsc.id:
dsc.rect_dsc.bg_color = lv.palette_darken(lv.PALETTE.RED, 3)
else:
dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.RED)
dsc.label_dsc.color = lv.color_white()
elif dsc.id == 3:
dsc.label_dsc.opa = lv.OPA.TRANSP # Hide the text if any
if code == lv.EVENT.DRAW_PART_END:
# Add custom content to the 4th button when the button itself was drawn
if dsc.id == 3:
# LV_IMG_DECLARE(img_star)
header = lv.img_header_t()
res = lv.img.decoder_get_info(img_star_argb, header)
if res != lv.RES.OK:
print("error when getting image header")
return
else:
a = lv.area_t()
a.x1 = dsc.draw_area.x1 + (dsc.draw_area.get_width() - header.w) // 2
a.x2 = a.x1 + header.w - 1
a.y1 = dsc.draw_area.y1 + (dsc.draw_area.get_height() - header.h) // 2
a.y2 = a.y1 + header.h - 1
img_draw_dsc = lv.draw_img_dsc_t()
img_draw_dsc.init()
img_draw_dsc.recolor = lv.color_black()
if obj.get_selected_btn() == dsc.id:
img_draw_dsc.recolor_opa = lv.OPA._30
dsc.draw_ctx.img(img_draw_dsc, a, img_star_argb)
#
# Add custom drawer to the button matrix to c
#
btnm = lv.btnmatrix(lv.scr_act())
btnm.add_event_cb(event_cb, lv.EVENT.ALL, None)
btnm.center()
2.7. Widgets 94
LVGL Documentation 8.3
Pagination
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
lv_btnmatrix_set_btn_ctrl(obj, i, LV_BTNMATRIX_CTRL_CHECKED);
}
}
/**
* Make a button group (pagination)
*/
void lv_example_btnmatrix_3(void)
{
static lv_style_t style_bg;
lv_style_init(&style_bg);
lv_style_set_pad_all(&style_bg, 0);
lv_style_set_pad_gap(&style_bg, 0);
lv_style_set_clip_corner(&style_bg, true);
lv_style_set_radius(&style_bg, LV_RADIUS_CIRCLE);
lv_style_set_border_width(&style_bg, 0);
static const char * map[] = {LV_SYMBOL_LEFT, "1", "2", "3", "4", "5", LV_SYMBOL_
,→ RIGHT, ""};
2.7. Widgets 95
LVGL Documentation 8.3
lv_btnmatrix_set_one_checked(btnm, true);
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED);
lv_obj_center(btnm);
#endif
def event_cb(e):
obj = e.get_target()
id = obj.get_selected_btn()
if id == 0:
prev = True
else:
prev = False
if id == 6:
next = True
else:
next = False
if prev or next:
# Find the checked butto
for i in range(7):
if obj.has_btn_ctrl(i, lv.btnmatrix.CTRL.CHECKED):
break
if prev and i > 1:
i-=1
elif next and i < 5:
i+=1
obj.set_btn_ctrl(i, lv.btnmatrix.CTRL.CHECKED)
#
# Make a button group
#
style_bg = lv.style_t()
style_bg.init()
style_bg.set_pad_all(0)
style_bg.set_pad_gap(0)
style_bg.set_clip_corner(True)
style_bg.set_radius(lv.RADIUS.CIRCLE)
style_bg.set_border_width(0)
style_btn = lv.style_t()
style_btn.init()
style_btn.set_radius(0)
style_btn.set_border_width(1)
style_btn.set_border_opa(lv.OPA._50)
style_btn.set_border_color(lv.palette_main(lv.PALETTE.GREY))
(continues on next page)
2.7. Widgets 96
LVGL Documentation 8.3
btnm = lv.btnmatrix(lv.scr_act())
btnm.set_map(map)
btnm.add_style(style_bg, 0)
btnm.add_style(style_btn, lv.PART.ITEMS)
btnm.add_event_cb(event_cb, lv.EVENT.VALUE_CHANGED, None)
btnm.set_size(225, 35)
btnm.set_one_checked(True)
btnm.set_btn_ctrl(1, lv.btnmatrix.CTRL.CHECKED)
btnm.center()
2.7.6 Calendar
#include "../../lv_examples.h"
#if LV_USE_CALENDAR && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
lv_calendar_date_t date;
if(lv_calendar_get_pressed_date(obj, &date)) {
LV_LOG_USER("Clicked date: %02d.%02d.%d", date.day, date.month, date.
,→year);
}
}
}
void lv_example_calendar_1(void)
{
lv_obj_t * calendar = lv_calendar_create(lv_scr_act());
lv_obj_set_size(calendar, 185, 185);
lv_obj_align(calendar, LV_ALIGN_CENTER, 0, 27);
lv_obj_add_event_cb(calendar, event_handler, LV_EVENT_ALL, NULL);
2.7. Widgets 97
LVGL Documentation 8.3
highlighted_days[0].year = 2021;
highlighted_days[0].month = 02;
highlighted_days[0].day = 6;
highlighted_days[1].year = 2021;
highlighted_days[1].month = 02;
highlighted_days[1].day = 11;
highlighted_days[2].year = 2022;
highlighted_days[2].month = 02;
highlighted_days[2].day = 22;
#if LV_USE_CALENDAR_HEADER_DROPDOWN
lv_calendar_header_dropdown_create(calendar);
#elif LV_USE_CALENDAR_HEADER_ARROW
lv_calendar_header_arrow_create(calendar);
#endif
lv_calendar_set_showed_date(calendar, 2021, 10);
}
#endif
def event_handler(evt):
code = evt.get_code()
if code == lv.EVENT.VALUE_CHANGED:
source = evt.get_current_target()
date = lv.calendar_date_t()
if source.get_pressed_date(date) == lv.RES.OK:
calendar.set_today_date(date.year, date.month, date.day)
print("Clicked date: %02d.%02d.%02d"%(date.day, date.month, date.year))
calendar = lv.calendar(lv.scr_act())
calendar.set_size(200, 200)
calendar.align(lv.ALIGN.CENTER, 0, 20)
calendar.add_event_cb(event_handler, lv.EVENT.ALL, None)
calendar.set_highlighted_dates(highlighted_days, len(highlighted_days))
lv.calendar_header_dropdown(calendar)
2.7. Widgets 98
LVGL Documentation 8.3
2.7.7 Canvas
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
void lv_example_canvas_1(void)
{
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.radius = 10;
rect_dsc.bg_opa = LV_OPA_COVER;
rect_dsc.bg_grad.dir = LV_GRAD_DIR_HOR;
rect_dsc.bg_grad.stops[0].color = lv_palette_main(LV_PALETTE_RED);
rect_dsc.bg_grad.stops[1].color = lv_palette_main(LV_PALETTE_BLUE);
rect_dsc.border_width = 2;
rect_dsc.border_opa = LV_OPA_90;
rect_dsc.border_color = lv_color_white();
rect_dsc.shadow_width = 5;
rect_dsc.shadow_ofs_x = 5;
rect_dsc.shadow_ofs_y = 5;
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.color = lv_palette_main(LV_PALETTE_ORANGE);
lv_obj_center(canvas);
lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER);
/*Test the rotation. It requires another buffer where the original image is␣
,→ stored.
*So copy the current image to buffer and rotate it to the canvas*/
static lv_color_t cbuf_tmp[CANVAS_WIDTH * CANVAS_HEIGHT];
memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp));
lv_img_dsc_t img;
img.data = (void *)cbuf_tmp;
img.header.cf = LV_IMG_CF_TRUE_COLOR;
img.header.w = CANVAS_WIDTH;
img.header.h = CANVAS_HEIGHT;
2.7. Widgets 99
LVGL Documentation 8.3
#endif
_CANVAS_WIDTH = 200
_CANVAS_HEIGHT = 150
LV_IMG_ZOOM_NONE = 256
rect_dsc = lv.draw_rect_dsc_t()
rect_dsc.init()
rect_dsc.radius = 10
rect_dsc.bg_opa = lv.OPA.COVER
rect_dsc.bg_grad.dir = lv.GRAD_DIR.HOR
rect_dsc.bg_grad.stops[0].color = lv.palette_main(lv.PALETTE.RED)
rect_dsc.bg_grad.stops[1].color = lv.palette_main(lv.PALETTE.BLUE)
rect_dsc.border_width = 2
rect_dsc.border_opa = lv.OPA._90
rect_dsc.border_color = lv.color_white()
rect_dsc.shadow_width = 5
rect_dsc.shadow_ofs_x = 5
rect_dsc.shadow_ofs_y = 5
label_dsc = lv.draw_label_dsc_t()
label_dsc.init()
label_dsc.color = lv.palette_main(lv.PALETTE.YELLOW)
canvas = lv.canvas(lv.scr_act())
canvas.set_buffer(cbuf, _CANVAS_WIDTH, _CANVAS_HEIGHT, lv.img.CF.TRUE_COLOR)
canvas.center()
canvas.fill_bg(lv.palette_lighten(lv.PALETTE.GREY, 3), lv.OPA.COVER)
# Test the rotation. It requires another buffer where the original image is stored.
# So copy the current image to buffer and rotate it to the canvas
img = lv.img_dsc_t()
img.data = cbuf[:]
img.header.cf = lv.img.CF.TRUE_COLOR
img.header.w = _CANVAS_WIDTH
img.header.h = _CANVAS_HEIGHT
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Create a transparent canvas with Chroma keying and indexed color format (palette).
*/
void lv_example_canvas_2(void)
{
/*Create a button to better see the transparency*/
lv_btn_create(lv_scr_act());
lv_canvas_set_palette(canvas, 0, LV_COLOR_CHROMA_KEY);
lv_canvas_set_palette(canvas, 1, lv_palette_main(LV_PALETTE_RED));
c0.full = 0;
c1.full = 1;
}
#endif
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_CHROMA_KEY = lv.color_hex(0x00ff00)
#
# Create a transparent canvas with Chroma keying and indexed color format (palette).
#
c0.full = 0
c1.full = 1
canvas.fill_bg(c1, lv.OPA.COVER)
2.7.8 Chart
Line Chart
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
void lv_example_chart_1(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
#endif
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.LINE) # Show lines and points too
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
/*Add a line mask that keeps the area below the line*/
lv_draw_mask_line_param_t line_mask_param;
lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->
,→p2->x, dsc->p2->y,
LV_DRAW_MASK_LINE_SIDE_BOTTOM);
int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);
obj->coords.y2);
int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);
lv_area_t a;
a.x1 = dsc->p1->x;
a.x2 = dsc->p2->x - 1;
a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
a.y2 = obj->coords.y2;
lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);
/*Vertical line*/
if(dsc->p1->x == dsc->p2->x) {
dsc->line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1);
if(dsc->id == 3) {
dsc->line_dsc->width = 2;
dsc->line_dsc->dash_gap = 0;
dsc->line_dsc->dash_width = 0;
}
else {
dsc->line_dsc->width = 1;
dsc->line_dsc->dash_gap = 6;
dsc->line_dsc->dash_width = 6;
}
}
/*Horizontal line*/
else {
if(dsc->id == 2) {
dsc->line_dsc->width = 2;
dsc->line_dsc->dash_gap = 0;
dsc->line_dsc->dash_width = 0;
}
else {
dsc->line_dsc->width = 2;
dsc->line_dsc->dash_gap = 6;
dsc->line_dsc->dash_width = 6;
}
if(dsc->id == 1 || dsc->id == 3) {
dsc->line_dsc->color = lv_palette_main(LV_PALETTE_GREEN);
}
else {
dsc->line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1);
}
}
}
}
cnt++;
}
/**
* Add a faded area effect to the line chart and make some division lines ticker
(continues on next page)
lv_chart_set_div_line_count(chart1, 5, 7);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90));
lv_chart_set_next_value(chart1, ser2, lv_rand(30, 70));
}
#endif
def draw_event_cb(e):
obj = e.get_target()
# Add a line mask that keeps the area below the line
line_mask_param = lv.draw_mask_line_param_t()
line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_MASK_
,→LINE_SIDE.BOTTOM)
# line_mask_id = line_mask_param.draw_mask_add(None)
line_mask_id = lv.draw_mask_add(line_mask_param, None)
# Add a fade effect: transparent bottom covering top
h = obj.get_height()
fade_mask_param = lv.draw_mask_fade_param_t()
coords = lv.area_t()
obj.get_coords(coords)
fade_mask_param.init(coords, lv.OPA.COVER, coords.y1 + h // 8, lv.OPA.TRANSP,
,→coords.y2)
fade_mask_id = lv.draw_mask_add(fade_mask_param,None)
(continues on next page)
a = lv.area_t()
a.x1 = dsc.p1.x
a.x2 = dsc.p2.x - 1
a.y1 = min(dsc.p1.y, dsc.p2.y)
coords = lv.area_t()
obj.get_coords(coords)
a.y2 = coords.y2
dsc.draw_ctx.rect(draw_rect_dsc, a)
def add_data(timer):
# LV_UNUSED(timer);
cnt = 0
chart1.set_next_value(ser1, lv.rand(20, 90))
if cnt % 4 == 0:
chart1.set_next_value(ser2, lv.rand(40, 60))
cnt +=1
#
# Add a faded area effect to the line chart
#
# Create a chart1
chart1 = lv.chart(lv.scr_act())
chart1.set_size(200, 150)
chart1.center()
chart1.set_type(lv.chart.TYPE.LINE) # Show lines and points too
for i in range(10):
chart1.set_next_value(ser1, lv.rand(20, 90))
chart1.set_next_value(ser2, lv.rand(30, 70))
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
/**
* Add ticks and labels to the axis and demonstrate scrolling
*/
void lv_example_chart_3(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 400);
lv_chart_set_point_count(chart, 12);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
LV_CHART_AXIS_SECONDARY_Y);
#endif
def draw_event_cb(e):
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if dsc.part == lv.PART.TICKS and dsc.id == lv.chart.AXIS.PRIMARY_X:
month = ["Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept",
,→"Oct", "Nov", "Dec"]
dsc.text = bytes(month[dsc.value],"ascii")
#
# Add ticks and labels to the axis and demonstrate scrolling
#
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.BAR)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 100)
chart.set_range(lv.chart.AXIS.SECONDARY_Y, 0, 400)
chart.set_point_count(12)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
# Zoom in a little in X
chart.set_zoom_x(800)
(continues on next page)
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_invalidate(chart);
}
if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
lv_coord_t * s = lv_event_get_param(e);
*s = LV_MAX(*s, 20);
}
else if(code == LV_EVENT_DRAW_POST_END) {
int32_t id = lv_chart_get_pressed_point(chart);
if(id == LV_CHART_POINT_NONE) return;
char buf[16];
lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"$%d", value);
lv_draw_rect_dsc_t draw_rect_dsc;
lv_draw_rect_dsc_init(&draw_rect_dsc);
draw_rect_dsc.bg_color = lv_color_black();
draw_rect_dsc.bg_opa = LV_OPA_50;
draw_rect_dsc.radius = 3;
draw_rect_dsc.bg_img_src = buf;
draw_rect_dsc.bg_img_recolor = lv_color_white();
lv_area_t a;
a.x1 = chart->coords.x1 + p.x - 20;
a.x2 = chart->coords.x1 + p.x + 20;
a.y1 = chart->coords.y1 + p.y - 30;
a.y2 = chart->coords.y1 + p.y - 10;
/**
* Show the value of the pressed points
*/
void lv_example_chart_4(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart, ser1, lv_rand(60, 90));
lv_chart_set_next_value(chart, ser2, lv_rand(10, 40));
(continues on next page)
#endif
def event_cb(e):
code = e.get_code()
chart = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
chart.invalidate()
if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
e.set_ext_draw_size(20)
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
draw_rect_dsc.bg_color = lv.color_black()
draw_rect_dsc.bg_opa = lv.OPA._50
draw_rect_dsc.radius = 3
draw_rect_dsc.bg_img_src = buf
draw_rect_dsc.bg_img_recolor = lv.color_white()
a = lv.area_t()
coords = lv.area_t()
chart.get_coords(coords)
a.x1 = coords.x1 + p.x - 20
a.x2 = coords.x1 + p.x + 20
a.y1 = coords.y1 + p.y - 30
a.y2 = coords.y1 + p.y - 10
clip_area = lv.area_t.__cast__(e.get_param())
lv.draw_rect(a, clip_area, draw_rect_dsc)
#
# Add ticks and labels to the axis and demonstrate scrolling
#
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
(continues on next page)
# Zoom in a little in X
chart.set_zoom_x(800)
ser1_p = []
ser2_p = []
for i in range(10):
ser1_p.append(lv.rand(60,90))
ser2_p.append(lv.rand(10,40))
ser1.y_points = ser1_p
ser2.y_points = ser2_p
series = [ser1,ser2]
series_points=[ser1_p,ser2_p]
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_USE_SLIDER && LV_BUILD_EXAMPLES
-112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10,␣
,→4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25,␣
,→14, 15, 19, 28, 31, 26, 23, 25, 31,
39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33,␣
,→19, -1, -27, -55, -67, -72, -71, -63,
-49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288,␣
,→274, 255, 212, 173, 143, 117, 82, 39,
-13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -
,→123, -123, -129, -139, -148, -153,
-159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -
,→473, -517, -556, -592, -612, -620,
-620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -
,→222, -167, -114, -70, -47, -28, -4, 12,
38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89,␣
,→88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115,␣
,→110, 96, 85, 73, 64, 69, 76, 79,
78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67,␣
,→73, 79, 74, 63, 57, 56, 58, 61, 55,
48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34,␣
,→30, 36, 34, 42, 38, 36, 40, 46, 50, (continues on next page)
24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -
,→3, -11, -20, -47, -100, -194, -236,
-212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27,␣
,→19, 17, 21, 20, 19, 19, 22, 36, 40,
35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -
,→5, -10, -19, -32, -42, -55, -60,
-68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -
,→50, -45, -35, -20, -3, 12, 20, 25,
26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9,␣
,→9, -3, -1, -18, -50, -108, -190,
-272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60,
,→ 58, 103, 129, 139, 155, 170, 173,
178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226,␣
,→224, 232, 233, 232, 224, 219, 219,
223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283,␣
,→271, 263, 252, 243, 226, 210, 197,
186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7,
,→ -11, -14, -18, -29, -37, -44, -50,
-58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -
,→52, -59, -69, -76, -76, -69, -67,
-74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -
,→17, -13, -10, -11, -13, -20, -20,
-12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21,␣
,→20, 18, 19, 19, 19, 16, 15, 13, 14,
14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -
,→18, -16, -9, -4, -5, -10, -9, -8,
-3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -
,→33, -19, 0, 17, 24, 9, -17, -47,
-63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -
,→8, 5, 18, 27, 32, 26, 25, 26, 22,
23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131,␣
,→114, 87, 60, 42, 29, 26, 34, 35, 34,
25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -
,→26, -25, -21, -15, -10, -13, -13,
-19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119,␣
,→-124, -129, -132, -146, -146, -138,
-124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2,␣
,→4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7,␣
,→12, 17, 11, 0, -6, -9, -8, -7, -5,
-6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -
,→60, -67, -65, -54, -35, -11, 30,
84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239,␣
,→197, 163, 136, 109, 77, 34, -18, -50,
-66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -
,→171, -169, -174, -175, -178, -191,
-202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -
,→565, -596, -619, -623, -623, -614,
-599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96,
,→ -57, -29, -8, 10, 31, 45, 60, 65,
/**
* Display 1000 data points with zooming and scrolling.
* See how the chart changes drawing mode (draw only vertical lines) when
* the points get too crowded.
*/
void lv_example_chart_5(void)
{
/*Create a chart*/
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, -30, -30);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -1000, 1000);
lv_obj_t * slider;
slider = lv_slider_create(lv_scr_act());
lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
lv_obj_add_event_cb(slider, slider_x_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_size(slider, 200, 10);
lv_obj_align_to(slider, chart, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
slider = lv_slider_create(lv_scr_act());
lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
lv_obj_add_event_cb(slider, slider_y_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_size(slider, 10, 150);
lv_obj_align_to(slider, chart, LV_ALIGN_OUT_RIGHT_MID, 20, 0);
}
#endif
# Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/
,→642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv
ecg_sample = [
(continues on next page)
-112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10,␣
,→4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25,␣
,→14, 15, 19, 28, 31, 26, 23, 25, 31,
39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33,␣
,→19, -1, -27, -55, -67, -72, -71, -63,
-49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288,␣
,→274, 255, 212, 173, 143, 117, 82, 39,
-13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -
,→123, -123, -129, -139, -148, -153,
-159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -
,→473, -517, -556, -592, -612, -620,
-620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -
,→222, -167, -114, -70, -47, -28, -4, 12,
38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89,␣
,→88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115,␣
,→110, 96, 85, 73, 64, 69, 76, 79,
78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67,␣
,→73, 79, 74, 63, 57, 56, 58, 61, 55,
48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34,␣
,→30, 36, 34, 42, 38, 36, 40, 46, 50,
47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -
,→32, -31, -19, -5, 3, 9, 13, 19,
24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -
,→3, -11, -20, -47, -100, -194, -236,
-212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27,␣
,→19, 17, 21, 20, 19, 19, 22, 36, 40,
35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -
,→5, -10, -19, -32, -42, -55, -60,
-68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -
,→50, -45, -35, -20, -3, 12, 20, 25,
26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9,␣
,→9, -3, -1, -18, -50, -108, -190,
-272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60,
,→ 58, 103, 129, 139, 155, 170, 173,
178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226,␣
,→224, 232, 233, 232, 224, 219, 219,
223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283,␣
,→271, 263, 252, 243, 226, 210, 197,
186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7,
,→ -11, -14, -18, -29, -37, -44, -50,
-58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -
,→52, -59, -69, -76, -76, -69, -67,
-74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -
,→17, -13, -10, -11, -13, -20, -20,
-12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21,␣
,→20, 18, 19, 19, 19, 16, 15, 13, 14,
14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -
,→18, -16, -9, -4, -5, -10, -9, -8,
-3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -
,→33, -19, 0, 17, 24, 9, -17, -47,
-63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -
,→8, 5, 18, 27, 32, 26, 25, 26, 22, (continues on next page)
25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -
,→26, -25, -21, -15, -10, -13, -13,
-19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119,␣
,→-124, -129, -132, -146, -146, -138,
-124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2,␣
,→4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7,␣
,→12, 17, 11, 0, -6, -9, -8, -7, -5,
-6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -
,→60, -67, -65, -54, -35, -11, 30,
84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239,␣
,→197, 163, 136, 109, 77, 34, -18, -50,
-66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -
,→171, -169, -174, -175, -178, -191,
-202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -
,→565, -596, -619, -623, -623, -614,
-599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96,
,→ -57, -29, -8, 10, 31, 45, 60, 65,
def slider_x_event_cb(e):
slider = e.get_target()
v = slider.get_value()
chart.set_zoom_x(v)
def slider_y_event_cb(e):
slider = e.get_target()
v = slider.get_value()
chart.set_zoom_y(v)
#
# Display 1000 data points with zooming and scrolling.
# See how the chart changes drawing mode (draw only vertical lines) when
# the points get too crowded.
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, -30, -30)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, -1000, 1000)
pcnt = len(ecg_sample)
chart.set_point_count(pcnt)
chart.set_ext_y_array(ser, ecg_sample)
slider = lv.slider(lv.scr_act())
(continues on next page)
slider = lv.slider(lv.scr_act())
slider.set_range(lv.IMG_ZOOM.NONE, lv.IMG_ZOOM.NONE * 10)
slider.add_event_cb(slider_y_event_cb, lv.EVENT.VALUE_CHANGED, None)
slider.set_size(10, 150)
slider.align_to(chart, lv.ALIGN.OUT_RIGHT_MID, 20, 0)
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
last_id = lv_chart_get_pressed_point(obj);
if(last_id != LV_CHART_POINT_NONE) {
lv_chart_set_cursor_point(obj, cursor, NULL, last_id);
}
}
else if(code == LV_EVENT_DRAW_PART_END) {
lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
if(!lv_obj_draw_part_check_type(dsc, &lv_chart_class, LV_CHART_DRAW_PART_
,→CURSOR)) return;
lv_point_t size;
lv_txt_get_size(&size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_
,→ NONE);
lv_area_t a;
a.y2 = dsc->p1->y - 5;
a.y1 = a.y2 - size.y - 10;
a.x1 = dsc->p1->x + 10;
a.x2 = a.x1 + size.x + 10;
lv_draw_label_dsc_t draw_label_dsc;
lv_draw_label_dsc_init(&draw_label_dsc);
draw_label_dsc.color = lv_color_white();
a.x1 += 5;
a.x2 -= 5;
a.y1 += 5;
a.y2 -= 5;
lv_draw_label(dsc->draw_ctx, &draw_label_dsc, &a, buf, NULL);
}
}
/**
* Show cursor on the clicked point
*/
void lv_example_chart_6(void)
{
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, -10);
lv_chart_set_zoom_x(chart, 500);
#endif
class ExampleChart_6():
def __init__(self):
self.last_id = -1
(continues on next page)
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, 0, -10)
self.ser_p = []
for i in range(10):
self.ser_p.append(lv.rand(10,90))
self.ser.y_points = self.ser_p
newser = chart.get_series_next(None)
# print("length of data points: ",len(newser.points))
chart.set_zoom_x(500)
label = lv.label(lv.scr_act())
label.set_text("Click on a point")
label.align_to(chart, lv.ALIGN.OUT_TOP_MID, 0, -5)
def event_cb(self,e):
code = e.get_code()
chart = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
# print("last_id: ",self.last_id)
self.last_id = chart.get_pressed_point()
if self.last_id != lv.CHART_POINT.NONE:
p = lv.point_t()
chart.get_point_pos_by_id(self.ser, self.last_id, p)
chart.set_cursor_point(self.cursor, None, self.last_id)
# print("value: ",v)
value_txt = str(v)
size = lv.point_t()
lv.txt_get_size(size, value_txt, lv.font_default(), 0, 0, lv.COORD.
,→MAX, lv.TEXT_FLAG.NONE)
a = lv.area_t()
a.y2 = dsc.p1.y - 5
a.y1 = a.y2 - size.y - 10
a.x1 = dsc.p1.x + 10
a.x2 = a.x1 + size.x + 10
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
draw_rect_dsc.bg_color = lv.palette_main(lv.PALETTE.BLUE)
draw_rect_dsc.radius = 3
draw_label_dsc = lv.draw_label_dsc_t()
draw_label_dsc.init()
draw_label_dsc.color = lv.color_white()
a.x1 += 5
a.x2 -= 5
a.y1 += 5
a.y2 -= 5
lv.draw_label(a, dsc.clip_area, draw_label_dsc, value_txt, None)
example_chart_6 = ExampleChart_6()
Scatter chart
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED),
lv_palette_main(LV_PALETTE_BLUE),
x_opa + y_opa);
}
}
/**
* A scatter chart
*/
void lv_example_chart_7(void)
{
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS); /*Remove the lines*/
lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);
lv_chart_set_point_count(chart, 50);
#endif
#!/opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
def draw_event_cb(e):
(continues on next page)
# print("p_act", p_act)
x_opa = (x_array[p_act] * lv.OPA._50) // 200
y_opa = (y_array[p_act] * lv.OPA._50) // 1000
dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.RED).color_mix(
lv.palette_main(lv.PALETTE.BLUE),
x_opa + y_opa)
def add_data(timer,chart):
# print("add_data")
x = lv.rand(0,200)
y = lv.rand(0,1000)
chart.set_next_value2(ser, x, y)
# chart.set_next_value2(chart.gx, y)
x_array.pop(0)
x_array.append(x)
y_array.pop(0)
y_array.append(y)
#
# A scatter chart
#
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, 0, 0)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
chart.set_style_line_width(0, lv.PART.ITEMS) # Remove the lines
chart.set_type(lv.chart.TYPE.SCATTER)
chart.set_range(lv.chart.AXIS.PRIMARY_X, 0, 200)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 1000)
chart.set_point_count(50)
x_array = []
y_array = []
for i in range(50):
x_array.append(lv.rand(0, 200))
y_array.append(lv.rand(0, 1000))
ser.x_points = x_array
ser.y_points = y_array
timer = lv.timer_create_basic()
timer.set_period(100)
timer.set_cb(lambda src: add_data(timer,chart))
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
/* A struct is used to keep track of the series list because later we need to draw␣
,→to the series in the reverse order to which they were initialised. */
typedef struct {
lv_obj_t * obj;
lv_chart_series_t * series_list[3];
} stacked_area_chart_t;
/**
* Callback which draws the blocks of colour under the lines
**/
static void draw_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
/*Add a line mask that keeps the area below the line*/
lv_draw_mask_line_param_t line_mask_param;
lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->
,→p2->x, dsc->p2->y,
LV_DRAW_MASK_LINE_SIDE_BOTTOM);
int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);
lv_area_t a;
a.x1 = dsc->p1->x;
a.x2 = dsc->p2->x;
a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
a.y2 = obj->coords.y2 -
13; /* -13 cuts off where the rectangle draws over the chart margin.␣
,→Without this an area of 0 doesn't look like 0 */
/**
* Helper function to round a fixed point number
**/
static int32_t round_fixed_point(int32_t n, int8_t shift)
{
/* Create a bitmask to isolates the decimal part of the fixed point number */
int32_t mask = 1;
for(int32_t bit_pos = 0; bit_pos < shift; bit_pos++) {
mask = (mask << 1) + 1;
}
/**
* Stacked area chart
*/
void lv_example_chart_8(void)
{
/*Create a stacked_area_chart.obj*/
stacked_area_chart.obj = lv_chart_create(lv_scr_act());
lv_obj_set_size(stacked_area_chart.obj, 200, 150);
lv_obj_center(stacked_area_chart.obj);
lv_chart_set_type(stacked_area_chart.obj, LV_CHART_TYPE_LINE);
lv_chart_set_div_line_count(stacked_area_chart.obj, 5, 7);
lv_obj_add_event_cb(stacked_area_chart.obj, draw_event_cb, LV_EVENT_DRAW_PART_
,→BEGIN, NULL);
LV_CHART_AXIS_PRIMARY_Y);
stacked_area_chart.series_list[1] = lv_chart_add_series(stacked_area_chart.obj,␣
,→lv_palette_main(LV_PALETTE_BLUE),
LV_CHART_AXIS_PRIMARY_Y);
stacked_area_chart.series_list[2] = lv_chart_add_series(stacked_area_chart.obj,␣
,→lv_palette_main(LV_PALETTE_GREEN),
LV_CHART_AXIS_PRIMARY_Y);
int8_t fixed_point_shift = 5;
uint32_t total = vals[0] + vals[1] + vals[2];
uint32_t draw_heights[3];
uint32_t int_sum = 0;
uint32_t decimal_sum = 0;
/* The draw heights are equal to the percentage of the total each value␣
,→ is + the cumulative sum of the previous percentages.
The accumulation is how the values get "stacked" */
draw_heights[series_index] = int_sum + modifier;
draw_heights[series_index]);
}
}
lv_chart_refresh(stacked_area_chart.obj);
}
#endif
import display_driver
import lvgl as lv
(continues on next page)
stacked_area_chart = StackedAreaChart()
#
# Callback which draws the blocks of colour under the lines
#
def draw_event_cb(e):
obj = e.get_target()
cont_a = lv.area_t()
obj.get_coords(cont_a)
# Add a line mask that keeps the area below the line
line_mask_param = lv.draw_mask_line_param_t()
line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_
,→MASK_LINE_SIDE.BOTTOM)
a = lv.area_t()
a.x1 = dsc.p1.x
a.x2 = dsc.p2.x
a.y1 = min(dsc.p1.y, dsc.p2.y)
a.y2 = cont_a.y2 - 13 # -13 cuts off where the rectangle draws over the chart␣
,→margin. Without this an area of 0 doesn't look like 0
dsc.draw_ctx.rect(draw_rect_dsc, a)
#
# Helper function to round a fixed point number
#
def round_fixed_point(n, shift):
# Create a bitmask to isolates the decimal part of the fixed point number
mask = 1
for bit_pos in range(shift):
(continues on next page)
#
# Stacked area chart
#
def lv_example_chart_8():
#Create a stacked_area_chart.obj
stacked_area_chart.obj = lv.chart(lv.scr_act())
stacked_area_chart.obj.set_size(200, 150)
stacked_area_chart.obj.center()
stacked_area_chart.obj.set_type( lv.chart.TYPE.LINE)
stacked_area_chart.obj.set_div_line_count(5, 7)
stacked_area_chart.obj.add_event_cb( draw_event_cb, lv.EVENT.DRAW_PART_BEGIN,␣
,→None)
stacked_area_chart.series_list[1] = stacked_area_chart.obj.add_series(lv.palette_
,→main(lv.PALETTE.BLUE), lv.chart.AXIS.PRIMARY_Y)
stacked_area_chart.series_list[2] = stacked_area_chart.obj.add_series(lv.palette_
,→main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)
fixed_point_shift = 5
total = vals[0] + vals[1] + vals[2]
draw_heights = [0, 0, 0]
int_sum = 0
decimal_sum = 0
# The draw heights are equal to the percentage of the total each value␣
,→ is + the cumulative sum of the previous percentages.
# The accumulation is how the values get "stacked"
draw_heights[series_index] = int(int_sum + modifier)
# Draw to the series in the reverse order to which they were initialised.
# Without this the higher values will draw on top of the lower ones.
# This is because the Z-height of a series matches the order it was␣
,→initialised
stacked_area_chart.obj.set_next_value( stacked_area_chart.series_list[3 -␣
,→series_index - 1], draw_heights[series_index])
stacked_area_chart.obj.refresh()
lv_example_chart_8()
2.7.9 Checkbox
Simple Checkboxes
#include "../../lv_examples.h"
#if LV_USE_CHECKBOX && LV_BUILD_EXAMPLES
void lv_example_checkbox_1(void)
{
lv_obj_set_flex_flow(lv_scr_act(), LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(lv_scr_act(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_
,→FLEX_ALIGN_CENTER);
lv_obj_t * cb;
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Apple");
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Banana");
lv_obj_add_state(cb, LV_STATE_CHECKED);
(continues on next page)
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Lemon");
lv_obj_add_state(cb, LV_STATE_DISABLED);
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(lv_scr_act());
lv_obj_add_state(cb, LV_STATE_CHECKED | LV_STATE_DISABLED);
lv_checkbox_set_text(cb, "Melon\nand a new line");
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
lv_obj_update_layout(cb);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
txt = obj.get_text()
if obj.get_state() & lv.STATE.CHECKED:
state = "Checked"
else:
state = "Unchecked"
print(txt + ":" + state)
lv.scr_act().set_flex_flow(lv.FLEX_FLOW.COLUMN)
lv.scr_act().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.
,→CENTER)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Apple")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Banana")
cb.add_state(lv.STATE.CHECKED)
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Lemon")
cb.add_state(lv.STATE.DISABLED)
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
cb.set_text("Melon")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb.update_layout()
#include "../../lv_examples.h"
#if LV_USE_CHECKBOX && LV_BUILD_EXAMPLES
*active_id = lv_obj_get_index(act_cb);
/**
* Checkboxes as radio buttons
*/
void lv_example_checkbox_2(void)
{
/* The idea is to enable `LV_OBJ_FLAG_EVENT_BUBBLE` on checkboxes and process the
* `LV_EVENT_CLICKED` on the container.
* A variable is passed as event user data where the index of the active
* radiobutton is saved */
lv_style_init(&style_radio);
lv_style_set_radius(&style_radio, LV_RADIUS_CIRCLE);
lv_style_init(&style_radio_chk);
lv_style_set_bg_img_src(&style_radio_chk, NULL);
uint32_t i;
(continues on next page)
}
/*Make the first checkbox checked*/
lv_obj_add_state(lv_obj_get_child(cont1, 0), LV_STATE_CHECKED);
#endif
2.7.10 Colorwheel
Simple Colorwheel
#include "../../lv_examples.h"
#if LV_USE_COLORWHEEL && LV_BUILD_EXAMPLES
void lv_example_colorwheel_1(void)
{
lv_obj_t * cw;
cw = lv_colorwheel_create(lv_scr_act(), true);
lv_obj_set_size(cw, 200, 200);
lv_obj_center(cw);
}
#endif
cw = lv.colorwheel(lv.scr_act(), True)
cw.set_size(200, 200)
cw.center()
2.7.11 Dropdown
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
void lv_example_dropdown_1(void)
{
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
option = " "*10 # should be large enough to store the option
obj.get_selected_str(option, len(option))
# .strip() removes trailing spaces
print("Option: \"%s\"" % option.strip())
dd.align(lv.ALIGN.TOP_MID, 0, 20)
dd.add_event_cb(event_handler, lv.EVENT.ALL, None)
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
/**
* Create a drop down, up, left and right menus
*/
void lv_example_dropdown_2(void)
{
static const char * opts = "Apple\n"
"Banana\n"
"Orange\n"
"Melon";
lv_obj_t * dd;
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_obj_align(dd, LV_ALIGN_TOP_MID, 0, 10);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_BOTTOM);
lv_dropdown_set_symbol(dd, LV_SYMBOL_UP);
lv_obj_align(dd, LV_ALIGN_BOTTOM_MID, 0, -10);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_RIGHT);
lv_dropdown_set_symbol(dd, LV_SYMBOL_RIGHT);
lv_obj_align(dd, LV_ALIGN_LEFT_MID, 10, 0);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_LEFT);
lv_dropdown_set_symbol(dd, LV_SYMBOL_LEFT);
lv_obj_align(dd, LV_ALIGN_RIGHT_MID, -10, 0);
(continues on next page)
#endif
#
# Create a drop down, up, left and right menus
#
opts = "\n".join([
"Apple",
"Banana",
"Orange",
"Melon",
"Grape",
"Raspberry"])
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.align(lv.ALIGN.TOP_MID, 0, 10)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.set_dir(lv.DIR.BOTTOM)
dd.set_symbol(lv.SYMBOL.UP)
dd.align(lv.ALIGN.BOTTOM_MID, 0, -10)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.set_dir(lv.DIR.RIGHT)
dd.set_symbol(lv.SYMBOL.RIGHT)
dd.align(lv.ALIGN.LEFT_MID, 10, 0)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.set_dir(lv.DIR.LEFT)
dd.set_symbol(lv.SYMBOL.LEFT)
dd.align(lv.ALIGN.RIGHT_MID, -10, 0)
Menu
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
/**
* Create a menu from a drop-down list and show some drop-down list features and␣
,→styling
(continues on next page)
/*Use a custom image as down icon and flip it when the list is opened*/
LV_IMG_DECLARE(img_caret_down)
lv_dropdown_set_symbol(dropdown, &img_caret_down);
lv_obj_set_style_transform_angle(dropdown, 1800, LV_PART_INDICATOR | LV_STATE_
,→CHECKED);
#endif
img_caret_down_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def event_cb(e):
dropdown = e.get_target()
option = " "*64 # should be large enough to store the option
dropdown.get_selected_str(option, len(option))
(continues on next page)
# Use a custom image as down icon and flip it when the list is opened
# LV_IMG_DECLARE(img_caret_down)
dropdown.set_symbol(img_caret_down_argb)
dropdown.set_style_transform_angle(1800, lv.PART.INDICATOR | lv.STATE.CHECKED)
2.7.12 Image
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
void lv_example_img_1(void)
{
LV_IMG_DECLARE(img_cogwheel_argb);
lv_obj_t * img1 = lv_img_create(lv_scr_act());
lv_img_set_src(img1, &img_cogwheel_argb);
lv_obj_align(img1, LV_ALIGN_CENTER, 0, -20);
lv_obj_set_size(img1, 200, 200);
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
img1 = lv.img(lv.scr_act())
img1.set_src(img_cogwheel_argb)
img1.align(lv.ALIGN.CENTER, 0, -20)
img1.set_size(200, 200)
img2 = lv.img(lv.scr_act())
img2.set_src(lv.SYMBOL.OK + "Accept")
img2.align_to(img1, lv.ALIGN.OUT_BOTTOM_MID, 0, 20)
Image recoloring
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Demonstrate runtime image re-coloring
*/
void lv_example_img_2(void)
{
/*Create 4 sliders to adjust RGB color and re-color intensity*/
red_slider = create_slider(lv_palette_main(LV_PALETTE_RED));
green_slider = create_slider(lv_palette_main(LV_PALETTE_GREEN));
blue_slider = create_slider(lv_palette_main(LV_PALETTE_BLUE));
intense_slider = create_slider(lv_palette_main(LV_PALETTE_GREY));
lv_slider_get_value(blue_slider));
lv_opa_t intense = lv_slider_get_value(intense_slider);
lv_obj_set_style_img_recolor_opa(img1, intense, 0);
lv_obj_set_style_img_recolor(img1, color, 0);
}
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def create_slider(color):
slider = lv.slider(lv.scr_act())
slider.set_range(0, 255)
slider.set_size(10, 200)
slider.set_style_bg_color(color, lv.PART.KNOB)
slider.set_style_bg_color(color.color_darken(lv.OPA._40), lv.PART.INDICATOR)
slider.add_event_cb(slider_event_cb, lv.EVENT.VALUE_CHANGED, None)
return slider
def slider_event_cb(e):
# Recolor the image based on the sliders' values
color = lv.color_make(red_slider.get_value(), green_slider.get_value(), blue_
,→slider.get_value())
intense = intense_slider.get_value()
img1.set_style_img_recolor_opa(intense, 0)
img1.set_style_img_recolor(color, 0)
#
# Demonstrate runtime image re-coloring
#
# Create 4 sliders to adjust RGB color and re-color intensity
red_slider = create_slider(lv.palette_main(lv.PALETTE.RED))
green_slider = create_slider(lv.palette_main(lv.PALETTE.GREEN))
blue_slider = create_slider(lv.palette_main(lv.PALETTE.BLUE))
intense_slider = create_slider(lv.palette_main(lv.PALETTE.GREY))
red_slider.set_value(lv.OPA._20, lv.ANIM.OFF)
green_slider.set_value(lv.OPA._90, lv.ANIM.OFF)
blue_slider.set_value(lv.OPA._60, lv.ANIM.OFF)
intense_slider.set_value(lv.OPA._50, lv.ANIM.OFF)
red_slider.align(lv.ALIGN.LEFT_MID, 25, 0)
green_slider.align_to(red_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
blue_slider.align_to(green_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
intense_slider.align_to(blue_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
/**
* Show transformations (zoom and rotation) using a pivot point.
*/
void lv_example_img_3(void)
{
LV_IMG_DECLARE(img_cogwheel_argb);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
lv_anim_set_exec_cb(&a, set_angle);
lv_anim_set_values(&a, 0, 3600);
lv_anim_set_time(&a, 5000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, set_zoom);
lv_anim_set_values(&a, 128, 256);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
(continues on next page)
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Show transformations (zoom and rotation) using a pivot point.
#
a1 = lv.anim_t()
a1.init()
a1.set_var(img)
a1.set_custom_exec_cb(lambda a,val: set_angle(img,val))
a1.set_values(0, 3600)
a1.set_time(5000)
a1.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a1)
a2 = lv.anim_t()
a2.init()
a2.set_var(img)
a2.set_custom_exec_cb(lambda a,val: set_zoom(img,val))
a2.set_values(128, 256)
a2.set_time(5000)
a2.set_playback_time(3000)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a2)
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
/**
* Image styling and offset
*/
void lv_example_img_4(void)
{
LV_IMG_DECLARE(img_skew_strip);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
lv_anim_set_exec_cb(&a, ofs_y_anim);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 500);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
#endif
img_skew_strip = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Image styling and offset
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.palette_main(lv.PALETTE.YELLOW))
style.set_bg_opa(lv.OPA.COVER)
style.set_img_recolor_opa(lv.OPA.COVER)
style.set_img_recolor(lv.color_black())
img = lv.img(lv.scr_act())
img.add_style(style, 0)
img.set_src(img_skew_strip)
img.set_size(150, 100)
img.center()
a = lv.anim_t()
a.init()
a.set_var(img)
a.set_values(0, 100)
a.set_time(3000)
a.set_playback_time(500)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a.set_custom_exec_cb(lambda a,val: ofs_y_anim(img,val))
lv.anim_t.start(a)
#include "../../lv_examples.h"
#if LV_USE_IMGBTN && LV_BUILD_EXAMPLES
void lv_example_imgbtn_1(void)
{
LV_IMG_DECLARE(imgbtn_left);
LV_IMG_DECLARE(imgbtn_right);
LV_IMG_DECLARE(imgbtn_mid);
#endif
imgbtn_left_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_left_data),
'data': imgbtn_left_data
})
try:
with open('../../assets/imgbtn_mid.png','rb') as f:
imgbtn_mid_data = f.read()
except:
(continues on next page)
imgbtn_mid_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_mid_data),
'data': imgbtn_mid_data
})
try:
with open('../../assets/imgbtn_right.png','rb') as f:
imgbtn_right_data = f.read()
except:
print("Could not find imgbtn_right.png")
sys.exit()
imgbtn_right_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_right_data),
'data': imgbtn_right_data
})
style_def = lv.style_t()
style_def.init()
style_def.set_text_color(lv.color_white())
style_def.set_transition(tr)
imgbtn1.add_style(style_def, 0)
imgbtn1.add_style(style_pr, lv.STATE.PRESSED)
imgbtn1.align(lv.ALIGN.CENTER, 0, 0)
2.7.14 Keyboard
#include "../../lv_examples.h"
#if LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
if(code == LV_EVENT_DEFOCUSED) {
lv_keyboard_set_textarea(kb, NULL);
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
}
void lv_example_keyboard_1(void)
{
/*Create a keyboard to use it with an of the text areas*/
lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
ta = lv_textarea_create(lv_scr_act());
lv_obj_align(ta, LV_ALIGN_TOP_RIGHT, -10, 10);
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_ALL, kb);
lv_obj_set_size(ta, 140, 80);
lv_keyboard_set_textarea(kb, ta);
}
#endif
def ta_event_cb(e,kb):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.FOCUSED:
kb.set_textarea(ta)
kb.clear_flag(lv.obj.FLAG.HIDDEN)
if code == lv.EVENT.DEFOCUSED:
kb.set_textarea(None)
kb.add_flag(lv.obj.FLAG.HIDDEN)
ta = lv.textarea(lv.scr_act())
ta.set_width(200)
ta.align(lv.ALIGN.TOP_RIGHT, -10, 10)
ta.add_event_cb(lambda e: ta_event_cb(e,kb), lv.EVENT.ALL, None)
kb.set_textarea(ta)
2.7.15 Label
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Show line wrap, re-color, line align and text scrolling.
*/
void lv_example_label_1(void)
{
lv_obj_t * label1 = lv_label_create(lv_scr_act());
lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP); /*Break the long lines*/
lv_label_set_recolor(label1, true); /*Enable re-coloring by␣
,→commands in the text*/
lv_obj_set_width(label2, 150);
lv_label_set_text(label2, "It is a circularly scrolling text. ");
lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}
#endif
#
# Show line wrap, re-color, line align and text scrolling.
#
label1 = lv.label(lv.scr_act())
(continues on next page)
label1.set_style_text_align(lv.ALIGN.CENTER, 0)
label1.align(lv.ALIGN.CENTER, 0, -40)
label2 = lv.label(lv.scr_act())
label2.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR) # Circular scroll
label2.set_width(150)
label2.set_text("It is a circularly scrolling text. ")
label2.align(lv.ALIGN.CENTER, 0, 40)
Text shadow
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Create a fake text shadow
*/
void lv_example_label_2(void)
{
/*Create a style for the shadow*/
static lv_style_t style_shadow;
lv_style_init(&style_shadow);
lv_style_set_text_opa(&style_shadow, LV_OPA_30);
lv_style_set_text_color(&style_shadow, lv_color_black());
#endif
#
# Create a fake text shadow
#
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES && LV_FONT_DEJAVU_16_PERSIAN_HEBREW && LV_FONT_
,→SIMSUN_16_CJK && LV_USE_BIDI
/**
* Show mixed LTR, RTL and Chinese label
*/
void lv_example_label_3(void)
{
lv_obj_t * ltr_label = lv_label_create(lv_scr_act());
lv_label_set_text(ltr_label, "In modern terminology, a microcontroller is similar␣
,→to a system on a chip (SoC).");
#endif
import fs_driver
#
# Show mixed LTR, RTL and Chinese label
#
ltr_label = lv.label(lv.scr_act())
ltr_label.set_text("In modern terminology, a microcontroller is similar to a system␣
,→on a chip (SoC).")
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
try:
ltr_label.set_style_text_font(ltr_label, lv.font_montserrat_16, 0)
except:
font_montserrat_16 = lv.font_load("S:../../assets/font/montserrat-16.fnt")
ltr_label.set_style_text_font(font_montserrat_16, 0)
ltr_label.set_width(310)
ltr_label.align(lv.ALIGN.TOP_LEFT, 5, 5)
rtl_label = lv.label(lv.scr_act())
rtl_label.set_text(", : ) CPU - Central␣
,→Processing Unit).")
rtl_label.set_style_base_dir(lv.BASE_DIR.RTL, 0)
rtl_label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
rtl_label.set_width(310)
rtl_label.align(lv.ALIGN.LEFT_MID, 5, 0)
font_simsun_16_cjk = lv.font_load("S:../../assets/font/lv_font_simsun_16_cjk.fnt")
cz_label = lv.label(lv.scr_act())
cz_label.set_style_text_font(font_simsun_16_cjk, 0)
cz_label.set_text(" Embedded System \n ")
cz_label.set_width(310)
cz_label.align(lv.ALIGN.BOTTOM_LEFT, 5, -5)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_USE_CANVAS && LV_BUILD_EXAMPLES && LV_DRAW_COMPLEX
}
else if(code == LV_EVENT_DRAW_MAIN_END) {
lv_draw_mask_free_param(&m);
lv_draw_mask_remove_id(mask_id);
}
}
/**
* Draw label with gradient color
*/
void lv_example_label_4(void)
{
/* Create the mask of a text by drawing it to a canvas*/
static lv_opa_t mask_map[MASK_WIDTH * MASK_HEIGHT];
/*Draw a label to the canvas. The result "image" will be used as mask*/
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.color = lv_color_white();
label_dsc.align = LV_TEXT_ALIGN_CENTER;
lv_canvas_draw_text(canvas, 5, 5, MASK_WIDTH, &label_dsc, "Text with gradient");
#endif
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_
,→SCROLL_CIRCULAR`
* long mode.
*/
void lv_example_label_5(void)
{
static lv_anim_t animation_template;
static lv_style_t label_style;
lv_anim_init(&animation_template);
lv_anim_set_delay(&animation_template, 1000); /*Wait 1 second to start␣
,→the first scroll*/
lv_anim_set_repeat_delay(&animation_template,
3000); /*Repeat the scroll 3 seconds after the label␣
,→scrolls back to the initial position*/
lv_obj_set_width(label1, 150);
lv_label_set_text(label1, "It is a circularly scrolling text. ");
lv_obj_align(label1, LV_ALIGN_CENTER, 0, 40);
lv_obj_add_style(label1, &label_style, LV_STATE_DEFAULT); /*Add the␣
,→style to the label*/
#endif
#
# Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_
,→SCROLL_CIRCULAR` long mode.
label1 = lv.label(lv.scr_act())
label1.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR) # Circular scroll
label1.set_width(150)
label1.set_text("It is a circularly scrolling text. ")
label1.align(lv.ALIGN.CENTER, 0, 40)
2.7.16 LED
#include "../../lv_examples.h"
#if LV_USE_LED && LV_BUILD_EXAMPLES
/**
* Create LED's with different brightness and color
*/
void lv_example_led_1(void)
{
/*Create a LED and switch it OFF*/
lv_obj_t * led1 = lv_led_create(lv_scr_act());
lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);
lv_led_off(led1);
#endif
#
# Create LED's with different brightness and color
#
2.7.17 Line
Simple Line
#include "../../lv_examples.h"
#if LV_USE_LINE && LV_BUILD_EXAMPLES
void lv_example_line_1(void)
{
/*Create an array for the points of the line*/
static lv_point_t line_points[] = { {5, 5}, {70, 70}, {120, 10}, {180, 60}, {240,␣
,→10} };
/*Create style*/
static lv_style_t style_line;
lv_style_init(&style_line);
lv_style_set_line_width(&style_line, 8);
lv_style_set_line_color(&style_line, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_line_rounded(&style_line, true);
#endif
# Create style
style_line = lv.style_t()
style_line.init()
style_line.set_line_width(8)
style_line.set_line_color(lv.palette_main(lv.PALETTE.BLUE))
style_line.set_line_rounded(True)
2.7.18 List
Simple List
#include "../../lv_examples.h"
#if LV_USE_LIST && LV_BUILD_EXAMPLES
static lv_obj_t * list1;
void lv_example_list_1(void)
{
/*Create a list*/
list1 = lv_list_create(lv_scr_act());
lv_obj_set_size(list1, 180, 220);
lv_obj_center(list1);
lv_list_add_text(list1, "File");
btn = lv_list_add_btn(list1, LV_SYMBOL_FILE, "New");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_DIRECTORY, "Open");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_SAVE, "Save");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, "Delete");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_EDIT, "Edit");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
lv_list_add_text(list1, "Connectivity");
btn = lv_list_add_btn(list1, LV_SYMBOL_BLUETOOTH, "Bluetooth");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_GPS, "Navigation");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_USB, "USB");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_BATTERY_FULL, "Battery");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
lv_list_add_text(list1, "Exit");
(continues on next page)
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
print("Clicked: list1." + list1.get_btn_text(obj))
# Create a list
list1 = lv.list(lv.scr_act())
list1.set_size(180, 220)
list1.center()
list1.add_text("Connectivity")
btn_bluetooth = list1.add_btn(lv.SYMBOL.BLUETOOTH, "Bluetooth")
btn_bluetooth.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_navig = list1.add_btn(lv.SYMBOL.GPS, "Navigation")
btn_navig.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_USB = list1.add_btn(lv.SYMBOL.USB, "USB")
btn_USB.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_battery = list1.add_btn(lv.SYMBOL.BATTERY_FULL, "Battery")
btn_battery.add_event_cb(event_handler,lv.EVENT.ALL, None)
list1.add_text("Exit")
btn_apply = list1.add_btn(lv.SYMBOL.OK, "Apply")
btn_apply.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_close = list1.add_btn(lv.SYMBOL.CLOSE, "Close")
btn_close.add_event_cb(event_handler,lv.EVENT.ALL, None)
#include <stdlib.h>
#include "../../lv_examples.h"
#if LV_USE_LIST && LV_BUILD_EXAMPLES
if(currentButton == obj) {
currentButton = NULL;
}
else {
currentButton = obj;
}
lv_obj_t * parent = lv_obj_get_parent(obj);
uint32_t i;
for(i = 0; i < lv_obj_get_child_cnt(parent); i++) {
lv_obj_t * child = lv_obj_get_child(parent, i);
if(child == currentButton) {
lv_obj_add_state(child, LV_STATE_CHECKED);
}
else {
lv_obj_clear_state(child, LV_STATE_CHECKED);
}
}
}
}
lv_obj_move_to_index(currentButton, pos);
lv_obj_scroll_to_view(currentButton, LV_ANIM_ON);
}
}
void lv_example_list_2(void)
{
/*Create a list*/
list1 = lv_list_create(lv_scr_act());
lv_obj_set_size(list1, lv_pct(60), lv_pct(100));
lv_obj_set_style_pad_row(list1, 5, 0);
#endif
import urandom
currentButton = None
list1 = None
def event_handler(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
if currentButton == obj:
currentButton = None
else:
currentButton = obj
parent = obj.get_parent()
for i in range( parent.get_child_cnt()):
child = parent.get_child(i)
if child == currentButton:
child.add_state(lv.STATE.CHECKED)
else:
child.clear_state(lv.STATE.CHECKED)
def event_handler_top(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
if currentButton == None:
return
currentButton.move_background()
currentButton.scroll_to_view( lv.ANIM.ON)
def event_handler_up(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
index = currentButton.get_index()
if index <= 0:
return
currentButton.move_to_index(index - 1)
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_center(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
parent = currentButton.get_parent()
pos = parent.get_child_cnt() // 2
currentButton.move_to_index(pos)
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_bottom(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
currentButton.move_foreground()
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_swap(evt):
global currentButton
global list1
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
cnt = list1.get_child_cnt()
for i in range(100):
if cnt > 1:
obj = list1.get_child(urandom.getrandbits(32) % cnt )
obj.move_to_index(urandom.getrandbits(32) % cnt)
if currentButton != None:
currentButton.scroll_to_view(lv.ANIM.ON)
for i in range(15):
btn = lv.btn(list1)
btn.set_width(lv.pct(100))
btn.add_event_cb( event_handler, lv.EVENT.CLICKED, None)
lab = lv.label(btn)
lab.set_text("Item " + str(i))
2.7.19 Menu
Simple Menu
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
void lv_example_menu_1(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
(continues on next page)
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
lv_obj_center(mbox1);
}
}
void lv_example_menu_2(void)
{
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_menu_set_mode_root_back_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
def back_event_handler(e):
obj = e.get_target()
if menu.back_btn_is_root(obj):
mbox1 = lv.msgbox(lv.scr_act(), "Hello", "Root back btn click.", None, True)
mbox1.center()
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_USER_DATA && LV_BUILD_EXAMPLES
void lv_example_menu_3(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_1_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(sub_2_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(sub_3_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_1_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_2_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_3_page);
lv_menu_set_page(menu, main_page);
}
#endif
cont = lv.menu_cont(sub_page_1)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
cont = lv.menu_cont(sub_page_2)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
cont = lv.menu_cont(sub_page_3)
label = lv.label(cont)
(continues on next page)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1 (Click me!)")
menu.set_load_page_event(cont, sub_page_1)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2 (Click me!)")
menu.set_load_page_event(cont, sub_page_2)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page_3)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
btn_cnt++;
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "Hello, I am hiding inside %"LV_PRIu32, btn_cnt);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "Item %"LV_PRIu32, btn_cnt);
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_obj_scroll_to_view_recursive(cont, LV_ANIM_ON);
}
void lv_example_menu_4(void)
(continues on next page)
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding inside the first item");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
#endif
btn_cnt = 1
def float_btn_event_cb(e):
global btn_cnt
btn_cnt += 1
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside {:d}".format(btn_cnt))
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item {:d}".format(btn_cnt))
menu.set_load_page_event(cont, sub_page)
(continues on next page)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside the first item")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
float_btn = lv.btn(lv.scr_act())
float_btn.set_size(50, 50)
float_btn.add_flag(lv.obj.FLAG.FLOATING)
float_btn.align(lv.ALIGN.BOTTOM_RIGHT, -10, -10)
float_btn.add_event_cb(float_btn_event_cb, lv.EVENT.CLICKED, None)
float_btn.set_style_radius(lv.RADIUS.CIRCLE, 0)
float_btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
float_btn.set_style_text_font(lv.theme_get_font_large(float_btn), 0)
Complex Menu
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
enum {
LV_MENU_ITEM_BUILDER_VARIANT_1,
LV_MENU_ITEM_BUILDER_VARIANT_2
};
typedef uint8_t lv_menu_builder_variant_t;
void lv_example_menu_5(void)
(continues on next page)
}
else {
lv_obj_set_style_bg_color(menu, lv_color_darken(lv_obj_get_style_bg_
,→color(menu, 0), 50), 0);
}
lv_menu_set_mode_root_back_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * section;
lv_menu_separator_create(sub_mechanics_page);
section = lv_menu_section_create(sub_mechanics_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Velocity", 0, 150, 120);
create_slider(section, LV_SYMBOL_SETTINGS, "Acceleration", 0, 150, 50);
create_slider(section, LV_SYMBOL_SETTINGS, "Weight limit", 0, 150, 80);
lv_menu_separator_create(sub_sound_page);
section = lv_menu_section_create(sub_sound_page);
create_switch(section, LV_SYMBOL_AUDIO, "Sound", false);
lv_menu_separator_create(sub_display_page);
section = lv_menu_section_create(sub_display_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Brightness", 0, 150, 100);
section = lv_menu_section_create(sub_software_info_page);
create_text(section, NULL, "Version 1.0", LV_MENU_ITEM_BUILDER_VARIANT_1);
section = lv_menu_section_create(sub_legal_info_page);
for(uint32_t i = 0; i < 15; i++) {
create_text(section, NULL,
"This is a long long long long long long long long long text, if␣
,→it is long enough it may scroll.", (continues on next page)
lv_menu_separator_create(sub_about_page);
section = lv_menu_section_create(sub_about_page);
cont = create_text(section, NULL, "Software information", LV_MENU_ITEM_BUILDER_
,→VARIANT_1);
lv_menu_separator_create(sub_menu_mode_page);
section = lv_menu_section_create(sub_menu_mode_page);
cont = create_switch(section, LV_SYMBOL_AUDIO, "Sidebar enable", true);
lv_obj_add_event_cb(lv_obj_get_child(cont, 2), switch_handler, LV_EVENT_VALUE_
,→CHANGED, menu);
section = lv_menu_section_create(root_page);
cont = create_text(section, LV_SYMBOL_SETTINGS, "Mechanics", LV_MENU_ITEM_BUILDER_
,→VARIANT_1);
lv_menu_set_sidebar_page(menu, root_page);
lv_event_send(lv_obj_get_child(lv_obj_get_child(lv_menu_get_cur_sidebar_
,→ page(menu), 0), 0), LV_EVENT_CLICKED, NULL);
}
if(lv_menu_back_btn_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Hello", "Root back btn click.",␣
,→NULL, true);
lv_obj_center(mbox1);
}
}
}
else {
lv_menu_set_sidebar_page(menu, NULL);
lv_menu_clear_history(menu); /* Clear history because we will be showing␣
,→the root page later */
lv_menu_set_page(menu, root_page);
}
}
}
static lv_obj_t * create_text(lv_obj_t * parent, const char * icon, const char * txt,
lv_menu_builder_variant_t builder_variant)
{
lv_obj_t * obj = lv_menu_cont_create(parent);
if(icon) {
img = lv_img_create(obj);
lv_img_set_src(img, icon);
}
if(txt) {
label = lv_label_create(obj);
lv_label_set_text(label, txt);
lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_flex_grow(label, 1);
}
return obj;
}
int32_t val)
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_2);
if(icon == NULL) {
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
}
return obj;
}
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_obj_t * sw = lv_switch_create(obj);
lv_obj_add_state(sw, chk ? LV_STATE_CHECKED : 0);
return obj;
}
#endif
2.7.20 Meter
Simple meter
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A simple meter
*/
void lv_example_meter_1(void)
{
(continues on next page)
lv_meter_indicator_t * indic;
false, 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
#
# A simple meter
#
meter = lv.meter(lv.scr_act())
meter.center()
meter.set_size(200, 200)
indic = lv.meter_indicator_t()
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A meter with multiple arcs
*/
void lv_example_meter_2(void)
{
meter = lv_meter_create(lv_scr_act());
lv_obj_center(meter);
lv_obj_set_size(meter, 200, 200);
lv_anim_set_time(&a, 2000);
lv_anim_set_playback_time(&a, 500);
lv_anim_set_var(&a, indic1);
(continues on next page)
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_time(&a, 1000);
lv_anim_set_var(&a, indic2);
lv_anim_start(&a);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_time(&a, 2000);
lv_anim_set_var(&a, indic3);
lv_anim_start(&a);
}
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
def set_value(indic,v):
meter.set_indicator_end_value(indic, v)
#
# A meter with multiple arcs
#
meter = lv.meter(lv.scr_act())
meter.center()
meter.set_size(200, 200)
a2 = lv.anim_t()
a2.init()
a2.set_values(0, 100)
a2.set_time(1000)
a2.set_repeat_delay(100)
a2.set_playback_delay(100)
a2.set_playback_time(1000)
a2.set_var(indic2)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a2.set_custom_exec_cb(lambda a,val: set_value(indic2,val))
lv.anim_t.start(a2)
a3 = lv.anim_t()
a3.init()
a3.set_values(0, 100)
a3.set_time(1000)
a3.set_repeat_delay(100)
a3.set_playback_delay(100)
a3.set_playback_time(2000)
a3.set_var(indic3)
a3.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a3.set_custom_exec_cb(lambda a,val: set_value(indic3,val))
lv.anim_t.start(a3)
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A clock from a meter
*/
void lv_example_meter_3(void)
{
meter = lv_meter_create(lv_scr_act());
lv_obj_set_size(meter, 220, 220);
lv_obj_center(meter);
/*Create another scale for the hours. It's only visual and contains only major␣
,→ ticks*/
lv_meter_scale_t * scale_hour = lv_meter_add_scale(meter);
lv_meter_set_scale_ticks(meter, scale_hour, 12, 0, 0, lv_palette_main(LV_PALETTE_
,→GREY)); /*12 ticks*/
lv_meter_set_scale_major_ticks(meter, scale_hour, 1, 2, 20, lv_color_black(), 10);
,→ /*Every tick is major*/
lv_meter_set_scale_range(meter, scale_hour, 1, 12, 330, 300); /*[1..12]␣
,→values in an almost full circle*/
LV_IMG_DECLARE(img_hand)
lv_anim_set_var(&a, indic_hour);
lv_anim_set_time(&a, 24000); /*24 sec for 1 turn of the hour hand*/
lv_anim_set_values(&a, 0, 60);
lv_anim_start(&a);
}
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_hand_min_dsc = lv.img_dsc_t({
'data_size': len(img_hand_min_data),
'data': img_hand_min_data
})
img_hand_hour_dsc = lv.img_dsc_t({
'data_size': len(img_hand_hour_data),
'data': img_hand_hour_data
})
meter = lv.meter(lv.scr_act())
meter.set_size(220, 220)
meter.center()
# Create another scale for the hours. It's only visual and contains only major ticks
scale_hour = meter.add_scale()
meter.set_scale_ticks(scale_hour, 12, 0, 0, lv.palette_main(lv.PALETTE.GREY)) # 12␣
,→ticks
# LV_IMG_DECLARE(img_hand)
a2 = lv.anim_t()
a2.init()
a2.set_var(indic_hour)
a2.set_time(24000) # 24 sec for 1 turn of the hour hand
a2.set_values(0, 60)
a2.set_custom_exec_cb(lambda a2,val: set_value(indic_hour,val))
lv.anim_t.start(a2)
Pie chart
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* Create a pie chart
*/
void lv_example_meter_4(void)
{
lv_obj_t * meter = lv_meter_create(lv_scr_act());
#endif
#
# Create a pie chart
#
meter = lv.meter(lv.scr_act())
meter.set_size(200, 200)
meter.center()
#include "../../lv_examples.h"
#if LV_USE_MSGBOX && LV_BUILD_EXAMPLES
void lv_example_msgbox_1(void)
{
static const char * btns[] = {"Apply", "Close", ""};
#endif
def event_cb(e):
mbox = e.get_current_target()
print("Button %s clicked" % mbox.get_active_btn_text())
2.7.22 Roller
Simple Roller
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_BUILD_EXAMPLES
/**
* An infinite roller with the name of the months
*/
void lv_example_roller_1(void)
{
lv_obj_t * roller1 = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller1,
"January\n"
"February\n"
"March\n"
"April\n"
"May\n"
"June\n"
"July\n"
"August\n"
"September\n"
"October\n"
"November\n"
(continues on next page)
lv_roller_set_visible_row_count(roller1, 4);
lv_obj_center(roller1);
lv_obj_add_event_cb(roller1, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
option = " "*10
obj.get_selected_str(option, len(option))
print("Selected month: " + option.strip())
#
# An infinite roller with the name of the months
#
roller1 = lv.roller(lv.scr_act())
roller1.set_options("\n".join([
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]),lv.roller.MODE.INFINITE)
roller1.set_visible_row_count(4)
roller1.center()
roller1.add_event_cb(event_handler, lv.EVENT.ALL, None)
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_FONT_MONTSERRAT_22 && LV_BUILD_EXAMPLES
/**
* Roller with various alignments and larger text in the selected area
*/
void lv_example_roller_2(void)
{
/*A style to make the selected option larger*/
static lv_style_t style_sel;
lv_style_init(&style_sel);
lv_style_set_text_font(&style_sel, &lv_font_montserrat_22);
/*A roller on the left with left aligned text, and custom width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 2);
lv_obj_set_width(roller, 100);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_set_style_text_align(roller, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_align(roller, LV_ALIGN_LEFT_MID, 10, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 2, LV_ANIM_OFF);
/*A roller on the middle with center aligned text, and auto (default) width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 3);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_align(roller, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 5, LV_ANIM_OFF);
/*A roller on the right with right aligned text, and custom width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 4);
lv_obj_set_width(roller, 80);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_set_style_text_align(roller, LV_TEXT_ALIGN_RIGHT, 0);
lv_obj_align(roller, LV_ALIGN_RIGHT_MID, -10, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 8, LV_ANIM_OFF);
}
#endif
import fs_driver
def event_handler(e):
code = e.get_code()
(continues on next page)
#
# Roller with various alignments and larger text in the selected area
#
try:
style_sel.set_text_font(lv.font_montserrat_22)
except:
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
print("montserrat-22 not enabled in lv_conf.h, dynamically loading the font")
font_montserrat_22 = lv.font_load("S:" + "../../assets/font/montserrat-22.fnt")
style_sel.set_text_font(font_montserrat_22)
opts = "\n".join(["1","2","3","4","5","6","7","8","9","10"])
# A roller on the left with left aligned text, and custom width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(2)
roller.set_width(100)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.set_style_text_align(lv.TEXT_ALIGN.LEFT, 0)
roller.align(lv.ALIGN.LEFT_MID, 10, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(2, lv.ANIM.OFF)
# A roller in the middle with center aligned text, and auto (default) width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(3)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.align(lv.ALIGN.CENTER, 0, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(5, lv.ANIM.OFF)
# A roller on the right with right aligned text, and custom width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(4)
roller.set_width(80)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.set_style_text_align(lv.TEXT_ALIGN.RIGHT, 0)
roller.align(lv.ALIGN.RIGHT_MID, -10, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(8, lv.ANIM.OFF)
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
if(code == LV_EVENT_COVER_CHECK) {
lv_event_set_cover_res(e, LV_COVER_RES_MASKED);
}
else if(code == LV_EVENT_DRAW_MAIN_BEGIN) {
/* add mask */
const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
lv_coord_t font_h = lv_font_get_line_height(font);
lv_area_t roller_coords;
lv_obj_get_coords(obj, &roller_coords);
lv_area_t rect_area;
rect_area.x1 = roller_coords.x1;
rect_area.x2 = roller_coords.x2;
rect_area.y1 = roller_coords.y1;
rect_area.y2 = roller_coords.y1 + (lv_obj_get_height(obj) - font_h - line_
,→space) / 2;
}
else if(code == LV_EVENT_DRAW_POST_END) {
lv_draw_mask_fade_param_t * fade_mask_top = lv_draw_mask_remove_id(mask_top_
,→id);
lv_draw_mask_free_param(fade_mask_top);
lv_draw_mask_free_param(fade_mask_bottom);
lv_mem_buf_release(fade_mask_top);
(continues on next page)
/**
* Add a fade mask to roller.
*/
void lv_example_roller_3(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_bg_color(&style, lv_color_black());
lv_style_set_text_color(&style, lv_color_white());
lv_style_set_border_width(&style, 0);
lv_style_set_pad_all(&style, 0);
lv_obj_add_style(lv_scr_act(), &style, 0);
#if LV_FONT_MONTSERRAT_22
lv_obj_set_style_text_font(roller1, &lv_font_montserrat_22, LV_PART_SELECTED);
#endif
lv_roller_set_options(roller1,
"January\n"
"February\n"
"March\n"
"April\n"
"May\n"
"June\n"
"July\n"
"August\n"
"September\n"
"October\n"
"November\n"
"December",
LV_ROLLER_MODE_NORMAL);
lv_obj_center(roller1);
lv_roller_set_visible_row_count(roller1, 3);
lv_obj_add_event_cb(roller1, mask_event_cb, LV_EVENT_ALL, NULL);
}
#endif
import fs_driver
import sys
class Lv_Roller_3():
def __init__(self):
self.mask_top_id = -1
(continues on next page)
#
# Add a fade mask to roller.
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.color_black())
style.set_text_color(lv.color_white())
lv.scr_act().add_style(style, 0)
roller1 = lv.roller(lv.scr_act())
roller1.add_style(style, 0)
roller1.set_style_border_width(0, 0)
roller1.set_style_pad_all(0, 0)
roller1.set_style_bg_opa(lv.OPA.TRANSP, lv.PART.SELECTED)
#if LV_FONT_MONTSERRAT_22
# lv_obj_set_style_text_font(roller1, &lv_font_montserrat_22, LV_PART_
,→SELECTED);
#endif
try:
roller1.set_style_text_font(lv.font_montserrat_22,lv.PART.SELECTED)
except:
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
print("montserrat-22 not enabled in lv_conf.h, dynamically loading the␣
,→font")
roller1.set_style_text_font(font_montserrat_22,lv.PART.SELECTED)
roller1.set_options("\n".join([
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]),lv.roller.MODE.NORMAL)
roller1.center()
roller1.set_visible_row_count(3)
roller1.add_event_cb(self.mask_event_cb, lv.EVENT.ALL, None)
def mask_event_cb(self,e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.COVER_CHECK:
(continues on next page)
roller_coords = lv.area_t()
obj.get_coords(roller_coords)
rect_area = lv.area_t()
rect_area.x1 = roller_coords.x1
rect_area.x2 = roller_coords.x2
rect_area.y1 = roller_coords.y1
rect_area.y2 = roller_coords.y1 + (obj.get_height() - font_h - line_
,→space) // 2
fade_mask_top = lv.draw_mask_fade_param_t()
fade_mask_top.init(rect_area, lv.OPA.TRANSP, rect_area.y1, lv.OPA.COVER,␣
,→rect_area.y2)
self.mask_top_id = lv.draw_mask_add(fade_mask_top,None)
fade_mask_bottom = lv.draw_mask_fade_param_t()
fade_mask_bottom.init(rect_area, lv.OPA.COVER, rect_area.y1, lv.OPA.
,→TRANSP, rect_area.y2)
roller3 = Lv_Roller_3()
2.7.23 Slider
Simple Slider
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* A default slider with a label displaying the current value
(continues on next page)
#endif
#
# A default slider with a label displaying the current value
#
def slider_event_cb(e):
slider = e.get_target()
slider_label.set_text("{:d}%".format(slider.get_value()))
slider_label.align_to(slider, lv.ALIGN.OUT_BOTTOM_MID, 0, 10)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Show how to style a slider.
*/
void lv_example_slider_2(void)
{
/*Create a transition*/
static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, 0};
static lv_style_transition_dsc_t transition_dsc;
lv_style_transition_dsc_init(&transition_dsc, props, lv_anim_path_linear, 300, 0,␣
,→NULL);
lv_style_init(&style_indicator);
lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER);
lv_style_set_bg_color(&style_indicator, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
lv_style_set_transition(&style_indicator, &transition_dsc);
lv_style_init(&style_knob);
lv_style_set_bg_opa(&style_knob, LV_OPA_COVER);
lv_style_set_bg_color(&style_knob, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_border_color(&style_knob, lv_palette_darken(LV_PALETTE_CYAN, 3));
lv_style_set_border_width(&style_knob, 2);
lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE);
lv_style_set_pad_all(&style_knob, 6); /*Makes the knob larger*/
lv_style_set_transition(&style_knob, &transition_dsc);
lv_style_init(&style_pressed_color);
lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_CYAN,␣
,→2));
#endif
#
# Show how to style a slider.
#
# Create a transition
props = [lv.STYLE.BG_COLOR, 0]
transition_dsc = lv.style_transition_dsc_t()
transition_dsc.init(props, lv.anim_t.path_linear, 300, 0, None)
style_main = lv.style_t()
style_indicator = lv.style_t()
style_knob = lv.style_t()
style_pressed_color = lv.style_t()
style_main.init()
style_main.set_bg_opa(lv.OPA.COVER)
style_main.set_bg_color(lv.color_hex3(0xbbb))
style_main.set_radius(lv.RADIUS.CIRCLE)
style_main.set_pad_ver(-2) # Makes the indicator larger
style_indicator.init()
style_indicator.set_bg_opa(lv.OPA.COVER)
style_indicator.set_bg_color(lv.palette_main(lv.PALETTE.CYAN))
style_indicator.set_radius(lv.RADIUS.CIRCLE)
style_indicator.set_transition(transition_dsc)
style_knob.init()
style_knob.set_bg_opa(lv.OPA.COVER)
style_knob.set_bg_color(lv.palette_main(lv.PALETTE.CYAN))
style_knob.set_border_color(lv.palette_darken(lv.PALETTE.CYAN, 3))
style_knob.set_border_width(2)
style_knob.set_radius(lv.RADIUS.CIRCLE)
style_knob.set_pad_all(6) # Makes the knob larger
style_knob.set_transition(transition_dsc)
style_pressed_color.init()
style_pressed_color.set_bg_color(lv.palette_darken(lv.PALETTE.CYAN, 2))
slider.add_style(style_main, lv.PART.MAIN)
slider.add_style(style_indicator, lv.PART.INDICATOR)
slider.add_style(style_pressed_color, lv.PART.INDICATOR | lv.STATE.PRESSED)
slider.add_style(style_knob, lv.PART.KNOB)
slider.add_style(style_pressed_color, lv.PART.KNOB | lv.STATE.PRESSED)
slider.center()
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Show the current value when the slider is pressed by extending the drawer
*
*/
void lv_example_slider_3(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider;
slider = lv_slider_create(lv_scr_act());
lv_obj_center(slider);
lv_slider_set_mode(slider, LV_SLIDER_MODE_RANGE);
lv_slider_set_value(slider, 70, LV_ANIM_OFF);
lv_slider_set_left_value(slider, 20, LV_ANIM_OFF);
lv_point_t label_size;
lv_txt_get_size(&label_size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, 0);
lv_area_t label_area;
label_area.x1 = dsc->draw_area->x1 + lv_area_get_width(dsc->draw_area) /␣
,→2 - label_size.x / 2;
lv_draw_label_dsc_t label_draw_dsc;
lv_draw_label_dsc_init(&label_draw_dsc);
label_draw_dsc.color = lv_color_hex3(0x888);
lv_draw_label(dsc->draw_ctx, &label_draw_dsc, &label_area, buf, NULL);
}
}
(continues on next page)
#endif
def slider_event_cb(e):
code = e.get_code()
obj = e.get_target()
# print(label_size.x,label_size.y)
label_area = lv.area_t()
label_area.x1 = dsc.draw_area.x1 + dsc.draw_area.get_width() // 2 - label_
,→size.x // 2
label_draw_dsc = lv.draw_label_dsc_t()
label_draw_dsc.init()
slider = lv.slider(lv.scr_act())
slider.center()
slider.set_mode(lv.slider.MODE.RANGE)
slider.set_value(70, lv.ANIM.OFF)
slider.set_left_value(20, lv.ANIM.OFF)
2.7.24 Span
#include "../../lv_examples.h"
#if LV_USE_SPAN && LV_BUILD_EXAMPLES
/**
* Create span.
*/
void lv_example_span_1(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_border_width(&style, 1);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_ORANGE));
lv_style_set_pad_all(&style, 2);
lv_spangroup_set_align(spans, LV_TEXT_ALIGN_LEFT);
lv_spangroup_set_overflow(spans, LV_SPAN_OVERFLOW_CLIP);
lv_spangroup_set_indent(spans, 20);
lv_spangroup_set_mode(spans, LV_SPAN_MODE_BREAK);
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "good good study, day day up.");
#if LV_FONT_MONTSERRAT_24
lv_style_set_text_font(&span->style, &lv_font_montserrat_24);
#endif
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_GREEN));
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "LVGL is an open-source graphics library.");
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_BLUE));
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "the boy no name.");
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_GREEN));
#if LV_FONT_MONTSERRAT_20
lv_style_set_text_font(&span->style, &lv_font_montserrat_20);
#endif
lv_style_set_text_decor(&span->style, LV_TEXT_DECOR_UNDERLINE);
span = lv_spangroup_new_span(spans);
lv_span_set_text(span, "I have a dream that hope to come true.");
lv_style_set_text_decor(&span->style, LV_TEXT_DECOR_STRIKETHROUGH);
(continues on next page)
lv_spangroup_refr_mode(spans);
}
#endif
#
# Create span
#
style = lv.style_t()
style.init()
style.set_border_width(1)
style.set_border_color(lv.palette_main(lv.PALETTE.ORANGE))
style.set_pad_all(2)
spans = lv.spangroup(lv.scr_act())
spans.set_width(300)
spans.set_height(300)
spans.center()
spans.add_style(style, 0)
spans.set_align(lv.TEXT_ALIGN.LEFT)
spans.set_overflow(lv.SPAN_OVERFLOW.CLIP)
spans.set_indent(20)
spans.set_mode(lv.SPAN_MODE.BREAK)
span = spans.new_span()
span.set_text("china is a beautiful country.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.RED))
span.style.set_text_decor(lv.TEXT_DECOR.STRIKETHROUGH | lv.TEXT_DECOR.UNDERLINE)
span.style.set_text_opa(lv.OPA._30)
span = spans.new_span()
span.set_text_static("good good study, day day up.")
#if LV_FONT_MONTSERRAT_24
# lv_style_set_text_font(&span->style, &lv_font_montserrat_24);
#endif
span.style.set_text_color(lv.palette_main(lv.PALETTE.GREEN))
span = spans.new_span()
span.set_text_static("LVGL is an open-source graphics library.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.BLUE))
span = spans.new_span()
span.set_text_static("the boy no name.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.GREEN))
#if LV_FONT_MONTSERRAT_20
# lv_style_set_text_font(&span->style, &lv_font_montserrat_20);
#endif
span.style.set_text_decor(lv.TEXT_DECOR.UNDERLINE)
span = spans.new_span()
span.set_text("I have a dream that hope to come true.")
spans.refr_mode()
2.7.25 Spinbox
Simple Spinbox
#include "../../lv_examples.h"
#if LV_USE_SPINBOX && LV_BUILD_EXAMPLES
void lv_example_spinbox_1(void)
{
spinbox = lv_spinbox_create(lv_scr_act());
lv_spinbox_set_range(spinbox, -1000, 25000);
lv_spinbox_set_digit_format(spinbox, 5, 2);
lv_spinbox_step_prev(spinbox);
lv_obj_set_width(spinbox, 100);
lv_obj_center(spinbox);
lv_coord_t h = lv_obj_get_height(spinbox);
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, h, h);
lv_obj_align_to(btn, spinbox, LV_ALIGN_OUT_LEFT_MID, -5, 0);
lv_obj_set_style_bg_img_src(btn, LV_SYMBOL_MINUS, 0);
lv_obj_add_event_cb(btn, lv_spinbox_decrement_event_cb, LV_EVENT_ALL, NULL);
}
#endif
def increment_event_cb(e):
code = e.get_code()
if code == lv.EVENT.SHORT_CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
spinbox.increment()
def decrement_event_cb(e):
code = e.get_code()
if code == lv.EVENT.SHORT_CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
spinbox.decrement()
spinbox = lv.spinbox(lv.scr_act())
spinbox.set_range(-1000, 25000)
spinbox.set_digit_format(5, 2)
spinbox.step_prev()
spinbox.set_width(100)
spinbox.center()
h = spinbox.get_height()
btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_RIGHT_MID, 5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
btn.add_event_cb(increment_event_cb, lv.EVENT.ALL, None)
btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_LEFT_MID, -5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.MINUS, 0)
btn.add_event_cb(decrement_event_cb, lv.EVENT.ALL, None)
2.7.26 Spinner
Simple spinner
#include "../../lv_examples.h"
#if LV_USE_SPINNER && LV_BUILD_EXAMPLES
void lv_example_spinner_1(void)
{
/*Create a spinner*/
lv_obj_t * spinner = lv_spinner_create(lv_scr_act(), 1000, 60);
lv_obj_set_size(spinner, 100, 100);
lv_obj_center(spinner);
}
#endif
# Create a spinner
spinner = lv.spinner(lv.scr_act(), 1000, 60)
spinner.set_size(100, 100)
spinner.center()
2.7.27 Switch
Simple Switch
#include "../../lv_examples.h"
#if LV_USE_SWITCH && LV_BUILD_EXAMPLES
}
}
void lv_example_switch_1(void)
{
lv_obj_set_flex_flow(lv_scr_act(), LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(lv_scr_act(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,␣
,→LV_FLEX_ALIGN_CENTER);
lv_obj_t * sw;
sw = lv_switch_create(lv_scr_act());
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_DISABLED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_CHECKED | LV_STATE_DISABLED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
if obj.has_state(lv.STATE.CHECKED):
print("State: on")
else:
print("State: off")
lv.scr_act().set_flex_flow(lv.FLEX_FLOW.COLUMN)
lv.scr_act().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.
,→CENTER)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.DISABLED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
2.7.28 Table
Simple table
#include "../../lv_examples.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
/*In the first column align the texts to the right*/
else if(col == 0) {
dsc->label_dsc->align = LV_TEXT_ALIGN_RIGHT;
}
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
}
}
void lv_example_table_1(void)
(continues on next page)
#endif
def draw_part_event_cb(e):
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
# If the cells are drawn../
if dsc.part == lv.PART.ITEMS:
row = dsc.id // obj.get_col_cnt()
col = dsc.id - row * obj.get_col_cnt()
dsc.rect_dsc.bg_opa = lv.OPA.COVER
table = lv.table(lv.scr_act())
#include "../../lv_examples.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.bg_color = chk ? lv_theme_get_color_primary(obj) : lv_palette_
,→lighten(LV_PALETTE_GREY, 2);
rect_dsc.radius = LV_RADIUS_CIRCLE;
rect_dsc.bg_color = lv_color_white();
if(chk) {
sw_area.x2 -= 2;
sw_area.x1 = sw_area.x2 - 16;
}
else {
sw_area.x1 += 2;
sw_area.x2 = sw_area.x1 + 16;
}
sw_area.y1 += 2;
sw_area.y2 -= 2;
lv_draw_rect(dsc->draw_ctx, &rect_dsc, &sw_area);
}
}
/**
* A very light-weighted list created from table
*/
void lv_example_table_2(void)
{
/*Measure memory usage*/
lv_mem_monitor_t mon1;
lv_mem_monitor(&mon1);
uint32_t t = lv_tick_get();
lv_table_set_col_width(table, 0, 150);
lv_table_set_row_cnt(table, ITEM_CNT); /*Not required but avoids a lot of memory␣
,→reallocation lv_table_set_set_value*/
lv_table_set_col_cnt(table, 1);
/*Don't make the cell pressed, we will draw something different in the event*/
lv_obj_remove_style(table, NULL, LV_PART_ITEMS | LV_STATE_PRESSED);
lv_mem_monitor_t mon2;
lv_mem_monitor(&mon2);
#endif
ITEM_CNT = 200
def draw_event_cb(e):
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
# If the cells are drawn...
if dsc.part == lv.PART.ITEMS:
chk = obj.has_cell_ctrl(dsc.id, 0, lv.table.CELL_CTRL.CUSTOM_1)
rect_dsc = lv.draw_rect_dsc_t()
rect_dsc.init()
if chk:
rect_dsc.bg_color = lv.theme_get_color_primary(obj)
else:
rect_dsc.bg_color = lv.palette_lighten(lv.PALETTE.GREY, 2)
rect_dsc.radius = lv.RADIUS.CIRCLE
sw_area = lv.area_t()
sw_area.x1 = dsc.draw_area.x2 - 50
sw_area.x2 = sw_area.x1 + 40
sw_area.y1 = dsc.draw_area.y1 + dsc.draw_area.get_height() // 2 - 10
(continues on next page)
rect_dsc.bg_color = lv.color_white()
if chk:
sw_area.x2 -= 2
sw_area.x1 = sw_area.x2 - 16
else:
sw_area.x1 += 2
sw_area.x2 = sw_area.x1 + 16
sw_area.y1 += 2
sw_area.y2 -= 2
dsc.draw_ctx.rect(rect_dsc, sw_area)
def change_event_cb(e):
obj = e.get_target()
row = lv.C_Pointer()
col = lv.C_Pointer()
table.get_selected_cell(row, col)
# print("row: ",row.uint_val)
#
# A very light-weighted list created from table
#
table.set_col_width(0, 150)
table.set_row_cnt(ITEM_CNT) # Not required but avoids a lot of memory reallocation␣
,→lv_table_set_set_value
table.set_col_cnt(1)
# Don't make the cell pressed, we will draw something different in the event
table.remove_style(None, lv.PART.ITEMS | lv.STATE.PRESSED)
for i in range(ITEM_CNT):
table.set_cell_value(i, 0, "Item " + str(i+1))
table.align(lv.ALIGN.CENTER, 0, -20)
gc.collect()
mem_used = mem_free - gc.mem_free()
elaps = ticks_ms()-t
label = lv.label(lv.scr_act())
label.set_text(str(ITEM_CNT) + " items were created in " + str(elaps) + " ms\n using
,→" + str(mem_used) + " bytes of memory")
label.align(lv.ALIGN.BOTTOM_MID, 0, -10)
2.7.29 Tabview
Simple Tabview
#include "../../lv_examples.h"
#if LV_USE_TABVIEW && LV_BUILD_EXAMPLES
void lv_example_tabview_1(void)
{
/*Create a Tab view object*/
lv_obj_t * tabview;
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 50);
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1");
lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2");
lv_obj_t * tab3 = lv_tabview_add_tab(tabview, "Tab 3");
label = lv_label_create(tab2);
lv_label_set_text(label, "Second tab");
lv_obj_scroll_to_view_recursive(label, LV_ANIM_ON);
}
#endif
# Add 3 tabs (the tabs are page (lv_page) and can be scrolled
tab1 = tabview.add_tab("Tab 1")
tab2 = tabview.add_tab("Tab 2")
tab3 = tabview.add_tab("Tab 3")
If the content
of a tab
becomes too
longer
than the
container
then it
automatically
becomes
scrollable.
label = lv.label(tab2)
label.set_text("Second tab")
label = lv.label(tab3)
label.set_text("Third tab");
label.scroll_to_view_recursive(lv.ANIM.ON)
#include "../../lv_examples.h"
#if LV_USE_TABVIEW && LV_BUILD_EXAMPLES
void lv_example_tabview_2(void)
{
/*Create a Tab view object*/
lv_obj_t * tabview;
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_LEFT, 80);
(continues on next page)
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1");
lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2");
lv_obj_t * tab3 = lv_tabview_add_tab(tabview, "Tab 3");
lv_obj_t * tab4 = lv_tabview_add_tab(tabview, "Tab 4");
lv_obj_t * tab5 = lv_tabview_add_tab(tabview, "Tab 5");
label = lv_label_create(tab2);
lv_label_set_text(label, "Second tab");
label = lv_label_create(tab3);
lv_label_set_text(label, "Third tab");
label = lv_label_create(tab4);
lv_label_set_text(label, "Forth tab");
label = lv_label_create(tab5);
lv_label_set_text(label, "Fifth tab");
lv_obj_clear_flag(lv_tabview_get_content(tabview), LV_OBJ_FLAG_SCROLLABLE);
}
#endif
tab_btns = tabview.get_tab_btns()
tab_btns.set_style_bg_color(lv.palette_darken(lv.PALETTE.GREY, 3), 0)
tab_btns.set_style_text_color(lv.palette_lighten(lv.PALETTE.GREY, 5), 0)
tab_btns.set_style_border_side(lv.BORDER_SIDE.RIGHT, lv.PART.ITEMS | lv.STATE.CHECKED)
# Add 3 tabs (the tabs are page (lv_page) and can be scrolled
tab1 = tabview.add_tab("Tab 1")
tab2 = tabview.add_tab("Tab 2")
tab3 = tabview.add_tab("Tab 3")
tab4 = tabview.add_tab("Tab 4")
tab5 = tabview.add_tab("Tab 5")
(continues on next page)
tab2.set_style_bg_color(lv.palette_lighten(lv.PALETTE.AMBER, 3), 0)
tab2.set_style_bg_opa(lv.OPA.COVER, 0)
label = lv.label(tab2)
label.set_text("Second tab")
label = lv.label(tab3)
label.set_text("Third tab")
label = lv.label(tab4)
label.set_text("Forth tab")
label = lv.label(tab5)
label.set_text("Fifth tab")
tabview.get_content().clear_flag(lv.obj.FLAG.SCROLLABLE)
2.7.30 Textarea
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_BUILD_EXAMPLES
void lv_example_textarea_1(void)
{
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
(continues on next page)
lv_btnmatrix_set_map(btnm, btnm_map);
}
#endif
ta = lv.textarea(lv.scr_act())
ta.set_one_line(True)
ta.align(lv.ALIGN.TOP_MID, 0, 10)
ta.add_event_cb(lambda e: textarea_event_handler(e, ta), lv.EVENT.READY, None)
ta.add_state(lv.STATE.FOCUSED) # To be sure the cursor is visible
btnm = lv.btnmatrix(lv.scr_act())
btnm.set_size(200, 150)
btnm.align(lv.ALIGN.BOTTOM_MID, 0, -10)
btnm.add_event_cb(lambda e: btnm_event_handler(e, ta), lv.EVENT.VALUE_CHANGED, None)
btnm.clear_flag(lv.obj.FLAG.CLICK_FOCUSABLE) # To keep the text area focused on␣
,→button clicks
btnm.set_map(btnm_map)
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
void lv_example_textarea_2(void)
{
/*Create the password box*/
lv_obj_t * pwd_ta = lv_textarea_create(lv_scr_act());
lv_textarea_set_text(pwd_ta, "");
lv_textarea_set_password_mode(pwd_ta, true);
lv_textarea_set_one_line(pwd_ta, true);
lv_obj_set_width(pwd_ta, lv_pct(40));
lv_obj_set_pos(pwd_ta, 5, 20);
lv_obj_add_event_cb(pwd_ta, ta_event_cb, LV_EVENT_ALL, NULL);
/*Create a keyboard*/
kb = lv_keyboard_create(lv_scr_act());
lv_obj_set_size(kb, LV_HOR_RES, LV_VER_RES / 2);
#endif
def ta_event_cb(e):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.FOCUSED:
# Focus on the clicked text area
if kb != None:
kb.set_textarea(ta)
pwd_ta = lv.textarea(lv.scr_act())
pwd_ta.set_text("")
pwd_ta.set_password_mode(True)
pwd_ta.set_one_line(True)
pwd_ta.set_width(LV_HOR_RES // 2 - 20)
pwd_ta.set_pos(5, 20)
pwd_ta.add_event_cb(ta_event_cb, lv.EVENT.ALL, None)
# Create a keyboard
kb = lv.keyboard(lv.scr_act())
kb.set_size(LV_HOR_RES, LV_VER_RES // 2)
Text auto-formatting
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
/**
* Automatically format text like a clock. E.g. "12:34"
* Add the ':' automatically.
*/
void lv_example_textarea_3(void)
{
/*Create the text area*/
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_textarea_set_accepted_chars(ta, "0123456789:");
lv_textarea_set_max_length(ta, 5);
lv_textarea_set_one_line(ta, true);
lv_textarea_set_text(ta, "");
/*Create a keyboard*/
kb = lv_keyboard_create(lv_scr_act());
lv_obj_set_size(kb, LV_HOR_RES, LV_VER_RES / 2);
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);
lv_keyboard_set_textarea(kb, ta);
}
#endif
def ta_event_cb(e):
ta = e.get_target()
txt = ta.get_text()
# print(txt)
pos = ta.get_cursor_pos()
# print("cursor pos: ",pos)
# find position of ":" in text
colon_pos= txt.find(":")
# if there are more than 2 digits before the colon, remove the last one entered
if colon_pos == 3:
ta.del_char()
if colon_pos != -1:
# if there are more than 3 digits after the ":" remove the last one entered
(continues on next page)
if len(txt) < 2:
return
if ":" in txt:
return
if txt[0] >= '0' and txt[0] <= '9' and \
txt[1] >= '0' and txt[1] <= '9':
if len(txt) == 2 or txt[2] != ':' :
ta.set_cursor_pos(2)
ta.add_char(ord(':'))
#
# Automatically format text like a clock. E.g. "12:34"
# Add the ':' automatically
#
# Create the text area
LV_HOR_RES = lv.scr_act().get_disp().driver.hor_res
LV_VER_RES = lv.scr_act().get_disp().driver.ver_res
ta = lv.textarea(lv.scr_act())
ta.add_event_cb(ta_event_cb, lv.EVENT.VALUE_CHANGED, None)
ta.set_accepted_chars("0123456789:")
ta.set_max_length(5)
ta.set_one_line(True)
ta.set_text("")
ta.add_state(lv.STATE.FOCUSED)
# Create a keyboard
kb = lv.keyboard(lv.scr_act())
kb.set_size(LV_HOR_RES, LV_VER_RES // 2)
kb.set_mode(lv.keyboard.MODE.NUMBER)
kb.set_textarea(ta)
2.7.31 Tabview
#include "../../lv_examples.h"
#if LV_USE_TILEVIEW && LV_BUILD_EXAMPLES
/**
* Create a 2x2 tile view and allow scrolling only in an "L" shape.
* Demonstrate scroll chaining with a long list that
* scrolls the tile view when it can't be scrolled further.
*/
void lv_example_tileview_1(void)
{
lv_obj_t * tv = lv_tileview_create(lv_scr_act());
/*Tile2: a button*/
lv_obj_t * tile2 = lv_tileview_add_tile(tv, 0, 1, LV_DIR_TOP | LV_DIR_RIGHT);
label = lv_label_create(btn);
lv_label_set_text(label, "Scroll up or right");
/*Tile3: a list*/
lv_obj_t * tile3 = lv_tileview_add_tile(tv, 1, 1, LV_DIR_LEFT);
lv_obj_t * list = lv_list_create(tile3);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
#endif
#
# Create a 2x2 tile view and allow scrolling only in an "L" shape.
# Demonstrate scroll chaining with a long list that
# scrolls the tile view when it can't be scrolled further.
#
tv = lv.tileview(lv.scr_act())
# Tile2: a button
tile2 = tv.add_tile(0, 1, lv.DIR.TOP | lv.DIR.RIGHT)
btn = lv.btn(tile2)
label = lv.label(btn)
(continues on next page)
btn.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
btn.center()
# Tile3: a list
tile3 = tv.add_tile(1, 1, lv.DIR.LEFT)
list = lv.list(tile3)
list.set_size(lv.pct(100), lv.pct(100))
list.add_btn(None, "One")
list.add_btn(None, "Two")
list.add_btn(None, "Three")
list.add_btn(None, "Four")
list.add_btn(None, "Five")
list.add_btn(None, "Six")
list.add_btn(None, "Seven")
list.add_btn(None, "Eight")
list.add_btn(None, "Nine")
list.add_btn(None, "Ten")
2.7.32 Window
Simple window
#include "../../lv_examples.h"
#if LV_USE_WIN && LV_BUILD_EXAMPLES
void lv_example_win_1(void)
{
lv_obj_t * win = lv_win_create(lv_scr_act(), 40);
lv_obj_t * btn;
btn = lv_win_add_btn(win, LV_SYMBOL_LEFT, 40);
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
print("Button {:d} clicked".format(obj.get_child_id()))
We need
quite some text
and we will
even put
some more
text to be
sure it
overflows.
""")
THREE
GET STARTED
There are several ways to get your feet wet with LVGL. Here is one recommended order of documents to read and things
to play with when you are learning to use LVGL:
1. Check the Online demos to see LVGL in action (3 minutes)
2. Read the Introduction page of the documentation (5 minutes)
3. Read the Quick overview page of the documentation (15 minutes)
4. Set up a Simulator (10 minutes)
5. Try out some Examples
6. Check out the Platform-specific tutorials. (in this section below). (10 minutes)
7. Port LVGL to a board. See the Porting guide or check the ready to use Projects
8. Read the Overview page to get a better understanding of the library. (2-3 hours)
9. Check the documentation of the Widgets to see their features and usage
10. If you have questions got to the Forum
11. Read the Contributing guide to see how you can help to improve LVGL (15 minutes)
Here you can learn the most important things about LVGL. You should read this first to get a general impression and read
the detailed Porting and Overview sections after that.
Instead of porting LVGL to embedded hardware straight away, it's highly recommended to get started in a simulator first.
LVGL is ported to many IDEs to be sure you will find your favorite one. Go to the Simulators section to get ready-to-use
projects that can be run on your PC. This way you can save the time of porting for now and get some experience with
LVGL immediately.
220
LVGL Documentation 8.3
If you would rather try LVGL on your own project follow these steps:
• Download or clone the library from GitHub with git clone https://github.com/lvgl/lvgl.git.
• Copy the lvgl folder into your project.
• Copy lvgl/lv_conf_template.h as lv_conf.h next to the lvgl folder, change the first #if 0 to 1
to enable the file's content and set the LV_COLOR_DEPTH defines.
• Include lvgl/lvgl.h in files where you need to use LVGL related functions.
• Call lv_tick_inc(x) every x milliseconds in a Timer or Task (x should be between 1 and 10). It is required
for the internal timing of LVGL. Alternatively, configure LV_TICK_CUSTOM (see lv_conf.h) so that LVGL
can retrieve the current time directly.
• Call lv_init()
• Create a draw buffer: LVGL will render the graphics here first, and send the rendered image to the display. The
buffer size can be set freely but 1/10 screen size is a good starting point.
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[DISP_HOR_RES * DISP_VER_RES / 10]; /
,→*Declare a buffer for 1/10 screen size*/
• Implement and register a function which can copy the rendered image to an area of your display:
static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
disp_drv.draw_buf = &draw_buf; /*Assign the buffer to the display*/
disp_drv.hor_res = MY_DISP_HOR_RES; /*Set the horizontal resolution of the display*/
disp_drv.ver_res = MY_DISP_VER_RES; /*Set the vertical resolution of the display*/
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
• Implement and register a function which can read an input device. E.g. for a touchpad:
static lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
(continues on next page)
• Call lv_timer_handler() periodically every few milliseconds in the main while(1) loop or in an oper-
ating system task. It will redraw the screen if required, handle input devices, animation etc.
For a more detailed guide go to the Porting section.
Widgets
The graphical elements like Buttons, Labels, Sliders, Charts etc. are called objects or widgets. Go to Widgets to see the
full list of available widgets.
Every object has a parent object where it is created. For example, if a label is created on a button, the button is the parent
of label.
The child object moves with the parent and if the parent is deleted the children will be deleted too.
Children can be visible only within their parent's bounding area. In other words, the parts of the children outside the
parent are clipped.
A Screen is the "root" parent. You can have any number of screens.
To get the current screen call lv_scr_act(), and to load a screen use lv_scr_load(scr1).
You can create a new object with lv_<type>_create(parent). It will return an lv_obj_t * variable that can
be used as a reference to the object to set its parameters.
For example:
To set some basic attributes lv_obj_set_<parameter_name>(obj, <value>) functions can be used. For
example:
lv_obj_set_x(btn1, 30);
lv_obj_set_y(btn1, 10);
lv_obj_set_size(btn1, 200, 50);
Along with the basic attributes, widgets can have type specific parameters which are set by
lv_<widget_type>_set_<parameter_name>(obj, <value>) functions. For example:
To see the full API visit the documentation of the widgets or the related header file (e.g. lvgl/src/widgets/lv_slider.h).
Events
Events are used to inform the user that something has happened with an object. You can assign one or more callbacks to
an object which will be called if the object is clicked, released, dragged, being deleted, etc.
A callback is assigned like this:
...
void btn_event_cb(lv_event_t * e)
{
printf("Clicked\n");
}
LV_EVENT_ALL can be used instead of LV_EVENT_CLICKED to invoke the callback for any event.
From lv_event_t * e the current event code can be retrieved with:
Parts
Widgets might be built from one or more parts. For example, a button has only one part called LV_PART_MAIN.
However, a Slider has LV_PART_MAIN, LV_PART_INDICATOR and LV_PART_KNOB.
By using parts you can apply different styles to sub-elements of a widget. (See below)
Read the widgets' documentation to learn which parts each uses.
States
For example, if you press an object it will automatically go to the LV_STATE_FOCUSED and LV_STATE_PRESSED
states and when you release it the LV_STATE_PRESSED state will be removed while focus remains active.
To check if an object is in a given state use lv_obj_has_state(obj, LV_STATE_...). It will return true if
the object is currently in that state.
To manually add or remove states use:
lv_obj_add_state(obj, LV_STATE_...);
lv_obj_clear_state(obj, LV_STATE_...);
Styles
A style instance contains properties such as background color, border width, font, etc. that describe the appearance of
objects.
Styles are represented with lv_style_t variables. Only their pointer is saved in the objects so they need to be defined
as static or global. Before using a style it needs to be initialized with lv_style_init(&style1). After that,
properties can be added to configure the style. For example:
Styles can be cascaded (similarly to CSS). It means you can add more styles to a part of an object. For example
style_btn can set a default button appearance, and style_btn_red can overwrite the background color to make
the button red:
If a property is not set on for the current state, the style with LV_STATE_DEFAULT will be used. A default value is
used if the property is not defined in the default state.
Some properties (typically the text-related ones) can be inherited. This means if a property is not set in an object it will
be searched for in its parents too. For example, you can set the font once in the screen's style and all text on that screen
will inherit it by default.
Local style properties also can be added to objects. This creates a style which resides inside the object and is used only
by the object:
To learn all the features of styles see the Style overview section.
Themes
Themes are the default styles for objects. Styles from a theme are applied automatically when objects are created.
The theme for your application is a compile time configuration set in lv_conf.h.
3.1.4 Examples
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN
/*Get the first child of the button which is the label and change its text*/
lv_obj_t * label = lv_obj_get_child(btn, 0);
lv_label_set_text_fmt(label, "Button: %d", cnt);
}
}
/**
* Create a button with a label and react on click event.
*/
void lv_example_get_started_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act()); /*Add a button the current␣
,→screen*/
#endif
class CounterBtn():
def __init__(self):
self.cnt = 0
#
# Create a button with a label and react on click event.
#
def btn_event_cb(self,evt):
code = evt.get_code()
btn = evt.get_target()
if code == lv.EVENT.CLICKED:
self.cnt += 1
# Get the first child of the button which is the label and change its text
label = btn.get_child(0)
label.set_text("Button: " + str(self.cnt))
counterBtn = CounterBtn()
#include "../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
{
LV_UNUSED(dsc);
return lv_color_darken(color, opa);
}
lv_style_set_border_color(&style_btn, lv_color_black());
lv_style_set_border_opa(&style_btn, LV_OPA_20);
lv_style_set_border_width(&style_btn, 2);
lv_style_set_text_color(&style_btn, lv_color_black());
/**
* Create styles from scratch for buttons.
*/
void lv_example_get_started_2(void)
{
/*Initialize the style*/
style_init();
label = lv_label_create(btn2);
lv_label_set_text(label, "Button 2");
lv_obj_center(label);
}
#endif
#
# Create styles from scratch for buttons.
#
style_btn = lv.style_t()
style_btn_red = lv.style_t()
style_btn_pressed = lv.style_t()
# Add a border
style_btn.set_border_color(lv.color_white())
style_btn.set_border_opa(lv.OPA._70)
style_btn.set_border_width(2)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SLIDER
/**
* Create a slider and write its value on a label.
*/
void lv_example_get_started_3(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_set_width(slider, 200); /*Set the width*/
lv_obj_center(slider); /*Align to the center of␣
,→the parent (screen)*/
#endif
def slider_event_cb(evt):
slider = evt.get_target()
#
# Create a slider and write its value on a label.
#
3.1.5 Micropython
3.2 Platforms
3.2.1 Simulator on PC
You can try out LVGL using only your PC (i.e. without any development boards). LVGL will run on a simulator
environment on the PC where anyone can write and experiment with real LVGL applications.
Using the simulator on a PC has the following advantages:
• Hardware independent - Write code, run it on the PC and see the result on a monitor.
• Cross-platform - Any Windows, Linux or macOS system can run the PC simulator.
• Portability - The written code is portable, which means you can simply copy it when migrating to embedded hard-
ware.
• Easy Validation - The simulator is also very useful to report bugs because it provides a common platform for every
user. So it's a good idea to reproduce a bug in the simulator and use that code snippet in the Forum.
Select an IDE
The simulator is ported to various IDEs (Integrated Development Environments). Choose your favorite IDE, read its
README on GitHub, download the project, and load it to the IDE.
• Eclipse with SDL driver: Recommended on Linux and Mac
• CodeBlocks: Recommended on Windows
• VisualStudio: For Windows
• VSCode with SDL driver: Recommended on Linux and Mac
• PlatformIO with SDL driver: Recommended on Linux and Mac
• MDK with FastModel: For Windows
External project not maintained by the LVGL organization:
• QT Creator: Cross platform
You can use any IDE for development but, for simplicity, the configuration for Eclipse CDT is what we'll focus on in this
tutorial. The following section describes the set-up guide of Eclipse CDT in more detail.
Note: If you are on Windows, it's usually better to use the Visual Studio or CodeBlocks projects instead. They
work out of the box without requiring extra steps.
You can download Eclipse's CDT from: https://www.eclipse.org/cdt/downloads.php. Start the installer and choose
Eclipse CDT from the list.
Install SDL 2
The PC simulator uses the SDL 2 cross-platform library to simulate a TFT display and a touchpad.
Linux
Windows
If you are using Windows firstly you need to install MinGW (64 bit version). After installing MinGW, do the following
steps to add SDL2:
1. Download the development libraries of SDL. Go to https://www.libsdl.org/download-2.0.php and download De-
velopment Libraries: SDL2-devel-2.0.5-mingw.tar.gz
2. Decompress the file and go to x86_64-w64-mingw32 directory (for 64 bit MinGW) or to i686-w64-mingw32 (for
32 bit MinGW)
3. Copy _...mingw32/include/SDL2 folder to C:/MinGW/.../x86_64-w64-mingw32/include
4. Copy _...mingw32/lib/ content to C:/MinGW/.../x86_64-w64-mingw32/lib
5. Copy _...mingw32/bin/SDL2.dll to {eclipse_workspace}/pc_simulator/Debug/. Do it later when Eclipse is installed.
Note: If you are using Microsoft Visual Studio instead of Eclipse then you don't have to install MinGW.
OSX
On OSX you can easily install SDL2 with brew: brew install sdl2
If something is not working, then please refer this tutorial to get started with SDL.
Pre-configured project
A pre-configured graphics library project (based on the latest release) is always available to get started easily. You can
find the latest one on GitHub. (Please note that, the project is configured for Eclipse CDT).
Run Eclipse CDT. It will show a dialogue about the workspace path. Before accepting the path, check that path and
copy (and unzip) the downloaded pre-configured project there. After that, you can accept the workspace path. Of course
you can modify this path but in that case copy the project to the corresponding location.
Close the start-up window and go to File->Import and choose General->Existing project into Workspace. Browse
the root directory of the project and click Finish
On Windows you have to do two additional things:
• Copy the SDL2.dll into the project's Debug folder
• Right-click on the project -> Project properties -> C/C++ Build -> Settings -> Libraries -> Add ... and add mingw32
above SDLmain and SDL. (The order is important: mingw32, SDLmain, SDL)
Now you are ready to run LVGL on your PC. Click on the Hammer Icon on the top menu bar to Build the project. If you
have done everything right, then you will not get any errors. Note that on some systems additional steps might be required
to "see" SDL 2 from Eclipse but in most cases the configuration in the downloaded project is enough.
After a successful build, click on the Play button on the top menu bar to run the project. Now a window should appear in
the middle of your screen.
Now you are ready to use LVGL and begin development on your PC.
3.2.2 NXP
NXP has integrated LVGL into the MCUXpresso SDK packages for general purpose and crossover microcontrollers,
allowing easy evaluation and migration into your product design. Download an SDK for a supported board today and get
started with your next GUI application.
Downloading the MCU SDK example project is recommended as a starting point. It comes fully configured with LVGL
(and with PXP/VGLite support if the modules are present), no additional integration work is required.
Depending on the RT platform used, the acceleration can be done by NXP PXP (PiXel Pipeline) and/or the Verisilicon
GPU through an API named VGLite. Each accelerator has its own context that allows them to be used individually as
well simultaneously (in LVGL multithreading mode).
PXP accelerator
Several drawing features in LVGL can be offloaded to the PXP engine. The CPU is available for other operations while
the PXP is running. RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU
for power savings.
Supported draw callbacks are available in "src/draw/nxp/pxp/lv_draw_pxp.c":
pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded;
pxp_draw_ctx->blend = lv_draw_pxp_blend;
pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish;
pxp_draw_ctx->base_draw.buffer_copy = lv_draw_pxp_buffer_copy;
Features supported:
Known limitations:
• Rotation is not supported for images unaligned to blocks of 16x16 pixels. PXP is set to process 16x16 blocks to
optimize the system for memory bandwidth and image processing time. The output engine essentially truncates
any output pixels after the desired number of pixels has been written. When rotating a source image and the output
is not divisible by the block size, the incorrect pixels could be truncated and the final output image can look shifted.
Basic configuration:
Basic initialization:
#if LV_USE_GPU_NXP_PXP
#include "src/draw/nxp/pxp/lv_gpu_nxp_pxp.h"
#endif
. . .
#if LV_USE_GPU_NXP_PXP
PXP_COND_STOP(!lv_gpu_nxp_pxp_init(), "PXP init failed.");
#endif
Project setup:
Logging:
• By default, LV_GPU_NXP_PXP_LOG_ERRORS is enabled so that any PXP error will be seen on SDK debug
console
• By default, LV_GPU_NXP_PXP_LOG_TRACES is disabled. Enable it for tracing logs (like PXP limitations)
Advanced configuration:
• Implementation depends on multiple OS-specific functions. The struct lv_nxp_pxp_cfg_t with callback
pointers is used as a parameter for the lv_gpu_nxp_pxp_init() function. Default implementation for
FreeRTOS and bare metal is provided in lv_gpu_nxp_pxp_osa.c
– pxp_interrupt_init(): Initialize PXP interrupt (HW setup, OS setup)
– pxp_interrupt_deinit(): Deinitialize PXP interrupt (HW setup, OS setup)
– pxp_run(): Start PXP job. Use OS-specific mechanism to block drawing thread. PXP must finish drawing
before leaving this function.
• Area threshold (size limit) is configurable and used to decide whether the area will be processed by PXP or not.
Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be processed
by PXP. The threshold is defined as a macro in lv_draw_pxp.c
– LV_GPU_NXP_PXP_SIZE_LIMIT: size threshold for fill/blit (with optional transformation)
VGLite accelerator
Extra drawing features in LVGL can be handled by the VGLite engine. The CPU is available for other operations while
the VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend
the CPU for power savings.
Supported draw callbacks are available in "src/draw/nxp/vglite/lv_draw_vglite.c":
vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
vglite_draw_ctx->blend = lv_draw_vglite_blend;
vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
vglite_draw_ctx->base_draw.buffer_copy = lv_draw_vglite_buffer_copy;
Features supported:
• Buffer copy
Known limitations:
• Source image alignment: The byte alignment requirement for a pixel depends on the specific pixel format. Both
buffer address and buffer stride must be aligned. As general rule, the alignment is set to 16 pixels. This makes the
buffer address alignment to be 32 bytes for RGB565 and 64 bytes for ARGB8888.
• For pixel engine (PE) destination, the alignment should be 64 bytes for all tiled (4x4) buffer layouts. The pixel
engine has no additional alignment requirement for linear buffer layouts (VG_LITE_LINEAR).
Basic configuration:
Basic initialization:
• Initialize VGLite before calling lv_init() by specifying the width/height of tessellation window. Value should
be a multiple of 16; minimum value is 16 pixels, maximum cannot be greater than the frame width. If less than or
equal to 0, then no tessellation buffer is created, in which case VGLite is initialized only for blitting.
#if LV_USE_GPU_NXP_VG_LITE
#include "vg_lite.h"
#endif
. . .
#if LV_USE_GPU_NXP_VG_LITE
VG_LITE_COND_STOP(vg_lite_init(64, 64) != VG_LITE_SUCCESS, "VGLite init␣
,→failed.");
#endif
Project setup:
Logging:
• By default, LV_GPU_NXP_VG_LITE_LOG_ERRORS is enabled so that any VGLite error will be seen on SDK
debug console
• By default, LV_GPU_NXP_VG_LITE_LOG_TRACES is disabled. Enable it for tracing logs (like blit split
workaround or VGLite fallback to CPU due to any error on the driver)
Advanced configuration:
• Area threshold (size limit) is configurable and used to decide whether the area will be processed by VGLite or
not. Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be
processed by VGLite. The threshold is defined as a macro in lv_draw_vglite.c
– LV_GPU_NXP_VG_LITE_SIZE_LIMIT: size threshold for fill/blit (with optional transformation)
3.2.3 STM32
TODO
We've created lv_port_esp32, a project using ESP-IDF and LVGL to show one of the demos from demos. You can
configure the project to use one of the many supported display controllers and targets (chips).
See lvgl_esp32_drivers repository for a complete list of supported display and indev (touch) controllers and targets.
Prerequisites
Obtaining LVGL
The above command will clone LVGL's main repository into the components/lvgl directory. LVGL includes a
CMakeLists.txt file that sets some configuration options so you can use LVGL right away.
Option 2: IDF Component Manager
LVGL is also distributed through IDF Component Manager. It allows users to seamlessly integrate LVGL component
into their project with following command:
During next project build, LVGL component will be fetched from the component registry and added to project build.
Configuration
When you are ready to configure LVGL, launch the configuration menu with idf.py menuconfig in your project
root directory, go to Component config and then LVGL configuration.
You can also add lvgl_esp32_drivers as a "component". This component should be located inside a directory
named "components" in your project root directory.
When your project is a git repository you can include lvgl_esp32_drivers as a git submodule:
3.2.5 Renesas
The HMI-Board development board SDK now comes with LVGL integration for quick evaluation. Simply download the
SDK for the supported motherboard and you’ll be on your way to creating your next GUI application in no time. For
more information, check out the Software design description.
It is recommended to start your project by downloading the HMI-Board SDK example project. It comes fully equipped
with LVGL and dave-2d support (if the modules are present), so you won’t need to do any additional integration work.
For RA6M3 platforms, hardware acceleration can be achieved using the dave-2d GPU, depending on the platform used.
Each accelerator has its own context, allowing them to be used individually or simultaneously in LVGL’s multithreading
mode.
Dave-2d accelerator
LVGL can offload several drawing features to the dave-2d engine, freeing up the CPU for other operations while dave-2d
runs. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for power
savings. Supported draw callbacks can be found in “src/draw/renesas/lv_gpu_d2_ra6m3.c”.
LVGL can offload several drawing features to the dave-2d engine, freeing up the CPU for other operations while dave-2d
runs. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for power
savings. Supported draw callbacks can be found in “src/draw/renesas/lv_gpu_d2_ra6m3.c”.
ra_2d_draw_ctx->blend = lv_draw_ra6m3_2d_blend;
ra_2d_draw_ctx->base_draw.draw_img_decoded = lv_port_gpu_img_decoded;
ra_2d_draw_ctx->base_draw.wait_for_finish = lv_port_gpu_wait;
ra_2d_draw_ctx->base_draw.draw_letter = lv_draw_gpu_letter;
Features supported:
Basic configuration:
RT-Thread Example:
• After initializing your peripherals (such as SPI, GPIOs, and LCD) in the lv_port_disp_init() function, you
can initialize LVGL using lv_init(). Next, register the frame buffers using lv_disp_draw_buf_init()
and create a new display driver using lv_disp_drv_init().
/*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_
,→2 */
• To run LVGL, you’ll need to create a thread. You can find examples of how to do this using RT-Thread in the
env_support/rt-thread/lv_rt_thread_port.c file.
static void lvgl_thread_entry(void *parameter)
{
#if LV_USE_LOG
lv_log_register_print_cb(lv_rt_log);
#endif /* LV_USE_LOG */
lv_init();
lv_port_disp_init();
lv_port_indev_init();
lv_user_gui_init();
if(err != RT_EOK)
{
LOG_E("Failed to create LVGL thread");
return -1;
}
rt_thread_startup(&lvgl_thread);
return 0;
}
INIT_ENV_EXPORT(lvgl_thread_init);
• The last step is to create a function to output the frame buffer to your LCD. The specifics of this function will
depend on the features of your MCU. Here’s an example for a typical MCU interface: my_flush_cb.
{
#ifdef PKG_USING_ILI9341
lcd_fill_array_spi(area->x1, area->y1, area->x2, area->y2, color_p);
#elif LV_USE_GPU_RA6M3_G2D
lv_port_gpu_blit(area->x1, area->y1, color_p, area);
#else
......
#endif
lv_disp_flush_ready(disp_drv);
}
3.2.6 Arduino
LVGL can be installed via the Arduino IDE Library Manager or as a .ZIP library.
You can Download the latest version of LVGL from GitHub and simply copy it to Arduino's library folder.
Set up drivers
To get started it's recommended to use TFT_eSPI library as a TFT driver to simplify testing. To make it work, setup
TFT_eSPI according to your TFT display type via editing either
• User_Setup.h
• or by selecting a configuration in the User_Setup_Select.h
Both files are located in TFT_eSPI library's folder.
Configure LVGL
LVGL has its own configuration file called lv_conf.h. When LVGL is installed, follow these configuration steps:
1. Go to the directory of the installed Arduino libraries
2. Go to lvgl and copy lv_conf_template.h as lv_conf.h into the Arduino Libraries directory next to
the lvgl library folder.
3. Open lv_conf.h and change the first #if 0 to #if 1 to enable the content of the file
4. Set the color depth of you display in LV_COLOR_DEPTH
5. Set LV_TICK_CUSTOM 1
Finally the layout with lv_conf.h should look like this:
arduino
|-libraries
|-lvgl
|-other_lib_1
|-other_lib_2
|-lv_conf.h
Take a look at LVGL_Arduino.ino to see how to initialize LVGL. TFT_eSPI is used as the display driver.
In the INO file you can see how to register a display and a touchpad for LVGL and call an example.
Note that, there is no dedicated INO file for every example. Instead, you can load an example by calling an
lv_example_... function. For example lv_example_btn_1().
IMPORTANT NOTE 1 Due to some the limitations of Arduino's build system you need to copy lvgl/examples
to lvgl/src/examples. Similarly for the demos lvgl/demos to lvgl/src/demos.
IMPORTANT NOTE 2 Note that the lv_examples library is for LVGL v7 and you shouldn't install it for this version
(since LVGL v8) as the examples and demos are now part of the main LVGL library.
LVGL can display debug information in case of trouble. In the LVGL_Arduino.ino example there is a my_print
method, which sends this debug information to the serial interface. To enable this feature you have to edit the lv_conf.
h file and enable logging in the section log settings:
/*Log settings*/
#define USE_LV_LOG 1 /*Enable/disable the log module*/
#if LV_USE_LOG
/* How important log should be added:
* LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
* LV_LOG_LEVEL_INFO Log important events
* LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a␣
,→problem
After enabling the log module and setting LV_LOG_LEVEL accordingly, the output log is sent to the Serial port @
115200 bps.
What is Tasmota?
Tasmota is a widely used open-source firmware for ESP8266 and EPS32 based devices. It supports a wide variety of
devices, sensors and integrations to Home Automation and Cloud services. Tasmota firmware is downloaded more than
200,000 times each month, and has an active and growing community.
Tasmota provides access to hundreds of supported devices, full support of MQTT, HTTP(S), integration with major
Home Automation systems, myriad of sensors, IR, RF, Zigbee, Bluetooth, AWS IoT, Azure IoT, Alexa and many more.
What is Berry?
Berry is a ultra-lightweight dynamically typed embedded scripting language. It is designed for lower-performance em-
bedded devices. The interpreter of Berry include a one-pass compiler and register-based VM, all the code is written in
ANSI C99. Berry offers a syntax very similar to Python, and is inspired from LUA VM. It is fully integrated in Tasmota
Highlights of Berry
In 2021, Tasmota added full support of LVGL for ESP32 based devices. It also introduced the Berry scripting language,
a small-footprint language similar to Python and fully integrated in Tasmota.
A comprehensive mapping of LVGL in Berry language is now available, similar to the mapping of Micropython. It allows
to use +98% of all LVGL features. It is also possible to write custom widgets in Berry.
Versions supported: LVGL v8.3.0, LodePNG v20201017, Freetype 2.10.4
TL;DR: Similar to MicroPython, it's very much like the C API, but Object-Oriented for LVGL components.
Let's dive right into an example!
A simple example
You can start in less than 10 minutes on a M5Stack or equivalent device in less than 10 minutes in this short tutorial
3.2.8 CMake
LVGL supports integrating with CMake. It comes with preconfigured targets for:
On top of the preconfigured targets you can also use "plain" CMake to integrate LVGL into any custom C/C++ project.
Prerequisites
There are many ways to include external CMake projects into your own. A modern one also used in this example is the
CMake FetchContent module. This module conveniently allows us to download dependencies directly at configure time
from e.g. GitHub. Here is an example how we might include LVGL into our own project.
cmake_minimum_required(VERSION 3.14)
include(FetchContent)
This configuration declares a dependency between the two targets MyFirmware and lvgl. Upon building the target
MyFirmware this dependency will be resolved and lvgl will be built and linked with it. Since LVGL requires a config
header called lv_conf.h to be includable by its sources we also set the option LV_CONF_PATH to point to our own copy
of it.
Besides LV_CONF_PATH there are two additional CMake options to specify include paths.
LV_LVGL_H_INCLUDE_SIMPLE which specifies whether to #include "lvgl.h" absolut or relative
LV_CONF_INCLUDE_SIMPLE which specifies whether to #include "lv_conf.h" and "lv_drv_conf.h"
absolut or relative
I do not recommend disabling those options unless your folder layout makes it absolutely necessary.
LVGL examples have their own CMake target. If you want to build the examples simply add them to your dependencies.
Exactly the same goes for the drivers and the demos.
FetchContent_Declare(lv_drivers
GIT_REPOSITORY https://github.com/lvgl/lv_drivers)
FetchContent_MakeAvailable(lv_drivers)
By default, LVGL will be built as a static library (archive). CMake can instead be instructed to build LVGL as shared
library (.so/.dll/etc.):
set(BUILD_SHARED_LIBS ON)
OR
$ cmake "-DBUILD_SHARED_LIBS=ON" .
3.3 (RT)OS
What is NuttX?
NuttX is a mature and secure real-time operating system (RTOS) with an emphasis on technical standards compliance
and small size. It is scalable from 8-bit to 64-bit microcontrollers and microprocessors and compliant with the Portable
Operating System Interface (POSIX) and the American National Standards Institute (ANSI) standards and with many
Linux-like subsystems. The best way to think about NuttX is to think of it as a small Unix/Linux for microcontrollers.
Highlights of NuttX
Although NuttX has its own graphic library called NX, LVGL is a good alternative because users could find more eye-
candy demos and they can reuse code from previous projects. LVGL is an Object-Oriented Component Based high-level
GUI library, that could fit very well for a RTOS with advanced features like NuttX. LVGL is implemented in C and its
APIs are in C.
• Develop GUI in Linux first and when it is done just compile it for NuttX. Nothing more, no wasting of time.
• Usually, GUI development for low level RTOS requires multiple iterations to get things right, where each iteration
consists of Change code > Build > Flash > Run. Using LVGL, Linux and NuttX you can reduce this
process and just test everything on your computer and when it is done, compile it on NuttX and that is it.
There are many boards in the NuttX mainline with support for LVGL. Let's use the STM32F429IDISCOVERY as an
example because it is a very popular board.
,→frontends openocd
$ mkdir ~/nuttxspace
$ cd ~/nuttxspace
Configure NuttX to use the stm32f429i-disco board and the LVGL Demo
$ ./tools/configure.sh stm32f429i-disco:lvgl
$ make
If everything went fine you should have now the file nuttx.bin to flash on your board:
$ ls -l nuttx.bin
-rwxrwxr-x 1 alan alan 287144 Jun 27 09:26 nuttx.bin
Reset the board and using the 'NSH>' terminal start the LVGL demo:
nsh> lvgldemo
What is RT-Thread?
Key features
• Designed for resource-constrained devices, the minimum kernel requires only 1.2KB of RAM and 3 KB of Flash.
• A variety of standard interfaces, such as POSIX, CMSIS, C++ application environment.
• Has rich components and a prosperous and fast growing package ecosystem
• Elegant code style, easy to use, read and master.
• High Scalability. RT-Thread has high-quality scalable software architecture, loose coupling, modularity, is easy to
tailor and expand.
• Supports high-performance applications.
• Supports all mainstream compiling tools such as GCC, Keil and IAR.
• Supports a wide range of architectures and chips.
2/72/72/72/7
LVGL has registered as a software package of RT-Thread. By using Env tool or RT-Thread Studio IDE, RT-Thread users
can easily download LVGL source code and combine with RT-Thread project. RT-Thread community has port LVGL to
several BSPs:
Clone the latest code from RT-Thread official repository. Open the RT-Thread Studio and select File -> Import.
In the Import menu, please select RT-Thread BSP Project into Workspace, and click next button. In the
BSP location area, please select the root path of the BSP which you prefer to import, such as C:\Users\xxx\
Desktop\rt-thread\bsp\stm32\stm32l475-atk-pandora. In the Project Name area, please
type a name for this project, then, press Finish button.
3.3.3 FreeRTOS
TODO
3.3.4 Zephyr
TODO
3.4 Bindings
3.4.1 Micropython
What is Micropython?
Micropython is Python for microcontrollers. Using Micropython, you can write Python3 code and run it even on a bare
metal architecture with limited resources.
Highlights of Micropython
• Compact - Fits and runs within just 256k of code space and 16k of RAM. No OS is needed, although you can also
run it with an OS, if you want.
• Compatible - Strives to be as compatible as possible with normal Python (known as CPython).
• Versatile - Supports many architectures (x86, x86-64, ARM, ARM Thumb, Xtensa).
• Interactive - No need for the compile-flash-boot cycle. With the REPL (interactive prompt) you can type com-
mands and execute them immediately, run scripts, etc.
• Popular - Many platforms are supported. The user base is growing bigger. Notable forks: MicroPython, Circuit-
Python, MicroPython_ESP32_psRAM_LoBo
• Embedded Oriented - Comes with modules specifically for embedded systems, such as the machine module for
accessing low-level hardware (I/O pins, ADC, UART, SPI, I2C, RTC, Timers etc.)
Currently, Micropython does not have a good high-level GUI library by default. LVGL is an Object-Oriented Component
Based high-level GUI library, which seems to be a natural candidate to map into a higher level language, such as Python.
LVGL is implemented in C and its APIs are in C.
• Develop GUI in Python, a very popular high level language. Use paradigms such as Object-Oriented Programming.
• Usually, GUI development requires multiple iterations to get things right. With C, each iteration consists of
Change code > Build > Flash > Run. In Micropython it's just Change code > Run ! You can
even run commands interactively using the REPL (the interactive prompt)
TL;DR: It's very much like the C API, but Object-Oriented for LVGL components.
Let's dive right into an example!
A simple example
import lvgl as lv
lv.init()
scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")
lv.scr_load(scr)
Online Simulator
If you want to experiment with LVGL + Micropython without downloading anything - you can use our online simulator!
It's a fully functional LVGL + Micropython that runs entirely in the browser and allows you to edit a python script and
run it.
Click here to experiment on the online simulator
Hello World
Note: the online simulator is available for lvgl v6 and v7.
PC Simulator
Micropython is ported to many platforms. One notable port is "unix", which allows you to build and run Micropython
(+LVGL) on a Linux machine. (On a Windows machine you might need Virtual Box or WSL or MinGW or Cygwin etc.)
Click here to know more information about building and running the unix port
Embedded platform
In the end, the goal is to run it all on an embedded platform. Both Micropython and LVGL can be used on many
embedded architectures, such as stm32, ESP32 etc. You would also need display and input drivers. We have some
sample drivers (ESP32+ILI9341, as well as some other examples), but chances are you would want to create your own
input/display drivers for your specific hardware. Drivers can be implemented either in C as a Micropython module, or in
pure Micropython!
3.4.2 Cpp
In progress: https://github.com/lvgl/lv_binding_cpp
FOUR
PORTING
The graphics library itself is the lvgl directory. It contains a couple of folders but to use lvgl you only need .c and
.h files from the src folder.
If your IDE automatically adds the files from the folders copied to the project folder (as Eclipse or VSCode does), you
can simply copy the lvgl folder as it is into your project.
LVGL also supports make and CMake build systems out of the box. To add LVGL to your Makefile based build system
add these lines to your main Makefile:
LVGL_DIR_NAME ?= lvgl #The name of the lvgl folder (change this if you have␣
,→renamed it)
For integration with CMake take a look this section of the Documentation.
254
LVGL Documentation 8.3
The Get started section contains many platform specific descriptions e.g. for ESP32, Arduino, NXP, RT-Thread, NuttX,
etc.
The lvgl folder also contains an examples and a demos folder. If you needed to add the source files manually to
your project, you can do the same with the source files of these two folders too. make and CMake handles the examples
and demos, so no extra action required in these cases.
There is a configuration header file for LVGL called lv_conf.h. You modify this header to set the library's basic behavior,
disable unused modules and features, adjust the size of memory buffers in compile-time, etc.
To get lv_conf.h copy lvgl/lv_conf_template.h next to the lvgl directory and rename it to lv_conf.h. Open the file
and change the #if 0 at the beginning to #if 1 to enable its content. So the layout of the files should look like this:
|-lvgl
|-lv_conf.h
|-other files and folders
Comments in the config file explain the meaning of the options. Be sure to set at least LV_COLOR_DEPTH according to
your display's color depth. Note that, the examples and demos explicitly need to be enabled in lv_conf.h.
Alternatively, lv_conf.h can be copied to another place but then you should add the LV_CONF_INCLUDE_SIMPLE
define to your compiler options (e.g. -DLV_CONF_INCLUDE_SIMPLE for GCC compiler) and set the include path
manually (e.g. -I../include/gui). In this case LVGL will attempt to include lv_conf.h simply with #in-
clude "lv_conf.h".
You can even use a different name for lv_conf.h. The custom path can be set via the LV_CONF_PATH define. For
example -DLV_CONF_PATH="/home/joe/my_project/my_custom_conf.h"
If LV_CONF_SKIP is defined, LVGL will not try to include lv_conf.h. Instead you can pass the config defines using
build options. For example "-DLV_COLOR_DEPTH=32 -DLV_USE_BTN=1". The unset options will get a default
value which is the same as the ones in lv_conf_template.h.
LVGL also can be used via Kconfig and menuconfig. You can use lv_conf.h together with Kconfig, but keep
in mind that the value from lv_conf.h or build settings (-D...) overwrite the values set in Kconfig. To ignore the
configs from lv_conf.h simply remove its content, or define LV_CONF_SKIP.
4.1.4 Initialization
To use the graphics library you have to initialize it and setup required components. The order of the initialization is:
1. Call lv_init().
2. Initialize your drivers.
3. Register the display and input devices drivers in LVGL. Learn more about Display and Input device registration.
4. Call lv_tick_inc(x) every x milliseconds in an interrupt to report the elapsed time to LVGL. Learn more.
5. Call lv_timer_handler() every few milliseconds to handle LVGL related tasks. Learn more.
To register a display for LVGL, a lv_disp_draw_buf_t and a lv_disp_drv_t variable have to be initialized.
• lv_disp_draw_buf_t contains internal graphic buffer(s) called draw buffer(s).
• lv_disp_drv_t contains callback functions to interact with the display and manipulate low level drawing be-
havior.
Draw buffer(s) are simple array(s) that LVGL uses to render the screen content. Once rendering is ready the content of
the draw buffer is sent to the display using the flush_cb function set in the display driver (see below).
A draw buffer can be initialized via a lv_disp_draw_buf_t variable like this:
/*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_
,→2 */
Note that lv_disp_draw_buf_t must be a static, global or dynamically allocated variable. It cannot be a local
variable as they are destroyed upon end of scope.
As you can see above, the draw buffer may be smaller than the screen. In this case, larger areas are redrawn in smaller
segments that fit into the draw buffer(s). If only a small area changes (e.g. a button is pressed) then only that area will be
refreshed.
A larger buffer results in better performance but above 1/10 screen sized buffer(s) there is no significant performance
improvement. Therefore it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized.
There are several settings to adjust the number draw buffers and buffering/refreshing modes.
You can measure the performance of different configurations using the benchmark example.
One buffer
If only one buffer is used LVGL draws the content of the screen into that draw buffer and sends it to the display. LVGL
then needs to wait until the content of the buffer is sent to the display before drawing something new in it.
Two buffers
If two buffers are used LVGL can draw into one buffer while the content of the other buffer is sent to the display in the
background. DMA or other hardware should be used to transfer data to the display so the MCU can continue drawing.
This way, the rendering and refreshing of the display become parallel operations.
Full refresh
In the display driver (lv_disp_drv_t) enabling the full_refresh bit will force LVGL to always redraw the whole
screen. This works in both one buffer and two buffers modes. If full_refresh is enabled and two screen sized draw
buffers are provided, LVGL's display handling works like "traditional" double buffering. This means the flush_cb
callback only has to update the address of the framebuffer (color_p parameter). This configuration should be used
if the MCU has an LCD controller peripheral and not with an external display controller (e.g. ILI9341 or SSD1963)
accessed via serial link. The latter will generally be too slow to maintain high frame rates with full screen redraws.
Direct mode
If the direct_mode flag is enabled in the display driver LVGL will draw directly into a screen sized frame buffer.
That is the draw buffer(s) needs to be screen sized. It this case flush_cb will be called only once when all dirty areas
are redrawn. With direct_mode the frame buffer always contains the current frame as it should be displayed on the
screen. If 2 frame buffers are provided as draw buffers LVGL will alter the buffers but always draw only the dirty areas.
Therefore the 2 buffers needs to synchronized in flush_cb like this:
1. Display the frame buffer pointed by color_p
2. Copy the redrawn areas from color_p to the other buffer.
The get the redrawn areas to copy use the following functions _lv_refr_get_disp_refreshing() re-
turns the display being refreshed disp->inv_areas[LV_INV_BUF_SIZE] contains the invalidated areas
disp->inv_area_joined[LV_INV_BUF_SIZE] if 1 that area was joined into another one and should be ig-
nored disp->inv_p number of valid elements in inv_areas
Once the buffer initialization is ready a lv_disp_drv_t display driver needs to be:
1. initialized with lv_disp_drv_init(&disp_drv)
2. its fields need to be set
3. it needs to be registered in LVGL with lv_disp_drv_register(&disp_drv)
Note that lv_disp_drv_t also needs to be a static, global or dynamically allocated variable.
Mandatory fields
In the most simple case only the following fields of lv_disp_drv_t need to be set:
• draw_buf pointer to an initialized lv_disp_draw_buf_t variable.
• hor_res horizontal resolution of the display in pixels.
• ver_res vertical resolution of the display in pixels.
• flush_cb a callback function to copy a buffer's content to a specific area of the display.
lv_disp_flush_ready(&disp_drv) needs to be called when flushing is ready. LVGL might ren-
der the screen in multiple chunks and therefore call flush_cb multiple times. To see if the current one is the
last chunk of rendering use lv_disp_flush_is_last(&disp_drv).
Optional fields
• gpu_wait_cb if any GPU function returns while the GPU is still working, LVGL will use this function when
required to make sure GPU rendering is ready.
Examples
lv_disp_t * disp;
disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created␣
,→display objects*/
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-
,→by-one
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
{
/*It's an example code which should be done by your GPU*/
uint32_t x, y;
dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
{
/* Write to the buffer as required for the display.
* For example it writes only 1-bit for monochrome displays mapped vertically.*/
buf += buf_w * (y >> 3) + x;
if(lv_color_brightness(color) > 128) (*buf) |= (1 << (y % 8));
else (*buf) &= ~(1 << (y % 8));
}
Rotation
LVGL supports rotation of the display in 90 degree increments. You can select whether you'd like software rotation or
hardware rotation.
If you select software rotation (sw_rotate flag set to 1), LVGL will perform the rotation for you. Your driver can and
should assume that the screen width and height have not changed. Simply flush pixels to the display as normal. Software
rotation requires no additional logic in your flush_cb callback.
There is a noticeable amount of overhead to performing rotation in software. Hardware rotation is available to avoid
unwanted slowdowns. In this mode, LVGL draws into the buffer as if your screen width and height were swapped. You
are responsible for rotating the provided pixels yourself.
The default rotation of your display when it is initialized can be set using the rotated flag. The available options are
LV_DISP_ROT_NONE, LV_DISP_ROT_90, LV_DISP_ROT_180, or LV_DISP_ROT_270. The rotation values
are relative to how you would rotate the physical display in the clockwise direction. Thus, LV_DISP_ROT_90 means
you rotate the hardware 90 degrees clockwise, and the display rotates 90 degrees counterclockwise to compensate.
(Note for users upgrading from 7.10.0 and older: these new rotation enum values match up with the old 0/1 system for
rotating 90 degrees, so legacy code should continue to work as expected. Software rotation is also disabled by default for
compatibility.)
Display rotation can also be changed at runtime using the lv_disp_set_rotation(disp, rot) API.
If you enable rotation the coordinates of the pointer input devices (e.g. touchpad) will be rotated too.
Note that when using software rotation, you cannot use neither direct_mode nor full_refresh in the driver.
When using either of these, you will have to rotate the pixels yourself e.g. in the flush_cb.
Support for software rotation is a new feature, so there may be some glitches/bugs depending on your configuration. If
you encounter a problem please open an issue on GitHub.
Normally the dirty (a.k.a invalid) areas are checked and redrawn in every LV_DISP_DEF_REFR_PERIOD milliseconds
(set in lv_conf.h). However, in some cases you might need more control on when the display refreshing happen, for
example to synchronize rendering with VSYNC or the TE signal.
You can do this in the following way:
If you have multiple displays call lv_disp_set_deafult(disp1); to select the display to refresh before
_lv_disp_refr_timer(NULL);.
Note that lv_timer_handler() and _lv_disp_refr_timer() can not run at the same time.
If the performance monitor is enabled, the value of LV_DISP_DEF_REFR_PERIOD needs to be set to be consistent
with the refresh period of the display to ensure that the statistical results are correct.
4.2.6 API
Typedefs
Enums
enum lv_disp_rot_t
Values:
enumerator LV_DISP_ROT_NONE
enumerator LV_DISP_ROT_90
enumerator LV_DISP_ROT_180
enumerator LV_DISP_ROT_270
Functions
struct _lv_disp_draw_buf_t
#include <lv_hal_disp.h> Structure for holding display buffer information.
Public Members
void *buf1
First display buffer.
void *buf2
Second display buffer.
void *buf_act
uint32_t size
int flushing
int flushing_last
uint32_t last_area
uint32_t last_part
struct _lv_disp_drv_t
#include <lv_hal_disp.h> Display Driver structure to be registered by HAL. Only its pointer will be saved in
lv_disp_t so it should be declared as static lv_disp_drv_t my_drv or allocated dynamically.
Public Members
lv_coord_t hor_res
Horizontal resolution.
lv_coord_t ver_res
Vertical resolution.
lv_coord_t physical_hor_res
Horizontal resolution of the full / physical display. Set to -1 for fullscreen mode.
lv_coord_t physical_ver_res
Vertical resolution of the full / physical display. Set to -1 for fullscreen mode.
lv_coord_t offset_x
Horizontal offset from the full / physical display. Set to 0 for fullscreen mode.
lv_coord_t offset_y
Vertical offset from the full / physical display. Set to 0 for fullscreen mode.
lv_disp_draw_buf_t *draw_buf
Pointer to a buffer initialized with lv_disp_draw_buf_init(). LVGL will use this buffer(s) to draw
the screens contents
uint32_t direct_mode
1: Use screen-sized buffers and draw to absolute coordinates
uint32_t full_refresh
1: Always make the whole screen redrawn
uint32_t sw_rotate
1: use software rotation (slower)
uint32_t antialiasing
1: anti-aliasing is enabled on this display.
uint32_t rotated
1: turn the display by 90 degree.
uint32_t screen_transp
uint32_t dpi
Handle if the screen doesn't have a solid (opa == LV_OPA_COVER) background. Use only if required
because it's slower.
void (*set_px_cb)(struct _lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t
y, lv_color_t color, lv_opa_t opa)
OPTIONAL: Set a pixel in a buffer according to the special requirements of the display Can be used for color
format not supported in LittelvGL. E.g. 2 bit -> 4 gray scales
lv_color_t color_chroma_key
On CHROMA_KEYED images this color will be transparent. LV_COLOR_CHROMA_KEY by default.
(lv_conf.h)
lv_draw_ctx_t *draw_ctx
size_t draw_ctx_size
void *user_data
Custom display driver user data
struct _lv_disp_t
#include <lv_hal_disp.h> Display structure.
Public Members
lv_timer_t *refr_timer
The theme assigned to the screen
See lv_disp_get_layer_top
See lv_disp_get_layer_sys
uint32_t screen_cnt
uint8_t draw_prev_over_act
1: Draw previous screen over active screen
uint8_t del_prev
1: Automatically delete the previous screen when the screen load anim. is ready
uint8_t rendering_in_progress
1: The current screen rendering is in progress
lv_opa_t bg_opa
Opacity of the background color or wallpaper
lv_color_t bg_color
Default display color when screens are transparent
lv_area_t inv_areas[LV_INV_BUF_SIZE]
Invalidated (marked to redraw) areas
uint8_t inv_area_joined[LV_INV_BUF_SIZE]
uint16_t inv_p
int32_t inv_en_cnt
lv_ll_t sync_areas
Double buffer sync areas
uint32_t last_activity_time
Last time when there was activity on this display
To register an input device an lv_indev_drv_t variable has to be initialized. Be sure to register at least one display
before you register any input devices.
/*Register at least one display before you register any input devices*/
lv_disp_drv_register(&disp_drv);
Input devices that can click points on the screen belong to this category.
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = my_input_read;
...
Keypad or keyboard
Full keyboards with all the letters or simple keypads with a few navigation buttons belong here.
To use a keyboard/keypad:
• Register a read_cb function with LV_INDEV_TYPE_KEYPAD type.
• An object group has to be created: lv_group_t * g = lv_group_create() and objects have to be
added to it with lv_group_add_obj(g, obj)
• The created group has to be assigned to an input device: lv_indev_set_group(my_indev, g)
(my_indev is the return value of lv_indev_drv_register)
• Use LV_KEY_... to navigate among the objects in the group. See lv_core/lv_group.h for the available
keys.
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
indev_drv.read_cb = keyboard_read;
...
Encoder
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_read;
...
In addition to standard encoder behavior, you can also utilize its logic to navigate(focus) and edit widgets using buttons.
This is especially handy if you have only few buttons available, or you want to use other buttons in addition to encoder
wheel.
You need to have 3 buttons available:
• LV_KEY_ENTER will simulate press or pushing of the encoder button
• LV_KEY_LEFT will simulate turning encoder left
• LV_KEY_RIGHT will simulate turning encoder right
• other keys will be passed to the focused widget
If you hold the keys it will simulate an encoder advance with period specified in indev_drv.
long_press_repeat_time.
indev_drv.type = LV_INDEV_TYPE_ENCODER;
indev_drv.read_cb = encoder_with_keys_read;
...
Button
Buttons mean external "hardware" buttons next to the screen which are assigned to specific coordinates of the screen. If
a button is pressed it will simulate the pressing on the assigned coordinate. (Similarly to a touchpad)
To assign buttons to coordinates use lv_indev_set_button_points(my_indev, points_array).
points_array should look like const lv_point_t points_array[] = { {12,30},{60,90},
...}
Important: The points_array can't go out of scope. Either declare it as a global variable or as a static variable inside a
function.
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
...
Parameters
Feedback
Besides read_cb a feedback_cb callback can be also specified in lv_indev_drv_t. feedback_cb is called
when any type of event is sent by the input devices (independently of its type). This allows generating feedback for the
user, e.g. to play a sound on LV_EVENT_CLICKED.
Every input device is associated with a display. By default, a new input device is added to the last display created or
explicitly selected (using lv_disp_set_default()). The associated display is stored and can be changed in disp
field of the driver.
Buffered reading
By default, LVGL calls read_cb periodically. Because of this intermittent polling there is a chance that some user
gestures are missed.
To solve this you can write an event driven driver for your input device that buffers measured data. In read_cb you can
report the buffered data instead of directly reading the input device. Setting the data->continue_reading flag
will tell LVGL there is more data to read and it should call read_cb again.
4.3.4 API
Typedefs
Enums
enum lv_indev_type_t
Possible input device types
Values:
enumerator LV_INDEV_TYPE_NONE
Uninitialized state
enumerator LV_INDEV_TYPE_POINTER
Touch pad, mouse, external button
enumerator LV_INDEV_TYPE_KEYPAD
Keypad or keyboard
enumerator LV_INDEV_TYPE_BUTTON
External (hardware button) which is assigned to a specific point of the screen
enumerator LV_INDEV_TYPE_ENCODER
Encoder with only Left, Right turn and a Button
enum lv_indev_state_t
States for input devices
Values:
enumerator LV_INDEV_STATE_RELEASED
enumerator LV_INDEV_STATE_PRESSED
Functions
struct lv_indev_data_t
#include <lv_hal_indev.h> Data structure passed to an input driver to fill
Public Members
lv_point_t point
For LV_INDEV_TYPE_POINTER the currently pressed point
uint32_t key
For LV_INDEV_TYPE_KEYPAD the currently pressed key
uint32_t btn_id
For LV_INDEV_TYPE_BUTTON the currently pressed button
int16_t enc_diff
For LV_INDEV_TYPE_ENCODER number of steps since the previous read
lv_indev_state_t state
LV_INDEV_STATE_REL or LV_INDEV_STATE_PR
bool continue_reading
If set to true, the read callback is invoked again
struct _lv_indev_drv_t
#include <lv_hal_indev.h> Initialized by the user and registered by 'lv_indev_add()'
Public Members
lv_indev_type_t type
< Input device type Function pointer to read input device data.
void *user_data
lv_timer_t *read_timer
Number of pixels to slide before actually drag the object
uint8_t scroll_limit
Drag throw slow-down in [%]. Greater value means faster slow-down
uint8_t scroll_throw
At least this difference should be between two points to evaluate as gesture
uint8_t gesture_min_velocity
At least this difference should be to send a gesture
uint8_t gesture_limit
Long press time in milliseconds
uint16_t long_press_time
Repeated trigger period in long press [ms]
uint16_t long_press_repeat_time
struct _lv_indev_proc_t
#include <lv_hal_indev.h> Run time data of input devices Internally used by the library, you should not need to
touch it.
Public Members
lv_indev_state_t state
Current state of the input device.
uint8_t long_pr_sent
uint8_t reset_query
uint8_t disabled
uint8_t wait_until_release
lv_point_t act_point
Current point of input device.
lv_point_t indev_point
lv_point_t last_point
Last point of input device.
lv_point_t last_raw_point
Last point read from read_cb.
lv_point_t vect
Difference between act_point and last_point.
lv_point_t scroll_sum
lv_point_t scroll_throw_vect
lv_point_t scroll_throw_vect_ori
lv_area_t scroll_area
lv_point_t gesture_sum
lv_dir_t scroll_dir
lv_dir_t gesture_dir
uint8_t gesture_sent
lv_indev_state_t last_state
uint32_t last_key
uint32_t pr_timestamp
Pressed time stamp
uint32_t longpr_rep_timestamp
Long press repeat time stamp
struct _lv_indev_t
#include <lv_hal_indev.h> The main input device descriptor with driver, runtime data ('proc') and some additional
information
Public Members
_lv_indev_proc_t proc
LVGL needs a system tick to know elapsed time for animations and other tasks.
You need to call the lv_tick_inc(tick_period) function periodically and provide the call period in milliseconds.
For example, lv_tick_inc(1) when calling every millisecond.
lv_tick_inc should be called in a higher priority routine than lv_task_handler() (e.g. in an interrupt) to
precisely know the elapsed milliseconds even if the execution of lv_task_handler takes more time.
With FreeRTOS lv_tick_inc can be called in vApplicationTickHook.
On Linux based operating systems (e.g. on Raspberry Pi) lv_tick_inc can be called in a thread like below:
4.4.1 API
Functions
uint32_t lv_tick_get(void)
Get the elapsed milliseconds since start up
Returns the elapsed milliseconds
uint32_t lv_tick_elaps(uint32_t prev_tick)
Get the elapsed milliseconds since a previous time stamp
Parameters prev_tick -- a previous time stamp (return value of lv_tick_get() )
Returns the elapsed milliseconds since 'prev_tick'
To handle the tasks of LVGL you need to call lv_timer_handler() periodically in one of the following:
• while(1) of main() function
• timer interrupt periodically (lower priority than lv_tick_inc())
• an OS task periodically
The timing is not critical but it should be about 5 milliseconds to keep the system responsive.
Example:
while(1) {
lv_timer_handler();
my_delay_ms(5);
}
while(1) {
...
lv_timer_handler_run_in_period(5); /* run lv_timer_handler() every 5ms */
...
}
In an OS environment, you can use it together with the delay or sleep provided by OS to release CPU whenever possible:
while (1) {
lv_timer_handler_run_in_period(5); /* run lv_timer_handler() every 5ms */
my_delay_ms(5); /* delay 5ms to avoid unnecessary polling */
}
The MCU can go to sleep when no user input happens. In this case, the main while(1) should look like this:
while(1) {
/*Normal operation (no sleep) in < 1 sec inactivity*/
if(lv_disp_get_inactive_time(NULL) < 1000) {
lv_task_handler();
}
/*Sleep after 1 sec inactivity*/
else {
timer_stop(); /*Stop the timer where lv_tick_inc() is called*/
sleep(); /*Sleep the MCU*/
}
my_delay_ms(5);
}
You should also add the following lines to your input device read function to signal a wake-up (press, touch or click etc.)
has happened:
If you need to use real tasks or threads, you need a mutex which should be invoked before the call of
lv_timer_handler and released after it. Also, you have to use the same mutex in other tasks and threads around
every LVGL (lv_...) related function call and code. This way you can use LVGL in a real multitasking environment.
Just make use of a mutex to avoid the concurrent calling of LVGL functions.
Here is some pseudocode to illustrate the concept:
void lvgl_thread(void)
{
while(1) {
mutex_lock(&lvgl_mutex);
(continues on next page)
void other_thread(void)
{
/* You must always hold the mutex while using LVGL APIs */
mutex_lock(&lvgl_mutex);
lv_obj_t *img = lv_img_create(lv_scr_act());
mutex_unlock(&lvgl_mutex);
while(1) {
mutex_lock(&lvgl_mutex);
/* change to the next image */
lv_img_set_src(img, next_image);
mutex_unlock(&lvgl_mutex);
thread_sleep(2000);
}
}
4.7.2 Interrupts
Try to avoid calling LVGL functions from interrupt handlers (except lv_tick_inc() and
lv_disp_flush_ready()). But if you need to do this you have to disable the interrupt which uses LVGL
functions while lv_timer_handler is running.
It's a better approach to simply set a flag or some value in the interrupt, and periodically check it in an LVGL timer (which
is run by lv_timer_handler).
4.8 Logging
LVGL has a built-in Log module to inform the user about what is happening in the library.
To enable logging, set LV_USE_LOG 1 in lv_conf.h and set LV_LOG_LEVEL to one of the following values:
• LV_LOG_LEVEL_TRACE A lot of logs to give detailed information
• LV_LOG_LEVEL_INFO Log important events
• LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem
• LV_LOG_LEVEL_ERROR Only critical issues, where the system may fail
• LV_LOG_LEVEL_USER Only user messages
• LV_LOG_LEVEL_NONE Do not log anything
The events which have a higher level than the set log level will be logged too. E.g. if you LV_LOG_LEVEL_WARN,
errors will be also logged.
If your system supports printf, you just need to enable LV_LOG_PRINTF in lv_conf.h to send the logs with
printf.
If you can't use printf or want to use a custom function to log, you can register a "logger" callback with
lv_log_register_print_cb().
For example:
...
lv_log_register_print_cb(my_log_cb);
You can also use the log module via the LV_LOG_TRACE/INFO/WARN/ERROR/USER(text) or LV_LOG(text)
functions. Here:
• LV_LOG_TRACE/INFO/WARN/ERROR/USER(text) append following information to your text
• Log Level
• __FILE__
• __LINE__
• __func__
• LV_LOG(text) is similar to LV_LOG_USER but has no extra information attached.
LVGL has a flexible and extendable draw pipeline. You can hook it to do some rendering with a GPU or even completely
replace the built-in software renderer.
The core structure of drawing is lv_draw_ctx_t. It contains a pointer to a buffer where drawing should happen and
a couple of callbacks to draw rectangles, texts, and other primitives.
Fields
Initialization
However, you can overwrite the callbacks and the size values before calling lv_disp_drv_register(). It makes
it possible to use your own draw_ctx with your own callbacks.
LVGL's built in software renderer extends the basic lv_draw_ctx_t structure and sets the draw callbacks. It looks
like this:
typedef struct {
/** Include the basic draw_ctx type*/
lv_draw_ctx_t base_draw;
draw_sw_ctx->base_draw.draw_rect = lv_draw_sw_rect;
draw_sw_ctx->base_draw.draw_letter = lv_draw_sw_letter;
...
Blend callback
As you saw above the software renderer adds the blend callback field. It's a special callback related to how the software
renderer works. All draw operations end up in the blend callback which can either fill an area or copy an image to an
area by considering an optional mask.
The lv_draw_sw_blend_dsc_t parameter describes what and how to blend. It has the following fields:
• const lv_area_t * blend_area The area with absolute coordinates to draw on draw_ctx->buf. If
src_buf is set, it's the coordinates of the image to blend.
• const lv_color_t * src_buf Pointer to an image to blend. If set, color is ignored. If not set fill
blend_area with color
• lv_color_t color Fill color. Used only if src_buf == NULL
• lv_opa_t * mask_buf NULL if ignored, or an alpha mask to apply on blend_area
• lv_draw_mask_res_t mask_res The result of the previous mask operation. (LV_DRAW_MASK_RES_.
..)
• const lv_area_t * mask_area The area of mask_buf with absolute coordinates
• lv_opa_t opa The overall opacity
• lv_blend_mode_t blend_mode E.g. LV_BLEND_MODE_ADDITIVE
Let's take a practical example: you would like to use your MCUs GPU for color fill operations only.
As all draw callbacks call blend callback to fill an area in the end only the blend callback needs to be overwritten.
First extend lv_draw_sw_ctx_t:
/*We don't add new fields, so just for clarity add new type*/
typedef lv_draw_sw_ctx_t my_draw_ctx_t;
my_draw_ctx->blend = my_draw_blend;
my_draw_ctx->base_draw.wait_for_finish = my_gpu_wait;
}
After calling lv_disp_draw_init(&drv) you can assign the new draw_ctx_init callback and set
draw_ctx_size to overwrite the defaults:
static lv_disp_drv_t drv;
lv_disp_draw_init(&drv);
drv->hor_res = my_hor_res;
drv->ver_res = my_ver_res;
drv->flush_cb = my_flush_cb;
lv_disp_drv_register(&drv);
This way when LVGL calls blend it will call my_draw_blend and we can do custom GPU operations. Here is a
complete example:
void my_draw_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
{
/*Let's get the blend area which is the intersection of the area to fill and the␣
,→clip area.*/
lv_area_t blend_area;
if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area)) return;
,→ /*Fully clipped, nothing to do*/
/*Fill only non masked, fully opaque, normal blended and not too small areas*/
if(dsc->src_buf == NULL && dsc->mask == NULL && dsc->opa >= LV_OPA_MAX &&
dsc->blend_mode == LV_BLEND_MODE_NORMAL && lv_area_get_size(&blend_area) >␣
,→100) {
/*Call your custom gou fill function to fill blend_area, on dest_buf with dsc-
,→ >color*/
my_gpu_fill(dest_buf, dest_stride, &blend_area, dsc->color);
}
/*Fallback: the GPU doesn't support these settings. Call the SW renderer.*/
else {
lv_draw_sw_blend_basic(draw_ctx, dsc);
}
}
If your MCU has a more powerful GPU that can draw e.g. rounded rectangles you can replace the original software
drawer too. A custom draw_rect callback might look like this:
void my_draw_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_
,→area_t * coords)
{
if(lv_draw_mask_is_any(coords) == false && dsc->grad == NULL && dsc->bg_img_src ==␣
,→NULL &&
}
(continues on next page)
For example if your MCU/MPU supports a powerful vector graphics engine you might use only that instead of LVGL's SW
renderer. In this case, you need to base the renderer on the basic lv_draw_ctx_t (instead of lv_draw_sw_ctx_t)
and extend/initialize it as you wish.
FIVE
OVERVIEW
5.1 Objects
In LVGL the basic building blocks of a user interface are the objects, also called Widgets. For example a Button, Label,
Image, List, Chart or Text area.
You can see all the Object types here.
All objects are referenced using an lv_obj_t pointer as a handle. This pointer can later be used to set or get the
attributes of the object.
5.1.1 Attributes
Basic attributes
To see all the available functions visit the Base object's documentation.
288
LVGL Documentation 8.3
Specific attributes
The object types have special attributes too. For example, a slider has
• Minimum and maximum values
• Current value
For these special attributes, every object type may have unique API functions. For example for a slider:
The API of the widgets is described in their Documentation but you can also check the respective header files (e.g.
widgets/lv_slider.h)
Parent-child structure
A parent object can be considered as the container of its children. Every object has exactly one parent object (except
screens), but a parent can have any number of children. There is no limitation for the type of the parent but there are
objects which are typically a parent (e.g. button) or a child (e.g. label).
Moving together
If the position of a parent changes, the children will move along with it. Therefore, all positions are relative to the parent.
lv_obj_set_pos(parent, 50, 50); /*Move the parent. The child will move with it.
,→*/
(For simplicity the adjusting of colors of the objects is not shown in the example.)
If a child is partially or fully outside its parent then the parts outside will not be visible.
lv_obj_set_x(obj1, -30); /*Move the child a little bit off the parent*/
In LVGL, objects can be created and deleted dynamically at run time. It means only the currently created (existing)
objects consume RAM.
This allows for the creation of a screen just when a button is clicked to open it, and for deletion of screens when a new
screen is loaded.
UIs can be created based on the current environment of the device. For example one can create meters, charts, bars and
sliders based on the currently attached sensors.
Every widget has its own create function with a prototype like this:
Typically, the create functions only have a parent parameter telling them on which object to create the new widget.
The return value is a pointer to the created object with lv_obj_t * type.
There is a common delete function for all object types. It deletes the object and all of its children.
lv_obj_del will delete the object immediately. If for any reason you can't delete the object immediately you can use
lv_obj_del_async(obj) which will perform the deletion on the next call of lv_timer_handler(). This is
useful e.g. if you want to delete the parent of an object in the child's LV_EVENT_DELETE handler.
You can remove all the children of an object (but not the object itself) using lv_obj_clean(obj).
You can use lv_obj_del_delayed(obj, 1000) to delete an object after some time. The delay is expressed in
milliseconds.
5.1.3 Screens
Create screens
The screens are special objects which have no parent object. So they can be created like:
Screens can be created with any object type. For example, a Base object or an image to make a wallpaper.
There is always an active screen on each display. By default, the library creates and loads a "Base object" as a screen for
each display.
To get the currently active screen use the lv_scr_act() function.
Load screens
Layers
A new screen can be loaded with animation by using lv_scr_load_anim(scr, transition_type, time,
delay, auto_del). The following transition types exist:
• LV_SCR_LOAD_ANIM_NONE Switch immediately after delay milliseconds
• LV_SCR_LOAD_ANIM_OVER_LEFT/RIGHT/TOP/BOTTOM Move the new screen over the current towards
the given direction
• LV_SCR_LOAD_ANIM_OUT_LEFT/RIGHT/TOP/BOTTOM Move out the old screen over the current towards
the given direction
• LV_SCR_LOAD_ANIM_MOVE_LEFT/RIGHT/TOP/BOTTOM Move both the current and new screens towards
the given direction
• LV_SCR_LOAD_ANIM_FADE_IN/OUT Fade the new screen over the old screen, or vice versa
Setting auto_del to true will automatically delete the old screen when the animation is finished.
The new screen will become active (returned by lv_scr_act()) when the animation starts after delay time. All
inputs are disabled during the screen animation.
Screens are created on the currently selected default display. The default display is the last regis-
tered display with lv_disp_drv_register. You can also explicitly select a new default display using
lv_disp_set_default(disp).
lv_scr_act(), lv_scr_load() and lv_scr_load_anim() operate on the default display.
Visit Multi-display support to learn more.
5.1.4 Parts
The widgets are built from multiple parts. For example a Base object uses the main and scrollbar parts but a Slider uses
the main, indicator and knob parts. Parts are similar to pseudo-elements in CSS.
The following predefined parts exist in LVGL:
• LV_PART_MAIN A background like rectangle
• LV_PART_SCROLLBAR The scrollbar(s)
• LV_PART_INDICATOR Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
• LV_PART_KNOB Like a handle to grab to adjust the value
• LV_PART_SELECTED Indicate the currently selected option or section
• LV_PART_ITEMS Used if the widget has multiple similar elements (e.g. table cells)
• LV_PART_TICKS Ticks on scales e.g. for a chart or meter
• LV_PART_CURSOR Mark a specific place e.g. text area's or chart's cursor
• LV_PART_CUSTOM_FIRST Custom parts can be added from here.
The main purpose of parts is to allow styling the "components" of the widgets. They are described in more detail in the
Style overview section.
5.1.5 States
5.1.6 Snapshot
A snapshot image can be generated for an object together with its children. Check details in Snapshot.
5.2.1 Overview
Similarly to many other parts of LVGL, the concept of setting the coordinates was inspired by CSS. LVGL has by no
means a complete implementation of CSS but a comparable subset is implemented (sometimes with minor adjustments).
In short this means:
• Explicitly set coordinates are stored in styles (size, position, layouts, etc.)
• support min-width, max-width, min-height, max-height
• have pixel, percentage, and "content" units
• x=0; y=0 coordinate means the top-left corner of the parent plus the left/top padding plus border width
• width/height means the full size, the "content area" is smaller with padding and border width
• a subset of flexbox and grid layouts are supported
Units
• pixel: Simply a position in pixels. An integer always means pixels. E.g. lv_obj_set_x(btn, 10)
• percentage: The percentage of the size of the object or its parent (depending on the property). lv_pct(value)
converts a value to percentage. E.g. lv_obj_set_width(btn, lv_pct(50))
• LV_SIZE_CONTENT: Special value to set the width/height of an object to involve all the children. It's similar to
auto in CSS. E.g. lv_obj_set_width(btn, LV_SIZE_CONTENT).
Boxing model
LVGL follows CSS's border-box model. An object's "box" is built from the following parts:
• bounding box: the width/height of the elements.
• border width: the width of the border.
• padding: space between the sides of the object and its children.
• content: the content area which is the size of the bounding box reduced by the border width and padding.
The border is drawn inside the bounding box. Inside the border LVGL keeps a "padding margin" when placing an object's
children.
The outline is drawn outside the bounding box.
Important notes
This section describes special cases in which LVGL's behavior might be unexpected.
LVGL doesn't recalculate all the coordinate changes immediately. This is done to improve performance. Instead, the
objects are marked as "dirty" and before redrawing the screen LVGL checks if there are any "dirty" objects. If so it
refreshes their position, size and layout.
In other words, if you need to get the coordinate of an object and the coordinates were just changed, LVGL needs to be
forced to recalculate the coordinates. To do this call lv_obj_update_layout(obj).
The size and position might depend on the parent or layout. Therefore lv_obj_update_layout recalculates the
coordinates of all objects on the screen of obj.
Removing styles
As it's described in the Using styles section, coordinates can also be set via style properties. To be more precise, under
the hood every style coordinate related property is stored as a style property. If you use lv_obj_set_x(obj, 20)
LVGL saves x=20 in the local style of the object.
This is an internal mechanism and doesn't matter much as you use LVGL. However, there is one case in which you need
to be aware of the implementation. If the style(s) of an object are removed by
lv_obj_remove_style_all(obj)
or
/*The size of obj1 will be set back to the default in the end*/
lv_obj_set_size(obj1, 200, 100); /*Now obj1 has 200;100 size*/
lv_obj_remove_style_all(obj1); /*It removes the set sizes*/
5.2.2 Position
Simple way
By default, the x and y coordinates are measured from the top left corner of the parent's content area. For example if the
parent has five pixels of padding on every side the above code will place obj at (15, 25) because the content area starts
after the padding.
Percentage values are calculated from the parent's content area size.
Align
In some cases it's convenient to change the origin of the positioning from the default top left. If the origin is changed e.g.
to bottom-right, the (0,0) position means: align to the bottom-right corner. To change the origin use:
lv_obj_set_align(obj, align);
lv_obj_center(obj);
If the parent's size changes, the set alignment and position of the children is updated automatically.
The functions introduced above align the object to its parent. However, it's also possible to align an object to an arbitrary
reference object.
Besides the alignments options above, the following can be used to align an object outside the reference object:
• LV_ALIGN_OUT_TOP_LEFT
• LV_ALIGN_OUT_TOP_MID
• LV_ALIGN_OUT_TOP_RIGHT
• LV_ALIGN_OUT_BOTTOM_LEFT
• LV_ALIGN_OUT_BOTTOM_MID
• LV_ALIGN_OUT_BOTTOM_RIGHT
• LV_ALIGN_OUT_LEFT_TOP
• LV_ALIGN_OUT_LEFT_MID
• LV_ALIGN_OUT_LEFT_BOTTOM
• LV_ALIGN_OUT_RIGHT_TOP
• LV_ALIGN_OUT_RIGHT_MID
• LV_ALIGN_OUT_RIGHT_BOTTOM
For example to align a label above a button and center the label horizontally:
Note that, unlike with lv_obj_align(), lv_obj_align_to() can not realign the object if its coordinates or the
reference object's coordinates change.
5.2.3 Size
Simple way
The width and the height of an object can be set easily as well:
Percentage values are calculated based on the parent's content area size. For example to set the object's height to the
screen height:
lv_obj_set_height(obj, lv_pct(100));
The size settings support a special value: LV_SIZE_CONTENT. It means the object's size in the respective direction will
be set to the size of its children. Note that only children on the right and bottom sides will be considered and children on
the top and left remain cropped. This limitation makes the behavior more predictable.
Objects with LV_OBJ_FLAG_HIDDEN or LV_OBJ_FLAG_FLOATING will be ignored by the LV_SIZE_CONTENT
calculation.
The above functions set the size of an object's bounding box but the size of the content area can be set as well. This means
an object's bounding box will be enlarged with the addition of padding.
The size of the bounding box and the content area can be retrieved with the following functions:
lv_coord_t w = lv_obj_get_width(obj);
lv_coord_t h = lv_obj_get_height(obj);
lv_coord_t content_w = lv_obj_get_content_width(obj);
lv_coord_t content_h = lv_obj_get_content_height(obj);
Under the hood the position, size and alignment properties are style properties. The above described "simple functions"
hide the style related code for the sake of simplicity and set the position, size, and alignment properties in the local styles
of the object.
However, using styles to set the coordinates has some great advantages:
• It makes it easy to set the width/height/etc. for several objects together. E.g. make all the sliders 100x10 pixels
sized.
• It also makes possible to modify the values in one place.
• The values can be partially overwritten by other styles. For example style_btn makes the object 100x50 by
default but adding style_full_width overwrites only the width of the object.
• The object can have different position or size depending on state. E.g. 100 px wide in LV_STATE_DEFAULT but
120 px in LV_STATE_PRESSED.
• Style transitions can be used to make the coordinate changes smooth.
Here are some examples to set an object's size using a style:
As you will see below there are some other great features of size and position setting. However, to keep the LVGL API
lean, only the most common coordinate setting features have a "simple" version and the more complex features can be
used via styles.
5.2.5 Translation
Let's say the there are 3 buttons next to each other. Their position is set as described above. Now you want to move a
button up a little when it's pressed.
One way to achieve this is by setting a new Y coordinate for the pressed state:
This works, but it's not really flexible because the pressed coordinate is hard-coded. If the buttons are not at y=100,
style_pressed won't work as expected. Translations can be used to solve this:
5.2.6 Transformation
Similarly to position, an object's size can be changed relative to the current size as well. The transformed width and height
are added on both sides of the object. This means a 10 px transformed width makes the object 2x10 pixels wider.
Unlike position translation, the size transformation doesn't make the object "really" larger. In other words scrollbars,
layouts, and LV_SIZE_CONTENT will not react to the transformed size. Hence, size transformation is "only" a visual
effect.
This code enlarges a button when it's pressed:
Similarly to CSS, LVGL also supports min-width, max-width, min-height and max-height. These are
limits preventing an object's size from becoming smaller/larger than these values. They are especially useful if the size is
set by percentage or LV_SIZE_CONTENT.
lv_obj_set_height(obj, lv_pct(100));
lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to␣
,→200 px
Percentage values can be used as well which are relative to the size of the parent's content area.
lv_obj_set_height(obj, lv_pct(100));
lv_obj_add_style(obj, &style_max_height, LV_STATE_DEFAULT); //Limit the height to␣
,→half parent height
5.2.7 Layout
Overview
Layouts can update the position and size of an object's children. They can be used to automatically arrange the children
into a line or column, or in much more complicated forms.
The position and size set by the layout overwrites the "normal" x, y, width, and height settings.
There is only one function that is the same for every layout: lv_obj_set_layout(obj, <LAYOUT_NAME>) sets
the layout on an object. For further settings of the parent and children see the documentation of the given layout.
Built-in layout
Flags
There are some flags that can be used on objects to affect how they behave with layouts:
• LV_OBJ_FLAG_HIDDEN Hidden objects are ignored in layout calculations.
• LV_OBJ_FLAG_IGNORE_LAYOUT The object is simply ignored by the layouts. Its coordinates can be set as
usual.
• LV_OBJ_FLAG_FLOATING Same as LV_OBJ_FLAG_IGNORE_LAYOUT but the object with
LV_OBJ_FLAG_FLOATING will be ignored in LV_SIZE_CONTENT calculations.
These flags can be added/removed with lv_obj_add/clear_flag(obj, FLAG);
uint32_t MY_LAYOUT;
...
...
Custom style properties can be added which can be retrieved and used in the update callback. For example:
uint32_t MY_PROP;
...
LV_STYLE_MY_PROP = lv_style_register_prop();
...
static inline void lv_style_set_my_prop(lv_style_t * style, uint32_t value)
{
lv_style_value_t v = {
.num = (int32_t)value
};
lv_style_set_prop(style, LV_STYLE_MY_PROP, v);
}
5.2.8 Examples
5.3 Styles
Styles are used to set the appearance of objects. Styles in lvgl are heavily inspired by CSS. The concept in a nutshell is as
follows:
• A style is an lv_style_t variable which can hold properties like border width, text color and so on. It's similar
to a class in CSS.
• Styles can be assigned to objects to change their appearance. Upon assignment, the target part (pseudo-element in
CSS) and target state (pseudo class) can be specified. For example one can add style_blue to the knob of a
slider when it's in pressed state.
• The same style can be used by any number of objects.
• Styles can be cascaded which means multiple styles may be assigned to an object and each style can have different
properties. Therefore, not all properties have to be specified in a style. LVGL will search for a property until a style
defines it or use a default if it's not specified by any of the styles. For example style_btn can result in a default
gray button and style_btn_red can add only a background-color=red to overwrite the background
color.
• The most recently added style has higher precedence. This means if a property is specified in two styles the newest
style in the object will be used.
• Some properties (e.g. text color) can be inherited from a parent(s) if it's not specified in an object.
• Objects can also have local styles with higher precedence than "normal" styles.
• Unlike CSS (where pseudo-classes describe different states, e.g. :focus), in LVGL a property is assigned to a
given state.
• Transitions can be applied when the object changes state.
5.3.1 States
An object can be in a combination of states such as being focused and pressed at the same time. This is represented as
LV_STATE_FOCUSED | LV_STATE_PRESSED.
A style can be added to any state or state combination. For example, setting a different background color for the default
and pressed states. If a property is not defined in a state the best matching state's property will be used. Typically this
means the property with LV_STATE_DEFAULT is used.˛ If the property is not set even for the default state the default
value will be used. (See later)
But what does the "best matching state's property" really mean? States have a precedence which is shown by their value
(see in the above list). A higher value means higher precedence. To determine which state's property to use let's take an
example. Imagine the background color is defined like this:
• LV_STATE_DEFAULT: white
• LV_STATE_PRESSED: gray
• LV_STATE_FOCUSED: red
1. Initially the object is in the default state, so it's a simple case: the property is perfectly defined in the object's current
state as white.
2. When the object is pressed there are 2 related properties: default with white (default is related to every state)
and pressed with gray. The pressed state has 0x0020 precedence which is higher than the default state's 0x0000
precedence, so gray color will be used.
3. When the object is focused the same thing happens as in pressed state and red color will be used. (Focused state
has higher precedence than default state).
4. When the object is focused and pressed both gray and red would work, but the pressed state has higher precedence
than focused so gray color will be used.
5. It's possible to set e.g. rose color for LV_STATE_PRESSED | LV_STATE_FOCUSED. In this case, this
combined state has 0x0020 + 0x0002 = 0x0022 precedence, which is higher than the pressed state's precedence so
rose color would be used.
6. When the object is in the checked state there is no property to set the background color for this state. So for lack
of a better option, the object remains white from the default state's property.
Some practical notes:
• The precedence (value) of states is quite intuitive, and it's something the user would expect naturally. E.g. if an
object is focused the user will still want to see if it's pressed, therefore the pressed state has a higher precedence.
If the focused state had a higher precedence it would overwrite the pressed color.
• If you want to set a property for all states (e.g. red background color) just set it for the default state. If the object
can't find a property for its current state it will fall back to the default state's property.
• Use ORed states to describe the properties for complex cases. (E.g. pressed + checked + focused)
• It might be a good idea to use different style elements for different states. For example, finding background colors
for released, pressed, checked + pressed, focused, focused + pressed, focused + pressed + checked, etc. states
is quite difficult. Instead, for example, use the background color for pressed and checked states and indicate the
focused state with a different border color.
It's not required to set all the properties in one style. It's possible to add more styles to an object and have the latter added
style modify or extend appearance. For example, create a general gray button style and create a new one for red buttons
where only the new background color is set.
This is much like in CSS when used classes are listed like <div class=".btn .btn-red">.
Styles added later have precedence over ones set earlier. So in the gray/red button example above, the normal button style
should be added first and the red style second. However, the precedence of the states are still taken into account. So let's
examine the following case:
• the basic button style defines dark-gray color for the default state and light-gray color for the pressed state
• the red button style defines the background color as red only in the default state
In this case, when the button is released (it's in default state) it will be red because a perfect match is found in the most
recently added style (red). When the button is pressed the light-gray color is a better match because it describes the
current state perfectly, so the button will be light-gray.
5.3.3 Inheritance
Some properties (typically those related to text) can be inherited from the parent object's styles. Inheritance is applied
only if the given property is not set in the object's styles (even in default state). In this case, if the property is inheritable,
the property's value will be searched in the parents until an object specifies a value for the property. The parents will use
their own state to determine the value. So if a button is pressed, and the text color comes from here, the pressed text color
will be used.
Sometimes you may want to force a child object to use the parent's value for a given style property. To do this you can
use one of the following (depending on what type of style you're using):
/* regular style */
lv_style_set_prop_meta(&style, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_INHERIT);
/* local style */
lv_obj_set_local_style_prop_meta(child, LV_STYLE_TEXT_COLOR, LV_STYLE_PROP_META_
,→INHERIT, LV_PART_MAIN);
This acts like a value has been set on the style, so setting the value of the property afterwards will remove the flag.
You may also want to force the default value of a property to be used, without needing to hardcode it in your application.
To do this you can use the same API but with LV_STYLE_PROP_META_INITIAL instead. In future versions of
LVGL, this will use the value based upon the current theme, but for now it just selects the internal default regardless of
theme.
5.3.5 Parts
Objects can be composed of parts which may each have their own styles.
The following predefined parts exist in LVGL:
• LV_PART_MAIN A background like rectangle
• LV_PART_SCROLLBAR The scrollbar(s)
• LV_PART_INDICATOR Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
• LV_PART_KNOB Like a handle to grab to adjust a value
• LV_PART_SELECTED Indicate the currently selected option or section
• LV_PART_ITEMS Used if the widget has multiple similar elements (e.g. table cells)
• LV_PART_TICKS Ticks on scales e.g. for a chart or meter
• LV_PART_CURSOR Mark a specific place e.g. text area's or chart's cursor
• LV_PART_CUSTOM_FIRST Custom part identifiers can be added starting from here.
For example a Slider has three parts:
• Background
• Indicator
• Knob
This means all three parts of the slider can have their own styles. See later how to add styles to objects and parts.
Styles are stored in lv_style_t variables. Style variables should be static, global or dynamically allocated. In
other words they cannot be local variables in functions which are destroyed when the function exits. Before using a style
it should be initialized with lv_style_init(&my_style). After initializing a style, properties can be added or
changed.
Property set functions looks like this: lv_style_set_<property_name>(&style, <value>); For exam-
ple:
lv_style_remove_prop(&style, LV_STYLE_BG_COLOR);
lv_style_value_t v;
lv_res_t res = lv_style_get_prop(&style, LV_STYLE_BG_COLOR, &v);
if(res == LV_RES_OK) { /*Found*/
do_something(v.color);
}
lv_style_reset(&style);
LV_STYLE_CONST_INIT(style1, style1_props);
Later const style can be used like any other style but (obviously) new properties can not be added.
A style on its own is not that useful. It must be assigned to an object to take effect.
Add styles
Remove styles
If a style which is already assigned to an object changes (i.e. a property is added or changed), the objects using that style
should be notified. There are 3 options to do this:
1. If you know that the changed properties can be applied by a simple redraw (e.g. color or opacity changes) just call
lv_obj_invalidate(obj) or lv_obj_invalidate(lv_scr_act()).
2. If more complex style properties were changed or added, and you know which object(s) are affected by that
style call lv_obj_refresh_style(obj, part, property). To refresh all parts and properties use
lv_obj_refresh_style(obj, LV_PART_ANY, LV_STYLE_PROP_ANY).
3. To make LVGL check all objects to see if they use a style and refresh them when needed, call
lv_obj_report_style_change(&style). If style is NULL all objects will be notified about a style
change.
To get a final value of property - considering cascading, inheritance, local styles and transitions (see below) - property get
functions like this can be used: lv_obj_get_style_<property_name>(obj, <part>). These functions
use the object's current state and if no better candidate exists they return a default value. For example:
In addition to "normal" styles, objects can also store local styles. This concept is similar to inline styles in CSS (e.g. <div
style="color:red">) with some modification.
Local styles are like normal styles, but they can't be shared among other objects. If used, local styles are allocated
automatically, and freed when the object is deleted. They are useful to add local customization to an object.
Unlike in CSS, LVGL local styles can be assigned to states (pseudo-classes) and parts (pseudo-elements).
To set a local property use functions like lv_obj_set_style_<property_name>(obj, <value>,
<selector>); For example:
5.3.9 Properties
In the documentation of the widgets you will see sentences like "The widget uses the typical background properties".
These "typical background properties" are the ones related to:
• Background
• Border
• Outline
• Shadow
• Padding
• Width and height transformation
• X and Y translation
5.3.10 Transitions
By default, when an object changes state (e.g. it's pressed) the new properties from the new state are set immediately.
However, with transitions it's possible to play an animation on state change. For example, on pressing a button its back-
ground color can be animated to the pressed color over 300 ms.
The parameters of the transitions are stored in the styles. It's possible to set
• the time of the transition
• the delay before starting the transition
• the animation path (also known as the timing or easing function)
• the properties to animate
The transition properties can be defined for each state. For example, setting a 500 ms transition time in the default state
means that when the object goes to the default state a 500 ms transition time is applied. Setting a 100 ms transition time in
the pressed state causes a 100 ms transition when going to the pressed state. This example configuration results in going
to the pressed state quickly and then going back to default slowly.
To describe a transition an lv_transition_dsc_t variable needs to be initialized and added to a style:
lv_style_set_transition(&style1, &trans1);
If the opa, blend_mode, transform_angle, or transform_zoom properties are set to their non-default value
LVGL creates a snapshot about the widget and all its children in order to blend the whole widget with the set opacity,
blend mode and transformation properties.
These properties have this effect only on the MAIN part of the widget.
The created snapshot is called "intermediate layer" or simply "layer". If only opa and/or blend_mode is set to a non-
default value LVGL can build the layer from smaller chunks. The size of these chunks can be configured by the following
properties in lv_conf.h:
• LV_LAYER_SIMPLE_BUF_SIZE: [bytes] the optimal target buffer size. LVGL will try to allocate this size of
memory.
• LV_LAYER_SIMPLE_FALLBACK_BUF_SIZE: [bytes] used if LV_LAYER_SIMPLE_BUF_SIZE couldn't
be allocated.
If transformation properties were also used the layer can not be rendered in chunks, but one larger memory needs to be
allocated. The required memory depends on the angle, zoom and pivot parameters, and the size of the area to redraw,
but it's never larger than the size of the widget (including the extra draw size used for shadow, outline, etc).
If the widget can fully cover the area to redraw, LVGL creates an RGB layer (which is faster to render and uses less
memory). If the opposite case ARGB rendering needs to be used. A widget might not cover its area if it has radius,
bg_opa != 255, has shadow, outline, etc.
The click area of the widget is also transformed accordingly.
TODO
5.3.13 Themes
Themes are a collection of styles. If there is an active theme LVGL applies it on every created widget. This will give a
default appearance to the UI which can then be modified by adding further styles.
Every display can have a different theme. For example, you could have a colorful theme on a TFT and monochrome
theme on a secondary monochrome display.
To set a theme for a display, two steps are required:
1. Initialize a theme
2. Assign the initialized theme to a display.
Theme initialization functions can have different prototypes. This example shows how to set the "default" theme:
LV_COLOR_PALETTE_BLUE, LV_COLOR_PALETTE_CYAN,␣
,→ /*Primary and secondary palette*/
false, /*Light or dark mode*/
&lv_font_montserrat_10, &lv_font_montserrat_
,→14, &lv_font_montserrat_18); /*Small, normal, large fonts*/
The included themes are enabled in lv_conf.h. If the default theme is enabled by LV_USE_THEME_DEFAULT 1
LVGL automatically initializes and sets it when a display is created.
Extending themes
Built-in themes can be extended. If a custom theme is created, a parent theme can be selected. The parent theme's styles
will be added before the custom theme's styles. Any number of themes can be chained this way. E.g. default theme ->
custom theme -> dark theme.
lv_theme_set_parent(new_theme, base_theme) extends the base_theme with the new_theme.
There is an example for it below.
5.3.14 Examples
Size styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using the Size, Position and Padding style properties
*/
void lv_example_style_1(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
/*Make a gradient*/
lv_style_set_width(&style, 150);
lv_style_set_height(&style, LV_SIZE_CONTENT);
lv_style_set_pad_ver(&style, 20);
lv_style_set_pad_left(&style, 5);
lv_style_set_x(&style, lv_pct(50));
lv_style_set_y(&style, 80);
#endif
#
# Using the Size, Position and Padding style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
(continues on next page)
# Make a gradient
style.set_width(150)
style.set_height(lv.SIZE.CONTENT)
style.set_pad_ver(20)
style.set_pad_left(5)
style.set_x(lv.pct(50))
style.set_y(80)
label = lv.label(obj)
label.set_text("Hello")
Background styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the background style properties
*/
void lv_example_style_2(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
/*Make a gradient*/
lv_style_set_bg_opa(&style, LV_OPA_COVER);
static lv_grad_dsc_t grad;
grad.dir = LV_GRAD_DIR_VER;
grad.stops_count = 2;
grad.stops[0].color = lv_palette_lighten(LV_PALETTE_GREY, 1);
grad.stops[1].color = lv_palette_main(LV_PALETTE_BLUE);
lv_style_set_bg_grad(&style, &grad);
#endif
#
# Using the background style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
# Make a gradient
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 1))
style.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_bg_grad_dir(lv.GRAD_DIR.VER)
Border styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the border style properties
*/
void lv_example_style_3(void)
{
static lv_style_t style;
lv_style_init(&style);
#endif
#
# Using the border style properties
#
style = lv.style_t()
style.init()
Outline styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the outline style properties
*/
void lv_example_style_4(void)
{
static lv_style_t style;
lv_style_init(&style);
/*Add outline*/
lv_style_set_outline_width(&style, 2);
lv_style_set_outline_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_outline_pad(&style, 8);
#endif
#
# Using the outline style properties
#
style = lv.style_t()
style.init()
# Add outline
style.set_outline_width(2)
style.set_outline_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_outline_pad(8)
Shadow styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Using the Shadow style properties
*/
void lv_example_style_5(void)
{
static lv_style_t style;
lv_style_init(&style);
/*Add a shadow*/
lv_style_set_shadow_width(&style, 55);
lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_BLUE));
// lv_style_set_shadow_ofs_x(&style, 10);
// lv_style_set_shadow_ofs_y(&style, 20);
#endif
#
# Using the Shadow style properties
#
style = lv.style_t()
style.init()
# Add a shadow
style.set_shadow_width(8)
style.set_shadow_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_shadow_ofs_x(10)
style.set_shadow_ofs_y(20)
Image styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using the Image style properties
*/
void lv_example_style_6(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_img_recolor(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_img_recolor_opa(&style, LV_OPA_50);
lv_style_set_transform_angle(&style, 300);
LV_IMG_DECLARE(img_cogwheel_argb);
lv_img_set_src(obj, &img_cogwheel_argb);
lv_obj_center(obj);
(continues on next page)
#endif
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Using the Image style properties
#
style = lv.style_t()
style.init()
style.set_img_recolor(lv.palette_main(lv.PALETTE.BLUE))
style.set_img_recolor_opa(lv.OPA._50)
# style.set_transform_angle(300)
obj.set_src(img_cogwheel_argb)
obj.center()
Arc styles
Text styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LABEL
/**
* Using the text style properties
*/
void lv_example_style_8(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 5);
lv_style_set_bg_opa(&style, LV_OPA_COVER);
lv_style_set_bg_color(&style, lv_palette_lighten(LV_PALETTE_GREY, 2));
lv_style_set_border_width(&style, 2);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_pad_all(&style, 10);
lv_style_set_text_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_text_letter_space(&style, 5);
lv_style_set_text_line_space(&style, 20);
lv_style_set_text_decor(&style, LV_TEXT_DECOR_UNDERLINE);
lv_obj_center(obj);
}
#endif
#
# Using the text style properties
#
style = lv.style_t()
style.init()
style.set_radius(5)
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_lighten(lv.PALETTE.GREY, 3))
style.set_border_width(2)
(continues on next page)
style.set_text_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_text_letter_space(5)
style.set_text_line_space(20)
style.set_text_decor(lv.TEXT_DECOR.UNDERLINE)
obj.center()
Line styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LINE
/**
* Using the line style properties
*/
void lv_example_style_9(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_line_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_line_width(&style, 6);
lv_style_set_line_rounded(&style, true);
lv_obj_center(obj);
}
#endif
#
# Using the line style properties
#
style = lv.style_t()
style.init()
style.set_line_color(lv.palette_main(lv.PALETTE.GREY))
(continues on next page)
obj.set_points(p, 3)
obj.center()
Transition
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Creating a transition
*/
void lv_example_style_10(void)
{
static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, LV_STYLE_BORDER_COLOR,␣
,→LV_STYLE_BORDER_WIDTH, 0};
/* A default transition
* Make it fast (100ms) and start with some delay (200 ms)*/
static lv_style_transition_dsc_t trans_def;
lv_style_transition_dsc_init(&trans_def, props, lv_anim_path_linear, 100, 200,␣
,→NULL);
lv_obj_center(obj);
(continues on next page)
#endif
#
# Creating a transition
#
# A default transition
# Make it fast (100ms) and start with some delay (200 ms)
trans_def = lv.style_transition_dsc_t()
trans_def.init(props, lv.anim_t.path_linear, 100, 200, None)
trans_pr = lv.style_transition_dsc_t()
trans_pr.init(props, lv.anim_t.path_linear, 500, 0, None)
style_def = lv.style_t()
style_def.init()
style_def.set_transition(trans_def)
style_pr = lv.style_t()
style_pr.init()
style_pr.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_pr.set_border_width(6)
style_pr.set_border_color(lv.palette_darken(lv.PALETTE.RED, 3))
style_pr.set_transition(trans_pr)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Using multiple styles
*/
void lv_example_style_11(void)
{
/*A base style*/
static lv_style_t style_base;
lv_style_init(&style_base);
lv_style_set_bg_color(&style_base, lv_palette_main(LV_PALETTE_LIGHT_BLUE));
(continues on next page)
lv_style_set_border_width(&style_base, 2);
lv_style_set_radius(&style_base, 10);
lv_style_set_shadow_width(&style_base, 10);
lv_style_set_shadow_ofs_y(&style_base, 5);
lv_style_set_shadow_opa(&style_base, LV_OPA_50);
lv_style_set_text_color(&style_base, lv_color_white());
lv_style_set_width(&style_base, 100);
lv_style_set_height(&style_base, LV_SIZE_CONTENT);
/*Create another object with the base style and earnings style too*/
lv_obj_t * obj_warning = lv_obj_create(lv_scr_act());
lv_obj_add_style(obj_warning, &style_base, 0);
lv_obj_add_style(obj_warning, &style_warning, 0);
lv_obj_align(obj_warning, LV_ALIGN_RIGHT_MID, -20, 0);
label = lv_label_create(obj_warning);
lv_label_set_text(label, "Warning");
lv_obj_center(label);
}
#endif
#
# Using multiple styles
#
# A base style
style_base = lv.style_t()
style_base.init()
style_base.set_bg_color(lv.palette_main(lv.PALETTE.LIGHT_BLUE))
style_base.set_border_color(lv.palette_darken(lv.PALETTE.LIGHT_BLUE, 3))
style_base.set_border_width(2)
style_base.set_radius(10)
style_base.set_shadow_width(10)
style_base.set_shadow_ofs_y(5)
style_base.set_shadow_opa(lv.OPA._50)
style_base.set_text_color(lv.color_white())
(continues on next page)
label = lv.label(obj_base)
label.set_text("Base")
label.center()
# Create another object with the base style and earnings style too
obj_warning = lv.obj(lv.scr_act())
obj_warning.add_style(style_base, 0)
obj_warning.add_style(style_warning, 0)
obj_warning.align(lv.ALIGN.RIGHT_MID, -20, 0)
label = lv.label(obj_warning)
label.set_text("Warning")
label.center()
Local styles
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Local styles
*/
void lv_example_style_12(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_GREEN));
lv_style_set_border_color(&style, lv_palette_lighten(LV_PALETTE_GREEN, 3));
lv_style_set_border_width(&style, 3);
lv_obj_center(obj);
}
#endif
#
# Local styles
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.palette_main(lv.PALETTE.GREEN))
style.set_border_color(lv.palette_lighten(lv.PALETTE.GREEN, 3))
style.set_border_width(3)
obj = lv.obj(lv.scr_act())
obj.add_style(style, 0)
obj.center()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/**
* Add styles to parts and states
*/
void lv_example_style_13(void)
{
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_color(&style_indic, lv_palette_lighten(LV_PALETTE_RED, 3));
lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_HOR);
#endif
#
# Add styles to parts and states
#
style_indic = lv.style_t()
(continues on next page)
style_indic_pr = lv.style_t()
style_indic_pr.init()
style_indic_pr.set_shadow_color(lv.palette_main(lv.PALETTE.RED))
style_indic_pr.set_shadow_width(10)
style_indic_pr.set_shadow_spread(3)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_IMG
/*Will be called when the styles of the base theme are already added
to add new styles*/
static void new_theme_apply_cb(lv_theme_t * th, lv_obj_t * obj)
{
LV_UNUSED(th);
if(lv_obj_check_type(obj, &lv_btn_class)) {
lv_obj_add_style(obj, &style_btn, 0);
}
}
/*Set the parent theme and the style apply callback for the new theme*/
lv_theme_set_parent(&th_new, th_act);
lv_theme_set_apply_cb(&th_new, new_theme_apply_cb);
/**
* Extending the current theme
*/
void lv_example_style_14(void)
{
lv_obj_t * btn;
lv_obj_t * label;
btn = lv_btn_create(lv_scr_act());
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 20);
label = lv_label_create(btn);
lv_label_set_text(label, "Original theme");
new_theme_init_and_set();
btn = lv_btn_create(lv_scr_act());
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -20);
label = lv_label_create(btn);
lv_label_set_text(label, "New theme");
}
#endif
# Will be called when the styles of the base theme are already added
# to add new styles
class NewTheme(lv.theme_t):
def __init__(self):
super().__init__()
# Initialize the styles
self.style_btn = lv.style_t()
self.style_btn.init()
self.style_btn.set_bg_color(lv.palette_main(lv.PALETTE.GREEN))
self.style_btn.set_border_color(lv.palette_darken(lv.PALETTE.GREEN, 3))
self.style_btn.set_border_width(3)
class ExampleStyle_14:
def __init__(self):
#
# Extending the current theme
#
btn = lv.btn(lv.scr_act())
btn.align(lv.ALIGN.TOP_MID, 0, 20)
(continues on next page)
label = lv.label(btn)
label.set_text("Original theme")
self.new_theme_init_and_set()
btn = lv.btn(lv.scr_act())
btn.align(lv.ALIGN.BOTTOM_MID, 0, -20)
label = lv.label(btn)
label.set_text("New theme")
def new_theme_init_and_set(self):
print("new_theme_init_and_set")
# Initialize the new theme from the current theme
self.th_new = NewTheme()
self.th_new.set_apply_cb(self.new_theme_apply_cb)
lv.disp_get_default().set_theme(self.th_new)
exampleStyle_14 = ExampleStyle_14()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN && LV_USE_LABEL
/**
* Opacity and Transformations
*/
void lv_example_style_15(void)
{
lv_obj_t * btn;
lv_obj_t * label;
/*Normal button*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, -70);
label = lv_label_create(btn);
lv_label_set_text(label, "Normal");
lv_obj_center(label);
/*Set opacity
*The button and the label is rendered to a layer first and that layer is␣
,→blended*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_set_style_opa(btn, LV_OPA_50, 0);
(continues on next page)
label = lv_label_create(btn);
lv_label_set_text(label, "Opa:50%");
lv_obj_center(label);
/*Set transformations
*The button and the label is rendered to a layer first and that layer is␣
,→transformed*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 40);
lv_obj_set_style_transform_angle(btn, 150, 0); /*15 deg*/
lv_obj_set_style_transform_zoom(btn, 256 + 64, 0); /*1.25x*/
lv_obj_set_style_transform_pivot_x(btn, 50, 0);
lv_obj_set_style_transform_pivot_y(btn, 20, 0);
lv_obj_set_style_opa(btn, LV_OPA_50, 0);
lv_obj_align(btn, LV_ALIGN_CENTER, 0, 70);
label = lv_label_create(btn);
lv_label_set_text(label, "Transf.");
lv_obj_center(label);
}
#endif
5.3.15 API
Typedefs
Enums
enum [anonymous]
Possible options how to blend opaque drawings
Values:
enumerator LV_BLEND_MODE_NORMAL
Simply mix according to the opacity value
enumerator LV_BLEND_MODE_ADDITIVE
Add the respective color channels
enumerator LV_BLEND_MODE_SUBTRACTIVE
Subtract the foreground from the background
enumerator LV_BLEND_MODE_MULTIPLY
Multiply the foreground and background
enumerator LV_BLEND_MODE_REPLACE
Replace background with foreground in the area
enum [anonymous]
Some options to apply decorations on texts. 'OR'ed values can be used.
Values:
enumerator LV_TEXT_DECOR_NONE
enumerator LV_TEXT_DECOR_UNDERLINE
enumerator LV_TEXT_DECOR_STRIKETHROUGH
enum [anonymous]
Selects on which sides border should be drawn 'OR'ed values can be used.
Values:
enumerator LV_BORDER_SIDE_NONE
enumerator LV_BORDER_SIDE_BOTTOM
enumerator LV_BORDER_SIDE_TOP
enumerator LV_BORDER_SIDE_LEFT
enumerator LV_BORDER_SIDE_RIGHT
enumerator LV_BORDER_SIDE_FULL
enumerator LV_BORDER_SIDE_INTERNAL
FOR matrix-like objects (e.g. Button matrix)
enum [anonymous]
The direction of the gradient.
Values:
enumerator LV_GRAD_DIR_NONE
No gradient (the grad_color property is ignored)
enumerator LV_GRAD_DIR_VER
Vertical (top to bottom) gradient
enumerator LV_GRAD_DIR_HOR
Horizontal (left to right) gradient
enum [anonymous]
The dithering algorithm for the gradient Depends on LV_DITHER_GRADIENT
Values:
enumerator LV_DITHER_NONE
No dithering, colors are just quantized to the output resolution
enumerator LV_DITHER_ORDERED
Ordered dithering. Faster to compute and use less memory but lower quality
enumerator LV_DITHER_ERR_DIFF
Error diffusion mode. Slower to compute and use more memory but give highest dither quality
enum lv_style_prop_t
Enumeration of all built in style properties
Props are split into groups of 16. When adding a new prop to a group, ensure it does not overflow into the next one.
Values:
enumerator LV_STYLE_PROP_INV
enumerator LV_STYLE_WIDTH
enumerator LV_STYLE_MIN_WIDTH
enumerator LV_STYLE_MAX_WIDTH
enumerator LV_STYLE_HEIGHT
enumerator LV_STYLE_MIN_HEIGHT
enumerator LV_STYLE_MAX_HEIGHT
enumerator LV_STYLE_X
enumerator LV_STYLE_Y
enumerator LV_STYLE_ALIGN
enumerator LV_STYLE_LAYOUT
enumerator LV_STYLE_RADIUS
enumerator LV_STYLE_PAD_TOP
enumerator LV_STYLE_PAD_BOTTOM
enumerator LV_STYLE_PAD_LEFT
enumerator LV_STYLE_PAD_RIGHT
enumerator LV_STYLE_PAD_ROW
enumerator LV_STYLE_PAD_COLUMN
enumerator LV_STYLE_BASE_DIR
enumerator LV_STYLE_CLIP_CORNER
enumerator LV_STYLE_BG_COLOR
enumerator LV_STYLE_BG_OPA
enumerator LV_STYLE_BG_GRAD_COLOR
enumerator LV_STYLE_BG_GRAD_DIR
enumerator LV_STYLE_BG_MAIN_STOP
enumerator LV_STYLE_BG_GRAD_STOP
enumerator LV_STYLE_BG_GRAD
enumerator LV_STYLE_BG_DITHER_MODE
enumerator LV_STYLE_BG_IMG_SRC
enumerator LV_STYLE_BG_IMG_OPA
enumerator LV_STYLE_BG_IMG_RECOLOR
enumerator LV_STYLE_BG_IMG_RECOLOR_OPA
enumerator LV_STYLE_BG_IMG_TILED
enumerator LV_STYLE_BORDER_COLOR
enumerator LV_STYLE_BORDER_OPA
enumerator LV_STYLE_BORDER_WIDTH
enumerator LV_STYLE_BORDER_SIDE
enumerator LV_STYLE_BORDER_POST
enumerator LV_STYLE_OUTLINE_WIDTH
enumerator LV_STYLE_OUTLINE_COLOR
enumerator LV_STYLE_OUTLINE_OPA
enumerator LV_STYLE_OUTLINE_PAD
enumerator LV_STYLE_SHADOW_WIDTH
enumerator LV_STYLE_SHADOW_OFS_X
enumerator LV_STYLE_SHADOW_OFS_Y
enumerator LV_STYLE_SHADOW_SPREAD
enumerator LV_STYLE_SHADOW_COLOR
enumerator LV_STYLE_SHADOW_OPA
enumerator LV_STYLE_IMG_OPA
enumerator LV_STYLE_IMG_RECOLOR
enumerator LV_STYLE_IMG_RECOLOR_OPA
enumerator LV_STYLE_LINE_WIDTH
enumerator LV_STYLE_LINE_DASH_WIDTH
enumerator LV_STYLE_LINE_DASH_GAP
enumerator LV_STYLE_LINE_ROUNDED
enumerator LV_STYLE_LINE_COLOR
enumerator LV_STYLE_LINE_OPA
enumerator LV_STYLE_ARC_WIDTH
enumerator LV_STYLE_ARC_ROUNDED
enumerator LV_STYLE_ARC_COLOR
enumerator LV_STYLE_ARC_OPA
enumerator LV_STYLE_ARC_IMG_SRC
enumerator LV_STYLE_TEXT_COLOR
enumerator LV_STYLE_TEXT_OPA
enumerator LV_STYLE_TEXT_FONT
enumerator LV_STYLE_TEXT_LETTER_SPACE
enumerator LV_STYLE_TEXT_LINE_SPACE
enumerator LV_STYLE_TEXT_DECOR
enumerator LV_STYLE_TEXT_ALIGN
enumerator LV_STYLE_OPA
enumerator LV_STYLE_OPA_LAYERED
enumerator LV_STYLE_COLOR_FILTER_DSC
enumerator LV_STYLE_COLOR_FILTER_OPA
enumerator LV_STYLE_ANIM
enumerator LV_STYLE_ANIM_TIME
enumerator LV_STYLE_ANIM_SPEED
enumerator LV_STYLE_TRANSITION
enumerator LV_STYLE_BLEND_MODE
enumerator LV_STYLE_TRANSFORM_WIDTH
enumerator LV_STYLE_TRANSFORM_HEIGHT
enumerator LV_STYLE_TRANSLATE_X
enumerator LV_STYLE_TRANSLATE_Y
enumerator LV_STYLE_TRANSFORM_ZOOM
enumerator LV_STYLE_TRANSFORM_ANGLE
enumerator LV_STYLE_TRANSFORM_PIVOT_X
enumerator LV_STYLE_TRANSFORM_PIVOT_Y
enumerator _LV_STYLE_LAST_BUILT_IN_PROP
enumerator _LV_STYLE_NUM_BUILT_IN_PROPS
enumerator LV_STYLE_PROP_ANY
enumerator _LV_STYLE_PROP_CONST
enum [anonymous]
Values:
enumerator LV_STYLE_RES_NOT_FOUND
enumerator LV_STYLE_RES_FOUND
enumerator LV_STYLE_RES_INHERIT
Functions
LV_EXPORT_CONST_INT(LV_IMG_ZOOM_NONE)
Note: Do not call lv_style_init on styles that already have some properties because this function won't free
the used memory, just sets a default state for the style. In other words be sure to initialize styles only once!
lv_style_prop_t lv_style_get_num_custom_props(void)
Get the number of custom properties that have been registered thus far.
bool lv_style_remove_prop(lv_style_t *style, lv_style_prop_t prop)
Remove a property from a style
Parameters
• style -- pointer to a style
• prop -- a style property ORed with a state.
Returns true: the property was found and removed; false: the property wasn't found
Parameters
• style -- pointer to a style
• prop -- the ID of a property
• value -- pointer to a lv_style_value_t variable to store the value
Returns LV_RES_INV: the property wasn't found in the style (value is unchanged) LV_RES_OK:
the property was fond, and value is set accordingly
Note: This function is the same as lv_style_get_prop but inlined. Use it only on performance critical places
Parameters
• style -- pointer to a style
• prop -- the ID of a property
• value -- pointer to a lv_style_value_t variable to store the value
Returns LV_RES_INV: the property wasn't found in the style (value is unchanged) LV_RES_OK:
the property was fond, and value is set accordingly
struct lv_gradient_stop_t
#include <lv_style.h> A gradient stop definition. This matches a color and a position in a virtual 0-255 scale.
Public Members
lv_color_t color
The stop color
uint8_t frac
The stop position in 1/255 unit
struct lv_grad_dsc_t
#include <lv_style.h> A descriptor of a gradient.
Public Members
lv_gradient_stop_t stops[LV_GRADIENT_MAX_STOPS]
A gradient stop array
uint8_t stops_count
The number of used stops in the array
lv_grad_dir_t dir
The gradient direction. Any of LV_GRAD_DIR_HOR, LV_GRAD_DIR_VER, LV_GRAD_DIR_NONE
lv_dither_mode_t dither
Whether to dither the gradient or not. Any of LV_DITHER_NONE, LV_DITHER_ORDERED,
LV_DITHER_ERR_DIFF
union lv_style_value_t
#include <lv_style.h> A common type to handle all the property types in the same way.
Public Members
int32_t num
Number integer number (opacity, enums, booleans or "normal" numbers)
lv_color_t color
Colors
struct lv_style_transition_dsc_t
#include <lv_style.h> Descriptor for style transitions
Public Members
void *user_data
A custom user data that will be passed to the animation's user_data
lv_anim_path_cb_t path_xcb
A path for the animation.
uint32_t time
Duration of the transition in [ms]
uint32_t delay
Delay before the transition in [ms]
struct lv_style_const_prop_t
#include <lv_style.h> Descriptor of a constant style property.
Public Members
lv_style_prop_t prop
lv_style_value_t value
struct lv_style_t
#include <lv_style.h> Descriptor of a style (a collection of properties and values).
Public Members
uint32_t sentinel
lv_style_value_t value1
uint8_t *values_and_props
uint16_t prop1
uint8_t has_group
uint8_t prop_cnt
Typedefs
Functions
struct _lv_theme_t
Public Members
lv_theme_apply_cb_t apply_cb
void *user_data
lv_color_t color_primary
lv_color_t color_secondary
uint32_t flags
Functions
static inline const lv_grad_dsc_t *lv_obj_get_style_bg_grad(const struct _lv_obj_t *obj, uint32_t part)
static inline const void *lv_obj_get_style_bg_img_src(const struct _lv_obj_t *obj, uint32_t part)
static inline const void *lv_obj_get_style_arc_img_src(const struct _lv_obj_t *obj, uint32_t part)
static inline const lv_font_t *lv_obj_get_style_text_font(const struct _lv_obj_t *obj, uint32_t part)
static inline const lv_anim_t *lv_obj_get_style_anim(const struct _lv_obj_t *obj, uint32_t part)
Functions
width
Sets the width of object. Pixel, percentage and LV_SIZE_CONTENT values can be used. Percentage values are relative
to the width of the parent's content area.
min_width
Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's
content area.
max_width
Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's
content area.
height
Sets the height of object. Pixel, percentage and LV_SIZE_CONTENT can be used. Percentage values are relative to the
height of the parent's content area.
min_height
Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's
content area.
max_height
Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's
content area.
Set the X coordinate of the object considering the set align. Pixel and percentage values can be used. Percentage values
are relative to the width of the parent's content area.
Set the Y coordinate of the object considering the set align. Pixel and percentage values can be used. Percentage values
are relative to the height of the parent's content area.
align
Set the alignment which tells from which point of the parent the X and Y coordinates should be interpreted. The possible
values are: LV_ALIGN_DEFAULT, LV_ALIGN_TOP_LEFT/MID/RIGHT, LV_ALIGN_BOTTOM_LEFT/
MID/RIGHT, LV_ALIGN_LEFT/RIGHT_MID, LV_ALIGN_CENTER. LV_ALIGN_DEFAULT means
LV_ALIGN_TOP_LEFT with LTR base direction and LV_ALIGN_TOP_RIGHT with RTL base direction.
transform_width
Make the object wider on both sides with this value. Pixel and percentage (with lv_pct(x)) values can be used.
Percentage values are relative to the object's width.
transform_height
Make the object higher on both sides with this value. Pixel and percentage (with lv_pct(x)) values can be used.
Percentage values are relative to the object's height.
translate_x
Move the object with this value in X direction. Applied after layouts, aligns and other positioning. Pixel and percentage
(with lv_pct(x)) values can be used. Percentage values are relative to the object's width.
translate_y
Move the object with this value in Y direction. Applied after layouts, aligns and other positioning. Pixel and percentage
(with lv_pct(x)) values can be used. Percentage values are relative to the object's height.
transform_zoom
Zoom an objects. The value 256 (or LV_IMG_ZOOM_NONE) means normal size, 128 half size, 512 double size, and so
on
transform_angle
Rotate an objects. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg.
transform_pivot_x
Set the pivot point's X coordinate for transformations. Relative to the object's top left corner'
transform_pivot_y
Set the pivot point's Y coordinate for transformations. Relative to the object's top left corner'
5.4.2 Padding
Properties to describe spacing between the parent's sides and the children and among the children. Very similar to the
padding properties in HTML.
pad_top
Sets the padding on the top. It makes the content area smaller in this direction.
pad_bottom
Sets the padding on the bottom. It makes the content area smaller in this direction.
pad_left
Sets the padding on the left. It makes the content area smaller in this direction.
pad_right
Sets the padding on the right. It makes the content area smaller in this direction.
pad_row
pad_column
5.4.3 Background
bg_color
bg_opa
Set the opacity of the background. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255,
LV_OPA_100 or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi
transparency.
bg_grad_color
Set the gradient color of the background. Used only if grad_dir is not LV_GRAD_DIR_NONE
bg_grad_dir
Set the direction of the gradient of the background. The possible values are LV_GRAD_DIR_NONE/HOR/VER.
bg_main_stop
Set the point from which the background color should start for gradients. 0 means to top/left side, 255 the bottom/right
side, 128 the center, and so on
bg_grad_stop
Set the point from which the background's gradient color should start. 0 means to top/left side, 255 the bottom/right side,
128 the center, and so on
bg_grad
Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps
BG_GRAD_COLOR, BG_GRAD_DIR, BG_MAIN_STOP and BG_GRAD_STOP into one descriptor and allows creat-
ing gradients with more colors too.
bg_dither_mode
Set the dithering mode of the gradient of the background. The possible values are LV_DITHER_NONE/ORDERED/
ERR_DIFF.
bg_img_src
bg_img_opa
Set the opacity of the background image. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255,
LV_OPA_100 or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi
transparency.
bg_img_recolor
bg_img_recolor_opa
Set the intensity of background image recoloring. Value 0, LV_OPA_0 or LV_OPA_TRANSP means no mixing, 255,
LV_OPA_100 or LV_OPA_COVER means full recoloring, other values or LV_OPA_10, LV_OPA_20, etc are inter-
preted proportionally.
bg_img_tiled
If enabled the background image will be tiled. The possible values are true or false.
5.4.4 Border
border_color
border_opa
Set the opacity of the border. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255, LV_OPA_100
or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
border_width
Set the width of the border. Only pixel values can be used.
border_side
Set only which side(s) the border should be drawn. The possible values are LV_BORDER_SIDE_NONE/TOP/
BOTTOM/LEFT/RIGHT/INTERNAL. OR-ed values can be used as well, e.g. LV_BORDER_SIDE_TOP |
LV_BORDER_SIDE_LEFT.
border_post
Sets whether the border should be drawn before or after the children are drawn. true: after children, false: before
children
5.4.5 Outline
Properties to describe the outline. It's like a border but drawn outside of the rectangles.
outline_width
outline_color
outline_opa
Set the opacity of the outline. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255, LV_OPA_100
or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
outline_pad
Set the padding of the outline, i.e. the gap between object and the outline.
5.4.6 Shadow
shadow_width
Set the width of the shadow in pixels. The value should be >= 0.
shadow_ofs_x
shadow_ofs_y
shadow_spread
Make the shadow calculation to use a larger or smaller rectangle as base. The value can be in pixel to make the area
larger/smaller
shadow_color
shadow_opa
Set the opacity of the shadow. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255, LV_OPA_100
or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
5.4.7 Image
img_opa
Set the opacity of an image. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255, LV_OPA_100
or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
img_recolor
img_recolor_opa
Set the intensity of the color mixing. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255,
LV_OPA_100 or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi
transparency.
5.4.8 Line
line_width
line_dash_width
Set the width of dashes in pixel. Note that dash works only on horizontal and vertical lines
line_dash_gap
Set the gap between dashes in pixel. Note that dash works only on horizontal and vertical lines
line_rounded
Make the end points of the lines rounded. true: rounded, false: perpendicular line ending
line_color
line_opa
5.4.9 Arc
TODO
arc_width
arc_rounded
Make the end points of the arcs rounded. true: rounded, false: perpendicular line ending
arc_color
arc_opa
arc_img_src
Set an image from which the arc will be masked out. It's useful to display complex effects on the arcs. Can be a pointer
to lv_img_dsc_t or a path to a file
5.4.10 Text
Properties to describe the properties of text. All these properties are inherited.
text_color
text_opa
Set the opacity of the text. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully transparent, 255, LV_OPA_100 or
LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
text_font
text_letter_space
text_line_space
text_decor
Set decoration for the text. The possible values are LV_TEXT_DECOR_NONE/UNDERLINE/STRIKETHROUGH.
OR-ed values can be used as well.
text_align
Set how to align the lines of the text. Note that it doesn't align the object itself, only the lines inside the object. The
possible values are LV_TEXT_ALIGN_LEFT/CENTER/RIGHT/AUTO. LV_TEXT_ALIGN_AUTO detect the text
base direction and uses left or right alignment accordingly
5.4.11 Miscellaneous
radius
Set the radius on every corner. The value is interpreted in pixel (>= 0) or LV_RADIUS_CIRCLE for max. radius
clip_corner
Enable to clip the overflowed content on the rounded corner. Can be true or false.
opa
Scale down all opacity values of the object by this factor. Value 0, LV_OPA_0 or LV_OPA_TRANSP means fully
transparent, 255, LV_OPA_100 or LV_OPA_COVER means fully covering, other values or LV_OPA_10, LV_OPA_20,
etc means semi transparency.
opa_layered
First draw the object on the layer, then scale down layer opacity factor. Value 0, LV_OPA_0 or LV_OPA_TRANSP
means fully transparent, 255, LV_OPA_100 or LV_OPA_COVER means fully covering, other values or LV_OPA_10,
LV_OPA_20, etc means semi transparency.
color_filter_dsc
color_filter_opa
anim
The animation template for the object's animation. Should be a pointer to lv_anim_t. The animation parameters are
widget specific, e.g. animation time could be the E.g. blink time of the cursor on the text area or scroll time of a roller.
See the widgets' documentation to learn more.
anim_time
The animation time in milliseconds. Its meaning is widget specific. E.g. blink time of the cursor on the text area or scroll
time of a roller. See the widgets' documentation to learn more.
anim_speed
The animation speed in pixel/sec. Its meaning is widget specific. E.g. scroll speed of label. See the widgets' documentation
to learn more.
transition
blend_mode
Describes how to blend the colors to the background. The possible values are LV_BLEND_MODE_NORMAL/
ADDITIVE/SUBTRACTIVE/MULTIPLY
layout
Set the layout of the object. The children will be repositioned and resized according to the policies set for the layout. For
the possible values see the documentation of the layouts.
base_dir
Set the base direction of the object. The possible values are LV_BIDI_DIR_LTR/RTL/AUTO.
5.5 Scroll
5.5.1 Overview
In LVGL scrolling works very intuitively: if an object is outside its parent content area (the size without padding), the
parent becomes scrollable and scrollbar(s) will appear. That's it.
Any object can be scrollable including lv_obj_t, lv_img, lv_btn, lv_meter, etc
The object can either be scrolled horizontally or vertically in one stroke; diagonal scrolling is not possible.
Scrollbar
Mode
Scrollbars are displayed according to a configured mode. The following modes exist:
• LV_SCROLLBAR_MODE_OFF Never show the scrollbars
• LV_SCROLLBAR_MODE_ON Always show the scrollbars
• LV_SCROLLBAR_MODE_ACTIVE Show scroll bars while an object is being scrolled
• LV_SCROLLBAR_MODE_AUTO Show scroll bars when the content is large enough to be scrolled
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_...) sets the scrollbar mode on an object.
Styling
The scrollbars have their own dedicated part, called LV_PART_SCROLLBAR. For example a scrollbar can turn to red
like this:
...
An object goes to the LV_STATE_SCROLLED state while it's being scrolled. This allows adding different styles to the
scrollbar or the object itself when scrolled. This code makes the scrollbar blue when the object is scrolled:
...
If the base direction of the LV_PART_SCROLLBAR is RTL (LV_BASE_DIR_RTL) the vertical scrollbar will be
placed on the left. Note that, the base_dir style property is inherited. Therefore, it can be set directly on the
LV_PART_SCROLLBAR part of an object or on the object's or any parent's main part to make a scrollbar inherit the
base direction.
pad_left/right/top/bottom sets the spacing around the scrollbars and width sets the scrollbar's width.
Events
TODO
Besides, managing "normal" scrolling there are many interesting and useful additional features.
Scrollable
Scroll chain
If an object can't be scrolled further (e.g. its content has reached the bottom-most position) additional scrolling is propa-
gated to its parent. If the parent can be scrolled in that direction than it will be scrolled instead. It continues propagating
to the grandparent and grand-grandparents as well.
The propagation on scrolling is called "scroll chaining" and it can be enabled/disabled with
LV_OBJ_FLAG_SCROLL_CHAIN_HOR/VER flag. If chaining is disabled the propagation stops on the object
and the parent(s) won't be scrolled.
Scroll momentum
When the user scrolls an object and releases it, LVGL can emulate inertial momentum for the scrolling. It's like the object
was thrown and scrolling slows down smoothly.
The scroll momentum can be enabled/disabled with the LV_OBJ_FLAG_SCROLL_MOMENTUM flag.
Elastic scroll
Normally an object can't be scrolled past the extremeties of its content. That is the top side of the content can't be below
the top side of the object.
However, with LV_OBJ_FLAG_SCROLL_ELASTIC a fancy effect is added when the user "over-scrolls" the content.
The scrolling slows down, and the content can be scrolled inside the object. When the object is released the content
scrolled in it will be animated back to the valid position.
Snapping
The children of an object can be snapped according to specific rules when scrolling ends. Children can be made snappable
individually with the LV_OBJ_FLAG_SNAPPABLE flag.
An object can align snapped children in four ways:
• LV_SCROLL_SNAP_NONE Snapping is disabled. (default)
• LV_SCROLL_SNAP_START Align the children to the left/top side of a scrolled object
• LV_SCROLL_SNAP_END Align the children to the right/bottom side of a scrolled object
• LV_SCROLL_SNAP_CENTER Align the children to the center of a scrolled object
Snap alignment is set with lv_obj_set_scroll_snap_x/y(obj, LV_SCROLL_SNAP_...):
Under the hood the following happens:
1. User scrolls an object and releases the screen
2. LVGL calculates where the scroll would end considering scroll momentum
3. LVGL finds the nearest scroll point
4. LVGL scrolls to the snap point with an animation
Scroll one
The "scroll one" feature tells LVGL to allow scrolling only one snappable child at a time. This requires making the
children snappable and setting a scroll snap alignment different from LV_SCROLL_SNAP_NONE.
This feature can be enabled by the LV_OBJ_FLAG_SCROLL_ONE flag.
Scroll on focus
Imagine that there a lot of objects in a group that are on a scrollable object. Pressing the "Tab" button focuses the next
object but it might be outside the visible area of the scrollable object. If the "scroll on focus" feature is enabled LVGL
will automatically scroll objects to bring their children into view. The scrolling happens recursively therefore even nested
scrollable objects are handled properly. The object will be scrolled into view even if it's on a different page of a tabview.
Scrool coordinates can be retrieve from differents axes with these functions:
• lv_obj_get_scroll_x(obj) Get the x coordinate of object
• lv_obj_get_scroll_y(obj) Get the y coordinate of object
• lv_obj_get_scroll_top(obj) Get the scroll coordinate from the top
• lv_obj_get_scroll_bottom(obj) Get the scroll coordinate from the bottom
• lv_obj_get_scroll_left(obj) Get the scroll coordinate from the left
• lv_obj_get_scroll_right(obj) Get the scroll coordinate from the right
Self size is a property of an object. Normally, the user shouldn't use this parameter but if a custom widget is created it
might be useful.
In short, self size establishes the size of an object's content. To understand it better take the example of a table. Let's say
it has 10 rows each with 50 px height. So the total height of the content is 500 px. In other words the "self height" is 500
px. If the user sets only 200 px height for the table LVGL will see that the self size is larger and make the table scrollable.
This means not only the children can make an object scrollable but a larger self size will too.
LVGL uses the LV_EVENT_GET_SELF_SIZE event to get the self size of an object. Here is an example to see how
to handle the event:
if(event_code == LV_EVENT_GET_SELF_SIZE) {
lv_point_t * p = lv_event_get_param(e);
if(p->y >= 0) {
p->y = 50; //Set or calculate the self height
}
}
5.5.6 Examples
Nested scrolling
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
/**
* Demonstrate how scrolling appears automatically
*/
void lv_example_scroll_1(void)
{
/*Create an object with the new style*/
lv_obj_t * panel = lv_obj_create(lv_scr_act());
lv_obj_set_size(panel, 200, 200);
lv_obj_center(panel);
lv_obj_t * child;
lv_obj_t * label;
child = lv_obj_create(panel);
lv_obj_set_pos(child, 0, 0);
lv_obj_set_size(child, 70, 70);
label = lv_label_create(child);
lv_label_set_text(label, "Zero");
lv_obj_center(label);
child = lv_obj_create(panel);
lv_obj_set_pos(child, 160, 80);
lv_obj_set_size(child, 80, 80);
label = lv_label_create(child2);
lv_label_set_text(label, "Right");
lv_obj_center(label);
child = lv_obj_create(panel);
lv_obj_set_pos(child, 40, 160);
lv_obj_set_size(child, 100, 70);
label = lv_label_create(child);
lv_label_set_text(label, "Bottom");
lv_obj_center(label);
}
#endif
#
# Demonstrate how scrolling appears automatically
#
# Create an object with the new style
panel = lv.obj(lv.scr_act())
panel.set_size(200, 200)
panel.center()
child = lv.obj(panel)
(continues on next page)
child = lv.obj(panel)
child.set_pos(-40, 100)
label = lv.label(child)
label.set_text("Left")
label.center()
child = lv.obj(panel)
child.set_pos(90, -30)
label = lv.label(child)
label.set_text("Top")
label.center()
child = lv.obj(panel)
child.set_pos(150, 80)
label = lv.label(child)
label.set_text("Right")
label.center()
child = lv.obj(panel)
child.set_pos(60, 170)
label = lv.label(child)
label.set_text("Bottom")
label.center()
Snapping
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_t * list = lv_event_get_user_data(e);
/**
* Show an example to scroll snap
*/
void lv_example_scroll_2(void)
{
lv_obj_t * panel = lv_obj_create(lv_scr_act());
(continues on next page)
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * btn = lv_btn_create(panel);
lv_obj_set_size(btn, 150, lv_pct(100));
lv_obj_center(label);
}
lv_obj_update_snap(panel, LV_ANIM_ON);
#if LV_USE_SWITCH
/*Switch between "One scroll" and "Normal scroll" mode*/
lv_obj_t * sw = lv_switch_create(lv_scr_act());
lv_obj_align(sw, LV_ALIGN_TOP_RIGHT, -20, 10);
lv_obj_add_event_cb(sw, sw_event_cb, LV_EVENT_ALL, panel);
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "One scroll");
lv_obj_align_to(label, sw, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
#endif
}
#endif
def sw_event_cb(e,panel):
code = e.get_code()
sw = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
if sw.has_state(lv.STATE.CHECKED):
panel.add_flag(lv.obj.FLAG.SCROLL_ONE)
else:
panel.clear_flag(lv.obj.FLAG.SCROLL_ONE)
#
# Show an example to scroll snap
#
panel = lv.obj(lv.scr_act())
panel.set_size(280, 150)
panel.set_scroll_snap_x(lv.SCROLL_SNAP.CENTER)
(continues on next page)
for i in range(10):
btn = lv.btn(panel)
btn.set_size(150, 100)
label = lv.label(btn)
if i == 3:
label.set_text("Panel {:d}\nno snap".format(i))
btn.clear_flag(lv.obj.FLAG.SNAPPABLE)
else:
label.set_text("Panel {:d}".format(i))
label.center()
panel.update_snap(lv.ANIM.ON)
Floating button
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LIST
if(code == LV_EVENT_CLICKED) {
lv_obj_t * list = lv_event_get_user_data(e);
char buf[32];
lv_snprintf(buf, sizeof(buf), "Track %d", (int)btn_cnt);
lv_obj_t * list_btn = lv_list_add_btn(list, LV_SYMBOL_AUDIO, buf);
btn_cnt++;
lv_obj_move_foreground(float_btn);
lv_obj_scroll_to_view(list_btn, LV_ANIM_ON);
}
}
/**
* Create a list with a floating button
(continues on next page)
#endif
class ScrollExample_3():
def __init__(self):
self.btn_cnt = 1
#
# Create a list with a floating button
#
list = lv.list(lv.scr_act())
list.set_size(280, 220)
list.center()
float_btn = lv.btn(list)
float_btn.set_size(50, 50)
float_btn.add_flag(lv.obj.FLAG.FLOATING)
float_btn.align(lv.ALIGN.BOTTOM_RIGHT, 0, -list.get_style_pad_right(lv.PART.
,→ MAIN))
float_btn.add_event_cb(lambda evt: self.float_btn_event_cb(evt,list), lv.
,→ EVENT.ALL, None)
float_btn.set_style_radius(lv.RADIUS.CIRCLE, 0)
float_btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
float_btn.set_style_text_font(lv.theme_get_font_large(float_btn), 0)
def float_btn_event_cb(self,e,list):
code = e.get_code()
float_btn = e.get_target()
if code == lv.EVENT.CLICKED:
(continues on next page)
float_btn.move_foreground()
list_btn.scroll_to_view(lv.ANIM.ON)
scroll_example_3 = ScrollExample_3()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_LIST
/**
* Styling the scrollbars
*/
void lv_example_scroll_4(void)
{
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj, 200, 100);
lv_obj_center(obj);
lv_style_set_radius(&style, 2);
lv_style_set_bg_opa(&style, LV_OPA_70);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_border_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 3));
lv_style_set_border_width(&style, 2);
lv_style_set_shadow_width(&style, 8);
lv_style_set_shadow_spread(&style, 2);
lv_style_set_shadow_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 1));
lv_style_set_transition(&style, &trans);
/*Make the scrollbars wider and use 100% opacity when scrolled*/
static lv_style_t style_scrolled;
lv_style_init(&style_scrolled);
lv_style_set_width(&style_scrolled, 8);
lv_style_set_bg_opa(&style_scrolled, LV_OPA_COVER);
#endif
#
# Styling the scrollbars
#
obj = lv.obj(lv.scr_act())
obj.set_size(200, 100)
obj.center()
label = lv.label(obj)
label.set_text(
"""
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Etiam dictum, tortor vestibulum lacinia laoreet, mi neque consectetur neque, vel␣
,→mattis odio dolor egestas ligula.
style.set_radius(2)
style.set_bg_opa(lv.OPA._70)
style.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_border_color(lv.palette_darken(lv.PALETTE.BLUE, 3))
style.set_border_width(2)
style.set_shadow_width(8)
style.set_shadow_spread(2)
style.set_shadow_color(lv.palette_darken(lv.PALETTE.BLUE, 1))
style.set_transition(trans)
# Make the scrollbars wider and use 100% opacity when scrolled
style_scrolled = lv.style_t()
style_scrolled.init()
style_scrolled.set_width(8)
style_scrolled.set_bg_opa(lv.OPA.COVER)
obj.add_style(style, lv.PART.SCROLLBAR)
obj.add_style(style_scrolled, lv.PART.SCROLLBAR | lv.STATE.SCROLLED)
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_FONT_DEJAVU_16_PERSIAN_HEBREW
/**
* Scrolling with Right To Left base direction
*/
void lv_example_scroll_5(void)
{
lv_obj_t * obj = lv_obj_create(lv_scr_act());
lv_obj_set_style_base_dir(obj, LV_BASE_DIR_RTL, 0);
lv_obj_set_size(obj, 200, 100);
lv_obj_center(obj);
,→ کنترل را دیگر ابزارهای تنهایی به میتواند. یک دیگر عبارت به کند،␣مدار میکروکنترلر
5.5. Scroll
,→مجتمع یک از که است کوچکیCPU مانند دیگری اجزای و کوچک،␣خروجی و ورودی درگاههای تایمر 374
,→ تشکیل حافظه و دیجیتال و آنالوگ.;)"شدهاست
LVGL Documentation 8.3
#endif
#
# Scrolling with Right To Left base direction
#
obj = lv.obj(lv.scr_act())
obj.set_style_base_dir(lv.BASE_DIR.RTL, 0)
obj.set_size(200, 100)
obj.center()
label = lv.label(obj)
label.set_text("ُکنترولر )به میکرو: انگلیسیMicrocontroller) ␣که است ریزپردازنده گونهای
,→ٔه دارای
( تصادفی دسترسی حافظRAM) ٔه و
( فقطخواندنی حافظROM)، ،␣و ورودی پورتهای تایمر
,→( خروجیI/O) ( ترتیبی درگاه وSerial Port پورت،( تراشه خود درون سریال،␣میتواند و است
,→ کنترل را دیگر ابزارهای تنهایی به. یک دیگر عبارت به کند،␣مجتمع مدار میکروکنترلر
,→ یک از که است کوچکیCPU مانند دیگری اجزای و کوچک،␣خروجی و ورودی درگاههای تایمر
label.set_width(400)
label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
Translate on scroll
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
lv_area_t cont_a;
lv_obj_get_coords(cont, &cont_a);
lv_coord_t cont_y_center = cont_a.y1 + lv_area_get_height(&cont_a) / 2;
if(diff_y >= r) {
x = r;
}
else {
/*Use Pythagoras theorem to get x from radius and y*/
uint32_t x_sqr = r * r - diff_y * diff_y;
lv_sqrt_res_t res;
lv_sqrt(x_sqr, &res, 0x8000); /*Use lvgl's built in sqrt root function*/
x = r - res.i;
}
/**
* Translate the object as they scroll
*/
void lv_example_scroll_6(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 200, 200);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN);
lv_obj_add_event_cb(cont, scroll_event_cb, LV_EVENT_SCROLL, NULL);
lv_obj_set_style_radius(cont, LV_RADIUS_CIRCLE, 0);
lv_obj_set_style_clip_corner(cont, true, 0);
lv_obj_set_scroll_dir(cont, LV_DIR_VER);
lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF);
uint32_t i;
for(i = 0; i < 20; i++) {
lv_obj_t * btn = lv_btn_create(cont);
lv_obj_set_width(btn, lv_pct(100));
#endif
def scroll_event_cb(e):
cont = e.get_target()
cont_a = lv.area_t()
cont.get_coords(cont_a)
cont_y_center = cont_a.y1 + cont_a.get_height() // 2
r = cont.get_height() * 7 // 10
child_cnt = cont.get_child_cnt()
for i in range(child_cnt):
child = cont.get_child(i)
child_a = lv.area_t()
child.get_coords(child_a)
# If diff_y is out of the circle use the last point of the circle (the radius)
if diff_y >= r:
x = r
else:
# Use Pythagoras theorem to get x from radius and y
x_sqr = r * r - diff_y * diff_y
res = lv.sqrt_res_t()
lv.sqrt(x_sqr, res, 0x8000) # Use lvgl's built in sqrt root function
x = r - res.i
#
# Translate the object as they scroll
#
cont = lv.obj(lv.scr_act())
cont.set_size(200, 200)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.COLUMN)
cont.add_event_cb(scroll_event_cb, lv.EVENT.SCROLL, None)
cont.set_style_radius(lv.RADIUS.CIRCLE, 0)
cont.set_style_clip_corner(True, 0)
cont.set_scroll_dir(lv.DIR.VER)
cont.set_scroll_snap_y(lv.SCROLL_SNAP.CENTER)
cont.set_scrollbar_mode(lv.SCROLLBAR_MODE.OFF)
for i in range(20):
btn = lv.btn(cont)
(continues on next page)
label = lv.label(btn)
label.set_text("Button " + str(i))
5.6 Layers
/*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 automatically setting␣
,→the size according to content*/
LVGL uses two special layers named layer_top and layer_sys. Both are visible and common on all screens of a
display. They are not, however, shared among multiple physical displays. The layer_top is always on top of the
default screen (lv_scr_act()), and layer_sys is on top of layer_top.
The layer_top can be used by the user to create some content visible everywhere. For example, a menu bar, a pop-up,
etc. If the click attribute is enabled, then layer_top will absorb all user clicks and acts as a modal.
lv_obj_add_flag(lv_layer_top(), LV_OBJ_FLAG_CLICKABLE);
The layer_sys is also used for similar purposes in LVGL. For example, it places the mouse cursor above all layers to
be sure it's always visible.
5.7 Events
Events are triggered in LVGL when something happens which might be interesting to the user, e.g. when an object
• is clicked
• is scrolled
• has its value changed
• is redrawn, etc.
The user can assign callback functions to an object to see its events. In practice, it looks like this:
...
In the example LV_EVENT_CLICKED means that only the click event will call my_event_cb. See the list of event
codes for all the options. LV_EVENT_ALL can be used to receive all events.
The last parameter of lv_obj_add_event_cb is a pointer to any custom data that will be available in the event. It
will be described later in more detail.
More events can be added to an object, like this:
Even the same event callback can be used on an object with different user_data. For example:
Events can be removed from an object with the lv_obj_remove_event_cb(obj, event_cb) func-
tion or lv_obj_remove_event_dsc(obj, event_dsc). event_dsc is a pointer returned by
lv_obj_add_event_cb.
Drawing events
Other events
• LV_EVENT_SCREEN_UNLOADED A screen was unloaded, called when all animations are finished
Special events
Custom events
/*Simulate the press of the first button (indexes start from zero)*/
uint32_t btn_id = 0;
lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
Refresh event
LV_EVENT_REFRESH is a special event because it's designed to let the user notify an object to refresh itself. Some
examples:
• notify a label to refresh its text according to one or more variables (e.g. current time)
• refresh a label when the language changes
• enable a button if some conditions are met (e.g. the correct PIN is entered)
• add/remove styles to/from an object if a limit is exceeded, etc
lv_event_t is the only parameter passed to the event callback and it contains all data about the event. The following
values can be gotten from it:
• lv_event_get_code(e) get the event code
• lv_event_get_current_target(e) get the object to which an event was sent. I.e. the object whose
event handler is being called.
• lv_event_get_target(e) get the object that originally triggered the event (different from
lv_event_get_target if event bubbling is enabled)
5.7.7 Examples
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
/**
* Add click event to a button
*/
void lv_example_event_1(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
lv_obj_center(btn);
lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);
#endif
class Event_1():
def __init__(self):
self.cnt = 1
#
# Add click event to a button
#
label = lv.label(btn)
label.set_text("Click me!")
label.center()
def event_cb(self,e):
print("Clicked")
btn = e.get_target()
label = btn.get_child(0)
label.set_text(str(self.cnt))
self.cnt += 1
evt1 = Event_1()
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
switch(code) {
case LV_EVENT_PRESSED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_PRESSED");
break;
case LV_EVENT_CLICKED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_CLICKED");
break;
case LV_EVENT_LONG_PRESSED:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED");
break;
case LV_EVENT_LONG_PRESSED_REPEAT:
lv_label_set_text(label, "The last button event:\nLV_EVENT_LONG_PRESSED_
,→REPEAT");
break;
default:
break;
}
}
/**
* Handle multiple events
*/
void lv_example_event_2(void)
{
lv_obj_t * btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, 100, 50);
(continues on next page)
#endif
def event_cb(e,label):
code = e.get_code()
if code == lv.EVENT.PRESSED:
label.set_text("The last button event:\nLV_EVENT_PRESSED")
elif code == lv.EVENT.CLICKED:
label.set_text("The last button event:\nLV_EVENT_CLICKED")
elif code == lv.EVENT.LONG_PRESSED:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED")
elif code == lv.EVENT.LONG_PRESSED_REPEAT:
label.set_text("The last button event:\nLV_EVENT_LONG_PRESSED_REPEAT")
btn = lv.btn(lv.scr_act())
btn.set_size(100, 50)
btn.center()
btn_label = lv.label(btn)
btn_label.set_text("Click me!")
btn_label.center()
info_label = lv.label(lv.scr_act())
info_label.set_text("The last button event:\nNone")
Event bubbling
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_FLEX
/*The current target is always the container as the event is added to it*/
lv_obj_t * cont = lv_event_get_current_target(e);
/**
* Demonstrate event bubbling
*/
void lv_example_event_3(void)
{
uint32_t i;
for(i = 0; i < 30; i++) {
lv_obj_t * btn = lv_btn_create(cont);
lv_obj_set_size(btn, 80, 50);
lv_obj_add_flag(btn, LV_OBJ_FLAG_EVENT_BUBBLE);
#endif
def event_cb(e):
# The original target of the event. Can be the buttons or the container
target = e.get_target()
# print(type(target))
#
# Demonstrate event bubbling
#
cont = lv.obj(lv.scr_act())
cont.set_size(320, 200)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(30):
btn = lv.btn(cont)
btn.set_size(80, 50)
btn.add_flag(lv.obj.FLAG.EVENT_BUBBLE)
(continues on next page)
label = lv.label(btn)
label.set_text(str(i))
label.center()
Important: Before reading further, please read the [Porting](/porting/indev) section of Input devices
5.8.1 Pointers
Cursor
...
lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
Gestures
Pointer input devices can detect basic gestures. By default, most of the widgets send the gestures to its parent, so finally
the gestures can be detected on the screen object in a form of an LV_EVENT_GESTURE event. For example:
void my_event(lv_event_t * e)
{
lv_obj_t * screen = lv_event_get_current_target(e);
lv_dir_t dir = lv_indev_get_gesture_dir(lv_indev_act());
switch(dir) {
case LV_DIR_LEFT:
...
break;
case LV_DIR_RIGHT:
...
break;
case LV_DIR_TOP:
...
break;
case LV_DIR_BOTTOM:
...
break;
}
}
...
To prevent passing the gesture event to the parent from an object use lv_obj_clear_flag(obj,
LV_OBJ_FLAG_GESTURE_BUBBLE).
Note that, gestures are not triggered if an object is being scrolled.
If you did some action on a gesture you can call lv_indev_wait_release(lv_indev_get_act()) in the
event handler to prevent LVGL sending further input device related events.
You can fully control the user interface without a touchpad or mouse by using a keypad or encoder(s). It works similar to
the TAB key on the PC to select an element in an application or a web page.
Groups
Objects you want to control with a keypad or encoder need to be added to a Group. In every group there is exactly one
focused object which receives the pressed keys or the encoder actions. For example, if a Text area is focused and you
press some letter on a keyboard, the keys will be sent and inserted into the text area. Similarly, if a Slider is focused and
you press the left or right arrows, the slider's value will be changed.
You need to associate an input device with a group. An input device can send key events to only one group but a group
can receive data from more than one input device.
To create a group use lv_group_t * g = lv_group_create() and to add an object to the group use
lv_group_add_obj(g, obj).
To associate a group with an input device use lv_indev_set_group(indev, g), where indev is the return
value of lv_indev_drv_register()
Keys
Since a keypad has plenty of keys, it's easy to navigate between objects and edit them using the keypad. But encoders
have a limited number of "keys" and hence it is difficult to navigate using the default options. Navigate and Edit modes
are used to avoid this problem with encoders.
In Navigate mode, an encoder's LV_KEY_LEFT/RIGHT is translated to LV_KEY_NEXT/PREV. Therefore, the next
or previous object will be selected by turning the encoder. Pressing LV_KEY_ENTER will change to Edit mode.
In Edit mode, LV_KEY_NEXT/PREV is usually used to modify an object. Depending on the object's type, a short or
long press of LV_KEY_ENTER changes back to Navigate mode. Usually, an object which cannot be pressed (like a
Slider) leaves Edit mode upon a short click. But with objects where a short click has meaning (e.g. Button), a long press
is required.
Default group
Interactive widgets - such as buttons, checkboxes, sliders, etc. - can be automatically added to a default group.
Just create a group with lv_group_t * g = lv_group_create(); and set the default group with
lv_group_set_default(g);
Don't forget to assign one or more input devices to the default group with lv_indev_set_group(my_indev,
g);.
Styling
If an object is focused either by clicking it via touchpad or focused via an encoder or keypad it goes to the
LV_STATE_FOCUSED state. Hence, focused styles will be applied to it.
If an object switches to edit mode it enters the LV_STATE_FOCUSED | LV_STATE_EDITED states so these style
properties will be shown.
For a more detailed description read the Style section.
5.8.3 API
Input device
Functions
Groups
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_KEY_UP
enumerator LV_KEY_DOWN
enumerator LV_KEY_RIGHT
enumerator LV_KEY_LEFT
enumerator LV_KEY_ESC
enumerator LV_KEY_DEL
enumerator LV_KEY_BACKSPACE
enumerator LV_KEY_ENTER
enumerator LV_KEY_NEXT
enumerator LV_KEY_PREV
enumerator LV_KEY_HOME
enumerator LV_KEY_END
enum lv_group_refocus_policy_t
Values:
enumerator LV_GROUP_REFOCUS_POLICY_NEXT
enumerator LV_GROUP_REFOCUS_POLICY_PREV
Functions
void _lv_group_init(void)
Init. the group module
Remark Internal function, do not call directly.
lv_group_t *lv_group_create(void)
Create a new object group
Returns pointer to the new object group
void lv_group_del(lv_group_t *group)
Delete a group object
Parameters group -- pointer to a group
void lv_group_set_default(lv_group_t *group)
Set a default group. New object are added to this group if it's enabled in their class with add_to_def_group
= true
Parameters group -- pointer to a group (can be NULL)
lv_group_t *lv_group_get_default(void)
Get the default group
Returns pointer to the default group
void lv_group_add_obj(lv_group_t *group, struct _lv_obj_t *obj)
Add an object to a group
Parameters
• group -- pointer to a group
• obj -- pointer to an object to add
void lv_group_swap_obj(struct _lv_obj_t *obj1, struct _lv_obj_t *obj2)
Swap 2 object in a group. The object must be in the same group
Parameters
• obj1 -- pointer to an object
• obj2 -- pointer to an other object
void lv_group_remove_obj(struct _lv_obj_t *obj)
Remove an object from its group
Parameters obj -- pointer to an object to remove
void lv_group_remove_all_objs(lv_group_t *group)
Remove all objects from a group
Parameters group -- pointer to a group
void lv_group_focus_obj(struct _lv_obj_t *obj)
Focus on an object (defocus the current)
Parameters obj -- pointer to an object to focus on
struct _lv_group_t
#include <lv_group.h> Groups can be used to logically hold objects so that they can be individually focused. They
are NOT for laying out objects on a screen (try layouts for that).
Public Members
lv_ll_t obj_ll
Linked list to store the objects in the group
lv_group_focus_cb_t focus_cb
A function to call when a new object is focused (optional)
lv_group_edge_cb_t edge_cb
A function to call when an edge is reached, no more focus targets are available in this direction (to allow edge
feedback like a sound or a scroll bounce)
void *user_data
uint8_t frozen
1: can't focus to new object
uint8_t editing
1: Edit mode, 0: Navigate mode
uint8_t refocus_policy
1: Focus prev if focused on deletion. 0: Focus next if focused on deletion.
uint8_t wrap
1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end of list.
5.9 Displays
Important: The basic concept of a display in LVGL is explained in the [Porting](/porting/display) section. So before
reading further, please read the [Porting](/porting/display) section first.
In LVGL you can have multiple displays, each with their own driver and objects. The only limitation is that every display
needs to have the same color depth (as defined in LV_COLOR_DEPTH). If the displays are different in this regard the
rendered image can be converted to the correct format in the drivers flush_cb.
Creating more displays is easy: just initialize more display buffers and register another driver for every display. When
you create the UI, use lv_disp_set_default(disp) to tell the library on which display to create objects.
Why would you want multi-display support? Here are some examples:
• Have a "normal" TFT display with local UI and create "virtual" screens on VNC on demand. (You need to add
your VNC driver).
• Have a large TFT display and a small monochrome display.
• Have some smaller and simple displays in a large instrument or technology.
• Have two large TFT displays: one for a customer and one for the shop assistant.
Using more displays can be useful but in most cases it's not required. Therefore, the whole concept of multi-display
handling is completely hidden if you register only one display. By default, the last created (and only) display is used.
lv_scr_act(), lv_scr_load(scr), lv_layer_top(), lv_layer_sys(), LV_HOR_RES and
LV_VER_RES are always applied on the most recently created (default) display. If you pass NULL as disp parameter
to display related functions the default display will usually be used. E.g. lv_disp_trig_activity(NULL) will
trigger a user activity on the default display. (See below in Inactivity).
Mirror display
To mirror the image of a display to another display, you don't need to use multi-display support. Just transfer the buffer
received in drv.flush_cb to the other display too.
Split image
You can create a larger virtual display from an array of smaller ones. You can create it as below:
1. Set the resolution of the displays to the large display's resolution.
2. In drv.flush_cb, truncate and modify the area parameter for each display.
3. Send the buffer's content to each real display with the truncated area.
5.9.2 Screens
Every display has its own set of screens and the objects on each screen.
Be sure not to confuse displays and screens:
• Displays are the physical hardware drawing the pixels.
• Screens are the high-level root objects associated with a particular display. One display can have multiple screens
associated with it, but not vice versa.
Screens can be considered the highest level containers which have no parent. A screen's size is always equal to its
display and their origin is (0;0). Therefore, a screen's coordinates can't be changed, i.e. lv_obj_set_pos(),
lv_obj_set_size() or similar functions can't be used on screens.
A screen can be created from any object type but the two most typical types are Base object and Image (to create a
wallpaper).
To create a screen, use lv_obj_t * scr = lv_<type>_create(NULL, copy). copy can be an existing
screen copied into the new screen.
To load a screen, use lv_scr_load(scr). To get the active screen, use lv_scr_act(). These functions work
on the default display. If you want to specify which display to work on, use lv_disp_get_scr_act(disp) and
lv_disp_load_scr(disp, scr). A screen can be loaded with animations too. Read more here.
Screens can be deleted with lv_obj_del(scr), but ensure that you do not delete the currently loaded screen.
Transparent screens
Usually, the opacity of the screen is LV_OPA_COVER to provide a solid background for its children. If this is not the
case (opacity < 100%) the display's background color or image will be visible. See the Display background section for
more details. If the display's background opacity is also not LV_OPA_COVER LVGL has no solid background to draw.
This configuration (transparent screen and display) could be used to create for example OSD menus where a video is
played on a lower layer, and a menu is overlayed on an upper layer.
To handle transparent displays, special (slower) color mixing algorithms need to be used by LVGL so this feature needs
to enabled with LV_COLOR_SCREEN_TRANSP in lv_conf.h. The Alpha channel of 32-bit colors will be 0 where
there are no objects and 255 where there are solid objects.
In summary, to enable transparent screens and displays for OSD menu-like UIs:
• Enable LV_COLOR_SCREEN_TRANSP in lv_conf.h
• Set the screen's opacity to LV_OPA_TRANSP e.g. with lv_obj_set_style_bg_opa(lv_scr_act(),
LV_OPA_TRANSP, LV_PART_MAIN)
• Set the display opacity to LV_OPA_TRANSP with lv_disp_set_bg_opa(NULL, LV_OPA_TRANSP);
Inactivity
A user's inactivity time is measured on each display. Every use of an Input device (if associated with the display) counts
as an activity. To get time elapsed since the last activity, use lv_disp_get_inactive_time(disp). If NULL is
passed, the lowest inactivity time among all displays will be returned (NULL isn't just the default display).
You can manually trigger an activity using lv_disp_trig_activity(disp). If disp is NULL, the default screen
will be used (and not all displays).
Background
Every display has a background color, background image and background opacity properties. They become visible when
the current screen is transparent or not positioned to cover the whole display.
The background color is a simple color to fill the display. It can be adjusted with lv_disp_set_bg_color(disp,
color);
The display background image is a path to a file or a pointer to an lv_img_dsc_t variable (converted image data) to
be used as wallpaper. It can be set with lv_disp_set_bg_image(disp, &my_img); If a background image is
configured the background won't be filled with bg_color.
The opacity of the background color or image can be adjusted with lv_disp_set_bg_opa(disp, opa).
The disp parameter of these functions can be NULL to select the default display.
5.9.4 API
Enums
enum lv_scr_load_anim_t
Values:
enumerator LV_SCR_LOAD_ANIM_NONE
enumerator LV_SCR_LOAD_ANIM_OVER_LEFT
enumerator LV_SCR_LOAD_ANIM_OVER_RIGHT
enumerator LV_SCR_LOAD_ANIM_OVER_TOP
enumerator LV_SCR_LOAD_ANIM_OVER_BOTTOM
enumerator LV_SCR_LOAD_ANIM_MOVE_LEFT
enumerator LV_SCR_LOAD_ANIM_MOVE_RIGHT
enumerator LV_SCR_LOAD_ANIM_MOVE_TOP
enumerator LV_SCR_LOAD_ANIM_MOVE_BOTTOM
enumerator LV_SCR_LOAD_ANIM_FADE_IN
enumerator LV_SCR_LOAD_ANIM_FADE_ON
enumerator LV_SCR_LOAD_ANIM_FADE_OUT
enumerator LV_SCR_LOAD_ANIM_OUT_LEFT
enumerator LV_SCR_LOAD_ANIM_OUT_RIGHT
enumerator LV_SCR_LOAD_ANIM_OUT_TOP
enumerator LV_SCR_LOAD_ANIM_OUT_BOTTOM
Functions
5.10 Colors
The color module handles all color-related functions like changing color depth, creating colors from hex code, converting
between color depths, mixing colors, etc.
The type lv_color_t is used to store a color. Its fields are set according to LV_COLOR_DEPTH in lv_conf.h.
(See below)
You may set LV_COLOR_16_SWAP in lv_conf.h to swap bytes of RGB565 colors. You may need this when sending
16-bit colors via a byte-oriented interface like SPI. As 16-bit numbers are stored in little-endian format (lower byte at
the lower address), the interface will send the lower byte first. However, displays usually need the higher byte first. A
mismatch in the byte order will result in highly distorted colors.
RGB
HSV
Palette
LVGL includes Material Design's palette of colors. In this system all named colors have a nominal main color as well as
four darker and five lighter variants.
The names of the colors are as follows:
• LV_PALETTE_RED
• LV_PALETTE_PINK
• LV_PALETTE_PURPLE
• LV_PALETTE_DEEP_PURPLE
• LV_PALETTE_INDIGO
• LV_PALETTE_BLUE
• LV_PALETTE_LIGHT_BLUE
• LV_PALETTE_CYAN
• LV_PALETTE_TEAL
• LV_PALETTE_GREEN
• LV_PALETTE_LIGHT_GREEN
• LV_PALETTE_LIME
• LV_PALETTE_YELLOW
• LV_PALETTE_AMBER
• LV_PALETTE_ORANGE
• LV_PALETTE_DEEP_ORANGE
• LV_PALETTE_BROWN
• LV_PALETTE_BLUE_GREY
• LV_PALETTE_GREY
To get the main color use lv_color_t c = lv_palette_main(LV_PALETTE_...).
For the lighter variants of a palette color use lv_color_t c = lv_palette_lighten(LV_PALETTE_.
.., v). v can be 1..5. For the darker variants of a palette color use lv_color_t c =
lv_palette_darken(LV_PALETTE_..., v). v can be 1..4.
// Mix two colors with a given ratio 0: full c2, 255: full c1, 128: half c1 and half␣
,→c2
Built-in colors
5.10.2 Opacity
To describe opacity the lv_opa_t type is created from uint8_t. Some special purpose defines are also introduced:
• LV_OPA_TRANSP Value: 0, means no opacity making the color completely transparent
• LV_OPA_10 Value: 25, means the color covers only a little
• LV_OPA_20 ... OPA_80 follow logically
• LV_OPA_90 Value: 229, means the color near completely covers
• LV_OPA_COVER Value: 255, means the color completely covers (full opacity)
You can also use the LV_OPA_* defines in lv_color_mix() as a mixing ratio.
Convert color
You can convert a color from the current color depth to another. The converter functions return with a number, so you
have to use the full field to map a converted color back into a structure:
lv_color_t c;
c.red = 0x38;
c.green = 0x70;
c.blue = 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_color32_t c24;
c32.full = lv_color_to32(c); /*Give a 32 bit number with the converted color*/
5.10.4 API
Typedefs
Enums
enum [anonymous]
Opacity percentages.
Values:
enumerator LV_OPA_TRANSP
enumerator LV_OPA_0
enumerator LV_OPA_10
enumerator LV_OPA_20
enumerator LV_OPA_30
enumerator LV_OPA_40
enumerator LV_OPA_50
enumerator LV_OPA_60
enumerator LV_OPA_70
enumerator LV_OPA_80
enumerator LV_OPA_90
enumerator LV_OPA_100
enumerator LV_OPA_COVER
enum lv_palette_t
Values:
enumerator LV_PALETTE_RED
enumerator LV_PALETTE_PINK
enumerator LV_PALETTE_PURPLE
enumerator LV_PALETTE_DEEP_PURPLE
enumerator LV_PALETTE_INDIGO
enumerator LV_PALETTE_BLUE
enumerator LV_PALETTE_LIGHT_BLUE
enumerator LV_PALETTE_CYAN
enumerator LV_PALETTE_TEAL
enumerator LV_PALETTE_GREEN
enumerator LV_PALETTE_LIGHT_GREEN
enumerator LV_PALETTE_LIME
enumerator LV_PALETTE_YELLOW
enumerator LV_PALETTE_AMBER
enumerator LV_PALETTE_ORANGE
enumerator LV_PALETTE_DEEP_ORANGE
enumerator LV_PALETTE_BROWN
enumerator LV_PALETTE_BLUE_GREY
enumerator LV_PALETTE_GREY
enumerator _LV_PALETTE_LAST
enumerator LV_PALETTE_NONE
Functions
LV_EXPORT_CONST_INT(LV_COLOR_DEPTH)
LV_EXPORT_CONST_INT(LV_COLOR_16_SWAP)
union lv_color1_t
Public Members
uint8_t full
uint8_t blue
uint8_t green
uint8_t red
union lv_color1_t::[anonymous] ch
union lv_color8_t
Public Members
uint8_t blue
uint8_t green
uint8_t red
struct lv_color8_t::[anonymous] ch
uint8_t full
union lv_color16_t
Public Members
uint16_t blue
uint16_t green
uint16_t red
uint16_t green_h
uint16_t green_l
struct lv_color16_t::[anonymous] ch
uint16_t full
union lv_color32_t
Public Members
uint8_t blue
uint8_t green
uint8_t red
uint8_t alpha
struct lv_color32_t::[anonymous] ch
uint32_t full
struct lv_color_hsv_t
Public Members
uint16_t h
uint8_t s
uint8_t v
struct _lv_color_filter_dsc_t
Public Members
lv_color_filter_cb_t filter_cb
void *user_data
5.11 Fonts
In LVGL fonts are collections of bitmaps and other information required to render images of individual letters (glyph).
A font is stored in a lv_font_t variable and can be set in a style's text_font field. For example:
Fonts have a bpp (bits per pixel) property. It shows how many bits are used to describe a pixel in a font. The value
stored for a pixel determines the pixel's opacity. This way, with higher bpp, the edges of the letter can be smoother. The
possible bpp values are 1, 2, 4 and 8 (higher values mean better quality).
The bpp property also affects the amount of memory needed to store a font. For example, bpp = 4 makes a font nearly
four times larger compared to bpp = 1.
LVGL supports UTF-8 encoded Unicode characters. Your editor needs to be configured to save your code/text as UTF-8
(usually this the default) and be sure that, LV_TXT_ENC is set to LV_TXT_ENC_UTF8 in lv_conf.h. (This is the default
value)
To test it try
There are several built-in fonts in different sizes, which can be enabled in lv_conf.h with LV_FONT_... defines.
Normal fonts
Containing all the ASCII characters, the degree symbol (U+00B0), the bullet symbol (U+2022) and the built-in symbols
(see below).
• LV_FONT_MONTSERRAT_12 12 px font
• LV_FONT_MONTSERRAT_14 14 px font
• LV_FONT_MONTSERRAT_16 16 px font
• LV_FONT_MONTSERRAT_18 18 px font
• LV_FONT_MONTSERRAT_20 20 px font
• LV_FONT_MONTSERRAT_22 22 px font
• LV_FONT_MONTSERRAT_24 24 px font
• LV_FONT_MONTSERRAT_26 26 px font
• LV_FONT_MONTSERRAT_28 28 px font
• LV_FONT_MONTSERRAT_30 30 px font
• LV_FONT_MONTSERRAT_32 32 px font
• LV_FONT_MONTSERRAT_34 34 px font
• LV_FONT_MONTSERRAT_36 36 px font
• LV_FONT_MONTSERRAT_38 38 px font
• LV_FONT_MONTSERRAT_40 40 px font
• LV_FONT_MONTSERRAT_42 42 px font
• LV_FONT_MONTSERRAT_44 44 px font
• LV_FONT_MONTSERRAT_46 46 px font
• LV_FONT_MONTSERRAT_48 48 px font
Special fonts
The built-in fonts are global variables with names like lv_font_montserrat_16 for a 16 px height font. To use
them in a style, just add a pointer to a font variable like shown above.
The built-in fonts with bpp = 4 contain the ASCII characters and use the Montserrat font.
In addition to the ASCII range, the following symbols are also added to the built-in fonts from the FontAwesome font.
lv_label_set_text(my_label, LV_SYMBOL_OK);
Bidirectional support
Most languages use a Left-to-Right (LTR for short) writing direction, however some languages (such as Hebrew, Persian
or Arabic) use Right-to-Left (RTL for short) direction.
LVGL not only supports RTL texts but supports mixed (a.k.a. bidirectional, BiDi) text rendering too. Some examples:
There are some special rules to display Arabic and Persian characters: the form of a character depends on its position in
the text. A different form of the same letter needs to be used when it is isolated, at start, middle or end positions. Besides
these, some conjunction rules should also be taken into account.
LVGL supports these rules if LV_USE_ARABIC_PERSIAN_CHARS is enabled.
However, there are some limitations:
• Only displaying text is supported (e.g. on labels), text inputs (e.g. text area) don't support this feature.
• Static text (i.e. const) is not processed. E.g. texts set by lv_label_set_text() will be "Arabic processed"
but lv_lable_set_text_static() won't.
• Text get functions (e.g. lv_label_get_text()) will return the processed text.
Subpixel rendering
Subpixel rendering allows for tripling the horizontal resolution by rendering anti-aliased edges on Red, Green and Blue
channels instead of at pixel level granularity. This takes advantage of the position of physical color channels of each pixel,
resulting in higher quality letter anti-aliasing. Learn more here.
For subpixel rendering, the fonts need to be generated with special settings:
• In the online converter tick the Subpixel box
• In the command line tool use --lcd flag. Note that the generated font needs about three times more memory.
Subpixel rendering works only if the color channels of the pixels have a horizontal layout. That is the R, G, B channels
are next to each other and not above each other. The order of color channels also needs to match with the library settings.
By default, LVGL assumes RGB order, however this can be swapped by setting LV_SUBPX_BGR 1 in lv_conf.h.
Compressed fonts
lv_font_load can be used to load a font from a file. The font needs to have a special binary format. (Not TTF or
WOFF). Use lv_font_conv with the --format bin option to generate an LVGL compatible font file.
Note that to load a font LVGL's filesystem needs to be enabled and a driver must be added.
Example
lv_font_t * my_font;
my_font = lv_font_load(X/path/to/my_font.bin);
LVGL's font interface is designed to be very flexible but, even so, you can add your own font engine in place of LVGL's
internal one. For example, you can use FreeType to real-time render glyphs from TTF fonts or use an external flash to
store the font's bitmap and read them when the library needs them.
A ready to use FreeType can be found in lv_freetype repository.
To do this, a custom lv_font_t variable needs to be created:
...
*/
bool my_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out,␣
,→uint32_t unicode_letter, uint32_t unicode_letter_next)
{
/*Your code here*/
return true; /*true: glyph found; false: glyph was not found*/
}
{
/* Your code here */
You can specify fallback in lv_font_t to provide fallback to the font. When the font fails to find glyph to a letter,
it will try to let font from fallback to handle.
fallback can be chained, so it will try to solve until there is no fallback set.
roboto->fallback = droid_sans_fallback;
5.12 Images
An image can be a file or a variable which stores the bitmap itself and some metadata.
Variables
Images stored internally in a variable are composed mainly of an lv_img_dsc_t structure with the following fields:
• header
– cf Color format. See below
– w width in pixels (<= 2048)
– h height in pixels (<= 2048)
– always zero 3 bits which need to be always zero
Files
To deal with files you need to add a storage Drive to LVGL. In short, a Drive is a collection of functions (open, read, close,
etc.) registered in LVGL to make file operations. You can add an interface to a standard file system (FAT32 on SD card)
or you create your simple file system to read data from an SPI Flash memory. In every case, a Drive is just an abstraction
to read and/or write data to memory. See the File system section to learn more.
Images stored as files are not linked into the resulting executable, and must be read into RAM before being drawn. As
a result, they are not as resource-friendly as images linked at compile time. However, they are easier to replace without
needing to rebuild the main program.
Online converter
If you are generating an image at run-time, you can craft an image variable to display it using LVGL. For example:
uint8_t my_img_data[] = {0x00, 0x01, 0x02, ...};
Use images
The simplest way to use an image in LVGL is to display it with an lv_img object:
lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
/*From variable*/
lv_img_set_src(icon, &my_icon_dsc);
/*From file*/
lv_img_set_src(icon, "S:my_icon.bin");
If the image was converted with the online converter, you should use LV_IMG_DECLARE(my_icon_dsc) to declare
the image in the file where you want to use it.
As you can see in the Color formats section, LVGL supports several built-in image formats. In many cases, these will be
all you need. LVGL doesn't directly support, however, generic image formats like PNG or JPG.
To handle non-built-in image formats, you need to use external libraries and attach them to LVGL via the Image decoder
interface.
An image decoder consists of 4 callbacks:
• info get some basic info about the image (width, height and color format).
• open open an image: either store a decoded image or set it to NULL to indicate the image can be read line-by-line.
• read if open didn't fully open an image this function should give some decoded data (max 1 line) from a given
position.
• close close an opened image, free the allocated resources.
You can add any number of image decoders. When an image needs to be drawn, the library will try all the registered
image decoders until it finds one which can open the image, i.e. one which knows that format.
The LV_IMG_CF_TRUE_COLOR_..., LV_IMG_INDEXED_... and LV_IMG_ALPHA_... formats (essentially,
all non-RAW formats) are understood by the built-in decoder.
The easiest way to create a custom image is to use the online image converter and select Raw, Raw with alpha or
Raw with chroma-keyed format. It will just take every byte of the binary file you uploaded and write it as an
image "bitmap". You then need to attach an image decoder that will parse that bitmap and generate the real, renderable
bitmap.
header.cf will be LV_IMG_CF_RAW, LV_IMG_CF_RAW_ALPHA or LV_IMG_CF_RAW_CHROMA_KEYED ac-
cordingly. You should choose the correct format according to your needs: a fully opaque image, using an alpha channel
or using a chroma key.
After decoding, the raw formats are considered True color by the library. In other words, the image decoder must decode
the Raw images to True color according to the format described in the Color formats section.
If you want to create a custom image, you should use LV_IMG_CF_USER_ENCODED_0..7 color formats. However,
the library can draw images only in True color format (or Raw but ultimately it will be in True color format). The
LV_IMG_CF_USER_ENCODED_... formats are not known by the library and therefore they should be decoded to
one of the known formats from the Color formats section. It's possible to decode an image to a non-true color format first
(for example: LV_IMG_INDEXED_4BITS) and then call the built-in decoder functions to convert it to True color.
With User encoded formats, the color format in the open function (dsc->header.cf) should be changed according
to the new format.
/**
* Get info about a PNG image
* @param decoder pointer to the decoder where this function belongs
* @param src can be file name or pointer to a C array
* @param header store the info here
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
*/
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_
,→header_t * header)
{
/*Check whether the type `src` is known by the decoder*/
if(is_png(src) == false) return LV_RES_INV;
header->cf = LV_IMG_CF_RAW_ALPHA;
header->w = width;
header->h = height;
}
/*Change the color format if required. For PNG usually 'Raw' is fine*/
dsc->header.cf = LV_IMG_CF_...
return res;
}
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in␣
,→`buf`.
* Required only if the "open" function can't open the whole decoded pixel array.␣
,→(dsc->img_data == NULL)
{
/*With PNG it's usually not required*/
/*Copy `len` pixels from `x` and `y` coordinates in True color format to `buf` */
/**
* Free the allocated resources
* @param decoder pointer to the decoder where this function belongs
* @param dsc pointer to a descriptor which describes this decoding session
*/
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(continues on next page)
/*Call the built-in close function if the built-in open/read_line was used*/
lv_img_decoder_built_in_close(decoder, dsc);
So in summary:
• In decoder_info, you should collect some basic information about the image and store it in header.
• In decoder_open, you should try to open the image source pointed by dsc->src. Its type is already in
dsc->src_type == LV_IMG_SRC_FILE/VARIABLE. If this format/type is not supported by the decoder,
return LV_RES_INV. However, if you can open the image, a pointer to the decoded True color image should be
set in dsc->img_data. If the format is known, but you don't want to decode the entire image (e.g. no memory
for it), set dsc->img_data = NULL and use read_line to get the pixel data.
• In decoder_close you should free all allocated resources.
• decoder_read is optional. Decoding the whole image requires extra memory and some computational over-
head. However, it can decode one line of the image without decoding the whole image, you can save memory and
time. To indicate that the line read function should be used, set dsc->img_data = NULL in the open function.
LVGL will use registered image decoders automatically if you try and draw a raw image (i.e. using the lv_img object)
but you can use them manually too. Create an lv_img_decoder_dsc_t variable to describe the decoding session
and call lv_img_decoder_open().
The color parameter is used only with LV_IMG_CF_ALPHA_1/2/4/8BIT images to tell color of the image.
frame_id can be used if the image to open is an animation.
lv_res_t res;
lv_img_decoder_dsc_t dsc;
res = lv_img_decoder_open(&dsc, &my_img_dsc, color, frame_id);
if(res == LV_RES_OK) {
/*Do something with `dsc->img_data`*/
lv_img_decoder_close(&dsc);
}
Sometimes it takes a lot of time to open an image. Continuously decoding a PNG image or loading images from a slow
external memory would be inefficient and detrimental to the user experience.
Therefore, LVGL caches a given number of images. Caching means some images will be left open, hence LVGL can
quickly access them from dsc->img_data instead of needing to decode them again.
Of course, caching images is resource intensive as it uses more RAM to store the decoded image. LVGL tries to optimize
the process as much as possible (see below), but you will still need to evaluate if this would be beneficial for your platform
or not. Image caching may not be worth it if you have a deeply embedded target which decodes small images from a
relatively fast storage medium.
Cache size
The number of cache entries can be defined with LV_IMG_CACHE_DEF_SIZE in lv_conf.h. The default value is 1 so
only the most recently used image will be left open.
The size of the cache can be changed at run-time with lv_img_cache_set_size(entry_num).
Value of images
When you use more images than cache entries, LVGL can't cache all the images. Instead, the library will close one of the
cached images to free space.
To decide which image to close, LVGL uses a measurement it previously made of how long it took to open the image.
Cache entries that hold slower-to-open images are considered more valuable and are kept in the cache as long as possible.
If you want or need to override LVGL's measurement, you can manually set the time to open value in the decoder open
function in dsc->time_to_open = time_ms to give a higher or lower value. (Leave it unchanged to let LVGL
control it.)
Every cache entry has a "life" value. Every time an image is opened through the cache, the life value of all entries is
decreased to make them older. When a cached image is used, its life value is increased by the time to open value to make
it more alive.
If there is no more space in the cache, the entry with the lowest life value will be closed.
Memory usage
Note that a cached image might continuously consume memory. For example, if three PNG images are cached, they will
consume memory while they are open.
Therefore, it's the user's responsibility to be sure there is enough RAM to cache even the largest images at the same time.
Let's say you have loaded a PNG image into a lv_img_dsc_t my_png variable and use it in an lv_img object. If
the image is already cached and you then change the underlying PNG file, you need to notify LVGL to cache the image
again. Otherwise, there is no easy way of detecting that the underlying file changed and LVGL will still draw the old
image from cache.
To do this, use lv_img_cache_invalidate_src(&my_png). If NULL is passed as a parameter, the whole
cache will be cleaned.
5.12.6 API
Image buffer
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_IMG_CF_UNKNOWN
enumerator LV_IMG_CF_RAW
Contains the file as it is. Needs custom decoder function
enumerator LV_IMG_CF_RAW_ALPHA
Contains the file as it is. The image has alpha. Needs custom decoder function
enumerator LV_IMG_CF_RAW_CHROMA_KEYED
Contains the file as it is. The image is chroma keyed. Needs custom decoder function
enumerator LV_IMG_CF_TRUE_COLOR
Color format and depth should match with LV_COLOR settings
enumerator LV_IMG_CF_TRUE_COLOR_ALPHA
Same as LV_IMG_CF_TRUE_COLOR but every pixel has an alpha byte
enumerator LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED
Same as LV_IMG_CF_TRUE_COLOR but LV_COLOR_TRANSP pixels will be transparent
enumerator LV_IMG_CF_INDEXED_1BIT
Can have 2 different colors in a palette (can't be chroma keyed)
enumerator LV_IMG_CF_INDEXED_2BIT
Can have 4 different colors in a palette (can't be chroma keyed)
enumerator LV_IMG_CF_INDEXED_4BIT
Can have 16 different colors in a palette (can't be chroma keyed)
enumerator LV_IMG_CF_INDEXED_8BIT
Can have 256 different colors in a palette (can't be chroma keyed)
enumerator LV_IMG_CF_ALPHA_1BIT
Can have one color and it can be drawn or not
enumerator LV_IMG_CF_ALPHA_2BIT
Can have one color but 4 different alpha value
enumerator LV_IMG_CF_ALPHA_4BIT
Can have one color but 16 different alpha value
enumerator LV_IMG_CF_ALPHA_8BIT
Can have one color but 256 different alpha value
enumerator LV_IMG_CF_RGB888
enumerator LV_IMG_CF_RGBA8888
enumerator LV_IMG_CF_RGBX8888
enumerator LV_IMG_CF_RGB565
enumerator LV_IMG_CF_RGBA5658
enumerator LV_IMG_CF_RGB565A8
enumerator LV_IMG_CF_RESERVED_15
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_16
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_17
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_18
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_19
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_20
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_21
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_22
Reserved for further use.
enumerator LV_IMG_CF_RESERVED_23
Reserved for further use.
enumerator LV_IMG_CF_USER_ENCODED_0
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_1
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_2
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_3
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_4
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_5
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_6
User holder encoding format.
enumerator LV_IMG_CF_USER_ENCODED_7
User holder encoding format.
Functions
struct lv_img_header_t
#include <lv_img_buf.h> The first 8 bit is very important to distinguish the different source types. For more info
see lv_img_get_src_type() in lv_img.c On big endian systems the order is reversed so cf and always_zero
must be at the end of the struct.
Public Members
uint32_t h
uint32_t w
uint32_t reserved
uint32_t always_zero
uint32_t cf
struct lv_img_dsc_t
#include <lv_img_buf.h> Image header it is compatible with the result from image converter utility
Public Members
lv_img_header_t header
A header describing the basics of the image
uint32_t data_size
Size of the image in bytes
LVGL has a 'File system' abstraction module that enables you to attach any type of file system. A file system is identified
by an assigned drive letter. For example, if an SD card is associated with the letter 'S', a file can be reached using
"S:path/to/file.txt".
The lv_fs_if repository contains prepared drivers using POSIX, standard C and the FATFS API. See its README for
the details.
Registering a driver
To add a driver, a lv_fs_drv_t needs to be initialized like below. The lv_fs_drv_t needs to be static, global or
dynamically allocated and not a local variable.
Any of the callbacks can be NULL to indicate that operation is not supported.
Open callback
path is the path after the drive letter (e.g. "S:path/to/file.txt" -> "path/to/file.txt"). mode can be LV_FS_MODE_WR or
LV_FS_MODE_RD to open for writes or reads.
The return value is a pointer to a file object that describes the opened file or NULL if there were any issues (e.g. the file
wasn't found). The returned file object will be passed to other file system related callbacks. (see below)
Other callbacks
The other callbacks are quite similar. For example write_cb looks like this:
For file_p, LVGL passes the return value of open_cb, buf is the data to write, btw is the Bytes To Write, bw is
the actually written bytes.
For a template of these callbacks see lv_fs_template.c.
lv_fs_file_t f;
lv_fs_res_t res;
res = lv_fs_open(&f, "S:folder/file.txt", LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) my_error_handling();
uint32_t read_num;
uint8_t buf[8];
res = lv_fs_read(&f, buf, 8, &read_num);
if(res != LV_FS_RES_OK || read_num != 8) my_error_handling();
lv_fs_close(&f);
The mode in lv_fs_open can be LV_FS_MODE_WR to open for writes only or LV_FS_MODE_RD |
LV_FS_MODE_WR for both
This example shows how to read a directory's content. It's up to the driver how to mark directories in the result but it can
be a good practice to insert a '/' in front of each directory name.
lv_fs_dir_t dir;
lv_fs_res_t res;
res = lv_fs_dir_open(&dir, "S:/folder");
if(res != LV_FS_RES_OK) my_error_handling();
char fn[256];
while(1) {
res = lv_fs_dir_read(&dir, fn);
if(res != LV_FS_RES_OK) {
my_error_handling();
break;
}
printf("%s\n", fn);
}
lv_fs_dir_close(&dir);
Image objects can be opened from files too (besides variables stored in the compiled program).
To use files in image widgets the following callbacks are required:
• open
• close
• read
• seek
• tell
5.13.5 API
Typedefs
Enums
enum [anonymous]
Errors in the file system module.
Values:
enumerator LV_FS_RES_OK
enumerator LV_FS_RES_HW_ERR
enumerator LV_FS_RES_FS_ERR
enumerator LV_FS_RES_NOT_EX
enumerator LV_FS_RES_FULL
enumerator LV_FS_RES_LOCKED
enumerator LV_FS_RES_DENIED
enumerator LV_FS_RES_BUSY
enumerator LV_FS_RES_TOUT
enumerator LV_FS_RES_NOT_IMP
enumerator LV_FS_RES_OUT_OF_MEM
enumerator LV_FS_RES_INV_PARAM
enumerator LV_FS_RES_UNKNOWN
enum [anonymous]
File open mode.
Values:
enumerator LV_FS_MODE_WR
enumerator LV_FS_MODE_RD
enum lv_fs_whence_t
Seek modes.
Values:
enumerator LV_FS_SEEK_SET
Set the position from absolutely (from the start of file)
enumerator LV_FS_SEEK_CUR
Set the position from the current position
enumerator LV_FS_SEEK_END
Set the position from the end of the file
Functions
void _lv_fs_init(void)
Initialize the File system interface
void lv_fs_drv_init(lv_fs_drv_t *drv)
Initialize a file system driver with default values. It is used to surly have known values in the fields ant not memory
junk. After it you can set the fields.
Parameters drv -- pointer to driver variable to initialize
void lv_fs_drv_register(lv_fs_drv_t *drv)
Add a new drive
Parameters drv -- pointer to an lv_fs_drv_t structure which is inited with the corresponding function
pointers. Only pointer is saved, so the driver should be static or dynamically allocated.
lv_fs_drv_t *lv_fs_get_drv(char letter)
Give a pointer to a driver from its letter
Parameters letter -- the driver letter
Returns pointer to a driver or NULL if not found
bool lv_fs_is_ready(char letter)
Test if a drive is ready or not. If the ready function was not initialized true will be returned.
Parameters letter -- letter of the drive
Returns true: drive is ready; false: drive is not ready
lv_fs_res_t lv_fs_open(lv_fs_file_t *file_p, const char *path, lv_fs_mode_t mode)
Open a file
Parameters
• file_p -- pointer to a lv_fs_file_t variable
• path -- path to the file beginning with the driver letter (e.g. S:/folder/file.txt)
• mode -- read: FS_MODE_RD, write: FS_MODE_WR, both: FS_MODE_RD |
FS_MODE_WR
Returns LV_FS_RES_OK or any error from lv_fs_res_t enum
lv_fs_res_t lv_fs_close(lv_fs_file_t *file_p)
Close an already opened file
Parameters file_p -- pointer to a lv_fs_file_t variable
struct _lv_fs_drv_t
Public Members
char letter
uint16_t cache_size
lv_fs_res_t (*read_cb)(struct _lv_fs_drv_t *drv, void *file_p, void *buf, uint32_t btr, uint32_t *br)
lv_fs_res_t (*write_cb)(struct _lv_fs_drv_t *drv, void *file_p, const void *buf, uint32_t btw, uint32_t *bw)
lv_fs_res_t (*seek_cb)(struct _lv_fs_drv_t *drv, void *file_p, uint32_t pos, lv_fs_whence_t whence)
void *user_data
Custom file user data
struct lv_fs_file_cache_t
Public Members
uint32_t start
uint32_t end
uint32_t file_position
void *buffer
struct lv_fs_file_t
Public Members
void *file_d
lv_fs_drv_t *drv
lv_fs_file_cache_t *cache
struct lv_fs_dir_t
Public Members
void *dir_d
lv_fs_drv_t *drv
5.14 Animations
You can automatically change the value of a variable between a start and an end value using animations. Animation will
happen by periodically calling an "animator" function with the corresponding value parameter.
The animator functions have the following prototype:
This prototype is compatible with the majority of the property set functions in LVGL. For example
lv_obj_set_x(obj, value) or lv_obj_set_width(obj, value)
To create an animation an lv_anim_t variable has to be initialized and configured with lv_anim_set_...()
functions.
/* INITIALIZE AN ANIMATION
*-----------------------*/
lv_anim_t a;
lv_anim_init(&a);
/* MANDATORY SETTINGS
*------------------*/
/* OPTIONAL SETTINGS
*------------------*/
/*When ready, play the animation backward with this duration. Default is 0 (disabled)␣
,→[ms]*/
lv_anim_set_playback_time(&a, time);
lv_anim_set_repeat_count(&a, cnt);
/*true (default): apply the start value immediately, false: apply start value after␣
,→delay when the anim. really starts. */
lv_anim_set_early_apply(&a, true/false);
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 and lv_obj_set_y. However, only one animation can exist with a given variable
and function pair and lv_anim_start() will remove any existing animations for such a pair.
You can control the path of an animation. The most simple case is linear, meaning the current value between start and
end is changed with fixed steps. A path is a function which calculates the next value to set based on the current state of
the animation. Currently, there are the following built-in path functions:
• lv_anim_path_linear linear animation
• lv_anim_path_step change in one step at the end
• lv_anim_path_ease_in slow at the beginning
• lv_anim_path_ease_out slow at the end
• lv_anim_path_ease_in_out slow at the beginning and end
• lv_anim_path_overshoot overshoot the end value
• lv_anim_path_bounce bounce back a little from the end value (like hitting a wall)
By default, you set the animation time directly. But in some cases, setting 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, lv_anim_speed_to_time(20,0,100) will yield 5000 milliseconds. For example, in the case of
lv_obj_set_x unit is pixels so 20 means 20 px/sec speed.
You can delete an animation with lv_anim_del(var, func) if you provide the animated variable and its animator
function.
5.14.5 Timeline
A timeline is a collection of multiple animations which makes it easy to create complex composite animations.
Firstly, create an animation element but don’t call lv_anim_start().
Secondly, create an animation timeline object by calling lv_anim_timeline_create().
Thirdly, add animation elements to the animation timeline by calling lv_anim_timeline_add(at,
start_time, &a). start_time is the start time of the animation on the timeline. Note that start_time
will override the value of delay.
Finally, call lv_anim_timeline_start(at) to start the animation timeline.
It supports forward and backward playback of the entire animation group, using
lv_anim_timeline_set_reverse(at, reverse).
Call lv_anim_timeline_stop(at) to stop the animation timeline.
Call lv_anim_timeline_set_progress(at, progress) function to set the state of the object correspond-
ing to the progress of the timeline.
Call lv_anim_timeline_get_playtime(at) function to get the total duration of the entire animation timeline.
Call lv_anim_timeline_get_reverse(at) function to get whether to reverse the animation timeline.
Call lv_anim_timeline_del(at) function to delete the animation timeline.
5.14.6 Examples
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
if(lv_obj_has_state(sw, LV_STATE_CHECKED)) {
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, label);
lv_anim_set_values(&a, lv_obj_get_x(label), 100);
lv_anim_set_time(&a, 500);
lv_anim_set_exec_cb(&a, anim_x_cb);
lv_anim_set_path_cb(&a, lv_anim_path_overshoot);
lv_anim_start(&a);
(continues on next page)
/**
* Start animation on an event
*/
void lv_example_anim_1(void)
{
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello animations!");
lv_obj_set_pos(label, 100, 10);
lv_obj_t * sw = lv_switch_create(lv_scr_act());
lv_obj_center(sw);
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, sw_event_cb, LV_EVENT_VALUE_CHANGED, label);
}
#endif
def sw_event_cb(e,label):
sw = e.get_target()
if sw.has_state(lv.STATE.CHECKED):
a = lv.anim_t()
a.init()
a.set_var(label)
a.set_values(label.get_x(), 100)
a.set_time(500)
a.set_path_cb(lv.anim_t.path_overshoot)
a.set_custom_exec_cb(lambda a,val: anim_x_cb(label,val))
lv.anim_t.start(a)
else:
a = lv.anim_t()
a.init()
a.set_var(label)
a.set_values(label.get_x(), -label.get_width())
a.set_time(500)
a.set_path_cb(lv.anim_t.path_ease_in)
a.set_custom_exec_cb(lambda a,val: anim_x_cb(label,val))
lv.anim_t.start(a)
label = lv.label(lv.scr_act())
label.set_text("Hello animations!")
label.set_pos(100, 10)
sw = lv.switch(lv.scr_act())
sw.center()
sw.add_state(lv.STATE.CHECKED)
sw.add_event_cb(lambda e: sw_event_cb(e,label), lv.EVENT.VALUE_CHANGED, None)
Playback animation
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_SWITCH
/**
* Create a playback animation
*/
void lv_example_anim_2(void)
{
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, obj);
lv_anim_set_values(&a, 10, 50);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_delay(&a, 100);
lv_anim_set_playback_time(&a, 300);
lv_anim_set_repeat_delay(&a, 500);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_path_cb(&a, lv_anim_path_ease_in_out);
#endif
#
# Create a playback animation
#
obj = lv.obj(lv.scr_act())
obj.set_style_bg_color(lv.palette_main(lv.PALETTE.RED), 0)
obj.set_style_radius(lv.RADIUS.CIRCLE, 0)
obj.align(lv.ALIGN.LEFT_MID, 10, 0)
a1 = lv.anim_t()
a1.init()
a1.set_var(obj)
a1.set_values(10, 50)
a1.set_time(1000)
a1.set_playback_delay(100)
a1.set_playback_time(300)
a1.set_repeat_delay(500)
a1.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a1.set_path_cb(lv.anim_t.path_ease_in_out)
a1.set_custom_exec_cb(lambda a1,val: anim_size_cb(obj,val))
lv.anim_t.start(a1)
a2 = lv.anim_t()
a2.init()
a2.set_var(obj)
a2.set_values(10, 240)
a2.set_time(1000)
a2.set_playback_delay(100)
a2.set_playback_time(300)
a2.set_repeat_delay(500)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a2.set_path_cb(lv.anim_t.path_ease_in_out)
a2.set_custom_exec_cb(lambda a1,val: anim_x_cb(obj,val))
lv.anim_t.start(a2)
Animation timeline
#include "../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
lv_anim_t a2;
lv_anim_init(&a2);
lv_anim_set_var(&a2, obj1);
lv_anim_set_values(&a2, 0, obj_height);
lv_anim_set_early_apply(&a2, false);
lv_anim_set_exec_cb(&a2, (lv_anim_exec_xcb_t)set_height);
lv_anim_set_path_cb(&a2, lv_anim_path_ease_out);
lv_anim_set_time(&a2, 300);
/* obj2 */
lv_anim_t a3;
lv_anim_init(&a3);
lv_anim_set_var(&a3, obj2);
lv_anim_set_values(&a3, 0, obj_width);
lv_anim_set_early_apply(&a3, false);
lv_anim_set_exec_cb(&a3, (lv_anim_exec_xcb_t)set_width);
lv_anim_set_path_cb(&a3, lv_anim_path_overshoot);
lv_anim_set_time(&a3, 300);
lv_anim_t a4;
lv_anim_init(&a4);
(continues on next page)
/* obj3 */
lv_anim_t a5;
lv_anim_init(&a5);
lv_anim_set_var(&a5, obj3);
lv_anim_set_values(&a5, 0, obj_width);
lv_anim_set_early_apply(&a5, false);
lv_anim_set_exec_cb(&a5, (lv_anim_exec_xcb_t)set_width);
lv_anim_set_path_cb(&a5, lv_anim_path_overshoot);
lv_anim_set_time(&a5, 300);
lv_anim_t a6;
lv_anim_init(&a6);
lv_anim_set_var(&a6, obj3);
lv_anim_set_values(&a6, 0, obj_height);
lv_anim_set_early_apply(&a6, false);
lv_anim_set_exec_cb(&a6, (lv_anim_exec_xcb_t)set_height);
lv_anim_set_path_cb(&a6, lv_anim_path_ease_out);
lv_anim_set_time(&a6, 300);
if(!anim_timeline) {
anim_timeline_create();
}
if(!anim_timeline) {
anim_timeline_create();
}
/**
* Create an animation timeline
*/
void lv_example_anim_timeline_1(void)
{
lv_obj_t * par = lv_scr_act();
lv_obj_set_flex_flow(par, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(par, LV_FLEX_ALIGN_SPACE_AROUND, LV_FLEX_ALIGN_CENTER, LV_
,→FLEX_ALIGN_CENTER);
/* create btn_start */
lv_obj_t * btn_start = lv_btn_create(par);
lv_obj_add_event_cb(btn_start, btn_start_event_handler, LV_EVENT_VALUE_CHANGED,␣
,→NULL);
lv_obj_add_flag(btn_start, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_add_flag(btn_start, LV_OBJ_FLAG_CHECKABLE);
lv_obj_align(btn_start, LV_ALIGN_TOP_MID, -100, 20);
/* create btn_del */
lv_obj_t * btn_del = lv_btn_create(par);
lv_obj_add_event_cb(btn_del, btn_del_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_add_flag(btn_del, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_align(btn_del, LV_ALIGN_TOP_MID, 0, 20);
/* create btn_stop */
lv_obj_t * btn_stop = lv_btn_create(par);
lv_obj_add_event_cb(btn_stop, btn_stop_event_handler, LV_EVENT_CLICKED, NULL);
lv_obj_add_flag(btn_stop, LV_OBJ_FLAG_IGNORE_LAYOUT);
(continues on next page)
/* create slider_prg */
lv_obj_t * slider_prg = lv_slider_create(par);
lv_obj_add_event_cb(slider_prg, slider_prg_event_handler, LV_EVENT_VALUE_CHANGED,␣
,→NULL);
lv_obj_add_flag(slider_prg, LV_OBJ_FLAG_IGNORE_LAYOUT);
lv_obj_align(slider_prg, LV_ALIGN_BOTTOM_MID, 0, -20);
lv_slider_set_range(slider_prg, 0, 65535);
/* create 3 objects */
obj1 = lv_obj_create(par);
lv_obj_set_size(obj1, obj_width, obj_height);
obj2 = lv_obj_create(par);
lv_obj_set_size(obj2, obj_width, obj_height);
obj3 = lv_obj_create(par);
lv_obj_set_size(obj3, obj_width, obj_height);
}
#endif
class LV_ExampleAnimTimeline_1(object):
def __init__(self):
self.obj_width = 120
self.obj_height = 150
#
# Create an animation timeline
#
self.par = lv.scr_act()
self.par.set_flex_flow(lv.FLEX_FLOW.ROW)
self.par.set_flex_align(lv.FLEX_ALIGN.SPACE_AROUND, lv.FLEX_ALIGN.CENTER, lv.
,→FLEX_ALIGN.CENTER)
self.btn_run = lv.btn(self.par)
self.btn_run.add_event_cb(self.btn_run_event_handler, lv.EVENT.VALUE_CHANGED,␣
,→ None)
self.btn_run.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.btn_run.add_flag(lv.obj.FLAG.CHECKABLE)
self.btn_run.align(lv.ALIGN.TOP_MID, -50, 20)
self.label_run = lv.label(self.btn_run)
self.label_run.set_text("Run")
self.label_run.center()
self.btn_del = lv.btn(self.par)
self.btn_del.add_event_cb(self.btn_del_event_handler, lv.EVENT.CLICKED, None)
self.btn_del.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.btn_del.align(lv.ALIGN.TOP_MID, 50, 20)
(continues on next page)
self.label_del = lv.label(self.btn_del)
self.label_del.set_text("Stop")
self.label_del.center()
self.slider = lv.slider(self.par)
self.slider.add_event_cb(self.slider_prg_event_handler, lv.EVENT.VALUE_
,→CHANGED, None)
self.slider.add_flag(lv.obj.FLAG.IGNORE_LAYOUT)
self.slider.align(lv.ALIGN.BOTTOM_RIGHT, -20, -20)
self.slider.set_range(0, 65535)
self.obj1 = lv.obj(self.par)
self.obj1.set_size(self.obj_width, self.obj_height)
self.obj2 = lv.obj(self.par)
self.obj2.set_size(self.obj_width, self.obj_height)
self.obj3 = lv.obj(self.par)
self.obj3.set_size(self.obj_width, self.obj_height)
self.anim_timeline = None
def anim_timeline_create(self):
# obj1
self.a1 = lv.anim_t()
self.a1.init()
self.a1.set_values(0, self.obj_width)
self.a1.set_early_apply(False)
self.a1.set_custom_exec_cb(lambda a,v: self.set_width(self.obj1,v))
self.a1.set_path_cb(lv.anim_t.path_overshoot)
self.a1.set_time(300)
self.a2 = lv.anim_t()
self.a2.init()
self.a2.set_values(0, self.obj_height)
self.a2.set_early_apply(False)
self.a2.set_custom_exec_cb(lambda a,v: self.set_height(self.obj1,v))
self.a2.set_path_cb(lv.anim_t.path_ease_out)
self.a2.set_time(300)
# obj2
self.a3=lv.anim_t()
self.a3.init()
self.a3.set_values(0, self.obj_width)
self.a3.set_early_apply(False)
self.a3.set_custom_exec_cb(lambda a,v: self.set_width(self.obj2,v))
self.a3.set_path_cb(lv.anim_t.path_overshoot)
self.a3.set_time(300)
self.a4 = lv.anim_t()
(continues on next page)
# obj3
self.a5 = lv.anim_t()
self.a5.init()
self.a5.set_values(0, self.obj_width)
self.a5.set_early_apply(False)
self.a5.set_custom_exec_cb(lambda a,v: self.set_width(self.obj3,v))
self.a5.set_path_cb(lv.anim_t.path_overshoot)
self.a5.set_time(300)
self.a6 = lv.anim_t()
self.a6.init()
self.a6.set_values(0, self.obj_height)
self.a6.set_early_apply(False)
self.a6.set_custom_exec_cb(lambda a,v: self.set_height(self.obj3,v))
self.a6.set_path_cb(lv.anim_t.path_ease_out)
self.a6.set_time(300)
def slider_prg_event_handler(self,e):
slider = e.get_target()
if not self.anim_timeline:
self.anim_timeline_create()
progress = slider.get_value()
lv.anim_timeline_set_progress(self.anim_timeline, progress)
def btn_run_event_handler(self,e):
btn = e.get_target()
if not self.anim_timeline:
self.anim_timeline_create()
reverse = btn.has_state(lv.STATE.CHECKED)
lv.anim_timeline_set_reverse(self.anim_timeline,reverse)
lv.anim_timeline_start(self.anim_timeline)
def btn_del_event_handler(self,e):
if self.anim_timeline:
lv.anim_timeline_del(self.anim_timeline)
self.anim_timeline = None
(continues on next page)
lv_example_anim_timeline_1 = LV_ExampleAnimTimeline_1()
5.14.7 API
Typedefs
Enums
enum lv_anim_enable_t
Can be used to indicate if animations are enabled or disabled in a case
Values:
enumerator LV_ANIM_OFF
enumerator LV_ANIM_ON
Functions
LV_EXPORT_CONST_INT(LV_ANIM_REPEAT_INFINITE)
LV_EXPORT_CONST_INT(LV_ANIM_PLAYTIME_INFINITE)
void _lv_anim_core_init(void)
Init. the animation module
void lv_anim_init(lv_anim_t *a)
Initialize an animation variable. E.g.: lv_anim_t a; lv_anim_init(&a); lv_anim_set_...(&a); lv_anim_start(&a);
Parameters a -- pointer to an lv_anim_t variable to initialize
static inline void lv_anim_set_var(lv_anim_t *a, void *var)
Set a variable to animate
Parameters
• a -- pointer to an initialized lv_anim_t variable
• var -- pointer to a variable to animate
static inline void lv_anim_set_exec_cb(lv_anim_t *a, lv_anim_exec_xcb_t exec_cb)
Set a function to animate var
Parameters
• a -- pointer to an initialized lv_anim_t variable
• exec_cb -- a function to execute during animation LVGL's built-in functions can be used.
E.g. lv_obj_set_x
static inline void lv_anim_set_time(lv_anim_t *a, uint32_t duration)
Set the duration of an animation
Parameters
• a -- pointer to an initialized lv_anim_t variable
• duration -- duration of the animation in milliseconds
static inline void lv_anim_set_delay(lv_anim_t *a, uint32_t delay)
Set a delay before starting the animation
Parameters
• a -- pointer to an initialized lv_anim_t variable
• delay -- delay before the animation in milliseconds
static inline void lv_anim_set_values(lv_anim_t *a, int32_t start, int32_t end)
Set the start and end values of an animation
Parameters
• a -- pointer to an initialized lv_anim_t variable
• start -- the start value
• end -- the end value
struct _lv_anim_t
#include <lv_anim.h> Describes an animation
Public Members
void *var
Variable to animate
lv_anim_exec_xcb_t exec_cb
Function to execute to animate
lv_anim_start_cb_t start_cb
Call it when the animation is starts (considering delay)
lv_anim_ready_cb_t ready_cb
Call it when the animation is ready
lv_anim_deleted_cb_t deleted_cb
Call it when the animation is deleted
lv_anim_get_value_cb_t get_value_cb
Get the current value in relative mode
void *user_data
Custom user data
lv_anim_path_cb_t path_cb
Describe the path (curve) of animations
int32_t start_value
Start value
int32_t current_value
Current value
int32_t end_value
End value
int32_t time
Animation time in ms
int32_t act_time
Current time in animation. Set to negative to make delay.
uint32_t playback_delay
Wait before play back
uint32_t playback_time
Duration of playback animation
uint32_t repeat_delay
Wait before repeat
uint16_t repeat_cnt
Repeat count for the animation
uint8_t early_apply
1: Apply start value immediately even is there is delay
uint8_t playback_now
Play back is in progress
uint8_t run_round
Indicates the animation has run in this round
uint8_t start_cb_called
Indicates that the start_cb was already called
5.15 Timers
LVGL has a built-in timer system. You can register a function to have it be called periodically. The timers are handled and
called in lv_timer_handler(), which needs to be called every few milliseconds. See Porting for more information.
Timers are non-preemptive, which means a timer cannot interrupt another timer. Therefore, you can call any LVGL
related function in a timer.
...
You can make a timer repeat only a given number of times with lv_timer_set_repeat_count(timer,
count). The timer will automatically be deleted after it's called the defined number of times. Set the count to -1
to repeat indefinitely.
You can get the idle percentage time of lv_timer_handler with lv_timer_get_idle(). Note that, it doesn't
measure the idle time of the overall system, only lv_timer_handler. It can be misleading if you use an operating
system and call lv_timer_handler in a timer, as it won't actually measure the time the OS spends in an idle thread.
In some cases, you can't perform an action immediately. For example, you can't delete an object because something else
is still using it, or you don't want to block the execution now. For these cases, lv_async_call(my_function,
data_p) can be used to call my_function on the next invocation of lv_timer_handler. data_p will be
passed to the function when it's called. Note that only the data pointer is saved, so you need to ensure that the variable
will be "alive" while the function is called. It can be static, global or dynamically allocated data. If you want to cancel an
asynchronous call, call lv_async_call_cancel(my_function, data_p), which will clear all asynchronous
calls matching my_function and data_p.
For example:
...
/*The screen is still valid so you can do other things with it*/
If you just want to delete an object and don't need to clean anything up in my_screen_cleanup you could just use
lv_obj_del_async which will delete the object on the next call to lv_timer_handler.
5.15.7 API
Typedefs
Functions
void _lv_timer_core_init(void)
Init the lv_timer module
static in-
line uint32_t LV_ATTRIBUTE_TIMER_HANDLER lv_timer_handler_run_in_period (uint32_t ms)
Call it in the super-loop of main() or threads. It will run lv_timer_handler() with a given period in ms. You can
use it with sleep or delay in OS environment. This function is used to simplify the porting.
struct _lv_timer_t
#include <lv_timer.h> Descriptor of a lv_timer
Public Members
uint32_t period
How often the timer should run
uint32_t last_run
Last time the timer ran
lv_timer_cb_t timer_cb
Timer function
void *user_data
Custom user data
int32_t repeat_count
1: One time; -1 : infinity; n>0: residual times
uint32_t paused
Typedefs
Functions
5.16 Drawing
With LVGL, you don't need to draw anything manually. Just create objects (like buttons, labels, arc, etc.), move and
change them, and LVGL will refresh and redraw what is required.
However, it can be useful to have a basic understanding of how drawing happens in LVGL to add customization, make it
easier to find bugs or just out of curiosity.
The basic concept is to not draw directly onto the display but rather to first draw on an internal draw buffer. When a
drawing (rendering) is ready that buffer is copied to the display.
The draw buffer can be smaller than a display's size. LVGL will simply render in "tiles" that fit into the given draw buffer.
This approach has two main advantages compared to directly drawing to the display:
1. It avoids flickering while the layers of the UI are drawn. For example, if LVGL drew directly onto the display,
when drawing a background + button + text, each "stage" would be visible for a short time.
2. It's faster to modify a buffer in internal RAM and finally write one pixel only once than reading/writing the display
directly on each pixel access. (e.g. via a display controller with SPI interface).
Note that this concept is different from "traditional" double buffering where there are two display sized frame buffers:
one holds the current image to show on the display, and rendering happens to the other (inactive) frame buffer, and they
are swapped when the rendering is finished. The main difference is that with LVGL you don't have to store two frame
buffers (which usually requires external RAM) but only smaller draw buffer(s) that can easily fit into internal RAM.
5.16.2 Masking
Masking is the basic concept of LVGL's draw engine. To use LVGL it's not required to know about the mechanisms
described here but you might find interesting to know how drawing works under hood. Knowing about masking comes in
handy if you want to customize drawing.
To learn about masking let's see the steps of drawing first. LVGL performs the following steps to render any shape, image
or text. It can be considered as a drawing pipeline.
1. Prepare the draw descriptors Create a draw descriptor from an object's styles (e.g. lv_draw_rect_dsc_t).
This gives us the parameters for drawing, for example colors, widths, opacity, fonts, radius, etc.
2. Call the draw function Call the draw function with the draw descriptor and some other parameters (e.g.
lv_draw_rect()). It will render the primitive shape to the current draw buffer.
3. Create masks If the shape is very simple and doesn't require masks, go to #5. Otherwise, create the required
masks in the draw function. (e.g. a rounded rectangle mask)
4. Calculate all the added mask It composites opacity values into a mask buffer with the "shape" of the created
masks. E.g. in case of a "line mask" according to the parameters of the mask, keep one side of the buffer as it is
(255 by default) and set the rest to 0 to indicate that this side should be removed.
5. Blend a color or image During blending, masking (make some pixels transparent or opaque), blending modes
(additive, subtractive, etc.) and color/image opacity are handled.
LVGL has the following built-in mask types which can be calculated and applied real-time:
• LV_DRAW_MASK_TYPE_LINE Removes a side from a line (top, bottom, left or right). lv_draw_line uses
four instances of it. Essentially, every (skew) line is bounded with four line masks forming a rectangle.
• LV_DRAW_MASK_TYPE_RADIUS Removes the inner or outer corners of a rectangle with a radiused transition.
It's also used to create circles by setting the radius to large value (LV_RADIUS_CIRCLE)
• LV_DRAW_MASK_TYPE_ANGLE Removes a circular sector. It is used by lv_draw_arc to remove the
"empty" sector.
• LV_DRAW_MASK_TYPE_FADE Create a vertical fade (change opacity)
• LV_DRAW_MASK_TYPE_MAP The mask is stored in a bitmap array and the necessary parts are applied
Masks are used to create almost every basic primitive:
• letters Create a mask from the letter and draw a rectangle with the letter's color using the mask.
• line Created from four "line masks" to mask out the left, right, top and bottom part of the line to get a perfectly
perpendicular perimeter.
• rounded rectangle A mask is created real-time to add a radius to the corners.
• clip corner To clip overflowing content (usually children) on rounded corners, a rounded rectangle mask is also
applied.
• rectangle border Same as a rounded rectangle but the inner part is masked out too.
• arc drawing A circular border is drawn but an arc mask is applied too.
• ARGB images The alpha channel is separated into a mask and the image is drawn as a normal RGB image.
Using masks
Every mask type has a related parameter structure to describe the mask's data. The following parameter types exist:
• lv_draw_mask_line_param_t
• lv_draw_mask_radius_param_t
• lv_draw_mask_angle_param_t
• lv_draw_mask_fade_param_t
• lv_draw_mask_map_param_t
1. Initialize a mask parameter with lv_draw_mask_<type>_init. See lv_draw_mask.h for the whole
API.
2. Add the mask parameter to the draw engine with int16_t mask_id = lv_draw_mask_add(¶m,
ptr). ptr can be any pointer to identify the mask, (NULL if unused).
3. Call the draw functions
4. Remove the mask from the draw engine with lv_draw_mask_remove_id(mask_id) or
lv_draw_mask_remove_custom(ptr).
5. Free the parameter with lv_draw_mask_free_param(¶m).
A parameter can be added and removed any number of times, but it needs to be freed when not required anymore.
lv_draw_mask_add saves only the pointer of the mask so the parameter needs to be valid while in use.
Although widgets can be easily customized by styles there might be cases when something more custom is required. To
ensure a great level of flexibility LVGL sends a lot of events during drawing with parameters that tell what LVGL is about
to draw. Some fields of these parameters can be modified to draw something else or any custom drawing operations can
be added manually.
A good use case for this is the Button matrix widget. By default, its buttons can be styled in different states, but you can't
style the buttons one by one. However, an event is sent for every button and you can, for example, tell LVGL to use
different colors on a specific button or to manually draw an image on some buttons.
Each of these events is described in detail below.
Main drawing
These events are related to the actual drawing of an object. E.g. the drawing of buttons, texts, etc. happens here.
lv_event_get_clip_area(event) can be used to get the current clip area. The clip area is required in draw
functions to make them draw only on a limited area.
LV_EVENT_DRAW_MAIN_BEGIN
Sent before starting to draw an object. This is a good place to add masks manually. E.g. add a line mask that "removes"
the right side of an object.
LV_EVENT_DRAW_MAIN
The actual drawing of an object happens in this event. E.g. a rectangle for a button is drawn here. First, the widgets'
internal events are called to perform drawing and after that you can draw anything on top of them. For example you can
add a custom text or an image.
LV_EVENT_DRAW_MAIN_END
Called when the main drawing is finished. You can draw anything here as well and it's also a good place to remove any
masks created in LV_EVENT_DRAW_MAIN_BEGIN.
Post drawing
Post drawing events are called when all the children of an object are drawn. For example LVGL use the post drawing
phase to draw scrollbars because they should be above all of the children.
lv_event_get_clip_area(event) can be used to get the current clip area.
LV_EVENT_DRAW_POST_BEGIN
Sent before starting the post draw phase. Masks can be added here too to mask out the post drawn content.
LV_EVENT_DRAW_POST
LV_EVENT_DRAW_POST_END
Called when post drawing has finished. If masks were not removed in LV_EVENT_DRAW_MAIN_END they should be
removed here.
Part drawing
When LVGL draws a part of an object (e.g. a slider's indicator, a table's cell or a button matrix's button) it sends events
before and after drawing that part with some context of the drawing. This allows changing the parts on a very low level
with masks, extra drawing, or changing the parameters that LVGL is planning to use for drawing.
In these events an lv_obj_draw_part_t structure is used to describe the context of the drawing. Not all fields are
set for every part and widget. To see which fields are set for a widget refer to the widget's documentation.
lv_obj_draw_part_t has the following fields:
// Always set
const lv_area_t * clip_area; // The current clip area, required if you need to␣
,→draw something in the event
uint32_t part; // The current part for which the event is sent
uint32_t id; // The index of the part. E.g. a button's index␣
,→on button matrix or table cell index.
// Other parameters
lv_area_t * draw_area; // The area of the part being drawn
const lv_point_t * p1; // A point calculated during drawing. E.g. a␣
,→point of a chart or the center of an arc.
LV_EVENT_DRAW_PART_BEGIN
Start the drawing of a part. This is a good place to modify the draw descriptors (e.g. rect_dsc), or add masks.
LV_EVENT_DRAW_PART_END
Finish the drawing of a part. This is a good place to draw extra content on the part or remove masks added in
LV_EVENT_DRAW_PART_BEGIN.
Others
LV_EVENT_COVER_CHECK
This event is used to check whether an object fully covers an area or not.
lv_event_get_cover_area(event) returns a pointer to an area to check and
lv_event_set_cover_res(event, res) can be used to set one of these results:
• LV_COVER_RES_COVER the area is fully covered by the object
• LV_COVER_RES_NOT_COVER the area is not covered by the object
• LV_COVER_RES_MASKED there is a mask on the object, so it does not fully cover the area
Here are some reasons why an object would be unable to fully cover an area:
• It's simply not fully in area
• It has a radius
• It doesn't have 100% background opacity
• It's an ARGB or chroma keyed image
• It does not have normal blending mode. In this case LVGL needs to know the colors under the object to apply
blending properly
• It's a text, etc
In short if for any reason the area below an object is visible than the object doesn't cover that area.
Before sending this event LVGL checks if at least the widget's coordinates fully cover the area or not. If not the event is
not called.
You need to check only the drawing you have added. The existing properties known by a widget are handled in its internal
events. E.g. if a widget has > 0 radius it might not cover an area, but you need to handle radius only if you will modify
it and the widget won't know about it.
LV_EVENT_REFR_EXT_DRAW_SIZE
If you need to draw outside a widget, LVGL needs to know about it to provide extra space for drawing. Let's say you
create an event which writes the current value of a slider above its knob. In this case LVGL needs to know that the slider's
draw area should be larger with the size required for the text.
You can simply set the required draw area with lv_event_set_ext_draw_size(e, size).
TODO
TODO
Arm-2D is not a GPU but an abstraction layer for 2D GPUs dedicated to Microcontrollers. It supports all Cortex-M
processors ranging from Cortex-M0 to the latest Cortex-M85.
Arm-2D is an open-source project on Github. For more, please refer to: https://github.com/ARM-software/Arm-2D.
How to Use
In general, you can set the macro LV_USE_GPU_ARM2D to 1in lv_conf.h to enable Arm-2D acceleration for LVGL.
If you are using CMSIS-Pack to deploy the LVGL. You don't have to define the macro LV_USE_GPU_ARM2D manually,
instead, please select the component GPU Arm-2D in the RTE dialog. This step will define the macro for us.
Design Considerations
As mentioned before, Arm-2D is an abstraction layer for 2D GPU; hence if there is no accelerator or dedicated instruction
set (such as Helium or ACI) available for Arm-2D, it provides negligible performance boost for LVGL (sometimes worse)
for regular Cortex-M processors.
We highly recommend you enable Arm-2D acceleration for LVGL when:
• The target processors are Cortex-M55 and/or Cortex-M85
• The target processors support Helium.
• The device vendor provides an arm-2d compliant driver for their propriotory 2D accelerators and/or customized
instruction set.
• The target device contains DMA-350
Examples
TODO
TODO
SIX
WIDGETS
6.1.1 Overview
The 'Base Object' implements the basic properties of widgets on a screen, such as:
• coordinates
• parent object
• children
• contains the styles
• attributes like Clickable, Scrollable, etc.
In object-oriented thinking, it is the base class from which all other objects in LVGL are inherited.
The functions and functionalities of the Base object can be used with other widgets too. For example
lv_obj_set_width(slider, 100)
The Base object can be directly used as a simple widget: it's nothing more than a rectangle. In HTML terms, think of it
as a <div>.
Coordinates
Only a small subset of coordinate settings is described here. To see all the features of LVGL (padding, coordinates in
styles, layouts, etc) visit the Coordinates page.
Size
The object size can be modified on individual axes with lv_obj_set_width(obj, new_width) and
lv_obj_set_height(obj, new_height), or both axes can be modified at the same time with
lv_obj_set_size(obj, new_width, new_height).
474
LVGL Documentation 8.3
Position
You can set the position relative to the parent with lv_obj_set_x(obj, new_x) and lv_obj_set_y(obj,
new_y), or both axes at the same time with lv_obj_set_pos(obj, new_x, new_y).
Alignment
You can align the object on its parent with lv_obj_set_align(obj, LV_ALIGN_...). After this every x and
y setting will be relative to the set alignment mode. For example, this will shift the object by 10;20 px from the center of
its parent:
lv_obj_set_align(obj, LV_ALIGN_CENTER);
lv_obj_set_pos(obj, 10, 20);
You can set a new parent for an object with lv_obj_set_parent(obj, new_parent). To get the current
parent, use lv_obj_get_parent(obj).
To get a specific child of a parent use lv_obj_get_child(parent, idx). Some examples for idx:
• 0 get the child created first
• 1 get the child created second
• -1 get the child created last
The children can be iterated lke this:
uint32_t i;
for(i = 0; i < lv_obj_get_child_cnt(parent); i++) {
lv_obj_t * child = lv_obj_get_child(parent, i);
/*Do something with child*/
}
lv_obj_get_index(obj) returns the index of the object in its parent. It is equivalent to the number of younger
children in the parent.
You can bring an object to the foreground or send it to the background with lv_obj_move_foreground(obj)
and lv_obj_move_background(obj).
You can change the index of an object in its parent using lv_obj_move_to_index(obj, index).
You can swap the position of two objects with lv_obj_swap(obj1, obj2).
At the highest level of the LVGL object hierarchy is the display which represents the driver for a display device (physical
display or simulator). A display can have one or more screens associated with it. Each screen contains a hierarchy of
objects for graphical widgets representing a layout that covers the entire display.
When you have created a screen like lv_obj_t * screen = lv_obj_create(NULL), you can make it active
with lv_scr_load(screen). The lv_scr_act() function gives you a pointer to the active screen.
If you have multiple displays, it's important to know that the screen functions operate on the most recently created display
or the one explicitly selected with lv_disp_set_default.
To get an object's screen use the lv_obj_get_screen(obj) function.
Events
Styles
Be sure to read the Style overview. Here only the most essential functions are described.
A new style can be added to an object with the lv_obj_add_style(obj, &new_style, selector) function.
selector is an ORed combination of part and state(s). E.g. LV_PART_SCROLLBAR | LV_STATE_PRESSED.
The base objects use LV_PART_MAIN style properties and LV_PART_SCROLLBAR with the typical background style
properties.
Flags
/*Hide on object*/
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
Groups
By default, the objects can be clicked only within their bounding area. However, this can be extended with
lv_obj_set_ext_click_area(obj, size).
6.1.2 Events
• LV_EVENT_VALUE_CHANGED when the LV_OBJ_FLAG_CHECKABLE flag is enabled and the object clicked
(on transition to/from the checked state)
• LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END is sent for the following types:
– LV_OBJ_DRAW_PART_RECTANGLE The main rectangle
∗ part: LV_PART_MAIN
∗ rect_dsc
∗ draw_area: the area of the rectangle
– LV_OBJ_DRAW_PART_BORDER_POST The border if the border_post style property is true
∗ part: LV_PART_MAIN
∗ rect_dsc
∗ draw_area: the area of the rectangle
– LV_OBJ_DRAW_PART_SCROLLBAR the scrollbars
∗ part: LV_PART_SCROLLBAR
∗ rect_dsc
∗ draw_area: the area of the rectangle
6.1.3 Keys
If LV_OBJ_FLAG_CHECKABLE is enabled, LV_KEY_RIGHT and LV_KEY_UP make the object checked, and
LV_KEY_LEFT and LV_KEY_DOWN make it unchecked.
If LV_OBJ_FLAG_SCROLLABLE is enabled, but the object is not editable (as declared by the widget class), the arrow
keys (LV_KEY_UP, LV_KEY_DOWN, LV_KEY_LEFT, LV_KEY_RIGHT) scroll the object. If the object can only scroll
vertically, LV_KEY_LEFT and LV_KEY_RIGHT will scroll up/down instead, making it compatible with an encoder
input device. See Input devices overview for more on encoder behaviors and the edit mode.
Learn more about Keys.
6.1.4 Example
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
void lv_example_obj_1(void)
{
lv_obj_t * obj1;
obj1 = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj1, 100, 50);
lv_obj_align(obj1, LV_ALIGN_CENTER, -60, -30);
lv_obj_t * obj2;
obj2 = lv_obj_create(lv_scr_act());
lv_obj_add_style(obj2, &style_shadow, 0);
lv_obj_align(obj2, LV_ALIGN_CENTER, 60, 30);
}
#endif
obj1 = lv.obj(lv.scr_act())
obj1.set_size(100, 50)
obj1.align(lv.ALIGN.CENTER, -60, -30)
style_shadow = lv.style_t()
style_shadow.init()
style_shadow.set_shadow_width(10)
style_shadow.set_shadow_spread(5)
style_shadow.set_shadow_color(lv.palette_main(lv.PALETTE.BLUE))
obj2 = lv.obj(lv.scr_act())
obj2.add_style(style_shadow, 0)
obj2.align(lv.ALIGN.CENTER, 60, 30)
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
lv_point_t vect;
lv_indev_get_vect(indev, &vect);
/**
* Make an object dragable.
*/
void lv_example_obj_2(void)
{
lv_obj_t * obj;
obj = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj, 150, 100);
lv_obj_add_event_cb(obj, drag_event_handler, LV_EVENT_PRESSING, NULL);
}
#endif
def drag_event_handler(e):
obj = e.get_target()
indev = lv.indev_get_act()
vect = lv.point_t()
indev.get_vect(vect)
x = obj.get_x() + vect.x
y = obj.get_y() + vect.y
obj.set_pos(x, y)
#
# Make an object dragable.
#
obj = lv.obj(lv.scr_act())
obj.set_size(150, 100)
obj.add_event_cb(drag_event_handler, lv.EVENT.PRESSING, None)
(continues on next page)
label = lv.label(obj)
label.set_text("Drag me")
label.center()
6.1.5 API
Typedefs
Enums
enum [anonymous]
Possible states of a widget. OR-ed values are possible
Values:
enumerator LV_STATE_DEFAULT
enumerator LV_STATE_CHECKED
enumerator LV_STATE_FOCUSED
enumerator LV_STATE_FOCUS_KEY
enumerator LV_STATE_EDITED
enumerator LV_STATE_HOVERED
enumerator LV_STATE_PRESSED
enumerator LV_STATE_SCROLLED
enumerator LV_STATE_DISABLED
enumerator LV_STATE_USER_1
enumerator LV_STATE_USER_2
enumerator LV_STATE_USER_3
enumerator LV_STATE_USER_4
enumerator LV_STATE_ANY
Special value can be used in some functions to target all states
enum [anonymous]
The possible parts of widgets. The parts can be considered as the internal building block of the widgets. E.g. slider
= background + indicator + knob Not all parts are used by every widget
Values:
enumerator LV_PART_MAIN
A background like rectangle
enumerator LV_PART_SCROLLBAR
The scrollbar(s)
enumerator LV_PART_INDICATOR
Indicator, e.g. for slider, bar, switch, or the tick box of the checkbox
enumerator LV_PART_KNOB
Like handle to grab to adjust the value
enumerator LV_PART_SELECTED
Indicate the currently selected option or section
enumerator LV_PART_ITEMS
Used if the widget has multiple similar elements (e.g. table cells)
enumerator LV_PART_TICKS
Ticks on scale e.g. for a chart or meter
enumerator LV_PART_CURSOR
Mark a specific place e.g. for text area's cursor or on a chart
enumerator LV_PART_CUSTOM_FIRST
Extension point for custom widgets
enumerator LV_PART_ANY
Special value can be used in some functions to target all parts
enum [anonymous]
On/Off features controlling the object's behavior. OR-ed values are possible
Values:
enumerator LV_OBJ_FLAG_HIDDEN
Make the object hidden. (Like it wasn't there at all)
enumerator LV_OBJ_FLAG_CLICKABLE
Make the object clickable by the input devices
enumerator LV_OBJ_FLAG_CLICK_FOCUSABLE
Add focused state to the object when clicked
enumerator LV_OBJ_FLAG_CHECKABLE
Toggle checked state when the object is clicked
enumerator LV_OBJ_FLAG_SCROLLABLE
Make the object scrollable
enumerator LV_OBJ_FLAG_SCROLL_ELASTIC
Allow scrolling inside but with slower speed
enumerator LV_OBJ_FLAG_SCROLL_MOMENTUM
Make the object scroll further when "thrown"
enumerator LV_OBJ_FLAG_SCROLL_ONE
Allow scrolling only one snappable children
enumerator LV_OBJ_FLAG_SCROLL_CHAIN_HOR
Allow propagating the horizontal scroll to a parent
enumerator LV_OBJ_FLAG_SCROLL_CHAIN_VER
Allow propagating the vertical scroll to a parent
enumerator LV_OBJ_FLAG_SCROLL_CHAIN
enumerator LV_OBJ_FLAG_SCROLL_ON_FOCUS
Automatically scroll object to make it visible when focused
enumerator LV_OBJ_FLAG_SCROLL_WITH_ARROW
Allow scrolling the focused object with arrow keys
enumerator LV_OBJ_FLAG_SNAPPABLE
If scroll snap is enabled on the parent it can snap to this object
enumerator LV_OBJ_FLAG_PRESS_LOCK
Keep the object pressed even if the press slid from the object
enumerator LV_OBJ_FLAG_EVENT_BUBBLE
Propagate the events to the parent too
enumerator LV_OBJ_FLAG_GESTURE_BUBBLE
Propagate the gestures to the parent
enumerator LV_OBJ_FLAG_ADV_HITTEST
Allow performing more accurate hit (click) test. E.g. consider rounded corners.
enumerator LV_OBJ_FLAG_IGNORE_LAYOUT
Make the object position-able by the layouts
enumerator LV_OBJ_FLAG_FLOATING
Do not scroll the object when the parent scrolls and ignore layout
enumerator LV_OBJ_FLAG_OVERFLOW_VISIBLE
Do not clip the children's content to the parent's boundary
enumerator LV_OBJ_FLAG_LAYOUT_1
Custom flag, free to use by layouts
enumerator LV_OBJ_FLAG_LAYOUT_2
Custom flag, free to use by layouts
enumerator LV_OBJ_FLAG_WIDGET_1
Custom flag, free to use by widget
enumerator LV_OBJ_FLAG_WIDGET_2
Custom flag, free to use by widget
enumerator LV_OBJ_FLAG_USER_1
Custom flag, free to use by user
enumerator LV_OBJ_FLAG_USER_2
Custom flag, free to use by user
enumerator LV_OBJ_FLAG_USER_3
Custom flag, free to use by user
enumerator LV_OBJ_FLAG_USER_4
Custom flag, free to use by user
enum lv_obj_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_obj_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_OBJ_DRAW_PART_RECTANGLE
The main rectangle
enumerator LV_OBJ_DRAW_PART_BORDER_POST
The border if style_border_post = true
enumerator LV_OBJ_DRAW_PART_SCROLLBAR
The scrollbar
Functions
void lv_init(void)
Initialize LVGL library. Should be called before any other LVGL related function.
void lv_deinit(void)
Deinit the 'lv' library Currently only implemented when not using custom allocators, or GC is enabled.
bool lv_is_initialized(void)
Returns whether the 'lv' library is currently initialized
lv_obj_t *lv_obj_create(lv_obj_t *parent)
Create a base object (a rectangle)
Parameters parent -- pointer to a parent object. If NULL then a screen will be created.
Returns pointer to the new object
void lv_obj_add_flag(lv_obj_t *obj, lv_obj_flag_t f)
Set one or more flags
Parameters
• obj -- pointer to an object
• f -- R-ed values from lv_obj_flag_t to set.
void lv_obj_clear_flag(lv_obj_t *obj, lv_obj_flag_t f)
Clear one or more flags
Parameters
• obj -- pointer to an object
• f -- OR-ed values from lv_obj_flag_t to set.
void lv_obj_add_state(lv_obj_t *obj, lv_state_t state)
Add one or more states to the object. The other state bits will remain unchanged. If specified in the styles, transition
animation will be started from the previous state to the current.
Parameters
Variables
struct _lv_obj_spec_attr_t
#include <lv_obj.h> Special, rarely used attributes. They are allocated automatically if any elements is set.
Public Members
uint32_t child_cnt
Number of children
lv_group_t *group_p
lv_point_t scroll
The current X/Y scroll offset
lv_coord_t ext_click_pad
Extra click padding in all direction
lv_coord_t ext_draw_size
EXTend the size in every direction for drawing.
lv_scrollbar_mode_t scrollbar_mode
How to display scrollbars
lv_scroll_snap_t scroll_snap_x
Where to align the snappable children horizontally
lv_scroll_snap_t scroll_snap_y
Where to align the snappable children vertically
lv_dir_t scroll_dir
The allowed scroll direction(s)
uint8_t event_dsc_cnt
Number of event callbacks stored in event_dsc array
uint8_t layer_type
Cache the layer type here. Element of @lv_intermediate_layer_type_t
struct _lv_obj_t
Public Members
_lv_obj_spec_attr_t *spec_attr
_lv_obj_style_t *styles
void *user_data
lv_area_t coords
lv_obj_flag_t flags
lv_state_t state
uint16_t layout_inv
uint16_t readjust_scroll_after_layout
uint16_t scr_layout_inv
uint16_t skip_trans
uint16_t style_cnt
uint16_t h_layout
uint16_t w_layout
uint16_t being_deleted
Overview
The Arc consists of a background and a foreground arc. The foreground (indicator) can be touch-adjusted.
• LV_PART_MAIN Draws a background using the typical background style properties and an arc using the arc style
properties. The arc's size and position will respect the padding style properties.
• LV_PART_INDICATOR Draws another arc using the arc style properties. Its padding values are interpreted
relative to the background arc.
• LV_PART_KNOB Draws a handle on the end of the indicator using all background properties and padding values.
With zero padding the knob size is the same as the indicator's width. Larger padding makes it larger, smaller
padding makes it smaller.
Usage
A new value can be set using lv_arc_set_value(arc, new_value). The value is interpreted in a range
(minimum and maximum values) which can be modified with lv_arc_set_range(arc, min, max). The
default range is 0..100.
The indicator arc is drawn on the main part's arc. This if the value is set to maximum the indicator arc will cover the entire
"background" arc. To set the start and end angle of the background arc use the lv_arc_set_bg_angles(arc,
start_angle, end_angle) functions or lv_arc_set_bg_start/end_angle(arc, angle).
Zero degrees is at the middle right (3 o'clock) of the object and the degrees are increasing in clockwise direction. The
angles should be in the [0;360] range.
Rotation
Mode
Change rate
If the arc is pressed the current value will set with a limited speed according to the set change rate. The change rate is
defined in degree/second unit and can be set with lv_arc_set_change_rage(arc, rate)
It's also possible to set the angles of the indicator arc directly with lv_arc_set_angles(arc, start_angle,
end_angle) function or lv_arc_set_start/end_angle(arc, start_angle). In this case the set
"value" and "mode" are ignored.
In other words, the angle and value settings are independent. You should exclusively use one or the other. Mixing the two
might result in unintended behavior.
To make the arc non-adjustable, remove the style of the knob and make the object non-clickable:
If the LV_OBJ_FLAG_ADV_HITTEST flag is enabled the arc can be clicked through in the middle. Clicks are recog-
nized only on the ring of the background arc. lv_obj_set_ext_click_size() makes the sensitive area larger
inside and outside with the given number of pixels.
Another object can be positioned according to the current position of the arc in order to follow the arc's current value
(angle). To do this use lv_arc_align_obj_to_angle(arc, obj_to_align, radius_offset).
Similarly lv_arc_rotate_obj_to_angle(arc, obj_to_rotate, radius_offset) can be used to
rotate the object to the current value of the arc.
It's a typical use case to call these functions in the VALUE_CHANGED event of the arc.
Events
Keys
Example
Simple Arc
#include "../../lv_examples.h"
void lv_example_arc_1(void)
{
lv_obj_t * label = lv_label_create(lv_scr_act());
/*Create an Arc*/
lv_obj_t * arc = lv_arc_create(lv_scr_act());
lv_obj_set_size(arc, 150, 150);
lv_arc_set_rotation(arc, 135);
lv_arc_set_bg_angles(arc, 0, 270);
lv_arc_set_value(arc, 10);
lv_obj_center(arc);
lv_obj_add_event_cb(arc, value_changed_event_cb, LV_EVENT_VALUE_CHANGED, label);
#endif
# Create an Arc
arc = lv.arc(lv.scr_act())
arc.set_end_angle(200)
arc.set_size(150, 150)
arc.center()
#include "../../lv_examples.h"
/**
* Create an arc which acts as a loader.
*/
void lv_example_arc_2(void)
{
/*Create an Arc*/
lv_obj_t * arc = lv_arc_create(lv_scr_act());
lv_arc_set_rotation(arc, 270);
lv_arc_set_bg_angles(arc, 0, 360);
lv_obj_remove_style(arc, NULL, LV_PART_KNOB); /*Be sure the knob is not␣
,→displayed*/
lv_obj_center(arc);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, arc);
lv_anim_set_exec_cb(&a, set_angle);
lv_anim_set_time(&a, 1000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); /*Just for the demo*/
lv_anim_set_repeat_delay(&a, 500);
lv_anim_set_values(&a, 0, 100);
lv_anim_start(&a);
#endif
#
# An `lv_timer` to call periodically to set the angles of the arc
#
class ArcLoader():
def __init__(self):
self.a = 270
def arc_loader_cb(self,tim,arc):
# print(tim,arc)
self.a += 5
arc.set_end_angle(self.a)
#
# Create an arc which acts as a loader.
#
# Create an Arc
arc = lv.arc(lv.scr_act())
arc.set_bg_angles(0, 360)
arc.set_angles(270, 270)
arc.center()
timer = lv.timer_create_basic()
timer.set_period(20)
timer.set_cb(lambda src: arc_loader.arc_loader_cb(timer,arc))
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_ARC_MODE_NORMAL
enumerator LV_ARC_MODE_SYMMETRICAL
enumerator LV_ARC_MODE_REVERSE
enum lv_arc_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_arc_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_ARC_DRAW_PART_BACKGROUND
The background arc
enumerator LV_ARC_DRAW_PART_FOREGROUND
The foreground arc
enumerator LV_ARC_DRAW_PART_KNOB
The knob
Functions
Variables
struct lv_arc_t
Public Members
lv_obj_t obj
uint16_t rotation
uint16_t indic_angle_start
uint16_t indic_angle_end
uint16_t bg_angle_start
uint16_t bg_angle_end
int16_t value
int16_t min_value
int16_t max_value
uint32_t dragging
uint32_t type
uint32_t min_close
uint32_t in_out
uint32_t chg_rate
uint32_t last_tick
int16_t last_angle
Overview
The bar object has a background and an indicator on it. The width of the indicator is set according to the current value
of the bar.
Vertical bars can be created if the width of the object is smaller than its height.
Not only the end, but also the start value of the bar can be set, which changes the start position of the indicator.
• LV_PART_MAIN The background of the bar and it uses the typical background style properties. Adding padding
makes the indicator smaller or larger. The anim_time style property sets the animation time if the values set
with LV_ANIM_ON.
• LV_PART_INDICATOR The indicator itself; also uses all the typical background properties.
Usage
A new value can be set by lv_bar_set_value(bar, new_value, LV_ANIM_ON/OFF). The value is inter-
preted in a range (minimum and maximum values) which can be modified with lv_bar_set_range(bar, min,
max). The default range is 0..100.
The new value in lv_bar_set_value can be set with or without an animation depending on the last parameter
(LV_ANIM_ON/OFF).
Modes
Events
Keys
Example
Simple Bar
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
void lv_example_bar_1(void)
{
lv_obj_t * bar1 = lv_bar_create(lv_scr_act());
(continues on next page)
#endif
bar1 = lv.bar(lv.scr_act())
bar1.set_size(200, 20)
bar1.center()
bar1.set_value(70, lv.ANIM.OFF)
Styling a bar
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Example of styling the bar
*/
void lv_example_bar_2(void)
{
static lv_style_t style_bg;
static lv_style_t style_indic;
lv_style_init(&style_bg);
lv_style_set_border_color(&style_bg, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_border_width(&style_bg, 2);
lv_style_set_pad_all(&style_bg, 6); /*To make the indicator smaller*/
lv_style_set_radius(&style_bg, 6);
lv_style_set_anim_time(&style_bg, 1000);
lv_style_init(&style_indic);
lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);
lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_radius(&style_indic, 3);
#endif
#
# Example of styling the bar
#
style_bg = lv.style_t()
(continues on next page)
style_bg.init()
style_bg.set_border_color(lv.palette_main(lv.PALETTE.BLUE))
style_bg.set_border_width(2)
style_bg.set_pad_all(6) # To make the indicator smaller
style_bg.set_radius(6)
style_bg.set_anim_time(1000)
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_radius(3)
bar = lv.bar(lv.scr_act())
bar.remove_style_all() # To have a clean start
bar.add_style(style_bg, 0)
bar.add_style(style_indic, lv.PART.INDICATOR)
bar.set_size(200, 20)
bar.center()
bar.set_value(100, lv.ANIM.ON)
Temperature meter
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* A temperature meter example
*/
void lv_example_bar_3(void)
{
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);
lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_RED));
lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_VER);
lv_anim_t a;
(continues on next page)
#endif
#
# A temperature meter example
#
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_opa(lv.OPA.COVER)
style_indic.set_bg_color(lv.palette_main(lv.PALETTE.RED))
style_indic.set_bg_grad_color(lv.palette_main(lv.PALETTE.BLUE))
style_indic.set_bg_grad_dir(lv.GRAD_DIR.VER)
bar = lv.bar(lv.scr_act())
bar.add_style(style_indic, lv.PART.INDICATOR)
bar.set_size(20, 200)
bar.center()
bar.set_range(-20, 40)
a = lv.anim_t()
a.init()
a.set_time(3000)
a.set_playback_time(3000)
a.set_var(bar)
a.set_values(-20, 40)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a.set_custom_exec_cb(lambda a, val: set_temp(bar,val))
lv.anim_t.start(a)
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Bar with stripe pattern and ranged value
*/
void lv_example_bar_4(void)
{
LV_IMG_DECLARE(img_skew_strip);
static lv_style_t style_indic;
lv_style_init(&style_indic);
lv_style_set_bg_img_src(&style_indic, &img_skew_strip);
lv_style_set_bg_img_tiled(&style_indic, true);
lv_style_set_bg_img_opa(&style_indic, LV_OPA_30);
#endif
#
# get an icon
#
def get_icon(filename,xres,yres):
try:
sdl_filename = "../../assets/" + filename + "_" + str(xres) + "x" + str(yres)␣
,→+ "_argb8888.fnt"
icon_dsc = lv.img_dsc_t(
{
"header": {"always_zero": 0, "w": xres, "h": yres, "cf": lv.img.CF.TRUE_
,→COLOR_ALPHA},
"data": icon_data,
"data_size": len(icon_data),
}
)
return icon_dsc
#
# Bar with stripe pattern and ranged value
#
(continues on next page)
img_skew_strip_dsc = get_icon("img_skew_strip",80,20)
style_indic = lv.style_t()
style_indic.init()
style_indic.set_bg_img_src(img_skew_strip_dsc)
style_indic.set_bg_img_tiled(True)
style_indic.set_bg_img_opa(lv.OPA._30)
bar = lv.bar(lv.scr_act())
bar.add_style(style_indic, lv.PART.INDICATOR)
bar.set_size(260, 20)
bar.center()
bar.set_mode(lv.bar.MODE.RANGE)
bar.set_value(90, lv.ANIM.OFF)
bar.set_start_value(20, lv.ANIM.OFF)
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
/**
* Bar with LTR and RTL base direction
*/
void lv_example_bar_5(void)
{
lv_obj_t * label;
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Left to Right base direction");
lv_obj_align_to(label, bar_ltr, LV_ALIGN_OUT_TOP_MID, 0, -5);
label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Right to Left base direction");
lv_obj_align_to(label, bar_rtl, LV_ALIGN_OUT_TOP_MID, 0, -5);
}
#endif
#
# Bar with LTR and RTL base direction
#
bar_ltr = lv.bar(lv.scr_act())
bar_ltr.set_size(200, 20)
bar_ltr.set_value(70, lv.ANIM.OFF)
bar_ltr.align(lv.ALIGN.CENTER, 0, -30)
label = lv.label(lv.scr_act())
label.set_text("Left to Right base direction")
label.align_to(bar_ltr, lv.ALIGN.OUT_TOP_MID, 0, -5)
bar_rtl = lv.bar(lv.scr_act())
bar_rtl.set_style_base_dir(lv.BASE_DIR.RTL,0)
bar_rtl.set_size(200, 20)
bar_rtl.set_value(70, lv.ANIM.OFF)
bar_rtl.align(lv.ALIGN.CENTER, 0, 30)
label = lv.label(lv.scr_act())
label.set_text("Right to Left base direction")
label.align_to(bar_rtl, lv.ALIGN.OUT_TOP_MID, 0, -5)
#include "../../lv_examples.h"
#if LV_USE_BAR && LV_BUILD_EXAMPLES
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.font = LV_FONT_DEFAULT;
char buf[8];
lv_snprintf(buf, sizeof(buf), "%d", (int)lv_bar_get_value(obj));
lv_point_t txt_size;
lv_txt_get_size(&txt_size, buf, label_dsc.font, label_dsc.letter_space, label_dsc.
,→line_space, LV_COORD_MAX,
label_dsc.flag);
lv_area_t txt_area;
/*If the indicator is long enough put the text inside on the right*/
if(lv_area_get_width(dsc->draw_area) > txt_size.x + 20) {
(continues on next page)
/**
* Custom drawer on the bar to display the current value
*/
void lv_example_bar_6(void)
{
lv_obj_t * bar = lv_bar_create(lv_scr_act());
lv_obj_add_event_cb(bar, event_cb, LV_EVENT_DRAW_PART_END, NULL);
lv_obj_set_size(bar, 200, 20);
lv_obj_center(bar);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, bar);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_exec_cb(&a, set_value);
lv_anim_set_time(&a, 2000);
lv_anim_set_playback_time(&a, 2000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
#endif
def event_cb(e):
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if dsc.part != lv.PART.INDICATOR:
return
obj= e.get_target()
label_dsc = lv.draw_label_dsc_t()
label_dsc.init()
# label_dsc.font = LV_FONT_DEFAULT;
txt_area = lv.area_t()
# If the indicator is long enough put the text inside on the right
if dsc.draw_area.get_width() > txt_size.x + 20:
txt_area.x2 = dsc.draw_area.x2 - 5
txt_area.x1 = txt_area.x2 - txt_size.x + 1
label_dsc.color = lv.color_white()
# If the indicator is still short put the text out of it on the right*/
else:
txt_area.x1 = dsc.draw_area.x2 + 5
txt_area.x2 = txt_area.x1 + txt_size.x - 1
label_dsc.color = lv.color_black()
#
# Custom drawer on the bar to display the current value
#
bar = lv.bar(lv.scr_act())
bar.add_event_cb(event_cb, lv.EVENT.DRAW_PART_END, None)
bar.set_size(200, 20)
bar.center()
a = lv.anim_t()
a.init()
a.set_var(bar)
a.set_values(0, 100)
a.set_custom_exec_cb(lambda a,val: set_value(bar,val))
a.set_time(2000)
a.set_playback_time(2000)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a)
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_BAR_MODE_NORMAL
enumerator LV_BAR_MODE_SYMMETRICAL
enumerator LV_BAR_MODE_RANGE
enum lv_bar_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_bar_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_BAR_DRAW_PART_INDICATOR
The indicator
Functions
Variables
struct _lv_bar_anim_t
Public Members
lv_obj_t *bar
int32_t anim_start
int32_t anim_end
int32_t anim_state
struct lv_bar_t
Public Members
lv_obj_t obj
int32_t cur_value
Current value of the bar
int32_t min_value
Minimum value of the bar
int32_t max_value
Maximum value of the bar
int32_t start_value
Start value of the bar
lv_area_t indic_area
Save the indicator area. Might be used by derived types
_lv_bar_anim_t cur_value_anim
_lv_bar_anim_t start_value_anim
lv_bar_mode_t mode
Type of bar
Overview
Buttons have no new features compared to the Base object. They are useful for semantic purposes and have slightly
different default settings.
Buttons, by default, differ from Base object in the following ways:
• Not scrollable
• Added to the default group
• Default height and width set to LV_SIZE_CONTENT
• LV_PART_MAIN The background of the button. Uses the typical background style properties.
Usage
Events
Keys
Example
Simple Buttons
#include "../../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
if(code == LV_EVENT_CLICKED) {
LV_LOG_USER("Clicked");
}
else if(code == LV_EVENT_VALUE_CHANGED) {
(continues on next page)
void lv_example_btn_1(void)
{
lv_obj_t * label;
label = lv_label_create(btn1);
lv_label_set_text(label, "Button");
lv_obj_center(label);
label = lv_label_create(btn2);
lv_label_set_text(label, "Toggle");
lv_obj_center(label);
}
#endif
def event_handler(evt):
code = evt.get_code()
if code == lv.EVENT.CLICKED:
print("Clicked event seen")
elif code == lv.EVENT.VALUE_CHANGED:
print("Value changed seen")
btn1.align(lv.ALIGN.CENTER,0,-40)
label=lv.label(btn1)
label.set_text("Button")
btn2.align(lv.ALIGN.CENTER,0,40)
btn2.add_flag(lv.obj.FLAG.CHECKABLE)
btn2.set_height(lv.SIZE.CONTENT)
(continues on next page)
label=lv.label(btn2)
label.set_text("Toggle")
label.center()
Styling buttons
#include "../../lv_examples.h"
#if LV_USE_BTN && LV_BUILD_EXAMPLES
/**
* Style a button from scratch
*/
void lv_example_btn_2(void)
{
/*Init the style for the default state*/
static lv_style_t style;
lv_style_init(&style);
lv_style_set_radius(&style, 3);
lv_style_set_bg_opa(&style, LV_OPA_100);
lv_style_set_bg_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_bg_grad_color(&style, lv_palette_darken(LV_PALETTE_BLUE, 2));
lv_style_set_bg_grad_dir(&style, LV_GRAD_DIR_VER);
lv_style_set_border_opa(&style, LV_OPA_40);
lv_style_set_border_width(&style, 2);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_shadow_width(&style, 8);
lv_style_set_shadow_color(&style, lv_palette_main(LV_PALETTE_GREY));
lv_style_set_shadow_ofs_y(&style, 8);
lv_style_set_outline_opa(&style, LV_OPA_COVER);
lv_style_set_outline_color(&style, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_text_color(&style, lv_color_white());
lv_style_set_pad_all(&style, 10);
lv_style_set_translate_y(&style_pr, 5);
lv_style_set_shadow_ofs_y(&style_pr, 3);
lv_style_set_bg_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 2));
lv_style_set_bg_grad_color(&style_pr, lv_palette_darken(LV_PALETTE_BLUE, 4));
lv_style_set_transition(&style_pr, &trans);
#
# Style a button from scratch
#
style.set_radius(3)
style.set_bg_opa(lv.OPA.COVER)
style.set_bg_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_bg_grad_color(lv.palette_darken(lv.PALETTE.BLUE, 2))
style.set_bg_grad_dir(lv.GRAD_DIR.VER)
style.set_border_opa(lv.OPA._40)
style.set_border_width(2)
style.set_border_color(lv.palette_main(lv.PALETTE.GREY))
style.set_shadow_width(8)
style.set_shadow_color(lv.palette_main(lv.PALETTE.GREY))
style.set_shadow_ofs_y(8)
style.set_outline_opa(lv.OPA.COVER)
style.set_outline_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_text_color(lv.color_white())
style.set_pad_all(10)
style_pr.set_translate_y(5)
style_pr.set_shadow_ofs_y(3)
style_pr.set_bg_color(lv.palette_darken(lv.PALETTE.BLUE, 2))
style_pr.set_bg_grad_color(lv.palette_darken(lv.PALETTE.BLUE, 4))
style_pr.set_transition(trans)
btn1 = lv.btn(lv.scr_act())
btn1.remove_style_all() # Remove the style coming from the␣
,→theme
btn1.add_style(style, 0)
btn1.add_style(style_pr, lv.STATE.PRESSED)
btn1.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
btn1.center()
label = lv.label(btn1)
label.set_text("Button")
label.center()
Gummy button
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES && LV_USE_BTN
/**
* Create a style transition on a button to act like a gum when clicked
*/
void lv_example_btn_3(void)
{
/*Properties to transition*/
static lv_style_prop_t props[] = {
LV_STYLE_TRANSFORM_WIDTH, LV_STYLE_TRANSFORM_HEIGHT, LV_STYLE_TEXT_LETTER_
,→SPACE, 0
};
#
# Create a style transition on a button to act like a gum when clicked
#
# Properties to transition
props = [lv.STYLE.TRANSFORM_WIDTH, lv.STYLE.TRANSFORM_HEIGHT, lv.STYLE.TEXT_LETTER_
,→SPACE, 0]
transition_dsc_def = lv.style_transition_dsc_t()
transition_dsc_def.init(props, lv.anim_t.path_overshoot, 250, 100, None)
label = lv.label(btn1)
label.set_text("Gum")
API
Functions
Variables
struct lv_btn_t
Public Members
lv_obj_t obj
Overview
The Button Matrix object is a lightweight way to display multiple buttons in rows and columns. Lightweight because the
buttons are not actually created but just virtually drawn on the fly. This way, one button use only eight extra bytes of
memory instead of the ~100-150 bytes a normal Button object plus the 100 or so bytes for the Label object.
The Button matrix is added to the default group (if one is set). Besides the Button matrix is an editable object to allow
selecting and clicking the buttons with encoder navigation too.
• LV_PART_MAIN The background of the button matrix, uses the typical background style properties. pad_row
and pad_column sets the space between the buttons.
• LV_PART_ITEMS The buttons all use the text and typical background style properties except translations and
transformations.
Usage
Button's text
There is a text on each button. To specify them a descriptor string array, called map, needs to be used. The map can be
set with lv_btnmatrix_set_map(btnm, my_map). The declaration of a map should look like const char
* map[] = {"btn1", "btn2", "btn3", NULL}. Note that the last element has to be either NULL or an
empty string ("")!
Use "\n" in the map to insert a line break. E.g. {"btn1", "btn2", "\n", "btn3", ""}. Each line's buttons
have their width calculated automatically. So in the example the first row will have 2 buttons each with 50% width and a
second row with 1 button having 100% width.
Control buttons
The buttons' width can be set relative to the other button in the same row with
lv_btnmatrix_set_btn_width(btnm, btn_id, width) E.g. in a line with two buttons: btnA,
width = 1 and btnB, width = 2, btnA will have 33 % width and btnB will have 66 % width. It's similar to how the
flex-grow property works in CSS. The width must be in the [1..15] range and the default width is 1.
In addition to the width, each button can be customized with the following parameters:
• LV_BTNMATRIX_CTRL_HIDDEN Makes a button hidden (hidden buttons still take up space in the layout, they
are just not visible or clickable)
• LV_BTNMATRIX_CTRL_NO_REPEAT Disable repeating when the button is long pressed
• LV_BTNMATRIX_CTRL_DISABLED Makes a button disabled Like LV_STATE_DISABLED on normal objects
• LV_BTNMATRIX_CTRL_CHECKABLE Enable toggling of a button. I.e. LV_STATE_CHECHED will be
added/removed as the button is clicked
• LV_BTNMATRIX_CTRL_CHECKED Make the button checked. It will use the LV_STATE_CHECHKED styles.
• LV_BTNMATRIX_CTRL_CLICK_TRIG Enabled: send LV_EVENT_VALUE_CHANGE on CLICK, Dis-
abled: send LV_EVENT_VALUE_CHANGE on PRESS
• LV_BTNMATRIX_CTRL_POPOVER Show the button label in a popover when pressing this key
• LV_BTNMATRIX_CTRL_RECOLOR Enable recoloring of button texts with #. E.g. "It's #ff0000 red#"
• LV_BTNMATRIX_CTRL_CUSTOM_1 Custom free to use flag
• LV_BTNMATRIX_CTRL_CUSTOM_2 Custom free to use flag
By default, all flags are disabled.
To set or clear a button's control attribute, use lv_btnmatrix_set_btn_ctrl(btnm,
btn_id, LV_BTNM_CTRL_...) and lv_btnmatrix_clear_btn_ctrl(btnm, btn_id,
LV_BTNMATRIX_CTRL_...) respectively. More LV_BTNM_CTRL_... values can be OR-ed
To set/clear the same control attribute for all buttons of a button matrix, use
lv_btnmatrix_set_btn_ctrl_all(btnm, LV_BTNM_CTRL_...) and
lv_btnmatrix_clear_btn_ctrl_all(btnm, LV_BTNMATRIX_CTRL_...).
The set a control map for a button matrix (similarly to the map for the text), use
lv_btnmatrix_set_ctrl_map(btnm, ctrl_map). An element of ctrl_map should look like
ctrl_map[0] = width | LV_BTNM_CTRL_NO_REPEAT | LV_BTNM_CTRL_CHECHKABLE. The
number of elements should be equal to the number of buttons (excluding newlines characters).
One check
The "One check" feature can be enabled with lv_btnmatrix_set_one_checked(btnm, true) to allow only
one button to be checked at a time.
Events
• LV_EVENT_VALUE_CHANGED Sent when a button is pressed/released or repeated after long press. The event
parameter is set to the ID of the pressed/released button.
• LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END are sent for the following types:
– LV_BTNMATRIX_DRAW_PART_BTN The individual buttons.
∗ part: LV_PART_ITEMS
∗ id:index of the button being drawn
∗ draw_area: the area of teh button
∗ rect_dsc
See the events of the Base object too.
lv_btnmatrix_get_selected_btn(btnm) returns the index of the most recently released or focused button
or LV_BTNMATRIX_BTN_NONE if no such button.
lv_btnmatrix_get_btn_text(btnm, btn_id) returns a pointer to the text of btn_idth button.
Learn more about Events.
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
static const char * btnm_map[] = {"1", "2", "3", "4", "5", "\n",
"6", "7", "8", "9", "0", "\n",
"Action1", "Action2", ""
};
void lv_example_btnmatrix_1(void)
{
lv_obj_t * btnm1 = lv_btnmatrix_create(lv_scr_act());
lv_btnmatrix_set_map(btnm1, btnm_map);
lv_btnmatrix_set_btn_width(btnm1, 10, 2); /*Make "Action1" twice as wide␣
,→as "Action2"*/
#endif
def event_handler(evt):
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.VALUE_CHANGED :
id = obj.get_selected_btn()
txt = obj.get_btn_text(id)
btnm1 = lv.btnmatrix(lv.scr_act())
btnm1.set_map(btnm_map)
btnm1.set_btn_width(10, 2) # Make "Action1" twice as wide as "Action2"
btnm1.set_btn_ctrl(10, lv.btnmatrix.CTRL.CHECKABLE)
(continues on next page)
#endif
Custom buttons
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
dsc->rect_dsc->shadow_width = 6;
dsc->rect_dsc->shadow_ofs_x = 3;
dsc->rect_dsc->shadow_ofs_y = 3;
dsc->label_dsc->color = lv_color_white();
}
/*Change the draw descriptor of the 3rd button*/
else if(dsc->id == 2) {
dsc->rect_dsc->radius = LV_RADIUS_CIRCLE;
if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) dsc->rect_dsc->bg_
,→color = lv_palette_darken(LV_PALETTE_RED, 3);
dsc->label_dsc->color = lv_color_white();
}
else if(dsc->id == 3) {
dsc->label_dsc->opa = LV_OPA_TRANSP; /*Hide the text if any*/
}
}
}
if(code == LV_EVENT_DRAW_PART_END) {
lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
lv_area_t a;
a.x1 = dsc->draw_area->x1 + (lv_area_get_width(dsc->draw_area) -␣
,→ header.w) / 2;
a.x2 = a.x1 + header.w - 1;
a.y1 = dsc->draw_area->y1 + (lv_area_get_height(dsc->draw_area) -␣
,→ header.h) / 2;
a.y2 = a.y1 + header.h - 1;
lv_draw_img_dsc_t img_draw_dsc;
lv_draw_img_dsc_init(&img_draw_dsc);
img_draw_dsc.recolor = lv_color_black();
if(lv_btnmatrix_get_selected_btn(obj) == dsc->id) img_draw_dsc.
,→recolor_opa = LV_OPA_30;
/**
* Add custom drawer to the button matrix to customize buttons one by one
*/
void lv_example_btnmatrix_2(void)
{
lv_obj_t * btnm = lv_btnmatrix_create(lv_scr_act());
lv_obj_add_event_cb(btnm, event_cb, LV_EVENT_ALL, NULL);
lv_obj_center(btnm);
}
#endif
img_star_argb = lv.img_dsc_t({
'data_size': len(png_data),
(continues on next page)
def event_cb(e):
code = e.get_code()
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if code == lv.EVENT.DRAW_PART_BEGIN:
# Change the draw descriptor the 2nd button
if dsc.id == 1:
dsc.rect_dsc.radius = 0
if obj.get_selected_btn() == dsc.id:
dsc.rect_dsc.bg_color = lv.palette_darken(lv.PALETTE.GREY, 3)
else:
dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.BLUE)
dsc.rect_dsc.shadow_width = 6
dsc.rect_dsc.shadow_ofs_x = 3
dsc.rect_dsc.shadow_ofs_y = 3
dsc.label_dsc.color = lv.color_white()
elif dsc.id == 2:
dsc.rect_dsc.radius = lv.RADIUS.CIRCLE
if obj.get_selected_btn() == dsc.id:
dsc.rect_dsc.bg_color = lv.palette_darken(lv.PALETTE.RED, 3)
else:
dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.RED)
dsc.label_dsc.color = lv.color_white()
elif dsc.id == 3:
dsc.label_dsc.opa = lv.OPA.TRANSP # Hide the text if any
if code == lv.EVENT.DRAW_PART_END:
# Add custom content to the 4th button when the button itself was drawn
if dsc.id == 3:
# LV_IMG_DECLARE(img_star)
header = lv.img_header_t()
res = lv.img.decoder_get_info(img_star_argb, header)
if res != lv.RES.OK:
print("error when getting image header")
return
else:
a = lv.area_t()
a.x1 = dsc.draw_area.x1 + (dsc.draw_area.get_width() - header.w) // 2
a.x2 = a.x1 + header.w - 1
a.y1 = dsc.draw_area.y1 + (dsc.draw_area.get_height() - header.h) // 2
a.y2 = a.y1 + header.h - 1
img_draw_dsc = lv.draw_img_dsc_t()
img_draw_dsc.init()
img_draw_dsc.recolor = lv.color_black()
if obj.get_selected_btn() == dsc.id:
img_draw_dsc.recolor_opa = lv.OPA._30
dsc.draw_ctx.img(img_draw_dsc, a, img_star_argb)
Pagination
#include "../../lv_examples.h"
#if LV_USE_BTNMATRIX && LV_BUILD_EXAMPLES
lv_btnmatrix_set_btn_ctrl(obj, i, LV_BTNMATRIX_CTRL_CHECKED);
}
}
/**
* Make a button group (pagination)
*/
void lv_example_btnmatrix_3(void)
{
static lv_style_t style_bg;
lv_style_init(&style_bg);
lv_style_set_pad_all(&style_bg, 0);
lv_style_set_pad_gap(&style_bg, 0);
lv_style_set_clip_corner(&style_bg, true);
lv_style_set_radius(&style_bg, LV_RADIUS_CIRCLE);
lv_style_set_border_width(&style_bg, 0);
static const char * map[] = {LV_SYMBOL_LEFT, "1", "2", "3", "4", "5", LV_SYMBOL_
,→ RIGHT, ""};
lv_btnmatrix_set_one_checked(btnm, true);
lv_btnmatrix_set_btn_ctrl(btnm, 1, LV_BTNMATRIX_CTRL_CHECKED);
lv_obj_center(btnm);
#endif
def event_cb(e):
obj = e.get_target()
id = obj.get_selected_btn()
if id == 0:
prev = True
else:
prev = False
if id == 6:
next = True
else:
next = False
if prev or next:
# Find the checked butto
for i in range(7):
if obj.has_btn_ctrl(i, lv.btnmatrix.CTRL.CHECKED):
break
if prev and i > 1:
i-=1
elif next and i < 5:
i+=1
obj.set_btn_ctrl(i, lv.btnmatrix.CTRL.CHECKED)
#
# Make a button group
#
style_bg = lv.style_t()
style_bg.init()
style_bg.set_pad_all(0)
style_bg.set_pad_gap(0)
(continues on next page)
style_btn = lv.style_t()
style_btn.init()
style_btn.set_radius(0)
style_btn.set_border_width(1)
style_btn.set_border_opa(lv.OPA._50)
style_btn.set_border_color(lv.palette_main(lv.PALETTE.GREY))
style_btn.set_border_side(lv.BORDER_SIDE.INTERNAL)
style_btn.set_radius(0)
btnm = lv.btnmatrix(lv.scr_act())
btnm.set_map(map)
btnm.add_style(style_bg, 0)
btnm.add_style(style_btn, lv.PART.ITEMS)
btnm.add_event_cb(event_cb, lv.EVENT.VALUE_CHANGED, None)
btnm.set_size(225, 35)
btnm.set_one_checked(True)
btnm.set_btn_ctrl(1, lv.btnmatrix.CTRL.CHECKED)
btnm.center()
API
Typedefs
Enums
enum [anonymous]
Type to store button control bits (disabled, hidden etc.) The first 3 bits are used to store the width
Values:
enumerator _LV_BTNMATRIX_WIDTH
Reserved to store the size units
enumerator LV_BTNMATRIX_CTRL_HIDDEN
Button hidden
enumerator LV_BTNMATRIX_CTRL_NO_REPEAT
Do not repeat press this button.
enumerator LV_BTNMATRIX_CTRL_DISABLED
Disable this button.
enumerator LV_BTNMATRIX_CTRL_CHECKABLE
The button can be toggled.
enumerator LV_BTNMATRIX_CTRL_CHECKED
Button is currently toggled (e.g. checked).
enumerator LV_BTNMATRIX_CTRL_CLICK_TRIG
1: Send LV_EVENT_VALUE_CHANGE on CLICK, 0: Send LV_EVENT_VALUE_CHANGE on PRESS
enumerator LV_BTNMATRIX_CTRL_POPOVER
Show a popover when pressing this key
enumerator LV_BTNMATRIX_CTRL_RECOLOR
Enable text recoloring with #color
enumerator _LV_BTNMATRIX_CTRL_RESERVED_1
Reserved for later use
enumerator _LV_BTNMATRIX_CTRL_RESERVED_2
Reserved for later use
enumerator LV_BTNMATRIX_CTRL_CUSTOM_1
Custom free to use flag
enumerator LV_BTNMATRIX_CTRL_CUSTOM_2
Custom free to use flag
enum lv_btnmatrix_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_btnmatrix_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_BTNMATRIX_DRAW_PART_BTN
The rectangle and label of buttons
Functions
LV_EXPORT_CONST_INT(LV_BTNMATRIX_BTN_NONE)
• btn_id -- 0 based index of the button to modify. (Not counting new lines)
• ctrl -- OR-ed attributs. E.g. LV_BTNMATRIX_CTRL_NO_REPEAT |
LV_BTNMATRIX_CTRL_CHECKABLE
void lv_btnmatrix_clear_btn_ctrl(lv_obj_t *obj, uint16_t btn_id, lv_btnmatrix_ctrl_t ctrl)
Clear the attributes of a button of the button matrix
Parameters
• obj -- pointer to button matrix object
• btn_id -- 0 based index of the button to modify. (Not counting new lines)
• ctrl -- OR-ed attributs. E.g. LV_BTNMATRIX_CTRL_NO_REPEAT |
LV_BTNMATRIX_CTRL_CHECKABLE
void lv_btnmatrix_set_btn_ctrl_all(lv_obj_t *obj, lv_btnmatrix_ctrl_t ctrl)
Set attributes of all buttons of a button matrix
Parameters
• obj -- pointer to a button matrix object
• ctrl -- attribute(s) to set from lv_btnmatrix_ctrl_t. Values can be ORed.
void lv_btnmatrix_clear_btn_ctrl_all(lv_obj_t *obj, lv_btnmatrix_ctrl_t ctrl)
Clear the attributes of all buttons of a button matrix
Parameters
• obj -- pointer to a button matrix object
• ctrl -- attribute(s) to set from lv_btnmatrix_ctrl_t. Values can be ORed.
• en -- true: set the attributes; false: clear the attributes
void lv_btnmatrix_set_btn_width(lv_obj_t *obj, uint16_t btn_id, uint8_t width)
Set a single button's relative width. This method will cause the matrix be regenerated and is a relatively expensive
operation. It is recommended that initial width be specified using lv_btnmatrix_set_ctrl_map and this
method only be used for dynamic changes.
Parameters
• obj -- pointer to button matrix object
• btn_id -- 0 based index of the button to modify.
• width -- relative width compared to the buttons in the same row. [1..7]
void lv_btnmatrix_set_one_checked(lv_obj_t *obj, bool en)
Make the button matrix like a selector widget (only one button may be checked at a time).
LV_BTNMATRIX_CTRL_CHECKABLE must be enabled on the buttons to be selected using
lv_btnmatrix_set_ctrl() or lv_btnmatrix_set_btn_ctrl_all().
Parameters
• obj -- pointer to a button matrix object
• en -- whether "one check" mode is enabled
const char **lv_btnmatrix_get_map(const lv_obj_t *obj)
Get the current map of a button matrix
Parameters obj -- pointer to a button matrix object
Variables
struct lv_btnmatrix_t
Public Members
lv_obj_t obj
lv_area_t *button_areas
lv_btnmatrix_ctrl_t *ctrl_bits
uint16_t btn_cnt
uint16_t row_cnt
uint16_t btn_id_sel
uint8_t one_check
Overview
A Canvas inherits from Image where the user can draw anything. Rectangles, texts, images, lines, arcs can be drawn here
using lvgl's drawing engine. Additionally "effects" can be applied, such as rotation, zoom and blur.
LV_PART_MAIN Uses the typical rectangle style properties and image style properties.
Usage
Buffer
The Canvas needs a buffer in which stores the drawn image. To assign a buffer to a Canvas, use
lv_canvas_set_buffer(canvas, buffer, width, height, LV_IMG_CF_...). Where buffer
is a static buffer (not just a local variable) to hold the image of the canvas. For example, static lv_color_t
buffer[LV_CANVAS_BUF_SIZE_TRUE_COLOR(width, height)]. LV_CANVAS_BUF_SIZE_...
macros help to determine the size of the buffer with different color formats.
The canvas supports all the built-in color formats like LV_IMG_CF_TRUE_COLOR or
LV_IMG_CF_INDEXED_2BIT. See the full list in the Color formats section.
Indexed colors
Drawing
Transformations
lv_canvas_transform() can be used to rotate and/or scale the image of an image and store the result on the
canvas. The function needs the following parameters:
• canvas pointer to a canvas object to store the result of the transformation.
• img pointer to an image descriptor to transform. Can be the image descriptor of another canvas too
(lv_canvas_get_img()).
• angle the angle of rotation (0..3600), 0.1 deg resolution
• zoom zoom factor (256: no zoom, 512: double size, 128: half size);
• offset_x offset X to tell where to put the result data on destination canvas
• offset_y offset X to tell where to put the result data on destination canvas
• pivot_x pivot X of rotation. Relative to the source canvas. Set to source width / 2 to rotate around the
center
• pivot_y pivot Y of rotation. Relative to the source canvas. Set to source height / 2 to rotate around the
center
• antialias true: apply anti-aliasing during the transformation. Looks better but slower.
Note that a canvas can't be rotated on itself. You need a source and destination canvas or image.
Blur
A given area of the canvas can be blurred horizontally with lv_canvas_blur_hor(canvas, &area, r) or
vertically with lv_canvas_blur_ver(canvas, &area, r). r is the radius of the blur (greater value means
more intensive burring). area is the area where the blur should be applied (interpreted relative to the canvas).
Events
No special events are sent by canvas objects. The same events are sent as for the
See the events of the Images too.
Learn more about Events.
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
void lv_example_canvas_1(void)
{
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.radius = 10;
rect_dsc.bg_opa = LV_OPA_COVER;
rect_dsc.bg_grad.dir = LV_GRAD_DIR_HOR;
rect_dsc.bg_grad.stops[0].color = lv_palette_main(LV_PALETTE_RED);
rect_dsc.bg_grad.stops[1].color = lv_palette_main(LV_PALETTE_BLUE);
rect_dsc.border_width = 2;
rect_dsc.border_opa = LV_OPA_90;
rect_dsc.border_color = lv_color_white();
rect_dsc.shadow_width = 5;
rect_dsc.shadow_ofs_x = 5;
rect_dsc.shadow_ofs_y = 5;
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.color = lv_palette_main(LV_PALETTE_ORANGE);
lv_obj_center(canvas);
lv_canvas_fill_bg(canvas, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER);
/*Test the rotation. It requires another buffer where the original image is␣
,→ stored.
*So copy the current image to buffer and rotate it to the canvas*/
static lv_color_t cbuf_tmp[CANVAS_WIDTH * CANVAS_HEIGHT];
memcpy(cbuf_tmp, cbuf, sizeof(cbuf_tmp));
lv_img_dsc_t img;
img.data = (void *)cbuf_tmp;
img.header.cf = LV_IMG_CF_TRUE_COLOR;
img.header.w = CANVAS_WIDTH;
img.header.h = CANVAS_HEIGHT;
#endif
_CANVAS_WIDTH = 200
_CANVAS_HEIGHT = 150
LV_IMG_ZOOM_NONE = 256
rect_dsc = lv.draw_rect_dsc_t()
rect_dsc.init()
rect_dsc.radius = 10
rect_dsc.bg_opa = lv.OPA.COVER
rect_dsc.bg_grad.dir = lv.GRAD_DIR.HOR
rect_dsc.bg_grad.stops[0].color = lv.palette_main(lv.PALETTE.RED)
rect_dsc.bg_grad.stops[1].color = lv.palette_main(lv.PALETTE.BLUE)
rect_dsc.border_width = 2
rect_dsc.border_opa = lv.OPA._90
rect_dsc.border_color = lv.color_white()
rect_dsc.shadow_width = 5
rect_dsc.shadow_ofs_x = 5
rect_dsc.shadow_ofs_y = 5
label_dsc = lv.draw_label_dsc_t()
label_dsc.init()
label_dsc.color = lv.palette_main(lv.PALETTE.YELLOW)
canvas = lv.canvas(lv.scr_act())
canvas.set_buffer(cbuf, _CANVAS_WIDTH, _CANVAS_HEIGHT, lv.img.CF.TRUE_COLOR)
canvas.center()
canvas.fill_bg(lv.palette_lighten(lv.PALETTE.GREY, 3), lv.OPA.COVER)
# Test the rotation. It requires another buffer where the original image is stored.
# So copy the current image to buffer and rotate it to the canvas
img = lv.img_dsc_t()
img.data = cbuf[:]
img.header.cf = lv.img.CF.TRUE_COLOR
img.header.w = _CANVAS_WIDTH
img.header.h = _CANVAS_HEIGHT
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Create a transparent canvas with Chroma keying and indexed color format (palette).
*/
void lv_example_canvas_2(void)
{
/*Create a button to better see the transparency*/
lv_btn_create(lv_scr_act());
lv_canvas_set_palette(canvas, 0, LV_COLOR_CHROMA_KEY);
lv_canvas_set_palette(canvas, 1, lv_palette_main(LV_PALETTE_RED));
c0.full = 0;
c1.full = 1;
}
#endif
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_CHROMA_KEY = lv.color_hex(0x00ff00)
#
# Create a transparent canvas with Chroma keying and indexed color format (palette).
#
c0.full = 0
c1.full = 1
canvas.fill_bg(c1, lv.OPA.COVER)
API
Functions
• offset_y -- offset X to tell where to put the result data on destination canvas
• pivot_x -- pivot X of rotation. Relative to the source canvas Set to source width /
2 to rotate around the center
• pivot_y -- pivot Y of rotation. Relative to the source canvas Set to source height /
2 to rotate around the center
• antialias -- apply anti-aliasing during the transformation. Looks better but slower.
void lv_canvas_blur_hor(lv_obj_t *canvas, const lv_area_t *area, uint16_t r)
Apply horizontal blur on the canvas
Parameters
• canvas -- pointer to a canvas object
• area -- the area to blur. If NULL the whole canvas will be blurred.
• r -- radius of the blur
void lv_canvas_blur_ver(lv_obj_t *canvas, const lv_area_t *area, uint16_t r)
Apply vertical blur on the canvas
Parameters
• canvas -- pointer to a canvas object
• area -- the area to blur. If NULL the whole canvas will be blurred.
• r -- radius of the blur
void lv_canvas_fill_bg(lv_obj_t *canvas, lv_color_t color, lv_opa_t opa)
Fill the canvas with color
Parameters
• canvas -- pointer to a canvas
• color -- the background color
• opa -- the desired opacity
void lv_canvas_draw_rect(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, const
lv_draw_rect_dsc_t *draw_dsc)
Draw a rectangle on the canvas
Parameters
• canvas -- pointer to a canvas object
• x -- left coordinate of the rectangle
• y -- top coordinate of the rectangle
• w -- width of the rectangle
• h -- height of the rectangle
• draw_dsc -- descriptor of the rectangle
void lv_canvas_draw_text(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, lv_coord_t max_w,
lv_draw_label_dsc_t *draw_dsc, const char *txt)
Draw a text on the canvas.
Parameters
Variables
struct lv_canvas_t
Public Members
lv_img_t img
lv_img_dsc_t dsc
Overview
The Checkbox object is created from a "tick box" and a label. When the Checkbox is clicked the tick box is toggled.
• LV_PART_MAIN The is the background of the Checkbox and it uses the text and all the typical background style
properties. pad_column adjusts the spacing between the tickbox and the label
• LV_PART_INDICATOR The "tick box" is a square that uses all the typical background style properties. By
default, its size is equal to the height of the main part's font. Padding properties make the tick box larger in the
respective directions.
The Checkbox is added to the default group (if it is set).
Usage
Text
The text can be modified with the lv_checkbox_set_text(cb, "New text") function and will be dynamically
allocated.
To set a static text, use lv_checkbox_set_static_text(cb, txt). This way, only a pointer to txt will be
stored. The text then shouldn't be deallocated while the checkbox exists.
You can manually check, un-check, and disable the Checkbox by using the common state add/clear function:
lv_obj_add_state(cb, LV_STATE_CHECKED); /*Make the chekbox checked*/
lv_obj_clear_state(cb, LV_STATE_CHECKED); /*MAke the checkbox unchecked*/
lv_obj_add_state(cb, LV_STATE_CHECKED | LV_STATE_DISABLED); /*Make the checkbox␣
,→checked and disabled*/
Events
Keys
Example
Simple Checkboxes
#include "../../lv_examples.h"
#if LV_USE_CHECKBOX && LV_BUILD_EXAMPLES
void lv_example_checkbox_1(void)
{
lv_obj_set_flex_flow(lv_scr_act(), LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(lv_scr_act(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_
,→FLEX_ALIGN_CENTER);
lv_obj_t * cb;
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Apple");
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Banana");
lv_obj_add_state(cb, LV_STATE_CHECKED);
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(lv_scr_act());
lv_checkbox_set_text(cb, "Lemon");
lv_obj_add_state(cb, LV_STATE_DISABLED);
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
cb = lv_checkbox_create(lv_scr_act());
lv_obj_add_state(cb, LV_STATE_CHECKED | LV_STATE_DISABLED);
lv_checkbox_set_text(cb, "Melon\nand a new line");
lv_obj_add_event_cb(cb, event_handler, LV_EVENT_ALL, NULL);
lv_obj_update_layout(cb);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
txt = obj.get_text()
if obj.get_state() & lv.STATE.CHECKED:
state = "Checked"
else:
state = "Unchecked"
print(txt + ":" + state)
lv.scr_act().set_flex_flow(lv.FLEX_FLOW.COLUMN)
lv.scr_act().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.
,→CENTER)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Apple")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
(continues on next page)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Lemon")
cb.add_state(lv.STATE.DISABLED)
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb = lv.checkbox(lv.scr_act())
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
cb.set_text("Melon")
cb.add_event_cb(event_handler, lv.EVENT.ALL, None)
cb.update_layout()
#include "../../lv_examples.h"
#if LV_USE_CHECKBOX && LV_BUILD_EXAMPLES
*active_id = lv_obj_get_index(act_cb);
/**
* Checkboxes as radio buttons
*/
void lv_example_checkbox_2(void)
{
/* The idea is to enable `LV_OBJ_FLAG_EVENT_BUBBLE` on checkboxes and process the
* `LV_EVENT_CLICKED` on the container.
* A variable is passed as event user data where the index of the active
* radiobutton is saved */
lv_style_init(&style_radio);
lv_style_set_radius(&style_radio, LV_RADIUS_CIRCLE);
lv_style_init(&style_radio_chk);
lv_style_set_bg_img_src(&style_radio_chk, NULL);
uint32_t i;
char buf[32];
}
/*Make the first checkbox checked*/
lv_obj_add_state(lv_obj_get_child(cont1, 0), LV_STATE_CHECKED);
#endif
API
Enums
enum lv_checkbox_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_checkbox_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_CHECKBOX_DRAW_PART_BOX
The tick box
Functions
Variables
struct lv_checkbox_t
Public Members
lv_obj_t obj
uint32_t static_txt
Overview
The drop-down list allows the user to select one value from a list.
The drop-down list is closed by default and displays a single value or a predefined text. When activated (by click on the
drop-down list), a list is created from which the user may select one option. When the user selects a new value, the list is
deleted again.
The Drop-down list is added to the default group (if it is set). Besides the Drop-down list is an editable object to allow
selecting an option with encoder navigation too.
The Dropdown widget is built from the elements: "button" and "list" (both not related to the button and list widgets)
Button
• LV_PART_MAIN The background of the button. Uses the typical background properties and text properties for
the text on it.
• LV_PART_INDICATOR Typically an arrow symbol that can be an image or a text (LV_SYMBOL).
The button goes to LV_STATE_CHECKED when it's opened.
List
• LV_PART_MAIN The list itself. Uses the typical background properties. max_height can be used to limit the
height of the list.
• LV_PART_SCROLLBAR The scrollbar background, border, shadow properties and width (for its own width) and
right padding for the spacing on the right.
• LV_PART_SELECTED Refers to the currently pressed, checked or pressed+checked option. Also uses the typical
background properties.
The list is hidden/shown on open/close. To add styles to it use lv_dropdown_get_list(dropdown) to get the
list object. For example:
Usage
Overview
Set options
Options are passed to the drop-down list as a string with lv_dropdown_set_options(dropdown, options).
Options should be separated by \n. For example: "First\nSecond\nThird". This string will be saved in the
drop-down list, so it can in a local variable.
The lv_dropdown_add_option(dropdown, "New option", pos) function inserts a new option to pos
index.
To save memory the options can set from a static(constant) string too with
lv_dropdown_set_options_static(dropdown, options). In this case the options string should
be alive while the drop-down list exists and lv_dropdown_add_option can't be used
You can select an option manually with lv_dropdown_set_selected(dropdown, id), where id is the index
of an option.
Direction
The list can be created on any side. The default LV_DIR_BOTTOM can be modified by
lv_dropdown_set_dir(dropdown, LV_DIR_LEFT/RIGHT/UP/BOTTOM) function.
If the list would be vertically out of the screen, it will be aligned to the edge.
Symbol
A symbol (typically an arrow) can be added to the dropdown list with lv_dropdown_set_symbol(dropdown,
LV_SYMBOL_...)
If the direction of the drop-down list is LV_DIR_LEFT the symbol will be shown on the left, otherwise on the right.
Show selected
The main part can either show the selected option or a static text. If a static is set with
lv_dropdown_set_text(dropdown, "Some text") it will be shown regardless to th selected op-
tion. If the text is NULL the selected option is displayed on the button.
Manually open/close
To manually open or close the drop-down list the lv_dropdown_open/close(dropdown) function can be used.
Events
Apart from the Generic events, the following Special events are sent by the drop-down list:
• LV_EVENT_VALUE_CHANGED Sent when the new option is selected or the list is opened/closed.
• LV_EVENT_CANCEL Sent when the list is closed
• LV_EVENT_READY Sent when the list is opened
See the events of the Base object too.
Learn more about Events.
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
void lv_example_dropdown_1(void)
{
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
option = " "*10 # should be large enough to store the option
obj.get_selected_str(option, len(option))
# .strip() removes trailing spaces
print("Option: \"%s\"" % option.strip())
dd.align(lv.ALIGN.TOP_MID, 0, 20)
dd.add_event_cb(event_handler, lv.EVENT.ALL, None)
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
/**
* Create a drop down, up, left and right menus
*/
void lv_example_dropdown_2(void)
{
static const char * opts = "Apple\n"
"Banana\n"
"Orange\n"
"Melon";
(continues on next page)
lv_obj_t * dd;
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_obj_align(dd, LV_ALIGN_TOP_MID, 0, 10);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_BOTTOM);
lv_dropdown_set_symbol(dd, LV_SYMBOL_UP);
lv_obj_align(dd, LV_ALIGN_BOTTOM_MID, 0, -10);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_RIGHT);
lv_dropdown_set_symbol(dd, LV_SYMBOL_RIGHT);
lv_obj_align(dd, LV_ALIGN_LEFT_MID, 10, 0);
dd = lv_dropdown_create(lv_scr_act());
lv_dropdown_set_options_static(dd, opts);
lv_dropdown_set_dir(dd, LV_DIR_LEFT);
lv_dropdown_set_symbol(dd, LV_SYMBOL_LEFT);
lv_obj_align(dd, LV_ALIGN_RIGHT_MID, -10, 0);
}
#endif
#
# Create a drop down, up, left and right menus
#
opts = "\n".join([
"Apple",
"Banana",
"Orange",
"Melon",
"Grape",
"Raspberry"])
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.align(lv.ALIGN.TOP_MID, 0, 10)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.set_dir(lv.DIR.BOTTOM)
dd.set_symbol(lv.SYMBOL.UP)
dd.align(lv.ALIGN.BOTTOM_MID, 0, -10)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
dd.set_dir(lv.DIR.RIGHT)
dd.set_symbol(lv.SYMBOL.RIGHT)
dd.align(lv.ALIGN.LEFT_MID, 10, 0)
dd = lv.dropdown(lv.scr_act())
dd.set_options_static(opts)
(continues on next page)
Menu
#include "../../lv_examples.h"
#if LV_USE_DROPDOWN && LV_BUILD_EXAMPLES
/**
* Create a menu from a drop-down list and show some drop-down list features and␣
,→styling
*/
void lv_example_dropdown_3(void)
{
/*Create a drop down list*/
lv_obj_t * dropdown = lv_dropdown_create(lv_scr_act());
lv_obj_align(dropdown, LV_ALIGN_TOP_LEFT, 10, 10);
lv_dropdown_set_options(dropdown, "New project\n"
"New file\n"
"Save\n"
"Save as ...\n"
"Open project\n"
"Recent projects\n"
"Preferences\n"
"Exit");
/*Use a custom image as down icon and flip it when the list is opened*/
LV_IMG_DECLARE(img_caret_down)
lv_dropdown_set_symbol(dropdown, &img_caret_down);
lv_obj_set_style_transform_angle(dropdown, 1800, LV_PART_INDICATOR | LV_STATE_
,→CHECKED);
#endif
img_caret_down_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def event_cb(e):
dropdown = e.get_target()
option = " "*64 # should be large enough to store the option
dropdown.get_selected_str(option, len(option))
print(option.strip() +" is selected")
#
# Create a menu from a drop-down list and show some drop-down list features and␣
,→styling
# Use a custom image as down icon and flip it when the list is opened
# LV_IMG_DECLARE(img_caret_down)
dropdown.set_symbol(img_caret_down_argb)
dropdown.set_style_transform_angle(1800, lv.PART.INDICATOR | lv.STATE.CHECKED)
API
Functions
LV_EXPORT_CONST_INT(LV_DROPDOWN_POS_LAST)
Note: angle and zoom transformation can be applied if the symbol is an image. E.g. when drop down is checked
(opened) rotate the symbol by 180 degree
Parameters
• obj -- pointer to drop-down list object
• symbol -- a text like LV_SYMBOL_DOWN, an image (pointer or path) or NULL to not draw
symbol icon
Returns
the options separated by '
'-s (E.g. "Option1\nOption2\nOption3")
uint16_t lv_dropdown_get_selected(const lv_obj_t *obj)
Get the index of the selected option
Parameters obj -- pointer to drop-down list object
Returns index of the selected option (0 ... number of option - 1);
uint16_t lv_dropdown_get_option_cnt(const lv_obj_t *obj)
Get the total number of options
Parameters obj -- pointer to drop-down list object
Returns the total number of options in the list
void lv_dropdown_get_selected_str(const lv_obj_t *obj, char *buf, uint32_t buf_size)
Get the current selected option as a string
Parameters
• obj -- pointer to drop-down object
• buf -- pointer to an array to store the string
• buf_size -- size of buf in bytes. 0: to ignore it.
int32_t lv_dropdown_get_option_index(lv_obj_t *obj, const char *option)
Get the index of an option.
Parameters
• obj -- pointer to drop-down object
• option -- an option as string
Returns index of option in the list of all options. -1 if not found.
const char *lv_dropdown_get_symbol(lv_obj_t *obj)
Get the symbol on the drop-down list. Typically a down caret or arrow.
Parameters obj -- pointer to drop-down list object
Returns the symbol or NULL if not enabled
bool lv_dropdown_get_selected_highlight(lv_obj_t *obj)
Get whether the selected option in the list should be highlighted or not
Parameters obj -- pointer to drop-down list object
Returns true: highlight enabled; false: disabled
lv_dir_t lv_dropdown_get_dir(const lv_obj_t *obj)
Get the direction of the drop-down list
Parameters obj -- pointer to a drop-down list object
Returns LV_DIR_LEF/RIGHT/TOP/BOTTOM
Variables
struct lv_dropdown_t
Public Members
lv_obj_t obj
lv_obj_t *list
The dropped down list
char *options
Options in a '
' separated list
uint16_t option_cnt
Number of options
uint16_t sel_opt_id
Index of the currently selected option
uint16_t sel_opt_id_orig
Store the original index on focus
uint16_t pr_opt_id
Index of the currently pressed option
lv_dir_t dir
Direction in which the list should open
uint8_t static_txt
1: Only a pointer is saved in options
uint8_t selected_highlight
1: Make the selected option highlighted in the list
struct lv_dropdown_list_t
Public Members
lv_obj_t obj
lv_obj_t *dropdown
Overview
Images are the basic object to display images from flash (as arrays) or from files. Images can display symbols
(LV_SYMBOL_...) too.
Using the Image decoder interface custom image formats can be supported as well.
• LV_PART_MAIN A background rectangle that uses the typical background style properties and the image itself
using the image style properties.
Usage
Image source
Label as an image
Images and labels are sometimes used to convey the same thing. For example, to describe what a button does. Therefore,
images and labels are somewhat interchangeable, that is the images can display texts by using LV_SYMBOL_DUMMY as
the prefix of the text. For example, lv_img_set_src(img, LV_SYMBOL_DUMMY "Some text").
Transparency
The internal (variable) and external images support 2 transparency handling methods:
• Chroma-keying - Pixels with LV_COLOR_CHROMA_KEY (lv_conf.h) color will be transparent.
• Alpha byte - An alpha byte is added to every pixel that contains the pixel's opacity
Besides the True color (RGB) color format, the following formats are supported:
• Indexed - Image has a palette.
• Alpha indexed - Only alpha values are stored.
These options can be selected in the image converter. To learn more about the color formats, read the Images section.
Recolor
A color can be mixed with every pixel of an image with a given intensity. This can be useful to show different states
(checked, inactive, pressed, etc.) of an image without storing more versions of the same image. This feature can be enabled
in the style by setting img_recolor_opa between LV_OPA_TRANSP (no recolor, value: 0) and LV_OPA_COVER
(full recolor, value: 255). The default value is LV_OPA_TRANSP so this feature is disabled.
The color to mix is set by img_recolor.
Auto-size
If the width or height of the image object is set to LV_SIZE_CONTENT the object's size will be set according to the size
of the image source in the respective direction.
Mosaic
If the object's size is greater than the image size in any directions, then the image will be repeated like a mosaic. This
allows creation a large image from only a very narrow source. For example, you can have a 300 x 5 image with a special
gradient and set it as a wallpaper using the mosaic feature.
Offset
Transformations
Using the lv_img_set_zoom(img, factor) the images will be zoomed. Set factor to 256 or
LV_IMG_ZOOM_NONE to disable zooming. A larger value enlarges the images (e.g. 512 double size), a smaller value
shrinks it (e.g. 128 half size). Fractional scale works as well. E.g. 281 for 10% enlargement.
To rotate the image use lv_img_set_angle(img, angle). Angle has 0.1 degree precision, so for 45.8° set 458.
The transform_zoom and transform_angle style properties are also used to determine the final zoom and angle.
By default, the pivot point of the rotation is the center of the image. It can be changed with
lv_img_set_pivot(img, pivot_x, pivot_y). 0;0 is the top left corner.
The quality of the transformation can be adjusted with lv_img_set_antialias(img, true/false). With
enabled anti-aliasing the transformations are higher quality but slower.
The transformations require the whole image to be available. Therefore indexed images (LV_IMG_CF_INDEXED_.
..), alpha only images (LV_IMG_CF_ALPHA_...) or images from files can not be transformed. In other words
transformations work only on true color images stored as C array, or if a custom Image decoder returns the whole image.
Note that the real coordinates of image objects won't change during transformation. That is lv_obj_get_width/
height/x/y() will return the original, non-zoomed coordinates.
IMPORTANT The transformation of the image is independent of the transformation properties coming from styles.
(See here). The main differences are that pure image widget transformation
• doesn't transform the children of the image widget
• image is transformed directly without creating an intermediate layer (buffer) to snapshot the widget
Size mode
By default, when the image is zoomed or rotated the real coordinates of the image object are not changed. The larger
content simply overflows the object's boundaries. It also means the layouts are not affected the by the transformations.
If you need the object size to be updated to the transformed size set lv_img_set_size_mode(img,
LV_IMG_SIZE_MODE_REAL). (The previous mode is the default and called LV_IMG_SIZE_MODE_VIRTUAL).
In this case if the width/height of the object is set to LV_SIZE_CONTENT the object's size will be set to the zoomed
and rotated size. If an explicit size is set then the overflowing content will be cropped.
Rounded image
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
void lv_example_img_1(void)
{
LV_IMG_DECLARE(img_cogwheel_argb);
lv_obj_t * img1 = lv_img_create(lv_scr_act());
lv_img_set_src(img1, &img_cogwheel_argb);
lv_obj_align(img1, LV_ALIGN_CENTER, 0, -20);
lv_obj_set_size(img1, 200, 200);
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
img1 = lv.img(lv.scr_act())
img1.set_src(img_cogwheel_argb)
img1.align(lv.ALIGN.CENTER, 0, -20)
img1.set_size(200, 200)
img2 = lv.img(lv.scr_act())
img2.set_src(lv.SYMBOL.OK + "Accept")
img2.align_to(img1, lv.ALIGN.OUT_BOTTOM_MID, 0, 20)
Image recoloring
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Demonstrate runtime image re-coloring
*/
void lv_example_img_2(void)
{
/*Create 4 sliders to adjust RGB color and re-color intensity*/
red_slider = create_slider(lv_palette_main(LV_PALETTE_RED));
green_slider = create_slider(lv_palette_main(LV_PALETTE_GREEN));
blue_slider = create_slider(lv_palette_main(LV_PALETTE_BLUE));
intense_slider = create_slider(lv_palette_main(LV_PALETTE_GREY));
lv_slider_get_value(blue_slider));
lv_opa_t intense = lv_slider_get_value(intense_slider);
lv_obj_set_style_img_recolor_opa(img1, intense, 0);
lv_obj_set_style_img_recolor(img1, color, 0);
}
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
def create_slider(color):
slider = lv.slider(lv.scr_act())
slider.set_range(0, 255)
slider.set_size(10, 200)
slider.set_style_bg_color(color, lv.PART.KNOB)
slider.set_style_bg_color(color.color_darken(lv.OPA._40), lv.PART.INDICATOR)
slider.add_event_cb(slider_event_cb, lv.EVENT.VALUE_CHANGED, None)
return slider
def slider_event_cb(e):
# Recolor the image based on the sliders' values
color = lv.color_make(red_slider.get_value(), green_slider.get_value(), blue_
,→slider.get_value())
intense = intense_slider.get_value()
img1.set_style_img_recolor_opa(intense, 0)
img1.set_style_img_recolor(color, 0)
#
# Demonstrate runtime image re-coloring
#
# Create 4 sliders to adjust RGB color and re-color intensity
red_slider = create_slider(lv.palette_main(lv.PALETTE.RED))
green_slider = create_slider(lv.palette_main(lv.PALETTE.GREEN))
blue_slider = create_slider(lv.palette_main(lv.PALETTE.BLUE))
intense_slider = create_slider(lv.palette_main(lv.PALETTE.GREY))
red_slider.set_value(lv.OPA._20, lv.ANIM.OFF)
green_slider.set_value(lv.OPA._90, lv.ANIM.OFF)
blue_slider.set_value(lv.OPA._60, lv.ANIM.OFF)
intense_slider.set_value(lv.OPA._50, lv.ANIM.OFF)
red_slider.align(lv.ALIGN.LEFT_MID, 25, 0)
green_slider.align_to(red_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
blue_slider.align_to(green_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
intense_slider.align_to(blue_slider, lv.ALIGN.OUT_RIGHT_MID, 25, 0)
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
/**
* Show transformations (zoom and rotation) using a pivot point.
*/
void lv_example_img_3(void)
{
LV_IMG_DECLARE(img_cogwheel_argb);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
lv_anim_set_exec_cb(&a, set_angle);
lv_anim_set_values(&a, 0, 3600);
lv_anim_set_time(&a, 5000);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, set_zoom);
lv_anim_set_values(&a, 128, 256);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
(continues on next page)
img_cogwheel_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Show transformations (zoom and rotation) using a pivot point.
#
a1 = lv.anim_t()
a1.init()
a1.set_var(img)
a1.set_custom_exec_cb(lambda a,val: set_angle(img,val))
a1.set_values(0, 3600)
a1.set_time(5000)
a1.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a1)
a2 = lv.anim_t()
a2.init()
a2.set_var(img)
a2.set_custom_exec_cb(lambda a,val: set_zoom(img,val))
a2.set_values(128, 256)
a2.set_time(5000)
a2.set_playback_time(3000)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
lv.anim_t.start(a2)
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
/**
* Image styling and offset
*/
void lv_example_img_4(void)
{
LV_IMG_DECLARE(img_skew_strip);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, img);
lv_anim_set_exec_cb(&a, ofs_y_anim);
lv_anim_set_values(&a, 0, 100);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 500);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_start(&a);
#endif
img_skew_strip = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Image styling and offset
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.palette_main(lv.PALETTE.YELLOW))
style.set_bg_opa(lv.OPA.COVER)
style.set_img_recolor_opa(lv.OPA.COVER)
style.set_img_recolor(lv.color_black())
img = lv.img(lv.scr_act())
img.add_style(style, 0)
img.set_src(img_skew_strip)
img.set_size(150, 100)
img.center()
a = lv.anim_t()
a.init()
a.set_var(img)
a.set_values(0, 100)
a.set_time(3000)
a.set_playback_time(500)
a.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a.set_custom_exec_cb(lambda a,val: ofs_y_anim(img,val))
lv.anim_t.start(a)
API
Typedefs
Enums
enum [anonymous]
Image size mode, when image size and object size is different
Values:
enumerator LV_IMG_SIZE_MODE_VIRTUAL
Zoom doesn't affect the coordinates of the object, however if zoomed in the image is drawn out of the its
coordinates. The layout's won't change on zoom
enumerator LV_IMG_SIZE_MODE_REAL
If the object size is set to SIZE_CONTENT, then object size equals zoomed image size. It causes layout
recalculation. If the object size is set explicitly, the image will be cropped when zoomed in.
Functions
Variables
struct lv_img_t
#include <lv_img.h> Data of image
Public Members
lv_obj_t obj
lv_point_t offset
lv_coord_t w
lv_coord_t h
uint16_t angle
lv_point_t pivot
uint16_t zoom
uint8_t src_type
uint8_t cf
uint8_t antialias
uint8_t obj_size_mode
Overview
• LV_PART_MAIN Uses all the typical background properties and the text properties. The padding values can be
used to add space between the text and the background.
• LV_PART_SCROLLBAR The scrollbar that is shown when the text is larger than the widget's size.
• LV_PART_SELECTED Tells the style of the selected text. Only text_color and bg_color style properties
can be used.
Usage
Set text
You can set the text on a label at runtime with lv_label_set_text(label, "New text"). This will allocate
a buffer dynamically, and the provided string will be copied into that buffer. Therefore, you don't need to keep the text
you pass to lv_label_set_text in scope after that function returns.
With lv_label_set_text_fmt(label, "Value: %d", 15) printf formatting can be used to set the text.
Labels are able to show text from a static character buffer. To do so, use lv_label_set_text_static(label,
"Text"). In this case, the text is not stored in the dynamic memory and the given buffer is used directly instead. This
means that the array can't be a local variable which goes out of scope when the function exits. Constant strings are safe
to use with lv_label_set_text_static (except when used with LV_LABEL_LONG_DOT, as it modifies the
buffer in-place), as they are stored in ROM memory, which is always accessible.
Newline
Newline characters are handled automatically by the label object. You can use \n to make a line break. For example:
"line1\nline2\n\nline4"
Long modes
By default, the width and height of the label is set to LV_SIZE_CONTENT. Therefore, the size of the label is automatically
expanded to the text size. Otherwise, if the width or height are explicitly set (using e.g.lv_obj_set_width or a
layout), the lines wider than the label's width can be manipulated according to several long mode policies. Similarly, the
policies can be applied if the height of the text is greater than the height of the label.
• LV_LABEL_LONG_WRAP Wrap too long lines. If the height is LV_SIZE_CONTENT the label's height will be
expanded, otherwise the text will be clipped. (Default)
• LV_LABEL_LONG_DOT Replaces the last 3 characters from bottom right corner of the label with dots (.)
• LV_LABEL_LONG_SCROLL If the text is wider than the label scroll it horizontally back and forth. If it's higher,
scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence.
• LV_LABEL_LONG_SCROLL_CIRCULAR If the text is wider than the label scroll it horizontally continuously.
If it's higher, scroll vertically. Only one direction is scrolled and horizontal scrolling has higher precedence.
• LV_LABEL_LONG_CLIP Simply clip the parts of the text outside the label.
You can specify the long mode with lv_label_set_long_mode(label, LV_LABEL_LONG_...)
Note that LV_LABEL_LONG_DOT manipulates the text buffer in-place in order to add/remove the dots. When
lv_label_set_text or lv_label_set_array_text are used, a separate buffer is allocated and this im-
plementation detail is unnoticed. This is not the case with lv_label_set_text_static. The buffer you pass to
lv_label_set_text_static must be writable if you plan to use LV_LABEL_LONG_DOT.
Text recolor
In the text, you can use commands to recolor parts of the text. For example: "Write a #ff0000 red# word".
This feature can be enabled individually for each label by lv_label_set_recolor() function, recoloring is only
supported when the text wrapped with ##ff0000 ... #sintax is in one line, it is not supported in wrapped text, see
example Line wrap, recoloring and scrolling.
Text selection
If enabled by LV_LABEL_TEXT_SELECTION part of the text can be selected. It's similar to when
you use your mouse on a PC to select a text. The whole mechanism (click and select the text
as you drag your finger/mouse) is implemented in Text area and the Label widget only allows man-
ual text selection with lv_label_get_text_selection_start(label, start_char_index) and
lv_label_get_text_selection_start(label, end_char_index).
LVGL can efficiently handle very long (e.g. > 40k characters) labels by saving some extra data (~12 bytes) to speed up
drawing. To enable this feature, set LV_LABEL_LONG_TXT_HINT 1 in lv_conf.h.
Symbols
The labels can display symbols alongside letters (or on their own). Read the Font section to learn more about the symbols.
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Show line wrap, re-color, line align and text scrolling.
*/
void lv_example_label_1(void)
{
lv_obj_t * label1 = lv_label_create(lv_scr_act());
lv_label_set_long_mode(label1, LV_LABEL_LONG_WRAP); /*Break the long lines*/
lv_label_set_recolor(label1, true); /*Enable re-coloring by␣
,→commands in the text*/
lv_obj_set_width(label2, 150);
lv_label_set_text(label2, "It is a circularly scrolling text. ");
lv_obj_align(label2, LV_ALIGN_CENTER, 0, 40);
}
#endif
#
# Show line wrap, re-color, line align and text scrolling.
#
label1 = lv.label(lv.scr_act())
label1.set_long_mode(lv.label.LONG.WRAP) # Break the long lines*/
label1.set_recolor(True) # Enable re-coloring by commands in the␣
,→text
label1.set_style_text_align(lv.ALIGN.CENTER, 0)
label1.align(lv.ALIGN.CENTER, 0, -40)
label2 = lv.label(lv.scr_act())
label2.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR) # Circular scroll
label2.set_width(150)
label2.set_text("It is a circularly scrolling text. ")
label2.align(lv.ALIGN.CENTER, 0, 40)
Text shadow
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Create a fake text shadow
*/
void lv_example_label_2(void)
{
/*Create a style for the shadow*/
static lv_style_t style_shadow;
lv_style_init(&style_shadow);
lv_style_set_text_opa(&style_shadow, LV_OPA_30);
lv_style_set_text_color(&style_shadow, lv_color_black());
#endif
#
# Create a fake text shadow
#
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES && LV_FONT_DEJAVU_16_PERSIAN_HEBREW && LV_FONT_
,→SIMSUN_16_CJK && LV_USE_BIDI
/**
* Show mixed LTR, RTL and Chinese label
*/
void lv_example_label_3(void)
{
lv_obj_t * ltr_label = lv_label_create(lv_scr_act());
lv_label_set_text(ltr_label, "In modern terminology, a microcontroller is similar␣
,→to a system on a chip (SoC).");
#endif
import fs_driver
#
# Show mixed LTR, RTL and Chinese label
#
ltr_label = lv.label(lv.scr_act())
ltr_label.set_text("In modern terminology, a microcontroller is similar to a system␣
,→on a chip (SoC).")
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
try:
ltr_label.set_style_text_font(ltr_label, lv.font_montserrat_16, 0)
except:
font_montserrat_16 = lv.font_load("S:../../assets/font/montserrat-16.fnt")
ltr_label.set_style_text_font(font_montserrat_16, 0)
ltr_label.set_width(310)
(continues on next page)
rtl_label = lv.label(lv.scr_act())
rtl_label.set_text(", : ) CPU - Central␣
,→Processing Unit).")
rtl_label.set_style_base_dir(lv.BASE_DIR.RTL, 0)
rtl_label.set_style_text_font(lv.font_dejavu_16_persian_hebrew, 0)
rtl_label.set_width(310)
rtl_label.align(lv.ALIGN.LEFT_MID, 5, 0)
font_simsun_16_cjk = lv.font_load("S:../../assets/font/lv_font_simsun_16_cjk.fnt")
cz_label = lv.label(lv.scr_act())
cz_label.set_style_text_font(font_simsun_16_cjk, 0)
cz_label.set_text(" Embedded System \n ")
cz_label.set_width(310)
cz_label.align(lv.ALIGN.BOTTOM_LEFT, 5, -5)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_USE_CANVAS && LV_BUILD_EXAMPLES && LV_DRAW_COMPLEX
}
else if(code == LV_EVENT_DRAW_MAIN_END) {
lv_draw_mask_free_param(&m);
lv_draw_mask_remove_id(mask_id);
}
}
/**
* Draw label with gradient color
*/
void lv_example_label_4(void)
{
(continues on next page)
/*Draw a label to the canvas. The result "image" will be used as mask*/
lv_draw_label_dsc_t label_dsc;
lv_draw_label_dsc_init(&label_dsc);
label_dsc.color = lv_color_white();
label_dsc.align = LV_TEXT_ALIGN_CENTER;
lv_canvas_draw_text(canvas, 5, 5, MASK_WIDTH, &label_dsc, "Text with gradient");
#endif
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_
,→SCROLL_CIRCULAR`
* long mode.
*/
void lv_example_label_5(void)
{
static lv_anim_t animation_template;
static lv_style_t label_style;
lv_anim_init(&animation_template);
lv_anim_set_delay(&animation_template, 1000); /*Wait 1 second to start␣
,→the first scroll*/
lv_anim_set_repeat_delay(&animation_template,
(continues on next page)
lv_obj_set_width(label1, 150);
lv_label_set_text(label1, "It is a circularly scrolling text. ");
lv_obj_align(label1, LV_ALIGN_CENTER, 0, 40);
lv_obj_add_style(label1, &label_style, LV_STATE_DEFAULT); /*Add the␣
,→style to the label*/
#endif
#
# Show customizing the circular scrolling animation of a label with `LV_LABEL_LONG_
,→SCROLL_CIRCULAR` long mode.
label1 = lv.label(lv.scr_act())
label1.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR) # Circular scroll
label1.set_width(150)
label1.set_text("It is a circularly scrolling text. ")
label1.align(lv.ALIGN.CENTER, 0, 40)
API
Typedefs
Enums
enum [anonymous]
Long mode behaviors. Used in 'lv_label_ext_t'
Values:
enumerator LV_LABEL_LONG_WRAP
Keep the object width, wrap the too long lines and expand the object height
enumerator LV_LABEL_LONG_DOT
Keep the size and write dots at the end if the text is too long
enumerator LV_LABEL_LONG_SCROLL
Keep the size and roll the text back and forth
enumerator LV_LABEL_LONG_SCROLL_CIRCULAR
Keep the size and roll the text circularly
enumerator LV_LABEL_LONG_CLIP
Keep the size and clip the text out of it
Functions
LV_EXPORT_CONST_INT(LV_LABEL_DOT_NUM)
LV_EXPORT_CONST_INT(LV_LABEL_POS_LAST)
LV_EXPORT_CONST_INT(LV_LABEL_TEXT_SELECTION_OFF)
Returns The index of the letter on the 'pos_p' point (E.g. on 0;0 is the 0. letter if aligned to the left)
Expressed in character index and not byte index (different in UTF-8)
bool lv_label_is_char_under_pos(const lv_obj_t *obj, lv_point_t *pos)
Check if a character is drawn under a point.
Parameters
• obj -- pointer to a label object
• pos -- Point to check for character under
Returns whether a character is drawn under the point
uint32_t lv_label_get_text_selection_start(const lv_obj_t *obj)
Get the selection start index.
Parameters obj -- pointer to a label object.
Returns selection start index. LV_LABEL_TEXT_SELECTION_OFF if nothing is selected.
uint32_t lv_label_get_text_selection_end(const lv_obj_t *obj)
Get the selection end index.
Parameters obj -- pointer to a label object.
Returns selection end index. LV_LABEL_TXT_SEL_OFF if nothing is selected.
void lv_label_ins_text(lv_obj_t *obj, uint32_t pos, const char *txt)
Insert a text to a label. The label text can not be static.
Parameters
• obj -- pointer to a label object
• pos -- character index to insert. Expressed in character index and not byte index. 0: before
first char. LV_LABEL_POS_LAST: after last char.
• txt -- pointer to the text to insert
void lv_label_cut_text(lv_obj_t *obj, uint32_t pos, uint32_t cnt)
Delete characters from a label. The label text can not be static.
Parameters
• obj -- pointer to a label object
• pos -- character index from where to cut. Expressed in character index and not byte index. 0:
start in from of the first character
• cnt -- number of characters to cut
Variables
struct lv_label_t
Public Members
lv_obj_t obj
char *text
char *tmp_ptr
char tmp[LV_LABEL_DOT_NUM + 1]
uint32_t dot_end
lv_draw_label_hint_t hint
uint32_t sel_start
uint32_t sel_end
lv_point_t offset
lv_label_long_mode_t long_mode
uint8_t static_txt
uint8_t recolor
uint8_t expand
uint8_t dot_tmp_alloc
Overview
The Line object is capable of drawing straight lines between a set of points.
• LV_PART_MAIN uses all the typical background properties and line style properties.
Usage
Set points
The points have to be stored in an lv_point_t array and passed to the object by the
lv_line_set_points(lines, point_array, point_cnt) function.
Auto-size
By default, the Line's width and height are set to LV_SIZE_CONTENT. This means it will automatically set its size to
fit all the points. If the size is set explicitly, parts on the line may not be visible.
Invert y
By default, the y == 0 point is in the top of the object. It might be counter-intuitive in some cases so the y coordinates
can be inverted with lv_line_set_y_invert(line, true). In this case, y == 0 will be the bottom of the
object. y invert is disabled by default.
Events
Keys
Example
Simple Line
#include "../../lv_examples.h"
#if LV_USE_LINE && LV_BUILD_EXAMPLES
void lv_example_line_1(void)
{
/*Create an array for the points of the line*/
static lv_point_t line_points[] = { {5, 5}, {70, 70}, {120, 10}, {180, 60}, {240,␣
,→10} };
#endif
# Create style
style_line = lv.style_t()
style_line.init()
style_line.set_line_width(8)
style_line.set_line_color(lv.palette_main(lv.PALETTE.BLUE))
style_line.set_line_rounded(True)
API
Functions
• points -- an array of points. Only the address is saved, so the array needs to be alive while
the line exists
• point_num -- number of points in 'point_a'
void lv_line_set_y_invert(lv_obj_t *obj, bool en)
Enable (or disable) the y coordinate inversion. If enabled then y will be subtracted from the height of the object,
therefore the y = 0 coordinate will be on the bottom.
Parameters
• obj -- pointer to a line object
• en -- true: enable the y inversion, false:disable the y inversion
bool lv_line_get_y_invert(const lv_obj_t *obj)
Get the y inversion attribute
Parameters obj -- pointer to a line object
Returns true: y inversion is enabled, false: disabled
Variables
struct lv_line_t
Public Members
lv_obj_t obj
uint16_t point_num
Number of points in 'point_array'
uint8_t y_inv
1: y == 0 will be on the bottom
Overview
Roller allows you to simply select one option from a list by scrolling.
• LV_PART_MAIN The background of the roller uses all the typical background properties and text style properties.
style_text_line_space adjusts the space between the options. When the Roller is scrolled and doesn't
stop exactly on an option it will scroll to the nearest valid option automatically in anim_time milliseconds as
specified in the style.
• LV_PART_SELECTED The selected option in the middle. Besides the typical background properties it uses the
text style properties to change the appearance of the text in the selected area.
Usage
Set options
Visible rows
Events
Keys
Example
Simple Roller
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_BUILD_EXAMPLES
/**
* An infinite roller with the name of the months
*/
void lv_example_roller_1(void)
{
lv_obj_t * roller1 = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller1,
"January\n"
"February\n"
"March\n"
"April\n"
"May\n"
"June\n"
"July\n"
"August\n"
"September\n"
"October\n"
"November\n"
"December",
LV_ROLLER_MODE_INFINITE);
lv_roller_set_visible_row_count(roller1, 4);
lv_obj_center(roller1);
lv_obj_add_event_cb(roller1, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
(continues on next page)
#
# An infinite roller with the name of the months
#
roller1 = lv.roller(lv.scr_act())
roller1.set_options("\n".join([
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]),lv.roller.MODE.INFINITE)
roller1.set_visible_row_count(4)
roller1.center()
roller1.add_event_cb(event_handler, lv.EVENT.ALL, None)
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_FONT_MONTSERRAT_22 && LV_BUILD_EXAMPLES
/**
* Roller with various alignments and larger text in the selected area
*/
void lv_example_roller_2(void)
{
/*A style to make the selected option larger*/
static lv_style_t style_sel;
lv_style_init(&style_sel);
(continues on next page)
/*A roller on the left with left aligned text, and custom width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 2);
lv_obj_set_width(roller, 100);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_set_style_text_align(roller, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_align(roller, LV_ALIGN_LEFT_MID, 10, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 2, LV_ANIM_OFF);
/*A roller on the middle with center aligned text, and auto (default) width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 3);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_align(roller, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 5, LV_ANIM_OFF);
/*A roller on the right with right aligned text, and custom width*/
roller = lv_roller_create(lv_scr_act());
lv_roller_set_options(roller, opts, LV_ROLLER_MODE_NORMAL);
lv_roller_set_visible_row_count(roller, 4);
lv_obj_set_width(roller, 80);
lv_obj_add_style(roller, &style_sel, LV_PART_SELECTED);
lv_obj_set_style_text_align(roller, LV_TEXT_ALIGN_RIGHT, 0);
lv_obj_align(roller, LV_ALIGN_RIGHT_MID, -10, 0);
lv_obj_add_event_cb(roller, event_handler, LV_EVENT_ALL, NULL);
lv_roller_set_selected(roller, 8, LV_ANIM_OFF);
}
#endif
import fs_driver
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
option = " "*10
obj.get_selected_str(option, len(option))
print("Selected value: %s\n" + option.strip())
#
# Roller with various alignments and larger text in the selected area
#
try:
style_sel.set_text_font(lv.font_montserrat_22)
except:
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
print("montserrat-22 not enabled in lv_conf.h, dynamically loading the font")
font_montserrat_22 = lv.font_load("S:" + "../../assets/font/montserrat-22.fnt")
style_sel.set_text_font(font_montserrat_22)
opts = "\n".join(["1","2","3","4","5","6","7","8","9","10"])
# A roller on the left with left aligned text, and custom width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(2)
roller.set_width(100)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.set_style_text_align(lv.TEXT_ALIGN.LEFT, 0)
roller.align(lv.ALIGN.LEFT_MID, 10, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(2, lv.ANIM.OFF)
# A roller in the middle with center aligned text, and auto (default) width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(3)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.align(lv.ALIGN.CENTER, 0, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(5, lv.ANIM.OFF)
# A roller on the right with right aligned text, and custom width
roller = lv.roller(lv.scr_act())
roller.set_options(opts, lv.roller.MODE.NORMAL)
roller.set_visible_row_count(4)
roller.set_width(80)
roller.add_style(style_sel, lv.PART.SELECTED)
roller.set_style_text_align(lv.TEXT_ALIGN.RIGHT, 0)
roller.align(lv.ALIGN.RIGHT_MID, -10, 0)
roller.add_event_cb(event_handler, lv.EVENT.ALL, None)
roller.set_selected(8, lv.ANIM.OFF)
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
if(code == LV_EVENT_COVER_CHECK) {
lv_event_set_cover_res(e, LV_COVER_RES_MASKED);
}
else if(code == LV_EVENT_DRAW_MAIN_BEGIN) {
/* add mask */
const lv_font_t * font = lv_obj_get_style_text_font(obj, LV_PART_MAIN);
lv_coord_t line_space = lv_obj_get_style_text_line_space(obj, LV_PART_MAIN);
lv_coord_t font_h = lv_font_get_line_height(font);
lv_area_t roller_coords;
lv_obj_get_coords(obj, &roller_coords);
lv_area_t rect_area;
rect_area.x1 = roller_coords.x1;
rect_area.x2 = roller_coords.x2;
rect_area.y1 = roller_coords.y1;
rect_area.y2 = roller_coords.y1 + (lv_obj_get_height(obj) - font_h - line_
,→space) / 2;
}
else if(code == LV_EVENT_DRAW_POST_END) {
lv_draw_mask_fade_param_t * fade_mask_top = lv_draw_mask_remove_id(mask_top_
,→id);
lv_draw_mask_free_param(fade_mask_top);
lv_draw_mask_free_param(fade_mask_bottom);
lv_mem_buf_release(fade_mask_top);
lv_mem_buf_release(fade_mask_bottom);
mask_top_id = -1;
mask_bottom_id = -1;
}
}
/**
* Add a fade mask to roller.
*/
void lv_example_roller_3(void)
(continues on next page)
#if LV_FONT_MONTSERRAT_22
lv_obj_set_style_text_font(roller1, &lv_font_montserrat_22, LV_PART_SELECTED);
#endif
lv_roller_set_options(roller1,
"January\n"
"February\n"
"March\n"
"April\n"
"May\n"
"June\n"
"July\n"
"August\n"
"September\n"
"October\n"
"November\n"
"December",
LV_ROLLER_MODE_NORMAL);
lv_obj_center(roller1);
lv_roller_set_visible_row_count(roller1, 3);
lv_obj_add_event_cb(roller1, mask_event_cb, LV_EVENT_ALL, NULL);
}
#endif
import fs_driver
import sys
class Lv_Roller_3():
def __init__(self):
self.mask_top_id = -1
self.mask_bottom_id = -1
#
# Add a fade mask to roller.
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.color_black())
style.set_text_color(lv.color_white())
roller1 = lv.roller(lv.scr_act())
roller1.add_style(style, 0)
roller1.set_style_border_width(0, 0)
roller1.set_style_pad_all(0, 0)
roller1.set_style_bg_opa(lv.OPA.TRANSP, lv.PART.SELECTED)
#if LV_FONT_MONTSERRAT_22
# lv_obj_set_style_text_font(roller1, &lv_font_montserrat_22, LV_PART_
,→SELECTED);
#endif
try:
roller1.set_style_text_font(lv.font_montserrat_22,lv.PART.SELECTED)
except:
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
print("montserrat-22 not enabled in lv_conf.h, dynamically loading the␣
,→font")
roller1.set_style_text_font(font_montserrat_22,lv.PART.SELECTED)
roller1.set_options("\n".join([
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"]),lv.roller.MODE.NORMAL)
roller1.center()
roller1.set_visible_row_count(3)
roller1.add_event_cb(self.mask_event_cb, lv.EVENT.ALL, None)
def mask_event_cb(self,e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.COVER_CHECK:
e.set_cover_res(lv.COVER_RES.MASKED)
roller_coords = lv.area_t()
obj.get_coords(roller_coords)
(continues on next page)
rect_area = lv.area_t()
rect_area.x1 = roller_coords.x1
rect_area.x2 = roller_coords.x2
rect_area.y1 = roller_coords.y1
rect_area.y2 = roller_coords.y1 + (obj.get_height() - font_h - line_
,→space) // 2
fade_mask_top = lv.draw_mask_fade_param_t()
fade_mask_top.init(rect_area, lv.OPA.TRANSP, rect_area.y1, lv.OPA.COVER,␣
,→rect_area.y2)
self.mask_top_id = lv.draw_mask_add(fade_mask_top,None)
fade_mask_bottom = lv.draw_mask_fade_param_t()
fade_mask_bottom.init(rect_area, lv.OPA.COVER, rect_area.y1, lv.OPA.
,→TRANSP, rect_area.y2)
roller3 = Lv_Roller_3()
API
Typedefs
Enums
enum [anonymous]
Roller mode.
Values:
enumerator LV_ROLLER_MODE_NORMAL
Normal mode (roller ends at the end of the options).
enumerator LV_ROLLER_MODE_INFINITE
Infinite mode (roller can be scrolled forever).
Functions
Returns
the options separated by '
'-s (E.g. "Option1\nOption2\nOption3")
uint16_t lv_roller_get_option_cnt(const lv_obj_t *obj)
Get the total number of options
Parameters obj -- pointer to a roller object
Returns the total number of options
Variables
struct lv_roller_t
Public Members
lv_obj_t obj
uint16_t option_cnt
Number of options
uint16_t sel_opt_id
Index of the current option
uint16_t sel_opt_id_ori
Store the original index on focus
lv_roller_mode_t mode
uint32_t moved
Overview
The Slider object looks like a Bar supplemented with a knob. The knob can be dragged to set a value. Just like Bar, Slider
can be vertical or horizontal.
• LV_PART_MAIN The background of the slider. Uses all the typical background style properties. padding
makes the indicator smaller in the respective direction.
• LV_PART_INDICATOR The indicator that shows the current state of the slider. Also uses all the typical back-
ground style properties.
• LV_PART_KNOB A rectangle (or circle) drawn at the current value. Also uses all the typical background properties
to describe the knob(s). By default, the knob is square (with an optional corner radius) with side length equal to
the smaller side of the slider. The knob can be made larger with the padding values. Padding values can be
asymmetric too.
Usage
Modes
Knob-only mode
Normally, the slider can be adjusted either by dragging the knob, or by clicking on the slider bar. In the latter case
the knob moves to the point clicked and slider value changes accordingly. In some cases it is desirable to set the
slider to react on dragging the knob only. This feature is enabled by adding the LV_OBJ_FLAG_ADV_HITTEST:
lv_obj_add_flag(slider, LV_OBJ_FLAG_ADV_HITTEST).
The extended click area (set by lv_obj_set_ext_click_area(slider, value)) increases to knob's click
area.
Events
• LV_EVENT_VALUE_CHANGED Sent while the slider is being dragged or changed with keys. The event is sent
continuously while the slider is being dragged.
• LV_EVENT_RELEASED Sent when the slider has just been released.
• LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END are sent for the following parts.
– LV_SLIDER_DRAW_PART_KNOB The main (right) knob of the slider
∗ part: LV_PART_KNOB
∗ draw_area: area of the indicator
∗ rect_dsc
∗ id: 0
– LV_SLIDER_DRAW_PART_KNOB The left knob of the slider
∗ part: LV_PART_KNOB
∗ draw_area: area of the indicator
∗ rect_dsc
∗ id: 1
See the events of the Bar too.
Learn more about Events.
Keys
Example
Simple Slider
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* A default slider with a label displaying the current value
*/
void lv_example_slider_1(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_center(slider);
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
(continues on next page)
#endif
#
# A default slider with a label displaying the current value
#
def slider_event_cb(e):
slider = e.get_target()
slider_label.set_text("{:d}%".format(slider.get_value()))
slider_label.align_to(slider, lv.ALIGN.OUT_BOTTOM_MID, 0, 10)
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Show how to style a slider.
*/
void lv_example_slider_2(void)
{
/*Create a transition*/
static const lv_style_prop_t props[] = {LV_STYLE_BG_COLOR, 0};
static lv_style_transition_dsc_t transition_dsc;
lv_style_transition_dsc_init(&transition_dsc, props, lv_anim_path_linear, 300, 0,␣
,→NULL);
(continues on next page)
lv_style_init(&style_indicator);
lv_style_set_bg_opa(&style_indicator, LV_OPA_COVER);
lv_style_set_bg_color(&style_indicator, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_radius(&style_indicator, LV_RADIUS_CIRCLE);
lv_style_set_transition(&style_indicator, &transition_dsc);
lv_style_init(&style_knob);
lv_style_set_bg_opa(&style_knob, LV_OPA_COVER);
lv_style_set_bg_color(&style_knob, lv_palette_main(LV_PALETTE_CYAN));
lv_style_set_border_color(&style_knob, lv_palette_darken(LV_PALETTE_CYAN, 3));
lv_style_set_border_width(&style_knob, 2);
lv_style_set_radius(&style_knob, LV_RADIUS_CIRCLE);
lv_style_set_pad_all(&style_knob, 6); /*Makes the knob larger*/
lv_style_set_transition(&style_knob, &transition_dsc);
lv_style_init(&style_pressed_color);
lv_style_set_bg_color(&style_pressed_color, lv_palette_darken(LV_PALETTE_CYAN,␣
,→2));
lv_obj_center(slider);
}
#endif
#
# Show how to style a slider.
#
# Create a transition
props = [lv.STYLE.BG_COLOR, 0]
transition_dsc = lv.style_transition_dsc_t()
transition_dsc.init(props, lv.anim_t.path_linear, 300, 0, None)
style_main = lv.style_t()
(continues on next page)
style_indicator.init()
style_indicator.set_bg_opa(lv.OPA.COVER)
style_indicator.set_bg_color(lv.palette_main(lv.PALETTE.CYAN))
style_indicator.set_radius(lv.RADIUS.CIRCLE)
style_indicator.set_transition(transition_dsc)
style_knob.init()
style_knob.set_bg_opa(lv.OPA.COVER)
style_knob.set_bg_color(lv.palette_main(lv.PALETTE.CYAN))
style_knob.set_border_color(lv.palette_darken(lv.PALETTE.CYAN, 3))
style_knob.set_border_width(2)
style_knob.set_radius(lv.RADIUS.CIRCLE)
style_knob.set_pad_all(6) # Makes the knob larger
style_knob.set_transition(transition_dsc)
style_pressed_color.init()
style_pressed_color.set_bg_color(lv.palette_darken(lv.PALETTE.CYAN, 2))
slider.add_style(style_main, lv.PART.MAIN)
slider.add_style(style_indicator, lv.PART.INDICATOR)
slider.add_style(style_pressed_color, lv.PART.INDICATOR | lv.STATE.PRESSED)
slider.add_style(style_knob, lv.PART.KNOB)
slider.add_style(style_pressed_color, lv.PART.KNOB | lv.STATE.PRESSED)
slider.center()
#include "../../lv_examples.h"
#if LV_USE_SLIDER && LV_BUILD_EXAMPLES
/**
* Show the current value when the slider is pressed by extending the drawer
*
*/
void lv_example_slider_3(void)
{
/*Create a slider in the center of the display*/
(continues on next page)
lv_slider_set_mode(slider, LV_SLIDER_MODE_RANGE);
lv_slider_set_value(slider, 70, LV_ANIM_OFF);
lv_slider_set_left_value(slider, 20, LV_ANIM_OFF);
lv_point_t label_size;
lv_txt_get_size(&label_size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, 0);
lv_area_t label_area;
label_area.x1 = dsc->draw_area->x1 + lv_area_get_width(dsc->draw_area) /␣
,→2 - label_size.x / 2;
lv_draw_label_dsc_t label_draw_dsc;
lv_draw_label_dsc_init(&label_draw_dsc);
label_draw_dsc.color = lv_color_hex3(0x888);
lv_draw_label(dsc->draw_ctx, &label_draw_dsc, &label_area, buf, NULL);
}
}
}
#endif
def slider_event_cb(e):
code = e.get_code()
obj = e.get_target()
# print(label_size.x,label_size.y)
label_area = lv.area_t()
label_area.x1 = dsc.draw_area.x1 + dsc.draw_area.get_width() // 2 - label_
,→size.x // 2
label_draw_dsc = lv.draw_label_dsc_t()
label_draw_dsc.init()
slider = lv.slider(lv.scr_act())
slider.center()
slider.set_mode(lv.slider.MODE.RANGE)
slider.set_value(70, lv.ANIM.OFF)
slider.set_left_value(20, lv.ANIM.OFF)
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_SLIDER_MODE_NORMAL
enumerator LV_SLIDER_MODE_SYMMETRICAL
enumerator LV_SLIDER_MODE_RANGE
enum lv_slider_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_slider_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_SLIDER_DRAW_PART_KNOB
The main (right) knob's rectangle
enumerator LV_SLIDER_DRAW_PART_KNOB_LEFT
The left knob's rectangle
Functions
Variables
struct lv_slider_t
Public Members
lv_bar_t bar
lv_area_t left_knob_area
lv_area_t right_knob_area
int32_t *value_to_set
uint8_t dragging
uint8_t left_knob_focus
Overview
The Switch looks like a little slider and can be used to turn something on and off.
• LV_PART_MAIN The background of the switch uses all the typical background style properties. padding makes
the indicator smaller in the respective direction.
• LV_PART_INDICATOR The indicator that shows the current state of the switch. Also uses all the typical back-
ground style properties.
• LV_PART_KNOB A rectangle (or circle) drawn at left or right side of the indicator. Also uses all the typical
background properties to describe the knob(s). By default, the knob is square (with an optional corner radius) with
side length equal to the smaller side of the slider. The knob can be made larger with the padding values. Padding
values can be asymmetric too.
Usage
Change state
Events
Keys
Example
Simple Switch
#include "../../lv_examples.h"
#if LV_USE_SWITCH && LV_BUILD_EXAMPLES
}
}
void lv_example_switch_1(void)
{
lv_obj_set_flex_flow(lv_scr_act(), LV_FLEX_FLOW_COLUMN);
lv_obj_set_flex_align(lv_scr_act(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,␣
,→LV_FLEX_ALIGN_CENTER);
lv_obj_t * sw;
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_DISABLED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
sw = lv_switch_create(lv_scr_act());
lv_obj_add_state(sw, LV_STATE_CHECKED | LV_STATE_DISABLED);
lv_obj_add_event_cb(sw, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
if obj.has_state(lv.STATE.CHECKED):
print("State: on")
else:
print("State: off")
lv.scr_act().set_flex_flow(lv.FLEX_FLOW.COLUMN)
lv.scr_act().set_flex_align(lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.
,→CENTER)
sw = lv.switch(lv.scr_act())
sw.add_event_cb(event_handler,lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.DISABLED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
sw.add_event_cb(event_handler, lv.EVENT.ALL, None)
API
Functions
Variables
struct lv_switch_t
Public Members
lv_obj_t obj
int32_t anim_state
Overview
Tables, as usual, are built from rows, columns, and cells containing texts.
The Table object is very lightweight because only the texts are stored. No real objects are created for cells but they are
just drawn on the fly.
The Table is added to the default group (if it is set). Besides the Table is an editable object to allow selecting a cell with
encoder navigation too.
• LV_PART_MAIN The background of the table uses all the typical background style properties.
• LV_PART_ITEMS The cells of the table also use all the typical background style properties and the text properties.
Usage
The cells can store only text so numbers need to be converted to text before displaying them in a table.
lv_table_set_cell_value(table, row, col, "Content"). The text is saved by the table so it can be
even a local variable.
Line breaks can be used in the text like "Value\n60.3".
New rows and columns are automatically added is required
To explicitly set number of rows and columns use lv_table_set_row_cnt(table, row_cnt) and
lv_table_set_col_cnt(table, col_cnt)
The width of the columns can be set with lv_table_set_col_width(table, col_id, width). The overall
width of the Table object will be set to the sum of columns widths.
The height is calculated automatically from the cell styles (font, padding etc) and the number of rows.
Merge cells
Scroll
If the label's width or height is set to LV_SIZE_CONTENT that size will be used to show the whole table in the respective
direction. E.g. lv_obj_set_size(table, LV_SIZE_CONTENT, LV_SIZE_CONTENT) automatically sets
the table size to show all the columns and rows.
If the width or height is set to a smaller number than the "intrinsic" size then the table becomes scrollable.
Events
Keys
Example
Simple table
#include "../../lv_examples.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
/*In the first column align the texts to the right*/
else if(col == 0) {
dsc->label_dsc->align = LV_TEXT_ALIGN_RIGHT;
}
dsc->rect_dsc->bg_opa = LV_OPA_COVER;
}
}
}
void lv_example_table_1(void)
(continues on next page)
#endif
def draw_part_event_cb(e):
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
# If the cells are drawn../
if dsc.part == lv.PART.ITEMS:
row = dsc.id // obj.get_col_cnt()
col = dsc.id - row * obj.get_col_cnt()
dsc.rect_dsc.bg_opa = lv.OPA.COVER
table = lv.table(lv.scr_act())
#include "../../lv_examples.h"
#if LV_USE_TABLE && LV_BUILD_EXAMPLES
lv_draw_rect_dsc_t rect_dsc;
lv_draw_rect_dsc_init(&rect_dsc);
rect_dsc.bg_color = chk ? lv_theme_get_color_primary(obj) : lv_palette_
,→lighten(LV_PALETTE_GREY, 2);
rect_dsc.radius = LV_RADIUS_CIRCLE;
(continues on next page)
lv_area_t sw_area;
sw_area.x1 = dsc->draw_area->x2 - 50;
sw_area.x2 = sw_area.x1 + 40;
sw_area.y1 = dsc->draw_area->y1 + lv_area_get_height(dsc->draw_area) / 2 - 10;
sw_area.y2 = sw_area.y1 + 20;
lv_draw_rect(dsc->draw_ctx, &rect_dsc, &sw_area);
rect_dsc.bg_color = lv_color_white();
if(chk) {
sw_area.x2 -= 2;
sw_area.x1 = sw_area.x2 - 16;
}
else {
sw_area.x1 += 2;
sw_area.x2 = sw_area.x1 + 16;
}
sw_area.y1 += 2;
sw_area.y2 -= 2;
lv_draw_rect(dsc->draw_ctx, &rect_dsc, &sw_area);
}
}
/**
* A very light-weighted list created from table
*/
void lv_example_table_2(void)
{
/*Measure memory usage*/
lv_mem_monitor_t mon1;
lv_mem_monitor(&mon1);
uint32_t t = lv_tick_get();
lv_table_set_col_width(table, 0, 150);
lv_table_set_row_cnt(table, ITEM_CNT); /*Not required but avoids a lot of memory␣
,→reallocation lv_table_set_set_value*/
lv_table_set_col_cnt(table, 1);
/*Don't make the cell pressed, we will draw something different in the event*/
lv_obj_remove_style(table, NULL, LV_PART_ITEMS | LV_STATE_PRESSED);
(continues on next page)
uint32_t i;
for(i = 0; i < ITEM_CNT; i++) {
lv_table_set_cell_value_fmt(table, i, 0, "Item %"LV_PRIu32, i + 1);
}
lv_mem_monitor_t mon2;
lv_mem_monitor(&mon2);
#endif
ITEM_CNT = 200
def draw_event_cb(e):
obj = e.get_target()
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
# If the cells are drawn...
if dsc.part == lv.PART.ITEMS:
chk = obj.has_cell_ctrl(dsc.id, 0, lv.table.CELL_CTRL.CUSTOM_1)
rect_dsc = lv.draw_rect_dsc_t()
rect_dsc.init()
if chk:
rect_dsc.bg_color = lv.theme_get_color_primary(obj)
else:
rect_dsc.bg_color = lv.palette_lighten(lv.PALETTE.GREY, 2)
rect_dsc.radius = lv.RADIUS.CIRCLE
sw_area = lv.area_t()
sw_area.x1 = dsc.draw_area.x2 - 50
sw_area.x2 = sw_area.x1 + 40
(continues on next page)
rect_dsc.bg_color = lv.color_white()
if chk:
sw_area.x2 -= 2
sw_area.x1 = sw_area.x2 - 16
else:
sw_area.x1 += 2
sw_area.x2 = sw_area.x1 + 16
sw_area.y1 += 2
sw_area.y2 -= 2
dsc.draw_ctx.rect(rect_dsc, sw_area)
def change_event_cb(e):
obj = e.get_target()
row = lv.C_Pointer()
col = lv.C_Pointer()
table.get_selected_cell(row, col)
# print("row: ",row.uint_val)
#
# A very light-weighted list created from table
#
table.set_col_width(0, 150)
table.set_row_cnt(ITEM_CNT) # Not required but avoids a lot of memory reallocation␣
,→lv_table_set_set_value
table.set_col_cnt(1)
# Don't make the cell pressed, we will draw something different in the event
table.remove_style(None, lv.PART.ITEMS | lv.STATE.PRESSED)
for i in range(ITEM_CNT):
table.set_cell_value(i, 0, "Item " + str(i+1))
table.align(lv.ALIGN.CENTER, 0, -20)
(continues on next page)
gc.collect()
mem_used = mem_free - gc.mem_free()
elaps = ticks_ms()-t
label = lv.label(lv.scr_act())
label.set_text(str(ITEM_CNT) + " items were created in " + str(elaps) + " ms\n using
,→" + str(mem_used) + " bytes of memory")
label.align(lv.ALIGN.BOTTOM_MID, 0, -10)
MicroPython
No examples yet.
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_TABLE_CELL_CTRL_MERGE_RIGHT
enumerator LV_TABLE_CELL_CTRL_TEXT_CROP
enumerator LV_TABLE_CELL_CTRL_CUSTOM_1
enumerator LV_TABLE_CELL_CTRL_CUSTOM_2
enumerator LV_TABLE_CELL_CTRL_CUSTOM_3
enumerator LV_TABLE_CELL_CTRL_CUSTOM_4
enum lv_table_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_table_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_TABLE_DRAW_PART_CELL
A cell
Functions
LV_EXPORT_CONST_INT(LV_TABLE_CELL_NONE)
Parameters
• obj -- pointer to a Table object
• row -- id of the row [0 .. row_cnt -1]
• col -- id of the column [0 .. col_cnt -1]
• txt -- text to display in the cell. It will be copied and saved so this variable is not required
after this function call.
void lv_table_set_cell_value_fmt(lv_obj_t *obj, uint16_t row, uint16_t col, const char *fmt, ...)
Set the value of a cell. Memory will be allocated to store the text by the table.
Parameters
• obj -- pointer to a Table object
• row -- id of the row [0 .. row_cnt -1]
• col -- id of the column [0 .. col_cnt -1]
• fmt -- printf-like format
Variables
struct lv_table_cell_t
Public Members
lv_table_cell_ctrl_t ctrl
void *user_data
Custom user data
char txt[]
struct lv_table_t
Public Members
lv_obj_t obj
uint16_t col_cnt
uint16_t row_cnt
lv_table_cell_t **cell_data
lv_coord_t *row_h
lv_coord_t *col_w
uint16_t col_act
uint16_t row_act
Overview
The Text Area is a Base object with a Label and a cursor on it. Texts or characters can be added to it. Long lines are
wrapped and when the text becomes long enough the Text area can be scrolled.
One line mode and password modes are supported.
• LV_PART_MAIN The background of the text area. Uses all the typical background style properties and the text
related style properties including text_align to align the text to the left, right or center.
• LV_PART_SCROLLBAR The scrollbar that is shown when the text is too long.
• LV_PART_SELECTED Determines the style of the selected text. Only text_color and bg_color style
properties can be used. bg_color should be set directly on the label of the text area.
• LV_PART_CURSOR Marks the position where the characters are inserted. The cursor's area is always the bounding
box of the current character. A block cursor can be created by adding a background color and background opacity
to LV_PART_CURSOR's style. The create line cursor leave the cursor transparent and set a left border. The
anim_time style property sets the cursor's blink time.
• LV_PART_TEXTAREA_PLACEHOLDER Unique to Text Area, allows styling the placeholder text.
Usage
Add text
You can insert text or characters to the current cursor's position with:
• lv_textarea_add_char(textarea, 'c')
• lv_textarea_add_text(textarea, "insert this text")
To add wide characters like 'á', 'ß' or CJK characters use lv_textarea_add_text(ta, "á").
lv_textarea_set_text(ta, "New text") changes the whole text.
Placeholder
A placeholder text can be specified - which is displayed when the Text area is empty - with
lv_textarea_set_placeholder_text(ta, "Placeholder text")
Delete character
To delete a character from the left of the current cursor position use lv_textarea_del_char(textarea). To
delete from the right use lv_textarea_del_char_forward(textarea)
The cursor position can be modified directly like lv_textarea_set_cursor_pos(textarea, 10). The 0
position means "before the first characters", LV_TA_CURSOR_LAST means "after the last character"
You can step the cursor with
• lv_textarea_cursor_right(textarea)
• lv_textarea_cursor_left(textarea)
• lv_textarea_cursor_up(textarea)
• lv_textarea_cursor_down(textarea)
If lv_textarea_set_cursor_click_pos(textarea, true) is applied the cursor will jump to the position
where the Text area was clicked.
The cursor is always visible, however it can be a good idea to style it to be visible only in LV_STATE_FOCUSED state.
The Text area can be configured to be on a single line with lv_textarea_set_one_line(textarea, true).
In this mode the height is set automatically to show only one line, line break characters are ignored, and word wrap is
disabled.
Password mode
The text area supports password mode which can be enabled with lv_textarea_set_password_mode(textarea,
true).
By default, if the • (Bullet, U+2022) character exists in the font, the entered characters are converted to it after some
time or when a new character is entered. If • does not exist in the font, * will be used. You can override the default
character with lv_textarea_set_password_bullet(textarea, "x").
In password mode lv_textarea_get_text(textarea) returns the actual text entered, not the bullet characters.
The visibility time can be adjusted with LV_TEXTAREA_DEF_PWD_SHOW_TIME) in lv_conf.h.
Accepted characters
If there is a very long text in the Text area (e.g. > 20k characters), scrolling and drawing might be slow. However, by
enabling LV_LABEL_LONG_TXT_HINT 1 in lv_conf.h the performance can be hugely improved. This will save
some additional information about the label to speed up its drawing. Using LV_LABEL_LONG_TXT_HINT the scrolling
and drawing will as fast as with "normal" short texts.
Select text
Events
• LV_EVENT_INSERT Sent right before a character or text is inserted. The event parameter is the text about to
be inserted. lv_textarea_set_insert_replace(textarea, "New text") replaces the text to
insert. The new text cannot be in a local variable which is destroyed when the event callback exists. "" means do
not insert anything.
• LV_EVENT_VALUE_CHANGED Sent when the content of the text area has been changed.
• LV_EVENT_READY Sent when LV_KEY_ENTER is pressed (or sent) to a one line text area.
See the events of the Base object too.
Learn more about Events.
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_BUILD_EXAMPLES
void lv_example_textarea_1(void)
{
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
lv_textarea_set_one_line(ta, true);
lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 10);
lv_obj_add_event_cb(ta, textarea_event_handler, LV_EVENT_READY, ta);
lv_obj_add_state(ta, LV_STATE_FOCUSED); /*To be sure the cursor is visible*/
lv_btnmatrix_set_map(btnm, btnm_map);
}
#endif
ta = lv.textarea(lv.scr_act())
ta.set_one_line(True)
ta.align(lv.ALIGN.TOP_MID, 0, 10)
ta.add_event_cb(lambda e: textarea_event_handler(e, ta), lv.EVENT.READY, None)
ta.add_state(lv.STATE.FOCUSED) # To be sure the cursor is visible
btnm = lv.btnmatrix(lv.scr_act())
btnm.set_size(200, 150)
btnm.align(lv.ALIGN.BOTTOM_MID, 0, -10)
btnm.add_event_cb(lambda e: btnm_event_handler(e, ta), lv.EVENT.VALUE_CHANGED, None)
btnm.clear_flag(lv.obj.FLAG.CLICK_FOCUSABLE) # To keep the text area focused on␣
,→button clicks
btnm.set_map(btnm_map)
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
void lv_example_textarea_2(void)
{
/*Create the password box*/
lv_obj_t * pwd_ta = lv_textarea_create(lv_scr_act());
lv_textarea_set_text(pwd_ta, "");
lv_textarea_set_password_mode(pwd_ta, true);
lv_textarea_set_one_line(pwd_ta, true);
lv_obj_set_width(pwd_ta, lv_pct(40));
lv_obj_set_pos(pwd_ta, 5, 20);
lv_obj_add_event_cb(pwd_ta, ta_event_cb, LV_EVENT_ALL, NULL);
/*Create a keyboard*/
kb = lv_keyboard_create(lv_scr_act());
lv_obj_set_size(kb, LV_HOR_RES, LV_VER_RES / 2);
#endif
def ta_event_cb(e):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.FOCUSED:
# Focus on the clicked text area
if kb != None:
kb.set_textarea(ta)
pwd_ta = lv.textarea(lv.scr_act())
(continues on next page)
# Create a keyboard
kb = lv.keyboard(lv.scr_act())
kb.set_size(LV_HOR_RES, LV_VER_RES // 2)
Text auto-formatting
#include "../../lv_examples.h"
#if LV_USE_TEXTAREA && LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
/**
* Automatically format text like a clock. E.g. "12:34"
* Add the ':' automatically.
*/
void lv_example_textarea_3(void)
{
/*Create the text area*/
lv_obj_t * ta = lv_textarea_create(lv_scr_act());
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_textarea_set_accepted_chars(ta, "0123456789:");
lv_textarea_set_max_length(ta, 5);
lv_textarea_set_one_line(ta, true);
(continues on next page)
/*Create a keyboard*/
kb = lv_keyboard_create(lv_scr_act());
lv_obj_set_size(kb, LV_HOR_RES, LV_VER_RES / 2);
lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);
lv_keyboard_set_textarea(kb, ta);
}
#endif
def ta_event_cb(e):
ta = e.get_target()
txt = ta.get_text()
# print(txt)
pos = ta.get_cursor_pos()
# print("cursor pos: ",pos)
# find position of ":" in text
colon_pos= txt.find(":")
# if there are more than 2 digits before the colon, remove the last one entered
if colon_pos == 3:
ta.del_char()
if colon_pos != -1:
# if there are more than 3 digits after the ":" remove the last one entered
rest = txt[colon_pos:]
if len(rest) > 3:
ta.del_char()
if len(txt) < 2:
return
if ":" in txt:
return
if txt[0] >= '0' and txt[0] <= '9' and \
txt[1] >= '0' and txt[1] <= '9':
if len(txt) == 2 or txt[2] != ':' :
ta.set_cursor_pos(2)
ta.add_char(ord(':'))
#
# Automatically format text like a clock. E.g. "12:34"
# Add the ':' automatically
#
# Create the text area
LV_HOR_RES = lv.scr_act().get_disp().driver.hor_res
(continues on next page)
ta = lv.textarea(lv.scr_act())
ta.add_event_cb(ta_event_cb, lv.EVENT.VALUE_CHANGED, None)
ta.set_accepted_chars("0123456789:")
ta.set_max_length(5)
ta.set_one_line(True)
ta.set_text("")
ta.add_state(lv.STATE.FOCUSED)
# Create a keyboard
kb = lv.keyboard(lv.scr_act())
kb.set_size(LV_HOR_RES, LV_VER_RES // 2)
kb.set_mode(lv.keyboard.MODE.NUMBER)
kb.set_textarea(ta)
API
Enums
enum [anonymous]
Values:
enumerator LV_PART_TEXTAREA_PLACEHOLDER
Functions
LV_EXPORT_CONST_INT(LV_TEXTAREA_CURSOR_LAST)
Variables
struct lv_textarea_t
Public Members
lv_obj_t obj
lv_obj_t *label
char *placeholder_txt
char *pwd_tmp
char *pwd_bullet
uint32_t max_length
uint16_t pwd_show_time
lv_coord_t valid_x
uint32_t pos
lv_area_t area
uint32_t txt_byte_pos
uint8_t show
uint8_t click_pos
uint32_t sel_start
uint32_t sel_end
uint8_t text_sel_in_prog
uint8_t text_sel_en
uint8_t pwd_mode
uint8_t one_line
Overview
The animation image is similar to the normal 'Image' object. The only difference is that instead of one source image, you
set an array of multiple source images.
You can specify a duration and repeat count.
• LV_PART_MAIN A background rectangle that uses the typical background style properties and the image itself
using the image style properties.
Usage
Image sources
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_ANIMIMG && LV_BUILD_EXAMPLES
LV_IMG_DECLARE(animimg001)
LV_IMG_DECLARE(animimg002)
LV_IMG_DECLARE(animimg003)
void lv_example_animimg_1(void)
{
lv_obj_t * animimg0 = lv_animimg_create(lv_scr_act());
lv_obj_center(animimg0);
lv_animimg_set_src(animimg0, (const void **) anim_imgs, 3);
lv_animimg_set_duration(animimg0, 1000);
lv_animimg_set_repeat_count(animimg0, LV_ANIM_REPEAT_INFINITE);
lv_animimg_start(animimg0);
}
#endif
anim_imgs = [None]*3
# Create an image from the png file
try:
with open('../../assets/animimg001.png','rb') as f:
anim001_data = f.read()
except:
print("Could not find animimg001.png")
sys.exit()
anim_imgs[0] = lv.img_dsc_t({
'data_size': len(anim001_data),
'data': anim001_data
})
try:
(continues on next page)
anim_imgs[1] = lv.img_dsc_t({
'data_size': len(anim002_data),
'data': anim002_data
})
try:
with open('../../assets/animimg003.png','rb') as f:
anim003_data = f.read()
except:
print("Could not find animimg003.png")
sys.exit()
anim_imgs[2] = lv.img_dsc_t({
'data_size': len(anim003_data),
'data': anim003_data
})
animimg0 = lv.animimg(lv.scr_act())
animimg0.center()
animimg0.set_src(anim_imgs, 3)
animimg0.set_duration(1000)
animimg0.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
animimg0.start()
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_ANIM_IMG_PART_MAIN
Functions
Variables
struct lv_animimg_t
Public Members
lv_img_t img
lv_anim_t anim
int8_t pic_count
From v8.1 the header is added directly into the Calendar widget and the API of the headers has been changed.
Overview
Usage
Some functions use the lv_calendar_date_t type which is a structure with year, month and day fields.
Current date
To set the current date (today), use the lv_calendar_set_today_date(calendar, year, month, day)
function. month needs to be in 1..12 range and day in 1..31 range.
Shown date
Highlighted days
The name of the days can be adjusted with lv_calendar_set_day_names(calendar, day_names) where
day_names looks like const char * day_names[7] = {"Su", "Mo", ...}; Only the pointer of the
day names is saved so the elements should be static, global or constant variables.
Events
Keys
Headers
Arrow buttons
lv_calendar_header_arrow_create(calendar) creates a header that contains a left and right arrow on the
sides and a text with the current year and month between them.
Drop-down
Example
#include "../../lv_examples.h"
#if LV_USE_CALENDAR && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
lv_calendar_date_t date;
if(lv_calendar_get_pressed_date(obj, &date)) {
LV_LOG_USER("Clicked date: %02d.%02d.%d", date.day, date.month, date.
,→year);
}
}
}
void lv_example_calendar_1(void)
{
lv_obj_t * calendar = lv_calendar_create(lv_scr_act());
lv_obj_set_size(calendar, 185, 185);
lv_obj_align(calendar, LV_ALIGN_CENTER, 0, 27);
lv_obj_add_event_cb(calendar, event_handler, LV_EVENT_ALL, NULL);
highlighted_days[0].year = 2021;
highlighted_days[0].month = 02;
highlighted_days[0].day = 6;
highlighted_days[1].year = 2021;
highlighted_days[1].month = 02;
highlighted_days[1].day = 11;
(continues on next page)
highlighted_days[2].year = 2022;
highlighted_days[2].month = 02;
highlighted_days[2].day = 22;
#if LV_USE_CALENDAR_HEADER_DROPDOWN
lv_calendar_header_dropdown_create(calendar);
#elif LV_USE_CALENDAR_HEADER_ARROW
lv_calendar_header_arrow_create(calendar);
#endif
lv_calendar_set_showed_date(calendar, 2021, 10);
}
#endif
def event_handler(evt):
code = evt.get_code()
if code == lv.EVENT.VALUE_CHANGED:
source = evt.get_current_target()
date = lv.calendar_date_t()
if source.get_pressed_date(date) == lv.RES.OK:
calendar.set_today_date(date.year, date.month, date.day)
print("Clicked date: %02d.%02d.%02d"%(date.day, date.month, date.year))
calendar = lv.calendar(lv.scr_act())
calendar.set_size(200, 200)
calendar.align(lv.ALIGN.CENTER, 0, 20)
calendar.add_event_cb(event_handler, lv.EVENT.ALL, None)
calendar.set_highlighted_dates(highlighted_days, len(highlighted_days))
lv.calendar_header_dropdown(calendar)
API
Functions
Variables
struct lv_calendar_date_t
#include <lv_calendar.h> Represents a date on the calendar object (platform-agnostic).
Public Members
uint16_t year
int8_t month
int8_t day
1..12
struct lv_calendar_t
Public Members
lv_obj_t obj
lv_obj_t *btnm
lv_calendar_date_t today
lv_calendar_date_t showed_date
lv_calendar_date_t *highlighted_dates
uint16_t highlighted_dates_num
Overview
Charts are a basic object to visualize data points. Currently Line charts (connect points with lines and/or draw points on
them) and Bar charts are supported.
Charts can have:
• division lines
• 2 y axis
• axis ticks and texts on ticks
• cursors
• scrolling and zooming
• LV_PART_MAIN The background of the chart. Uses all the typical background and line (for the division lines)
related style properties. Padding makes the series area smaller. For column charts pad_column sets the space
between the columns of the adjacent indices.
• LV_PART_SCROLLBAR The scrollbar used if the chart is zoomed. See the Base object's documentation for
details.
• LV_PART_ITEMS Refers to the line or bar series.
– Line chart: The line properties are used by the lines. width, height, bg_color and radius is used
to set the appearance of points.
– Bar chart: The typical background properties are used to style the bars. pad_column sets the space between
the columns on the same index.
• LV_PART_INDICATOR Refers to the points on line and scatter chart (small circles or squares).
• LV_PART_CURSOR Line properties are used to style the cursors. width, height, bg_color and radius
are used to set the appearance of points.
• LV_PART_TICKS Line and Text style properties are used to style the ticks
Usage
Chart type
Data series
You can add any number of series to the charts by lv_chart_add_series(chart, color, axis). This
allocates an lv_chart_series_t structure which contains the chosen color and an array for the data points.
axis can have the following values:
• LV_CHART_AXIS_PRIMARY_Y Left axis
• LV_CHART_AXIS_SECONDARY_Y Right axis
• LV_CHART_AXIS_PRIMARY_X Bottom axis
• LV_CHART_AXIS_SECONDARY_X Top axis
axis tells which axis's range should be used te scale the values.
lv_chart_set_ext_y_array(chart, ser, value_array) makes the chart use an external array for the
given series. value_array should look like this: lv_coord_t * value_array[num_points]. The array
size needs to be large enough to hold all the points of that series. The array's pointer will be saved in the chart so it needs
to be global, static or dynamically allocated. Note: you should call lv_chart_refresh(chart) after the external
data source has been updated to update the chart.
The value array of a series can be obtained with lv_chart_get_y_array(chart, ser), which can be used
with ext_array or normal arrays.
For LV_CHART_TYPE_SCATTER type lv_chart_set_ext_x_array(chart, ser, value_array) and
lv_chart_get_x_array(chart, ser) can be used as well.
Update modes
Number of points
On line charts, if the number of points is greater than the pixels horizontally, the Chart will draw only vertical lines to
make the drawing of large amount of data effective. If there are, let's say, 10 points to a pixel, LVGL searches the smallest
and the largest value and draws a vertical lines between them to ensure no peaks are missed.
Vertical range
You can specify the minimum and maximum values in y-direction with lv_chart_set_range(chart, axis,
min, max). axis can be LV_CHART_AXIS_PRIMARY (left axis) or LV_CHART_AXIS_SECONDARY (right
axis).
The value of the points will be scaled proportionally. The default range is: 0..100.
Division lines
If you want a plot to start from a point other than the default which is point[0] of the series, you can set an alternative
index with the function lv_chart_set_x_start_point(chart, ser, id) where id is the new index
position to start plotting from.
Note that LV_CHART_UPDATE_MODE_SHIFT also changes the start_point.
Ticks and labels can be added to the axis with lv_chart_set_axis_tick(chart, axis, major_len,
minor_len, major_cnt, minor_cnt, label_en, draw_size).
• axis can be LV_CHART_AXIS_X/PRIMARY_Y/SECONDARY_Y
• major_len is the length of major ticks
• minor_len is the length of minor ticks
• major_cnt is the number of major ticks on the axis
• minor_cnt in the number of minor ticks between two major ticks
• label_en true: enable label drawing on major ticks
• draw_size extra size required to draw the tick and labels (start with 20 px and increase if the ticks/labels are
clipped)
Zoom
The chart can be zoomed independently in x and y directions with lv_chart_set_zoom_x(chart, factor)
and lv_chart_set_zoom_y(chart, factor). If factor is 256 there is no zoom. 512 means double zoom,
etc. Fractional values are also possible but < 256 value is not allowed.
Cursor
Events
∗ rect_dsc
∗ draw_area: area of the points
– LV_CHART_DRAW_PART_TICK_LABEL Used on tick lines and labels.
∗ part: LV_PART_TICKS
∗ id: axis
∗ value: value of the tick
∗ text: value converted to decimal or NULL for minor ticks
∗ line_dsc,
∗ label_dsc,
See the events of the Base object too.
Learn more about Events.
Keys
Example
Line Chart
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
void lv_example_chart_1(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/
#endif
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.LINE) # Show lines and points too
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
/*Add a line mask that keeps the area below the line*/
lv_draw_mask_line_param_t line_mask_param;
lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->
,→p2->x, dsc->p2->y,
LV_DRAW_MASK_LINE_SIDE_BOTTOM);
int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);
obj->coords.y2);
int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);
lv_area_t a;
a.x1 = dsc->p1->x;
a.x2 = dsc->p2->x - 1;
a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
a.y2 = obj->coords.y2;
lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);
/*Vertical line*/
(continues on next page)
if(dsc->id == 1 || dsc->id == 3) {
dsc->line_dsc->color = lv_palette_main(LV_PALETTE_GREEN);
}
else {
dsc->line_dsc->color = lv_palette_lighten(LV_PALETTE_GREY, 1);
}
}
}
}
cnt++;
}
/**
* Add a faded area effect to the line chart and make some division lines ticker
*/
void lv_example_chart_2(void)
{
/*Create a chart1*/
chart1 = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart1, 200, 150);
lv_obj_center(chart1);
lv_chart_set_type(chart1, LV_CHART_TYPE_LINE); /*Show lines and points too*/
(continues on next page)
lv_chart_set_div_line_count(chart1, 5, 7);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart1, ser1, lv_rand(20, 90));
lv_chart_set_next_value(chart1, ser2, lv_rand(30, 70));
}
#endif
def draw_event_cb(e):
obj = e.get_target()
# Add a line mask that keeps the area below the line
line_mask_param = lv.draw_mask_line_param_t()
line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_MASK_
,→LINE_SIDE.BOTTOM)
# line_mask_id = line_mask_param.draw_mask_add(None)
line_mask_id = lv.draw_mask_add(line_mask_param, None)
# Add a fade effect: transparent bottom covering top
h = obj.get_height()
fade_mask_param = lv.draw_mask_fade_param_t()
coords = lv.area_t()
obj.get_coords(coords)
fade_mask_param.init(coords, lv.OPA.COVER, coords.y1 + h // 8, lv.OPA.TRANSP,
,→coords.y2)
fade_mask_id = lv.draw_mask_add(fade_mask_param,None)
a = lv.area_t()
(continues on next page)
def add_data(timer):
# LV_UNUSED(timer);
cnt = 0
chart1.set_next_value(ser1, lv.rand(20, 90))
if cnt % 4 == 0:
chart1.set_next_value(ser2, lv.rand(40, 60))
cnt +=1
#
# Add a faded area effect to the line chart
#
# Create a chart1
chart1 = lv.chart(lv.scr_act())
chart1.set_size(200, 150)
chart1.center()
chart1.set_type(lv.chart.TYPE.LINE) # Show lines and points too
for i in range(10):
chart1.set_next_value(ser1, lv.rand(20, 90))
chart1.set_next_value(ser2, lv.rand(30, 70))
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
/**
* Add ticks and labels to the axis and demonstrate scrolling
*/
void lv_example_chart_3(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
lv_chart_set_type(chart, LV_CHART_TYPE_BAR);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
lv_chart_set_range(chart, LV_CHART_AXIS_SECONDARY_Y, 0, 400);
lv_chart_set_point_count(chart, 12);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
LV_CHART_AXIS_SECONDARY_Y);
#endif
def draw_event_cb(e):
dsc = lv.obj_draw_part_dsc_t.__cast__(e.get_param())
if dsc.part == lv.PART.TICKS and dsc.id == lv.chart.AXIS.PRIMARY_X:
month = ["Jan", "Febr", "March", "Apr", "May", "Jun", "July", "Aug", "Sept",
,→"Oct", "Nov", "Dec"]
dsc.text = bytes(month[dsc.value],"ascii")
#
# Add ticks and labels to the axis and demonstrate scrolling
#
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.set_type(lv.chart.TYPE.BAR)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 100)
chart.set_range(lv.chart.AXIS.SECONDARY_Y, 0, 400)
chart.set_point_count(12)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
# Zoom in a little in X
chart.set_zoom_x(800)
(continues on next page)
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_invalidate(chart);
}
if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
lv_coord_t * s = lv_event_get_param(e);
*s = LV_MAX(*s, 20);
}
else if(code == LV_EVENT_DRAW_POST_END) {
int32_t id = lv_chart_get_pressed_point(chart);
if(id == LV_CHART_POINT_NONE) return;
char buf[16];
lv_snprintf(buf, sizeof(buf), LV_SYMBOL_DUMMY"$%d", value);
lv_draw_rect_dsc_t draw_rect_dsc;
lv_draw_rect_dsc_init(&draw_rect_dsc);
draw_rect_dsc.bg_color = lv_color_black();
draw_rect_dsc.bg_opa = LV_OPA_50;
draw_rect_dsc.radius = 3;
draw_rect_dsc.bg_img_src = buf;
draw_rect_dsc.bg_img_recolor = lv_color_white();
lv_area_t a;
a.x1 = chart->coords.x1 + p.x - 20;
a.x2 = chart->coords.x1 + p.x + 20;
a.y1 = chart->coords.y1 + p.y - 30;
a.y2 = chart->coords.y1 + p.y - 10;
/**
* Show the value of the pressed points
*/
void lv_example_chart_4(void)
{
/*Create a chart*/
lv_obj_t * chart;
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_center(chart);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_chart_set_next_value(chart, ser1, lv_rand(60, 90));
(continues on next page)
#endif
def event_cb(e):
code = e.get_code()
chart = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
chart.invalidate()
if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
e.set_ext_draw_size(20)
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
draw_rect_dsc.bg_color = lv.color_black()
draw_rect_dsc.bg_opa = lv.OPA._50
draw_rect_dsc.radius = 3
draw_rect_dsc.bg_img_src = buf
draw_rect_dsc.bg_img_recolor = lv.color_white()
a = lv.area_t()
coords = lv.area_t()
chart.get_coords(coords)
a.x1 = coords.x1 + p.x - 20
a.x2 = coords.x1 + p.x + 20
a.y1 = coords.y1 + p.y - 30
a.y2 = coords.y1 + p.y - 10
clip_area = lv.area_t.__cast__(e.get_param())
lv.draw_rect(a, clip_area, draw_rect_dsc)
#
# Add ticks and labels to the axis and demonstrate scrolling
#
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
(continues on next page)
# Zoom in a little in X
chart.set_zoom_x(800)
ser1_p = []
ser2_p = []
for i in range(10):
ser1_p.append(lv.rand(60,90))
ser2_p.append(lv.rand(10,40))
ser1.y_points = ser1_p
ser2.y_points = ser2_p
series = [ser1,ser2]
series_points=[ser1_p,ser2_p]
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_USE_SLIDER && LV_BUILD_EXAMPLES
-112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10,␣
,→4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25,␣
,→14, 15, 19, 28, 31, 26, 23, 25, 31,
39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33,␣
,→19, -1, -27, -55, -67, -72, -71, -63,
-49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288,␣
,→274, 255, 212, 173, 143, 117, 82, 39,
-13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -
,→123, -123, -129, -139, -148, -153,
-159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -
,→473, -517, -556, -592, -612, -620,
-620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -
,→222, -167, -114, -70, -47, -28, -4, 12,
38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89,␣
,→88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115,␣
,→110, 96, 85, 73, 64, 69, 76, 79,
78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67,␣
,→73, 79, 74, 63, 57, 56, 58, 61, 55,
(continues on next page)
47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -
,→32, -31, -19, -5, 3, 9, 13, 19,
24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -
,→3, -11, -20, -47, -100, -194, -236,
-212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27,␣
,→19, 17, 21, 20, 19, 19, 22, 36, 40,
35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -
,→5, -10, -19, -32, -42, -55, -60,
-68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -
,→50, -45, -35, -20, -3, 12, 20, 25,
26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9,␣
,→9, -3, -1, -18, -50, -108, -190,
-272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60,
,→ 58, 103, 129, 139, 155, 170, 173,
178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226,␣
,→224, 232, 233, 232, 224, 219, 219,
223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283,␣
,→271, 263, 252, 243, 226, 210, 197,
186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7,
,→ -11, -14, -18, -29, -37, -44, -50,
-58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -
,→52, -59, -69, -76, -76, -69, -67,
-74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -
,→17, -13, -10, -11, -13, -20, -20,
-12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21,␣
,→20, 18, 19, 19, 19, 16, 15, 13, 14,
14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -
,→18, -16, -9, -4, -5, -10, -9, -8,
-3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -
,→33, -19, 0, 17, 24, 9, -17, -47,
-63, -67, -59, -52, -51, -50, -49, -42, -26, -21, -15, -20, -23, -22, -19, -12, -
,→8, 5, 18, 27, 32, 26, 25, 26, 22,
23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131,␣
,→114, 87, 60, 42, 29, 26, 34, 35, 34,
25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -
,→26, -25, -21, -15, -10, -13, -13,
-19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119,␣
,→-124, -129, -132, -146, -146, -138,
-124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2,␣
,→4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7,␣
,→12, 17, 11, 0, -6, -9, -8, -7, -5,
-6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -
,→60, -67, -65, -54, -35, -11, 30,
84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239,␣
,→197, 163, 136, 109, 77, 34, -18, -50,
-66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -
,→171, -169, -174, -175, -178, -191,
-202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -
,→565, -596, -619, -623, -623, -614,
-599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96,
,→ -57, -29, -8, 10, 31, 45, 60, 65,
/**
* Display 1000 data points with zooming and scrolling.
* See how the chart changes drawing mode (draw only vertical lines) when
* the points get too crowded.
*/
void lv_example_chart_5(void)
{
/*Create a chart*/
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, -30, -30);
lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, -1000, 1000);
lv_obj_t * slider;
slider = lv_slider_create(lv_scr_act());
lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
lv_obj_add_event_cb(slider, slider_x_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_size(slider, 200, 10);
lv_obj_align_to(slider, chart, LV_ALIGN_OUT_BOTTOM_MID, 0, 20);
slider = lv_slider_create(lv_scr_act());
lv_slider_set_range(slider, LV_IMG_ZOOM_NONE, LV_IMG_ZOOM_NONE * 10);
lv_obj_add_event_cb(slider, slider_y_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
lv_obj_set_size(slider, 10, 150);
lv_obj_align_to(slider, chart, LV_ALIGN_OUT_RIGHT_MID, 20, 0);
}
#endif
# Source: https://github.com/ankur219/ECG-Arrhythmia-classification/blob/
,→642230149583adfae1e4bd26c6f0e1fd8af2be0e/sample.csv
(continues on next page)
-112, -100, -89, -83, -71, -64, -58, -58, -62, -62, -58, -51, -46, -39, -27, -10,␣
,→4, 7, 1, -3, 0, 14, 24, 30, 25, 19,
13, 7, 12, 15, 18, 21, 13, 6, 9, 8, 17, 19, 13, 11, 11, 11, 23, 30, 37, 34, 25,␣
,→14, 15, 19, 28, 31, 26, 23, 25, 31,
39, 37, 37, 34, 30, 32, 22, 29, 31, 33, 37, 23, 13, 7, 2, 4, -2, 2, 11, 22, 33,␣
,→19, -1, -27, -55, -67, -72, -71, -63,
-49, -18, 35, 113, 230, 369, 525, 651, 722, 730, 667, 563, 454, 357, 305, 288,␣
,→274, 255, 212, 173, 143, 117, 82, 39,
-13, -53, -78, -91, -101, -113, -124, -131, -131, -131, -129, -128, -129, -125, -
,→123, -123, -129, -139, -148, -153,
-159, -166, -183, -205, -227, -243, -248, -246, -254, -280, -327, -381, -429, -
,→473, -517, -556, -592, -612, -620,
-620, -614, -604, -591, -574, -540, -497, -441, -389, -358, -336, -313, -284, -
,→222, -167, -114, -70, -47, -28, -4, 12,
38, 52, 58, 56, 56, 57, 68, 77, 86, 86, 80, 69, 67, 70, 82, 85, 89, 90, 89, 89,␣
,→88, 91, 96, 97, 91, 83, 78, 82, 88, 95,
96, 105, 106, 110, 102, 100, 96, 98, 97, 101, 98, 99, 100, 107, 113, 119, 115,␣
,→110, 96, 85, 73, 64, 69, 76, 79,
78, 75, 85, 100, 114, 113, 105, 96, 84, 74, 66, 60, 75, 85, 89, 83, 67, 61, 67,␣
,→73, 79, 74, 63, 57, 56, 58, 61, 55,
48, 45, 46, 55, 62, 55, 49, 43, 50, 59, 63, 57, 40, 31, 23, 25, 27, 31, 35, 34,␣
,→30, 36, 34, 42, 38, 36, 40, 46, 50,
47, 32, 30, 32, 52, 67, 73, 71, 63, 54, 53, 45, 41, 28, 13, 3, 1, 4, 4, -8, -23, -
,→32, -31, -19, -5, 3, 9, 13, 19,
24, 27, 29, 25, 22, 26, 32, 42, 51, 56, 60, 57, 55, 53, 53, 54, 59, 54, 49, 26, -
,→3, -11, -20, -47, -100, -194, -236,
-212, -123, 8, 103, 142, 147, 120, 105, 98, 93, 81, 61, 40, 26, 28, 30, 30, 27,␣
,→19, 17, 21, 20, 19, 19, 22, 36, 40,
35, 20, 7, 1, 10, 18, 27, 22, 6, -4, -2, 3, 6, -2, -13, -14, -10, -2, 3, 2, -1, -
,→5, -10, -19, -32, -42, -55, -60,
-68, -77, -86, -101, -110, -117, -115, -104, -92, -84, -85, -84, -73, -65, -52, -
,→50, -45, -35, -20, -3, 12, 20, 25,
26, 28, 28, 30, 28, 25, 28, 33, 42, 42, 36, 23, 9, 0, 1, -4, 1, -4, -4, 1, 5, 9,␣
,→9, -3, -1, -18, -50, -108, -190,
-272, -340, -408, -446, -537, -643, -777, -894, -920, -853, -697, -461, -251, -60,
,→ 58, 103, 129, 139, 155, 170, 173,
178, 185, 190, 193, 200, 208, 215, 225, 224, 232, 234, 240, 240, 236, 229, 226,␣
,→224, 232, 233, 232, 224, 219, 219,
223, 231, 226, 223, 219, 218, 223, 223, 223, 233, 245, 268, 286, 296, 295, 283,␣
,→271, 263, 252, 243, 226, 210, 197,
186, 171, 152, 133, 117, 114, 110, 107, 96, 80, 63, 48, 40, 38, 34, 28, 15, 2, -7,
,→ -11, -14, -18, -29, -37, -44, -50,
-58, -63, -61, -52, -50, -48, -61, -59, -58, -54, -47, -52, -62, -61, -64, -54, -
,→52, -59, -69, -76, -76, -69, -67,
-74, -78, -81, -80, -73, -65, -57, -53, -51, -47, -35, -27, -22, -22, -24, -21, -
,→17, -13, -10, -11, -13, -20, -20,
-12, -2, 7, -1, -12, -16, -13, -2, 2, -4, -5, -2, 9, 19, 19, 14, 11, 13, 19, 21,␣
,→20, 18, 19, 19, 19, 16, 15, 13, 14,
14, 7, 10, 15, 16, 11, 12, 10, 13, 9, -2, -4, -2, 7, 16, 16, 17, 16, 7, -1, -16, -
,→18, -16, -9, -4, -5, -10, -9, -8,
-3, -4, -10, -19, -20, -16, -9, -9, -23, -40, -48, -43, -33, -19, -21, -26, -31, -
,→33, -19, 0, 17, 24, 9, -17, -47,
(continues on next page)
23, 17, 14, 17, 21, 25, 2, -45, -121, -196, -226, -200, -118, -9, 73, 126, 131,␣
,→114, 87, 60, 42, 29, 26, 34, 35, 34,
25, 12, 9, 7, 3, 2, -8, -11, 2, 23, 38, 41, 23, 9, 10, 13, 16, 8, -8, -17, -23, -
,→26, -25, -21, -15, -10, -13, -13,
-19, -22, -29, -40, -48, -48, -54, -55, -66, -82, -85, -90, -92, -98, -114, -119,␣
,→-124, -129, -132, -146, -146, -138,
-124, -99, -85, -72, -65, -65, -65, -66, -63, -64, -64, -58, -46, -26, -9, 2, 2,␣
,→4, 0, 1, 4, 3, 10, 11, 10, 2, -4,
0, 10, 18, 20, 6, 2, -9, -7, -3, -3, -2, -7, -12, -5, 5, 24, 36, 31, 25, 6, 3, 7,␣
,→12, 17, 11, 0, -6, -9, -8, -7, -5,
-6, -2, -2, -6, -2, 2, 14, 24, 22, 15, 8, 4, 6, 7, 12, 16, 25, 20, 7, -16, -41, -
,→60, -67, -65, -54, -35, -11, 30,
84, 175, 302, 455, 603, 707, 743, 714, 625, 519, 414, 337, 300, 281, 263, 239,␣
,→197, 163, 136, 109, 77, 34, -18, -50,
-66, -74, -79, -92, -107, -117, -127, -129, -135, -139, -141, -155, -159, -167, -
,→171, -169, -174, -175, -178, -191,
-202, -223, -235, -243, -237, -240, -256, -298, -345, -393, -432, -475, -518, -
,→565, -596, -619, -623, -623, -614,
-599, -583, -559, -524, -477, -425, -383, -357, -331, -301, -252, -198, -143, -96,
,→ -57, -29, -8, 10, 31, 45, 60, 65,
def slider_x_event_cb(e):
slider = e.get_target()
v = slider.get_value()
chart.set_zoom_x(v)
def slider_y_event_cb(e):
slider = e.get_target()
v = slider.get_value()
chart.set_zoom_y(v)
#
# Display 1000 data points with zooming and scrolling.
# See how the chart changes drawing mode (draw only vertical lines) when
# the points get too crowded.
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, -30, -30)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, -1000, 1000)
pcnt = len(ecg_sample)
chart.set_point_count(pcnt)
chart.set_ext_y_array(ser, ecg_sample)
(continues on next page)
slider = lv.slider(lv.scr_act())
slider.set_range(lv.IMG_ZOOM.NONE, lv.IMG_ZOOM.NONE * 10)
slider.add_event_cb(slider_x_event_cb, lv.EVENT.VALUE_CHANGED, None)
slider.set_size(200,10)
slider.align_to(chart, lv.ALIGN.OUT_BOTTOM_MID, 0, 20)
slider = lv.slider(lv.scr_act())
slider.set_range(lv.IMG_ZOOM.NONE, lv.IMG_ZOOM.NONE * 10)
slider.add_event_cb(slider_y_event_cb, lv.EVENT.VALUE_CHANGED, None)
slider.set_size(10, 150)
slider.align_to(chart, lv.ALIGN.OUT_RIGHT_MID, 20, 0)
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
last_id = lv_chart_get_pressed_point(obj);
if(last_id != LV_CHART_POINT_NONE) {
lv_chart_set_cursor_point(obj, cursor, NULL, last_id);
}
}
else if(code == LV_EVENT_DRAW_PART_END) {
lv_obj_draw_part_dsc_t * dsc = lv_event_get_draw_part_dsc(e);
if(!lv_obj_draw_part_check_type(dsc, &lv_chart_class, LV_CHART_DRAW_PART_
,→CURSOR)) return;
lv_point_t size;
lv_txt_get_size(&size, buf, LV_FONT_DEFAULT, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_
,→ NONE);
lv_area_t a;
a.y2 = dsc->p1->y - 5;
a.y1 = a.y2 - size.y - 10;
(continues on next page)
lv_draw_rect_dsc_t draw_rect_dsc;
lv_draw_rect_dsc_init(&draw_rect_dsc);
draw_rect_dsc.bg_color = lv_palette_main(LV_PALETTE_BLUE);
draw_rect_dsc.radius = 3;
lv_draw_label_dsc_t draw_label_dsc;
lv_draw_label_dsc_init(&draw_label_dsc);
draw_label_dsc.color = lv_color_white();
a.x1 += 5;
a.x2 -= 5;
a.y1 += 5;
a.y2 -= 5;
lv_draw_label(dsc->draw_ctx, &draw_label_dsc, &a, buf, NULL);
}
}
/**
* Show cursor on the clicked point
*/
void lv_example_chart_6(void)
{
chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, -10);
lv_chart_set_zoom_x(chart, 500);
#endif
class ExampleChart_6():
(continues on next page)
def __init__(self):
self.last_id = -1
#
# Show cursor on the clicked point
#
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, 0, -10)
self.ser_p = []
for i in range(10):
self.ser_p.append(lv.rand(10,90))
self.ser.y_points = self.ser_p
newser = chart.get_series_next(None)
# print("length of data points: ",len(newser.points))
chart.set_zoom_x(500)
label = lv.label(lv.scr_act())
label.set_text("Click on a point")
label.align_to(chart, lv.ALIGN.OUT_TOP_MID, 0, -5)
def event_cb(self,e):
code = e.get_code()
chart = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
# print("last_id: ",self.last_id)
self.last_id = chart.get_pressed_point()
if self.last_id != lv.CHART_POINT.NONE:
p = lv.point_t()
chart.get_point_pos_by_id(self.ser, self.last_id, p)
chart.set_cursor_point(self.cursor, None, self.last_id)
v = self.ser_p[self.last_id]
# print("value: ",v)
value_txt = str(v)
size = lv.point_t()
lv.txt_get_size(size, value_txt, lv.font_default(), 0, 0, lv.COORD.
,→MAX, lv.TEXT_FLAG.NONE)
a = lv.area_t()
a.y2 = dsc.p1.y - 5
a.y1 = a.y2 - size.y - 10
a.x1 = dsc.p1.x + 10
a.x2 = a.x1 + size.x + 10
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
draw_rect_dsc.bg_color = lv.palette_main(lv.PALETTE.BLUE)
draw_rect_dsc.radius = 3
draw_label_dsc = lv.draw_label_dsc_t()
draw_label_dsc.init()
draw_label_dsc.color = lv.color_white()
a.x1 += 5
a.x2 -= 5
a.y1 += 5
a.y2 -= 5
lv.draw_label(a, dsc.clip_area, draw_label_dsc, value_txt, None)
example_chart_6 = ExampleChart_6()
Scatter chart
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
dsc->rect_dsc->bg_color = lv_color_mix(lv_palette_main(LV_PALETTE_RED),
lv_palette_main(LV_PALETTE_BLUE),
x_opa + y_opa);
}
}
/**
* A scatter chart
*/
void lv_example_chart_7(void)
{
lv_obj_t * chart = lv_chart_create(lv_scr_act());
lv_obj_set_size(chart, 200, 150);
lv_obj_align(chart, LV_ALIGN_CENTER, 0, 0);
lv_obj_add_event_cb(chart, draw_event_cb, LV_EVENT_DRAW_PART_BEGIN, NULL);
lv_obj_set_style_line_width(chart, 0, LV_PART_ITEMS); /*Remove the lines*/
lv_chart_set_type(chart, LV_CHART_TYPE_SCATTER);
lv_chart_set_point_count(chart, 50);
#endif
#!/opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
(continues on next page)
def draw_event_cb(e):
dsc = e.get_draw_part_dsc()
if dsc.part == lv.PART.ITEMS:
obj = e.get_target()
ser = obj.get_series_next(None)
cnt = obj.get_point_count()
# print("cnt: ",cnt)
# Make older value more transparent
dsc.rect_dsc.bg_opa = (lv.OPA.COVER * dsc.id) // (cnt - 1)
# print("p_act", p_act)
x_opa = (x_array[p_act] * lv.OPA._50) // 200
y_opa = (y_array[p_act] * lv.OPA._50) // 1000
dsc.rect_dsc.bg_color = lv.palette_main(lv.PALETTE.RED).color_mix(
lv.palette_main(lv.PALETTE.BLUE),
x_opa + y_opa)
def add_data(timer,chart):
# print("add_data")
x = lv.rand(0,200)
y = lv.rand(0,1000)
chart.set_next_value2(ser, x, y)
# chart.set_next_value2(chart.gx, y)
x_array.pop(0)
x_array.append(x)
y_array.pop(0)
y_array.append(y)
#
# A scatter chart
#
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.align(lv.ALIGN.CENTER, 0, 0)
chart.add_event_cb(draw_event_cb, lv.EVENT.DRAW_PART_BEGIN, None)
chart.set_style_line_width(0, lv.PART.ITEMS) # Remove the lines
chart.set_type(lv.chart.TYPE.SCATTER)
chart.set_range(lv.chart.AXIS.PRIMARY_X, 0, 200)
chart.set_range(lv.chart.AXIS.PRIMARY_Y, 0, 1000)
(continues on next page)
chart.set_point_count(50)
x_array = []
y_array = []
for i in range(50):
x_array.append(lv.rand(0, 200))
y_array.append(lv.rand(0, 1000))
ser.x_points = x_array
ser.y_points = y_array
timer = lv.timer_create_basic()
timer.set_period(100)
timer.set_cb(lambda src: add_data(timer,chart))
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_DRAW_COMPLEX && LV_BUILD_EXAMPLES
/* A struct is used to keep track of the series list because later we need to draw␣
,→to the series in the reverse order to which they were initialised. */
typedef struct {
lv_obj_t * obj;
lv_chart_series_t * series_list[3];
} stacked_area_chart_t;
/**
* Callback which draws the blocks of colour under the lines
**/
static void draw_event_cb(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_target(e);
/*Add a line mask that keeps the area below the line*/
lv_draw_mask_line_param_t line_mask_param;
lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->
,→p2->x, dsc->p2->y,
LV_DRAW_MASK_LINE_SIDE_BOTTOM);
int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);
lv_area_t a;
a.x1 = dsc->p1->x;
a.x2 = dsc->p2->x;
a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
a.y2 = obj->coords.y2 -
13; /* -13 cuts off where the rectangle draws over the chart margin.␣
,→Without this an area of 0 doesn't look like 0 */
/**
* Helper function to round a fixed point number
**/
static int32_t round_fixed_point(int32_t n, int8_t shift)
{
/* Create a bitmask to isolates the decimal part of the fixed point number */
int32_t mask = 1;
for(int32_t bit_pos = 0; bit_pos < shift; bit_pos++) {
mask = (mask << 1) + 1;
}
/**
* Stacked area chart
*/
void lv_example_chart_8(void)
{
/*Create a stacked_area_chart.obj*/
stacked_area_chart.obj = lv_chart_create(lv_scr_act());
lv_obj_set_size(stacked_area_chart.obj, 200, 150);
lv_obj_center(stacked_area_chart.obj);
lv_chart_set_type(stacked_area_chart.obj, LV_CHART_TYPE_LINE);
lv_chart_set_div_line_count(stacked_area_chart.obj, 5, 7);
lv_obj_add_event_cb(stacked_area_chart.obj, draw_event_cb, LV_EVENT_DRAW_PART_
,→BEGIN, NULL);
LV_CHART_AXIS_PRIMARY_Y);
stacked_area_chart.series_list[1] = lv_chart_add_series(stacked_area_chart.obj,␣
,→lv_palette_main(LV_PALETTE_BLUE),
LV_CHART_AXIS_PRIMARY_Y);
stacked_area_chart.series_list[2] = lv_chart_add_series(stacked_area_chart.obj,␣
,→lv_palette_main(LV_PALETTE_GREEN),
LV_CHART_AXIS_PRIMARY_Y);
int8_t fixed_point_shift = 5;
uint32_t total = vals[0] + vals[1] + vals[2];
uint32_t draw_heights[3];
uint32_t int_sum = 0;
uint32_t decimal_sum = 0;
/* The draw heights are equal to the percentage of the total each value␣
,→ is + the cumulative sum of the previous percentages.
The accumulation is how the values get "stacked" */
draw_heights[series_index] = int_sum + modifier;
draw_heights[series_index]);
}
}
lv_chart_refresh(stacked_area_chart.obj);
}
#endif
import display_driver
import lvgl as lv
stacked_area_chart = StackedAreaChart()
#
# Callback which draws the blocks of colour under the lines
#
def draw_event_cb(e):
obj = e.get_target()
cont_a = lv.area_t()
obj.get_coords(cont_a)
# Add a line mask that keeps the area below the line
line_mask_param = lv.draw_mask_line_param_t()
line_mask_param.points_init(dsc.p1.x, dsc.p1.y, dsc.p2.x, dsc.p2.y, lv.DRAW_
,→MASK_LINE_SIDE.BOTTOM)
a = lv.area_t()
a.x1 = dsc.p1.x
a.x2 = dsc.p2.x
a.y1 = min(dsc.p1.y, dsc.p2.y)
a.y2 = cont_a.y2 - 13 # -13 cuts off where the rectangle draws over the chart␣
,→margin. Without this an area of 0 doesn't look like 0
dsc.draw_ctx.rect(draw_rect_dsc, a)
#
# Helper function to round a fixed point number
#
def round_fixed_point(n, shift):
# Create a bitmask to isolates the decimal part of the fixed point number
(continues on next page)
#
# Stacked area chart
#
def lv_example_chart_8():
#Create a stacked_area_chart.obj
stacked_area_chart.obj = lv.chart(lv.scr_act())
stacked_area_chart.obj.set_size(200, 150)
stacked_area_chart.obj.center()
stacked_area_chart.obj.set_type( lv.chart.TYPE.LINE)
stacked_area_chart.obj.set_div_line_count(5, 7)
stacked_area_chart.obj.add_event_cb( draw_event_cb, lv.EVENT.DRAW_PART_BEGIN,␣
,→None)
stacked_area_chart.series_list[1] = stacked_area_chart.obj.add_series(lv.palette_
,→main(lv.PALETTE.BLUE), lv.chart.AXIS.PRIMARY_Y)
stacked_area_chart.series_list[2] = stacked_area_chart.obj.add_series(lv.palette_
,→main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)
fixed_point_shift = 5
total = vals[0] + vals[1] + vals[2]
draw_heights = [0, 0, 0]
int_sum = 0
decimal_sum = 0
# The draw heights are equal to the percentage of the total each value␣
,→ is + the cumulative sum of the previous percentages.
# The accumulation is how the values get "stacked"
draw_heights[series_index] = int(int_sum + modifier)
# Draw to the series in the reverse order to which they were initialised.
# Without this the higher values will draw on top of the lower ones.
# This is because the Z-height of a series matches the order it was␣
,→initialised
stacked_area_chart.obj.set_next_value( stacked_area_chart.series_list[3 -␣
,→series_index - 1], draw_heights[series_index])
stacked_area_chart.obj.refresh()
lv_example_chart_8()
API
Typedefs
Enums
enum [anonymous]
Chart types
Values:
enumerator LV_CHART_TYPE_NONE
Don't draw the series
enumerator LV_CHART_TYPE_LINE
Connect the points with lines
enumerator LV_CHART_TYPE_BAR
Draw columns
enumerator LV_CHART_TYPE_SCATTER
Draw points and lines in 2D (x,y coordinates)
enum [anonymous]
Chart update mode for lv_chart_set_next
Values:
enumerator LV_CHART_UPDATE_MODE_SHIFT
Shift old data to the left and add the new one the right
enumerator LV_CHART_UPDATE_MODE_CIRCULAR
Add the new data in a circular way
enum [anonymous]
Enumeration of the axis'
Values:
enumerator LV_CHART_AXIS_PRIMARY_Y
enumerator LV_CHART_AXIS_SECONDARY_Y
enumerator LV_CHART_AXIS_PRIMARY_X
enumerator LV_CHART_AXIS_SECONDARY_X
enumerator _LV_CHART_AXIS_LAST
enum lv_chart_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_chart_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_CHART_DRAW_PART_DIV_LINE_INIT
Used before/after drawn the div lines
enumerator LV_CHART_DRAW_PART_DIV_LINE_HOR
Used for each horizontal division lines
enumerator LV_CHART_DRAW_PART_DIV_LINE_VER
Used for each vertical division lines
enumerator LV_CHART_DRAW_PART_LINE_AND_POINT
Used on line and scatter charts for lines and points
enumerator LV_CHART_DRAW_PART_BAR
Used on bar charts for the rectangles
enumerator LV_CHART_DRAW_PART_CURSOR
Used on cursor lines and points
enumerator LV_CHART_DRAW_PART_TICK_LABEL
Used on tick lines and labels
Functions
LV_EXPORT_CONST_INT(LV_CHART_POINT_NONE)
Variables
struct lv_chart_series_t
#include <lv_chart.h> Descriptor a chart series
Public Members
lv_coord_t *x_points
lv_coord_t *y_points
lv_color_t color
uint16_t start_point
uint8_t hidden
uint8_t x_ext_buf_assigned
uint8_t y_ext_buf_assigned
uint8_t x_axis_sec
uint8_t y_axis_sec
struct lv_chart_cursor_t
Public Members
lv_point_t pos
lv_coord_t point_id
lv_color_t color
lv_chart_series_t *ser
lv_dir_t dir
uint8_t pos_set
struct lv_chart_tick_dsc_t
Public Members
lv_coord_t major_len
lv_coord_t minor_len
lv_coord_t draw_size
uint32_t minor_cnt
uint32_t major_cnt
uint32_t label_en
struct lv_chart_t
Public Members
lv_obj_t obj
lv_ll_t series_ll
Linked list for the series (stores lv_chart_series_t)
lv_ll_t cursor_ll
Linked list for the cursors (stores lv_chart_cursor_t)
lv_chart_tick_dsc_t tick[4]
lv_coord_t ymin[2]
lv_coord_t ymax[2]
lv_coord_t xmin[2]
lv_coord_t xmax[2]
lv_coord_t pressed_point_id
uint16_t hdiv_cnt
Number of horizontal division lines
uint16_t vdiv_cnt
Number of vertical division lines
uint16_t point_cnt
Point number in a data line
uint16_t zoom_x
uint16_t zoom_y
lv_chart_type_t type
Line or column chart
lv_chart_update_mode_t update_mode
Overview
As its name implies Color wheel allows the user to select a color. The Hue, Saturation and Value of the color can be
selected separately.
Long pressing the object, the color wheel will change to the next parameter of the color (hue, saturation or value). A
double click will reset the current parameter.
• LV_PART_MAIN Only arc_width is used to set the width of the color wheel
• LV_PART_KNOB A rectangle (or circle) drawn on the current value. It uses all the rectangle like style properties
and padding to make it larger than the width of the arc.
Usage
Set color
Color mode
Events
Keys
Example
Simple Colorwheel
#include "../../lv_examples.h"
#if LV_USE_COLORWHEEL && LV_BUILD_EXAMPLES
void lv_example_colorwheel_1(void)
{
lv_obj_t * cw;
cw = lv_colorwheel_create(lv_scr_act(), true);
lv_obj_set_size(cw, 200, 200);
lv_obj_center(cw);
}
#endif
cw = lv.colorwheel(lv.scr_act(), True)
cw.set_size(200, 200)
cw.center()
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_COLORWHEEL_MODE_HUE
enumerator LV_COLORWHEEL_MODE_SATURATION
enumerator LV_COLORWHEEL_MODE_VALUE
Functions
Variables
struct lv_colorwheel_t
Public Members
lv_obj_t obj
lv_color_hsv_t hsv
lv_point_t pos
uint8_t recolor
uint32_t last_click_time
uint32_t last_change_time
lv_point_t last_press_point
lv_colorwheel_mode_t mode
uint8_t mode_fixed
Overview
The Image button is very similar to the simple 'Button' object. The only difference is that it displays user-defined images
in each state instead of drawing a rectangle.
You can set a left, right and center image, and the center image will be repeated to match the width of the object.
• LV_PART_MAIN Refers to the image(s). If background style properties are used, a rectangle will be drawn behind
the image button.
Usage
Image sources
States
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_IMGBTN && LV_BUILD_EXAMPLES
void lv_example_imgbtn_1(void)
{
LV_IMG_DECLARE(imgbtn_left);
LV_IMG_DECLARE(imgbtn_right);
LV_IMG_DECLARE(imgbtn_mid);
#endif
imgbtn_left_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_left_data),
'data': imgbtn_left_data
})
try:
with open('../../assets/imgbtn_mid.png','rb') as f:
imgbtn_mid_data = f.read()
except:
print("Could not find imgbtn_mid.png")
sys.exit()
imgbtn_mid_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_mid_data),
'data': imgbtn_mid_data
})
try:
with open('../../assets/imgbtn_right.png','rb') as f:
imgbtn_right_data = f.read()
except:
print("Could not find imgbtn_right.png")
sys.exit()
imgbtn_right_dsc = lv.img_dsc_t({
'data_size': len(imgbtn_right_data),
'data': imgbtn_right_data
})
style_def = lv.style_t()
style_def.init()
style_def.set_text_color(lv.color_white())
style_def.set_transition(tr)
imgbtn1.add_style(style_def, 0)
imgbtn1.add_style(style_pr, lv.STATE.PRESSED)
imgbtn1.align(lv.ALIGN.CENTER, 0, 0)
API
Enums
enum lv_imgbtn_state_t
Values:
enumerator LV_IMGBTN_STATE_RELEASED
enumerator LV_IMGBTN_STATE_PRESSED
enumerator LV_IMGBTN_STATE_DISABLED
enumerator LV_IMGBTN_STATE_CHECKED_RELEASED
enumerator LV_IMGBTN_STATE_CHECKED_PRESSED
enumerator LV_IMGBTN_STATE_CHECKED_DISABLED
enumerator _LV_IMGBTN_STATE_NUM
Functions
Variables
struct lv_imgbtn_t
Public Members
lv_obj_t obj
lv_img_cf_t act_cf
Overview
The Keyboard object is a special Button matrix with predefined keymaps and other features to realize a virtual keyboard
to write texts into a Text area.
Usage
Modes
You can assign a Text area to the Keyboard to automatically put the clicked characters there. To assign the text area, use
lv_keyboard_set_textarea(kb, ta).
Key Popovers
To enable key popovers on press, like on common Android and iOS keyboards, use
lv_keyboard_set_popovers(kb, true). The default control maps are preconfigured to only show
the popovers on keys that produce a symbol and not on e.g. space. If you use a custom keymap, set the
LV_BTNMATRIX_CTRL_POPOVER flag for all keys that you want to show a popover.
Note that popovers for keys in the top row will draw outside the widget boundaries. To account for this, reserve extra free
space on top of the keyboard or ensure that the keyboard is added after any widgets adjacent to its top boundary so that
the popovers can draw over those.
The popovers currently are merely a visual effect and don't allow selecting additional characters such as accents yet.
New Keymap
You can specify a new map (layout) for the keyboard with lv_keyboard_set_map(kb, map) and
lv_keyboard_set_ctrl_map(kb, ctrl_map). Learn more about the Button matrix object. Keep in mind
that using following keywords will have the same effect as with the original map:
• LV_SYMBOL_OK Apply.
• LV_SYMBOL_CLOSE or LV_SYMBOL_KEYBOARD Close.
• LV_SYMBOL_BACKSPACE Delete on the left.
• LV_SYMBOL_LEFT Move the cursor left.
• LV_SYMBOL_RIGHT Move the cursor right.
• LV_SYMBOL_NEW_LINE New line.
• "ABC" Load the uppercase map.
• "abc" Load the lower case map.
• "1#" Load the lower case map.
Events
• LV_EVENT_VALUE_CHANGED Sent when the button is pressed/released or repeated after long press. The event
data is set to the ID of the pressed/released button.
• LV_EVENT_READY - The Ok button is clicked.
• LV_EVENT_CANCEL - The Close button is clicked.
The keyboard has a default event handler callback called lv_keyboard_def_event_cb, which handles the button
pressing, map changing, the assigned text area, etc. You can remove it and replace it with a custom event handler if you
wish.
Note: In 8.0 and newer, adding an event handler to the keyboard does not remove the default event handler. This behavior
differs from v7, where adding an event handler would always replace the previous one.
Keys
Examples
#include "../../lv_examples.h"
#if LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
if(code == LV_EVENT_DEFOCUSED) {
lv_keyboard_set_textarea(kb, NULL);
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
}
void lv_example_keyboard_1(void)
{
/*Create a keyboard to use it with an of the text areas*/
lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
ta = lv_textarea_create(lv_scr_act());
lv_obj_align(ta, LV_ALIGN_TOP_RIGHT, -10, 10);
lv_obj_add_event_cb(ta, ta_event_cb, LV_EVENT_ALL, kb);
lv_obj_set_size(ta, 140, 80);
lv_keyboard_set_textarea(kb, ta);
}
#endif
def ta_event_cb(e,kb):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.FOCUSED:
kb.set_textarea(ta)
kb.clear_flag(lv.obj.FLAG.HIDDEN)
if code == lv.EVENT.DEFOCUSED:
kb.set_textarea(None)
kb.add_flag(lv.obj.FLAG.HIDDEN)
ta = lv.textarea(lv.scr_act())
ta.set_width(200)
ta.align(lv.ALIGN.TOP_RIGHT, -10, 10)
ta.add_event_cb(lambda e: ta_event_cb(e,kb), lv.EVENT.ALL, None)
kb.set_textarea(ta)
API
Typedefs
Enums
enum [anonymous]
Current keyboard mode.
Values:
enumerator LV_KEYBOARD_MODE_TEXT_LOWER
enumerator LV_KEYBOARD_MODE_TEXT_UPPER
enumerator LV_KEYBOARD_MODE_SPECIAL
enumerator LV_KEYBOARD_MODE_NUMBER
enumerator LV_KEYBOARD_MODE_USER_1
enumerator LV_KEYBOARD_MODE_USER_2
enumerator LV_KEYBOARD_MODE_USER_3
enumerator LV_KEYBOARD_MODE_USER_4
Functions
Variables
struct lv_keyboard_t
Public Members
lv_btnmatrix_t btnm
lv_obj_t *ta
lv_keyboard_mode_t mode
uint8_t popovers
Overview
The LEDs are rectangle-like (or circle) object whose brightness can be adjusted. With lower brightness the colors of the
LED become darker.
The LEDs have only one main part, called LV_LED_PART_MAIN and it uses all the typical background style properties.
Usage
Color
You can set the color of the LED with lv_led_set_color(led, lv_color_hex(0xff0080)). This will
be used as background color, border color, and shadow color.
Brightness
You can set their brightness with lv_led_set_bright(led, bright). The brightness should be between 0
(darkest) and 255 (lightest).
Toggle
Use lv_led_on(led) and lv_led_off(led) to set the brightness to a predefined ON or OFF value. The
lv_led_toggle(led) toggles between the ON and OFF state.
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_LED && LV_BUILD_EXAMPLES
/**
* Create LED's with different brightness and color
*/
void lv_example_led_1(void)
{
/*Create a LED and switch it OFF*/
lv_obj_t * led1 = lv_led_create(lv_scr_act());
lv_obj_align(led1, LV_ALIGN_CENTER, -80, 0);
lv_led_off(led1);
#endif
#
# Create LED's with different brightness and color
#
API
Enums
enum lv_led_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_led_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_LED_DRAW_PART_RECTANGLE
The main rectangle
Functions
Variables
struct lv_led_t
Public Members
lv_obj_t obj
lv_color_t color
uint8_t bright
Current brightness of the LED (0..255)
Overview
The List is basically a rectangle with vertical layout to which Buttons and Texts can be added
Background
• LV_PART_MAIN The main part of the list that uses all the typical background properties
• LV_PART_SCROLLBAR The scrollbar. See the Base objects documentation for details.
Buttons and Texts See the Button's and Label's documentation.
Usage
Buttons
lv_list_add_btn(list, icon, text) adds a full-width button with an icon - that can be an image or symbol
- and a text.
The text starts to scroll horizontally if it's too long.
Texts
Events
No special events are sent by the List, but sent by the Button as usual.
Learn more about Events.
Keys
Example
Simple List
#include "../../lv_examples.h"
#if LV_USE_LIST && LV_BUILD_EXAMPLES
static lv_obj_t * list1;
void lv_example_list_1(void)
{
/*Create a list*/
list1 = lv_list_create(lv_scr_act());
lv_obj_set_size(list1, 180, 220);
lv_obj_center(list1);
lv_list_add_text(list1, "File");
btn = lv_list_add_btn(list1, LV_SYMBOL_FILE, "New");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_DIRECTORY, "Open");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_SAVE, "Save");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, "Delete");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_EDIT, "Edit");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
(continues on next page)
lv_list_add_text(list1, "Connectivity");
btn = lv_list_add_btn(list1, LV_SYMBOL_BLUETOOTH, "Bluetooth");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_GPS, "Navigation");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_USB, "USB");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_BATTERY_FULL, "Battery");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
lv_list_add_text(list1, "Exit");
btn = lv_list_add_btn(list1, LV_SYMBOL_OK, "Apply");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, "Close");
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.CLICKED:
print("Clicked: list1." + list1.get_btn_text(obj))
# Create a list
list1 = lv.list(lv.scr_act())
list1.set_size(180, 220)
list1.center()
list1.add_text("Connectivity")
btn_bluetooth = list1.add_btn(lv.SYMBOL.BLUETOOTH, "Bluetooth")
btn_bluetooth.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_navig = list1.add_btn(lv.SYMBOL.GPS, "Navigation")
btn_navig.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_USB = list1.add_btn(lv.SYMBOL.USB, "USB")
btn_USB.add_event_cb(event_handler,lv.EVENT.ALL, None)
btn_battery = list1.add_btn(lv.SYMBOL.BATTERY_FULL, "Battery")
btn_battery.add_event_cb(event_handler,lv.EVENT.ALL, None)
list1.add_text("Exit")
btn_apply = list1.add_btn(lv.SYMBOL.OK, "Apply")
(continues on next page)
#include <stdlib.h>
#include "../../lv_examples.h"
#if LV_USE_LIST && LV_BUILD_EXAMPLES
if(currentButton == obj) {
currentButton = NULL;
}
else {
currentButton = obj;
}
lv_obj_t * parent = lv_obj_get_parent(obj);
uint32_t i;
for(i = 0; i < lv_obj_get_child_cnt(parent); i++) {
lv_obj_t * child = lv_obj_get_child(parent, i);
if(child == currentButton) {
lv_obj_add_state(child, LV_STATE_CHECKED);
}
else {
lv_obj_clear_state(child, LV_STATE_CHECKED);
}
}
}
}
lv_obj_move_to_index(currentButton, pos);
lv_obj_scroll_to_view(currentButton, LV_ANIM_ON);
}
}
void lv_example_list_2(void)
{
/*Create a list*/
list1 = lv_list_create(lv_scr_act());
lv_obj_set_size(list1, lv_pct(60), lv_pct(100));
lv_obj_set_style_pad_row(list1, 5, 0);
#endif
import urandom
currentButton = None
list1 = None
def event_handler(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
if currentButton == obj:
currentButton = None
else:
currentButton = obj
parent = obj.get_parent()
for i in range( parent.get_child_cnt()):
child = parent.get_child(i)
if child == currentButton:
child.add_state(lv.STATE.CHECKED)
else:
child.clear_state(lv.STATE.CHECKED)
def event_handler_top(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
if currentButton == None:
return
currentButton.move_background()
currentButton.scroll_to_view( lv.ANIM.ON)
def event_handler_up(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
index = currentButton.get_index()
if index <= 0:
return
currentButton.move_to_index(index - 1)
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_center(evt):
global currentButton
code = evt.get_code()
(continues on next page)
def event_handler_dn(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
index = currentButton.get_index()
currentButton.move_to_index(index + 1)
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_bottom(evt):
global currentButton
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if currentButton == None:
return
currentButton.move_foreground()
currentButton.scroll_to_view(lv.ANIM.ON)
def event_handler_swap(evt):
global currentButton
global list1
code = evt.get_code()
obj = evt.get_target()
if code == lv.EVENT.CLICKED:
cnt = list1.get_child_cnt()
for i in range(100):
if cnt > 1:
obj = list1.get_child(urandom.getrandbits(32) % cnt )
obj.move_to_index(urandom.getrandbits(32) % cnt)
if currentButton != None:
currentButton.scroll_to_view(lv.ANIM.ON)
for i in range(15):
btn = lv.btn(list1)
btn.set_width(lv.pct(100))
btn.add_event_cb( event_handler, lv.EVENT.CLICKED, None)
lab = lv.label(btn)
lab.set_text("Item " + str(i))
API
Functions
Variables
Overview
The menu widget can be used to easily create multi-level menus. It handles the traversal between pages automatically.
Usage
Create a menu
Header mode
lv_menu_page_create(menu, title) creates a new empty menu page. You can add any widgets to the page.
Once a menu page has been created, you can set it to the main area with lv_menu_set_page(menu, page).
NULL to clear main and clear menu history.
Once a menu page has been created, you can set it to the sidebar with lv_menu_set_sidebar_page(menu,
page). NULL to clear sidebar.
For instance, you have created a btn obj in the main page. When you click the btn obj, you want it to open up a new page,
use lv_menu_set_load_page_event(menu, obj, new page).
The following objects can be created so that it is easier to style the menu:
lv_menu_cont_create(parent page) creates a new empty container.
lv_menu_section_create(parent page) creates a new empty section.
lv_menu_separator_create(parent page) creates a separator.
Events
Keys
Example
Simple Menu
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
void lv_example_menu_1(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
(continues on next page)
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
if(lv_menu_back_btn_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Hello", "Root back btn click.",␣
,→NULL, true);
lv_obj_center(mbox1);
}
}
void lv_example_menu_2(void)
{
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_menu_set_mode_root_back_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
}
#endif
def back_event_handler(e):
obj = e.get_target()
if menu.back_btn_is_root(obj):
mbox1 = lv.msgbox(lv.scr_act(), "Hello", "Root back btn click.", None, True)
mbox1.center()
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_USER_DATA && LV_BUILD_EXAMPLES
void lv_example_menu_3(void)
{
/*Create a menu object*/
lv_obj_t * menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
(continues on next page)
cont = lv_menu_cont_create(sub_1_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(sub_2_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(sub_3_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding here");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_1_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 2 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_2_page);
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 3 (Click me!)");
lv_menu_set_load_page_event(menu, cont, sub_3_page);
lv_menu_set_page(menu, main_page);
}
#endif
cont = lv.menu_cont(sub_page_1)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
cont = lv.menu_cont(sub_page_2)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
cont = lv.menu_cont(sub_page_3)
label = lv.label(cont)
label.set_text("Hello, I am hiding here")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1 (Click me!)")
menu.set_load_page_event(cont, sub_page_1)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 2 (Click me!)")
menu.set_load_page_event(cont, sub_page_2)
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 3 (Click me!)")
menu.set_load_page_event(cont, sub_page_3)
menu.set_page(main_page)
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_BUILD_EXAMPLES
btn_cnt++;
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
(continues on next page)
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text_fmt(label, "Item %"LV_PRIu32, btn_cnt);
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_obj_scroll_to_view_recursive(cont, LV_ANIM_ON);
}
void lv_example_menu_4(void)
{
/*Create a menu object*/
menu = lv_menu_create(lv_scr_act());
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * label;
cont = lv_menu_cont_create(sub_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Hello, I am hiding inside the first item");
cont = lv_menu_cont_create(main_page);
label = lv_label_create(cont);
lv_label_set_text(label, "Item 1");
lv_menu_set_load_page_event(menu, cont, sub_page);
lv_menu_set_page(menu, main_page);
#endif
btn_cnt = 1
def float_btn_event_cb(e):
global btn_cnt
btn_cnt += 1
(continues on next page)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside {:d}".format(btn_cnt))
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item {:d}".format(btn_cnt))
menu.set_load_page_event(cont, sub_page)
cont = lv.menu_cont(sub_page)
label = lv.label(cont)
label.set_text("Hello, I am hiding inside the first item")
cont = lv.menu_cont(main_page)
label = lv.label(cont)
label.set_text("Item 1")
menu.set_load_page_event(cont, sub_page)
menu.set_page(main_page)
float_btn = lv.btn(lv.scr_act())
float_btn.set_size(50, 50)
float_btn.add_flag(lv.obj.FLAG.FLOATING)
float_btn.align(lv.ALIGN.BOTTOM_RIGHT, -10, -10)
float_btn.add_event_cb(float_btn_event_cb, lv.EVENT.CLICKED, None)
float_btn.set_style_radius(lv.RADIUS.CIRCLE, 0)
float_btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
float_btn.set_style_text_font(lv.theme_get_font_large(float_btn), 0)
Complex Menu
#include "../../lv_examples.h"
#if LV_USE_MENU && LV_USE_MSGBOX && LV_BUILD_EXAMPLES
enum {
LV_MENU_ITEM_BUILDER_VARIANT_1,
LV_MENU_ITEM_BUILDER_VARIANT_2
};
typedef uint8_t lv_menu_builder_variant_t;
void lv_example_menu_5(void)
{
lv_obj_t * menu = lv_menu_create(lv_scr_act());
}
else {
lv_obj_set_style_bg_color(menu, lv_color_darken(lv_obj_get_style_bg_
,→color(menu, 0), 50), 0);
}
lv_menu_set_mode_root_back_btn(menu, LV_MENU_ROOT_BACK_BTN_ENABLED);
lv_obj_add_event_cb(menu, back_event_handler, LV_EVENT_CLICKED, menu);
lv_obj_set_size(menu, lv_disp_get_hor_res(NULL), lv_disp_get_ver_res(NULL));
lv_obj_center(menu);
lv_obj_t * cont;
lv_obj_t * section;
lv_menu_separator_create(sub_mechanics_page);
section = lv_menu_section_create(sub_mechanics_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Velocity", 0, 150, 120);
create_slider(section, LV_SYMBOL_SETTINGS, "Acceleration", 0, 150, 50);
create_slider(section, LV_SYMBOL_SETTINGS, "Weight limit", 0, 150, 80);
lv_menu_separator_create(sub_sound_page);
section = lv_menu_section_create(sub_sound_page);
create_switch(section, LV_SYMBOL_AUDIO, "Sound", false);
lv_menu_separator_create(sub_display_page);
section = lv_menu_section_create(sub_display_page);
create_slider(section, LV_SYMBOL_SETTINGS, "Brightness", 0, 150, 100);
section = lv_menu_section_create(sub_software_info_page);
create_text(section, NULL, "Version 1.0", LV_MENU_ITEM_BUILDER_VARIANT_1);
section = lv_menu_section_create(sub_legal_info_page);
for(uint32_t i = 0; i < 15; i++) {
create_text(section, NULL,
"This is a long long long long long long long long long text, if␣
,→it is long enough it may scroll.",
LV_MENU_ITEM_BUILDER_VARIANT_1);
}
lv_menu_separator_create(sub_about_page);
section = lv_menu_section_create(sub_about_page);
cont = create_text(section, NULL, "Software information", LV_MENU_ITEM_BUILDER_
,→VARIANT_1);
lv_menu_separator_create(sub_menu_mode_page);
section = lv_menu_section_create(sub_menu_mode_page);
cont = create_switch(section, LV_SYMBOL_AUDIO, "Sidebar enable", true);
lv_obj_add_event_cb(lv_obj_get_child(cont, 2), switch_handler, LV_EVENT_VALUE_
,→CHANGED, menu);
section = lv_menu_section_create(root_page);
cont = create_text(section, LV_SYMBOL_SETTINGS, "Mechanics", LV_MENU_ITEM_BUILDER_
,→VARIANT_1);
lv_menu_set_sidebar_page(menu, root_page);
lv_event_send(lv_obj_get_child(lv_obj_get_child(lv_menu_get_cur_sidebar_
,→ page(menu), 0), 0), LV_EVENT_CLICKED, NULL);
}
if(lv_menu_back_btn_is_root(menu, obj)) {
lv_obj_t * mbox1 = lv_msgbox_create(NULL, "Hello", "Root back btn click.",␣
,→NULL, true);
lv_obj_center(mbox1);
}
}
}
else {
lv_menu_set_sidebar_page(menu, NULL);
lv_menu_clear_history(menu); /* Clear history because we will be showing␣
,→the root page later */
lv_menu_set_page(menu, root_page);
}
}
}
static lv_obj_t * create_text(lv_obj_t * parent, const char * icon, const char * txt,
lv_menu_builder_variant_t builder_variant)
{
lv_obj_t * obj = lv_menu_cont_create(parent);
if(icon) {
img = lv_img_create(obj);
lv_img_set_src(img, icon);
}
if(txt) {
label = lv_label_create(obj);
lv_label_set_text(label, txt);
(continues on next page)
return obj;
}
int32_t val)
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_2);
if(icon == NULL) {
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
}
return obj;
}
{
lv_obj_t * obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_1);
lv_obj_t * sw = lv_switch_create(obj);
lv_obj_add_state(sw, chk ? LV_STATE_CHECKED : 0);
return obj;
}
#endif
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_MENU_HEADER_TOP_FIXED
enumerator LV_MENU_HEADER_TOP_UNFIXED
enumerator LV_MENU_HEADER_BOTTOM_FIXED
enum [anonymous]
Values:
enumerator LV_MENU_ROOT_BACK_BTN_DISABLED
enumerator LV_MENU_ROOT_BACK_BTN_ENABLED
Functions
Variables
struct lv_menu_load_page_event_data_t
Public Members
lv_obj_t *menu
lv_obj_t *page
struct lv_menu_history_t
Public Members
lv_obj_t *page
struct lv_menu_t
Public Members
lv_obj_t obj
lv_obj_t *storage
lv_obj_t *main
lv_obj_t *main_page
lv_obj_t *main_header
lv_obj_t *main_header_back_btn
lv_obj_t *main_header_title
lv_obj_t *sidebar
lv_obj_t *sidebar_page
lv_obj_t *sidebar_header
lv_obj_t *sidebar_header_back_btn
lv_obj_t *sidebar_header_title
lv_obj_t *selected_tab
lv_ll_t history_ll
uint8_t cur_depth
uint8_t prev_depth
uint8_t sidebar_generated
lv_menu_mode_header_t mode_header
lv_menu_mode_root_back_btn_t mode_root_back_btn
struct lv_menu_page_t
Public Members
lv_obj_t obj
char *title
Overview
The Meter widget can visualize data in very flexible ways. It can show arcs, needles, ticks lines and labels.
• LV_PART_MAIN The background of the Meter. Uses the typical background properties.
• LV_PART_TICKS The tick lines a labels using the line and text style properties.
• LV_PART_INDICATOR The needle line or image using the line and img style properties, as well as the background
properties to draw a square (or circle) on the pivot of the needles. Padding makes the square larger.
• LV_PART_ITEMS The arcs using the arc properties.
Usage
Add a scale
Add indicators
Indicators need to be added to a Scale and their value is interpreted in the range of the Scale.
All the indicator add functions return lv_meter_indicator_t *.
Needle line
Needle image
Arc
Events
Keys
Example
Simple meter
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A simple meter
*/
void lv_example_meter_1(void)
{
meter = lv_meter_create(lv_scr_act());
lv_obj_center(meter);
lv_obj_set_size(meter, 200, 200);
lv_meter_indicator_t * indic;
false, 0);
lv_meter_set_indicator_start_value(meter, indic, 0);
lv_meter_set_indicator_end_value(meter, indic, 20);
0);
lv_meter_set_indicator_start_value(meter, indic, 80);
lv_meter_set_indicator_end_value(meter, indic, 100);
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
#
# A simple meter
#
meter = lv.meter(lv.scr_act())
meter.center()
meter.set_size(200, 200)
indic = lv.meter_indicator_t()
meter.set_indicator_start_value(indic, 0)
meter.set_indicator_end_value(indic, 20)
meter.set_indicator_start_value(indic, 80)
meter.set_indicator_end_value(indic, 100)
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A meter with multiple arcs
*/
void lv_example_meter_2(void)
{
meter = lv_meter_create(lv_scr_act());
lv_obj_center(meter);
lv_obj_set_size(meter, 200, 200);
lv_anim_set_time(&a, 2000);
lv_anim_set_playback_time(&a, 500);
lv_anim_set_var(&a, indic1);
lv_anim_start(&a);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_time(&a, 1000);
lv_anim_set_var(&a, indic2);
lv_anim_start(&a);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_time(&a, 2000);
lv_anim_set_var(&a, indic3);
lv_anim_start(&a);
}
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
def set_value(indic,v):
meter.set_indicator_end_value(indic, v)
#
# A meter with multiple arcs
#
meter = lv.meter(lv.scr_act())
meter.center()
meter.set_size(200, 200)
a2 = lv.anim_t()
a2.init()
a2.set_values(0, 100)
a2.set_time(1000)
a2.set_repeat_delay(100)
a2.set_playback_delay(100)
a2.set_playback_time(1000)
a2.set_var(indic2)
a2.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a2.set_custom_exec_cb(lambda a,val: set_value(indic2,val))
lv.anim_t.start(a2)
a3 = lv.anim_t()
a3.init()
a3.set_values(0, 100)
a3.set_time(1000)
a3.set_repeat_delay(100)
a3.set_playback_delay(100)
a3.set_playback_time(2000)
a3.set_var(indic3)
a3.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a3.set_custom_exec_cb(lambda a,val: set_value(indic3,val))
lv.anim_t.start(a3)
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* A clock from a meter
*/
void lv_example_meter_3(void)
{
meter = lv_meter_create(lv_scr_act());
lv_obj_set_size(meter, 220, 220);
lv_obj_center(meter);
/*Create another scale for the hours. It's only visual and contains only major␣
,→ ticks*/
lv_meter_scale_t * scale_hour = lv_meter_add_scale(meter);
lv_meter_set_scale_ticks(meter, scale_hour, 12, 0, 0, lv_palette_main(LV_PALETTE_
,→GREY)); /*12 ticks*/
lv_meter_set_scale_major_ticks(meter, scale_hour, 1, 2, 20, lv_color_black(), 10);
,→ /*Every tick is major*/
lv_meter_set_scale_range(meter, scale_hour, 1, 12, 330, 300); /*[1..12]␣
,→values in an almost full circle*/
LV_IMG_DECLARE(img_hand)
lv_anim_set_var(&a, indic_hour);
(continues on next page)
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
img_hand_min_dsc = lv.img_dsc_t({
'data_size': len(img_hand_min_data),
'data': img_hand_min_data
})
img_hand_hour_dsc = lv.img_dsc_t({
'data_size': len(img_hand_hour_data),
'data': img_hand_hour_data
})
meter = lv.meter(lv.scr_act())
meter.set_size(220, 220)
meter.center()
# Create another scale for the hours. It's only visual and contains only major ticks
scale_hour = meter.add_scale()
meter.set_scale_ticks(scale_hour, 12, 0, 0, lv.palette_main(lv.PALETTE.GREY)) # 12␣
,→ticks
# LV_IMG_DECLARE(img_hand)
a2 = lv.anim_t()
a2.init()
a2.set_var(indic_hour)
a2.set_time(24000) # 24 sec for 1 turn of the hour hand
a2.set_values(0, 60)
a2.set_custom_exec_cb(lambda a2,val: set_value(indic_hour,val))
lv.anim_t.start(a2)
Pie chart
#include "../../lv_examples.h"
#if LV_USE_METER && LV_BUILD_EXAMPLES
/**
* Create a pie chart
*/
void lv_example_meter_4(void)
{
lv_obj_t * meter = lv_meter_create(lv_scr_act());
#endif
#
# Create a pie chart
#
meter = lv.meter(lv.scr_act())
meter.set_size(200, 200)
meter.center()
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_METER_INDICATOR_TYPE_NEEDLE_IMG
enumerator LV_METER_INDICATOR_TYPE_NEEDLE_LINE
enumerator LV_METER_INDICATOR_TYPE_SCALE_LINES
enumerator LV_METER_INDICATOR_TYPE_ARC
enum lv_meter_draw_part_type_t
type field in lv_obj_draw_part_dsc_t if class_p = lv_meter_class Used in
LV_EVENT_DRAW_PART_BEGIN and LV_EVENT_DRAW_PART_END
Values:
enumerator LV_METER_DRAW_PART_ARC
The arc indicator
enumerator LV_METER_DRAW_PART_NEEDLE_LINE
The needle lines
enumerator LV_METER_DRAW_PART_NEEDLE_IMG
The needle images
enumerator LV_METER_DRAW_PART_TICK
The tick lines and labels
Functions
Note: the needle image should point to the right, like -O-->
Parameters
• obj -- pointer to a meter object
• scale -- pointer to scale (added to meter)
• src -- the image source of the indicator. path or pointer to lv_img_dsc_t
• pivot_x -- the X pivot point of the needle
• pivot_y -- the Y pivot point of the needle
Returns the new indicator
• r_mod -- the radius modifier (added to the scale's radius) to get the outer radius of the arc
Returns the new indicator
lv_meter_indicator_t *lv_meter_add_scale_lines(lv_obj_t *obj, lv_meter_scale_t *scale, lv_color_t
color_start, lv_color_t color_end, bool local, int16_t
width_mod)
Add a scale line indicator the scale. It will modify the ticks.
Parameters
• obj -- pointer to a meter object
• scale -- pointer to scale (added to meter)
• color_start -- the start color
• color_end -- the end color
• local -- tell how to map start and end color. true: the indicator's start and end_value; false:
the scale's min max value
• width_mod -- add this the affected tick's width
Returns the new indicator
void lv_meter_set_indicator_value(lv_obj_t *obj, lv_meter_indicator_t *indic, int32_t value)
Set the value of the indicator. It will set start and and value to the same value
Parameters
• obj -- pointer to a meter object
• indic -- pointer to an indicator
• value -- the new value
void lv_meter_set_indicator_start_value(lv_obj_t *obj, lv_meter_indicator_t *indic, int32_t value)
Set the start value of the indicator.
Parameters
• obj -- pointer to a meter object
• indic -- pointer to an indicator
• value -- the new value
void lv_meter_set_indicator_end_value(lv_obj_t *obj, lv_meter_indicator_t *indic, int32_t value)
Set the start value of the indicator.
Parameters
• obj -- pointer to a meter object
• indic -- pointer to an indicator
• value -- the new value
Variables
struct lv_meter_scale_t
Public Members
lv_color_t tick_color
uint16_t tick_cnt
uint16_t tick_length
uint16_t tick_width
lv_color_t tick_major_color
uint16_t tick_major_nth
uint16_t tick_major_length
uint16_t tick_major_width
int16_t label_gap
int32_t min
int32_t max
int16_t r_mod
uint16_t angle_range
int16_t rotation
struct lv_meter_indicator_t
Public Members
lv_meter_scale_t *scale
lv_meter_indicator_type_t type
lv_opa_t opa
int32_t start_value
int32_t end_value
lv_point_t pivot
uint16_t width
int16_t r_mod
lv_color_t color
int16_t width_mod
lv_color_t color_start
lv_color_t color_end
uint8_t local_grad
struct lv_meter_t
Public Members
lv_obj_t obj
lv_ll_t scale_ll
lv_ll_t indicator_ll
Overview
The Message boxes act as pop-ups. They are built from a background container, a title, an optional close button, a text
and optional buttons.
The text will be broken into multiple lines automatically and the height will be set automatically to include the text and
the buttons.
The message box can be modal (blocking clicks on the rest of the screen) or not modal.
The message box is built from other widgets, so you can check these widgets' documentation for details.
• Background: lv_obj
• Close button: lv_btn
• Title and text: lv_label
• Buttons: lv_btnmatrix
Usage
The building blocks of the message box can be obtained using the following functions:
Events
Keys
Keys have effect on the close button and button matrix. You can add them manually to a group if required.
Learn more about Keys.
Example
#include "../../lv_examples.h"
#if LV_USE_MSGBOX && LV_BUILD_EXAMPLES
void lv_example_msgbox_1(void)
{
static const char * btns[] = {"Apply", "Close", ""};
#endif
def event_cb(e):
mbox = e.get_current_target()
print("Button %s clicked" % mbox.get_active_btn_text())
API
Functions
lv_obj_t *lv_msgbox_create(lv_obj_t *parent, const char *title, const char *txt, const char *btn_txts[], bool
add_close_btn)
Create a message box object
Parameters
• parent -- pointer to parent or NULL to create a full screen modal message box
• title -- the title of the message box
• txt -- the text of the message box
• btn_txts -- the buttons as an array of texts terminated by an "" element. E.g. {"btn1",
"btn2", ""}
• add_close_btn -- true: add a close button
Returns pointer to the message box object
lv_obj_t *lv_msgbox_get_title(lv_obj_t *obj)
Variables
struct lv_msgbox_t
Public Members
lv_obj_t obj
lv_obj_t *title
lv_obj_t *close_btn
lv_obj_t *content
lv_obj_t *text
lv_obj_t *btns
Overview
A spangroup is the object that is used to display rich text. Different from the label object, spangroup can render text
styled with different fonts, colors, and sizes into the spangroup object.
Usage
The spangroup object uses span to describe text and text style. so, first we need to create span de-
scriptor using lv_span_t * span = lv_spangroup_new_span(spangroup). Then use
lv_span_set_text(span, "text") to set text. The style of the span is configured as with
a normal style object by using its style member, eg:lv_style_set_text_color(&span->style,
lv_palette_main(LV_PALETTE_RED)).
If spangroup object mode != LV_SPAN_MODE_FIXED you must call lv_spangroup_refr_mode() after you
have modified span style(eg:set text, changed the font size, del span).
Spangroups store their children differently from normal objects, so normal functions for getting children won't work.
lv_spangroup_get_child(spangroup, id) will return a pointer to the child span at index id. In addition,
id can be negative to index from the end of the spangroup where -1 is the youngest child, -2 is second youngest, etc.
e.g. lv_span_t* span = lv_spangroup_get_child(spangroup, 0) will return the first child of the
spangroup. lv_span_t* span = lv_spangroup_get_child(spangroup, -1) will return the last (or
most recent) child.
Child Count
Use the function lv_spangroup_get_child_cnt(spangroup) to get back the number of spans the group is
maintaining.
e.g. uint32_t size = lv_spangroup_get_child_cnt(spangroup)
Text align
like label object, the spangroup can be set to one the following modes:
• LV_TEXT_ALIGN_LEFT Align text to left.
• LV_TEXT_ALIGN_CENTER Align text to center.
• LV_TEXT_ALIGN_RIGHT Align text to right.
• LV_TEXT_ALIGN_AUTO Align text auto.
use function lv_spangroup_set_align(spangroup, LV_TEXT_ALIGN_CENTER) to set text align.
Modes
Overflow
Use lv_spangroup_set_indent(spangroup, 20) to set the indent of the first line. All modes support pixel
units, in addition to LV_SPAN_MODE_FIXED and LV_SPAN_MODE_BREAK mode supports percentage units too.
lines
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_SPAN && LV_BUILD_EXAMPLES
/**
* Create span.
*/
void lv_example_span_1(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_border_width(&style, 1);
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_ORANGE));
lv_style_set_pad_all(&style, 2);
lv_spangroup_set_align(spans, LV_TEXT_ALIGN_LEFT);
lv_spangroup_set_overflow(spans, LV_SPAN_OVERFLOW_CLIP);
lv_spangroup_set_indent(spans, 20);
lv_spangroup_set_mode(spans, LV_SPAN_MODE_BREAK);
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "good good study, day day up.");
#if LV_FONT_MONTSERRAT_24
lv_style_set_text_font(&span->style, &lv_font_montserrat_24);
#endif
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_GREEN));
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "LVGL is an open-source graphics library.");
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_BLUE));
span = lv_spangroup_new_span(spans);
lv_span_set_text_static(span, "the boy no name.");
lv_style_set_text_color(&span->style, lv_palette_main(LV_PALETTE_GREEN));
#if LV_FONT_MONTSERRAT_20
lv_style_set_text_font(&span->style, &lv_font_montserrat_20);
#endif
lv_style_set_text_decor(&span->style, LV_TEXT_DECOR_UNDERLINE);
span = lv_spangroup_new_span(spans);
lv_span_set_text(span, "I have a dream that hope to come true.");
lv_style_set_text_decor(&span->style, LV_TEXT_DECOR_STRIKETHROUGH);
(continues on next page)
lv_spangroup_refr_mode(spans);
}
#endif
#
# Create span
#
style = lv.style_t()
style.init()
style.set_border_width(1)
style.set_border_color(lv.palette_main(lv.PALETTE.ORANGE))
style.set_pad_all(2)
spans = lv.spangroup(lv.scr_act())
spans.set_width(300)
spans.set_height(300)
spans.center()
spans.add_style(style, 0)
spans.set_align(lv.TEXT_ALIGN.LEFT)
spans.set_overflow(lv.SPAN_OVERFLOW.CLIP)
spans.set_indent(20)
spans.set_mode(lv.SPAN_MODE.BREAK)
span = spans.new_span()
span.set_text("china is a beautiful country.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.RED))
span.style.set_text_decor(lv.TEXT_DECOR.STRIKETHROUGH | lv.TEXT_DECOR.UNDERLINE)
span.style.set_text_opa(lv.OPA._30)
span = spans.new_span()
span.set_text_static("good good study, day day up.")
#if LV_FONT_MONTSERRAT_24
# lv_style_set_text_font(&span->style, &lv_font_montserrat_24);
#endif
span.style.set_text_color(lv.palette_main(lv.PALETTE.GREEN))
span = spans.new_span()
span.set_text_static("LVGL is an open-source graphics library.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.BLUE))
span = spans.new_span()
span.set_text_static("the boy no name.")
span.style.set_text_color(lv.palette_main(lv.PALETTE.GREEN))
#if LV_FONT_MONTSERRAT_20
# lv_style_set_text_font(&span->style, &lv_font_montserrat_20);
#endif
span.style.set_text_decor(lv.TEXT_DECOR.UNDERLINE)
span = spans.new_span()
span.set_text("I have a dream that hope to come true.")
spans.refr_mode()
API
Typedefs
Enums
enum [anonymous]
Values:
enumerator LV_SPAN_OVERFLOW_CLIP
enumerator LV_SPAN_OVERFLOW_ELLIPSIS
enum [anonymous]
Values:
enumerator LV_SPAN_MODE_FIXED
fixed the obj size
enumerator LV_SPAN_MODE_EXPAND
Expand the object size to the text size
enumerator LV_SPAN_MODE_BREAK
Keep width, break the too long lines and expand height
Functions
Parameters obj -- The spangroup object to get the child count of.
Returns The span count of the spangroup.
lv_text_align_t lv_spangroup_get_align(lv_obj_t *obj)
get the align of the spangroup.
Parameters obj -- pointer to a spangroup object.
Returns the align value.
lv_span_overflow_t lv_spangroup_get_overflow(lv_obj_t *obj)
get the overflow of the spangroup.
Parameters obj -- pointer to a spangroup object.
Returns the overflow value.
lv_coord_t lv_spangroup_get_indent(lv_obj_t *obj)
get the indent of the spangroup.
Parameters obj -- pointer to a spangroup object.
Returns the indent value.
lv_span_mode_t lv_spangroup_get_mode(lv_obj_t *obj)
get the mode of the spangroup.
Parameters obj -- pointer to a spangroup object.
int32_t lv_spangroup_get_lines(lv_obj_t *obj)
get lines of the spangroup.
Parameters obj -- pointer to a spangroup object.
Returns the lines value.
Variables
struct lv_span_t
Public Members
char *txt
lv_obj_t *spangroup
lv_style_t style
uint8_t static_flag
struct lv_spangroup_t
#include <lv_span.h> Data of label
Public Members
lv_obj_t obj
int32_t lines
lv_coord_t indent
lv_coord_t cache_w
lv_coord_t cache_h
lv_ll_t child_ll
uint8_t mode
uint8_t overflow
uint8_t refresh
Overview
The Spinbox contains a number as text which can be increased or decreased by Keys or API functions. Under the hood
the Spinbox is a modified Text area.
If an encoder is used as input device, the selected digit is shifted to the right by default when-
ever the encoder button is clicked. To change this behaviour to shifting to the left, the
lv_spinbox_set_digit_step_direction(spinbox, LV_DIR_LEFT) can be used
Format
Rollover
Events
Keys
• LV_KEY_LEFT/RIGHT With Keypad move the cursor left/right. With Encoder decrement/increment the se-
lected digit.
• LV_KEY_UP/DOWN With Keypad and Encoder increment/decrement the value.
• LV_KEY_ENTER With Encoder got the next digit. Jump to the first after the last.
Example
Simple Spinbox
#include "../../lv_examples.h"
#if LV_USE_SPINBOX && LV_BUILD_EXAMPLES
void lv_example_spinbox_1(void)
{
spinbox = lv_spinbox_create(lv_scr_act());
lv_spinbox_set_range(spinbox, -1000, 25000);
lv_spinbox_set_digit_format(spinbox, 5, 2);
lv_spinbox_step_prev(spinbox);
lv_obj_set_width(spinbox, 100);
lv_obj_center(spinbox);
lv_coord_t h = lv_obj_get_height(spinbox);
btn = lv_btn_create(lv_scr_act());
lv_obj_set_size(btn, h, h);
lv_obj_align_to(btn, spinbox, LV_ALIGN_OUT_LEFT_MID, -5, 0);
lv_obj_set_style_bg_img_src(btn, LV_SYMBOL_MINUS, 0);
lv_obj_add_event_cb(btn, lv_spinbox_decrement_event_cb, LV_EVENT_ALL, NULL);
}
#endif
def increment_event_cb(e):
code = e.get_code()
if code == lv.EVENT.SHORT_CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
spinbox.increment()
def decrement_event_cb(e):
code = e.get_code()
if code == lv.EVENT.SHORT_CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
spinbox.decrement()
spinbox = lv.spinbox(lv.scr_act())
spinbox.set_range(-1000, 25000)
spinbox.set_digit_format(5, 2)
spinbox.step_prev()
spinbox.set_width(100)
spinbox.center()
h = spinbox.get_height()
btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_RIGHT_MID, 5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.PLUS, 0)
(continues on next page)
btn = lv.btn(lv.scr_act())
btn.set_size(h, h)
btn.align_to(spinbox, lv.ALIGN.OUT_LEFT_MID, -5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.MINUS, 0)
btn.add_event_cb(decrement_event_cb, lv.EVENT.ALL, None)
API
Functions
Variables
struct lv_spinbox_t
Public Members
lv_textarea_t ta
int32_t value
int32_t range_max
int32_t range_min
int32_t step
uint16_t digit_count
uint16_t dec_point_pos
uint16_t rollover
uint16_t digit_step_dir
Example
Overview
Usage
Create a spinner
To create a spinner use lv_spinner_create(parent, spin_time, arc_length). spin time sets the
spin time in milliseconds, arc_length sets the length of the spinning arc in degrees.
Events
Keys
Example
Simple spinner
#include "../../lv_examples.h"
#if LV_USE_SPINNER && LV_BUILD_EXAMPLES
void lv_example_spinner_1(void)
{
/*Create a spinner*/
lv_obj_t * spinner = lv_spinner_create(lv_scr_act(), 1000, 60);
lv_obj_set_size(spinner, 100, 100);
lv_obj_center(spinner);
}
#endif
# Create a spinner
spinner = lv.spinner(lv.scr_act(), 1000, 60)
spinner.set_size(100, 100)
spinner.center()
API
Functions
Variables
Overview
The Tab view object can be used to organize content in tabs. The Tab view is built from other widgets:
• Main container: lv_obj)
– Tab buttons: lv_btnmatrix
– Container for the tabs: lv_obj
∗ Content of the tabs: lv_obj
The tab buttons can be positioned on the top, bottom, left and right side of the Tab view.
A new tab can be selected either by clicking on a tab button or by sliding horizontally on the content.
There are no special parts on the Tab view but the lv_obj and lv_btnnmatrix widgets are used to create the Tab
view.
Usage
lv_tabview_create(parent, tab_pos, tab_size); creates a new empty Tab view. tab_pos can be
LV_DIR_TOP/BOTTOM/LEFT/RIGHT to position the tab buttons to a side. tab_size is the height (in case of
LV_DIR_TOP/BOTTOM) or width (in case of LV_DIR_LEFT/RIGHT) tab buttons.
Add tabs
New tabs can be added with lv_tabview_add_tab(tabview, "Tab name"). This will return a pointer to an
lv_obj object where the tab's content can be created.
Rename tabs
Change tab
Events
• LV_EVENT_VALUE_CHANGED Sent when a new tab is selected by sliding or clicking the tab button.
lv_tabview_get_tab_act(tabview) returns the zero based index of the current tab.
Learn more about Events.
Keys
Keys have effect only on the tab buttons (Button matrix). Add manually to a group if required.
Learn more about Keys.
Example
Simple Tabview
#include "../../lv_examples.h"
#if LV_USE_TABVIEW && LV_BUILD_EXAMPLES
void lv_example_tabview_1(void)
{
/*Create a Tab view object*/
lv_obj_t * tabview;
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 50);
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1");
lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2");
lv_obj_t * tab3 = lv_tabview_add_tab(tabview, "Tab 3");
label = lv_label_create(tab2);
lv_label_set_text(label, "Second tab");
label = lv_label_create(tab3);
lv_label_set_text(label, "Third tab");
lv_obj_scroll_to_view_recursive(label, LV_ANIM_ON);
}
#endif
# Add 3 tabs (the tabs are page (lv_page) and can be scrolled
tab1 = tabview.add_tab("Tab 1")
tab2 = tabview.add_tab("Tab 2")
tab3 = tabview.add_tab("Tab 3")
If the content
of a tab
becomes too
longer
than the
container
then it
automatically
becomes
scrollable.
label = lv.label(tab2)
label.set_text("Second tab")
(continues on next page)
label = lv.label(tab3)
label.set_text("Third tab");
label.scroll_to_view_recursive(lv.ANIM.ON)
#include "../../lv_examples.h"
#if LV_USE_TABVIEW && LV_BUILD_EXAMPLES
void lv_example_tabview_2(void)
{
/*Create a Tab view object*/
lv_obj_t * tabview;
tabview = lv_tabview_create(lv_scr_act(), LV_DIR_LEFT, 80);
/*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/
lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1");
lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2");
lv_obj_t * tab3 = lv_tabview_add_tab(tabview, "Tab 3");
lv_obj_t * tab4 = lv_tabview_add_tab(tabview, "Tab 4");
lv_obj_t * tab5 = lv_tabview_add_tab(tabview, "Tab 5");
label = lv_label_create(tab2);
lv_label_set_text(label, "Second tab");
label = lv_label_create(tab3);
lv_label_set_text(label, "Third tab");
label = lv_label_create(tab4);
lv_label_set_text(label, "Forth tab");
label = lv_label_create(tab5);
lv_label_set_text(label, "Fifth tab");
lv_obj_clear_flag(lv_tabview_get_content(tabview), LV_OBJ_FLAG_SCROLLABLE);
}
#endif
tab_btns = tabview.get_tab_btns()
tab_btns.set_style_bg_color(lv.palette_darken(lv.PALETTE.GREY, 3), 0)
tab_btns.set_style_text_color(lv.palette_lighten(lv.PALETTE.GREY, 5), 0)
tab_btns.set_style_border_side(lv.BORDER_SIDE.RIGHT, lv.PART.ITEMS | lv.STATE.CHECKED)
# Add 3 tabs (the tabs are page (lv_page) and can be scrolled
tab1 = tabview.add_tab("Tab 1")
tab2 = tabview.add_tab("Tab 2")
tab3 = tabview.add_tab("Tab 3")
tab4 = tabview.add_tab("Tab 4")
tab5 = tabview.add_tab("Tab 5")
tab2.set_style_bg_color(lv.palette_lighten(lv.PALETTE.AMBER, 3), 0)
tab2.set_style_bg_opa(lv.OPA.COVER, 0)
label = lv.label(tab2)
label.set_text("Second tab")
label = lv.label(tab3)
label.set_text("Third tab")
label = lv.label(tab4)
label.set_text("Forth tab")
label = lv.label(tab5)
label.set_text("Fifth tab")
tabview.get_content().clear_flag(lv.obj.FLAG.SCROLLABLE)
API
Functions
Variables
struct lv_tabview_t
Public Members
lv_obj_t obj
uint16_t tab_cnt
uint16_t tab_cur
lv_dir_t tab_pos
Overview
The Tile view is a container object whose elements (called tiles) can be arranged in grid form. A user can navigate between
the tiles by swiping. Any direction of swiping can be disabled on the tiles individually to not allow moving from one tile
to another.
If the Tile view is screen sized, the user interface resembles what you may have seen on smartwatches.
The Tile view is built from an lv_obj container and lv_obj tiles.
The parts and styles work the same as for lv_obj.
Usage
Add a tile
lv_tileview_add_tile(tileview, row_id, col_id, dir) creates a new tile on the row_idth row
and col_idth column. dir can be LV_DIR_LEFT/RIGHT/TOP/BOTTOM/HOR/VER/ALL or OR-ed values to
enable moving to the adjacent tiles into the given direction by swiping.
The returned value is an lv_obj_t * on which the content of the tab can be created.
Change tile
The Tile view can scroll to a tile with lv_obj_set_tile(tileview, tile_obj, LV_ANIM_ON/OFF) or
lv_obj_set_tile_id(tileviewv, col_id, row_id, LV_ANIM_ON/OFF);
Events
Keys
Example
#include "../../lv_examples.h"
#if LV_USE_TILEVIEW && LV_BUILD_EXAMPLES
/**
* Create a 2x2 tile view and allow scrolling only in an "L" shape.
* Demonstrate scroll chaining with a long list that
* scrolls the tile view when it can't be scrolled further.
*/
void lv_example_tileview_1(void)
{
lv_obj_t * tv = lv_tileview_create(lv_scr_act());
/*Tile2: a button*/
lv_obj_t * tile2 = lv_tileview_add_tile(tv, 0, 1, LV_DIR_TOP | LV_DIR_RIGHT);
label = lv_label_create(btn);
lv_label_set_text(label, "Scroll up or right");
/*Tile3: a list*/
lv_obj_t * tile3 = lv_tileview_add_tile(tv, 1, 1, LV_DIR_LEFT);
lv_obj_t * list = lv_list_create(tile3);
lv_obj_set_size(list, LV_PCT(100), LV_PCT(100));
(continues on next page)
#endif
#
# Create a 2x2 tile view and allow scrolling only in an "L" shape.
# Demonstrate scroll chaining with a long list that
# scrolls the tile view when it can't be scrolled further.
#
tv = lv.tileview(lv.scr_act())
# Tile2: a button
tile2 = tv.add_tile(0, 1, lv.DIR.TOP | lv.DIR.RIGHT)
btn = lv.btn(tile2)
label = lv.label(btn)
label.set_text("Scroll up or right")
btn.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
btn.center()
# Tile3: a list
tile3 = tv.add_tile(1, 1, lv.DIR.LEFT)
list = lv.list(tile3)
list.set_size(lv.pct(100), lv.pct(100))
list.add_btn(None, "One")
list.add_btn(None, "Two")
list.add_btn(None, "Three")
list.add_btn(None, "Four")
list.add_btn(None, "Five")
list.add_btn(None, "Six")
list.add_btn(None, "Seven")
list.add_btn(None, "Eight")
list.add_btn(None, "Nine")
list.add_btn(None, "Ten")
API
Functions
Variables
struct lv_tileview_t
Public Members
lv_obj_t obj
lv_obj_t *tile_act
struct lv_tileview_tile_t
Public Members
lv_obj_t obj
lv_dir_t dir
Overview
The Window is container-like object built from a header with title and buttons and a content area.
The Window is built from other widgets so you can check their documentation for details:
• Background: lv_obj
• Header on the background: lv_obj
• Title on the header: lv_label
• Buttons on the header: lv_btn
• Content area on the background: lv_obj
Usage
Create a Window
Any number of texts (but typically only one) can be added to the header with lv_win_add_title(win, "The
title").
Control buttons can be added to the window's header with lv_win_add_btn(win, icon, btn_width). icon
can be any image source, and btn_width is the width of the button.
The title and the buttons will be added in the order the functions are called. So adding a button, a text and two other
buttons will result in a button on the left, a title, and 2 buttons on the right. The width of the title is set to take all the
remaining space on the header. In other words: it pushes to the right all the buttons that are added after the title.
Events
No special events are sent by the windows, however events can be added manually to the return value of
lv_win_add_btn.
Learn more about Events.
Keys
Example
Simple window
#include "../../lv_examples.h"
#if LV_USE_WIN && LV_BUILD_EXAMPLES
void lv_example_win_1(void)
{
lv_obj_t * win = lv_win_create(lv_scr_act(), 40);
lv_obj_t * btn;
btn = lv_win_add_btn(win, LV_SYMBOL_LEFT, 40);
lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL);
#endif
def event_handler(e):
code = e.get_code()
(continues on next page)
We need
quite some text
and we will
even put
some more
text to be
sure it
overflows.
""")
API
Functions
Variables
struct lv_win_t
Public Members
lv_obj_t obj
SEVEN
LAYOUTS
7.1 Flex
7.1.1 Overview
7.1.2 Terms
With the following functions you can set a Flex layout on any parent.
789
LVGL Documentation 8.3
Flex flow
lv_obj_set_flex_flow(obj, flex_flow)
The possible values for flex_flow are:
• LV_FLEX_FLOW_ROW Place the children in a row without wrapping
• LV_FLEX_FLOW_COLUMN Place the children in a column without wrapping
• LV_FLEX_FLOW_ROW_WRAP Place the children in a row with wrapping
• LV_FLEX_FLOW_COLUMN_WRAP Place the children in a column with wrapping
• LV_FLEX_FLOW_ROW_REVERSE Place the children in a row without wrapping but in reversed order
• LV_FLEX_FLOW_COLUMN_REVERSE Place the children in a column without wrapping but in reversed order
• LV_FLEX_FLOW_ROW_WRAP_REVERSE Place the children in a row with wrapping but in reversed order
• LV_FLEX_FLOW_COLUMN_WRAP_REVERSE Place the children in a column with wrapping but in reversed
order
Flex align
Flex grow
Flex grow can be used to make one or more children fill the available space on the track. When more children have
grow parameters, the available space will be distributed proportionally to the grow values. For example, there is 400 px
remaining space and 4 objects with grow:
• A with grow = 1
• B with grow = 1
• C with grow = 2
A and B will have 100 px size, and C will have 200 px size.
Flex grow can be set on a child with lv_obj_set_flex_grow(child, value). value needs to be > 1 or 0
to disable grow on the child.
All the Flex-related values are style properties under the hood and you can use them similarly to any other style property.
The following flex related style properties exist:
• FLEX_FLOW
• FLEX_MAIN_PLACE
• FLEX_CROSS_PLACE
• FLEX_TRACK_PLACE
• FLEX_GROW
Internal padding
To modify the minimum space flexbox inserts between objects, the following properties can be set on the flex container
style:
• pad_row Sets the padding between the rows.
• pad_column Sets the padding between the columns.
These can for example be used if you don't want any padding between your objects:
lv_style_set_pad_column(&row_container_style,0)
RTL
If the base direction of the container is set the LV_BASE_DIR_RTL the meaning of LV_FLEX_ALIGN_START and
LV_FLEX_ALIGN_END is swapped on ROW layouts. I.e. START will mean right.
The items on ROW layouts, and tracks of COLUMN layouts will be placed from right to left.
New track
You can force Flex to put an item into a new line with lv_obj_add_flag(child,
LV_OBJ_FLAG_FLEX_IN_NEW_TRACK).
7.1.6 Example
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* A simple row and a column layout with flexbox
*/
void lv_example_flex_1(void)
{
/*Create a container with ROW flex direction*/
lv_obj_t * cont_row = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont_row, 300, 75);
lv_obj_align(cont_row, LV_ALIGN_TOP_MID, 0, 5);
lv_obj_set_flex_flow(cont_row, LV_FLEX_FLOW_ROW);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * obj;
lv_obj_t * label;
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "Item: %"LV_PRIu32, i);
lv_obj_center(label);
}
}
#endif
#
# A simple row and a column layout with flexbox
#
for i in range(10):
# Add items to the row
obj = lv.btn(cont_row)
obj.set_size(100, lv.pct(100))
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
label = lv.label(obj)
label.set_text("Item: {:d}".format(i))
label.center()
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Arrange items in rows with wrap and place the items to get even space around them.
*/
void lv_example_flex_2(void)
{
static lv_style_t style;
lv_style_init(&style);
lv_style_set_flex_flow(&style, LV_FLEX_FLOW_ROW_WRAP);
lv_style_set_flex_main_place(&style, LV_FLEX_ALIGN_SPACE_EVENLY);
lv_style_set_layout(&style, LV_LAYOUT_FLEX);
#endif
#
# Arrange items in rows with wrap and place the items to get even space around them.
#
style = lv.style_t()
style.init()
style.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
style.set_flex_main_place(lv.FLEX_ALIGN.SPACE_EVENLY)
style.set_layout(lv.LAYOUT_FLEX.value)
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.add_style(style, 0)
for i in range(8):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text("{:d}".format(i))
label.center()
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate flex grow.
*/
void lv_example_flex_3(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
lv_obj_t * obj;
obj = lv_obj_create(cont);
(continues on next page)
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 1); /*1 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
lv_obj_set_flex_grow(obj, 2); /*2 portion from the free space*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, 40, 40); /*Fix size. It is flushed to the right by␣
,→the "grow" items*/
#endif
#
# Demonstrate flex grow.
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW)
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(1) # 1 portion from the free space
obj = lv.obj(cont)
obj.set_height(40)
obj.set_flex_grow(2) # 2 portion from the free space
obj = lv.obj(cont)
obj.set_size(40, 40) # Fix size. It is flushed to the right by the "grow"␣
,→items
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Reverse the order of flex items
*/
void lv_example_flex_4(void)
{
uint32_t i;
for(i = 0; i < 6; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 100, 50);
#endif
#
# Reverse the order of flex items
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.COLUMN_REVERSE)
for i in range(6):
obj = lv.obj(cont)
obj.set_size(100, 50)
label = lv.label(obj)
label.set_text("Item: " + str(i))
label.center()
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate the effect of column and row gap style properties
*/
void lv_example_flex_5(void)
{
(continues on next page)
uint32_t i;
for(i = 0; i < 9; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, cont);
lv_anim_set_values(&a, 0, 10);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, row_gap_anim);
lv_anim_set_time(&a, 500);
lv_anim_set_playback_time(&a, 500);
lv_anim_start(&a);
lv_anim_set_exec_cb(&a, column_gap_anim);
lv_anim_set_time(&a, 3000);
lv_anim_set_playback_time(&a, 3000);
lv_anim_start(&a);
}
#endif
#
# Demonstrate the effect of column and row gap style properties
#
cont = lv.obj(lv.scr_act())
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(9):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
(continues on next page)
a_row = lv.anim_t()
a_row.init()
a_row.set_var(cont)
a_row.set_values(0, 10)
a_row.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_row.set_time(500)
a_row.set_playback_time(500)
a_row.set_custom_exec_cb(lambda a,val: row_gap_anim(cont,val))
lv.anim_t.start(a_row)
a_col = lv.anim_t()
a_col.init()
a_col.set_var(cont)
a_col.set_values(0, 10)
a_col.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_col.set_time(3000)
a_col.set_playback_time(3000)
a_col.set_custom_exec_cb(lambda a,val: column_gap_anim(cont,val))
lv.anim_t.start(a_col)
#include "../../lv_examples.h"
#if LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* RTL base direction changes order of the items.
* Also demonstrate how horizontal scrolling works with RTL.
*/
void lv_example_flex_6(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_style_base_dir(cont, LV_BASE_DIR_RTL, 0);
lv_obj_set_size(cont, 300, 220);
lv_obj_center(cont);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW_WRAP);
uint32_t i;
for(i = 0; i < 20; i++) {
lv_obj_t * obj = lv_obj_create(cont);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
#
# RTL base direction changes order of the items.
# Also demonstrate how horizontal scrolling works with RTL.
#
cont = lv.obj(lv.scr_act())
cont.set_style_base_dir(lv.BASE_DIR.RTL,0)
cont.set_size(300, 220)
cont.center()
cont.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
for i in range(20):
obj = lv.obj(cont)
obj.set_size(70, lv.SIZE.CONTENT)
label = lv.label(obj)
label.set_text(str(i))
label.center()
7.1.7 API
Enums
enum lv_flex_align_t
Values:
enumerator LV_FLEX_ALIGN_START
enumerator LV_FLEX_ALIGN_END
enumerator LV_FLEX_ALIGN_CENTER
enumerator LV_FLEX_ALIGN_SPACE_EVENLY
enumerator LV_FLEX_ALIGN_SPACE_AROUND
enumerator LV_FLEX_ALIGN_SPACE_BETWEEN
enum lv_flex_flow_t
Values:
enumerator LV_FLEX_FLOW_ROW
enumerator LV_FLEX_FLOW_COLUMN
enumerator LV_FLEX_FLOW_ROW_WRAP
enumerator LV_FLEX_FLOW_ROW_REVERSE
enumerator LV_FLEX_FLOW_ROW_WRAP_REVERSE
enumerator LV_FLEX_FLOW_COLUMN_WRAP
enumerator LV_FLEX_FLOW_COLUMN_REVERSE
enumerator LV_FLEX_FLOW_COLUMN_WRAP_REVERSE
Functions
LV_EXPORT_CONST_INT(LV_OBJ_FLAG_FLEX_IN_NEW_TRACK)
void lv_flex_init(void)
Initialize a flex layout the default values
Parameters flex -- pointer to a flex layout descriptor
void lv_obj_set_flex_flow(lv_obj_t *obj, lv_flex_flow_t flow)
Set hot the item should flow
Parameters
• flex -- pointer to a flex layout descriptor
• flow -- an element of lv_flex_flow_t.
void lv_obj_set_flex_align(lv_obj_t *obj, lv_flex_align_t main_place, lv_flex_align_t cross_place,
lv_flex_align_t track_cross_place)
Set how to place (where to align) the items and tracks
Parameters
• flex -- pointer: to a flex layout descriptor
• main_place -- where to place the items on main axis (in their track). Any value of
lv_flex_align_t.
• cross_place -- where to place the item in their track on the cross axis.
LV_FLEX_ALIGN_START/END/CENTER
• track_place -- where to place the tracks in the cross direction. Any value of
lv_flex_align_t.
void lv_obj_set_flex_grow(lv_obj_t *obj, uint8_t grow)
Sets the width or height (on main axis) to grow the object in order fill the free space
Parameters
• obj -- pointer to an object. The parent must have flex layout else nothing will happen.
• grow -- a value to set how much free space to take proportionally to other growing items.
void lv_style_set_flex_flow(lv_style_t *style, lv_flex_flow_t value)
Variables
uint16_t LV_LAYOUT_FLEX
lv_style_prop_t LV_STYLE_FLEX_FLOW
lv_style_prop_t LV_STYLE_FLEX_MAIN_PLACE
lv_style_prop_t LV_STYLE_FLEX_CROSS_PLACE
lv_style_prop_t LV_STYLE_FLEX_TRACK_PLACE
lv_style_prop_t LV_STYLE_FLEX_GROW
7.2 Grid
7.2.1 Overview
7.2.2 Terms
With the following functions you can easily set a Grid layout on any parent.
Grid descriptors
First you need to describe the size of rows and columns. It can be done by declaring 2 arrays and the track sizes in them.
The last element must be LV_GRID_TEMPLATE_LAST.
For example:
static lv_coord_t row_dsc[] = {100, 100, 100, LV_GRID_TEMPLATE_LAST}; /*3 100 px tall␣
,→rows*/
Grid items
By default, the children are not added to the grid. They need to be added manually to a cell.
To do this call lv_obj_set_grid_cell(child, column_align, column_pos, column_span,
row_align, row_pos, row_span).
column_align and row_align determine how to align the children in its cell. The possible values are:
• LV_GRID_ALIGN_START means left on a horizontally and top vertically. (default)
• LV_GRID_ALIGN_END means right on a horizontally and bottom vertically
• LV_GRID_ALIGN_CENTER simply center
colum_pos and row_pos means the zero based index of the cell into the item should be placed.
colum_span and row_span means how many tracks should the item involve from the start cell. Must be > 1.
Grid align
If there are some empty space the track can be aligned several ways:
• LV_GRID_ALIGN_START means left on a horizontally and top vertically. (default)
• LV_GRID_ALIGN_END means right on a horizontally and bottom vertically
• LV_GRID_ALIGN_CENTER simply center
• LV_GRID_ALIGN_SPACE_EVENLY items are distributed so that the spacing between any two items (and the
space to the edges) is equal. Not applies to track_cross_place.
• LV_GRID_ALIGN_SPACE_AROUND items are evenly distributed in the track with equal space around them.
Note that visually the spaces aren’t equal, since all the items have equal space on both sides. The first item will have
one unit of space against the container edge, but two units of space between the next item because that next item
has its own spacing that applies. Not applies to track_cross_place.
• LV_GRID_ALIGN_SPACE_BETWEEN items are evenly distributed in the track: first item is on the start line,
last item on the end line. Not applies to track_cross_place.
To set the track's alignment use lv_obj_set_grid_align(obj, column_align, row_align).
All the Grid related values are style properties under the hood and you can use them similarly to any other style properties.
The following Grid related style properties exist:
• GRID_COLUMN_DSC_ARRAY
• GRID_ROW_DSC_ARRAY
• GRID_COLUMN_ALIGN
• GRID_ROW_ALIGN
• GRID_CELL_X_ALIGN
• GRID_CELL_COLUMN_POS
• GRID_CELL_COLUMN_SPAN
• GRID_CELL_Y_ALIGN
• GRID_CELL_ROW_POS
• GRID_CELL_ROW_SPAN
Internal padding
To modify the minimum space Grid inserts between objects, the following properties can be set on the Grid container
style:
• pad_row Sets the padding between the rows.
• pad_column Sets the padding between the columns.
RTL
If the base direction of the container is set to LV_BASE_DIR_RTL, the meaning of LV_GRID_ALIGN_START and
LV_GRID_ALIGN_END is swapped. I.e. START will mean right-most.
The columns will be placed from right to left.
7.2.6 Example
A simple grid
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* A simple grid
*/
void lv_example_grid_1(void)
{
static lv_coord_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_btn_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
(continues on next page)
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "c%d, r%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# A simple grid
#
for i in range(9):
col = i % 3
row = i // 3
obj = lv.btn(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("c" +str(col) + "r" +str(row))
label.center()
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate cell placement and span
*/
void lv_example_grid_2(void)
{
static lv_coord_t col_dsc[] = {70, 70, 70, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {50, 50, 50, LV_GRID_TEMPLATE_LAST};
lv_obj_t * label;
lv_obj_t * obj;
/*Cell to 0;0 and align to to the start (left/top) horizontally and vertically␣
,→ too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 0, 1,
LV_GRID_ALIGN_START, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c0, r0");
/*Cell to 1;0 and align to to the start (left) horizontally and center vertically␣
,→ too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 1, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c1, r0");
/*Cell to 2;0 and align to to the start (left) horizontally and end (bottom)␣
,→ vertically too*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_START, 2, 1,
LV_GRID_ALIGN_END, 0, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c2, r0");
/*Cell to 1;1 but 2 column wide (span = 2).Set width and height to stretched.*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 1, 2,
LV_GRID_ALIGN_STRETCH, 1, 1);
label = lv_label_create(obj);
lv_label_set_text(label, "c1-2, r1");
/*Cell to 0;1 but 2 rows tall (span = 2).Set width and height to stretched.*/
obj = lv_obj_create(cont);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, 0, 1,
LV_GRID_ALIGN_STRETCH, 1, 2);
label = lv_label_create(obj);
lv_label_set_text(label, "c0\nr1-2");
}
#endif
#
(continues on next page)
# Cell to 0;0 and align to the start (left/top) horizontally and vertically too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 0, 1,
lv.GRID_ALIGN.START, 0, 1)
label = lv.label(obj)
label.set_text("c0, r0")
# Cell to 1;0 and align to the start (left) horizontally and center vertically too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 1, 1,
lv.GRID_ALIGN.CENTER, 0, 1)
label = lv.label(obj)
label.set_text("c1, r0")
# Cell to 2;0 and align to the start (left) horizontally and end (bottom) vertically␣
,→too
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.START, 2, 1,
lv.GRID_ALIGN.END, 0, 1)
label = lv.label(obj)
label.set_text("c2, r0")
# Cell to 1;1 but 2 column wide (span = 2).Set width and height to stretched.
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, 1, 2,
lv.GRID_ALIGN.STRETCH, 1, 1)
label = lv.label(obj)
label.set_text("c1-2, r1")
# Cell to 0;1 but 2 rows tall (span = 2).Set width and height to stretched.
obj = lv.obj(cont)
obj.set_size(lv.SIZE.CONTENT, lv.SIZE.CONTENT)
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, 0, 1,
lv.GRID_ALIGN.STRETCH, 1, 2)
label = lv.label(obj)
label.set_text("c0\nr1-2")
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate grid's "free unit"
*/
void lv_example_grid_3(void)
{
/*Column 1: fix width 60 px
*Column 2: 1 unit from the remaining free space
*Column 3: 2 unit from the remaining free space*/
static lv_coord_t col_dsc[] = {60, LV_GRID_FR(1), LV_GRID_FR(2), LV_GRID_TEMPLATE_
,→LAST};
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_obj_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# Demonstrate grid's "free unit"
#
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("%d,%d"%(col, row))
label.center()
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate track placement
*/
void lv_example_grid_4(void)
{
static lv_coord_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};
/*Add space between the columns and move the rows to the bottom (end)*/
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
(continues on next page)
obj = lv_obj_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# Demonstrate track placement
#
# Add space between the columns and move the rows to the bottom (end)
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("{:d}{:d}".format(col, row))
label.center()
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate column and row gap
*/
void lv_example_grid_5(void)
{
/*60x60 cells*/
static lv_coord_t col_dsc[] = {60, 60, 60, LV_GRID_TEMPLATE_LAST};
static lv_coord_t row_dsc[] = {45, 45, 45, LV_GRID_TEMPLATE_LAST};
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_obj_create(cont);
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
lv_anim_t a;
lv_anim_init(&a);
lv_anim_set_var(&a, cont);
lv_anim_set_values(&a, 0, 10);
lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&a, row_gap_anim);
lv_anim_set_time(&a, 500);
lv_anim_set_playback_time(&a, 500);
lv_anim_start(&a);
#endif
#
# Demonstrate column and row gap
#
# 60x60 cells
col_dsc = [60, 60, 60, lv.GRID_TEMPLATE.LAST]
row_dsc = [40, 40, 40, lv.GRID_TEMPLATE.LAST]
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("{:d},{:d}".format(col, row))
label.center()
a_row = lv.anim_t()
a_row.init()
a_row.set_var(cont)
a_row.set_values(0, 10)
a_row.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_row.set_time(500)
a_row.set_playback_time(500)
a_row. set_custom_exec_cb(lambda a,val: row_gap_anim(cont,val))
lv.anim_t.start(a_row)
a_col = lv.anim_t()
a_col.init()
a_col.set_var(cont)
a_col.set_values(0, 10)
a_col.set_repeat_count(lv.ANIM_REPEAT.INFINITE)
a_col.set_time(500)
(continues on next page)
#include "../../lv_examples.h"
#if LV_USE_GRID && LV_BUILD_EXAMPLES
/**
* Demonstrate RTL direction on grid
*/
void lv_example_grid_6(void)
{
lv_obj_t * label;
lv_obj_t * obj;
uint32_t i;
for(i = 0; i < 9; i++) {
uint8_t col = i % 3;
uint8_t row = i / 3;
obj = lv_obj_create(cont);
/*Stretch the cell horizontally and vertically too
*Set span to 1 to make the cell 1 column/row sized*/
lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1,
LV_GRID_ALIGN_STRETCH, row, 1);
label = lv_label_create(obj);
lv_label_set_text_fmt(label, "%d,%d", col, row);
lv_obj_center(label);
}
}
#endif
#
# Demonstrate RTL direction on grid
#
col_dsc = [60, 60, 60, lv.GRID_TEMPLATE.LAST]
row_dsc = [40, 40, 40, lv.GRID_TEMPLATE.LAST]
for i in range(9):
col = i % 3
row = i // 3
obj = lv.obj(cont)
# Stretch the cell horizontally and vertically too
# Set span to 1 to make the cell 1 column/row sized
obj.set_grid_cell(lv.GRID_ALIGN.STRETCH, col, 1,
lv.GRID_ALIGN.STRETCH, row, 1)
label = lv.label(obj)
label.set_text("{:d},{:d}".format(col, row))
label.center()
7.2.7 API
Enums
enum lv_grid_align_t
Values:
enumerator LV_GRID_ALIGN_START
enumerator LV_GRID_ALIGN_CENTER
enumerator LV_GRID_ALIGN_END
enumerator LV_GRID_ALIGN_STRETCH
enumerator LV_GRID_ALIGN_SPACE_EVENLY
enumerator LV_GRID_ALIGN_SPACE_AROUND
enumerator LV_GRID_ALIGN_SPACE_BETWEEN
Functions
LV_EXPORT_CONST_INT(LV_GRID_CONTENT)
LV_EXPORT_CONST_INT(LV_GRID_TEMPLATE_LAST)
void lv_grid_init(void)
Variables
uint16_t LV_LAYOUT_GRID
lv_style_prop_t LV_STYLE_GRID_COLUMN_DSC_ARRAY
lv_style_prop_t LV_STYLE_GRID_COLUMN_ALIGN
lv_style_prop_t LV_STYLE_GRID_ROW_DSC_ARRAY
lv_style_prop_t LV_STYLE_GRID_ROW_ALIGN
lv_style_prop_t LV_STYLE_GRID_CELL_COLUMN_POS
lv_style_prop_t LV_STYLE_GRID_CELL_COLUMN_SPAN
lv_style_prop_t LV_STYLE_GRID_CELL_X_ALIGN
lv_style_prop_t LV_STYLE_GRID_CELL_ROW_POS
lv_style_prop_t LV_STYLE_GRID_CELL_ROW_SPAN
lv_style_prop_t LV_STYLE_GRID_CELL_Y_ALIGN
EIGHT
LVGL has a File system module to provide an abstraction layer for various file system drivers. You still need to provide
the drivers and libraries, this extension provides only the bridge between FATFS, LittleFS, STDIO, POSIX, WIN32 and
LVGL.
FATFS
Bridge for FatFS. FatFS itself is not part of LVGL, but can be added and initialized externally.
LittleFS
Though lv_fs_littlefs uses LittleFS API, the LittleFS library needs other external libraries that handle the mount-
ing of partitions and low-level accesses, according to the given architecture. The functions for the latter are given to the
lfs_t structure as pointers by an external low-level library.
There's a convenience function called lv_fs_littlefs_set_driver(LV_FS_LITTLEFS_LETTER,
my_lfs), specific to lv_fs_littlefs, to attach a lfs_t object's pointer to a registered driver-letter. See its
comments for more info.
esp_littlefs is a wrapper for LittleFS to be used in Espressif ESP-devices. It handles the mounting and has the low-level
littlefs_api functions to read/write/erase blocks that LittleFS library needs. On mounting by esp_littlefs
the lfs_t structures are created. You need to get a handle to these to use ESP with lv_fs_littlefs, as all functions
use that lfs_t in LittleFS to identify the mounted partition.
In case you don't find a special function in the lv_fs_littlefs wrapper, you can look for it in the esp_littlefs
API and use it directly, as lv_fs_littlefs and the esp_littlefs APIs can be used side-by-side.
818
LVGL Documentation 8.3
STDIO
Bride to C standard functions on Linux and Windows. For example fopen, fread, etc.
POSIX
Bride to POSIX functions on Linux and Windows. For example open, read, etc.
WIN32
8.1.2 Usage
In lv_conf.h enable LV_USE_FS_... and assign an upper cased letter to LV_FS_..._LETTER (e.g. 'S').
After that you can access files using that driver letter. E.g. "S:path/to/file.txt".
The work directory can be set with LV_FS_..._PATH. E.g. "/home/joe/projects/" The actual file/directory
paths will be appended to it.
Cached reading is also supported if LV_FS_..._CACHE_SIZE is set to not 0 value. lv_fs_read caches this size
of data to lower the number of actual reads from the storage.
This extension allows the use of BMP images in LVGL. This implementation uses bmp-decoder library. The pixels are
read on demand (not the whole image is loaded) so using BMP images requires very little RAM.
If enabled in lv_conf.h by LV_USE_BMP LVGL will register a new image decoder automatically so BMP files can
be directly used as image sources. For example:
lv_img_set_src(my_img, "S:path/to/picture.bmp");
Note that, a file system driver needs to registered to open images from files. Read more about it here or just enable one
in lv_conf.h with LV_USE_FS_...
8.2.1 Limitations
• Only BMP files are supported and BMP images as C array (lv_img_dsc_t) are not. It's because there is no
practical differences between how the BMP files and LVGL's image format stores the image data.
• BMP files can be loaded only from file. If you want to store them in flash it's better to convert them to C array with
LVGL's image converter.
• The BMP files color format needs to match with LV_COLOR_DEPTH. Use GIMP to save the image in the required
format. Both RGB888 and ARGB888 works with LV_COLOR_DEPTH 32
• Palette is not supported.
• Because not the whole image is read in can not be zoomed or rotated.
8.2.2 Example
#include "../../lv_examples.h"
#if LV_USE_BMP && LV_BUILD_EXAMPLES
/**
* Open a BMP file from a file
*/
void lv_example_bmp_1(void)
{
lv_obj_t * img = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
#if LV_COLOR_DEPTH == 32
lv_img_set_src(img, "A:lvgl/examples/libs/bmp/example_32bit.bmp");
#elif LV_COLOR_DEPTH == 16
lv_img_set_src(img, "A:lvgl/examples/libs/bmp/example_16bit.bmp");
#endif
lv_obj_center(img);
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
import fs_driver
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
img = lv.img(lv.scr_act())
# The File system is attached to letter 'S'
img.set_src("S:example_32bit.bmp")
img.center()
8.2.3 API
Functions
void lv_bmp_init(void)
Allow the use of JPG images in LVGL. Besides that it also allows the use of a custom format, called Split JPG (SJPG),
which can be decoded in more optimal way on embedded systems.
8.3.1 Overview
8.3.2 Usage
If enabled in lv_conf.h by LV_USE_SJPG LVGL will register a new image decoder automatically so JPG and SJPG
files can be directly used as image sources. For example:
lv_img_set_src(my_img, "S:path/to/picture.jpg");
Note that, a file system driver needs to registered to open images from files. Read more about it here or just enable one
in lv_conf.h with LV_USE_FS_...
8.3.3 Converter
python3 and the PIL library required. (PIL can be installed with pip3 install pillow)
To create SJPG from JPG:
• Copy the image to convert into lvgl/scripts
• cd lvgl/scripts
• python3 jpg_to_sjpg.py image_to_convert.jpg. It creates both a C files and an SJPG image.
The expected result is:
Conversion started...
Input:
image_to_convert.jpg
RES = 640 x 480
Output:
Time taken = 1.66 sec
bin size = 77.1 KB
walpaper.sjpg (bin file)
walpaper.c (c array)
All good!
8.3.4 Example
#include "../../lv_examples.h"
#if LV_USE_SJPG && LV_BUILD_EXAMPLES
/**
* Load an SJPG image
*/
void lv_example_sjpg_1(void)
{
lv_obj_t * wp;
wp = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_img_set_src(wp, "A:lvgl/examples/libs/sjpg/small_image.sjpg");
}
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
import fs_driver
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
wp = lv.img(lv.scr_act())
# The File system is attached to letter 'S'
wp.set_src("S:small_image.sjpg")
wp.center()
8.3.5 API
Functions
void lv_split_jpeg_init(void)
Allow the use of PNG images in LVGL. This implementation uses lodepng library.
If enabled in lv_conf.h by LV_USE_PNG LVGL will register a new image decoder automatically so PNG files can
be directly used as any other image sources.
Note that, a file system driver needs to registered to open images from files. Read more about it here or just enable one
in lv_conf.h with LV_USE_FS_...
The whole PNG image is decoded so during decoding RAM equals to image width x image height x 4
bytes are required.
As it might take significant time to decode PNG images LVGL's images caching feature can be useful.
8.4.1 Example
#include "../../lv_examples.h"
#if LV_USE_PNG && LV_USE_IMG && LV_BUILD_EXAMPLES
/**
* Open a PNG image from a file and a variable
*/
void lv_example_png_1(void)
{
LV_IMG_DECLARE(img_wink_png);
lv_obj_t * img;
img = lv_img_create(lv_scr_act());
lv_img_set_src(img, &img_wink_png);
lv_obj_align(img, LV_ALIGN_LEFT_MID, 20, 0);
img = lv_img_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_img_set_src(img, "A:lvgl/examples/libs/png/wink.png");
lv_obj_align(img, LV_ALIGN_RIGHT_MID, -20, 0);
}
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
from imagetools import get_png_info, open_png
(continues on next page)
img_wink_png = lv.img_dsc_t(
{
"header": {"always_zero": 0, "w": 50, "h": 50, "cf": lv.img.CF.RAW_ALPHA},
"data_size": 5158,
"data": img_wink_png_map,
}
)
img1 = lv.img(lv.scr_act())
img1.set_src(img_wink_png)
img1.align(lv.ALIGN.RIGHT_MID, -250, 0)
wink_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
img2 = lv.img(lv.scr_act())
img2.set_src(wink_argb)
img2.align(lv.ALIGN.RIGHT_MID, -150, 0)
8.4.2 API
Functions
void lv_png_init(void)
Register the PNG decoder functions in LVGL
To convert a GIF file to byte values array use LVGL's online converter. Select "Raw" color format and "C array" Output
format.
For example:
lv_gif_set_src(obj, "S:path/to/example.gif");
Note that, a file system driver needs to be registered to open images from files. Read more about it here or just enable
one in lv_conf.h with LV_USE_FS_...
To decode and display a GIF animation the following amount of RAM is required:
• LV_COLOR_DEPTH 8: 3 x image width x image height
• LV_COLOR_DEPTH 16: 4 x image width x image height
• LV_COLOR_DEPTH 32: 5 x image width x image height
8.5.4 Example
#include "../../lv_examples.h"
#if LV_USE_GIF && LV_BUILD_EXAMPLES
/**
* Open a GIF image from a file and a variable
*/
void lv_example_gif_1(void)
{
LV_IMG_DECLARE(img_bulb_gif);
lv_obj_t * img;
img = lv_gif_create(lv_scr_act());
lv_gif_set_src(img, &img_bulb_gif);
lv_obj_align(img, LV_ALIGN_LEFT_MID, 20, 0);
img = lv_gif_create(lv_scr_act());
/* Assuming a File system is attached to letter 'A'
* E.g. set LV_USE_FS_STDIO 'A' in lv_conf.h */
lv_gif_set_src(img, "A:lvgl/examples/libs/gif/bulb.gif");
lv_obj_align(img, LV_ALIGN_RIGHT_MID, -20, 0);
}
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
import fs_driver
from img_bulb_gif import img_bulb_gif_map
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
#
# Open a GIF image from a file and a variable
#
img_bulb_gif = lv.img_dsc_t(
{
"header": {"always_zero": 0, "w": 0, "h": 0, "cf": lv.img.CF.RAW},
"data_size": 0,
"data": img_bulb_gif_map,
}
)
img1 = lv.gif(lv.scr_act())
img1.set_src(img_bulb_gif)
img1.align(lv.ALIGN.RIGHT_MID, -150, 0)
img2 = lv.gif(lv.scr_act())
# The File system is attached to letter 'S'
img2.set_src("S:bulb.gif")
img2.align(lv.ALIGN.RIGHT_MID, -250, 0)
8.5.5 API
Functions
Variables
struct lv_gif_t
Public Members
lv_img_t img
gd_GIF *gif
lv_timer_t *timer
lv_img_dsc_t imgdsc
uint32_t last_call
8.6.3 Usage
When you are sure that all the used font sizes will not be greater than 256, you can enable
LV_FREETYPE_SBIT_CACHE, which is much more memory efficient for small bitmaps.
You can use lv_ft_font_init() to create FreeType fonts. It returns true to indicate success, at the same time,
the font member of lv_ft_info_t will be filled with a pointer to an LVGL font, and you can use it like any LVGL
font.
Font style supports bold and italic, you can use the following macros to set:
1. FT_FONT_STYLE_NORMAL:default style.
2. FT_FONT_STYLE_ITALIC:Italic style
3. FT_FONT_STYLE_BOLD:bold style
They can be combined.eg:FT_FONT_STYLE_BOLD | FT_FONT_STYLE_ITALIC.
Note that, the FreeType extension doesn't use LVGL's file system. You can simply pass the path to the font as usual on
your operating system or platform.
8.6.4 Example
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_FREETYPE
/**
* Load a font with FreeType
*/
void lv_example_freetype_1(void)
{
/*Create a font*/
static lv_ft_info_t info;
/*FreeType uses C standard file system, so no driver letter is required.*/
info.name = "./lvgl/examples/libs/freetype/Lato-Regular.ttf";
info.weight = 24;
info.style = FT_FONT_STYLE_NORMAL;
info.mem = NULL;
if(!lv_ft_font_init(&info)) {
LV_LOG_ERROR("create failed.");
}
#endif
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
import fs_driver
info = lv.ft_info_t()
info.name ="./Lato-Regular.ttf"
info.weight = 24
info.style = lv.FT_FONT_STYLE.NORMAL
info.font_init()
• FreeType tutorial
• LVGL's font interface
8.6.6 API
Enums
enum LV_FT_FONT_STYLE
Values:
enumerator FT_FONT_STYLE_NORMAL
enumerator FT_FONT_STYLE_ITALIC
enumerator FT_FONT_STYLE_BOLD
Functions
struct lv_ft_info_t
Public Members
size_t mem_size
lv_font_t *font
uint16_t weight
uint16_t style
8.7.1 Usage
8.7.2 API
Functions
8.8 QR code
/*Set data*/
lv_qrcode_update(qr, data, strlen(data));
8.8.2 Notes
• QR codes with less data are smaller, but they scaled by an integer number to best fit to the given size.
8.8.3 Example
Create a QR Code
#include "../../lv_examples.h"
#if LV_USE_QRCODE && LV_BUILD_EXAMPLES
/**
* Create a QR Code
*/
void lv_example_qrcode_1(void)
{
lv_color_t bg_color = lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 5);
lv_color_t fg_color = lv_palette_darken(LV_PALETTE_BLUE, 4);
/*Set data*/
const char * data = "https://lvgl.io";
lv_qrcode_update(qr, data, strlen(data));
lv_obj_center(qr);
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
bg_color = lv.palette_lighten(lv.PALETTE.LIGHT_BLUE, 5)
fg_color = lv.palette_darken(lv.PALETTE.BLUE, 4)
8.8.4 API
Functions
Variables
Allows to use Lottie animations in LVGL. Taken from this base repository
LVGL provides the interface to Samsung/rlottie library's C API. That is the actual Lottie player is not part of LVGL, it
needs to be built separately.
To build Samsung's Rlottie C++14-compatible compiler and optionally CMake 3.14 or higher is required.
To build on desktop you can follow the instructions from Rlottie's README. In the most basic case it looks like this:
mkdir rlottie_workdir
cd rlottie_workdir
git clone https://github.com/Samsung/rlottie.git
mkdir build
cd build
cmake ../rlottie
make -j
sudo make install
8.9.2 Usage
You can use animation from files or raw data (text). In either case first you need to enable LV_USE_RLOTTIE in
lv_conf.h.
The width and height of the object be set in the create function and the animation will be scaled accordingly.
Note that, Rlottie uses the standard STDIO C file API, so you can use the path "normally" and no LVGL specific driver
letter is required.
lv_example_rlottie_approve.c contains an example animation in raw format. Instead storing the JSON string
a hex array is stored for the following reasons:
• avoid escaping " in the JSON file
• some compilers don't support very long strings
lvgl/scripts/filetohex.py can be used to convert a Lottie file a hex array. E.g.:
Lottie is standard and popular format so you can find many animation files on the web. For example: https://lottiefiles.com/
You can also create your own animations with Adobe After Effects or similar software.
LVGL provides two functions to control the animation mode: lv_rlottie_set_play_mode and
lv_rlottie_set_current_frame. You'll combine your intentions when calling the first method, like in
these examples:
8.9.5 Example
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_RLOTTIE
/**
* Load an lottie animation from flash
*/
void lv_example_rlottie_1(void)
{
extern const uint8_t lv_example_rlottie_approve[];
lv_obj_t * lottie = lv_rlottie_create_from_raw(lv_scr_act(), 100, 100, (const␣
,→void *)lv_example_rlottie_approve);
lv_obj_center(lottie);
}
#else
void lv_example_rlottie_1(void)
{
/*TODO
*fallback for online examples*/
#endif
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
#
# Load a lottie animation from flash
#
from lv_example_rlottie_approve import lv_example_rlottie_approve
lottie.center()
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_RLOTTIE
/**
* Load an lottie animation from file
*/
void lv_example_rlottie_2(void)
{
/*The rlottie library uses STDIO file API, so there is no driver letter for LVGL*/
lv_obj_t * lottie = lv_rlottie_create_from_file(lv_scr_act(), 100, 100,
"lvgl/examples/libs/rlottie/lv_
,→example_rlottie_approve.json");
lv_obj_center(lottie);
}
#else
void lv_example_rlottie_2(void)
{
/*TODO
*fallback for online examples*/
#endif
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
lottie.center()
8.9.6 API
Enums
enum lv_rlottie_ctrl_t
Values:
enumerator LV_RLOTTIE_CTRL_FORWARD
enumerator LV_RLOTTIE_CTRL_BACKWARD
enumerator LV_RLOTTIE_CTRL_PAUSE
enumerator LV_RLOTTIE_CTRL_PLAY
enumerator LV_RLOTTIE_CTRL_LOOP
Functions
Variables
struct lv_rlottie_t
Public Members
lv_img_t img_ext
lv_timer_t *task
lv_img_dsc_t imgdsc
size_t total_frames
size_t current_frame
size_t framerate
uint32_t *allocated_buf
size_t allocated_buffer_size
size_t scanline_width
lv_rlottie_ctrl_t play_ctrl
size_t dest_frame
FFmpeg A complete, cross-platform solution to record, convert and stream audio and video.
• Add library: FFmpeg (for GCC: -lavformat -lavcodec -lavutil -lswscale -lm -lz
-lpthread)
8.10.3 Usage
8.10.4 Example
Decode image
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_FFMPEG
/**
* Open an image from a file
*/
void lv_example_ffmpeg_1(void)
{
lv_obj_t * img = lv_img_create(lv_scr_act());
(continues on next page)
#else
void lv_example_ffmpeg_1(void)
{
/*TODO
*fallback for online examples*/
#endif
#endif
Decode video
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_FFMPEG
/**
* Open a video from a file
*/
void lv_example_ffmpeg_2(void)
{
/*birds.mp4 is downloaded from http://www.videezy.com (Free Stock Footage by␣
,→Videezy!)
*https://www.videezy.com/abstract/44864-silhouettes-of-birds-over-the-sunset*/
lv_obj_t * player = lv_ffmpeg_player_create(lv_scr_act());
lv_ffmpeg_player_set_src(player, "./lvgl/examples/libs/ffmpeg/birds.mp4");
lv_ffmpeg_player_set_auto_restart(player, true);
lv_ffmpeg_player_set_cmd(player, LV_FFMPEG_PLAYER_CMD_START);
lv_obj_center(player);
}
#else
void lv_example_ffmpeg_2(void)
{
/*TODO
*fallback for online examples*/
#endif
#endif
8.10.5 API
Enums
enum lv_ffmpeg_player_cmd_t
Values:
enumerator LV_FFMPEG_PLAYER_CMD_START
enumerator LV_FFMPEG_PLAYER_CMD_STOP
enumerator LV_FFMPEG_PLAYER_CMD_PAUSE
enumerator LV_FFMPEG_PLAYER_CMD_RESUME
enumerator _LV_FFMPEG_PLAYER_CMD_LAST
Functions
void lv_ffmpeg_init(void)
Register FFMPEG image decoder
int lv_ffmpeg_get_frame_num(const char *path)
Get the number of frames contained in the file
Parameters path -- image or video file name
Returns Number of frames, less than 0 means failed
lv_obj_t *lv_ffmpeg_player_create(lv_obj_t *parent)
Create ffmpeg_player object
Parameters parent -- pointer to an object, it will be the parent of the new player
Returns pointer to the created ffmpeg_player
lv_res_t lv_ffmpeg_player_set_src(lv_obj_t *obj, const char *path)
Set the path of the file to be played
Parameters
• obj -- pointer to a ffmpeg_player object
• path -- video file path
Variables
struct lv_ffmpeg_player_t
Public Members
lv_img_t img
lv_timer_t *timer
lv_img_dsc_t imgdsc
bool auto_restart
NINE
OTHERS
9.1 Snapshot
Snapshot provides APIs to take snapshot image for LVGL object together with its children. The image will look exactly
like the object.
9.1.1 Usage
Simply call API lv_snapshot_take to generate the image descriptor which can be set as image object src using
lv_img_set_src.
Note, only below color formats are supported for now:
• LV_IMG_CF_TRUE_COLOR_ALPHA
• LV_IMG_CF_ALPHA_1BIT
• LV_IMG_CF_ALPHA_2BIT
• LV_IMG_CF_ALPHA_4BIT
• LV_IMG_CF_ALPHA_8BIT
The memory lv_snapshot_take uses are dynamically allocated using lv_mem_alloc. Use API
lv_snapshot_free to free the memory it takes. This will firstly free memory the image data takes, then the image
descriptor.
Take caution to free the snapshot but not delete the image object. Before free the memory, be sure to firstly unlink it from
image object, using lv_img_set_src(NULL) and lv_img_cache_invalidate_src(src).
Below code snippet explains usage of this API.
843
LVGL Documentation 8.3
If the snapshot needs update now and then, or simply caller provides memory, use API lv_res_t
lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc,
void * buf, uint32_t buf_size); for this case. It's caller's responsibility to alloc/free the memory.
If snapshot is generated successfully, the image descriptor is updated and image data will be stored to provided buf.
Note that snapshot may fail if provided buffer is not enough, which may happen when object size changes. It's recom-
mended to use API lv_snapshot_buf_size_needed to check the needed buffer size in byte firstly and resize the
buffer accordingly.
9.1.2 Example
#include "../../lv_examples.h"
#if LV_USE_SNAPSHOT && LV_BUILD_EXAMPLES
if(snapshot_obj) {
lv_img_dsc_t * snapshot = (void *)lv_img_get_src(snapshot_obj);
if(snapshot) {
lv_snapshot_free(snapshot);
}
void lv_example_snapshot_1(void)
{
LV_IMG_DECLARE(img_star);
lv_obj_t * root = lv_scr_act();
lv_obj_set_style_bg_color(root, lv_palette_main(LV_PALETTE_LIGHT_BLUE), 0);
lv_obj_center(container);
lv_obj_set_size(container, 180, 180);
(continues on next page)
#endif
import gc
import lvgl as lv
from imagetools import get_png_info, open_png
label = lv.label(lv.scr_act())
label.align(lv.ALIGN.BOTTOM_MID, 0, -10)
label.set_text(" memory free:" + str(mem_free/1024) + " kB")
img_star = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
if snapshot_obj:
# no need to free the old source for snapshot_obj, gc will free it for us.
(continues on next page)
gc.collect()
mem_used = mem_free - gc.mem_free()
label.set_text("memory used:" + str(mem_used/1024) + " kB")
root = lv.scr_act()
root.set_style_bg_color(lv.palette_main(lv.PALETTE.LIGHT_BLUE), 0)
container.set_style_radius(50, 0)
for i in range(4):
img = lv.img(container)
img.set_src(img_star)
img.set_style_bg_color(lv.palette_main(lv.PALETTE.GREY), 0)
img.set_style_bg_opa(lv.OPA.COVER, 0)
img.set_style_transform_zoom(400, lv.STATE.PRESSED)
img.add_flag(img.FLAG.CLICKABLE)
img.add_event_cb(lambda e: event_cb(e, snapshot_obj), lv.EVENT.PRESSED, None)
img.add_event_cb(lambda e: event_cb(e, snapshot_obj), lv.EVENT.RELEASED, None)
9.1.3 API
Functions
9.2 Monkey
A simple monkey test. Use random input to stress test the application.
9.2.1 Usage
9.2.2 Example
#include "../../lv_examples.h"
#if LV_USE_MONKEY && LV_BUILD_EXAMPLES
void lv_example_monkey_1(void)
{
/*Create pointer monkey test*/
lv_monkey_config_t config;
lv_monkey_config_init(&config);
config.type = LV_INDEV_TYPE_POINTER;
config.period_range.min = 10;
config.period_range.max = 100;
lv_monkey_t * monkey = lv_monkey_create(&config);
#endif
#include "../../lv_examples.h"
#if LV_USE_MONKEY && LV_BUILD_EXAMPLES
void lv_example_monkey_2(void)
{
/*Create encoder monkey test*/
lv_monkey_config_t config;
lv_monkey_config_init(&config);
config.type = LV_INDEV_TYPE_ENCODER;
config.period_range.min = 50;
config.period_range.max = 500;
config.input_range.min = -5;
config.input_range.max = 5;
lv_monkey_t * monkey = lv_monkey_create(&config);
#endif
#include "../../lv_examples.h"
#if LV_USE_MONKEY && LV_BUILD_EXAMPLES
void lv_example_monkey_3(void)
{
static lv_point_t btn_points[3];
lv_coord_t hor_res = LV_HOR_RES;
lv_indev_set_button_points(lv_monkey_get_indev(monkey), btn_points);
#endif
9.2.3 API
Typedefs
Functions
struct lv_monkey_config_t
Public Members
lv_indev_type_t type
< Input device type Monkey execution period
uint32_t min
uint32_t max
int32_t min
int32_t max
Grid navigation (gridnav for short) is a feature that changes the currently focused child object as arrow keys are pressed.
If the children are arranged into a grid-like layout then the up, down, left and right arrows move focus to the nearest
sibling in the respective direction.
It doesn't matter how the children are positioned, as only the current x and y coordinates are considered. This means that
gridnav works with manually positioned children, as well as Flex and Grid layouts.
Gridnav also works if the children are arranged into a single row or column. That makes it useful, for example, to simplify
navigation on a List widget.
Gridnav assumes that the object to which gridnav is added is part of a group. This way, if the object with gridnav is
focused, the arrow key presses are automatically forwarded to the object so that gridnav can process the arrow keys.
To move the focus to the next widget of the group use LV_KEY_NEXT/PREV or lv_group_focus_next/prev()
or the TAB key on keyboard as usual.
If the container is scrollable and the focused child is out of the view, gridnav will automatically scroll the child into view.
9.3.1 Usage
• LV_GRIDNAV_CTRL_SCROLL_FIRST If an arrow is pressed and the focused object can be scrolled in that
direction then it will be scrolled instead of going to the next/previous object. If there is no more room for scrolling
the next/previous object will be focused normally
lv_gridnav_remove(cont) Removes gridnav from an object.
9.3.3 Example
#include "../../lv_examples.h"
#if LV_USE_GRIDNAV && LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Demonstrate a a basic grid navigation
*/
void lv_example_gridnav_1(void)
{
/*It's assumed that the default group is set and
*there is a keyboard indev*/
/*Use flex here, but works with grid or manually placed objects as well*/
lv_obj_set_flex_flow(cont1, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_style_bg_color(cont1, lv_palette_lighten(LV_PALETTE_BLUE, 5), LV_STATE_
,→FOCUSED);
uint32_t i;
for(i = 0; i < 10; i++) {
lv_obj_t * obj = lv_btn_create(cont1);
lv_obj_set_size(obj, 70, LV_SIZE_CONTENT);
lv_obj_add_flag(obj, LV_OBJ_FLAG_CHECKABLE);
lv_group_remove_obj(obj); /*Not needed, we use the gridnav instead*/
label = lv_label_create(cont2);
lv_obj_set_width(label, lv_pct(100));
lv_label_set_text_fmt(label, "Rollover\nUse tab to focus the other container");
lv_obj_t * cb = lv_checkbox_create(cont2);
lv_obj_set_pos(cb, 0, 170);
lv_group_remove_obj(cb); /*Not needed, we use the gridnav instead*/
#endif
#include "../../lv_examples.h"
#if LV_USE_GRIDNAV && LV_USE_LIST && LV_BUILD_EXAMPLES
/**
* Grid navigation on a list
*/
void lv_example_gridnav_2(void)
{
/*It's assumed that the default group is set and
*there is a keyboard indev*/
lv_group_add_obj(lv_group_get_default(), list1);
char buf[32];
uint32_t i;
for(i = 0; i < 15; i++) {
lv_snprintf(buf, sizeof(buf), "File %d", i + 1);
lv_obj_t * item = lv_list_add_btn(list1, LV_SYMBOL_FILE, buf);
lv_obj_set_style_bg_opa(item, 0, 0);
lv_group_remove_obj(item); /*Not needed, we use the gridnav instead*/
}
lv_group_add_obj(lv_group_get_default(), list2);
#endif
#include "../../lv_examples.h"
#if LV_USE_GRIDNAV && LV_USE_FLEX && LV_BUILD_EXAMPLES
}
(continues on next page)
/**
* Nested grid navigations
*/
void lv_example_gridnav_3(void)
{
/*It's assumed that the default group is set and
*there is a keyboard indev*/
/*Use flex here, but works with grid or manually placed objects as well*/
lv_obj_set_flex_flow(cont_main, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_style_bg_color(cont_main, lv_palette_lighten(LV_PALETTE_BLUE, 5), LV_
,→STATE_FOCUSED);
lv_obj_t * btn;
lv_obj_t * label;
btn = lv_btn_create(cont_main);
lv_group_remove_obj(btn);
label = lv_label_create(btn);
lv_label_set_text(label, "Button 1");
btn = lv_btn_create(cont_main);
lv_group_remove_obj(btn);
label = lv_label_create(btn);
lv_label_set_text(label, "Button 2");
label = lv_label_create(cont_sub1);
lv_obj_set_style_bg_color(cont_sub1, lv_palette_lighten(LV_PALETTE_RED, 5), LV_
,→STATE_FOCUSED);
lv_obj_set_width(label, lv_pct(100));
lv_label_set_text(label,
"I'm a very long text which is makes my container scrollable. "
"As LV_GRIDNAV_FLAG_SCROLL_FIRST is enabled arrow will scroll␣
,→me first "
"Hello world!\n"
"Hello world!\n"
"Hello world!\n"
"Hello world!\n"
"Hello world!\n"
(continues on next page)
/*Create a third container that can be focused with ENTER and contains an other␣
,→ grid nav*/
lv_obj_t * cont_sub2 = lv_obj_create(cont_main);
lv_gridnav_add(cont_sub2, LV_GRIDNAV_CTRL_ROLLOVER);
/*Only the container needs to be in a group*/
lv_group_add_obj(lv_group_get_default(), cont_sub2);
/*Use flex here, but works with grid or manually placed objects as well*/
lv_obj_set_flex_flow(cont_sub2, LV_FLEX_FLOW_ROW_WRAP);
lv_obj_set_style_bg_color(cont_sub2, lv_palette_lighten(LV_PALETTE_RED, 5), LV_
,→STATE_FOCUSED);
label = lv_label_create(cont_sub2);
lv_label_set_text(label, "Use ENTER/ESC to focus/defocus this container");
lv_obj_set_width(label, lv_pct(100));
btn = lv_btn_create(cont_sub2);
lv_group_remove_obj(btn);
label = lv_label_create(btn);
lv_label_set_text(label, "Button 3");
btn = lv_btn_create(cont_sub2);
lv_group_remove_obj(btn);
label = lv_label_create(btn);
lv_label_set_text(label, "Button 4");
#endif
#include "../../lv_examples.h"
#if LV_USE_GRIDNAV && LV_USE_FLEX && LV_BUILD_EXAMPLES
/**
* Simple navigation on a list widget
*/
void lv_example_gridnav_4(void)
(continues on next page)
uint32_t i;
for(i = 0; i < 20; i++) {
char buf[32];
#endif
9.3.4 API
Typedefs
Enums
enum lv_gridnav_ctrl_t
Values:
enumerator LV_GRIDNAV_CTRL_NONE
enumerator LV_GRIDNAV_CTRL_ROLLOVER
If there is no next/previous object in a direction, the focus goes to the object in the next/previous row (on
left/right keys) or first/last row (on up/down keys)
enumerator LV_GRIDNAV_CTRL_SCROLL_FIRST
If an arrow is pressed and the focused object can be scrolled in that direction then it will be scrolled instead
of going to the next/previous object. If there is no more room for scrolling the next/previous object will be
focused normally
Functions
9.4 Fragment
9.4.1 Usage
struct sample_fragment_t {
/* IMPORTANT: don't miss this part */
lv_fragment_t base;
/* States, object references and data fields for this fragment */
const char *title;
};
Use lv_fragment_manager
/* Add one instance into manager stack. View object of current fragment will be␣
,→destroyed,
/* Remove the top most fragment from the stack, and bring back previous one. */
lv_fragment_manager_pop(manager);
9.4.2 Example
/**
* @file lv_example_fragment_1.c
* @brief Basic usage of obj fragment
*/
#include "../../lv_examples.h"
struct sample_fragment_t {
lv_fragment_t base;
const char * name;
};
void lv_example_fragment_1(void)
{
root = lv_obj_create(lv_scr_act());
lv_obj_set_size(root, LV_PCT(100), LV_PCT(100));
lv_fragment_manager_t * manager = lv_fragment_manager_create(NULL);
/* Clean up the fragment manager before objects in containers got deleted */
lv_obj_add_event_cb(root, sample_container_del, LV_EVENT_DELETE, manager);
return label;
}
lv_fragment_manager_del(manager);
}
#endif
/**
* @file lv_example_fragment_2.c
* @brief Navigation stack using obj fragment
*/
#include "../../lv_examples.h"
void lv_example_fragment_2(void)
{
lv_obj_t * root = lv_obj_create(lv_scr_act());
lv_obj_set_size(root, LV_PCT(100), LV_PCT(100));
lv_obj_set_layout(root, LV_LAYOUT_GRID);
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_
,→TEMPLATE_LAST};
int depth = 0;
lv_fragment_t * fragment = lv_fragment_create(&sample_cls, &depth);
lv_fragment_manager_push(manager, fragment, &container);
lv_obj_add_event_cb(push_btn, sample_push_click, LV_EVENT_CLICKED, manager);
lv_obj_add_event_cb(pop_btn, sample_pop_click, LV_EVENT_CLICKED, manager);
}
return content;
}
lv_fragment_manager_pop(manager);
}
lv_fragment_manager_del(manager);
}
#endif
language c
9.4.3 API
Typedefs
Functions
struct _lv_fragment_t
Public Members
lv_fragment_managed_states_t *managed
Managed fragment states. If not null, then this fragment is managed.
lv_fragment_manager_t *child_manager
Child fragment manager
lv_obj_t *obj
lv_obj returned by create_obj_cb
struct _lv_fragment_class_t
Public Members
size_t instance_size
REQUIRED: Allocation size of fragment
struct _lv_fragment_managed_states_t
#include <lv_fragment.h> Fragment states
Public Members
lv_fragment_manager_t *manager
Manager the fragment attached to
lv_fragment_t *instance
Fragment instance
bool obj_created
true between create_obj_cb and obj_deleted_cb
bool destroying_obj
true before lv_fragment_del_obj is called. Don't touch any object if this is true
bool in_stack
true if this fragment is in navigation stack that can be popped
9.5 Messaging
9.5.1 IDs
Both the publishers and the subscribers needs to know the message identifiers. In lv_msg these are simple uint32_t
integers. For example:
#define MSG_DOOR_OPENED 1
#define MSG_DOOR_CLOSED 2
#define MSG_USER_NAME_CHANGED 100
#define MSG_USER_AVATAR_CHANGED 101
lv_msg_send(MSG_USER_DOOR_OPENED, NULL);
lv_msg_send(MSG_USER_NAME_CHANGED, "John Smith");
...do something...
}
It's quite typical that an LVGL widget is interested in some messages. To make it simpler
lv_msg_subsribe_obj(msg_id, obj, user_data) can be used. If a new message is published
with msg_id an LV_EVENT_MSG_RECEIVED event will be sent to the object.
For example:
...
void user_name_label_event_cb(lv_event_t * e)
{
lv_obj_t * label = lv_event_get_target(e);
lv_msg_t * m = lv_event_get_msg(e);
lv_label_set_text(label, lv_msg_get_payload(m));
}
Unsubscribe
void * s1;
s1 = lv_msg_subscribe(MSG_USER_DOOR_OPENED, some_callback, NULL);
...
lv_msg_unsubscribe(s1);
9.5.5 Example
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* A slider sends a message on value change and a label display's that value
*/
void lv_example_msg_1(void)
{
/*Create a slider in the center of the display*/
lv_obj_t * slider = lv_slider_create(lv_scr_act());
lv_obj_center(slider);
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
/*Subscribe the label to a message. Also use the user_data to set a format string␣
,→ here.*/
lv_msg_subsribe_obj(MSG_NEW_TEMPERATURE, label, "%d °C");
}
#endif
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Simple PIN login screen.
* No global variables are used, all state changes are communicated via messages.
*/
void lv_example_msg_2(void)
{
lv_msg_subsribe(MSG_LOGIN_ATTEMPT, auth_manager, "hello");
lv_obj_t * kb = lv_keyboard_create(lv_scr_act());
lv_keyboard_set_textarea(kb, ta);
(continues on next page)
lv_obj_t * btn;
lv_obj_t * label;
/*Create a log out button which will be active only when logged in*/
btn = lv_btn_create(lv_scr_act());
lv_obj_set_pos(btn, 240, 10);
lv_obj_add_event_cb(btn, log_out_event_cb, LV_EVENT_ALL, NULL);
lv_msg_subsribe_obj(MSG_LOGIN_OK, btn, NULL);
lv_msg_subsribe_obj(MSG_LOG_OUT, btn, NULL);
label = lv_label_create(btn);
lv_label_set_text(label, "LOG OUT");
label = lv_label_create(btn);
lv_label_set_text(label, "START ENGINE");
lv_msg_send(MSG_LOG_OUT, NULL);
}
#endif
#include "../../lv_examples.h"
#if LV_USE_MSG && LV_USE_SLIDER && LV_USE_LABEL && LV_BUILD_EXAMPLES
/**
* Show how an increment button, a decrement button, as slider can set a value
* and a label display it.
* The current value (i.e. the system's state) is stored only in one static variable␣
,→in a function
lv_obj_t * btn;
lv_obj_t * label;
/*Up button*/
btn = lv_btn_create(panel);
lv_obj_set_flex_grow(btn, 1);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_LEFT);
lv_obj_center(label);
/*Current value*/
label = lv_label_create(panel);
lv_obj_set_flex_grow(label, 2);
lv_obj_set_style_text_align(label, LV_TEXT_ALIGN_CENTER, 0);
lv_label_set_text(label, "?");
lv_msg_subsribe_obj(MSG_UPDATE, label, NULL);
lv_obj_add_event_cb(label, label_event_cb, LV_EVENT_MSG_RECEIVED, NULL);
/*Down button*/
btn = lv_btn_create(panel);
lv_obj_set_flex_grow(btn, 1);
lv_obj_add_event_cb(btn, btn_event_cb, LV_EVENT_ALL, NULL);
label = lv_label_create(btn);
lv_label_set_text(label, LV_SYMBOL_RIGHT);
lv_obj_center(label);
/*Slider*/
lv_obj_t * slider = lv_slider_create(panel);
lv_obj_set_flex_grow(slider, 1);
lv_obj_add_flag(slider, LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);
lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_ALL, NULL);
lv_msg_subsribe_obj(MSG_UPDATE, slider, NULL);
/* As there are new UI elements that don't know the system's state
* send an UPDATE REQUEST message which will trigger an UPDATE message with the␣
,→current value*/
lv_msg_send(MSG_UPDATE_REQUEST, NULL);
}
if(value != old_value) {
lv_msg_send(MSG_UPDATE, &value);
}
}
#endif
9.5.6 API
Typedefs
Functions
LV_EXPORT_CONST_INT(LV_MSG_ID_ANY)
void lv_msg_init(void)
Called internally to initialize the message module
void *lv_msg_subsribe(uint32_t msg_id, lv_msg_subscribe_cb_t cb, void *user_data)
Subscribe to an msg_id
Parameters
• msg_id -- the message ID to listen to
• cb -- callback to call if a message with msg_id was sent
• user_data -- arbitrary data which will be available in cb too
Returns pointer to a "subscribe object". It can be used the unsubscribe.
void *lv_msg_subsribe_obj(uint32_t msg_id, lv_obj_t *obj, void *user_data)
Subscribe an lv_obj to a message. LV_EVENT_MSG_RECEIVED will be triggered if a message with matching
ID was sent
Parameters
• msg_id -- the message ID to listen to
• obj -- pointer to an lv_obj
• user_data -- arbitrary data which will be available in cb too
Variables
lv_event_code_t LV_EVENT_MSG_RECEIVED
struct lv_msg_t
Public Members
uint32_t id
void *user_data
void *_priv_data
Draw image in label or span obj with imgfont. This is often used to display Unicode emoji icons in text. Supported image
formats: determined by LVGL image decoder.
9.6.1 Usage
9.6.2 Example
#include "../../lv_examples.h"
#include <stdio.h>
#if LV_BUILD_EXAMPLES
#if LV_USE_IMGFONT
LV_IMG_DECLARE(emoji_F617)
static bool get_imgfont_path(const lv_font_t * font, void * img_src,
uint16_t len, uint32_t unicode, uint32_t unicode_next)
{
LV_UNUSED(font);
(continues on next page)
if(unicode == 0xF617) {
memcpy(img_src, &emoji_F617, sizeof(lv_img_dsc_t));
}
else {
char * path = (char *)img_src;
snprintf(path, len, "%s/%04X.%s", "A:lvgl/examples/assets/emoji", unicode,
,→"png");
path[len - 1] = '\0';
}
return true;
}
/**
* draw img in label or span obj
*/
void lv_example_imgfont_1(void)
{
lv_font_t * imgfont = lv_imgfont_create(80, get_imgfont_path);
if(imgfont == NULL) {
LV_LOG_ERROR("imgfont init error");
}
imgfont->fallback = LV_FONT_DEFAULT;
void lv_example_imgfont_1(void)
{
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "imgfont is not installed");
lv_obj_center(label);
}
#endif
#endif
9.6.3 API
Typedefs
typedef bool (*lv_get_imgfont_path_cb_t)(const lv_font_t *font, void *img_src, uint16_t len, uint32_t
unicode, uint32_t unicode_next)
Functions
Pinyin IME provides API to provide Chinese Pinyin input method (Chinese input) for keyboard object, which supports 26
key and 9 key input modes. You can think of lv_ime_pinyin as a Pinyin input method plug-in for keyboard objects.
Normally, an environment where lv_keyboard can run can also run lv_ime_pinyin. There are two main influencing
factors: the size of the font file and the size of the dictionary.
lv_ime_pinyin2/7 2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7(2/72/72/72/72/72/72/72/72/72/7)2/72/72/7262/72/792/72/72/72/72/72/72/72/72/72/7 lv_ime_pinyin
2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7
2/72/72/72/72/72/72/72/72/7 2/72/72/72/72/72/72/72/7 lv_ime_pinyin 2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7
9.7.1 Usage
If you don't want to use the built-in Pinyin dictionary, you can use the custom dictionary. Or if you think that the built-in
phonetic dictionary consumes a lot of memory, you can also use a custom dictionary.
Customizing the dictionary is very simple.
First, set LV_IME_PINYIN_USE_DEFAULT_DICT to 0 in lv_conf.h
Then, write a dictionary in the following format.
2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7
2/72/72/72/72/72/72/72/72/72/7 2/72/72/72/7 lv_conf.h 2/7 LV_IME_PINYIN_USE_DEFAULT_DICT 2/72/72/7 02/7 2/72/72/72/72/72/72/72/72/72/72/72/72/72/7
Dictionary format
The arrangement order of each pinyin syllable is very important. You need to customize your own thesaurus according
to the Hanyu Pinyin syllable table. You can read here to learn about the Hanyu Pinyin syllables and the syllable table.
Then, write your own dictionary according to the following format:
2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7
2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7
lv_100ask_pinyin_dict_t your_pinyin_dict[] = {
{ "a", " " },
{ "ai", " " },
{ "an", " " },
{ "ang", " " },
{ "ao", " " },
{ "ba", " " },
{ "bai", " " },
/* ...... */
{ "zuo", " "},
{NULL, NULL}
The last item must end with {null, null} , or it will not work properly.
After writing a dictionary according to the above dictionary format, you only need to call this function to set up and use
your dictionary:
2/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7 lv_100ask_pinyin_ime_set_dict(pinyin_ime,
your_pinyin_dict) 2/72/72/72/72/72/72/72/72/72/72/72/72/7
lv_ime_pinyin supports 26 key and 9 key input modes. The mode switching is very simple, just call the function
lv_ime_pinyin_set_mode. If the second parameter of function lv_ime_pinyin_set_mode is' 1 ', switch
to 26 key input mode; if it is' 0', switch to 9 key input mode, and the default is' 1 '.
lv_ime_pinyin 2/72/7262/72/792/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/72/7 lv_ime_pinyin_set_mode 2/72/72/72/72/72/72/7
lv_ime_pinyin_set_mode 2/72/722/72/72/72/7 1 2/72/72/72/7 26 2/72/72/72/72/72/72/72/72/7 0 2/72/72/72/7 9 2/72/72/72/72/72/72/72/72/72/7 1 2/7
9.7.4 Example
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_USE_TEXTAREA && LV_FONT_SIMSUN_16_CJK && LV_USE_IME_PINYIN &&␣
,→LV_BUILD_EXAMPLES
if(code == LV_EVENT_FOCUSED) {
if(lv_indev_get_type(lv_indev_get_act()) != LV_INDEV_TYPE_KEYPAD) {
lv_keyboard_set_textarea(kb, ta);
lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
}
else if(code == LV_EVENT_CANCEL) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_state(ta, LV_STATE_FOCUSED);
lv_indev_reset(NULL, ta); /*To forget the last clicked object to make it␣
,→focusable again*/
}
}
void lv_example_ime_pinyin_1(void)
{
lv_obj_t * pinyin_ime = lv_ime_pinyin_create(lv_scr_act());
lv_obj_set_style_text_font(pinyin_ime, &lv_font_simsun_16_cjk, 0);
//lv_ime_pinyin_set_dict(pinyin_ime, your_dict); // Use a custom dictionary. If␣
,→it is not set, the built-in dictionary will be used.
/* ta1 */
lv_obj_t * ta1 = lv_textarea_create(lv_scr_act());
lv_textarea_set_one_line(ta1, true);
lv_obj_set_style_text_font(ta1, &lv_font_simsun_16_cjk, 0);
lv_obj_align(ta1, LV_ALIGN_TOP_LEFT, 0, 0);
/*Try using ime_pinyin to output the Chinese below in the ta1 above*/
lv_obj_t * cz_label = lv_label_create(lv_scr_act());
lv_label_set_text(cz_label,
" Embedded System \n ");
lv_obj_set_style_text_font(cz_label, &lv_font_simsun_16_cjk, 0);
lv_obj_set_width(cz_label, 310);
lv_obj_align_to(cz_label, ta1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
}
#endif
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_USE_TEXTAREA && LV_FONT_SIMSUN_16_CJK && LV_USE_IME_PINYIN &&␣
,→LV_IME_PINYIN_USE_K9_MODE && LV_BUILD_EXAMPLES
if(code == LV_EVENT_FOCUSED) {
if(lv_indev_get_type(lv_indev_get_act()) != LV_INDEV_TYPE_KEYPAD) {
lv_keyboard_set_textarea(kb, ta);
lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN);
}
}
else if(code == LV_EVENT_READY) {
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_state(ta, LV_STATE_FOCUSED);
(continues on next page)
}
}
void lv_example_ime_pinyin_2(void)
{
lv_obj_t * pinyin_ime = lv_ime_pinyin_create(lv_scr_act());
lv_obj_set_style_text_font(pinyin_ime, &lv_font_simsun_16_cjk, 0);
//lv_ime_pinyin_set_dict(pinyin_ime, your_dict); // Use a custom dictionary. If␣
,→it is not set, the built-in dictionary will be used.
/* ta1 */
lv_obj_t * ta1 = lv_textarea_create(lv_scr_act());
lv_textarea_set_one_line(ta1, true);
lv_obj_set_style_text_font(ta1, &lv_font_simsun_16_cjk, 0);
lv_obj_align(ta1, LV_ALIGN_TOP_LEFT, 0, 0);
lv_ime_pinyin_set_keyboard(pinyin_ime, kb);
lv_ime_pinyin_set_mode(pinyin_ime,
LV_IME_PINYIN_MODE_K9); // Set to 9-key input mode.␣
,→Default: 26-key input(k26) mode.
/*Try using ime_pinyin to output the Chinese below in the ta1 above*/
lv_obj_t * cz_label = lv_label_create(lv_scr_act());
lv_label_set_text(cz_label,
" Embedded System \n ");
lv_obj_set_style_text_font(cz_label, &lv_font_simsun_16_cjk, 0);
lv_obj_set_width(cz_label, 310);
lv_obj_align_to(cz_label, ta1, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
}
#endif
9.7.5 API
Enums
enum lv_ime_pinyin_mode_t
Values:
enumerator LV_IME_PINYIN_MODE_K26
enumerator LV_IME_PINYIN_MODE_K9
Functions
struct lv_pinyin_dict_t
Public Members
struct ime_pinyin_k9_py_str_t
Public Members
char py_str[7]
struct lv_ime_pinyin_t
Public Members
lv_obj_t obj
lv_obj_t *kb
lv_obj_t *cand_panel
lv_pinyin_dict_t *dict
lv_ll_t k9_legal_py_ll
char *cand_str
char input_char[16]
char k9_input_str[LV_IME_PINYIN_K9_MAX_INPUT]
uint16_t k9_py_ll_pos
uint16_t k9_legal_py_count
uint16_t k9_input_str_len
uint16_t ta_count
uint16_t cand_num
uint16_t py_page
uint16_t py_num[26]
uint16_t py_pos[26]
uint8_t mode
TEN
CONTRIBUTING
10.1 Introduction
890
LVGL Documentation 8.3
Merging new code into the lvgl, documentation, blog, examples, and other repositories happen via Pull requests (PR for
short). A PR is a notification like "Hey, I made some updates to your project. Here are the changes, you can add them
if you want." To do this you need a copy (called fork) of the original project under your account, make some changes
there, and notify the original repository about your updates. You can see what it looks like on GitHub for LVGL here:
https://github.com/lvgl/lvgl/pulls.
To add your changes you can edit files online on GitHub and send a new Pull request from there (recommended for
small changes) or add the updates in your favorite editor/IDE and use git to publish the changes (recommended for more
complex updates).
The instructions describe the main lvgl repository but it works the same way for the other repositories.
1. Fork the lvgl repository. To do this click the "Fork" button in the top right corner. It will "copy" the lvgl
repository to your GitHub account (https://github.com/<YOUR_NAME>?tab=repositories)
2. Clone your forked repository.
3. Add your changes. You can create a feature branch from master for the updates: git checkout -b
the-new-feature
4. Commit and push your changes to the forked lvgl repository.
5. Create a PR on GitHub from the page of your lvgl repository (https://github.com/<YOUR_NAME>/
lvgl) by clicking the "New pull request" button. Don't forget to select the branch where you added your changes.
6. Set the base branch. It means where you want to merge your update. In the lvgl repo both the fixes and new
features go to master branch.
7. Describe what is in the update. An example code is welcome if applicable.
8. If you need to make more changes, just update your forked lvgl repo with new commits. They will automatically
appear in the PR.
Possible <type>s:
• fix bugfix in the source code.
• feat new feature
• arch architectural changes
• perf changes that affect the performance
• example anything related to examples (even fixes and new examples)
• docs anything related to the documentation (even fixes, formatting, and new pages)
• test anything related to tests (new and updated tests or CI actions)
• chore any minor formatting or style changes that would make the changelog noisy
<scope> is the module, file, or sub-system that is affected by the commit. It's usually one word and can be chosen freely.
For example img, layout, txt, anim. The scope can be omitted.
<subject> contains a short description of the change:
• use the imperative, present tense: "change" not "changed" nor "changes"
• don't capitalize the first letter
• no dot (.) at the end
• max 90 characters
<body> optional and can be used to describe the details of this change.
<footer> shall contain
• the words "BREAKING CHANGE" if the changes break the API
• reference to the GitHub issue or Pull Request if applicable.
Some examples:
fix(img): update size if a new source is set
Fixes: #1234
The span widget allows mixing different font sizes, colors and styles.
It's similar to HTML <span>
10.3.1 Overview
To ensure all licensing criteria are met for every repository of the LVGL project, we apply a process called DCO (Devel-
oper's Certificate of Origin).
The text of DCO can be read here: https://developercertificate.org/.
By contributing to any repositories of the LVGL project you agree that your contribution complies with the DCO.
If your contribution fulfills the requirements of the DCO no further action is needed. If you are unsure feel free to ask us
in a comment.
To make the DCO easier to digest, here are some practical guides about specific cases:
The simplest case is when the contribution is solely your own work. In this case you can just send a Pull Request without
worrying about any licensing issues.
If the code you would like to add is based on an article, post or comment on a website (e.g. StackOverflow) the license
and/or rules of that site should be followed.
For example in case of StackOverflow a notice like this can be used:
As LVGL is MIT licensed, other MIT licensed code can be integrated without issues. The MIT license requires a copyright
notice be added to the derived work. Any derivative work based on MIT licensed code must copy the original work's
license file or text.
The GPL license is not compatible with the MIT license. Therefore, LVGL can not accept GPL licensed code.
Even if you're just getting started with LVGL there are plenty of ways to get your feet wet. Most of these options don't
even require knowing a single line of LVGL code.
Below we have collected some opportunities about the ways you can contribute to LVGL.
Have you already started using LVGL in a Simulator, a development board, or on your custom hardware? Was it easy or
were there some obstacles? Are you happy with the result? Showing your project to others is a win-win situation because
it increases your and LVGL's reputation at the same time.
You can post about your project on Twitter, Facebook, LinkedIn, create a YouTube video, and so on. Only one thing:
On social media don't forget to add a link to https://lvgl.io or https://github.com/lvgl and use the
hashtag #lvgl. Thank you! :)
You can also open a new topic in the My projects category of the Forum.
The LVGL Blog welcomes posts from anyone. It's a good place to talk about a project you created with LVGL, write a
tutorial, or share some nice tricks. The latest blog posts are shown on the homepage of LVGL to make your work more
visible.
The blog is hosted on GitHub. If you add a post GitHub automatically turns it into a website. See the README of the
blog repo to see how to add your post.
Any of these help to spread the word and familiarize new developers with LVGL.
If you don't want to speak about your project publicly, feel free to use Contact form on lvgl.io to private message to us.
As you learn LVGL you will probably play with the features of widgets. Why not publish your experiments?
Each widgets' documentation contains examples. For instance, here are the examples of the Drop-down list widget. The
examples are directly loaded from the lvgl/examples folder.
So all you need to do is send a Pull request to the lvgl repository and follow some conventions:
• Name the examples like lv_example_<widget_name>_<index>.
• Make the example as short and simple as possible.
• Add comments to explain what the example does.
• Use 320x240 resolution.
• Update index.rst in the example's folder with your new example. To see how other examples are added, look
in the lvgl/examples/widgets folder.
As you read the documentation you might see some typos or unclear sentences. All the documentation is located in the
lvgl/docs folder. For typos and straightforward fixes, you can simply edit the file on GitHub.
Note that the documentation is also formatted in Markdown.
As you use LVGL you might find bugs. Before reporting them be sure to check the relevant parts of the documentation.
If it really seems like a bug feel free to open an issue on GitHub.
When filing the issue be sure to fill out the template. It helps find the root of the problem while avoiding extensive
questions and exchanges with other developers.
The beauty of open-source software is you can easily dig in to it to understand how it works. You can also fix or adjust it
as you wish.
If you found and fixed a bug don't hesitate to send a Pull request with the fix.
In your Pull request please also add a line to CHANGELOG.md.
It feels great to know you are not alone if something is not working. It's even better to help others when they struggle with
something.
While you were learning LVGL you might have had questions and used the Forum to get answers. As a result, you
probably have more knowledge about how LVGL works.
One of the best ways to give back is to use the Forum and answer the questions of newcomers - like you were once.
Just read the titles and if you are familiar with the topic don't hesitate to share your thoughts and suggestions.
Participating in the discussions is one of the best ways to become part of the project and get to know like-minded people!
If you have created a cool widget, or added useful feature to LVGL feel free to open a new PR for it. We collect the
optional features (a.k.a. plugins) in lvgl/src/extra folder so if you are interested in adding a new features please use this
folder. The README file describes the basics rules of contribution and also lists some ideas.
For further ideas take a look at the Roadmap page. If you are interested in any of them feel free to share your opinion
and/or participate in the implementation.
Other features which are (still) not on the road map are listed in the Feature request category of the Forum.
When adding a new features the followings also needs to be updated:
• Update lv_conf_template.h
• Add description in the docs
• Add examples
• Update the changelog
If you want to become part of the core development team, you can become a maintainer of a repository.
By becoming a maintainer:
• You get write access to that repo:
– Add code directly without sending a pull request
– Accept pull requests
– Close/reopen/edit issues
• Your input has higher impact when we are making decisions
You can become a maintainer by invitation, however the following conditions need to met
1. Have > 50 replies in the Forum. You can look at your stats here
2. Send > 5 non-trivial pull requests to the repo where you would like to be a maintainer
If you are interested, just send a message (e.g. from the Forum) to the current maintainers of the repository. They
will check if the prerequisites are met. Note that meeting the prerequisites is not a guarantee of acceptance, i.e. if the
conditions are met you won't automatically become a maintainer. It's up to the current maintainers to make the decision.
Besides the core lvgl repository there are other repos for ports to development boards, IDEs or other environment. If
you ported LVGL to a new platform we can host it under the LVGL organization among the other repos.
This way your project will become part of the whole LVGL project and can get more visibility. If you are interested in
this opportunity just open an issue in lvgl repo and tell what you have!
If we agree that your port fit well into the LVGL organization, we will open a repository for your project where you will
have admin rights.
To make this concept sustainable there a few rules to follow:
• You need to add a README to your repo.
• We expect to maintain the repo to some extent:
ELEVEN
CHANGELOG
11.1.2 Fixes
898
LVGL Documentation 8.3
11.1.3 Docs
11.1.4 Others
• feat(disp): add double buffered direct-mode efficient sync algorithm (v8.3) 4497
• feat(style): backport opa_layered 6548ea0
11.2.2 Fixes
11.2.3 Docs
• ci: update screenshot compare from v9 to automatically create missing reference images fd21ed0
• ci(dropdown): fix test 5fc488a
11.2.5 Others
11.3.1 Fixes
11.3.2 Docs
• docs(disp): metined that rotation rotates the touch coordinates too 810852b
11.3.3 Others
• feat(rt-thread): make the rt-thread env recursively glob the UI files 8b83fe7
11.4.2 Performance
11.4.3 Fixes
11.4.4 Examples
11.4.5 Docs
• docs: mention incompatibility between software rotation and direct_mode or full_refresh 4308
• docs(faq): don't say 24 bit is support as LVGL can't render in RGB888 directly 227ac02
11.4.7 Others
• feat(btnmatrix): review ctrl map and allow width values to be max 15 a150b15
11.5.2 Fixes
11.6.2 Performance
11.6.3 Fixes
11.6.4 Examples
11.6.5 Docs
11.6.7 Others
11.7.1 Performance
11.7.2 Fixes
11.7.3 Examples
11.7.4 Docs
11.7.6 Others
11.8.2 Fixes
v8.3.3 is the same as v8.3.2. It was released only because the version number was set incorrectly in lvgl.h.
11.10.1 Fixes
11.10.2 Docs
11.10.4 Others
11.11.1 Fixes
• fix(led): add bg_color draw descriptors back to led draw event to support LV_DRAW_COMPLEX 0 3515
• fix(slider): fix knob drawing in symmetrical mode 2967172
• fix(refr): fix lv_refr_get_top_obj 9750c97
• fix(arc): fix arc knob invalidation in SYMMETRICAL mode a283273
11.11.2 Examples
• example(freetype): Update the Micropython example to use the Lato font 71913d3
• example(freetype): replace the arial font with lato to avoid licensing issues 8544cc3
11.11.3 Docs
11.12.1 Overview
• Layers Support transforming (zoom and rotate) any widgets and their children drawn by LVGL. To do this LVGL
renders the transformed widgets into a layer and draws that layer as an image applying all the transformations.
Layers are also used when opa (not bg_opa, border_opa, etc) and blend_mode are set. This way nested
objects are blended as one layer to avoid color bleeding. See more here.
• inherit and initial style properties Besides setting "normal values" for style properties now you can set them to
inherit (inherit the parent's value) and initial (set the system default). See more here
• NXP-PXP and VGLITE GPU support The support for NXP GPUs are added again
• Color font support You can use emojis and images in texts with this great new features. See more here.
• ARM2D GPU support Get support for ARM's own GPU.
• PubSub messaging A publisher-subscriber based messaging system is added to make communication between
components easier. See more here.
• Pinyin IME Add support for Pinyin IME Chinese input. See more here.
• render_start_cb A new callback is added to lv_disp_drv_t to indicate when the rendering starts. It's useful
to make synchronization, e.g. wait for a TE signal.
11.12.3 Performance
11.12.4 Fixes
11.12.5 Examples
11.12.6 Docs
11.13.1 Overview
Among many fixes and minor updates these are the most important features in v8.2.0:
• Abstract render layer to make it easier to attach external draw engines
• Add LV_FLAD_OVERFLOW_VISIBLE. If enabled the children of an object won't be clipped to the boundary of
the object
• Add ffmpeg decoder support to play videos and open a wide variety of image formats
• Add font fallback support
• Add gradient dithering support
• Add "monkey test"
• Add cmsis-pack support
• Add Grid navigation (lv_gridnav)
The GPU support for NXP microcontrollers is still not updated to the new draw architecture. See #3052
11.13.3 Architectural
11.13.5 Performance
11.13.6 Fixes
• fix(obj): make lv_obj_fade_in/out use the current opa as start value 2819
• fix(qrcode):minimize margins as much as possible 2804
• fix(scripts): switch all scripts to python3 2820
• fix(event): event_send_core crash in special case. 2807
• fix(Kconfig) remove duplicate LV_BUILD_EXAMPLES configuration 2813
• fix(obj): in obj event use the current target instead of target 2785
• fix(draw_label): radius Mask doesn't work in Specific condition 2784
• fix(draw_mask): will crash if get_width/height < 0 2793
• fix(theme) make the basic theme really basic a369f18
• fix(arc): fix knob invalidation 345f688
• fix(theme): add arc, spinner and colorwheel to basic theme adc218a
• fix(conf) define LV_LOG_TRACE_... to 0 in lv_conf_internal.h to avoid warnings 305284c
• fix(draw): consider opa and clip corner on bg_img d51aea4
• fix(draw): add grad_cache_mem to GC_ROOTs 138db9c
• fix(bar, slider): fix shadow drawing on short indicators 364ca3c
• fix(theme): fix theme initialization issue introduced in 6e0072479 d231644
• fix(draw): add lv_draw_sw_bg 49642d3
• fix(draw) border_draw crash is special case 075831a
• fix(theme): fix crash in lv_theme_basic_init ca5f04c
• fix(draw): fix indexed image drawing 5a0dbcc
• fix(roller): clip overflowing text 5709528
• fix(align) fix LV_SIZE_CONTENT size calculation with not LEFT or TOP alignment 9c67642
• fix(draw): futher bg_img draw fixes 81bfb76
• fix(btnmatrix): keep the selected button even on release d47cd1d
• fix(sw): make knob size calculation more intuitive 5ec532d
• fix(switch): make knob height calculation similar to slider 0921dfc
• fix(span): explicitly set span->txt to the return value of lv_mem_realloc(#3005) a9a6cb8
• fix(example): update LVGL_Arduino.ino d79283c
• fix(draw) simplify how outline_pad is compnesated 81d8be1
• fix(obj) make LV_OBJ_FLAG_SCROLL_CHAIN part of the enum instead of define f8d8856
• fix(label): dot not add dots if the label height > 1 font line height 4d61f38
• fix(event): crash if an object was deleted in an event 9810920
• fix(build) fix sdl build with make 43729d1
• fix(config): fix anonymous choice 71c739c
• chore(docs): fix lv_list_add_text a5fbf22
• fix(png) check png magic number to be sure it's a png image 1092550
11.13.7 Examples
11.13.8 Docs
• docs(faq): add "LVGL doesn't start, nothing is drawn on the display" section 0388d92
• docs add demos 02a6614
• docs(fs): update fs interface description to the latest API 285e6b3
• docs(format) let wrap 4bf49a8
• docs(imgbtn) fix typo d792c5f
• docs(porting) clarify that displays must be registered before input devices 1c64b78
• docs(event) fix lv_event_get_original_target vs lv_event_get_current_target cdd5128
• docs(events) rename LV_EVENT_APPLY to LV_EVENT_READY (#2791) bf6837f
• docs(gpu): link style properties and boxing model 6266851
• docs(gesture): clarify gesture triggering with scrolling e3b43ee
• docs(contributing): remove the mentioning of the dev branch 00d4ef3
• docs(bar) fix default range eeee48b
• docs(event): tell to not adjust widgets in draw events 933d67f
• docs(switch) improve wording b4986ab
• docs(font) fix example to match v8 2f80896
11.14.1 Overview
v8.1 is a minor release, so besides many fixes it contains a lot of new features too.
Some of the most important features are
• Built in support for SDL based GPU drawing
• Much faster circle drawing in the software renderer
• Several 3rd party libraries are merged directly into LVGL.
• Add LVGL as an RT-Thread and ESP32 component
• :warning: feat(calendar): add the header directly into the calendar widget 2e08f80
11.14.3 Architectural
11.14.5 Performance
11.14.6 Fixes
• fix(bidi): add weak characters to the previous strong character's run 2777
• fix(draw_img): radius mask doesn't work in specific condition 2786
• fix(border_post): ignore bg_img_opa draw when draw border_post 2788
• fix(refresh) switch to portable format specifiers 2781
• fix(stm32) Mark unused variable in stm32 DMA2D driver 2782
• fix(conf): Make LV_COLOR_MIX_ROUND_OFS configurable 2766
• fix(misc): correct the comment and code style 2769
• fix(draw_map) use existing variables instead function calls 2776
• fix(draw_img): fix typos in API comments 2773
• fix(draw_img):radius Mask doesn't work in Specific condition 2775
• fix(proto) Remove redundant prototype declarations 2771
• fix(conf) better support bool option from Kconfign 2555
• fix(draw_border):draw error if radius == 0 and parent clip_corner == true 2764
• fix(msgbox) add declaration for lv_msgbox_content_class 2761
• fix(core) add L suffix to enums to ensure 16-bit compatibility 2760
• fix(anim): add lv_anim_get_playtime 2745
• fix(area) minor fixes 2749
• fix(mem): ALIGN_MASK should equal 0x3 on 32bit platform 2748
• fix(template) prototype error 2755
• fix(anim): remove time_orig from lv_anim_t 2744
• fix(draw_rect):bottom border lost if enable clip_corner 2742
• fix(anim) and improvement 2738
• fix(draw border):border draw error if border width > radius 2739
• fix(fsdrv): remove the seek call in fs_open 2736
• fix(fsdrv): skip the path format if LV_FS_xxx_PATH not defined 2726
• fix(lv_obj.h)typos 2350
• fix(obj) delete useless type conversion 2343
• fix(lv_obj_scroll.h) typos 2345
• fix(txt) enhance the function of break_chars 2327
• fix(vglite): update for v8 e3e3eea
• fix(widgets) use lv_obj_class for all the widgets 3fb8baf
• fix(refr) reduce the nesting level in lv_refr_area 2df1282
• fix(pxp): update for v8 8a2a4a1
• fix(obj) move clean ups from lv_obj_del to lv_obj_destructor b063937
• fix (draw) fix arc bg image drawing with full arcs c3b6c6d
• fix(pxp): update RTOS macro for SDK 2.10 00c3eb1
• fix(textarea) style update in oneline mode + improve sroll to cursor 60d9a5e
• feat(led) send LV_EVENT_DRAW_PART_BEGIN/END fcd4aa3
• fix warnings introduced by 3fb8baf5 e302403
• fix(roller) fix partial redraw of the selected area 6bc40f8
• fix(flex) fix layout update and invalidation issues 5bd82b0
• fix(indev) focus on objects on release instead of press 76a8293
• fix tests 449952e
• fix(dropdown) forget the selected option on encoder longpress e66b935
• fix(obj) improve how the focusing indev is determined a04f2de
• fix(workflow) speed up MicroPython workflow 38ad5d5
• fix(test) do not including anything in test files when not running tests 9043860
• fix tests 36b9db3
• fix(scroll) fire LV_EVENT_SCROLL_BEGIN in the same spot for both axes b158932
• fix(btnmatrix) fix button invalidation on focus change 77cedfa
• fix(tlsf) do not use <assert.h> c9745b9
• fix(template) include lvgl.h in lv_port_*_template.c files 0ae15bd
• fix(docs) add margin for example description b5f632e
• fix(imgbtn) use the correct src in LV_EVENT_GET_SELF_SIZE 04c515a
• fix(color) remove extraneous cast for 8-bit color 157534c
• fix(workflow) use same Unix port variant for MicroPython submodules ac68b10
• fix(README) improve grammar de81889
• fix(printf) skip defining attribute if pycparser is used ee9bbea
• fix(README) spelling correction 41869f2
• fix(color) overflow with 16-bit color depth fe6d8d7
• fix(docs) consider an example to be visible over a wider area 145a0fa
11.14.7 Examples
11.14.8 Docs
11.14.10 Others
v8.0 brings many new features like simplified and more powerful scrolling, new layouts inspired by CSS Flexbox and
Grid, simplified and improved widgets, more powerful events, hookable drawing, and more.
v8 is a major change and therefore it's not backward compatible with v7.
11.17.5 Styles
11.17.6 Events
11.18.2 Bugfixes
11.19.1 Bugfixes
• fix(text) improve Arabic contextual analysis by adding hyphen processing and proper handling of lam-alef sequence
• fix(delete) delete animation after the children are deleted
• fix(gauge) consider paddings for needle images
11.20.2 Bugfixes
11.21.1 Bugfixes
11.22.2 Bugfixes
11.23.1 Bugfixes
• fix(lv_scr_load_anim) fix when multiple screens are loaded at the same time with delay
• fix(page) fix LV_SCROLLBAR_MODE_DRAG
11.24.2 Bugfixes
11.25.1 Bugfixes
11.26.1 Bugfixes
11.27.2 Bugfixes
11.28.1 Bugfixes
• Check whether any style property has changed on a state change to decide if any redraw is required
11.29.2 Bugfixes
• Add clean_dcache_cb and lv_disp_clean_dcache to enable users to use their own cache management
function
• Add gpu_wait_cb to wait until the GPU is working. It allows to run CPU a wait only when the rendered data
is needed.
• Add 10px and 8ox built in fonts
11.30.2 Bugfixes
The main new features of v7.4 are run-time font loading, style caching and arc knob with value setting by click.
• Add lv_font_load() function - Loads a lv_font_t object from a binary font file
• Add lv_font_free() function - Frees the memory allocated by the lv_font_load() function
• Add style caching to reduce access time of properties with default value
• arc: add set value by click feature
• arc: add LV_ARC_PART_KNOB similarly to slider
• send gestures event if the object was dragged. User can check dragging with
lv_indev_is_dragging(lv_indev_act()) in the event function.
11.31.2 Bugfixes
11.32.1 Bugfixes
• Add lv_task_get_next
• Add lv_event_send_refresh, lv_event_send_refresh_recursive to easily send
LV_EVENT_REFRESH to object
• Add lv_tabview_set_tab_name() function - used to change a tab's name
11.33.2 Bugfixes
• Do not print warning for missing glyph if its height OR width is zero.
• Prevent duplicated sending of LV_EVENT_INSERT from text area
• Tidy outer edges of cpicker widget.
• Remove duplicated lines from lv_tabview_add_tab
• btnmatrix: handle combined states of buttons (e.g. checked + disabled)
• textarea: fix typo in lv_textarea_set_scrollbar_mode
• gauge: fix image needle drawing
• fix using freed memory in _lv_style_list_remove_style
• Add theme->apply_cb to replace theme->apply_xcb to make it compatible with the MicroPython bind-
ing
• Add lv_theme_set_base() to allow easy extension of built-in (or any) themes
• Add lv_obj_align_x() and lv_obj_align_y() functions
• Add lv_obj_align_origo_x() and lv_obj_align_origo_y() functions
11.34.2 Bugfixes
11.35.2 Bugfixes
11.36.1 Bugfixes
• lv_textarea fix wrong cursor position when clicked after the last character
• Change all text related indices from 16-bit to 32-bit integers throughout whole library. #1545
• Fix gestures
• Do not call set_px_cb for transparent pixel
• Fix list button focus in material theme
• Fix crash when a text area is cleared with the backspace of a keyboard
• Add version number to lv_conf_template.h
• Add log in true double buffering mode with set_px_cb
• lv_dropdown: fix missing LV_EVENT_VALUE_CHANGED event when used with encoder
• lv_tileview: fix if not the {0;0} tile is created first
• lv_debug: restructure to allow asserting in from lv_misc too
• add assert if _lv_mem_buf_get() fails
• lv_textarea: fix character delete in password mode
• Update LV_OPA_MIN and LV_OPA_MAX to widen the opacity processed range
• lv_btnm fix sending events for hidden buttons
• lv_gaguge make lv_gauge_set_angle_offset offset the labels and needles too
• Fix typo in the API scrllable -> scrollable
• tabview by default allow auto expanding the page only to right and bottom (#1573)
• fix crash when drawing gradient to the same color
• chart: fix memory leak
• img: improve hit test for transformed images
11.37.1 Bugfixes
• Add LV_COLOR_MIX_ROUND_OFS to adjust color mixing to make it compatible with the GPU
• Improve DMA2D blending
• Remove memcpy from lv_ll (caused issues with some optimization settings)
• lv_chart fix X tick drawing
• Fix vertical dashed line drawing
• Some additional minor fixes and formattings
11.38.1 Documentation
The name of the project is changed to LVGL and the new website is on https://lvgl.io
LVGL remains free under the same conditions (MIT license) and a company is created to manage LVGL and offer services.
Complete rework of LVGL's draw engine to use "masks" for more advanced and higher quality graphical effects. A
possible use-case of this system is to remove the overflowing content from the rounded edges. It also allows drawing
perfectly anti-aliased circles, lines, and arcs. Internally, the drawings happen by defining masks (such as rounded rectangle,
line, angle). When something is drawn the currently active masks can make some pixels transparent. For example,
rectangle borders are drawn by using 2 rectangle masks: one mask removes the inner part and another the outer part.
The API in this regard remained the same but some new functions were added:
• lv_img_set_zoom: set image object's zoom factor
• lv_img_set_angle: set image object's angle without using canvas
• lv_img_set_pivot: set the pivot point of rotation
The new drawing engine brought new drawing features too. They are highlighted in the "style" section.
The old style system is replaced with a new more flexible and lightweighted one. It uses an approach similar to CSS:
support cascading styles, inheriting properties and local style properties per object. As part of these updates, a lot of
objects were reworked and the APIs have been changed.
• more shadows options: offset and spread
• gradient stop position to shift the gradient area and horizontal gradient
• LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE blending modes
• clip corner: crop the content on the rounded corners
• text underline and strikethrough
To better utilize GPUs, from this version GPU usage can be integrated into LVGL. In lv_conf.h any supported GPUs
can be enabled with a single configuration option.
Right now, only ST's DMA2D (Chrom-ART) is integrated. More will in the upcoming releases.
11.38.6 Renames
• dropdown: Completely reworked. Now creates a separate list when opened and can be dropped to
down/up/left/right.
• label: body_draw is removed, instead, if its style has a visible background/border/shadow etc it will be drawn.
Padding really makes the object larger (not just virtually as before)
• arc: can draw background too.
• btn: doesn't store styles for each state because it's done naturally in the new style system.
• calendar: highlight the pressed datum. The used styles are changed: use LV_CALENDAR_PART_DATE nor-
mal for normal dates, checked for highlighted, focused for today, pressed for the being pressed. (checked+pressed,
focused+pressed also work)
• chart: only has LINE and COLUMN types because with new styles all the others can be described.
LV_CHART_PART_SERIES sets the style of the series. bg_opa > 0 draws an area in LINE mode.
LV_CHART_PART_SERIES_BG also added to set a different style for the series area. Padding in
LV_CHART_PART_BG makes the series area smaller, and it ensures space for axis labels/numbers.
• linemeter, gauge: can have background if the related style properties are set. Padding makes the scale/lines
smaller. scale_border_width and scale_end_border_width allow to draw an arc on the outer part of the scale lines.
• gauge: lv_gauge_set_needle_img allows use image as needle
• canvas: allow drawing to true color alpha and alpha only canvas, add lv_canvas_blur_hor/ver and
rename lv_canvas_rotate to lv_canvas_transform
• textarea: If available in the font use bullet (U+2022) character in text area password
• lv_objmask: masks can be added to it. The children will be masked accordingly.
11.38.9 Others
• Change the built-in fonts to Montserrat and add built-in fonts from 12 px to 48 px for every 2nd size.
• Add example CJK and Arabic/Persian/Hebrew built-in font
• Add ° and "bullet" to the built-in fonts
• Add Arabic/Persian script support: change the character according to its position in the text.
• Add playback_time to animations.
• Add repeat_count to animations instead of the current "repeat forever".
• Replace LV_LAYOUT_PRETTY with LV_LAYOUT_PRETTY_TOP/MID/BOTTOM
11.38.10 Demos
• lv_examples was reworked and new examples and demos were added
TWELVE
ROADMAP
This is a summary for planned new features and a collection of ideas. This list indicates only the current intention and it
can be changed.
12.1 v8.2
See #2790
12.2 Ideas
• Reconsider color format management for run time color format setting, and custom color format usage. (Also
RGB888)
• Make gradients more versatile
• Image transformations matrix
• Switch to RGBA colors in styles
• Consider direct binary font format support
• Simplify groups. Discussion is here.
• lv_mem_alloc_aligned(size, align)
• Text node. See #1701
• CPP binding. See Forum
• Optimize font decompression
• Need static analyze (via coverity.io or something else)
• Support dot_begin and dot_middle long modes for labels
• Add new label alignment modes. #1656
• Support larger images: #1892
• Curved text on path
• Variable binding improvements like Redux?
• Functional programming support, pure view? See here
• Circle layout. See #2871
958
INDEX
959
LVGL Documentation 8.3
266 _lv_fragment_class_t::constructor_cb
_lv_disp_drv_t::offset_x (C++ member), 265 (C++ member), 867
_lv_disp_drv_t::offset_y (C++ member), 265 _lv_fragment_class_t::create_obj_cb
_lv_disp_drv_t::physical_hor_res (C++ (C++ member), 868
member), 265 _lv_fragment_class_t::destructor_cb
_lv_disp_drv_t::physical_ver_res (C++ (C++ member), 867
member), 265 _lv_fragment_class_t::detached_cb (C++
_lv_disp_drv_t::render_start_cb (C++ member), 867
member), 267 _lv_fragment_class_t::event_cb (C++ mem-
_lv_disp_drv_t::rotated (C++ member), 266 ber), 868
_lv_disp_drv_t::rounder_cb (C++ member), _lv_fragment_class_t::instance_size
266 (C++ member), 868
_lv_disp_drv_t::screen_transp (C++ mem- _lv_fragment_class_t::obj_created_cb
ber), 266 (C++ member), 868
_lv_disp_drv_t::set_px_cb (C++ member), _lv_fragment_class_t::obj_deleted_cb
266 (C++ member), 868
_lv_disp_drv_t::sw_rotate (C++ member), _lv_fragment_class_t::obj_will_delete_cb
265 (C++ member), 868
_lv_disp_drv_t::user_data (C++ member), _lv_fragment_managed_states_t (C++ struct),
267 868
_lv_disp_drv_t::ver_res (C++ member), 265 _lv_fragment_managed_states_t::cls (C++
_lv_disp_drv_t::wait_cb (C++ member), 266 member), 869
_lv_disp_get_refr_timer (C++ function), 403 _lv_fragment_managed_states_t::container
_lv_disp_t (C++ struct), 267 (C++ member), 869
_lv_disp_t::act_scr (C++ member), 267 _lv_fragment_managed_states_t::destroying_obj
_lv_disp_t::bg_color (C++ member), 268 (C++ member), 869
_lv_disp_t::bg_img (C++ member), 268 _lv_fragment_managed_states_t::in_stack
_lv_disp_t::bg_opa (C++ member), 268 (C++ member), 869
_lv_disp_t::del_prev (C++ member), 268 _lv_fragment_managed_states_t::instance
_lv_disp_t::draw_prev_over_act (C++ mem- (C++ member), 869
ber), 268 _lv_fragment_managed_states_t::manager
_lv_disp_t::driver (C++ member), 267 (C++ member), 869
_lv_disp_t::inv_area_joined (C++ member), _lv_fragment_managed_states_t::obj_created
268 (C++ member), 869
_lv_disp_t::inv_areas (C++ member), 268 _lv_fragment_t (C++ struct), 867
_lv_disp_t::inv_en_cnt (C++ member), 268 _lv_fragment_t::child_manager (C++ mem-
_lv_disp_t::inv_p (C++ member), 268 ber), 867
_lv_disp_t::last_activity_time (C++ mem- _lv_fragment_t::cls (C++ member), 867
ber), 268 _lv_fragment_t::managed (C++ member), 867
_lv_disp_t::prev_scr (C++ member), 267 _lv_fragment_t::obj (C++ member), 867
_lv_disp_t::refr_timer (C++ member), 267 _lv_fs_drv_t (C++ struct), 439
_lv_disp_t::rendering_in_progress (C++ _lv_fs_drv_t::cache_size (C++ member), 439
member), 268 _lv_fs_drv_t::close_cb (C++ member), 439
_lv_disp_t::scr_to_load (C++ member), 268 _lv_fs_drv_t::dir_close_cb (C++ member),
_lv_disp_t::screen_cnt (C++ member), 268 440
_lv_disp_t::screens (C++ member), 267 _lv_fs_drv_t::dir_open_cb (C++ member),
_lv_disp_t::sync_areas (C++ member), 268 440
_lv_disp_t::sys_layer (C++ member), 268 _lv_fs_drv_t::dir_read_cb (C++ member),
_lv_disp_t::theme (C++ member), 267 440
_lv_disp_t::top_layer (C++ member), 268 _lv_fs_drv_t::letter (C++ member), 439
_lv_fragment_class_t (C++ struct), 867 _lv_fs_drv_t::open_cb (C++ member), 439
_lv_fragment_class_t::attached_cb (C++ _lv_fs_drv_t::read_cb (C++ member), 440
member), 867 _lv_fs_drv_t::ready_cb (C++ member), 439
_lv_fs_drv_t::seek_cb (C++ member), 440
Index 960
LVGL Documentation 8.3
Index 961
LVGL Documentation 8.3
Index 962
LVGL Documentation 8.3
Index 963
LVGL Documentation 8.3
[anonymous]::LV_IMG_CF_RAW_CHROMA_KEYED [anonymous]::LV_IMG_CF_USER_ENCODED_7
(C++ enumerator), 428 (C++ enumerator), 430
[anonymous]::LV_IMG_CF_RESERVED_15 (C++ [anonymous]::LV_IMG_SIZE_MODE_REAL (C++
enumerator), 429 enumerator), 570
[anonymous]::LV_IMG_CF_RESERVED_16 (C++ [anonymous]::LV_IMG_SIZE_MODE_VIRTUAL
enumerator), 429 (C++ enumerator), 570
[anonymous]::LV_IMG_CF_RESERVED_17 (C++ [anonymous]::LV_KEYBOARD_MODE_NUMBER
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_18 (C++ [anonymous]::LV_KEYBOARD_MODE_SPECIAL
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_19 (C++ [anonymous]::LV_KEYBOARD_MODE_TEXT_LOWER
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_20 (C++ [anonymous]::LV_KEYBOARD_MODE_TEXT_UPPER
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_21 (C++ [anonymous]::LV_KEYBOARD_MODE_USER_1
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_22 (C++ [anonymous]::LV_KEYBOARD_MODE_USER_2
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RESERVED_23 (C++ [anonymous]::LV_KEYBOARD_MODE_USER_3
enumerator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RGB565 (C++ enu- [anonymous]::LV_KEYBOARD_MODE_USER_4
merator), 429 (C++ enumerator), 705
[anonymous]::LV_IMG_CF_RGB565A8 (C++ [anonymous]::LV_KEY_BACKSPACE (C++ enu-
enumerator), 429 merator), 394
[anonymous]::LV_IMG_CF_RGB888 (C++ enu- [anonymous]::LV_KEY_DEL (C++ enumerator),
merator), 429 394
[anonymous]::LV_IMG_CF_RGBA5658 (C++ [anonymous]::LV_KEY_DOWN (C++ enumerator),
enumerator), 429 394
[anonymous]::LV_IMG_CF_RGBA8888 (C++ [anonymous]::LV_KEY_END (C++ enumerator),
enumerator), 429 394
[anonymous]::LV_IMG_CF_RGBX8888 (C++ [anonymous]::LV_KEY_ENTER (C++ enumerator),
enumerator), 429 394
[anonymous]::LV_IMG_CF_TRUE_COLOR (C++ [anonymous]::LV_KEY_ESC (C++ enumerator),
enumerator), 428 394
[anonymous]::LV_IMG_CF_TRUE_COLOR_ALPHA [anonymous]::LV_KEY_HOME (C++ enumerator),
(C++ enumerator), 428 394
[anonymous]::LV_KEY_LEFT (C++ enumerator),
[anonymous]::LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED
(C++ enumerator), 428 394
[anonymous]::LV_IMG_CF_UNKNOWN (C++ enu- [anonymous]::LV_KEY_NEXT (C++ enumerator),
merator), 428 394
[anonymous]::LV_IMG_CF_USER_ENCODED_0 [anonymous]::LV_KEY_PREV (C++ enumerator),
(C++ enumerator), 429 394
[anonymous]::LV_IMG_CF_USER_ENCODED_1 [anonymous]::LV_KEY_RIGHT (C++ enumerator),
(C++ enumerator), 429 394
[anonymous]::LV_IMG_CF_USER_ENCODED_2 [anonymous]::LV_KEY_UP (C++ enumerator), 394
(C++ enumerator), 430 [anonymous]::LV_LABEL_LONG_CLIP (C++
[anonymous]::LV_IMG_CF_USER_ENCODED_3 enumerator), 582
(C++ enumerator), 430 [anonymous]::LV_LABEL_LONG_DOT (C++ enu-
[anonymous]::LV_IMG_CF_USER_ENCODED_4 merator), 581
(C++ enumerator), 430 [anonymous]::LV_LABEL_LONG_SCROLL (C++
[anonymous]::LV_IMG_CF_USER_ENCODED_5 enumerator), 581
(C++ enumerator), 430 [anonymous]::LV_LABEL_LONG_SCROLL_CIRCULAR
[anonymous]::LV_IMG_CF_USER_ENCODED_6 (C++ enumerator), 582
(C++ enumerator), 430 [anonymous]::LV_LABEL_LONG_WRAP (C++
Index 964
LVGL Documentation 8.3
Index 965
LVGL Documentation 8.3
Index 966
LVGL Documentation 8.3
Index 967
LVGL Documentation 8.3
Index 968
LVGL Documentation 8.3
Index 969
LVGL Documentation 8.3
Index 970
LVGL Documentation 8.3
Index 971
LVGL Documentation 8.3
Index 972
LVGL Documentation 8.3
Index 973
LVGL Documentation 8.3
Index 974
LVGL Documentation 8.3
Index 975
LVGL Documentation 8.3
Index 976
LVGL Documentation 8.3
Index 977
LVGL Documentation 8.3
Index 978
LVGL Documentation 8.3
Index 979
LVGL Documentation 8.3
Index 980
LVGL Documentation 8.3
Index 981
LVGL Documentation 8.3
Index 982
LVGL Documentation 8.3
Index 983
LVGL Documentation 8.3
lv_rlottie_ctrl_t::LV_RLOTTIE_CTRL_FORWARD lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_FADE_IN
(C++ enumerator), 837 (C++ enumerator), 401
lv_rlottie_ctrl_t::LV_RLOTTIE_CTRL_LOOP lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_FADE_ON
(C++ enumerator), 838 (C++ enumerator), 401
lv_rlottie_ctrl_t::LV_RLOTTIE_CTRL_PAUSElv_scr_load_anim_t::LV_SCR_LOAD_ANIM_FADE_OUT
(C++ enumerator), 837 (C++ enumerator), 401
lv_rlottie_ctrl_t::LV_RLOTTIE_CTRL_PLAY lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_MOVE_BOTTOM
(C++ enumerator), 837 (C++ enumerator), 401
lv_rlottie_set_current_frame (C++ func- lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_MOVE_LEFT
tion), 838 (C++ enumerator), 401
lv_rlottie_set_play_mode (C++ function), 838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_MOVE_RIGHT
lv_rlottie_t (C++ struct), 838 (C++ enumerator), 401
lv_rlottie_t::allocated_buf (C++ member), lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_MOVE_TOP
838 (C++ enumerator), 401
lv_rlottie_t::allocated_buffer_size lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_NONE
(C++ member), 838 (C++ enumerator), 401
lv_rlottie_t::animation (C++ member), 838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OUT_BOTTOM
lv_rlottie_t::current_frame (C++ member), (C++ enumerator), 401
838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OUT_LEFT
lv_rlottie_t::dest_frame (C++ member), 839 (C++ enumerator), 401
lv_rlottie_t::framerate (C++ member), 838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OUT_RIGHT
lv_rlottie_t::img_ext (C++ member), 838 (C++ enumerator), 401
lv_rlottie_t::imgdsc (C++ member), 838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OUT_TOP
lv_rlottie_t::play_ctrl (C++ member), 838 (C++ enumerator), 401
lv_rlottie_t::scanline_width (C++ mem- lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OVER_BOTTOM
ber), 838 (C++ enumerator), 401
lv_rlottie_t::task (C++ member), 838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OVER_LEFT
lv_rlottie_t::total_frames (C++ member), (C++ enumerator), 401
838 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OVER_RIGHT
lv_roller_class (C++ member), 599 (C++ enumerator), 401
lv_roller_create (C++ function), 598 lv_scr_load_anim_t::LV_SCR_LOAD_ANIM_OVER_TOP
lv_roller_get_option_cnt (C++ function), 599 (C++ enumerator), 401
lv_roller_get_options (C++ function), 598 lv_slider_class (C++ member), 609
lv_roller_get_selected (C++ function), 598 lv_slider_create (C++ function), 607
lv_roller_get_selected_str (C++ function), lv_slider_draw_part_type_t (C++ enum), 607
598 lv_slider_draw_part_type_t::LV_SLIDER_DRAW_PART_KNO
lv_roller_mode_t (C++ type), 597 (C++ enumerator), 607
lv_roller_set_options (C++ function), 598 lv_slider_draw_part_type_t::LV_SLIDER_DRAW_PART_KNO
lv_roller_set_selected (C++ function), 598 (C++ enumerator), 607
lv_roller_set_visible_row_count (C++ lv_slider_get_left_value (C++ function), 608
function), 598 lv_slider_get_max_value (C++ function), 608
lv_roller_t (C++ struct), 599 lv_slider_get_min_value (C++ function), 608
lv_roller_t::mode (C++ member), 599 lv_slider_get_mode (C++ function), 608
lv_roller_t::moved (C++ member), 599 lv_slider_get_value (C++ function), 608
lv_roller_t::obj (C++ member), 599 lv_slider_is_dragged (C++ function), 608
lv_roller_t::option_cnt (C++ member), 599 lv_slider_mode_t (C++ type), 606
lv_roller_t::sel_opt_id (C++ member), 599 lv_slider_set_left_value (C++ function), 607
lv_roller_t::sel_opt_id_ori (C++ member), lv_slider_set_mode (C++ function), 608
599 lv_slider_set_range (C++ function), 607
lv_scr_act (C++ function), 404 lv_slider_set_value (C++ function), 607
lv_scr_load (C++ function), 404 lv_slider_t (C++ struct), 609
lv_scr_load_anim (C++ function), 403 lv_slider_t::bar (C++ member), 609
lv_scr_load_anim_t (C++ enum), 401 lv_slider_t::dragging (C++ member), 609
lv_slider_t::left_knob_area (C++ member),
Index 984
LVGL Documentation 8.3
Index 985
LVGL Documentation 8.3
Index 986
LVGL Documentation 8.3
Index 987
LVGL Documentation 8.3
Index 988
LVGL Documentation 8.3
Index 989
LVGL Documentation 8.3
Index 990
LVGL Documentation 8.3
Index 991