LVGL Library
LVGL Library
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.4 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.5 Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.6 Scrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.7 Widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4 Porting 281
4.1 Set up a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
4.2 Display interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
4.3 Input device interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
4.4 Tick interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304
4.5 Timer Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
4.6 Sleep management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305
4.7 Operating system and interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
4.8 Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
4.9 Add custom GPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
5 Overview 313
5.1 Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313
5.2 Positions, sizes, and layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
5.3 Styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
5.4 Style properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
5.5 Scroll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
i
5.6 Layers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
5.7 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
5.8 Input devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
5.9 Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 439
5.10 Colors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
5.11 Fonts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461
5.12 Images . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 468
5.13 File system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
5.14 Animations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
5.15 Timers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
5.16 Drawing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
5.17 Renderers and GPUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
5.18 New widget . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519
6 Widgets 520
6.1 Base object (lv_obj) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
6.2 Arc (lv_arc) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 535
6.3 Animation Image (lv_animimg) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
6.4 Bar (lv_bar) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 550
6.5 Button (lv_btn) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562
6.6 Button matrix (lv_btnmatrix) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 569
6.7 Calendar (lv_calendar) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
6.8 Chart (lv_chart) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
6.9 Color wheel (lv_colorwheel) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 631
6.10 Canvas (lv_canvas) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 636
6.11 Checkbox (lv_checkbox) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 652
6.12 Drop-down list (lv_dropdown) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659
6.13 Image (lv_img) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 670
6.14 Image button (lv_imgbtn) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684
6.15 Keyboard (lv_keyboard) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
6.16 Label (lv_label) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 697
6.17 LED (lv_led) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
6.18 Line (lv_line) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
6.19 List (lv_list) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
6.20 Menu (lv_menu) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 725
6.21 Meter (lv_meter) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 747
6.22 Message box (lv_msgbox) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764
6.23 Roller (lv_roller) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 768
6.24 Slider (lv_slider) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 779
6.25 Span (lv_span) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 788
6.26 Spinbox (lv_spinbox) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 797
6.27 Spinner (lv_spinner) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 802
6.28 Switch (lv_switch) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 804
6.29 Table (lv_table) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
6.30 Tabview (lv_tabview) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 819
6.31 Text area (lv_textarea) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 825
6.32 Tile view (lv_tileview) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
6.33 Window (lv_win) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 843
7 Layouts 847
7.1 Flex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 847
7.2 Grid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 860
ii
8.1 File System Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876
8.2 BMP decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 876
8.3 JPG decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 878
8.4 PNG decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 880
8.5 GIF decoder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 882
8.6 FreeType support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 884
8.7 Tiny TTF font engine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 888
8.8 QR code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 891
8.9 Barcode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 894
8.10 Lottie player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897
8.11 FFmpeg support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 904
9 Others 909
9.1 Snapshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 909
9.2 Monkey . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 913
9.3 Grid navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 917
9.4 File Explorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928
9.5 Fragment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 946
9.6 Messaging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 957
9.7 Image font (imgfont) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 973
9.8 Pinyin IME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976
10 Contributing 985
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 985
10.2 Pull request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 986
10.3 Developer Certification of Origin (DCO) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 988
10.4 Ways to contribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 989
11 Changelog 993
11.1 v8.3.5 7 February 2023 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 993
11.2 v8.3.4 15 December 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 994
11.3 v8.3.3 06 October 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 995
11.4 v8.3.2 27 September 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 995
11.5 v8.3.1 25 July 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996
11.6 v8.3.0 6 July 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996
11.7 v8.2.0 31 January 2022 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1004
11.8 v8.1.0 10 November 2021 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1012
11.9 v8.0.2 (16.07.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1028
11.10 v8.0.1 (14.06.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029
11.11 v8.0.0 (01.06.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1031
11.12 v7.11.0 (16.03.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1033
11.13 v7.10.1 (16.02.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1034
11.14 v7.10.0 (02.02.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1034
11.15 v7.9.1 (19.01.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1034
11.16 v7.9.0 (05.01.2021) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035
11.17 v7.8.1 (15.12.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035
11.18 v7.8.0 (01.12.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1035
11.19 v7.7.2 (17.11.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1036
11.20 v7.7.1 (03.11.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1036
11.21 v7.7.0 (20.10.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1037
11.22 v7.6.1 (06.10.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1037
11.23 v7.6.0 (22.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038
11.24 v7.5.0 (15.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038
11.25 v7.4.0 (01.09.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1038
iii
11.26 v7.3.1 (18.08.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1039
11.27 v7.3.0 (04.08.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
11.28 v7.2.0 (21.07.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1040
11.29 v7.1.0 (07.07.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1041
11.30 v7.0.2 (16.06.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1042
11.31 v7.0.1 (01.06.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1043
11.32 v7.0.0 (18.05.2020) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1043
12 Roadmap 1047
12.1 Planned for v9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1047
12.2 Planned in general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049
12.3 Ideas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1050
Index 1051
iv
LVGL Documentation 9.0
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 9.0
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 9.0
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, Espressif ESP32 and Raspberry Pi Pico W
• 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 9.0
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 24 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 9.0
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.
1.6. FAQ 6
LVGL Documentation 9.0
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_LABEL
/**
* Basic example to create a "Hello world" label
*/
void lv_example_get_started_1(void)
{
/*Change the active screen's background color*/
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x003a57), LV_PART_MAIN);
/*Create a white label, set its text and align it to the center*/
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello world");
lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}
#endif
# Create a white label, set its text and align it to the center
label = lv.label(lv.scr_act())
label.set_text("Hello world")
label.set_style_text_color(lv.color_hex(0xffffff), lv.PART.MAIN)
label.align(lv.ALIGN.CENTER, 0, 0)
8
LVGL Documentation 9.0
#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_2(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,e):
code = e.get_code()
btn = e.get_target_obj()
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_3(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_4(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(e):
slider = e.get_target_obj()
#
# Create a slider and write its value on a label.
#
(continues on next page)
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);
#endif
2.2. Styles 14
LVGL Documentation 9.0
#
# 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);
lv_style_set_bg_grad(&style, &grad);
2.2. Styles 15
LVGL Documentation 9.0
#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 16
LVGL Documentation 9.0
#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);
/*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);
2.2. Styles 17
LVGL Documentation 9.0
#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);
/*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);
2.2. Styles 18
LVGL Documentation 9.0
#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);
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);
2.2. Styles 19
LVGL Documentation 9.0
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)
obj.set_src(img_cogwheel_argb)
obj.center()
2.2. Styles 20
LVGL Documentation 9.0
#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)
style.set_border_color(lv.palette_main(lv.PALETTE.BLUE))
style.set_pad_all(10)
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)
2.2. Styles 21
LVGL Documentation 9.0
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()
style.set_line_color(lv.palette_main(lv.PALETTE.GREY))
style.set_line_width(6)
style.set_line_rounded(True)
2.2. Styles 22
LVGL Documentation 9.0
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);
lv_obj_center(obj);
}
#endif
#
# Creating a transition
#
2.2. Styles 23
LVGL Documentation 9.0
# 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));
lv_style_set_border_color(&style_base, lv_palette_darken(LV_PALETTE_LIGHT_BLUE,␣
,→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);
(continues on next page)
2.2. Styles 24
LVGL Documentation 9.0
/*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())
style_base.set_width(100)
style_base.set_height(lv.SIZE_CONTENT)
2.2. Styles 25
LVGL Documentation 9.0
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);
}
#endif
#
# Local styles
#
style = lv.style_t()
style.init()
style.set_bg_color(lv.palette_main(lv.PALETTE.GREEN))
(continues on next page)
2.2. Styles 26
LVGL Documentation 9.0
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()
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()
(continues on next page)
2.2. Styles 27
LVGL Documentation 9.0
#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);
2.2. Styles 28
LVGL Documentation 9.0
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)
label = lv.label(btn)
(continues on next page)
2.2. Styles 29
LVGL Documentation 9.0
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);
(continues on next page)
2.2. Styles 30
LVGL Documentation 9.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;
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);
(continues on next page)
2.3. Animations 31
LVGL Documentation 9.0
/**
* 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(sw, sw_event_cb, LV_EVENT_VALUE_CHANGED, label);
}
#endif
def sw_event_cb(e,label):
sw = e.get_target_obj()
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)
(continues on next page)
2.3. Animations 32
LVGL Documentation 9.0
#
# 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(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);
lv_anim_set_values(&a, 10, 50);
lv_anim_set_time(&a, 1000);
lv_anim_set_playback_delay(&a, 100);
(continues on next page)
2.3. Animations 33
LVGL Documentation 9.0
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)
a2.set_custom_exec_cb(lambda a1,val: anim_x_cb(obj,val))
lv.anim_t.start(a2)
2.3. Animations 34
LVGL Documentation 9.0
#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)
2.3. Animations 35
LVGL Documentation 9.0
/* 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 36
LVGL Documentation 9.0
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(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(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(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)
2.3. Animations 37
LVGL Documentation 9.0
/* create slider_prg */
lv_obj_t * slider_prg = lv_slider_create(par);
lv_obj_add_event(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(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(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)
2.3. Animations 38
LVGL Documentation 9.0
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(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)
2.3. Animations 39
LVGL Documentation 9.0
# 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_obj()
if not self.anim_timeline:
self.anim_timeline_create()
progress = slider.get_value()
self.anim_timeline.set_progress(progress)
def btn_run_event_handler(self,e):
btn = e.get_target_obj()
if not self.anim_timeline:
self.anim_timeline_create()
reverse = btn.has_state(lv.STATE.CHECKED)
self.anim_timeline.set_reverse(reverse)
self.anim_timeline.start()
def btn_del_event_handler(self,e):
if self.anim_timeline:
self.anim_timeline._del()
self.anim_timeline = None
(continues on next page)
2.3. Animations 40
LVGL Documentation 9.0
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(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())
btn.set_size(100, 50)
btn.center()
btn.add_event(self.event_cb, lv.EVENT.CLICKED, None)
label = lv.label(btn)
label.set_text("Click me!")
(continues on next page)
2.4. Events 41
LVGL Documentation 9.0
def event_cb(self,e):
print("Clicked")
btn = e.get_target_obj()
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);
lv_obj_center(btn);
2.4. Events 42
LVGL Documentation 9.0
#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);
/**
* Demonstrate event bubbling
*/
(continues on next page)
2.4. Events 43
LVGL Documentation 9.0
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_obj()
# 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)
label = lv.label(btn)
label.set_text(str(i))
label.center()
2.4. Events 44
LVGL Documentation 9.0
#include "../lv_examples.h"
#if LV_BUILD_EXAMPLES
lv_area_t a;
a.x1 = 0;
a.y1 = 0;
a.x2 = size;
a.y2 = size;
lv_area_align(&obj->coords, &a, LV_ALIGN_CENTER, 0, 0);
/**
* Demonstrate the usage of draw event
*/
void lv_example_event_4(void)
{
lv_obj_t * cont = lv_obj_create(lv_scr_act());
lv_obj_set_size(cont, 200, 200);
lv_obj_center(cont);
lv_obj_add_event(cont, event_cb, LV_EVENT_DRAW_PART_END, NULL);
lv_timer_create(timer_cb, 30, cont);
}
#endif
2.4. Events 45
LVGL Documentation 9.0
class LV_Example_Event_4:
def __init__(self):
#
# Demonstrate the usage of draw event
#
self.size = 0
self.size_dec = False
self.cont = lv.obj(lv.scr_act())
self.cont.set_size(200, 200)
self.cont.center()
self.cont.add_event(self.event_cb, lv.EVENT.DRAW_PART_END, None)
lv.timer_create(self.timer_cb, 30, None)
def timer_cb(self,timer) :
self.cont.invalidate()
if self.size_dec :
self.size -= 1
else :
self.size += 1
if self.size == 50 :
self.size_dec = True
elif self.size == 0:
self.size_dec = False
def event_cb(self,e) :
obj = e.get_target_obj()
dsc = e.get_draw_part_dsc()
if dsc.class_p == lv.obj_class and dsc.part == lv.PART.MAIN :
draw_dsc = lv.draw_rect_dsc_t()
draw_dsc.init()
draw_dsc.bg_color = lv.color_hex(0xffaaaa)
draw_dsc.radius = lv.RADIUS_CIRCLE
draw_dsc.border_color = lv.color_hex(0xff5555)
draw_dsc.border_width = 2
draw_dsc.outline_color = lv.color_hex(0xff0000)
draw_dsc.outline_pad = 3
draw_dsc.outline_width = 2
a = lv.area_t()
a.x1 = 0
a.y1 = 0
a.x2 = self.size
a.y2 = self.size
coords = lv.area_t()
obj.get_coords(coords)
coords.align(a, lv.ALIGN.CENTER, 0, 0)
dsc.draw_ctx.rect(draw_dsc, a)
lv_example_event_4 = LV_Example_Event_4()
2.4. Events 46
LVGL Documentation 9.0
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);
}
}
#endif
#
# A simple row and a column layout with flexbox
#
2.5. Layouts 47
LVGL Documentation 9.0
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);
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);
(continues on next page)
2.5. Layouts 48
LVGL Documentation 9.0
#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);
lv_obj_set_size(obj, 40, 40); /*Fix size*/
obj = lv_obj_create(cont);
lv_obj_set_height(obj, 40);
(continues on next page)
2.5. Layouts 49
LVGL Documentation 9.0
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)
{
2.5. Layouts 50
LVGL Documentation 9.0
#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)
{
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);
(continues on next page)
2.5. Layouts 51
LVGL Documentation 9.0
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))
label.center()
a_row = lv.anim_t()
a_row.init()
(continues on next page)
2.5. Layouts 52
LVGL Documentation 9.0
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.
(continues on next page)
2.5. Layouts 53
LVGL Documentation 9.0
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};
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);
2.5. Layouts 54
LVGL Documentation 9.0
#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};
2.5. Layouts 55
LVGL Documentation 9.0
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
#
# Demonstrate cell placement and span
#
(continues on next page)
2.5. Layouts 56
LVGL Documentation 9.0
# 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")
2.5. Layouts 57
LVGL Documentation 9.0
#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"
#
2.5. Layouts 58
LVGL Documentation 9.0
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++) {
(continues on next page)
2.5. Layouts 59
LVGL Documentation 9.0
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()
2.5. Layouts 60
LVGL Documentation 9.0
#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);
2.5. Layouts 61
LVGL Documentation 9.0
#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)
2.5. Layouts 62
LVGL Documentation 9.0
#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]
2.5. Layouts 63
LVGL Documentation 9.0
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)
{
/*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);
2.6. Scrolling 64
LVGL Documentation 9.0
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()
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. Scrolling 65
LVGL Documentation 9.0
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));
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(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
(continues on next page)
2.6. Scrolling 66
LVGL Documentation 9.0
#endif
def sw_event_cb(e,panel):
code = e.get_code()
sw = e.get_target_obj()
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:
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)
2.6. Scrolling 67
LVGL Documentation 9.0
#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);
#endif
class ScrollExample_3():
def __init__(self):
self.btn_cnt = 1
#
(continues on next page)
2.6. Scrolling 68
LVGL Documentation 9.0
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(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_obj()
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)
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);
2.6. Scrolling 69
LVGL Documentation 9.0
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
2.6. Scrolling 70
LVGL Documentation 9.0
#
# 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()
(continues on next page)
2.6. Scrolling 71
LVGL Documentation 9.0
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);
lv_obj_set_style_text_font(label, &lv_font_dejavu_16_persian_hebrew, 0);
#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 مانند دیگری اجزای و کوچک،␣خروجی و ورودی درگاههای تایمر
2.6. Scrolling 72
LVGL Documentation 9.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;
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;
}
2.6. Scrolling 73
LVGL Documentation 9.0
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_obj()
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)
2.6. Scrolling 74
LVGL Documentation 9.0
# 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(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))
label = lv.label(btn)
label.set_text("Button " + str(i))
2.6. Scrolling 75
LVGL Documentation 9.0
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)
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
2.7. Widgets 76
LVGL Documentation 9.0
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(obj, drag_event_handler, LV_EVENT_PRESSING, NULL);
}
#endif
def drag_event_handler(e):
obj = e.get_target_obj()
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(drag_event_handler, lv.EVENT.PRESSING, None)
label = lv.label(obj)
label.set_text("Drag me")
label.center()
2.7. Widgets 77
LVGL Documentation 9.0
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(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 78
LVGL Documentation 9.0
#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 79
LVGL Documentation 9.0
#
# 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))
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 80
LVGL Documentation 9.0
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 81
LVGL Documentation 9.0
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
2.7. Widgets 82
LVGL Documentation 9.0
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 83
LVGL Documentation 9.0
#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.COLOR_FORMAT.
,→NATIVE_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 84
LVGL Documentation 9.0
#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 85
LVGL Documentation 9.0
#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(bar, event_cb, LV_EVENT_DRAW_PART_END, NULL);
(continues on next page)
2.7. Widgets 86
LVGL Documentation 9.0
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_obj()
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 87
LVGL Documentation 9.0
bar = lv.bar(lv.scr_act())
bar.add_event(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 88
LVGL Documentation 9.0
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 89
LVGL Documentation 9.0
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 90
LVGL Documentation 9.0
#
# 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 91
LVGL Documentation 9.0
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 92
LVGL Documentation 9.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)
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 93
LVGL Documentation 9.0
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(e):
code = e.get_code()
obj = e.get_target_obj()
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(event_handler, lv.EVENT.ALL, None)
#endif
2.7. Widgets 94
LVGL Documentation 9.0
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;
(continues on next page)
2.7. Widgets 95
LVGL Documentation 9.0
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(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_obj()
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)
(continues on next page)
2.7. Widgets 96
LVGL Documentation 9.0
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(event_cb, lv.EVENT.ALL, None)
btnm.center()
2.7. Widgets 97
LVGL Documentation 9.0
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 98
LVGL Documentation 9.0
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_obj()
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)
(continues on next page)
2.7. Widgets 99
LVGL Documentation 9.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(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(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;
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(e):
code = e.get_code()
if code == lv.EVENT.VALUE_CHANGED:
source = e.get_current_target_obj()
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(event_handler, lv.EVENT.ALL, None)
calendar.set_highlighted_dates(highlighted_days, len(highlighted_days))
(continues on next page)
lv.calendar_header_dropdown(calendar)
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 uint8_t cbuf_tmp[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_
,→HEIGHT)];
#endif
_CANVAS_WIDTH = 200
_CANVAS_HEIGHT = 150
LV_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.COLOR_FORMAT.NATIVE)
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.COLOR_FORMAT.NATIVE
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_to32(LV_COLOR_CHROMA_KEY));
lv_canvas_set_palette(canvas, 1, lv_color_to32(lv_palette_main(LV_PALETTE_RED)));
lv_color_set_int(&c0, 0);
lv_color_set_int(&c1, 1);
import math
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.set_int(0)
c1.set_int(1)
canvas.fill_bg(c1, lv.OPA.COVER)
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Draw a rectangle to the canvas
*/
void lv_example_canvas_3(void)
{
/*Create a buffer for the canvas*/
static uint8_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_rect_dsc_t dsc;
lv_draw_rect_dsc_init(&dsc);
dsc.bg_color = lv_palette_main(LV_PALETTE_RED);
dsc.border_color = lv_palette_main(LV_PALETTE_BLUE);
dsc.border_width = 3;
dsc.outline_color = lv_palette_main(LV_PALETTE_GREEN);
dsc.outline_width = 2;
dsc.outline_pad = 2;
dsc.outline_opa = LV_OPA_50;
dsc.radius = 5;
dsc.border_width = 3;
lv_canvas_draw_rect(canvas, 10, 10, 30, 20, &dsc);
}
#endif
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_SIZE = 32
#
# Draw a rectangle to the canvas
#
# Create a buffer for the canvas
cbuf = bytearray((LV_COLOR_SIZE // 8) * CANVAS_WIDTH * CANVAS_HEIGHT)
canvas.fill_bg(lv.color_hex3(0xccc), lv.OPA.COVER)
canvas.center()
dsc = lv.draw_rect_dsc_t()
dsc.init()
dsc.bg_color = lv.palette_main(lv.PALETTE.RED)
dsc.border_color = lv.palette_main(lv.PALETTE.BLUE)
dsc.border_width = 3
dsc.outline_color = lv.palette_main(lv.PALETTE.GREEN)
dsc.outline_width = 2
dsc.outline_pad = 2
dsc.outline_opa = lv.OPA._50
dsc.radius = 5
dsc.border_width = 3
canvas.draw_rect(10, 10, 30, 20, dsc)
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_FONT_MONTSERRAT_18 && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Draw a text to the canvas
*/
void lv_example_canvas_4(void)
{
/*Create a buffer for the canvas*/
static uint8_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_label_dsc_t dsc;
lv_draw_label_dsc_init(&dsc);
dsc.color = lv_palette_main(LV_PALETTE_RED);
dsc.font = &lv_font_montserrat_18;
dsc.decor = LV_TEXT_DECOR_UNDERLINE;
import fs_driver
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_SIZE = 32
#
# Draw a text to the canvas
#
dsc = lv.draw_label_dsc_t()
dsc.init()
dsc.color = lv.palette_main(lv.PALETTE.RED)
(continues on next page)
try:
dsc.font = lv_font_montserrat_18
except:
# needed for dynamic font loading
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
dsc.decor = lv.TEXT_DECOR.UNDERLINE
print('Printing "Hello"')
canvas.draw_text(10, 10, 30, dsc, "Hello")
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Draw an arc to the canvas
*/
void lv_example_canvas_5(void)
{
/*Create a buffer for the canvas*/
static uint8_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_arc_dsc_t dsc;
lv_draw_arc_dsc_init(&dsc);
dsc.color = lv_palette_main(LV_PALETTE_RED);
dsc.width = 5;
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_SIZE = 32
#
# Draw an arc to the canvas
#
dsc = lv.draw_arc_dsc_t()
dsc.init()
dsc.color = lv.palette_main(lv.PALETTE.RED)
dsc.width = 5
#include "../../lv_examples.h"
#if LV_USE_CANVAS && LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Draw an image to the canvas
*/
void lv_example_canvas_6(void)
{
/*Create a buffer for the canvas*/
static uint8_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_img_dsc_t dsc;
lv_draw_img_dsc_init(&dsc);
LV_IMG_DECLARE(img_star);
lv_canvas_draw_img(canvas, 5, 5, &img_star, &dsc);
}
#endif
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_SIZE = 32
img_star_argb = lv.img_dsc_t({
'data_size': len(png_data),
'data': png_data
})
#
# Draw an image to the canvas
#
dsc = lv.draw_img_dsc_t()
dsc.init()
#include "../../lv_examples.h"
#if LV_USE_CANVAS&& LV_BUILD_EXAMPLES
#define CANVAS_WIDTH 50
#define CANVAS_HEIGHT 50
/**
* Draw a line to the canvas
*/
void lv_example_canvas_7(void)
{
/*Create a buffer for the canvas*/
static uint8_t cbuf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(CANVAS_WIDTH, CANVAS_HEIGHT)];
lv_draw_line_dsc_t dsc;
lv_draw_line_dsc_init(&dsc);
dsc.color = lv_palette_main(LV_PALETTE_RED);
dsc.width = 4;
dsc.round_end = 1;
dsc.round_start = 1;
CANVAS_WIDTH = 50
CANVAS_HEIGHT = 50
LV_COLOR_SIZE = 32
#
# Draw a line to the canvas
#
dsc = lv.draw_line_dsc_t()
dsc.init()
dsc.color = lv.palette_main(lv.PALETTE.RED)
dsc.width = 4
dsc.round_end = 1
dsc.round_start = 1
p = [ {"x":15,"y":15},
{"x":35,"y":10},
{"x":10,"y":40} ]
canvas.draw_line(p, 3, dsc)
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_USE_DRAW_MASKS && 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);
}
}
}
(continues on next page)
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*/
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_obj()
# 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()
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(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)
(continues on next page)
# Zoom in a little in X
chart.set_zoom_x(800)
#include "../../lv_examples.h"
#if LV_USE_CHART && LV_BUILD_EXAMPLES
if(code == LV_EVENT_VALUE_CHANGED) {
lv_obj_invalidate(chart);
}
(continues on next page)
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));
}
}
#endif
#!/opt/bin/lv_micropython -i
import lvgl as lv
def event_cb(e):
code = e.get_code()
chart = e.get_target_obj()
if code == lv.EVENT.VALUE_CHANGED:
chart.invalidate()
if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
# s = lv.coord_t.__cast__(e.get_param())
# print("s: {:d}".format(s))
e.set_ext_draw_size(20)
ser = chart.get_series_next(None)
while(ser) :
p = lv.point_t()
chart.get_point_pos_by_id(ser, id, p)
# print("point coords: x: {:d}, y: {:d}".format(p.x,p.y))
y_array = chart.get_y_array(ser)
value = y_array[id]
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
(continues on next page)
coords = lv.area_t()
chart.get_coords(coords)
# print("coords: x1: {:d}, y1: {:d}".format(coords.x1, coords.y1))
a = lv.area_t()
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
# print("a: x1: {:d}, x2: {:d}, y1: {:d}, y2: {:d}".format(a.x1,a.x2,a.y1,
,→ a.y2))
draw_ctx = e.get_draw_ctx()
draw_ctx.rect(draw_rect_dsc, a)
ser = chart.get_series_next(ser)
#
# Show the value of the pressed points
#
# Create a chart
chart = lv.chart(lv.scr_act())
chart.set_size(200, 150)
chart.center()
chart.refresh_ext_draw_size()
# Zoom in a little in X
chart.set_zoom_x(800)
#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,
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,
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);
(continues on next page)
lv_obj_t * slider;
slider = lv_slider_create(lv_scr_act());
lv_slider_set_range(slider, LV_ZOOM_NONE, LV_ZOOM_NONE * 10);
lv_obj_add_event(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_ZOOM_NONE, LV_ZOOM_NONE * 10);
lv_obj_add_event(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 = [
-2, 2, 0, -15, -39, -63, -71, -68, -67, -69, -84, -95, -104, -107, -108, -107, -
,→107, -107, -107, -114, -118, -117,
-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,
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,
slider = e.get_target_obj()
v = slider.get_value()
chart.set_zoom_x(v)
def slider_y_event_cb(e):
slider = e.get_target_obj()
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())
slider.set_range(lv.ZOOM_NONE, lv.ZOOM_NONE * 10)
slider.add_event(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.ZOOM_NONE, lv.ZOOM_NONE * 10)
slider.add_event(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_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;
(continues on next page)
/**
* 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
#
# 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_obj()
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_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(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
def draw_event_cb(e):
dsc = e.get_draw_part_dsc()
if dsc.part == lv.PART.ITEMS:
obj = e.get_target_obj()
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(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_USE_DRAW_MASKS && 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
(continues on next page)
/**
* 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(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;
(continues on next page)
/* 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 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_obj()
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):
mask = (mask << 1) + 1
#
# Stacked area chart
#
def lv_example_chart_8():
#Create a stacked_area_chart.obj
stacked_area_chart.obj = lv.chart(lv.scr_act())
(continues on next page)
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
LV_UNUSED(txt);
LV_UNUSED(state);
LV_LOG_USER("%s: %s", txt, state);
}
}
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, 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, 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, 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, event_handler, LV_EVENT_ALL, NULL);
lv_obj_update_layout(cb);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target_obj()
if code == lv.EVENT.VALUE_CHANGED:
(continues on next page)
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(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(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(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(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
import time
class LV_Example_Checkbox_2:
def __init__(self):
#
# Checkboxes as radio buttons
#
# The idea is to enable `LV_OBJ_FLAG_EVENT_BUBBLE` on checkboxes and process␣
,→the
self.active_index_1 = 0
self.active_index_2 = 0
self.style_radio = lv.style_t()
self.style_radio.init()
self.style_radio.set_radius(lv.RADIUS_CIRCLE)
self.style_radio_chk = lv.style_t()
self.style_radio_chk.init()
self.style_radio_chk.init()
self.style_radio_chk.set_bg_img_src(None)
self.cont1 = lv.obj(lv.scr_act())
self.cont1.set_flex_flow(lv.FLEX_FLOW.COLUMN)
self.cont1.set_size(lv.pct(40), lv.pct(80))
self.cont1.add_event(self.radio_event_handler, lv.EVENT.CLICKED, None)
for i in range(5):
txt = "A {:d}".format(i+1)
self.radiobutton_create(self.cont1,txt)
self.cont2 = lv.obj(lv.scr_act())
self.cont2.set_flex_flow(lv.FLEX_FLOW.COLUMN)
self.cont2.set_size(lv.pct(40), lv.pct(80))
self.cont2.set_x(lv.pct(50))
self.cont2.add_event(self.radio_event_handler, lv.EVENT.CLICKED, None)
(continues on next page)
for i in range(3):
txt = "B {:d}".format(i+1)
self.radiobutton_create(self.cont2,txt)
def radio_event_handler(self,e):
cont = e.get_current_target_obj()
act_cb = e.get_target_obj()
if cont == self.cont1:
active_id = self.active_index_1
else:
active_id = self.active_index_2
old_cb = cont.get_child(active_id)
if cont == self.cont1:
self.active_index_1 = act_cb.get_index()
# print("active index 1: ", self.active_index_1)
else:
self.active_index_2 = act_cb.get_index()
# print("active index 2: ", self.active_index_2)
lv_example_checkbox_2 = LV_Example_Checkbox_2()
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_obj()
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(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());
(continues on next page)
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)
dd.set_dir(lv.DIR.LEFT)
dd.set_symbol(lv.SYMBOL.LEFT)
dd.align(lv.ALIGN.RIGHT_MID, -10, 0)
(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_obj()
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)
2.7.12 Image
#include "../../lv_examples.h"
#if LV_USE_IMG && LV_BUILD_EXAMPLES
void lv_example_img_1(void)
(continues on next page)
#endif
#!/opt/bin/lv_micropython -i
import usys as sys
import lvgl as lv
import display_driver
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
/**
(continues on next page)
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
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(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)
intense_slider.send_event(lv.EVENT.VALUE_CHANGED, None)
#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
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
#
# 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:
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:
(continues on next page)
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(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_obj()
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(lambda e: ta_event_cb(e,kb), lv.EVENT.ALL, None)
(continues on next page)
kb.set_textarea(ta)
#include "../../lv_examples.h"
#if LV_USE_KEYBOARD && LV_BUILD_EXAMPLES
void lv_example_keyboard_2(void)
{
/*Create an AZERTY keyboard map*/
static const char * kb_map[] = {"A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P",␣
,→LV_SYMBOL_BACKSPACE, "\n",
"Q", "S", "D", "F", "G", "J", "K", "L", "M", LV_
,→SYMBOL_NEW_LINE, "\n",
"W", "X", "C", "V", "B", "N", ",", ".", ":", "!",
,→"?", "\n",
};
};
lv_keyboard_set_textarea(kb, ta);
}
#endif
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())
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)
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 ")
(continues on next page)
#include "../../lv_examples.h"
#if LV_USE_LABEL && LV_USE_CANVAS && LV_BUILD_EXAMPLES && LV_USE_DRAW_MASKS
}
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*/
}
(continues on next page)
#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()
(continues on next page)
2.7.18 List
Simple List
#include "../../lv_examples.h"
#if LV_USE_LIST && LV_BUILD_EXAMPLES
static lv_obj_t * list1;
lv_list_add_text(list1, "File");
btn = lv_list_add_btn(list1, LV_SYMBOL_FILE, "New");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_DIRECTORY, "Open");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_SAVE, "Save");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, "Delete");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_EDIT, "Edit");
lv_obj_add_event(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(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_GPS, "Navigation");
(continues on next page)
lv_list_add_text(list1, "Exit");
btn = lv_list_add_btn(list1, LV_SYMBOL_OK, "Apply");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
btn = lv_list_add_btn(list1, LV_SYMBOL_CLOSE, "Close");
lv_obj_add_event(btn, event_handler, LV_EVENT_CLICKED, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target_obj()
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(event_handler,lv.EVENT.ALL, None)
btn_navig = list1.add_btn(lv.SYMBOL.GPS, "Navigation")
btn_navig.add_event(event_handler,lv.EVENT.ALL, None)
btn_USB = list1.add_btn(lv.SYMBOL.USB, "USB")
btn_USB.add_event(event_handler,lv.EVENT.ALL, None)
btn_battery = list1.add_btn(lv.SYMBOL.BATTERY_FULL, "Battery")
btn_battery.add_event(event_handler,lv.EVENT.ALL, None)
list1.add_text("Exit")
btn_apply = list1.add_btn(lv.SYMBOL.OK, "Apply")
btn_apply.add_event(event_handler,lv.EVENT.ALL, None)
btn_close = list1.add_btn(lv.SYMBOL.CLOSE, "Close")
btn_close.add_event(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(e):
global currentButton
code = e.get_code()
obj = e.get_target_obj()
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(e):
global currentButton
code = e.get_code()
obj = e.get_target_obj()
if code == lv.EVENT.CLICKED:
if currentButton == None:
return
currentButton.move_background()
currentButton.scroll_to_view( lv.ANIM.ON)
def event_handler_up(e):
global currentButton
code = e.get_code()
obj = e.get_target_obj()
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(e):
global currentButton
code = e.get_code()
obj = e.get_target_obj()
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(e):
global currentButton
code = e.get_code()
obj = e.get_target_obj()
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(e):
global currentButton
global list1
code = e.get_code()
obj = e.get_target_obj()
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( 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(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_obj()
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(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(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(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_obj_send_event(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);
}
}
NULL);
}
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;
(continues on next page)
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
obj = lv.menu_cont(parent)
img = None
label = None
if icon :
img = lv.img(obj)
img.set_src(icon)
if txt :
label = lv.label(obj)
label.set_text(txt)
label.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR)
label.set_flex_grow(1)
return obj
slider = lv.slider(obj)
slider.set_flex_grow(1)
slider.set_range(min, max)
slider.set_value(val, lv.ANIM.OFF)
if icon == None :
slider.add_flag(lv.obj.FLAG_FLEX.IN_NEW_TRACK)
return obj
sw = lv.switch(obj)
if chk == lv.STATE.CHECKED:
sw.add_state(chk )
else:
sw.add_state(0)
return obj
def back_event_handler(e,menu):
obj = e.get_target_obj()
# menu = lv_event_get_user_data(e);
if menu.back_btn_is_root(obj) :
mbox1 = lv.msgbox(None, "Hello", "Root back btn click.", None, True)
mbox1.center()
def switch_handler(e,menu):
code = e.get_code()
obj = e.get_target_obj()
if code == lv.EVENT.VALUE_CHANGED :
if obj.has_state(lv.STATE.CHECKED) :
menu.set_page(None)
menu.set_sidebar_page(root_page)
menu.get_cur_sidebar_page().get_child(0).get_child(0).send_event(lv.EVENT.
,→CLICKED,None)
else :
menu.set_sidebar_page(None)
menu.clear_history() # Clear history because we will be showing the␣
,→root page later
menu.set_page(root_page)
LV_MENU_ITEM_BUILDER_VARIANT_1 = const(0)
(continues on next page)
menu = lv.menu(lv.scr_act())
bg_color = menu.get_style_bg_color(0)
if bg_color.color_brightness() > 127 :
menu.set_style_bg_color(menu.get_style_bg_color(0).color_darken(10),0)
else :
menu.set_style_bg_color(menu.get_style_bg_color(0).color_darken(50),0)
menu.set_mode_root_back_btn(lv.menu.ROOT_BACK_BTN.ENABLED)
menu.add_event(lambda evt: back_event_handler(evt,menu), lv.EVENT.CLICKED, None)
menu.set_size(lv.pct(100), lv.pct(100))
menu.center()
section = lv.menu_section(sub_software_info_page)
create_text(section,None, "Version 1.0", LV_MENU_ITEM_BUILDER_VARIANT_1)
section = lv.menu_section(sub_legal_info_page)
for i in range(15):
create_text(section, None,
"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)
menu.set_load_page_event(cont, sub_software_info_page);
cont = create_text(section, None, "Legal information", LV_MENU_ITEM_BUILDER_VARIANT_
,→1);
menu.set_load_page_event(cont, sub_legal_info_page)
menu.set_load_page_event(cont, sub_mechanics_page);
cont = create_text(section, lv.SYMBOL.AUDIO, "Sound", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_sound_page)
cont = create_text(section, lv.SYMBOL.SETTINGS, "Display", LV_MENU_ITEM_BUILDER_
,→VARIANT_1);
menu.set_load_page_event(cont, sub_display_page)
menu.set_load_page_event(cont, sub_menu_mode_page)
menu.set_sidebar_page(root_page)
menu.get_cur_sidebar_page().get_child(0).get_child(0).send_event(lv.EVENT.CLICKED,
,→None)
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)
{
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, 220, 220);
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)
# Scale settings
meter.set_scale_ticks(11, 2, 10, lv.palette_main(lv.PALETTE.GREY))
meter.set_scale_major_ticks(1, 2, 30, lv.color_hex3(0xeee), 10)
meter.set_scale_range(0, 100, 270, 90)
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);
LV_IMG_DECLARE(img_hand)
lv_anim_set_var(&a, indic_hour);
lv_anim_set_time(&a, 240000); /*24 sec for 1 turn of the hour hand*/
lv_anim_set_values(&a, 0, 59);
lv_anim_start(&a);
(continues on next page)
#endif
#!//opt/bin/lv_micropython -i
import utime as time
import lvgl as lv
import display_driver
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
})
def tick_label_event(e):
draw_part_dsc = e.get_draw_part_dsc();
idx = int(draw_part_dsc.id / 5)
(continues on next page)
meter = lv.meter(lv.scr_act())
meter.set_size(220, 220)
meter.center()
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_target_obj()
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"
"December",
LV_ROLLER_MODE_INFINITE);
lv_roller_set_visible_row_count(roller1, 4);
lv_obj_center(roller1);
lv_obj_add_event(roller1, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target_obj()
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
#
(continues on next page)
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(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);
lv_style_set_bg_color(&style_sel, lv_color_hex3(0xf88));
lv_style_set_border_width(&style_sel, 2);
lv_style_set_border_color(&style_sel, lv_color_hex3(0xf00));
/*A roller on the left with left aligned text, and custom width*/
roller = lv_roller_create(lv_scr_act());
(continues on next page)
/*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(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(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_obj()
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)
(continues on next page)
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(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(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(event_handler, lv.EVENT.ALL, None)
roller.set_selected(8, lv.ANIM.OFF)
#include "../../lv_examples.h"
#if LV_USE_ROLLER && LV_USE_DRAW_MASKS && LV_BUILD_EXAMPLES
if(code == LV_EVENT_COVER_CHECK) {
lv_event_set_cover_res(e, LV_COVER_RES_MASKED);
(continues on next page)
}
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_free(fade_mask_top);
lv_free(fade_mask_bottom);
mask_top_id = -1;
mask_bottom_id = -1;
}
}
/**
* 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());
(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(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())
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)
(continues on next page)
#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(self.mask_event_cb, lv.EVENT.ALL, None)
def mask_event_cb(self,e):
code = e.get_code()
obj = e.get_target_obj()
if code == lv.EVENT.COVER_CHECK:
e.set_cover_res(lv.COVER_RES.MASKED)
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
(continues on next page)
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
*/
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(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
#endif
#
# A default slider with a label displaying the current value
#
def slider_event_cb(e):
slider = e.get_target_obj()
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));
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()
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)
(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*/
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);
(continues on next page)
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_obj()
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);
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)
(continues on next page)
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()
# lv_span_del(spans, span);
# lv_obj_del(spans);
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(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_LEFT_MID, -5, 0)
btn.set_style_bg_img_src(lv.SYMBOL.MINUS, 0)
btn.add_event(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(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(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(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(sw, event_handler, LV_EVENT_ALL, NULL);
}
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target_obj()
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(event_handler,lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED)
sw.add_event(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.DISABLED)
sw.add_event(event_handler, lv.EVENT.ALL, None)
sw = lv.switch(lv.scr_act())
sw.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
(continues on next page)
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)
{
lv_obj_t * table = lv_table_create(lv_scr_act());
#endif
def draw_part_event_cb(e):
obj = e.get_target_obj()
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
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;
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;
}
(continues on next page)
/**
* 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);
uint32_t i;
for(i = 0; i < ITEM_CNT; i++) {
lv_table_set_cell_value_fmt(table, i, 0, "Item %"LV_PRIu32, i + 1);
}
#endif
ITEM_CNT = 200
def draw_event_cb(e):
obj = e.get_target_obj()
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
sw_area.y2 = sw_area.y1 + 20
dsc.draw_ctx.rect(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
(continues on next page)
def change_event_cb(e):
obj = e.get_target_obj()
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")
(continues on next page)
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");
label = lv_label_create(tab3);
lv_label_set_text(label, "Third tab");
lv_obj_scroll_to_view_recursive(label, LV_ANIM_ON);
}
#endif
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);
lv_obj_add_event(lv_tabview_get_content(tabview), scroll_begin_event, LV_EVENT_
,→SCROLL_BEGIN, NULL);
/*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
def scroll_begin_event(e):
tabview.set_style_bg_color(lv.palette_lighten(lv.PALETTE.RED, 2), 0)
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)
(continues on next page)
# 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)
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());
lv_textarea_set_one_line(ta, true);
lv_obj_align(ta, LV_ALIGN_TOP_MID, 0, 10);
lv_obj_add_event(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(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(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(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_obj()
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.pct(45))
pwd_ta.set_pos(5, 20)
pwd_ta.add_event(ta_event_cb, lv.EVENT.ALL, None)
# Create a keyboard
kb = lv.keyboard(lv.scr_act())
kb.set_size(lv.pct(100), lv.pct(50))
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(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_obj()
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
ta = lv.textarea(lv.scr_act())
ta.add_event(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.pct(100), lv.pct(50))
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
(continues on next page)
# 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")
2.7.32 Window
Simple window
#include "../../lv_examples.h"
#if LV_USE_WIN && LV_BUILD_EXAMPLES
void lv_example_win_1(void)
{
(continues on next page)
#endif
def event_handler(e):
code = e.get_code()
obj = e.get_target_obj()
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.
237
LVGL Documentation 9.0
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[MY_DISP_HOR_RES * MY_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_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_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/slider/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_LABEL
/**
* Basic example to create a "Hello world" label
*/
void lv_example_get_started_1(void)
{
/*Change the active screen's background color*/
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x003a57), LV_PART_MAIN);
/*Create a white label, set its text and align it to the center*/
lv_obj_t * label = lv_label_create(lv_scr_act());
lv_label_set_text(label, "Hello world");
lv_obj_set_style_text_color(lv_scr_act(), lv_color_hex(0xffffff), LV_PART_MAIN);
lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);
}
#endif
# Create a white label, set its text and align it to the center
label = lv.label(lv.scr_act())
label.set_text("Hello world")
label.set_style_text_color(lv.color_hex(0xffffff), lv.PART.MAIN)
label.align(lv.ALIGN.CENTER, 0, 0)
#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_2(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,e):
code = e.get_code()
btn = e.get_target_obj()
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_3(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_4(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(e):
slider = e.get_target_obj()
#
# 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 with SDL driver: 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.
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;
Features supported:
• Color keying
• Recoloring (color tint)
• Image Rotation (90, 180, 270 degree)
• RTOS integration layer
• Default FreeRTOS and bare metal code provided
• Combination of recolor and/or rotation + color key/alpha blend/transparency is supported. That is achieved by PXP
in two steps:
– First step is to recolor/rotate the image to a temporary buffer (statically allocated)
– Second step is required to handle color keying, alpha channel or to apply transparency
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;
(continues on next page)
Features supported:
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
. . .
(continues on next page)
#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
LVGL Can be added to STM32CubeIDE in a similar fashion to any other Eclipse-based IDE.
//Frame buffers
/*A static or global variable to store the buffers*/
static lv_disp_draw_buf_t disp_buf;
• In your main() function, after initialising your CPU, peripherals, and LCD panel, call lv_init(); to initialise
LVGL. You can then register the frame buffers using lv_disp_draw_buf_init(), and create the display
driver using lv_disp_drv_init().
static lv_disp_drv_t disp_drv; /*A variable to hold the drivers. Must be␣
,→static or global.*/
lv_disp_t * disp;
disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created␣
,→display objects*/
/*Create a spinner*/
lv_obj_t * spinner = lv_spinner_create(lv_scr_act(), 1000, 60);
lv_obj_set_size(spinner, 64, 64);
lv_obj_align(spinner, LV_ALIGN_BOTTOM_MID, 0, 0);
/* Infinite loop */
while (1)
{
lv_timer_handler();
HAL_Delay(5);
}
• Add a call to lv_tick_inc() inside the SysTick_Handler() function. Open the stm32xxxx_it.c file (the
name will depend on your specific MCU), and update the SysTick_Handler() function:
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
HAL_SYSTICK_IRQHandler();
lv_tick_inc(1);
#ifdef USE_RTOS_SYSTICK
osSystickHandler();
#endif
• Finally, write the callback function, my_flush_cb(), which will send the display buffer to your LCD panel.
Below is one example, but it will vary depending on your setup.
{
//Set the drawing region
set_draw_window(area->x1, area->y1, area->x2, area->y2);
//Return CS to high
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
FreeRTOS Example
A minimal example using STM32CubeIDE, HAL, and CMSISv1 (FreeRTOS). Note that we have not used Mutexes in
this example, however LVGL is NOT thread safe and so Mutexes should be used. See: Operating system and interrupts
• #include "lvgl.h"
• Create your frame buffer(s) as global variables:
//Frame buffers
/*A static or global variable to store the buffers*/
static lv_disp_draw_buf_t disp_buf;
• In your main() function, after your peripherals (SPI, GPIOs, LCD etc) have been initialised, initialise LVGL
using lv_init();, register the frame buffers using lv_disp_draw_buf_init(), and create a new display
driver using lv_disp_drv_init().
static lv_disp_drv_t disp_drv; /*A variable to hold the drivers. Must be␣
,→static or global.*/
lv_disp_t * disp;
disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created␣
,→display objects*/
// Register the touch controller with LVGL - Not included here for brevity.
/*Create a spinner*/
lv_obj_t * spinner = lv_spinner_create(lv_scr_act(), 1000, 60);
lv_obj_set_size(spinner, 64, 64);
lv_obj_align(spinner, LV_ALIGN_BOTTOM_MID, 0, 0);
• Create two threads to call lv_timer_handler(), and lv_tick_inc().You will need two osThreadId
handles for CMSISv1. These don't strictly have to be globally accessible in this case, however STM32Cube code
generation does by default. If you are using CMSIS and STM32Cube code generation it should look something
like this:
//Thread Handles
osThreadId lvgl_tickHandle;
osThreadId lvgl_timerHandle;
• Finally, create the my_flush_cb() function to output the frame buffer to your LCD. The specifics of this
function will vary depending on which MCU features you are using. Below is an example for a typical MCU
interface.
{
//Set the drawing region
set_draw_window(area->x1, area->y1, area->x2, area->y2);
(continues on next page)
//Return CS to high
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
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 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 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.
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.0.2, 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.7 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.
Examples/demos options
LVGL examples and demos are built by default in the main CMake file.To disable their built, use:
• LV_CONF_BUILD_DISABLE_EXAMPLES: Set to 1 to disable examples build
• LV_CONF_BUILD_DISABLE_DEMOS: Set to 1 to disable demos build
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.2.9 MDK
TODO
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?
RT-Thread is an open source, neutral, and community-based real-time operating system (RTOS). RT-Thread has Stan-
dard version and Nano version. For resource-constrained microcontroller (MCU) systems, the Nano version that re-
quires only 3 KB Flash and 1.2 KB RAM memory resources can be tailored with easy-to-use tools. For resource-rich IoT
devices, RT-Thread can use the online software package management tool, together with system configuration tools, to
achieve intuitive and rapid modular cutting, seamlessly import rich software packages; thus, achieving complex functions
like Android's graphical interface and touch sliding effects, smart voice interaction effects, and so on.
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:
Tutorials
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.)
Micropython does not have a good native high-level GUI library. 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.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text('Hello World!')
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
Many LVGL examples are available also for Micropython.Just click the link!
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 Platforms
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. lv_micropython is a fork of Micropython+LVGL and currently supports Linux, ESP32, STM32 and RP2.
It can be ported to any other platform supported by Micropython.
You would also need display and input drivers. You can either use one of the existing drivers provided with
lv_micropython, or you can create your own input/display drivers for your specific hardware.Drivers can be implemented
either in C as a Micropython module, or in pure Python!
lv_micropython already contains these drivers:
• Display drivers:
– SDL on Linux
– ESP32 specific: ILI9341, ILI9488, GC9A01, ST7789, ST7735
– Generic (pure Python): ILI9341, ST7789, ST7735
• Input drivers:
– SDL, XPT2046, FT6X36, ESP32 ADC with resistive touch
• lv_micropython README
• lv_binding_micropython README
• The LVGL micropython forum (Feel free to ask anything!)
• At Micropython: docs and forum
• Blog Post, a little outdated.
LVGL is a git submodule inside lv_micropython (LVGL is a git submodule of lv_binding_micropython which is itself
a submodule of lv_micropython).When building lv_micropython, the public LVGL C API is scanned and Micropython
API is auto-generated. That means that lv_micropython provides LVGL API for any LVGL version, and generally does
not require code changes as LVGL evolves.
To support the auto-generation of the Python API, the LVGL C API must follow some coding conventions:
• Use enums instead of macros. If inevitable to use defines export them with
LV_EXPORT_CONST_INT(defined_value) right after the define.
• In function arguments use type name[] declaration for array parameters instead of type * name
• Use typed pointers instead of void * pointers
• Widget constructor must follow the lv_<widget_name>_create(lv_obj_t * parent) pattern.
• Widget members function must start with lv_<modul_name> and should receive lv_obj_t * as first argu-
ment which is a pointer to widget object itself.
• struct APIs should follow the widgets' conventions. That is to receive a pointer to the struct as the first
argument, and the prefix of the struct name should be used as the prefix of the function name too (e.g.
lv_disp_set_default(lv_disp_t * disp))
• Functions and structs which are not part of the public API must begin with underscore in order to mark them
as "private".
• Argument must be named in H files too.
• Do not malloc into a static or global variables. Instead declare the variable in LV_ITERATE_ROOTS list in
lv_gc.h and mark the variable with GC_ROOT(variable) when it's used.See Memory Management
• To register and use callbacks one of the followings needs to be followed. See Callbacks
– Pass a pointer to a struct as the first argument of both the registration function and the callback. That
struct must contain void * user_data field.
– The last argument of the registration function must be void * user_data and the same user_data
needs to be passed as the last argument of the callback.
Most of these rules are simple and straightforward but there are two related concepts that worth a deeper look: Memory
Management and Callbacks.
Memory Management
When LVGL runs in Micropython, all dynamic memory allocations (lv_malloc) are handled by Micropython's mem-
ory manager which is garbage-collected (GC).To prevent GC from collecting memory prematurely, all dynamic allocated
RAM must be reachable by GC.GC is aware of most allocations, except from pointers on the Data Segment:
• Pointers which are global variables
• Pointers which are static global variables
• Pointers which are static local variables
Such pointers need to be defined in a special way to make them reachable by GC
Problem happens when an allocated memory's pointer (return value of lv_malloc) is stored only in either global,
static global or static local pointer variable and not as part of a previously allocated struct or other variable.
Example
https://github.com/lvgl/lvgl/commit/adced46eccfa0437f84aa51aedca4895cc3c679c
More Information
Callbacks
In C a callback is just a function pointer. But in Micropython we need to register a Micropython callable object for each
callback. Therefore in the Micropython binding we need to register both a function pointer and a Micropython object for
every callback.
Therefore we defined a callback convention for the LVGL C API that expects lvgl headers to be defined in a certain way.
Callbacks that are declared according to the convention would allow the binding to register a Micropython object next to
the function pointer when registering a callback, and access that object when the callback is called.
The basic idea is that we have void * user_data field that is used automatically by the Micropython Binding to
save the Micropython callable object for a callback. This field must be provided when registering the function pointer,
and provided to the callback function itself.Although called "user_data", the user is not expectd to read/write that field.
Instead, the Micropython glue code uses user_data to automatically keep track of the Micropython callable object.
The glue code updates it when the callback is registered, and uses it when the callback is called in order to invoke a call
to the original callable object.
There are a few options for defining a callback in LVGL C API:
• Option 1: user_data in a struct
– There's a struct that contains a field called void * user_data
– A pointer to that struct is provided as the first argument of a callback registration function
– A pointer to that struct is provided as the first argument of the callback itself
• Option 2: user_data as a function argument
– A parameter called void * user_data is provided to the registration function as the last argument
– The callback itself recieves void * as the last argument
• Option 3: both callback and user_data are struct fields
– The API exposes a struct with both function pointer member and user_data member
– The function pointer member receives the same struct as its first argument
In practice it's also possible to mix these options, for example provide a struct pointer when registering a callback (option
1) and provide user_data argument when calling the callback (options 2), as long as the same user_data that
was registered is passed to the callback when it's called.
Examples
More Information
3.4.2 Cpp
In progress: https://github.com/lvgl/lv_binding_cpp
3.4.3 PikaScript
What is PikaScript ?
PikaScript is a Python interpreter designed specifically for microcontrollers, and it supports a subset of the common
Python3 syntax.
It's lighter, requiring only 32k of code space and 4k of RAM, which means it can run on stm32f103c8 (blue-pill) or even
stm32g030c8, on the other hand, you can leave valuable space for more material or larger buffer areas.
It is simpler, out of the box, runs with no porting and configuration at all, does not depend on OS or file system, has good
support for popular IDEs for Windows platforms like Keil, IAR, RT-Thread-Studio, and of course, supports linux-gcc
development platforms.
It's smarter, with a unique C module mechanism that allows you to generate bindings automatically by simply writing the
API for the C module in Python, and you don't need to deal with the headache of writing any macros or global tables
manually. On the other hand, all C modules have sophisticated smart hints, even hinting at the types of your arguments .
PikaScript now supports the main features of LVGL8, and these APIs are fully compatible with Micropython!
This means that you can continue to use already written code from Micropython, and then use less code space and RAM.
Enjoy detailed code hints down to the parameter type for a better programming experience
Use a more convenient IDE, such as vs-based simulation projects
Here are some examples of lvgl that PikaScript can already run, they are mainly from the lvgl documentation examples
LV_ARC
import pika_lvgl as lv
import PikaStdLib
mem = PikaStdLib.MemChecker()
# Create an Arc
arc = lv.arc(lv.scr_act())
arc.set_end_angle(200)
arc.set_size(150, 150)
arc.center()
print('mem used max: %0.2f kB' % (mem.getMax()))
print('mem used now: %0.2f kB' % (mem.getNow()))
LV_BAR
import pika_lvgl as lv
import PikaStdLib
mem = PikaStdLib.MemChecker()
bar1 = lv.bar(lv.scr_act())
bar1.set_size(200, 20)
bar1.center()
bar1.set_value(70, lv.ANIM.OFF)
print('mem used max: %0.2f kB' % (mem.getMax()))
print('mem used now: %0.2f kB' % (mem.getNow()))
LV_BTN
import pika_lvgl as lv
import PikaStdLib
mem = PikaStdLib.MemChecker()
def event_cb_1(evt):
print('in evt1')
print('mem used now: %0.2f kB' % (mem.getNow()))
def event_cb_2(evt):
print('in evt2')
print('mem used now: %0.2f kB' % (mem.getNow()))
btn1 = lv.btn(lv.scr_act())
(continues on next page)
LV_CHECKBOX
import pika_lvgl as lv
import PikaStdLib
mem = PikaStdLib.MemChecker()
cb = lv.checkbox(lv.scr_act())
cb.set_text("Apple")
cb.align(lv.ALIGN.TOP_LEFT, 0 ,0)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Banana")
cb.add_state(lv.STATE.CHECKED)
cb.align(lv.ALIGN.TOP_LEFT, 0 ,30)
cb = lv.checkbox(lv.scr_act())
cb.set_text("Lemon")
cb.add_state(lv.STATE.DISABLED)
cb.align(lv.ALIGN.TOP_LEFT, 0 ,60)
cb = lv.checkbox(lv.scr_act())
cb.add_state(lv.STATE.CHECKED | lv.STATE.DISABLED)
cb.set_text("Melon")
cb.align(lv.ALIGN.TOP_LEFT, 0 ,90)
print('mem used max: %0.2f kB' % (mem.getMax()))
print('mem used now: %0.2f kB' % (mem.getNow()))
# pika_lvgl.pyi
class arc(lv_obj):
def set_end_angle(self, angle: int): ...
def set_bg_angles(self, start: int, end: int): ...
def set_angles(self, start: int, end: int): ...
Then PikaScript's pre-compiler can automatically bind the following C functions, simply by naming the functions in the
module_class_method format, without any additional work, and all binding and registration is done automatically.
/* pika_lvgl_arc.c */
void pika_lvgl_arc_set_end_angle(PikaObj* self, int angle) {
lv_obj_t* lv_obj = obj_getPtr(self, "lv_obj");
lv_arc_set_end_angle(lv_obj, angle);
}
(continues on next page)
To use the module, just import pika_lvgl and the precompiler will automatically scan main.py and bind the
pika_lvgl module
$ ./rust-msc-latest-win10.exe
(pikascript) packages installed:
pikascript-core==v1.10.0
PikaStdLib==v1.10.0
PikaStdDevice==v1.10.0
(pikascript) pika compiler:
scaning main.py...
binding pika_lvgl.pyi...
The precompiler is written in Rust, runs on windows and linux, and is completely open source.
In addition to binding C modules, the precompiler compiles Python scripts to bytecode in the PC, reducing the size of
the script and increasing its speed.
3.4.4 JavaScript
Table of Contents
• Features
• Demo
• Building
• Components
• Font
• Animation
• Style
• JSAPI
• Thanks
Features
Demo
Building
The following are developer notes on how to build lvgljs on your native platform. They are not complete guides, but
include notes on the necessary libraries, compile flags, etc.
lvgljs
JS Bundle
Components
Font
Buitin-Symbol
Animation
Animation
Style
JSAPI
Thanks
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.
281
LVGL Documentation 9.0
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 create a display for LVGL call lv_disp_t * disp = lv_disp_create(hor_res, ver_res). You
can create a multiple displays and a different driver for each (see below),
Draw buffer(s) are simple array(s) that LVGL uses to render the screen's content. Once rendering is ready the content of
the draw buffer is sent to the display using the flush_cb function.
flush_cb
/* IMPORTANT!!!
* Inform LVGL that you are ready with the flushing and buf is not used anymore*/
lv_disp_flush_ready(disp);
}
Draw buffers
The draw buffers can be set with lv_disp_set_draw_buffers(disp, buf1, buf2, buf_size_px,
render_mode);
• buf1 a bufer where LVGL can render
• buf2 a second optional buffer (see more details below)
• buf_size_byte size of the buffer(s) in bytes
• render_mode
– LV_DISP_RENDER_MODE_PARTIAL Use the buffer(s) to render the screen is smaller parts. This way
the buffers can be smaller then the display to save RAM. At least 1/10 sceen size buffer(s) are recommended.
In flush_cb the rendered images needs to be copied to the given area of the display.
– LV_DISP_RENDER_MODE_DIRECT The buffer(s) has to be screen sized and LVGL will render into the
correct location of the buffer. This way the buffer always contain the whole image. If two buffer are used the
rendered ares are automatically copied to the other buffer after flushing. Due to this in flush_cb typically
only a frame buffer address needs to be changed and always the changed areas will be redrawn.
– LV_DISP_RENDER_MODE_FULL The buffer can smaller or screen sized but LVGL will always redraw the
whole screen even is only 1 pixel has been changed. If 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).
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 via the
flush_cb. LVGL then needs to wait until the content of the buffer is sent to the display before drawing something new
into 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.
Resoltion
To set the resolution of the display after creation use lv_disp_set_res(disp, hor_res, ver_res);
It's not mandatory to use the whole display for LVGL, however in some cases the physical resolution is important. For
example the touchpad still sees the whole resolution and the values needs to be converted to the active LVGL display area.
So the physical resoltution and the offset of the active area can be set with lv_disp_set_physical_res(disp,
hor_res, ver_res);and lv_disp_set_offset(disp, x, y);
Rotation
LVGL supports rotation of the display in 90 degree increments. You can select whether you'd like software rotation or
hardware rotation.
The orientation of the display can be changed with lv_disp_set_rotation(disp, LV_DISP_ROTATION_0/
90/180/270, true/false). LVGL will swap the horizontal and vertical resolutions internally according to the
set degree. IF the last paramter is true LVGL will rotate the rendered image. If it's false the display driver should
rotate the rendered image.
Color format
Set the color format of the display. The default is LV_COLOR_FORMAT_NATIVE which means LVGL render with the
follow formats dpeneding on LV_COLOR_DEPTH:
• LV_COLOR_DEPTH 32 XRGB8888 (4 bytes/pixel)
• LV_COLOR_DEPTH 24 RGB888 (3 bytes/pixel)
• LV_COLOR_DEPTH 16 RGB565 (2 bytes/pixel)
• LV_COLOR_DEPTH 8 L8 (1 bytes/pixel)
The color_format can be changed with lv_disp_set_color_depth(disp, LV_COLOR_FORMAT_...
) to the following values:
• LV_COLOR_FORMAT_NATIVE_ALPHA Append an alpha byte to the native format resulting in A8L8,
ARGB8565, ARGB8888 formats.
• LV_COLOR_FORMAT_NATIVE_REVERSE Reverse the byte order of the native format. Useful if the rendered
image is sent to the disply via SPI and the display needs the bytes in the opposite order.
• LV_COLOR_FORMAT_L8 Lightness only on 8 bit
• LV_COLOR_FORMAT_A8 Alpha only on 8 bit
• LV_COLOR_FORMAT_I8 Indexed (palette) 8 bit
• LV_COLOR_FORMAT_A8L8 Lightness on 8 bit with 8 bit alpha
• LV_COLOR_FORMAT_ARGB2222 ARGB with 2 bit for each channel
• LV_COLOR_FORMAT_RGB565 16 bit RGB565 format without alpha channel
• LV_COLOR_FORMAT_ARGB8565 16 bit RGB565 format and 8 bit alpha channel
• LV_COLOR_FORMAT_ARGB1555 5 bit for each color channel and 1 bit for alpha
• LV_COLOR_FORMAT_ARGB4444 4 bit for each channel
• LV_COLOR_FORMAT_RGB888 8 bit for each color channel with out alpha channel
• LV_COLOR_FORMAT_ARGB8888 8 bit for each channel
• LV_COLOR_FORMAT_XRGB8888 8 bit for each color channel and 8 bit placholder for the alpha cannel
If the color fotmat is set to non-native draw_ctx->buffer_convert function will be called before calling
flush_cb to convert the native color format to the desired, therfore rendering in non-native formats has a negative
effect on peroformance. Learn more about draw_ctx here.
It's very important that draw buffer(s) should be large enough for both the native format and the target color format. For
example if LV_COLOR_DEPTH == 16 and LV_COLOR_FORMAT_XRGB8888 is selected LVGL will choosoe the
larger to figure out how many pixel can be rendered at once. Therefore with LV_DISP_RENDER_MODE_FULL and the
larger pixel size needs to choosen.
LV_DISP_RENDER_MODE_DIRECT supports only the LV_COLOR_FORMAT_NATIVE format.
Antialiasing
User data
4.2.3 Events
Normally the dirty (a.k.a invalid) areas are checked and redrawn in every LV_DEF_REFR_PERIOD milliseconds (set
in lv_hal_disp.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_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_rotation_t
Values:
enumerator LV_DISP_ROTATION_0
enumerator LV_DISP_ROTATION_90
enumerator LV_DISP_ROTATION_180
enumerator LV_DISP_ROTATION_270
enum lv_disp_render_mode_t
Values:
enumerator LV_DISP_RENDER_MODE_PARTIAL
Use the buffer(s) to render the screen is smaller parts. This way the buffers can be smaller then the display to
save RAM. At least 1/10 sceen size buffer(s) are recommended.
enumerator LV_DISP_RENDER_MODE_DIRECT
The buffer(s) has to be screen sized and LVGL will render into the correct location of the buffer. This way
the buffer always contain the whole image. Only the changed ares will be updated. With 2 buffers the buffers'
content are kept in sync automatically and in flush_cb only address change is required.
enumerator LV_DISP_RENDER_MODE_FULL
Always redraw the whole screen even if only one pixel has been changed. With 2 buffers in flush_cb only and
address change is required.
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
• en -- true/false
bool lv_disp_get_antialiasing(lv_disp_t *disp)
Get if anti-aliasing is enabled for a display or not
Parameters disp -- pointer to a display (NULL to use the default display)
Returns true/false
bool lv_disp_is_double_buffered(lv_disp_t *disp)
/*Register at least one display before you register any input devices*/
lv_indev_t * indev = lv_indev_create();
lv_indev_set_type(indev, LV_INDEV_TYPE_...); /*See below.*/
lv_indev_set_read_cb(indev, read_cb); /*See below.*/
Input devices that can click points on the screen belong to this category.
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
...
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 and use 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(indev, g)
• Use LV_KEY_... to navigate among the objects in the group. See lv_core/lv_group.h for the available
keys.
lv_indev_set_type(indev, LV_INDEV_TYPE_KEYPAD);
...
Encoder
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
...
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.
lv_indev_set_type(indev, LV_INDEV_TYPE_ENCODER);
...
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.
lv_indev_set_type(indev, LV_INDEV_TYPE_BUTTON);
...
Parameters
Feedback
Besides read_cb a feedback_cb callback can be also specified in lv_indev_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
lv_indev_t *lv_indev_create(void)
struct lv_indev_data_t
#include <lv_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
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);
lv_task_handler();
mutex_unlock(&lvgl_mutex);
thread_sleep(10); /* sleep for 10 ms */
}
}
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
• void (*wait_for_finish)() Wait until all background operation are finished. (E.g. GPU operations)
• void * user_data Custom user data for arbitrary purpose
(For the sake of simplicity the parameters of the callbacks are not shown here.)
All draw_* callbacks receive a pointer to the current draw_ctx as their first parameter. Among the other parameters
there is a descriptor that tells what to draw, e.g. for draw_rect it's called lv_draw_rect_dsc_t, for lv_draw_line
it's called lv_draw_line_dsc_t, etc.
To correctly render according to a draw_dsc you need to be familiar with the Boxing model of LVGL and the meanings
of the fields. The name and meaning of the fields are identical to name and meaning of the Style properties.
Initialization
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:
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:
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:
{
if(lv_draw_mask_is_any(coords) == false && dsc->grad == NULL && dsc->bg_img_src ==␣
,→NULL &&
}
}
/*Fallback*/
else {
lv_draw_sw_rect(draw_ctx, dsc, coords);
}
}
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.
313
LVGL Documentation 9.0
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 screen.
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
Replace 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.
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 i