add the md files from the docs repo to start updating them to v8
@@ -0,0 +1,77 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/arduino.md
|
||||
```
|
||||
|
||||
# Arduino
|
||||
|
||||
The [core LVGL library](https://github.com/lvgl/lvgl) and the [examples](https://github.com/lvgl/lv_examples) are directly available as Arduino libraries.
|
||||
|
||||
Note that you need to choose a powerful enough board to run LVGL and your GUI. See the [requirements of LVGL](https://docs.lvgl.io/latest/en/html/intro/index.html#requirements).
|
||||
|
||||
For example ESP32 is a good candidate to create your UI with LVGL.
|
||||
|
||||
|
||||
## Get the LVGL Ardunio library
|
||||
|
||||
LVGL can be installed via Arduino IDE Library Manager or as an .ZIP library.
|
||||
It will also install [lv_exmaples](https://github.com/lvgl/lv_examples) which contains a lot of examples and demos to try LVGL.
|
||||
|
||||
## Set up drivers
|
||||
|
||||
To get started it's recommended to use [TFT_eSPI](https://github.com/Bodmer/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 the followings needs to be done to configure it:
|
||||
1. Go to 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`
|
||||
4. Set the resolution of your display in `LV_HOR_RES_MAX` and `LV_VER_RES_MAX`
|
||||
5. Set the color depth of you display in `LV_COLOR_DEPTH`
|
||||
6. Set `LV_TICK_CUSTOM 1`
|
||||
|
||||
## Configure the examples
|
||||
`lv_examples` can be configures similarly to LVGL but it's configuration file is called `lv_ex_conf.h`.
|
||||
1. Go to directory of the installed Arduino libraries
|
||||
2. Go to `lv_examples` and copy `lv_ex_template.h` as `lv_ex_conf.h` next to the `lv_examples` folder.
|
||||
3. Open `lv_ex_conf.h` and change the first `#if 0` to `#if 1`
|
||||
4. Enable the demos you want to use. (The small examples starting with `lv_ex_...()` are always enabled.)
|
||||
|
||||
## Initialize LVGL and run an example
|
||||
|
||||
Take a look at [LVGL_Arduino.ino](https://github.com/lvgl/lvgl/blob/master/examples/LVGL_Arduino.ino) to see how to initialize LVGL.
|
||||
It also uses TFT_eSPI as driver.
|
||||
|
||||
In the INO file you can see how to register a display and a touch pad for LVGL and call an example.
|
||||
|
||||
Note that, there is no dedicated INO file for every example but you can call functions like `lv_ex_btn1()` or `lv_ex_slider1()` to run an example.
|
||||
For the full list of examples see the [README of lv_examples](https://github.com/lvgl/lv_examples/blob/master/README.md).
|
||||
|
||||
## Debugging and logging
|
||||
|
||||
In case of trouble there are debug information inside LVGL.
|
||||
In the `LVGL_Arduino.ino` example there is `my_print` method, which allow to send this debug information to the serial interface.
|
||||
To enable this feature you have to edit `lv_conf.h` file and enable logging in section `log settings`:
|
||||
|
||||
```c
|
||||
/*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
|
||||
* LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
* LV_LOG_LEVEL_NONE Do not log anything
|
||||
*/
|
||||
# define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
```
|
||||
|
||||
After enabling log module and setting LV_LOG_LEVEL accordingly the output log is sent to the `Serial` port @ 115200 Baud rate.
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/espressif.md
|
||||
```
|
||||
|
||||
# Espressif (ESP32)
|
||||
Since v7.7.1 LVGL includes a Kconfig file, so LVGL can be used as an ESP-IDF v4 component.
|
||||
|
||||
## Get the LVGL demo project for ESP32
|
||||
|
||||
We've created [lv_port_esp32](https://github.com/lvgl/lv_port_esp32), a project using ESP-IDF and LVGL to show one of the demos from [lv_examples](https://github.com/lvgl/lv_examples).
|
||||
You are able to configure the project to use one of the many supported display controllers, see [lvgl_esp32_drivers](https://github.com/lvgl/lvgl_esp32_drivers) for a complete list
|
||||
of supported display and indev (touch) controllers.
|
||||
|
||||
## Use LVGL in your ESP32 project
|
||||
|
||||
### Prerequisites
|
||||
|
||||
ESP-IDF v4 framework is the suggested version to use.
|
||||
|
||||
### Get LVGL
|
||||
|
||||
You are suggested to add LVGL as a "component". This component can be located inside a directory named "components" on your project root directory.
|
||||
|
||||
When your project is a git repository you can include LVGL as a git submodule:
|
||||
|
||||
```c
|
||||
git submodule add https://github.com/lvgl/lvgl.git components/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.
|
||||
|
||||
When you are ready to configure LVGL launch the configuration menu with `idf.py menuconfig` on your project root directory, go to `Component config` and then `LVGL configuration`.
|
||||
|
||||
## Use lvgl_esp32_drivers in your project
|
||||
|
||||
You are suggested to add `lvgl_esp32_drivers` as a "component". This component can be located inside a directory named "components" on your project root directory.
|
||||
|
||||
When your project is a git repository you can include `lvgl_esp32_drivers` as a git submodule:
|
||||
|
||||
```c
|
||||
git submodule add https://github.com/lvgl/lvgl_esp32_drivers.git components/lvgl_esp32_drivers
|
||||
```
|
||||
|
||||
### Support for ESP32-S2
|
||||
|
||||
Basic support for ESP32-S2 has been added into the `lvgl_esp32_drivers` repository.
|
||||
@@ -0,0 +1,34 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/index.md
|
||||
```
|
||||
# Get started
|
||||
|
||||
There are several ways to get your feet wet with LVGL. This list shows the recommended way of learning the library:
|
||||
1. Check the [Online demos](https://lvgl.io/demos) to see LVGL in action (3 minutes)
|
||||
2. Read the [Introduction](https://docs.lvgl.io/latest/en/html/intro/index.html) page of the documentation (5 minutes)
|
||||
3. Read the [Quick overview](https://docs.lvgl.io/latest/en/html/get-started/quick-overview.html) page of the documentation (15 minutes)
|
||||
4. Set up a [Simulator](https://docs.lvgl.io/latest/en/html/get-started/pc-simulator.html) (10 minutes)
|
||||
5. Try out some [Examples](https://github.com/lvgl/lv_examples/)
|
||||
6. Port LVGL to a board. See the [Porting](https://docs.lvgl.io/latest/en/html/porting/index.html) guide or check the ready to use [Projects](https://github.com/lvgl?q=lv_port_&type=&language=)
|
||||
7. Read the [Overview](https://docs.lvgl.io/latest/en/html/overview/index.html) page to get a better understanding of the library. (2-3 hours)
|
||||
8. Check the documentation of the [Widgets](https://docs.lvgl.io/latest/en/html/widgets/index.html) to see their features and usage
|
||||
9. If you have questions got to the [Forum](http://forum.lvgl.io/)
|
||||
10. Read the [Contributing](https://docs.lvgl.io/latest/en/html/contributing/index.html) guide to see how you can help to improve LVGL (15 minutes)
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:hidden:
|
||||
|
||||
quick-overview
|
||||
pc-simulator
|
||||
stm32
|
||||
nxp
|
||||
espressif
|
||||
arduino
|
||||
micropython
|
||||
nuttx
|
||||
```
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/micropython.md
|
||||
```
|
||||
# Micropython
|
||||
|
||||
## What is Micropython?
|
||||
|
||||
[Micropython](http://micropython.org/) 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 commands and execute them immediately, run scripts etc.
|
||||
- **Popular** - Many platforms are supported. The user base is growing bigger. Notable forks: [MicroPython](https://github.com/micropython/micropython), [CircuitPython](https://github.com/adafruit/circuitpython), [MicroPython_ESP32_psRAM_LoBo](https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo)
|
||||
- **Embedded Oriented** - Comes with modules specifically for embedded systems, such as the [machine module](https://docs.micropython.org/en/latest/library/machine.html#classes) for accessing low-level hardware (I/O pins, ADC, UART, SPI, I2C, RTC, Timers etc.)
|
||||
|
||||
---
|
||||
|
||||
## Why Micropython + LVGL?
|
||||
|
||||
Currently, Micropython [does not have a good high-level GUI library](https://forum.micropython.org/viewtopic.php?f=18&t=5543) by default. LVGL is an [Object Oriented Component Based](https://blog.lvgl.io/2018-12-13/extend-lvgl-objects) 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.
|
||||
|
||||
### Here are some advantages of using LVGL in Micropython:
|
||||
|
||||
- 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](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (the interactive prompt)
|
||||
|
||||
### Micropython + LVGL could be used for:
|
||||
|
||||
- Fast prototyping GUI.
|
||||
- Shorten the cycle of changing and fine-tuning the GUI.
|
||||
- Model the GUI in a more abstract way by defining reusable composite objects, taking advantage of Python's language features such as Inheritance, Closures, List Comprehension, Generators, Exception Handling, Arbitrary Precision Integers and others.
|
||||
- Make LVGL accessible to a larger audience. No need to know C in order to create a nice GUI on an embedded system.
|
||||
This goes well with [CircuitPython vision](https://learn.adafruit.com/welcome-to-circuitpython/what-is-circuitpython). CircuitPython was designed with education in mind, to make it easier for new or unexperienced users to get started with embedded development.
|
||||
- Creating tools to work with LVGL at a higher level (e.g. drag-and-drop designer).
|
||||
|
||||
---
|
||||
|
||||
## So what does it look like?
|
||||
|
||||
> 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
|
||||
|
||||
```python
|
||||
import lvgl as lv
|
||||
lv.init()
|
||||
scr = lv.obj()
|
||||
btn = lv.btn(scr)
|
||||
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
|
||||
label = lv.label(btn)
|
||||
label.set_text("Button")
|
||||
lv.scr_load(scr)
|
||||
```
|
||||
|
||||
## How can I use it?
|
||||
|
||||
### 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](https://sim.lvgl.io/)
|
||||
|
||||
[Hello World](https://sim.lvgl.io/v7/micropython/ports/javascript/bundle_out/index.html?script=https://gist.githubusercontent.com/amirgon/51299ce9b6448328a855826149482ae6/raw/0f235c6d40462fd2f0e55364b874f14fe3fd613c/lvgl_hello_world.py&script_startup=https://gist.githubusercontent.com/amirgon/7bf15a66ba6d959bbf90d10f3da571be/raw/8684b5fa55318c184b1310663b187aaab5c65be6/init_lv_mp_js.py)
|
||||
|
||||
Note: the online simulator is available for lvgl v6 and v7.
|
||||
|
||||
### PC Simulator
|
||||
|
||||
Micropython is ported to many platforms. One notable port is "unix", which allows you to build and run Micropython (+LVGL) on a Linux machine. (On a Windows machine you might need Virtual Box or WSL or MinGW or Cygwin etc.)
|
||||
|
||||
[Click here to know more information about building and running the unix port](https://github.com/lvgl/lv_micropython)
|
||||
|
||||
### Embedded platform
|
||||
|
||||
At the end, the goal is to run it all on an embedded platform.
|
||||
Both Micropython and LVGL can be used on many embedded architectures, such as stm32, ESP32 etc.
|
||||
You would also need display and input drivers. We have some sample drivers (ESP32+ILI9341, as well as some other examples), but most chances are you would want to create your own input/display drivers for your specific purposes.
|
||||
Drivers can be implemented either in C as Micropython module, or in pure Micropython!
|
||||
|
||||
## Where can I find more information?
|
||||
|
||||
- On the [Blog Post](https://blog.lvgl.io/2019-02-20/micropython-bindings)
|
||||
- On `lv_micropython` [README](https://github.com/lvgl/lv_micropython)
|
||||
- On `lv_binding_micropython` [README](https://github.com/lvgl/lv_binding_micropython)
|
||||
- On LVGL forum (Feel free to ask anything!)
|
||||
- On Micropython [docs](http://docs.micropython.org/en/latest/) and [forum](https://forum.micropython.org/)
|
||||
@@ -0,0 +1,101 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/nuttx.md
|
||||
```
|
||||
# NuttX RTOS
|
||||
|
||||
## What is NuttX?
|
||||
|
||||
[NuttX](https://nuttx.apache.org/) 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 microcontroller and microprocessors. Complaint 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 thinking about a small Unix/Linux for microcontrollers.
|
||||
|
||||
### Highlights of NuttX
|
||||
|
||||
- **Small** - Fits and runs within small microcontroller as small was 32KB Flash and 8KB of RAM.
|
||||
- **Compliant** - Strives to be as compatible as possible with POSIX and Linux.
|
||||
- **Versatile** - Supports many architectures (ARM, ARM Thumb, AVR, MIPS, OpenRISC, RISC-V 32-bit and 64-bit, RX65N, x86-64, Xtensa, Z80/Z180, etc).
|
||||
- **Modular** - Its modular design allow developers to select only what really matters and use modules to include new features.
|
||||
- **Popular** - NuttX is used by many companies around the world. Probably you already used a product with NuttX without knowing it was running NuttX.
|
||||
- **Predictable** - NuttX is a preemptible Realtime kernel, then you can use it to create predictable applications for realtime control.
|
||||
|
||||
---
|
||||
|
||||
## Why NuttX + LVGL?
|
||||
|
||||
Although NuttX has its own graphic library called [NX](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=139629474), LVGL is a good alternative because users could find more eyes-candy demos and reuse it from previous projects.
|
||||
LVGL is an [Object Oriented Component Based](https://blog.lvgl.io/2018-12-13/extend-lvgl-objects) 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.
|
||||
|
||||
### Here are some advantages of using LVGL in NuttX
|
||||
|
||||
- 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.
|
||||
|
||||
### NuttX + LVGL could be used for
|
||||
|
||||
- GUI demos to demonstrate your board graphics capacities.
|
||||
- Fast prototyping GUI for MVP (Minimum Viable Product) presentation.
|
||||
- Easy way to visualize sensors data directly on the board without using a computer.
|
||||
- Final products GUI without touchscreen (i.e. 3D Printer Interface using Rotary Encoder to Input data).
|
||||
- Final products interface with touchscren (and bells and whistles).
|
||||
|
||||
---
|
||||
|
||||
## How to get started with NuttX and LVGL?
|
||||
|
||||
There are many boards in the NuttX mainline (https://github.com/apache/incubator-nuttx) with support for LVGL.
|
||||
Let's to use the [STM32F429IDISCOVERY](https://www.st.com/en/evaluation-tools/32f429idiscovery.html) as example because it is a very popular board.
|
||||
|
||||
### First you need to install the pre-requisite on your system
|
||||
|
||||
Let's to use Linux and example, for [Windows](https://acassis.wordpress.com/2018/01/10/how-to-build-nuttx-on-windows-10/)
|
||||
|
||||
```shell
|
||||
$ sudo apt-get install automake bison build-essential flex gcc-arm-none-eabi gperf git libncurses5-dev libtool libusb-dev libusb-1.0.0-dev pkg-config kconfig-frontends openocd
|
||||
```
|
||||
|
||||
### Now let's to create a workspace to save our files
|
||||
|
||||
```shell
|
||||
$ mkdir ~/nuttxspace
|
||||
$ cd ~/nuttxspace
|
||||
```
|
||||
|
||||
### Clone the NuttX and Apps repositories:
|
||||
|
||||
```shell
|
||||
$ git clone https://github.com/apache/incubator-nuttx nuttx
|
||||
$ git clone https://github.com/apache/incubator-nuttx-apps apps
|
||||
```
|
||||
|
||||
### Configure NuttX to use the stm32f429i-disco board and the LVGL Demo
|
||||
|
||||
```shell
|
||||
$ ./tools/configure.sh stm32f429i-disco:lvgl
|
||||
$ make
|
||||
```
|
||||
|
||||
If everything went fine you should have now the file `nuttx.bin` to flash on your board:
|
||||
|
||||
```shell
|
||||
$ ls -l nuttx.bin
|
||||
-rwxrwxr-x 1 alan alan 287144 Jun 27 09:26 nuttx.bin
|
||||
```
|
||||
|
||||
### Flashing the firmware in the board using OpenOCD:
|
||||
```shell
|
||||
$ sudo openocd -f interface/stlink-v2.cfg -f target/stm32f4x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"
|
||||
```
|
||||
|
||||
Reset the board and using the 'NSH>' terminal start the LVGL demo:
|
||||
```shell
|
||||
nsh> lvgldemo
|
||||
```
|
||||
|
||||
## Where can I find more information?
|
||||
|
||||
- On the [LVGL on LPCXpresso54628](https://acassis.wordpress.com/2018/07/19/running-nuttx-on-lpcxpresso54628-om13098/)
|
||||
- NuttX mailing list [Apache NuttX Mailing List](http://nuttx.incubator.apache.org/community/)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/nxp.md
|
||||
```
|
||||
# NXP
|
||||
NXP has integrated LVGL into the MCUXpresso SDK packages for several of their general
|
||||
purpose and crossover microcontrollers, allowing easy evaluation and migration into your
|
||||
product design. [Download an SDK for a supported board](https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
|
||||
today and get started with your next GUI application.
|
||||
|
||||
## Creating new project with LVGL
|
||||
Downloading the MCU SDK example project is recommended as a starting point. It comes fully
|
||||
configured with LVGL (and with PXP support if module is present), no additional integration
|
||||
work is required.
|
||||
|
||||
## Adding HW acceleration for NXP iMX RT platforms using PXP (PiXel Pipeline) engine for existing projects
|
||||
Several drawing features in LVGL can be offloaded to PXP engine. In order to use CPU time while PXP
|
||||
is running, RTOS is required to block the LVGL drawing thread and switch to another task, or simply to
|
||||
idle task, where CPU could be suspended to save power.
|
||||
|
||||
#### Features supported:
|
||||
- RGB565 color format
|
||||
- Area fill + optional transparency
|
||||
- BLIT (BLock Image Transfer) + optional transparency
|
||||
- Color keying + optional transparency
|
||||
- Recoloring (color tint) + optional transparency
|
||||
- RTOS integration layer
|
||||
- Default FreeRTOS and bare metal code provided
|
||||
|
||||
#### Basic configuration:
|
||||
- Select NXP PXP engine in lv_conf.h: Set `LV_USE_GPU_NXP_PXP` to 1
|
||||
- Enable default implementation for interrupt handling, PXP start function and automatic initialization: Set `LV_USE_GPU_NXP_PXP_AUTO_INIT` to 1
|
||||
- If `FSL_RTOS_FREE_RTOS` symbol is defined, FreeRTOS implementation will be used, otherwise bare metal code will be included
|
||||
|
||||
#### Basic initialization:
|
||||
- If `LV_USE_GPU_NXP_PXP_AUTO_INIT` is enabled, no user code is required; PXP is initialized automatically in `lv_init()`
|
||||
- For manual PXP initialization, default configuration structure for callbacks can be used. Initialize PXP before calling `lv_init()`
|
||||
```c
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
#include "lv_gpu/lv_gpu_nxp_pxp.h"
|
||||
#include "lv_gpu/lv_gpu_nxp_pxp_osa.h"
|
||||
#endif
|
||||
. . .
|
||||
#if LV_USE_GPU_NXP_PXP
|
||||
if (lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) {
|
||||
PRINTF("PXP init error. STOP.\n");
|
||||
for ( ; ; ) ;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
#### Project setup:
|
||||
- Add PXP related files to project:
|
||||
- lv_gpu/lv_gpu_nxp.c, lv_gpu/lv_gpu_nxp.h: low level drawing calls for LVGL
|
||||
- lv_gpu/lv_gpu_nxp_osa.c, lv_gpu/lv_gpu_osa.h: default implementation of OS-specific functions (bare metal and FreeRTOS only)
|
||||
- optional, required only if `LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to 1
|
||||
- PXP related code depends on two drivers provided by MCU SDK. These drivers need to be added to project:
|
||||
- fsl_pxp.c, fsl_pxp.h: PXP driver
|
||||
- fsl_cache.c, fsl_cache.h: CPU cache handling functions
|
||||
|
||||
#### Advanced configuration:
|
||||
- Implementation depends on multiple OS-specific functions. Structure `lv_nxp_pxp_cfg_t` with callback pointers is used
|
||||
as a parameter for `lv_gpu_nxp_pxp_init()` function. Default implementation for FreeRTOS and baremetal is provided in lv_gpu_nxp_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.
|
||||
- There are configurable area thresholds which are used to decide whether the area will be processed by CPU, or by PXP. Areas smaller than
|
||||
defined value will be processed by CPU, areas bigger than the threshold will be processed by PXP. These thresholds may be defined as a
|
||||
preprocessor variables. Default values are defined lv_gpu/lv_gpu_nxp_pxp.h
|
||||
- `GPU_NXP_PXP_BLIT_SIZE_LIMIT`: size threshold for image BLIT, BLIT with color keying, and BLIT with recolor (OPA > LV_OPA_MAX)
|
||||
- `GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT`: size threshold for image BLIT and BLIT with color keying with transparency (OPA < LV_OPA_MAX)
|
||||
- `GPU_NXP_PXP_FILL_SIZE_LIMIT`: size threshold for fill operation (OPA > LV_OPA_MAX)
|
||||
- `GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT`: size threshold for fill operation with transparency (OPA < LV_OPA_MAX)
|
||||
@@ -0,0 +1,98 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/pc-simulator.md
|
||||
```
|
||||
# Simulator on PC
|
||||
|
||||
|
||||
You can try out the LVGL **using only your PC** (i.e. without any development boards). The LVGL will run on a simulator environment on the PC where anyone can write and experiment the real LVGL applications.
|
||||
|
||||
Simulator on the PC have the following advantages:
|
||||
- Hardware independent - Write a code, run it on the PC and see the result on the PC monitor.
|
||||
- Cross-platform - Any Windows, Linux or OSX PC can run the PC simulator.
|
||||
- Portability - the written code is portable, which means you can simply copy it when using an embedded hardware.
|
||||
- Easy Validation - The simulator is also very useful to report bugs because it means common platform for every user. So it's a good idea to reproduce a bug in simulator and use the code snippet in the [Forum](https://forum.lvgl.io).
|
||||
|
||||
## 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](https://github.com/lvgl/lv_sim_eclipse_sdl): Recommended on Linux and Mac
|
||||
- [CodeBlocks](https://github.com/lvgl/lv_sim_codeblocks_win): Recommended on Windows
|
||||
- [VisualStudio with SDL driver](https://github.com/lvgl/lv_sim_visual_studio_sdl): For Windows
|
||||
- [VSCode with SDL driver](https://github.com/lvgl/lv_sim_vscode_sdl): Recommended on Linux and Mac
|
||||
- [PlatformIO with SDL driver](https://github.com/lvgl/lv_platformio): Recommended on Linux and Mac
|
||||
|
||||
You can use any IDEs for the development but, for simplicity, the configuration for Eclipse CDT is focused in this tutorial.
|
||||
The following section describes the set-up guide of Eclipse CDT in more details.
|
||||
|
||||
**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.**
|
||||
|
||||
## Set-up Eclipse CDT
|
||||
|
||||
### Install Eclipse CDT
|
||||
|
||||
[Eclipse CDT](https://eclipse.org/cdt/) is a C/C++ IDE.
|
||||
|
||||
Eclipse is a Java based software therefore be sure **Java Runtime Environment** is installed on your system.
|
||||
|
||||
On Debian-based distros (e.g. Ubuntu): `sudo apt-get install default-jre`
|
||||
|
||||
Note: If you are using other distros, then please refer and install 'Java Runtime Environment' suitable to your distro.
|
||||
Note: If you are using macOS and get a "Failed to create the Java Virtual Machine" error, uninstall any other Java JDK installs and install Java JDK 8u. This should fix the problem.
|
||||
|
||||
You can download Eclipse's CDT from: [https://www.eclipse.org/cdt/downloads.php](https://www.eclipse.org/cdt/downloads.php). Start the installer and choose *Eclipse CDT* from the list.
|
||||
|
||||
### Install SDL 2
|
||||
|
||||
The PC simulator uses the [SDL 2](https://www.libsdl.org/download-2.0.php) cross platform library to simulate a TFT display and a touch pad.
|
||||
|
||||
#### Linux
|
||||
On **Linux** you can easily install SDL2 using a terminal:
|
||||
|
||||
1. Find the current version of SDL2: `apt-cache search libsdl2 (e.g. libsdl2-2.0-0)`
|
||||
2. Install SDL2: `sudo apt-get install libsdl2-2.0-0` (replace with the found version)
|
||||
3. Install SDL2 development package: `sudo apt-get install libsdl2-dev`
|
||||
4. If build essentials are not installed yet: `sudo apt-get install build-essential`
|
||||
|
||||
#### Windows
|
||||
If you are using **Windows** firstly you need to install MinGW ([64 bit version](http://mingw-w64.org/doku.php/download)). 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](https://www.libsdl.org/download-2.0.php) and download _Development 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_worksapce}/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](http://lazyfoo.net/tutorials/SDL/01_hello_SDL/index.php) 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](https://github.com/lvgl/lv_sim_eclipse_sdl).
|
||||
(Please note that, the project is configured for Eclipse CDT).
|
||||
|
||||
### Add the pre-configured project to 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)
|
||||
|
||||
### Compile and Run
|
||||
|
||||
Now you are ready to run the LVGL Graphics Library 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 of cases the configurations in the downloaded project is enough.
|
||||
|
||||
After a success 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 everything is ready to use the LVGL in the practice or begin the development on your PC.
|
||||
@@ -0,0 +1,219 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/quick-overview.md
|
||||
```
|
||||
|
||||
# Quick overview
|
||||
|
||||
Here you can learn the most important things about LVGL.
|
||||
You should read it first to get a general impression and read the detailed [Porting](/porting/index) and [Overview](/overview/index) sections after that.
|
||||
|
||||
## Get started in a simulator
|
||||
|
||||
Instead of porting LVGL to an embedded hardware, it's highly recommended to get started in a simulator first.
|
||||
|
||||
LVGL is ported to many IDEs to be sure you will find your faviourite one. Go to [Simulators](/get-started/pc-simulator) to get ready-to-use projects which can be run on your PC. This way you can save the porting for now and make some experience with LVGL immediately.
|
||||
|
||||
## Add LVGL into your project
|
||||
|
||||
The following steps show how to setup LVGL on an embedded system with a display and a touchpad.
|
||||
|
||||
- [Download](https://github.com/lvgl/lvgl/archive/master.zip) 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 at least `LV_HOR_RES_MAX`, `LV_VER_RES_MAX` and `LV_COLOR_DEPTH` defines.
|
||||
- Include `lvgl/lvgl.h` 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 display buffer for LVGL. LVGL will render the graphics here first, and seed the rendered image to the display. The buffer size can be set freely but 1/10 screen size is a good starting point.
|
||||
```c
|
||||
static lv_disp_buf_t disp_buf;
|
||||
static lv_color_t buf[LV_HOR_RES_MAX * LV_VER_RES_MAX / 10]; /*Declare a buffer for 1/10 screen size*/
|
||||
lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX / 10); /*Initialize the display buffer*/
|
||||
```
|
||||
- Implement and register a function which can **copy the rendered image** to an area of your display:
|
||||
```c
|
||||
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/
|
||||
disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/
|
||||
lv_disp_drv_register(&disp_drv); /*Finally register the driver*/
|
||||
|
||||
void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
|
||||
{
|
||||
int32_t x, y;
|
||||
for(y = area->y1; y <= area->y2; y++) {
|
||||
for(x = area->x1; x <= area->x2; x++) {
|
||||
set_pixel(x, y, *color_p); /* Put a pixel to the display.*/
|
||||
color_p++;
|
||||
}
|
||||
}
|
||||
|
||||
lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/
|
||||
}
|
||||
|
||||
```
|
||||
- Implement and register a function which can **read an input device**. E.g. for a touch pad:
|
||||
```c
|
||||
lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
|
||||
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
|
||||
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
|
||||
lv_indev_drv_register(&indev_drv); /*Finally register the driver*/
|
||||
|
||||
bool my_touchpad_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
{
|
||||
data->state = touchpad_is_pressed() ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
|
||||
if(data->state == LV_INDEV_STATE_PR) touchpad_get_xy(&data->point.x, &data->point.y);
|
||||
|
||||
return false; /*Return `false` because we are not buffering and no more data to read*/
|
||||
}
|
||||
```
|
||||
- Call `lv_task_handler()` periodically every few milliseconds in the main `while(1)` loop, in Timer interrupt or in an Operation system task.
|
||||
It will redraw the screen if required, handle input devices etc.
|
||||
|
||||
For a more detailed guide go to the [Porting](https://docs.lvgl.io/v7/en/html/porting/index.html) section.
|
||||
|
||||
## Learn the basics
|
||||
|
||||
### Widgets
|
||||
|
||||
The graphical elements like Buttons, Labels, Sliders, Charts etc are called objects or widgets in LVGL. Go to [Widgets](/widgets/index) to see the full list of available widgets.
|
||||
|
||||
Every object has a parent object where it is create. 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 on their parent. It other words, the parts of the children out of 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, obj_to_copy)`. It will return an `lv_obj_t *` variable which should be used as a reference to the object to set its parameters.
|
||||
The first parameter is the desired *parent*, the second parameters can be an object to copy (`NULL` if unused).
|
||||
For example:
|
||||
```c
|
||||
lv_obj_t * slider1 = lv_slider_create(lv_scr_act(), NULL);
|
||||
```
|
||||
|
||||
To set some basic attribute `lv_obj_set_<paramters_name>(obj, <value>)` function can be used. For example:
|
||||
```c
|
||||
lv_obj_set_x(btn1, 30);
|
||||
lv_obj_set_y(btn1, 10);
|
||||
lv_obj_set_size(btn1, 200, 50);
|
||||
```
|
||||
|
||||
The objects has type specific parameters too which can be set by `lv_<type>_set_<paramters_name>(obj, <value>)` functions. For example:
|
||||
```c
|
||||
lv_slider_set_value(slider1, 70, LV_ANIM_ON);
|
||||
```
|
||||
|
||||
To see the full API visit the documentation of the widgets or the related header file (e.g. [lvgl/src/lv_widgets/lv_slider.h](https://github.com/lvgl/lvgl/blob/master/src/lv_widgets/lv_slider.h)).
|
||||
|
||||
### Events
|
||||
Events are used to inform the user if something has happened with an object. You can assign a callback to an object which will be called if the object is clicked, released, dragged, being deleted etc. It should look like this:
|
||||
|
||||
```c
|
||||
lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/
|
||||
|
||||
...
|
||||
|
||||
void btn_event_cb(lv_obj_t * btn, lv_event_t event)
|
||||
{
|
||||
if(event == LV_EVENT_CLICKED) {
|
||||
printf("Clicked\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about the events in the [Event overview](/overview/event) section.
|
||||
|
||||
### Parts
|
||||
Widgets might be built from one or more parts. For example a button has only one part called `LV_BTN_PART_MAIN`.
|
||||
However, a [Page](/widgets/page) has `LV_PAGE_PART_BG`, `LV_PAGE_PART_SCROLLABLE`, `LV_PAGE_PART_SCROLLBAR` and `LV_PAGE_PART_EDGE_FLASG`.
|
||||
|
||||
Some parts are *virtual* (they are not real object, just drawn on the fly, such as the scrollbar of a page) but other parts are *real* (they are real object, such as the scrollable part of the page).
|
||||
|
||||
Parts come into play when you want to set the styles and states of a given part of an object. (See below)
|
||||
|
||||
### States
|
||||
The objects can be in a combination of the following states:
|
||||
- **LV_STATE_DEFAULT** Normal, released
|
||||
- **LV_STATE_CHECKED** Toggled or checked
|
||||
- **LV_STATE_FOCUSED** Focused via keypad or encoder or clicked via touchpad/mouse
|
||||
- **LV_STATE_EDITED** Edit by an encoder
|
||||
- **LV_STATE_HOVERED** Hovered by mouse (not supported now)
|
||||
- **LV_STATE_PRESSED** Pressed
|
||||
- **LV_STATE_DISABLED** Disabled or inactive
|
||||
|
||||
For example, if you press an object it will automatically get the `LV_STATE_PRESSED` state and when you release it, the state will be removed.
|
||||
|
||||
To get the current state use `lv_obj_get_state(obj, part)`. It will return the `OR`ed states.
|
||||
For example, this is a valid state for a checkbox: `LV_STATE_CHECKED | LV_STATE_PRESSED | LV_STATE_FOCUSED`
|
||||
|
||||
### Styles
|
||||
Styles can be assigned to the parts of an object to change their appearance.
|
||||
A style can describe for example the background color, border width, text font and so on. See the full list [here](https://docs.lvgl.io/v7/en/html/overview/style.html#properties).
|
||||
|
||||
The 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 some properties to make the button red-
|
||||
|
||||
Every style property you set is specific to a state. For example, you can set a different background color for `LV_STATE_DEFAULT` and `LV_STATE_PRESSED`.
|
||||
The library finds the best match between the state of the given part and the available style properties. For example if the object is in pressed state and the border width is specified for pressed state, then it will be used.
|
||||
However, if it's not specified for pressed state, the `LV_STATE_DEFAULT`'s border width will be used. If the border width not defined for `LV_STATE_DEFAULT` either, a default value will be used.
|
||||
|
||||
Some properties (typically the text-related ones) can be inherited. It means if a property is not set in an object it will be searched in its parents too.
|
||||
For example you can set the font once in the screen's style and every text will inherit it by default.
|
||||
|
||||
Local style properties also can be added to the objects.
|
||||
|
||||
### Themes
|
||||
Themes are the default styles of the objects.
|
||||
The styles from the themes are applied automatically when the objects are created.
|
||||
|
||||
You can select the theme to use in `lv_conf.h`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Button with label
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_1.*
|
||||
:alt: Simple button with label with LVGL
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_1.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
|
||||
### Styling buttons
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_2.*
|
||||
:alt: Styling buttons with LVGL
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_2.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
|
||||
### Slider and alignment
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_3.*
|
||||
:alt: Create a slider with LVGL
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_3.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
## Micropython
|
||||
Learn more about [Micropython](/get-started/micropython).
|
||||
```python
|
||||
# Create a Button and a Label
|
||||
scr = lv.obj()
|
||||
btn = lv.btn(scr)
|
||||
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
|
||||
label = lv.label(btn)
|
||||
label.set_text("Button")
|
||||
|
||||
# Load the screen
|
||||
lv.scr_load(scr)
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/get-started/stm32.md
|
||||
```
|
||||
|
||||
# STM32
|
||||
|
||||
TODO
|
||||
@@ -0,0 +1,222 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/intro/index.md
|
||||
```
|
||||
|
||||
# Introduction
|
||||
|
||||
LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint.
|
||||
|
||||
|
||||
## Key features
|
||||
- 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 more TFT, monochrome displays simultaneously
|
||||
- Fully customizable graphic elements
|
||||
- Hardware independent to use with any microcontroller or display
|
||||
- Scalable to operate with little memory (64 kB Flash, 16 kB RAM)
|
||||
- OS, External memory and GPU supported but not required
|
||||
- Single frame buffer operation even with advanced graphical 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 as online and offline
|
||||
- Free and open-source under MIT license
|
||||
|
||||
## Requirements
|
||||
Basically, every modern controller (which is able to drive a display) is suitable to run LVGL. The minimal requirements are:
|
||||
<ul>
|
||||
<li> 16, 32 or 64 bit microcontroller or processor</li>
|
||||
<li>> 16 MHz clock speed is recommended</li>
|
||||
<li> Flash/ROM: > 64 kB for the very essential components (> 180 kB is recommended)</li>
|
||||
<li> RAM:
|
||||
<ul>
|
||||
<li> Static RAM usage: ~2 kB depending on the used features and objects types</li>
|
||||
<li> Stack: > 2kB (> 8 kB is recommended)</li>
|
||||
<li> Dynamic data (heap): > 2 KB (> 16 kB is recommended if using several objects).
|
||||
Set by <em>LV_MEM_SIZE</em> in <em>lv_conf.h</em>. </li>
|
||||
<li> Display buffer: > <em>"Horizontal resolution"</em> pixels (> 10 × <em>"Horizontal resolution"</em> is recommended) </li>
|
||||
<li> One frame buffer in the MCU or in external display controller</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li> C99 or newer compiler</li>
|
||||
<li> Basic C (or C++) knowledge:
|
||||
<a href="https://www.tutorialspoint.com/cprogramming/c_pointers.htm">pointers</a>,
|
||||
<a href="https://www.tutorialspoint.com/cprogramming/c_structures.htm">structs</a>,
|
||||
<a href="https://www.geeksforgeeks.org/callbacks-in-c/">callbacks</a></li>
|
||||
</ul>
|
||||
<em>Note that the memory usage might vary depending on the architecture, compiler and build options.</em>
|
||||
|
||||
## License
|
||||
The LVGL project (including all repositories) is licensed under [MIT license](https://github.com/lvgl/lvgl/blob/master/LICENCE.txt).
|
||||
It 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](https://forum.lvgl.io/c/my-projects/10) category of the Forum or a private message from [lvgl.io](https://lvgl.io/#contact).
|
||||
|
||||
Although you can get LVGL for free there is a huge 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](/contributing/index) to the project.
|
||||
You can choose from [many ways of contributions](/contributing/index) such as simply writing a tweet about you are using LVGL, fixing bugs, translating the documentation, or even becoming a maintainer.
|
||||
|
||||
## Repository layout
|
||||
All repositories of the LVGL project are hosted n GitHub: https://github.com/lvgl
|
||||
|
||||
You fill these repositories there:
|
||||
- [lvgl](https://github.com/lvgl/lvgl) The library itself
|
||||
- [lv_examples](https://github.com/lvgl/lv_examples) Examples and demos
|
||||
- [lv_drivers](https://github.com/lvgl/lv_drivers) Display and input device drivers
|
||||
- [docs](https://github.com/lvgl/docs) Source of the documentation's site (https://docs.lvgl.io)
|
||||
- [blog](https://github.com/lvgl/blog) Source of the blog's site (https://blog.lvgl.io)
|
||||
- [sim](https://github.com/lvgl/sim) Source of the online simulator's site (https://sim.lvgl.io)
|
||||
- [lv_sim_...](https://github.com/lvgl?q=lv_sim&type=&language=) Simulator projects for various IDEs and platforms
|
||||
- [lv_port_...](https://github.com/lvgl?q=lv_port&type=&language=) LVGL ports to development boards
|
||||
- [lv_binding_..](https://github.com/lvgl?q=lv_binding&type=&language=l) Bindings to other languages
|
||||
- [lv_...](https://github.com/lvgl?q=lv_&type=&language=) Ports to other platforms
|
||||
|
||||
The [lvgl](https://github.com/lvgl/lvgl), [lv_examples](https://github.com/lvgl/lv_examples) and [lv_drivers](https://github.com/lvgl/lv_drivers) are the core repositories which gets the most attentions regarding maintenance.
|
||||
|
||||
## Release policy
|
||||
|
||||
The core repositories follow the rules of [Semantic versioning](https://semver.org/):
|
||||
- Major versions for incompatible API changes. E.g. v5.0.0, v6.0.0
|
||||
- Minor version for new but backward-compatible functionalities. E.g. v6.1.0, v6.2.0
|
||||
- Patch version for backward-compatible bug fixes. E.g. v6.1.1, v6.1.2
|
||||
|
||||
### Branches
|
||||
The core repositories have at least the following branches:
|
||||
- `master` latest version, patches are merged directly here.
|
||||
- `dev` merge new features here until they are merged into `master`.
|
||||
- `release/vX` stable versions of the major releases
|
||||
|
||||
### Release cycle
|
||||
|
||||
LVGL has 2 weeks release cycle. On every first and third Tuesday of a month:
|
||||
1. A major, minor or bug fix release is created (based on the new features) from the `master` branch
|
||||
2. `master` is merged into `release/vX`
|
||||
3. Immediately after the release `dev` is merged into `master`
|
||||
4. In the upcoming 2 weeks the new features in `master` can be tested
|
||||
5. Bug fixes are merged directly into `master`
|
||||
6. After 2 weeks start again from the first point
|
||||
|
||||
### Tags
|
||||
|
||||
Tags like `vX.Y.Z` are created for every release.
|
||||
|
||||
### Changelog
|
||||
|
||||
The changes are recorded in [CHANGELOG.md](https://github.com/lvgl/lvgl/blob/master/CHANGELOG.md).
|
||||
|
||||
### Side projects
|
||||
The [docs](https://github.com/lvgl/docs) is rebuilt on every release. By default, the `latest` documentation is displayed which is for the current `master` branch of lvgl.
|
||||
The documentation of earlier versions is available from the menu on the left.
|
||||
|
||||
The simulator, porting, and other projects are updated with best effort. Pull requests are welcome if you updated one of them.
|
||||
|
||||
### Version support
|
||||
In the core repositories each major version has a branch (e.g. `release/v6`). All the minor and patch releases of that major version are merged there.
|
||||
|
||||
It makes possible to add fixed older versions without bothering the newer ones.
|
||||
|
||||
All major versions are officially supported for 1 year.
|
||||
|
||||
|
||||
## FAQ
|
||||
|
||||
### Where can I ask questions?
|
||||
You can ask questions in the Forum: [https://forum.lvgl.io/](https://forum.lvgl.io/).
|
||||
|
||||
We use [GitHub issues](https://github.com/lvgl/lvgl/issues) for development related discussion.
|
||||
So you should use them only if your question or issue is tightly related to the development of the library.
|
||||
|
||||
### Is my MCU/hardware supported?
|
||||
Every MCU which is capable of driving a display via Parallel port, SPI, RGB interface or anything else and fulfills the [Requirements](#requirements) is supported by LLVGL.
|
||||
|
||||
It includes:
|
||||
- "Common" MCUs like STM32F, STM32H, NXP Kinetis, LPC, iMX, dsPIC33, PIC32 etc.
|
||||
- Bluetooth, GSM, WiFi modules like Nordic NRF and Espressif ESP32
|
||||
- Linux frame buffer like /dev/fb0 which includes Single-board computers too like Raspberry Pi
|
||||
- And anything else with a strong enough MCU and a periphery to drive a display
|
||||
|
||||
### Is my display supported?
|
||||
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 that display with LVGL.
|
||||
|
||||
Some examples of the supported display types:
|
||||
- TFTs with 16 or 24 bit color depth
|
||||
- Monitors with 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](/porting/display) section to learn more.
|
||||
|
||||
### Nothing happens, my display driver is not called. What have I missed?
|
||||
Be sure you are calling `lv_tick_inc(x)` in an interrupt and `lv_task_handler()` in your main `while(1)`.
|
||||
|
||||
Learn more in the [Tick](/porting/tick) and [Task handler](/porting/task-handler) section.
|
||||
|
||||
### Why the display driver is 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*".
|
||||
|
||||
### Why I see only garbage on the screen?
|
||||
Probably there a bug in your display driver. Try the following code without using LVGL. You should see a square with red-blue gradient
|
||||
|
||||
```c
|
||||
#define BUF_W 20
|
||||
#define BUF_H 10
|
||||
|
||||
lv_color_t buf[BUF_W * BUF_H];
|
||||
lv_color_t * buf_p = buf;
|
||||
uint16_t x, y;
|
||||
for(y = 0; y < BUF_H; y++) {
|
||||
lv_color_t c = lv_color_mix(LV_COLOR_BLUE, LV_COLOR_RED, (y * 255) / BUF_H);
|
||||
for(x = 0; x < BUF_W; x++){
|
||||
(*buf_p) = c;
|
||||
buf_p++;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
```
|
||||
|
||||
### Why I see non-sense colors on the screen?
|
||||
Probably LVGL's color format is not compatible with your displays color format. Check `LV_COLOR_DEPTH` in *lv_conf.h*.
|
||||
|
||||
If you are using 16 bit colors with SPI (or other byte-oriented interface) probably you need to set `LV_COLOR_16_SWAP 1` in *lv_conf.h*.
|
||||
It swaps the upper and lower bytes of the pixels.
|
||||
|
||||
### How to speed up my UI?
|
||||
- Turn on compiler optimization and enable cache if your MCU has
|
||||
- Increase the size of the display buffer
|
||||
- Use 2 display buffers and flush the buffer with DMA (or similar periphery) in the background
|
||||
- Increase the clock speed of the SPI or Parallel port if you use them to drive the display
|
||||
- If your display has SPI port consider changing to a model with parallel because it has much higher throughput
|
||||
- Keep the display buffer in the internal RAM (not in external SRAM) because LVGL uses it a lot and it should have a small access time
|
||||
|
||||
### How to reduce flash/ROM usage?
|
||||
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 you can add
|
||||
- `-fdata-sections -ffunction-sections` compiler flags
|
||||
- `--gc-sections` linker flag
|
||||
|
||||
to remove unused functions and variables from the final binary
|
||||
|
||||
### How to reduce the RAM usage
|
||||
- Lower the size of the *Display buffer*
|
||||
- Reduce `LV_MEM_SIZE` in *lv_conf.h*. This memory used when you create objects like buttons, labels, etc.
|
||||
- To work with lower `LV_MEM_SIZE` you can create the objects only when required and deleted them when they are not required anymore
|
||||
|
||||
### How to work with an operating system?
|
||||
|
||||
To work with an operating system where tasks can interrupt each other (preemptive) you should protect LVGL related function calls with a mutex.
|
||||
See the [Operating system and interrupts](/porting/os) section to learn more.
|
||||
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 973 B |
|
After Width: | Height: | Size: 993 B |
|
After Width: | Height: | Size: 990 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,126 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/animation.md
|
||||
```
|
||||
# Animations
|
||||
|
||||
You can automatically change the value of a variable between a start and an end value using animations.
|
||||
The animation will happen by the periodical call of an "animator" function with the corresponding value parameter.
|
||||
|
||||
The *animator* functions has the following prototype:
|
||||
```c
|
||||
void func(void * var, lv_anim_var_t value);
|
||||
```
|
||||
This prototype is compatible with the majority of the *set* function of LVGL. For example `lv_obj_set_x(obj, value)` or `lv_obj_set_width(obj, value)`
|
||||
|
||||
|
||||
## Create an animation
|
||||
To create an animation an `lv_anim_t` variable has to be initialized and configured with `lv_anim_set_...()` functions.
|
||||
|
||||
```c
|
||||
|
||||
/* INITIALIZE AN ANIMATION
|
||||
*-----------------------*/
|
||||
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
|
||||
/* MANDATORY SETTINGS
|
||||
*------------------*/
|
||||
|
||||
/*Set the "animator" function*/
|
||||
lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t) lv_obj_set_x);
|
||||
|
||||
/*Set the "animator" function*/
|
||||
lv_anim_set_var(&a, obj);
|
||||
|
||||
/*Length of the animation [ms]*/
|
||||
lv_anim_set_time(&a, duration);
|
||||
|
||||
/*Set start and end values. E.g. 0, 150*/
|
||||
lv_anim_set_values(&a, start, end);
|
||||
|
||||
/* OPTIONAL SETTINGS
|
||||
*------------------*/
|
||||
|
||||
/*Time to wait before starting the animation [ms]*/
|
||||
lv_anim_set_delay(&a, delay);
|
||||
|
||||
/*Set path (curve). Default is linear*/
|
||||
lv_anim_set_path(&a, &path);
|
||||
|
||||
/*Set a callback to call when animation is ready.*/
|
||||
lv_anim_set_ready_cb(&a, ready_cb);
|
||||
|
||||
/*Set a callback to call when animation is started (after delay).*/
|
||||
lv_anim_set_start_cb(&a, start_cb);
|
||||
|
||||
/*Play the animation backward too with this duration. Default is 0 (disabled) [ms]*/
|
||||
lv_anim_set_playback_time(&a, wait_time);
|
||||
|
||||
/*Delay before playback. Default is 0 (disabled) [ms]*/
|
||||
lv_anim_set_playback_delay(&a, wait_time);
|
||||
|
||||
/*Number of repetitions. Default is 1. LV_ANIM_REPEAT_INFINIT for infinite repetition*/
|
||||
lv_anim_set_repeat_count(&a, wait_time);
|
||||
|
||||
/*Delay before repeat. Default is 0 (disabled) [ms]*/
|
||||
lv_anim_set_repeat_delay(&a, wait_time);
|
||||
|
||||
/*true (default): apply the start vale immediately, false: apply start vale after delay when then anim. really starts. */
|
||||
lv_anim_set_early_apply(&a, true/false);
|
||||
|
||||
/* START THE ANIMATION
|
||||
*------------------*/
|
||||
lv_anim_start(&a); /*Start the animation*/
|
||||
```
|
||||
|
||||
|
||||
You can apply **multiple different animations** on the same variable at the same time.
|
||||
For example, animate the x and y coordinates with `lv_obj_set_x` and `lv_obj_set_y`. However, only one animation can exist with a given variable and function pair.
|
||||
Therefore `lv_anim_start()` will delete the already existing variable-function animations.
|
||||
|
||||
## Animation path
|
||||
|
||||
You can determinate the **path of animation**. In the most simple case, it is linear, which means the current value between *start* and *end* is changed linearly.
|
||||
A *path* is mainly a function which calculates the next value to set based on the current state of the animation. Currently, there are the following built-in paths functions:
|
||||
|
||||
- **lv_anim_path_linear** linear animation
|
||||
- **lv_anim_path_step** change in one step at the end
|
||||
- **lv_anim_path_ease_in** slow at the beginning
|
||||
- **lv_anim_path_ease_out** slow at the end
|
||||
- **lv_anim_path_ease_in_out** slow at the beginning and end too
|
||||
- **lv_anim_path_overshoot** overshoot the end value
|
||||
- **lv_anim_path_bounce** bounce back a little from the end value (like hitting a wall)
|
||||
|
||||
A path can be initialized like this:
|
||||
```c
|
||||
lv_anim_path_t path;
|
||||
lv_anim_path_init(&path);
|
||||
lv_anim_path_set_cb(&path, lv_anim_path_overshoot);
|
||||
lv_anim_path_set_user_data(&path, &foo); /*Optional for custom functions*/
|
||||
|
||||
/*Set the path in an animation*/
|
||||
lv_anim_set_path(&a, &path);
|
||||
```
|
||||
|
||||
## Speed vs time
|
||||
By default, you can set the animation time. But, in some cases, the **animation speed** is more practical.
|
||||
|
||||
The `lv_anim_speed_to_time(speed, start, end)` function calculates the required time in milliseconds to reach the end value from a start value with the given speed.
|
||||
The speed is interpreted in _unit/sec_ dimension. For example, `lv_anim_speed_to_time(20,0,100)` will give 5000 milliseconds. For example, in case of `lv_obj_set_x` *unit* is pixels so *20* means *20 px/sec* speed.
|
||||
|
||||
## Delete animations
|
||||
|
||||
You can **delete an animation** by `lv_anim_del(var, func)` by providing the animated variable and its animator function.
|
||||
|
||||
## API
|
||||
|
||||
### Input device
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_anim.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,215 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/display.md
|
||||
```
|
||||
# Displays
|
||||
|
||||
``` important:: The basic concept of *display* in LVGL is explained in the [Porting](/porting/display) section. So before reading further, please read the [Porting](/porting/display) section first.
|
||||
```
|
||||
|
||||
## Multiple display support
|
||||
|
||||
In LVGL, you can have multiple displays, each with their own driver and objects. The only limitation is that every display needs to be have same color depth (as defined in `LV_COLOR_DEPTH`).
|
||||
If the displays are different in this regard the rendered image can be converted to the correct format in the drivers `flush_cb`.
|
||||
|
||||
Creating more displays is easy: just initialize more display buffers and register another driver for every display.
|
||||
When you create the UI, use `lv_disp_set_default(disp)` to tell the library on which display to create objects.
|
||||
|
||||
Why would you want multi-display support? Here are some examples:
|
||||
- Have a "normal" TFT display with local UI and create "virtual" screens on VNC on demand. (You need to add your VNC driver).
|
||||
- Have a large TFT display and a small monochrome display.
|
||||
- Have some smaller and simple displays in a large instrument or technology.
|
||||
- Have two large TFT displays: one for a customer and one for the shop assistant.
|
||||
|
||||
### Using only one display
|
||||
Using more displays can be useful, but in most cases, it's not required. Therefore, the whole concept of multi-display is completely hidden if you register only one display.
|
||||
By default, the lastly created (the only one) display is used as default.
|
||||
|
||||
`lv_scr_act()`, `lv_scr_load(scr)`, `lv_layer_top()`, `lv_layer_sys()`, `LV_HOR_RES` and `LV_VER_RES` are always applied on the lastly created (default) screen.
|
||||
If you pass `NULL` as `disp` parameter to display related function, usually the default display will be used.
|
||||
E.g. `lv_disp_trig_activity(NULL)` will trigger a user activity on the default screen. (See below in [Inactivity](#Inactivity)).
|
||||
|
||||
### Mirror display
|
||||
|
||||
To mirror the image of the display to another display, you don't need to use the multi-display support. Just transfer the buffer received in `drv.flush_cb` to another display too.
|
||||
|
||||
### Split image
|
||||
You can create a larger display from smaller ones. You can create it as below:
|
||||
1. Set the resolution of the displays to the large display's resolution.
|
||||
2. In `drv.flush_cb`, truncate and modify the `area` parameter for each display.
|
||||
3. Send the buffer's content to each display with the truncated area.
|
||||
|
||||
## Screens
|
||||
|
||||
Every display has each set of [Screens](overview/object#screen-the-most-basic-parent) and the object on the screens.
|
||||
|
||||
Be sure not to confuse displays and screens:
|
||||
|
||||
* **Displays** are the physical hardware drawing the pixels.
|
||||
* **Screens** are the high-level root objects associated with a particular display. One display can have multiple screens associated with it, but not vice versa.
|
||||
|
||||
Screens can be considered the highest level containers which have no parent.
|
||||
The screen's size is always equal to its display and size their position is (0;0). Therefore, the screens coordinates can't be changed, i.e. `lv_obj_set_pos()`, `lv_obj_set_size()` or similar functions can't be used on screens.
|
||||
|
||||
A screen can be created from any object type but, the two most typical types are the [Base object](/widgets/obj) and the [Image](/widgets/img) (to create a wallpaper).
|
||||
|
||||
To create a screen, use `lv_obj_t * scr = lv_<type>_create(NULL, copy)`. `copy` can be an other screen to copy it.
|
||||
|
||||
To load a screen, use `lv_scr_load(scr)`. To get the active screen, use `lv_scr_act()`. These functions works on the default display. If you want to to specify which display to work on, use `lv_disp_get_scr_act(disp)` and `lv_disp_load_scr(disp, scr)`. Screen can be loaded with animations too. Read more [here](object.html#load-screens).
|
||||
|
||||
Screens can be deleted with `lv_obj_del(scr)`, but ensure that you do not delete the currently loaded screen.
|
||||
|
||||
### Transparent screens
|
||||
|
||||
Usually, the opacity of the screen is `LV_OPA_COVER` to provide a solid background for its children. If it's not the case (opacity < 100%) the display's background color or image will be visible.
|
||||
See the [Display background](#display-background) section for more details. If the display's background opacity is also not `LV_OPA_COVER` LVGL has no solid background to draw.
|
||||
|
||||
This configuration (transparent screen ans display) could be used to create for example OSD menus where a video is played to lower layer, and menu is created on an upper layer.
|
||||
|
||||
To handle transparent displays special (slower) color mixing algorithms needs to be used by LVGL so this feature needs to enabled with `LV_COLOR_SCREEN_TRANSP` n `lv_conf.h`.
|
||||
As this mode operates on the Alpha channel of the pixels `LV_COLOR_DEPTH = 32` is also required. The Alpha channel of 32-bit colors will be 0 where there are no objects and will be 255 where there are solid objects.
|
||||
|
||||
In summary, to enable transparent screen and displays to create OSD menu-like UIs:
|
||||
- Enable `LV_COLOR_SCREEN_TRANSP` in `lv_conf.h`
|
||||
- Be sure to use `LV_COLOR_DEPTH 32`
|
||||
- Set the screens opacity to `LV_OPA_TRANSP` e.g. with `lv_obj_set_style_local_bg_opa(lv_scr_act(), LV_OBJMASK_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP)`
|
||||
- Set the display opacity to `LV_OPA_TRANSP` with `lv_disp_set_bg_opa(NULL, LV_OPA_TRANSP);`
|
||||
|
||||
## Features of displays
|
||||
|
||||
### Inactivity
|
||||
|
||||
The user's inactivity is measured on each display. Every use of an [Input device](/overview/indev) (if [associated with the display](/porting/indev#other-features)) counts as an activity.
|
||||
To get time elapsed since the last activity, use `lv_disp_get_inactive_time(disp)`. If `NULL` is passed, the overall smallest inactivity time will be returned from all displays (**not the default display**).
|
||||
|
||||
You can manually trigger an activity using `lv_disp_trig_activity(disp)`. If `disp` is `NULL`, the default screen will be used (**and not all displays**).
|
||||
|
||||
### Background
|
||||
Every display has background color, a background image and background opacity properties. They become visible when the current screen is transparent or not positioned to cover the whole display.
|
||||
|
||||
Background color is a simple color to fill the display. It can be adjusted with `lv_disp_set_bg_color(disp, color)`;
|
||||
|
||||
Background image is path to file or pointer to an `lv_img_dsc_t` variable (converted image) to be used as wallpaper. It can be set with `lv_disp_set_bg_color(disp, &my_img)`;
|
||||
If the background image is set (not `NULL`) the background won't filled with `bg_color`.
|
||||
|
||||
The opacity of the background color or image can be adjusted with `lv_disp_set_bg_opa(disp, opa)`.
|
||||
|
||||
The `disp` parameter of these functions can be `NULL` to refer it to the default display.
|
||||
|
||||
|
||||
## Colors
|
||||
|
||||
The color module handles all color-related functions like changing color depth, creating colors from hex code, converting between color depths, mixing colors, etc.
|
||||
|
||||
The following variable types are defined by the color module:
|
||||
|
||||
- **lv_color1_t** Store monochrome color. For compatibility, it also has R, G, B fields but they are always the same value (1 byte)
|
||||
- **lv_color8_t** A structure to store R (3 bit),G (3 bit),B (2 bit) components for 8-bit colors (1 byte)
|
||||
- **lv_color16_t** A structure to store R (5 bit),G (6 bit),B (5 bit) components for 16-bit colors (2 byte)
|
||||
- **lv_color32_t** A structure to store R (8 bit),G (8 bit), B (8 bit) components for 24-bit colors (4 byte)
|
||||
- **lv_color_t** Equal to `lv_color1/8/16/24_t` according to color depth settings
|
||||
- **lv_color_int_t** `uint8_t`, `uint16_t` or `uint32_t` according to color depth setting. Used to build color arrays from plain numbers.
|
||||
- **lv_opa_t** A simple `uint8_`t type to describe opacity.
|
||||
|
||||
The `lv_color_t`, `lv_color1_t`, `lv_color8_t`, `lv_color16_t` and `lv_color32_t` types have got four fields:
|
||||
|
||||
- **ch.red** red channel
|
||||
- **ch.green** green channel
|
||||
- **ch.blue** blue channel
|
||||
- **full** red + green + blue as one number
|
||||
|
||||
You can set the current color depth in *lv_conf.h*, by setting the `LV_COLOR_DEPTH` define to 1 (monochrome), 8, 16 or 32.
|
||||
|
||||
### Convert color
|
||||
You can convert a color from the current color depth to another. The converter functions return with a number, so you have to use the `full` field:
|
||||
|
||||
```c
|
||||
lv_color_t c;
|
||||
c.red = 0x38;
|
||||
c.green = 0x70;
|
||||
c.blue = 0xCC;
|
||||
|
||||
lv_color1_t c1;
|
||||
c1.full = lv_color_to1(c); /*Return 1 for light colors, 0 for dark colors*/
|
||||
|
||||
lv_color8_t c8;
|
||||
c8.full = lv_color_to8(c); /*Give a 8 bit number with the converted color*/
|
||||
|
||||
lv_color16_t c16;
|
||||
c16.full = lv_color_to16(c); /*Give a 16 bit number with the converted color*/
|
||||
|
||||
lv_color32_t c24;
|
||||
c32.full = lv_color_to32(c); /*Give a 32 bit number with the converted color*/
|
||||
```
|
||||
|
||||
### Swap 16 colors
|
||||
You may set `LV_COLOR_16_SWAP` in *lv_conf.h* to swap the bytes of *RGB565* colors. It's useful if you send the 16-bit colors via a byte-oriented interface like SPI.
|
||||
|
||||
As 16-bit numbers are stored in Little Endian format (lower byte on the lower address), the interface will send the lower byte first. However, displays usually need the higher byte first. A mismatch in the byte order will result in highly distorted colors.
|
||||
|
||||
### Create and mix colors
|
||||
You can create colors with the current color depth using the LV_COLOR_MAKE macro. It takes 3 arguments (red, green, blue) as 8-bit numbers.
|
||||
For example to create light red color: `my_color = COLOR_MAKE(0xFF,0x80,0x80)`.
|
||||
|
||||
Colors can be created from HEX codes too: `my_color = lv_color_hex(0x288ACF)` or `my_color = lv_folro_hex3(0x28C)`.
|
||||
|
||||
Mixing two colors is possible with `mixed_color = lv_color_mix(color1, color2, ratio)`. Ration can be 0..255. 0 results fully color2, 255 result fully color1.
|
||||
|
||||
Colors can be created with from HSV space too using `lv_color_hsv_to_rgb(hue, saturation, value)` . `hue` should be in 0..360 range, `saturation` and `value` in 0..100 range.
|
||||
|
||||
### Opacity
|
||||
To describe opacity the `lv_opa_t` type is created as a wrapper to `uint8_t`. Some defines are also introduced:
|
||||
|
||||
- **LV_OPA_TRANSP** Value: 0, means the opacity makes the color completely transparent
|
||||
- **LV_OPA_10** Value: 25, means the color covers only a little
|
||||
- **LV_OPA_20 ... OPA_80** come logically
|
||||
- **LV_OPA_90** Value: 229, means the color near completely covers
|
||||
- **LV_OPA_COVER** Value: 255, means the color completely covers
|
||||
|
||||
You can also use the `LV_OPA_*` defines in `lv_color_mix()` as a *ratio*.
|
||||
|
||||
### Built-in colors
|
||||
|
||||
The color module defines the most basic colors such as:
|
||||
|
||||
-  `LV_COLOR_WHITE`
|
||||
-  `LV_COLOR_BLACK`
|
||||
-  `LV_COLOR_GRAY`
|
||||
-  `LV_COLOR_SILVER`
|
||||
-  `LV_COLOR_RED`
|
||||
-  `LV_COLOR_MAROON`
|
||||
-  `LV_COLOR_LIME`
|
||||
-  `LV_COLOR_GREEN`
|
||||
-  `LV_COLOR_OLIVE`
|
||||
-  `LV_COLOR_BLUE`
|
||||
-  `LV_COLOR_NAVY`
|
||||
-  `LV_COLOR_TEAL`
|
||||
-  `LV_COLOR_CYAN`
|
||||
-  `LV_COLOR_AQUA`
|
||||
-  `LV_COLOR_PURPLE`
|
||||
-  `LV_COLOR_MAGENTA`
|
||||
-  `LV_COLOR_ORANGE`
|
||||
-  `LV_COLOR_YELLOW`
|
||||
|
||||
as well as `LV_COLOR_WHITE` (fully white).
|
||||
|
||||
## API
|
||||
|
||||
|
||||
### Display
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_disp.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
|
||||
### Colors
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_color.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,100 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/drawing.md
|
||||
```
|
||||
# Drawing
|
||||
|
||||
With LVGL, you don't need to draw anything manually. Just create objects (like buttons and labels), move and change them and LVGL will refresh and redraw what is required.
|
||||
|
||||
However, it might be useful to have a basic understanding of how drawing happens in LVGL.
|
||||
|
||||
The basic concept is to not draw directly to the screen, but draw to an internal buffer first and then copy that buffer to screen when the rendering is ready. It has two main advantages:
|
||||
1. **Avoids flickering** while layers of the UI are drawn. For example, when drawing a *background + button + text*, each "stage" would be visible for a short time.
|
||||
2. **It's faster** to modify a buffer in RAM and finally write one pixel once
|
||||
than read/write a display directly on each pixel access. (e.g. via a display controller with SPI interface). Hence, it's suitable for pixels that are redrawn multiple times (e.g. background + button + text).
|
||||
|
||||
## Buffering types
|
||||
|
||||
As you already might learn in the [Porting](/porting/display) section, there are 3 types of buffers:
|
||||
1. **One buffer** - LVGL draws the content of the screen into a buffer and sends it to the display. The buffer can be smaller than the screen. In this case, the larger areas will be redrawn in multiple parts. If only small areas changes (e.g. button press), then only those areas will be refreshed.
|
||||
2. **Two non-screen-sized buffers** - having two buffers, LVGL can draw into one buffer while the content of the other buffer is sent to display in the background.
|
||||
DMA or other hardware should be used to transfer the data to the display to let the CPU draw meanwhile.
|
||||
This way, the rendering and refreshing of the display become parallel. If the buffer is smaller than the area to refresh, LVGL will draw the display's content in chunks similar to the *One buffer*.
|
||||
3. **Two screen-sized buffers** -
|
||||
In contrast to *Two non-screen-sized buffers*, LVGL will always provide the whole screen's content, not only chunks. This way, the driver can simply change the address of the frame buffer to the buffer received from LVGL.
|
||||
Therefore, this method works best when the MCU has an LCD/TFT interface and the frame buffer is just a location in the RAM.
|
||||
|
||||
## Mechanism of screen refreshing
|
||||
|
||||
1. Something happens on the GUI which requires redrawing. For example, a button has been pressed, a chart has been changed or an animation happened, etc.
|
||||
2. LVGL saves the changed object's old and new area into a buffer, called an *Invalid area buffer*. For optimization, in some cases, objects are not added to the buffer:
|
||||
- Hidden objects are not added.
|
||||
- Objects completely out of their parent are not added.
|
||||
- Areas out of the parent are cropped to the parent's area.
|
||||
- The object on other screens are not added.
|
||||
3. In every `LV_DISP_DEF_REFR_PERIOD` (set in *lv_conf.h*):
|
||||
- LVGL checks the invalid areas and joins the adjacent or intersecting areas.
|
||||
- Takes the first joined area, if it's smaller than the *display buffer*, then simply draw the areas' content to the *display buffer*. If the area doesn't fit into the buffer, draw as many lines as possible to the *display buffer*.
|
||||
- When the area is drawn, call `flush_cb` from the display driver to refresh the display.
|
||||
- If the area was larger than the buffer, redraw the remaining parts too.
|
||||
- Do the same with all the joined areas.
|
||||
|
||||
While an area is redrawn, the library searches the most top object which covers the area to redraw, and starts to draw from that object.
|
||||
For example, if a button's label has changed, the library will see that it's enough to draw the button under the text, and it's not required to draw the background too.
|
||||
|
||||
The difference between buffer types regarding the drawing mechanism is the following:
|
||||
1. **One buffer** - LVGL needs to wait for `lv_disp_flush_ready()` (called at the end of `flush_cb`) before starting to redraw the next part.
|
||||
2. **Two non-screen-sized buffers** - LVGL can immediately draw to the second buffer when the first is sent to `flush_cb` because the flushing should be done by DMA (or similar hardware) in the background.
|
||||
3. **Two screen-sized buffers** - After calling `flush_cb`, the first buffer, if being displayed as frame buffer. Its content is copied to the second buffer and all the changes are drawn on top of it.
|
||||
|
||||
## Masking
|
||||
*Masking* is the basic concept of LVGL's drawing engine.
|
||||
To use LVGL it's not required to know about the mechanisms described here,
|
||||
but you might find interesting to know how the drawing works under hood.
|
||||
|
||||
To learn masking let's learn the steps of drawing first:
|
||||
1. Create a draw descriptor from an object's styles (e.g. `lv_draw_rect_dsc_t`).
|
||||
It tells the parameters of drawing, for example the colors, widths, opacity, fonts, radius, etc.
|
||||
2. Call the draw function with the initialized descriptor and some other parameters.
|
||||
It renders the primitive shape to the current draw buffer.
|
||||
3. If the shape is very simple and doesn't require masks go to #5.
|
||||
Else create the required masks (e.g. a rounded rectangle mask)
|
||||
4. Apply all the created mask(s) for one or a few lines.
|
||||
It create 0..255 values into a *mask buffer* with the "shape" of the created masks.
|
||||
E.g. in case of a "line mask" according to the parameters of the mask,
|
||||
keep one side of the buffer as it is (255 by default) and set the rest to 0 to indicate that the latter side should be removed.
|
||||
5. Blend the image or rectangle to the screen.
|
||||
During blending masks (make some pixels transparent or opaque), blending modes (additive, subtractive, etc), opacity are handled.
|
||||
6. Repeat from #4.
|
||||
|
||||
Masks are used the create almost every basic primitives:
|
||||
- **letters** create a mask from the letter and draw a “letter-colored” rectangle using the mask.
|
||||
- **line** created from 4 "line masks", to mask out the left, right, top and bottom part of the line to get perfectly perpendicular line ending
|
||||
- **rounded rectangle** a mask is created real-time for each line of a rounded rectangle and a normal filled rectangle is drawn according to the mask.
|
||||
- **clip corner** to clip to overflowing content on the rounded corners also a rounded rectangle mask is applied.
|
||||
- **rectangle border** same as a rounded rectangle, but inner part is masked out too
|
||||
- **arc drawing** a circle border is drawn, but an arc mask is applied.
|
||||
- **ARGB images** the alpha channel is separated into a mask and the image is drawn as a normal RGB image.
|
||||
|
||||
As mentioned in #3 above in some cases no mask is required:
|
||||
- a mono colored, not rounded rectangles
|
||||
- RGB images
|
||||
|
||||
|
||||
LVGL has the following built-in mask types which can be calculated and applied real-time:
|
||||
- **LV_DRAW_MASK_TYPE_LINE** Removes a side of a line (top, bottom, left or right). `lv_draw_line` uses 4 of it.
|
||||
Essentially, every (skew) line is bounded with 4 line masks by forming a rectangle.
|
||||
- **LV_DRAW_MASK_TYPE_RADIUS** Removes the inner or outer parts of a rectangle which can have radius too. It's also used to create circles by setting the radius to large value (`LV_RADIUS_CIRCLE`)
|
||||
- **LV_DRAW_MASK_TYPE_ANGLE** Removes a circle sector. It is used by `lv_draw_arc` to remove the "empty" sector.
|
||||
- **LV_DRAW_MASK_TYPE_FADE** Create a vertical fade (change opacity)
|
||||
- **LV_DRAW_MASK_TYPE_MAP** The mask is stored in an array and the necessary parts are applied
|
||||
|
||||
|
||||
Masks are create and removed automatically during drawing but the [lv_objmask](/widgets/objmask) allows the user to add masks.
|
||||
Here is an example:
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. include:: /lv_examples/src/lv_ex_widgets/lv_ex_objmask/index.rst
|
||||
|
||||
```
|
||||
@@ -0,0 +1,133 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/event.md
|
||||
```
|
||||
# Events
|
||||
|
||||
Events are triggered in LVGL when something happens which might be interesting to the user, e.g. if an object:
|
||||
- is clicked
|
||||
- is dragged
|
||||
- its value has changed, etc.
|
||||
|
||||
The user can assign a callback function to an object to see these events. In practice, it looks like this:
|
||||
```c
|
||||
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);
|
||||
lv_obj_set_event_cb(btn, my_event_cb); /*Assign an event callback*/
|
||||
|
||||
...
|
||||
|
||||
static void my_event_cb(lv_obj_t * obj, lv_event_t event)
|
||||
{
|
||||
switch(event) {
|
||||
case LV_EVENT_PRESSED:
|
||||
printf("Pressed\n");
|
||||
break;
|
||||
|
||||
case LV_EVENT_SHORT_CLICKED:
|
||||
printf("Short clicked\n");
|
||||
break;
|
||||
|
||||
case LV_EVENT_CLICKED:
|
||||
printf("Clicked\n");
|
||||
break;
|
||||
|
||||
case LV_EVENT_LONG_PRESSED:
|
||||
printf("Long press\n");
|
||||
break;
|
||||
|
||||
case LV_EVENT_LONG_PRESSED_REPEAT:
|
||||
printf("Long press repeat\n");
|
||||
break;
|
||||
|
||||
case LV_EVENT_RELEASED:
|
||||
printf("Released\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/*Etc.*/
|
||||
}
|
||||
```
|
||||
|
||||
More objects can use the same *event callback*.
|
||||
|
||||
## Event types
|
||||
|
||||
The following event types exist:
|
||||
|
||||
### Generic events
|
||||
|
||||
All objects (such as Buttons/Labels/Sliders etc.) receive these generic events regardless of their type.
|
||||
|
||||
#### Related to the input devices
|
||||
These are sent when an object is pressed/released etc. by the user. They are used not only for *Pointers* but can used for *Keypad*, *Encoder* and *Button* input devices as well. Visit the [Overview of input devices](/overview/indev) section to learn more about them.
|
||||
- **LV_EVENT_PRESSED** The object has been pressed
|
||||
- **LV_EVENT_PRESSING** The object is being pressed (sent continuously while pressing)
|
||||
- **LV_EVENT_PRESS_LOST** The input device is still being pressed but is no longer on the object
|
||||
- **LV_EVENT_SHORT_CLICKED** Released before `LV_INDEV_LONG_PRESS_TIME` time. Not called if dragged.
|
||||
- **LV_EVENT_LONG_PRESSED** Pressing for `LV_INDEV_LONG_PRESS_TIME` time. Not called if dragged.
|
||||
- **LV_EVENT_LONG_PRESSED_REPEAT** Called after `LV_INDEV_LONG_PRESS_TIME` in every `LV_INDEV_LONG_PRESS_REP_TIME` ms. Not called if dragged.
|
||||
- **LV_EVENT_CLICKED** Called on release if not dragged (regardless to long press)
|
||||
- **LV_EVENT_RELEASED** Called in every case when the object has been released even if it was dragged. Not called if slid from the object while pressing and released outside of the object. In this case, `LV_EVENT_PRESS_LOST` is sent.
|
||||
|
||||
#### Related to pointer
|
||||
These events are sent only by pointer-like input devices (E.g. mouse or touchpad)
|
||||
- **LV_EVENT_DRAG_BEGIN** Dragging of the object has started
|
||||
- **LV_EVENT_DRAG_END** Dragging finished (including drag throw)
|
||||
- **LV_EVENT_DRAG_THROW_BEGIN** Drag throw started (released after drag with "momentum")
|
||||
|
||||
#### Related to keypad and encoder
|
||||
These events are sent by keypad and encoder input devices. Learn more about *Groups* in [overview/indev](Input devices) section.
|
||||
- **LV_EVENT_KEY** A *Key* is sent to the object. Typically when it was pressed or repeated after a long press. The key can be retrived by `uint32_t * key = lv_event_get_data()`
|
||||
- **LV_EVENT_FOCUSED** The object is focused in its group
|
||||
- **LV_EVENT_DEFOCUSED** The object is defocused in its group
|
||||
|
||||
#### General events
|
||||
Other general events sent by the library.
|
||||
- **LV_EVENT_DELETE** The object is being deleted. Free the related user-allocated data.
|
||||
|
||||
### Special events
|
||||
These events are specific to a particular object type.
|
||||
- **LV_EVENT_VALUE_CHANGED** The object value has changed (e.g. for a [Slider](/widgets/slider))
|
||||
- **LV_EVENT_INSERT** Something is inserted to the object. (Typically to a [Text area](/widgets/textarea))
|
||||
- **LV_EVENT_APPLY** "Ok", "Apply" or similar specific button has clicked. (Typically from a [Keyboard](/widgets/keyboard) object)
|
||||
- **LV_EVENT_CANCEL** "Close", "Cancel" or similar specific button has clicked. (Typically from a [Keyboard](/widgets/keyboard) object)
|
||||
- **LV_EVENT_REFRESH** Query to refresh the object. Never sent by the library but can be sent by the user.
|
||||
|
||||
Visit particular [Object type's documentation](/widgets/index) to understand which events are used by an object type.
|
||||
|
||||
## Custom data
|
||||
Some events might contain custom data. For example, `LV_EVENT_VALUE_CHANGED` in some cases tells the new value. For more information, see the particular [Object type's documentation](/widgets/index).
|
||||
To get the custom data in the event callback use `lv_event_get_data()`.
|
||||
|
||||
The type of the custom data depends on the sending object but if it's a
|
||||
- single number then it's `uint32_t *` or `int32_t *`
|
||||
- text then `char * ` or `const char *`
|
||||
|
||||
|
||||
## Send events manually
|
||||
|
||||
### Arbitrary events
|
||||
|
||||
To manually send events to an object, use `lv_event_send(obj, LV_EVENT_..., &custom_data)`.
|
||||
|
||||
For example, it can be used to manually close a message box by simulating a button press (although there are simpler ways of doing this):
|
||||
```c
|
||||
/*Simulate the press of the first button (indexes start from zero)*/
|
||||
uint32_t btn_id = 0;
|
||||
lv_event_send(mbox, LV_EVENT_VALUE_CHANGED, &btn_id);
|
||||
```
|
||||
|
||||
### Refresh event
|
||||
|
||||
`LV_EVENT_REFRESH` is special event because it's designed to be used by the user to notify an object to refresh itself. Some examples:
|
||||
- notify a label to refresh its text according to one or more variables (e.g. current time)
|
||||
- refresh a label when the language changes
|
||||
- enable a button if some conditions are met (e.g. the correct PIN is entered)
|
||||
- add/remove styles to/from an object if a limit is exceeded, etc
|
||||
|
||||
To simplest way to handle similar cases is utilizing the following functions.
|
||||
|
||||
`lv_event_send_refresh(obj)` is just a wrapper to `lv_event_send(obj, LV_EVENT_REFRESH, NULL)`. So it simply sends an `LV_EVENT_REFRESH` to an object.
|
||||
|
||||
`lv_event_send_refresh_recursive(obj)` sends `LV_EVENT_REFRESH` event to an object and all of its children. If `NULL` is passed as parameter all objects of all displays will be refreshed.
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/file-system.md
|
||||
```
|
||||
# File system
|
||||
|
||||
LVGL has a 'File system' abstraction module that enables you to attach any type of file systems.
|
||||
The file system is identified by a drive letter.
|
||||
For example, if the SD card is associated with the letter `'S'`, a file can be reached like `"S:path/to/file.txt"`.
|
||||
|
||||
## Add a driver
|
||||
|
||||
To add a driver, `lv_fs_drv_t` needs to be initialized like this:
|
||||
```c
|
||||
lv_fs_drv_t drv;
|
||||
lv_fs_drv_init(&drv); /*Basic initialization*/
|
||||
|
||||
drv.letter = 'S'; /*An uppercase letter to identify the drive */
|
||||
drv.file_size = sizeof(my_file_object); /*Size required to store a file object*/
|
||||
drv.rddir_size = sizeof(my_dir_object); /*Size required to store a directory object (used by dir_open/close/read)*/
|
||||
drv.ready_cb = my_ready_cb; /*Callback to tell if the drive is ready to use */
|
||||
drv.open_cb = my_open_cb; /*Callback to open a file */
|
||||
drv.close_cb = my_close_cb; /*Callback to close a file */
|
||||
drv.read_cb = my_read_cb; /*Callback to read a file */
|
||||
drv.write_cb = my_write_cb; /*Callback to write a file */
|
||||
drv.seek_cb = my_seek_cb; /*Callback to seek in a file (Move cursor) */
|
||||
drv.tell_cb = my_tell_cb; /*Callback to tell the cursor position */
|
||||
drv.trunc_cb = my_trunc_cb; /*Callback to delete a file */
|
||||
drv.size_cb = my_size_cb; /*Callback to tell a file's size */
|
||||
drv.rename_cb = my_rename_cb; /*Callback to rename a file */
|
||||
|
||||
|
||||
drv.dir_open_cb = my_dir_open_cb; /*Callback to open directory to read its content */
|
||||
drv.dir_read_cb = my_dir_read_cb; /*Callback to read a directory's content */
|
||||
drv.dir_close_cb = my_dir_close_cb; /*Callback to close a directory */
|
||||
|
||||
drv.free_space_cb = my_free_space_cb; /*Callback to tell free space on the drive */
|
||||
|
||||
drv.user_data = my_user_data; /*Any custom data if required*/
|
||||
|
||||
lv_fs_drv_register(&drv); /*Finally register the drive*/
|
||||
|
||||
```
|
||||
|
||||
Any of the callbacks can be `NULL` to indicate that operation is not supported.
|
||||
|
||||
As an example of how the callbacks are used, if you use `lv_fs_open(&file, "S:/folder/file.txt", LV_FS_MODE_WR)`, LVGL:
|
||||
|
||||
1. Verifies that a registered drive exists with the letter `'S'`.
|
||||
2. Checks if it's `open_cb` is implemented (not `NULL`).
|
||||
3. Calls the set `open_cb` with `"folder/file.txt"` path.
|
||||
|
||||
## Usage example
|
||||
|
||||
The example below shows how to read from a file:
|
||||
```c
|
||||
lv_fs_file_t f;
|
||||
lv_fs_res_t res;
|
||||
res = lv_fs_open(&f, "S:folder/file.txt", LV_FS_MODE_RD);
|
||||
if(res != LV_FS_RES_OK) my_error_handling();
|
||||
|
||||
uint32_t read_num;
|
||||
uint8_t buf[8];
|
||||
res = lv_fs_read(&f, buf, 8, &read_num);
|
||||
if(res != LV_FS_RES_OK || read_num != 8) my_error_handling();
|
||||
|
||||
lv_fs_close(&f);
|
||||
```
|
||||
*The mode in `lv_fs_open` can be `LV_FS_MODE_WR` to open for write or `LV_FS_MODE_RD | LV_FS_MODE_WR` for both*
|
||||
|
||||
This example shows how to read a directory's content. It's up to the driver how to mark the directories, but it can be a good practice to insert a `'/'` in front of the directory name.
|
||||
```c
|
||||
lv_fs_dir_t dir;
|
||||
lv_fs_res_t res;
|
||||
res = lv_fs_dir_open(&dir, "S:/folder");
|
||||
if(res != LV_FS_RES_OK) my_error_handling();
|
||||
|
||||
char fn[256];
|
||||
while(1) {
|
||||
res = lv_fs_dir_read(&dir, fn);
|
||||
if(res != LV_FS_RES_OK) {
|
||||
my_error_handling();
|
||||
break;
|
||||
}
|
||||
|
||||
/*fn is empty, if not more files to read*/
|
||||
if(strlen(fn) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
printf("%s\n", fn);
|
||||
}
|
||||
|
||||
lv_fs_dir_close(&dir);
|
||||
```
|
||||
|
||||
## Use drivers for images
|
||||
|
||||
[Image](/widgets/img) objects can be opened from files too (besides variables stored in the flash).
|
||||
|
||||
To initialize the image, the following callbacks are required:
|
||||
- open
|
||||
- close
|
||||
- read
|
||||
- seek
|
||||
- tell
|
||||
|
||||
|
||||
## API
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_fs.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,255 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/font.md
|
||||
```
|
||||
# Fonts
|
||||
|
||||
In LVGL fonts are collections of bitmaps and other information required to render the images of the letters (glyph).
|
||||
A font is stored in a `lv_font_t` variable and can be set in style's *text_font* field. For example:
|
||||
```c
|
||||
lv_style_set_text_font(&my_style, LV_STATE_DEFAULT, &lv_font_montserrat_28); /*Set a larger font*/
|
||||
```
|
||||
|
||||
The fonts have a **bpp (bits per pixel)** property. It shows how many bits are used to describe a pixel in the font. The value stored for a pixel determines the pixel's opacity.
|
||||
This way, with higher *bpp*, the edges of the letter can be smoother. The possible *bpp* values are 1, 2, 4 and 8 (higher value means better quality).
|
||||
|
||||
The *bpp* also affects the required memory size to store the font. For example, *bpp = 4* makes the font nearly 4 times greater compared to *bpp = 1*.
|
||||
|
||||
## Unicode support
|
||||
|
||||
LVGL supports **UTF-8** encoded Unicode characters.
|
||||
Your editor needs to be configureed to save your code/text as UTF-8 (usually this the default) and be sure that, `LV_TXT_ENC` is set to `LV_TXT_ENC_UTF8` in *lv_conf.h*. (This is the default value)
|
||||
|
||||
To test it try
|
||||
```c
|
||||
lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL);
|
||||
lv_label_set_text(label1, LV_SYMBOL_OK);
|
||||
```
|
||||
|
||||
If all works well, a ✓ character should be displayed.
|
||||
|
||||
## Built-in fonts
|
||||
|
||||
There are several built-in fonts in different sizes, which can be enabled in `lv_conf.h` by *LV_FONT_...* defines.
|
||||
### Normal fonts
|
||||
Containing all the ASCII characters, the degree symbol (U+00B0), the bullet symbol (U+2022) and the build in symbols (see below).
|
||||
- `LV_FONT_MONTSERRAT_12` 12 px font
|
||||
- `LV_FONT_MONTSERRAT_14` 14 px font
|
||||
- `LV_FONT_MONTSERRAT_16` 16 px font
|
||||
- `LV_FONT_MONTSERRAT_18` 18 px font
|
||||
- `LV_FONT_MONTSERRAT_20` 20 px font
|
||||
- `LV_FONT_MONTSERRAT_22` 22 px font
|
||||
- `LV_FONT_MONTSERRAT_24` 24 px font
|
||||
- `LV_FONT_MONTSERRAT_26` 26 px font
|
||||
- `LV_FONT_MONTSERRAT_28` 28 px font
|
||||
- `LV_FONT_MONTSERRAT_30` 30 px font
|
||||
- `LV_FONT_MONTSERRAT_32` 32 px font
|
||||
- `LV_FONT_MONTSERRAT_34` 34 px font
|
||||
- `LV_FONT_MONTSERRAT_36` 36 px font
|
||||
- `LV_FONT_MONTSERRAT_38` 38 px font
|
||||
- `LV_FONT_MONTSERRAT_40` 40 px font
|
||||
- `LV_FONT_MONTSERRAT_42` 42 px font
|
||||
- `LV_FONT_MONTSERRAT_44` 44 px font
|
||||
- `LV_FONT_MONTSERRAT_46` 46 px font
|
||||
- `LV_FONT_MONTSERRAT_48` 48 px font
|
||||
|
||||
### Special fonts
|
||||
- `LV_FONT_MONTSERRAT_12_SUBPX` Same as normal 12 px font but with [subpixel rendering](#subpixel-rendering)
|
||||
- `LV_FONT_MONTSERRAT_28_COMPRESSED` Same as normal 28 px font but [compressed font](#compress-fonts) with 3 bpp
|
||||
- `LV_FONT_DEJAVU_16_PERSIAN_HEBREW` 16 px font with normal range + Hebrew, Arabic, Perisan letters and all their forms
|
||||
- `LV_FONT_SIMSUN_16_CJK`16 px font with normal range + 1000 most common CJK radicals
|
||||
- `LV_FONT_UNSCII_8` 8 px pixel perfect font with only ASCII characters
|
||||
- `LV_FONT_UNSCII_16` 16 px pixel perfect font with only ASCII characters
|
||||
|
||||
|
||||
The built-in fonts are **global variables** with names like `lv_font_montserrat_16` for 16 px hight font. To use them in a style, just add a pointer to a font variable like shown above.
|
||||
|
||||
The built-in fonts have *bpp = 4*, contains the ASCII characters and uses the [Montserrat](https://fonts.google.com/specimen/Montserrat) font.
|
||||
|
||||
In addition to the ASCII range, the following symbols are also added to the built-in fonts from the [FontAwesome](https://fontawesome.com/) font.
|
||||
|
||||

|
||||
|
||||
The symbols can be used as:
|
||||
```c
|
||||
lv_label_set_text(my_label, LV_SYMBOL_OK);
|
||||
```
|
||||
|
||||
Or with together with strings:
|
||||
```c
|
||||
lv_label_set_text(my_label, LV_SYMBOL_OK "Apply");
|
||||
```
|
||||
|
||||
Or more symbols together:
|
||||
```c
|
||||
lv_label_set_text(my_label, LV_SYMBOL_OK LV_SYMBOL_WIFI LV_SYMBOL_PLAY);
|
||||
```
|
||||
|
||||
## Special features
|
||||
|
||||
### Bidirectional support
|
||||
Most of the languages use Left-to-Right (LTR for short) writing direction, however some languages (such as Hebrew, Persian or Arabic) uses Right-to-Left (RTL for short) direction.
|
||||
|
||||
LVGL not only supports RTL texts but supports mixed (a.k.a. bidirectional, BiDi) text rendering too. Some examples:
|
||||
|
||||

|
||||
|
||||
The BiDi support can be enabled by `LV_USE_BIDI` in *lv_conf.h*
|
||||
|
||||
All texts have a base direction (LTR or RTL) which determines some rendering rules and the default alignment of the text (Left or Right).
|
||||
However, in LVGL, base direction is applied not only for labels. It's a general property which can be set for every object.
|
||||
If unset then it will be inherited from the parent.
|
||||
So it's enough to set the base direction of the screen and every object will inherit it.
|
||||
|
||||
The default base direction of screen can be set by `LV_BIDI_BASE_DIR_DEF` in *lv_conf.h* and other objects inherit the base direction from their parent.
|
||||
|
||||
To set an object's base direction use `lv_obj_set_base_dir(obj, base_dir)`. The possible base direction are:
|
||||
- `LV_BIDI_DIR_LTR`: Left to Right base direction
|
||||
- `LV_BIDI_DIR_RTL`: Right to Left base direction
|
||||
- `LV_BIDI_DIR_AUTO`: Auto detect base direction
|
||||
- `LV_BIDI_DIR_INHERIT`: Inherit the base direction from the parent (default for non-screen objects)
|
||||
|
||||
This list summarizes the effect of RTL base direction on objects:
|
||||
- Create objects by default on the right
|
||||
- `lv_tabview`: displays tabs from right to left
|
||||
- `lv_checkbox`: Show the box on the right
|
||||
- `lv_btnmatrix`: Show buttons from right to left
|
||||
- `lv_list`: Show the icon on the right
|
||||
- `lv_dropdown`: Align the options to the right
|
||||
- The texts in `lv_table`, `lv_btnmatrix`, `lv_keyboard`, `lv_tabview`, `lv_dropdown`, `lv_roller` are "BiDi processed" to be displayed correctly
|
||||
|
||||
### Arabic and Persian support
|
||||
There are some special rules to display Arabic and Persian characters: the *form* of the character depends on their position in the text.
|
||||
A different form of the same letter needs to be used if it isolated, start, middle or end position. Besides these some conjunction rules also should be taken into account.
|
||||
|
||||
LVGL supports to apply these rules if `LV_USE_ARABIC_PERSIAN_CHARS` is enabled.
|
||||
|
||||
However, there some limitations:
|
||||
- Only displaying texts is supported (e.g. on labels), text inputs (e.g. text area) doesn't support this feature
|
||||
- Static text (i.e. const) are not processed. E.g. texts set by `lv_label_set_text()` will "Arabic processed" but `lv_lable_set_text_static()` won't.
|
||||
- Text get functions (e.g. `lv_label_get_text()`) will return the processed text.
|
||||
|
||||
### Subpixel rendering
|
||||
|
||||
Subpixel rendering means to triple the horizontal resolution by rendering on Red, Green and Blue channel instead of pixel level. It takes advantage of the position of physical color channels of each pixel.
|
||||
It results in higher quality letter anti-aliasing. Lear more [here](https://en.wikipedia.org/wiki/Subpixel_rendering).
|
||||
|
||||
Subpixel rendering requires to generate the fonts with special settings:
|
||||
- In the online converter tick the `Subpixel` box
|
||||
- In the command line tool use `--lcd` flag. Note that the generated font needs about 3 times more memory.
|
||||
|
||||
Subpixel rendering works only if the color channels of the pixels have a horizontal layout. That is the R, G, B channels are next each other and not above each other.
|
||||
The order of color channels also needs to match with the library settings. By default the LVGL assumes `RGB` order, however it can be swapped by setting `LV_SUBPX_BGR 1` in *lv_conf.h*.
|
||||
|
||||
### Compress fonts
|
||||
The bitmaps of the fonts can be compressed by
|
||||
- ticking the `Compressed` check box in the online converter
|
||||
- not passing `--no-compress` flag to the offline converter (applies compression by default)
|
||||
|
||||
The compression is more effective with larger fonts and higher bpp. However, it's about 30% slower to render the compressed fonts.
|
||||
Therefore it's recommended to compress only the largest fonts of user interface, because
|
||||
- they need the most memory
|
||||
- they can be compressed better
|
||||
- and probably they are used less frequently then the medium sized fonts. (so performance cost is smaller)
|
||||
|
||||
## Add new font
|
||||
|
||||
There are several ways to add a new font to your project:
|
||||
1. The simplest method is to use the [Online font converter](https://lvgl.io/tools/fontconverter). Just set the parameters, click the *Convert* button, copy the font to your project and use it. **Be sure to carefully read the steps provided on that site or you will get an error while converting.**
|
||||
2. Use the [Offline font converter](https://github.com/lvgl/lv_font_conv). (Requires Node.js to be installed)
|
||||
3. If you want to create something like the built-in fonts (Roboto font and symbols) but in different size and/or ranges, you can use the `built_in_font_gen.py` script in `lvgl/scripts/built_in_font` folder.
|
||||
(It requires Python and `lv_font_conv` to be installed)
|
||||
|
||||
To declare the font in a file, use `LV_FONT_DECLARE(my_font_name)`.
|
||||
|
||||
To make the fonts globally available (like the builtin fonts), add them to `LV_FONT_CUSTOM_DECLARE` in *lv_conf.h*.
|
||||
|
||||
## Add new symbols
|
||||
The built-in symbols are created from [FontAwesome](https://fontawesome.com/) font.
|
||||
|
||||
1. Search symbol on [https://fontawesome.com](https://fontawesome.com). For example the [USB symbol](https://fontawesome.com/icons/usb?style=brands). Copy it's Unicode ID which is `0xf287` in this case.
|
||||
2. Open the [Online font converter](https://lvgl.io/tools/fontconverter). Add Add [FontAwesome.woff](https://lvgl.io/assets/others/FontAwesome5-Solid+Brands+Regular.woff). .
|
||||
3. Set the parameters such as Name, Size, BPP. You'll use this name to declare and use the font in your code.
|
||||
4. Add the Unicode ID of the symbol to the range field. E.g.` 0xf287` for the USB symbol. More symbols can be enumerated with `,`.
|
||||
5. Convert the font and copy it to your project. Make sure to compile the .c file of your font.
|
||||
6. Declare the font using `extern lv_font_t my_font_name;` or simply `LV_FONT_DECLARE(my_font_name);`.
|
||||
|
||||
**Using the symbol**
|
||||
1. Convert the Unicode value to UTF8. You can do it e.g on [this site](http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=f287&mode=hex). For `0xf287` the *Hex UTF-8 bytes* are `EF 8A 87`.
|
||||
2. Create a `define` from the UTF8 values: `#define MY_USB_SYMBOL "\xEF\x8A\x87"`
|
||||
3. Create a label and set the text. Eg. `lv_label_set_text(label, MY_USB_SYMBOL)`
|
||||
|
||||
Note - `lv_label_set_text(label, MY_USB_SYMBOL)` searches for this symbol in the font defined in `style.text.font` properties. To use the symbol you may need to change it. Eg ` style.text.font = my_font_name`
|
||||
|
||||
## Load font in run-time
|
||||
`lv_font_load` can be used to load a font from a file. The font to load needs to have a special binary format. (Not TTF or WOFF).
|
||||
Use [lv_font_conv](https://github.com/lvgl/lv_font_conv/) with `--format bin` option to generate an LVGL compatible font file.
|
||||
|
||||
Note that to load a font [LVGL's filesystem](/overview/file-system) needs to be enabled and a driver needs to be added.
|
||||
|
||||
Example
|
||||
```c
|
||||
lv_font_t * my_font;
|
||||
my_font = lv_font_load(X/path/to/my_font.bin);
|
||||
|
||||
/*Use the font*/
|
||||
|
||||
/*Free the font if not required anymore*/
|
||||
lv_font_free(my_font);
|
||||
```
|
||||
|
||||
|
||||
## Add a new font engine
|
||||
|
||||
LVGL's font interface is designed to be very flexible.
|
||||
You don't need to use LVGL's internal font engine but, you can add your own.
|
||||
For example, use [FreeType](https://www.freetype.org/) to real-time render glyphs from TTF fonts or use an external flash to store the font's bitmap and read them when the library needs them.
|
||||
|
||||
A ready to use FreeType can be found in [lv_freetype](https://github.com/lvgl/lv_lib_freetype) repository.
|
||||
|
||||
To do this a custom `lv_font_t` variable needs to be created:
|
||||
```c
|
||||
/*Describe the properties of a font*/
|
||||
lv_font_t my_font;
|
||||
my_font.get_glyph_dsc = my_get_glyph_dsc_cb; /*Set a callback to get info about gylphs*/
|
||||
my_font.get_glyph_bitmap = my_get_glyph_bitmap_cb; /*Set a callback to get bitmap of a glyp*/
|
||||
my_font.line_height = height; /*The real line height where any text fits*/
|
||||
my_font.base_line = base_line; /*Base line measured from the top of line_height*/
|
||||
my_font.dsc = something_required; /*Store any implementation specific data here*/
|
||||
my_font.user_data = user_data; /*Optionally some extra user data*/
|
||||
|
||||
...
|
||||
|
||||
/* Get info about glyph of `unicode_letter` in `font` font.
|
||||
* Store the result in `dsc_out`.
|
||||
* The next letter (`unicode_letter_next`) might be used to calculate the width required by this glyph (kerning)
|
||||
*/
|
||||
bool my_get_glyph_dsc_cb(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next)
|
||||
{
|
||||
/*Your code here*/
|
||||
|
||||
/* Store the result.
|
||||
* For example ...
|
||||
*/
|
||||
dsc_out->adv_w = 12; /*Horizontal space required by the glyph in [px]*/
|
||||
dsc_out->box_h = 8; /*Height of the bitmap in [px]*/
|
||||
dsc_out->box_w = 6; /*Width of the bitmap in [px]*/
|
||||
dsc_out->ofs_x = 0; /*X offset of the bitmap in [pf]*/
|
||||
dsc_out->ofs_y = 3; /*Y offset of the bitmap measured from the as line*/
|
||||
dsc_out->bpp = 2; /*Bits per pixel: 1/2/4/8*/
|
||||
|
||||
return true; /*true: glyph found; false: glyph was not found*/
|
||||
}
|
||||
|
||||
|
||||
/* Get the bitmap of `unicode_letter` from `font`. */
|
||||
const uint8_t * my_get_glyph_bitmap_cb(const lv_font_t * font, uint32_t unicode_letter)
|
||||
{
|
||||
/* Your code here */
|
||||
|
||||
/* The bitmap should be a continuous bitstream where
|
||||
* each pixel is represented by `bpp` bits */
|
||||
|
||||
return bitmap; /*Or NULL if not found*/
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,357 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/image.md
|
||||
```
|
||||
# Images
|
||||
|
||||
An image can be a file or variable which stores the bitmap itself and some metadata.
|
||||
|
||||
## Store images
|
||||
You can store images in two places
|
||||
- as a variable in the internal memory (RAM or ROM)
|
||||
- as a file
|
||||
|
||||
### Variables
|
||||
The images stored internally in a variable is composed mainly of an `lv_img_dsc_t` structure with the following fields:
|
||||
- **header**
|
||||
- *cf* Color format. See [below](#color-format)
|
||||
- *w* width in pixels (<= 2048)
|
||||
- *h* height in pixels (<= 2048)
|
||||
- *always zero* 3 bits which need to be always zero
|
||||
- *reserved* reserved for future use
|
||||
- **data** pointer to an array where the image itself is stored
|
||||
- **data_size** length of `data` in bytes
|
||||
|
||||
These are usually stored within a project as C files. They are linked into the resulting executable like any other constant data.
|
||||
|
||||
### Files
|
||||
To deal with files you need to add a *Drive* to LVGL. In short, a *Drive* is a collection of functions (*open*, *read*, *close*, etc.) registered in LVGL to make file operations.
|
||||
You can add an interface to a standard file system (FAT32 on SD card) or you create your simple file system to read data from an SPI Flash memory.
|
||||
In every case, a *Drive* is just an abstraction to read and/or write data to a memory.
|
||||
See the [File system](/overview/file-system) section to learn more.
|
||||
|
||||
Images stored as files are not linked into the resulting executable, and must be read to RAM before being drawn. As a result, they are not as resource-friendly as variable images. However, they are easier to replace without needing to recompile the main program.
|
||||
|
||||
## Color formats
|
||||
Various built-in color formats are supported:
|
||||
- **LV_IMG_CF_TRUE_COLOR** Simply stores the RGB colors (in whatever color depth LVGL is configured for).
|
||||
- **LV_IMG_CF_TRUE_COLOR_ALPHA** Like `LV_IMG_CF_TRUE_COLOR` but it also adds an alpha (transparency) byte for every pixel.
|
||||
- **LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED** Like `LV_IMG_CF_TRUE_COLOR` but if a pixel has `LV_COLOR_TRANSP` (set in *lv_conf.h*) color the pixel will be transparent.
|
||||
- **LV_IMG_CF_INDEXED_1/2/4/8BIT** Uses a palette with 2, 4, 16 or 256 colors and stores each pixel in 1, 2, 4 or 8 bits.
|
||||
- **LV_IMG_CF_ALPHA_1/2/4/8BIT** **Only stores the Alpha value on 1, 2, 4 or 8 bits.** The pixels take the color of `style.image.color` and the set opacity. The source image has to be an alpha channel. This is ideal for bitmaps similar to fonts (where the whole image is one color but you'd like to be able to change it).
|
||||
|
||||
The bytes of the `LV_IMG_CF_TRUE_COLOR` images are stored in the following order.
|
||||
|
||||
For 32-bit color depth:
|
||||
- Byte 0: Blue
|
||||
- Byte 1: Green
|
||||
- Byte 2: Red
|
||||
- Byte 3: Alpha
|
||||
|
||||
For 16-bit color depth:
|
||||
- Byte 0: Green 3 lower bit, Blue 5 bit
|
||||
- Byte 1: Red 5 bit, Green 3 higher bit
|
||||
- Byte 2: Alpha byte (only with LV_IMG_CF_TRUE_COLOR_ALPHA)
|
||||
|
||||
For 8-bit color depth:
|
||||
- Byte 0: Red 3 bit, Green 3 bit, Blue 2 bit
|
||||
- Byte 2: Alpha byte (only with LV_IMG_CF_TRUE_COLOR_ALPHA)
|
||||
|
||||
|
||||
You can store images in a *Raw* format to indicate that, it's not a built-in color format and an external [Image decoder](#image-decoder) needs to be used to decode the image.
|
||||
- **LV_IMG_CF_RAW** Indicates a basic raw image (e.g. a PNG or JPG image).
|
||||
- **LV_IMG_CF_RAW_ALPHA** Indicates that the image has alpha and an alpha byte is added for every pixel.
|
||||
- **LV_IMG_CF_RAW_CHROME_KEYED** Indicates that the image is chrome keyed as described in `LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED` above.
|
||||
|
||||
|
||||
## Add and use images
|
||||
|
||||
You can add images to LVGL in two ways:
|
||||
- using the online converter
|
||||
- manually create images
|
||||
|
||||
### Online converter
|
||||
The online Image converter is available here: https://lvgl.io/tools/imageconverter
|
||||
|
||||
Adding an image to LVGL via online converter is easy.
|
||||
|
||||
1. You need to select a *BMP*, *PNG* or *JPG* image first.
|
||||
2. Give the image a name that will be used within LVGL.
|
||||
3. Select the [Color format](#color-formats).
|
||||
4. Select the type of image you want. Choosing a binary will generate a `.bin` file that must be stored separately and read using the [file support](#files). Choosing a variable will generate a standard C file that can be linked into your project.
|
||||
5. Hit the *Convert* button. Once the conversion is finished, your browser will automatically download the resulting file.
|
||||
|
||||
In the converter C arrays (variables), the bitmaps for all the color depths (1, 8, 16 or 32) are included in the C file, but only the color depth that matches `LV_COLOR_DEPTH` in *lv_conf.h* will actually be linked into the resulting executable.
|
||||
|
||||
In case of binary files, you need to specify the color format you want:
|
||||
- RGB332 for 8-bit color depth
|
||||
- RGB565 for 16-bit color depth
|
||||
- RGB565 Swap for 16-bit color depth (two bytes are swapped)
|
||||
- RGB888 for 32-bit color depth
|
||||
|
||||
### Manually create an image
|
||||
If you are generating an image at run-time, you can craft an image variable to display it using LVGL. For example:
|
||||
|
||||
```c
|
||||
uint8_t my_img_data[] = {0x00, 0x01, 0x02, ...};
|
||||
|
||||
static lv_img_dsc_t my_img_dsc = {
|
||||
.header.always_zero = 0,
|
||||
.header.w = 80,
|
||||
.header.h = 60,
|
||||
.data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
|
||||
.header.cf = LV_IMG_CF_TRUE_COLOR, /*Set the color format*/
|
||||
.data = my_img_data,
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
If the color format is `LV_IMG_CF_TRUE_COLOR_ALPHA` you can set `data_size` like `80 * 60 * LV_IMG_PX_SIZE_ALPHA_BYTE`.
|
||||
|
||||
Another (possibly simpler) option to create and display an image at run-time is to use the [Canvas](/widgets/canvas) object.
|
||||
|
||||
### Use images
|
||||
|
||||
The simplest way to use an image in LVGL is to display it with an [lv_img](/widgets/img) object:
|
||||
|
||||
```c
|
||||
lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
|
||||
|
||||
/*From variable*/
|
||||
lv_img_set_src(icon, &my_icon_dsc);
|
||||
|
||||
/*From file*/
|
||||
lv_img_set_src(icon, "S:my_icon.bin");
|
||||
```
|
||||
|
||||
If the image was converted with the online converter, you should use `LV_IMG_DECLARE(my_icon_dsc)` to declare the image in the file where you want to use it.
|
||||
|
||||
|
||||
## Image decoder
|
||||
As you can see in the [Color formats](#color-formats) section, LVGL supports several built-in image formats. In many cases, these will be all you need. LVGL doesn't directly support, however, generic image formats like PNG or JPG.
|
||||
|
||||
To handle non-built-in image formats, you need to use external libraries and attach them to LVGL via the *Image decoder* interface.
|
||||
|
||||
The image decoder consists of 4 callbacks:
|
||||
- **info** get some basic info about the image (width, height and color format).
|
||||
- **open** open the image: either store the decoded image or set it to `NULL` to indicate the image can be read line-by-line.
|
||||
- **read** if *open* didn't fully open the image this function should give some decoded data (max 1 line) from a given position.
|
||||
- **close** close the opened image, free the allocated resources.
|
||||
|
||||
You can add any number of image decoders. When an image needs to be drawn, the library will try all the registered image decoder until finding one which can open the image, i.e. knowing that format.
|
||||
|
||||
The `LV_IMG_CF_TRUE_COLOR_...`, `LV_IMG_INDEXED_...` and `LV_IMG_ALPHA_...` formats (essentially, all non-`RAW` formats) are understood by the built-in decoder.
|
||||
|
||||
### Custom image formats
|
||||
|
||||
The easiest way to create a custom image is to use the online image converter and set `Raw`, `Raw with alpha` or `Raw with chrome keyed` format. It will just take every byte of the binary file you uploaded and write it as the image "bitmap". You then need to attach an image decoder that will parse that bitmap and generate the real, renderable bitmap.
|
||||
|
||||
`header.cf` will be `LV_IMG_CF_RAW`, `LV_IMG_CF_RAW_ALPHA` or `LV_IMG_CF_RAW_CHROME_KEYED` accordingly. You should choose the correct format according to your needs: fully opaque image, use alpha channel or use chroma keying.
|
||||
|
||||
After decoding, the *raw* formats are considered *True color* by the library. In other words, the image decoder must decode the *Raw* images to *True color* according to the format described in [#color-formats](Color formats) section.
|
||||
|
||||
If you want to create a custom image, you should use `LV_IMG_CF_USER_ENCODED_0..7` color formats. However, the library can draw the images only in *True color* format (or *Raw* but finally it's supposed to be in *True color* format).
|
||||
So the `LV_IMG_CF_USER_ENCODED_...` formats are not known by the library, therefore, they should be decoded to one of the known formats from [#color-formats](Color formats) section.
|
||||
It's possible to decode the image to a non-true color format first, for example, `LV_IMG_INDEXED_4BITS`, and then call the built-in decoder functions to convert it to *True color*.
|
||||
|
||||
With *User encoded* formats, the color format in the open function (`dsc->header.cf`) should be changed according to the new format.
|
||||
|
||||
|
||||
### Register an image decoder
|
||||
|
||||
Here's an example of getting LVGL to work with PNG images.
|
||||
|
||||
First, you need to create a new image decoder and set some functions to open/close the PNG files. It should looks like this:
|
||||
|
||||
```c
|
||||
/*Create a new decoder and register functions */
|
||||
lv_img_decoder_t * dec = lv_img_decoder_create();
|
||||
lv_img_decoder_set_info_cb(dec, decoder_info);
|
||||
lv_img_decoder_set_open_cb(dec, decoder_open);
|
||||
lv_img_decoder_set_close_cb(dec, decoder_close);
|
||||
|
||||
|
||||
/**
|
||||
* Get info about a PNG image
|
||||
* @param decoder pointer to the decoder where this function belongs
|
||||
* @param src can be file name or pointer to a C array
|
||||
* @param header store the info here
|
||||
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
|
||||
*/
|
||||
static lv_res_t decoder_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
|
||||
{
|
||||
/*Check whether the type `src` is known by the decoder*/
|
||||
if(is_png(src) == false) return LV_RES_INV;
|
||||
|
||||
/* Read the PNG header and find `width` and `height` */
|
||||
...
|
||||
|
||||
header->cf = LV_IMG_CF_RAW_ALPHA;
|
||||
header->w = width;
|
||||
header->h = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a PNG image and return the decided image
|
||||
* @param decoder pointer to the decoder where this function belongs
|
||||
* @param dsc pointer to a descriptor which describes this decoding session
|
||||
* @return LV_RES_OK: no error; LV_RES_INV: can't get the info
|
||||
*/
|
||||
static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
|
||||
/*Check whether the type `src` is known by the decoder*/
|
||||
if(is_png(src) == false) return LV_RES_INV;
|
||||
|
||||
/*Decode and store the image. If `dsc->img_data` is `NULL`, the `read_line` function will be called to get the image data line-by-line*/
|
||||
dsc->img_data = my_png_decoder(src);
|
||||
|
||||
/*Change the color format if required. For PNG usually 'Raw' is fine*/
|
||||
dsc->header.cf = LV_IMG_CF_...
|
||||
|
||||
/*Call a built in decoder function if required. It's not required if`my_png_decoder` opened the image in true color format.*/
|
||||
lv_res_t res = lv_img_decoder_built_in_open(decoder, dsc);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
|
||||
* Required only if the "open" function can't open the whole decoded pixel array. (dsc->img_data == NULL)
|
||||
* @param decoder pointer to the decoder the function associated with
|
||||
* @param dsc pointer to decoder descriptor
|
||||
* @param x start x coordinate
|
||||
* @param y start y coordinate
|
||||
* @param len number of pixels to decode
|
||||
* @param buf a buffer to store the decoded pixels
|
||||
* @return LV_RES_OK: ok; LV_RES_INV: failed
|
||||
*/
|
||||
lv_res_t decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
|
||||
lv_coord_t y, lv_coord_t len, uint8_t * buf)
|
||||
{
|
||||
/*With PNG it's usually not required*/
|
||||
|
||||
/*Copy `len` pixels from `x` and `y` coordinates in True color format to `buf` */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the allocated resources
|
||||
* @param decoder pointer to the decoder where this function belongs
|
||||
* @param dsc pointer to a descriptor which describes this decoding session
|
||||
*/
|
||||
static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
/*Free all allocated data*/
|
||||
|
||||
/*Call the built-in close function if the built-in open/read_line was used*/
|
||||
lv_img_decoder_built_in_close(decoder, dsc);
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
So in summary:
|
||||
- In `decoder_info`, you should collect some basic information about the image and store it in `header`.
|
||||
- In `decoder_open`, you should try to open the image source pointed by `dsc->src`. Its type is already in `dsc->src_type == LV_IMG_SRC_FILE/VARIABLE`.
|
||||
If this format/type is not supported by the decoder, return `LV_RES_INV`.
|
||||
However, if you can open the image, a pointer to the decoded *True color* image should be set in `dsc->img_data`.
|
||||
If the format is known but, you don't want to decode while image (e.g. no memory for it) set `dsc->img_data = NULL` to call `read_line` to get the pixels.
|
||||
- In `decoder_close` you should free all the allocated resources.
|
||||
- `decoder_read` is optional. Decoding the whole image requires extra memory and some computational overhead.
|
||||
However, if can decode one line of the image without decoding the whole image, you can save memory and time.
|
||||
To indicate that, the *line read* function should be used, set `dsc->img_data = NULL` in the open function.
|
||||
|
||||
|
||||
### Manually use an image decoder
|
||||
|
||||
LVGL will use the registered image decoder automatically if you try and draw a raw image (i.e. using the `lv_img` object) but you can use them manually too. Create a `lv_img_decoder_dsc_t` variable to describe the decoding session and call `lv_img_decoder_open()`.
|
||||
|
||||
```c
|
||||
|
||||
lv_res_t res;
|
||||
lv_img_decoder_dsc_t dsc;
|
||||
res = lv_img_decoder_open(&dsc, &my_img_dsc, LV_COLOR_WHITE);
|
||||
|
||||
if(res == LV_RES_OK) {
|
||||
/*Do something with `dsc->img_data`*/
|
||||
lv_img_decoder_close(&dsc);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Image caching
|
||||
Sometimes it takes a lot of time to open an image.
|
||||
Continuously decoding a PNG image or loading images from a slow external memory would be inefficient and detrimental to the user experience.
|
||||
|
||||
Therefore, LVGL caches a given number of images. Caching means some images will be left open, hence LVGL can quickly access them from `dsc->img_data` instead of needing to decode them again.
|
||||
|
||||
Of course, caching images is resource-intensive as it uses more RAM (to store the decoded image). LVGL tries to optimize the process as much as possible (see below), but you will still need to evaluate if this would be beneficial for your platform or not. If you have a deeply embedded target which decodes small images from a relatively fast storage medium, image caching may not be worth it.
|
||||
|
||||
### Cache size
|
||||
The number of cache entries can be defined in `LV_IMG_CACHE_DEF_SIZE` in *lv_conf.h*. The default value is 1 so only the most recently used image will be left open.
|
||||
|
||||
The size of the cache can be changed at run-time with `lv_img_cache_set_size(entry_num)`.
|
||||
|
||||
### Value of images
|
||||
When you use more images than cache entries, LVGL can't cache all of the images. Instead, the library will close one of the cached images (to free space).
|
||||
|
||||
To decide which image to close, LVGL uses a measurement it previously made of how long it took to open the image. Cache entries that hold slower-to-open images are considered more valuable and are kept in the cache as long as possible.
|
||||
|
||||
If you want or need to override LVGL's measurement, you can manually set the *time to open* value in the decoder open function in `dsc->time_to_open = time_ms` to give a higher or lower value. (Leave it unchanged to let LVGL set it.)
|
||||
|
||||
Every cache entry has a *"life"* value. Every time an image opening happens through the cache, the *life* of all entries are decreased to make them older.
|
||||
When a cached image is used, its *life* is increased by the *time to open* value to make it more alive.
|
||||
|
||||
If there is no more space in the cache, always the entry with the smallest life will be closed.
|
||||
|
||||
### Memory usage
|
||||
Note that, the cached image might continuously consume memory. For example, if 3 PNG images are cached, they will consume memory while they are opened.
|
||||
|
||||
Therefore, it's the user's responsibility to be sure there is enough RAM to cache, even the largest images at the same time.
|
||||
|
||||
### Clean the cache
|
||||
Let's say you have loaded a PNG image into a `lv_img_dsc_t my_png` variable and use it in an `lv_img` object. If the image is already cached and you then change the underlying PNG file, you need to notify LVGL to cache the image again. Otherwise, there is no easy way of detecting that the underlying file changed and LVGL will still draw the old image.
|
||||
|
||||
To do this, use `lv_img_cache_invalidate_src(&my_png)`. If `NULL` is passed as a parameter, the whole cache will be cleaned.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### Image decoder
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_img_decoder.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Image cache
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_img_cache.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
|
||||
### Image buffer
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_img_buf.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
|
||||
### Image draw
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_draw_img.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,112 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/indev.md
|
||||
```
|
||||
# Input devices
|
||||
|
||||
An input device usually means:
|
||||
- Pointer-like input device like touchpad or mouse
|
||||
- Keypads like a normal keyboard or simple numeric keypad
|
||||
- Encoders with left/right turn and push options
|
||||
- External hardware buttons which are assigned to specific points on the screen
|
||||
|
||||
|
||||
``` important:: Before reading further, please read the [Porting](/porting/indev) section of Input devices
|
||||
```
|
||||
|
||||
## Pointers
|
||||
|
||||
Pointer input devices can have a cursor. (typically for mouses)
|
||||
|
||||
```c
|
||||
...
|
||||
lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
|
||||
|
||||
LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
|
||||
lv_obj_t * cursor_obj = lv_img_create(lv_scr_act(), NULL); /*Create an image object for the cursor */
|
||||
lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
|
||||
lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/
|
||||
|
||||
```
|
||||
|
||||
Note that the cursor object should have `lv_obj_set_click(cursor_obj, false)`.
|
||||
For images, *clicking* is disabled by default.
|
||||
|
||||
## Keypad and encoder
|
||||
|
||||
You can fully control the user interface without touchpad or mouse using a keypad or encoder(s). It works similar to the *TAB* key on the PC to select the element in an application or a web page.
|
||||
|
||||
### Groups
|
||||
|
||||
The objects, you want to control with keypad or encoder, needs to be added to a *Group*.
|
||||
In every group, there is exactly one focused object which receives the pressed keys or the encoder actions.
|
||||
For example, if a [Text area](/widgets/textarea) is focused and you press some letter on a keyboard, the keys will be sent and inserted into the text area.
|
||||
Similarly, if a [Slider](/widgets/slider) is focused and you press the left or right arrows, the slider's value will be changed.
|
||||
|
||||
You need to associate an input device with a group. An input device can send the keys to only one group but, a group can receive data from more than one input device too.
|
||||
|
||||
To create a group use `lv_group_t * g = lv_group_create()` and to add an object to the group use `lv_group_add_obj(g, obj)`.
|
||||
|
||||
To associate a group with an input device use `lv_indev_set_group(indev, g)`, where `indev` is the return value of `lv_indev_drv_register()`
|
||||
|
||||
#### Keys
|
||||
There are some predefined keys which have special meaning:
|
||||
- **LV_KEY_NEXT** Focus on the next object
|
||||
- **LV_KEY_PREV** Focus on the previous object
|
||||
- **LV_KEY_ENTER** Triggers `LV_EVENT_PRESSED/CLICKED/LONG_PRESSED` etc. events
|
||||
- **LV_KEY_UP** Increase value or move upwards
|
||||
- **LV_KEY_DOWN** Decrease value or move downwards
|
||||
- **LV_KEY_RIGHT** Increase value or move the the right
|
||||
- **LV_KEY_LEFT** Decrease value or move the the left
|
||||
- **LV_KEY_ESC** Close or exit (E.g. close a [Drop down list](/widgets/dropdown))
|
||||
- **LV_KEY_DEL** Delete (E.g. a character on the right in a [Text area](/widgets/textarea))
|
||||
- **LV_KEY_BACKSPACE** Delete a character on the left (E.g. in a [Text area](/widgets/textarea))
|
||||
- **LV_KEY_HOME** Go to the beginning/top (E.g. in a [Text area](/widgets/textarea))
|
||||
- **LV_KEY_END** Go to the end (E.g. in a [Text area](/widgets/textarea)))
|
||||
|
||||
The most important special keys are `LV_KEY_NEXT/PREV`, `LV_KEY_ENTER` and `LV_KEY_UP/DOWN/LEFT/RIGHT`.
|
||||
In your `read_cb` function, you should translate some of your keys to these special keys to navigate in the group and interact with the selected object.
|
||||
|
||||
Usually, it's enough to use only `LV_KEY_LEFT/RIGHT` because most of the objects can be fully controlled with them.
|
||||
|
||||
With an encoder, you should use only `LV_KEY_LEFT`, `LV_KEY_RIGHT`, and `LV_KEY_ENTER`.
|
||||
|
||||
#### Edit and navigate mode
|
||||
|
||||
Since a keypad has plenty of keys, it's easy to navigate between the objects and edit them using the keypad. But, the encoders have a limited number of "keys" hence, it is difficult to navigate using the default options. *Navigate* and *Edit* are created to avoid this problem with the encoders.
|
||||
|
||||
In *Navigate* mode, the encoders `LV_KEY_LEFT/RIGHT` is translated to `LV_KEY_NEXT/PREV`. Therefore the next or previous object will be selected by turning the encoder.
|
||||
Pressing `LV_KEY_ENTER` will change to *Edit* mode.
|
||||
|
||||
In *Edit* mode, `LV_KEY_NEXT/PREV` is usually used to edit the object.
|
||||
Depending on the object's type, a short or long press of `LV_KEY_ENTER` changes back to *Navigate* mode.
|
||||
Usually, an object which can not be pressed (like a [Slider](/widgets/slider)) leaves *Edit* mode on short click. But with objects where short click has meaning (e.g. [Button](/widgets/btn)), a long press is required.
|
||||
|
||||
### Styling
|
||||
|
||||
If an object is focused either by clicking it via touchpad, or focused via an encoder or keypad it goes to `LV_STATE_FOCUSED`. Hence focused styles will be applied on it.
|
||||
|
||||
If the object goes to edit mode it goes to `LV_STATE_FOCUSED | LV_STATE_EDITED` state so these style properties will be shown.
|
||||
|
||||
For a more detaild description read the [Style](https://docs.lvgl.io/v7/en/html/overview/style.html) section.
|
||||
|
||||
## API
|
||||
|
||||
|
||||
### Input device
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_indev.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
|
||||
### Groups
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_group.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,27 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/index.md
|
||||
```
|
||||
|
||||
# Overview
|
||||
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
object
|
||||
layer
|
||||
event
|
||||
style
|
||||
indev
|
||||
display
|
||||
font
|
||||
image
|
||||
file-system
|
||||
animation
|
||||
task
|
||||
drawing
|
||||
```
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/layer.md
|
||||
```
|
||||
|
||||
# Layers
|
||||
|
||||
## Order of creation
|
||||
|
||||
By default, LVGL draws old objects on the background and new objects on the foreground.
|
||||
|
||||
For example, assume we added a button to a parent object named button1 and then another button named button2. Then button1 (with its child object(s)) will be in the background and can be covered by button2 and its children.
|
||||
|
||||
|
||||

|
||||
|
||||
```c
|
||||
/*Create a screen*/
|
||||
lv_obj_t * scr = lv_obj_create(NULL, NULL);
|
||||
lv_scr_load(scr); /*Load the screen*/
|
||||
|
||||
/*Create 2 buttons*/
|
||||
lv_obj_t * btn1 = lv_btn_create(scr, NULL); /*Create a button on the screen*/
|
||||
lv_btn_set_fit(btn1, true, true); /*Enable to automatically set the size according to the content*/
|
||||
lv_obj_set_pos(btn1, 60, 40); /*Set the position of the button*/
|
||||
|
||||
lv_obj_t * btn2 = lv_btn_create(scr, btn1); /*Copy the first button*/
|
||||
lv_obj_set_pos(btn2, 180, 80); /*Set the position of the button*/
|
||||
|
||||
/*Add labels to the buttons*/
|
||||
lv_obj_t * label1 = lv_label_create(btn1, NULL); /*Create a label on the first button*/
|
||||
lv_label_set_text(label1, "Button 1"); /*Set the text of the label*/
|
||||
|
||||
lv_obj_t * label2 = lv_label_create(btn2, NULL); /*Create a label on the second button*/
|
||||
lv_label_set_text(label2, "Button 2"); /*Set the text of the label*/
|
||||
|
||||
/*Delete the second label*/
|
||||
lv_obj_del(label2);
|
||||
```
|
||||
|
||||
## Bring to the foreground
|
||||
|
||||
There are several ways to bring an object to the foreground:
|
||||
- Use `lv_obj_set_top(obj, true)`. If `obj` or any of its children is clicked, then LVGL will automatically bring the object to the foreground.
|
||||
It works similarly to a typical GUI on a PC. When a window in the background is clicked, it will come to the foreground automatically.
|
||||
- Use `lv_obj_move_foreground(obj)` to explicitly tell the library to bring an object to the foreground. Similarly, use `lv_obj_move_background(obj)` to move to the background.
|
||||
- When `lv_obj_set_parent(obj, new_parent)` is used, `obj` will be on the foreground on the `new_parent`.
|
||||
|
||||
|
||||
## Top and sys layers
|
||||
|
||||
LVGL uses two special layers named as `layer_top` and `layer_sys`.
|
||||
Both are visible and common on all screens of a display. **They are not, however, shared among multiple physical displays.** The `layer_top` is always on top of the default screen (`lv_scr_act()`), and `layer_sys` is on top of `layer_top`.
|
||||
|
||||
The `layer_top` can be used by the user to create some content visible everywhere. For example, a menu bar, a pop-up, etc. If the `click` attribute is enabled, then `layer_top` will absorb all user click and acts as a modal.
|
||||
```c
|
||||
lv_obj_set_click(lv_layer_top(), true);
|
||||
```
|
||||
|
||||
The `layer_sys` is also used for a similar purpose on LVGL. For example, it places the mouse cursor above all layers to be sure it's always visible.
|
||||
@@ -0,0 +1,195 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/object.md
|
||||
```
|
||||
# Objects
|
||||
|
||||
In the LVGL the **basic building blocks** of a user interface are the objects, also called *Widgets*.
|
||||
For example a [Button](/widgets/btn), [Label](/widgets/label), [Image](/widgets/img), [List](/widgets/list), [Chart](/widgets/chart) or [Text area](/widgets/textarea).
|
||||
|
||||
Check all the [Object types](/widgets/index) here.
|
||||
|
||||
## Attributes
|
||||
|
||||
### Basic attributes
|
||||
|
||||
All object types share some basic attributes:
|
||||
- Position
|
||||
- Size
|
||||
- Parent
|
||||
- Drag enable
|
||||
- Click enable etc.
|
||||
|
||||
You can set/get these attributes with `lv_obj_set_...` and `lv_obj_get_...` functions. For example:
|
||||
|
||||
```c
|
||||
/*Set basic object attributes*/
|
||||
lv_obj_set_size(btn1, 100, 50); /*Button size*/
|
||||
lv_obj_set_pos(btn1, 20,30); /*Button position*/
|
||||
```
|
||||
|
||||
To see all the available functions visit the Base object's [documentation](/widgets/obj).
|
||||
|
||||
### Specific attributes
|
||||
|
||||
The object types have special attributes too. For example, a slider has
|
||||
- Min. max. values
|
||||
- Current value
|
||||
- Custom styles
|
||||
|
||||
For these attributes, every object type have unique API functions. For example for a slider:
|
||||
|
||||
```c
|
||||
/*Set slider specific attributes*/
|
||||
lv_slider_set_range(slider1, 0, 100); /*Set min. and max. values*/
|
||||
lv_slider_set_value(slider1, 40, LV_ANIM_ON); /*Set the current value (position)*/
|
||||
lv_slider_set_action(slider1, my_action); /*Set a callback function*/
|
||||
```
|
||||
|
||||
The API of the object types are described in their [Documentation](/widgets/index) but you can also check the respective header files (e.g. *lv_objx/lv_slider.h*)
|
||||
|
||||
## Working mechanisms
|
||||
|
||||
### 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 an unlimited number of children.
|
||||
There is no limitation for the type of the parent but, there are typical parent (e.g. button) and typical child (e.g. label) objects.
|
||||
|
||||
### Moving together
|
||||
|
||||
If the position of the parent is changed the children will move with the parent.
|
||||
Therefore all positions are relative to the parent.
|
||||
|
||||
The (0;0) coordinates mean the objects will remain in the top left-hand corner of the parent independently from the position of the parent.
|
||||
|
||||

|
||||
|
||||
```c
|
||||
lv_obj_t * par = lv_obj_create(lv_scr_act(), NULL); /*Create a parent object on the current screen*/
|
||||
lv_obj_set_size(par, 100, 80); /*Set the size of the parent*/
|
||||
|
||||
lv_obj_t * obj1 = lv_obj_create(par, NULL); /*Create an object on the previously created parent object*/
|
||||
lv_obj_set_pos(obj1, 10, 10); /*Set the position of the new object*/
|
||||
```
|
||||
|
||||
Modify the position of the parent:
|
||||
|
||||

|
||||
|
||||
```c
|
||||
lv_obj_set_pos(par, 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.)
|
||||
|
||||
### Visibility only on the parent
|
||||
|
||||
If a child is partially or fully out of its parent then the parts outside will not be visible.
|
||||
|
||||

|
||||
|
||||
```c
|
||||
lv_obj_set_x(obj1, -30); /*Move the child a little bit of the parent*/
|
||||
```
|
||||
|
||||
### Create - delete objects
|
||||
|
||||
In LVGL objects can be created and deleted dynamically in run-time.
|
||||
It means only the currently created objects consume RAM.
|
||||
For example, if you need a chart, you can create it when required and delete it when it is not visible or necessary.
|
||||
|
||||
Every object type has its own **create** function with a unified prototype.
|
||||
It needs two parameters:
|
||||
- A pointer to the *parent* object. To create a screen give *NULL* as parent.
|
||||
- Optionally, a pointer to *copy* object with the same type to copy it. This *copy* object can be *NULL* to avoid the copy operation.
|
||||
|
||||
All objects are referenced in C code using an `lv_obj_t` pointer as a handle. This pointer can later be used to set or get the attributes of the object.
|
||||
|
||||
The create functions look like this:
|
||||
|
||||
```c
|
||||
lv_obj_t * lv_ <type>_create(lv_obj_t * parent, lv_obj_t * copy);
|
||||
```
|
||||
|
||||
There is a common **delete** function for all object types. It deletes the object and all of its children.
|
||||
|
||||
```c
|
||||
void lv_obj_del(lv_obj_t * obj);
|
||||
```
|
||||
|
||||
`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)`.
|
||||
It is useful e.g. if you want to delete the parent of an object in the child's `LV_EVENT_DELETE` signal.
|
||||
|
||||
You can remove all the children of an object (but not the object itself) using `lv_obj_clean`:
|
||||
|
||||
```c
|
||||
void lv_obj_clean(lv_obj_t * obj);
|
||||
```
|
||||
|
||||
## Screens
|
||||
|
||||
### Create screens
|
||||
The screens are special objects which have no parent object. So they can be created like:
|
||||
```c
|
||||
lv_obj_t * scr1 = lv_obj_create(NULL, NULL);
|
||||
```
|
||||
|
||||
Screens can be created with any object type. For example, a [Base object](/widgets/obj) or an image to make a wallpaper.
|
||||
|
||||
### Get the active screen
|
||||
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
|
||||
|
||||
To load a new screen, use `lv_scr_load(scr1)`.
|
||||
|
||||
#### Load screen with animation
|
||||
|
||||
A new screen can be loaded with animation too 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` ms
|
||||
- `LV_SCR_LOAD_ANIM_OVER_LEFT/RIGHT/TOP/BOTTOM` move the new screen over the other towards the given direction
|
||||
- `LV_SCR_LOAD_ANIM_MOVE_LEFT/RIGHT/TOP/BOTTOM` move both the old and new screens towards the given direction
|
||||
- `LV_SCR_LOAD_ANIM_FADE_ON` fade the new screen over the old screen
|
||||
|
||||
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 animations starts after `delay` time.
|
||||
|
||||
### Handling multiple displays
|
||||
Screens are created on the currently selected *default display*.
|
||||
The *default display* is the last registered display with `lv_disp_drv_register` or you can 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](/overview/display) to learn more.
|
||||
|
||||
## Parts
|
||||
|
||||
The widgets can have multiple parts. For example a [Button](/widgets/btn) has only a main part but a [Slider](/widgets/slider) is built from a background, an indicator and a knob.
|
||||
|
||||
The name of the parts is constructed like `LV_ + <TYPE> _PART_ <NAME>`. For example `LV_BTN_PART_MAIN` or `LV_SLIDER_PART_KNOB`. The parts are usually used when styles are add to the objects.
|
||||
Using parts different styles can be assigned to the different parts of the objects.
|
||||
|
||||
To learn more about the parts read the related section of the [Style overview](/overview/style#parts).
|
||||
|
||||
|
||||
## States
|
||||
The object can be in a combinations of the following states:
|
||||
- **LV_STATE_DEFAULT** Normal, released
|
||||
- **LV_STATE_CHECKED** Toggled or checked
|
||||
- **LV_STATE_FOCUSED** Focused via keypad or encoder or clicked via touchpad/mouse
|
||||
- **LV_STATE_EDITED** Edit by an encoder
|
||||
- **LV_STATE_HOVERED** Hovered by mouse (not supported now)
|
||||
- **LV_STATE_PRESSED** Pressed
|
||||
- **LV_STATE_DISABLED** Disabled or inactive
|
||||
|
||||
The states are usually automatically changed by the library as the user presses, releases, focuses etc an object.
|
||||
However, the states can be changed manually too. To completely overwrite the current state use `lv_obj_set_state(obj, part, LV_STATE...)`.
|
||||
To set or clear given state (but leave to other states untouched) use `lv_obj_add/clear_state(obj, part, LV_STATE_...)`
|
||||
In both cases ORed state values can be used as well. E.g. `lv_obj_set_state(obj, part, LV_STATE_PRESSED | LV_PRESSED_CHECKED)`.
|
||||
|
||||
To learn more about the states read the related section of the [Style overview](/overview/style#states).
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/task.md
|
||||
```
|
||||
# Tasks
|
||||
|
||||
LVGL has a built-in task system. You can register a function to have it be called periodically. The tasks are handled and called in `lv_task_handler()`, which needs to be called periodically every few milliseconds.
|
||||
See [Porting](/porting/task-handler) for more information.
|
||||
|
||||
The tasks are non-preemptive, which means a task cannot interrupt another task. Therefore, you can call any LVGL related function in a task.
|
||||
|
||||
|
||||
## Create a task
|
||||
To create a new task, use `lv_task_create(task_cb, period_ms, LV_TASK_PRIO_OFF/LOWEST/LOW/MID/HIGH/HIGHEST, user_data)`. It will create an `lv_task_t *` variable, which can be used later to modify the parameters of the task.
|
||||
`lv_task_create_basic()` can also be used. It allows you to create a new task without specifying any parameters.
|
||||
|
||||
A task callback should have `void (*lv_task_cb_t)(lv_task_t *);` prototype.
|
||||
|
||||
For example:
|
||||
```c
|
||||
void my_task(lv_task_t * task)
|
||||
{
|
||||
/*Use the user_data*/
|
||||
uint32_t * user_data = task->user_data;
|
||||
printf("my_task called with user data: %d\n", *user_data);
|
||||
|
||||
/*Do something with LVGL*/
|
||||
if(something_happened) {
|
||||
something_happened = false;
|
||||
lv_btn_create(lv_scr_act(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
static uint32_t user_data = 10;
|
||||
lv_task_t * task = lv_task_create(my_task, 500, LV_TASK_PRIO_MID, &user_data);
|
||||
|
||||
```
|
||||
|
||||
## Ready and Reset
|
||||
|
||||
`lv_task_ready(task)` makes the task run on the next call of `lv_task_handler()`.
|
||||
|
||||
`lv_task_reset(task)` resets the period of a task. It will be called again after the defined period of milliseconds has elapsed.
|
||||
|
||||
|
||||
## Set parameters
|
||||
You can modify some parameters of the tasks later:
|
||||
- `lv_task_set_cb(task, new_cb)`
|
||||
- `lv_task_set_period(task, new_period)`
|
||||
- `lv_task_set_prio(task, new_priority)`
|
||||
|
||||
## One-shot tasks
|
||||
|
||||
You can make a task to run only once by calling`lv_task_once(task)`. The task will automatically be deleted after being called for the first time.
|
||||
|
||||
|
||||
## Measure idle time
|
||||
|
||||
You can get the idle percentage time `lv_task_handler` with `lv_task_get_idle()`. Note that, it doesn't measure the idle time of the overall system, only `lv_task_handler`.
|
||||
It can be misleading if you use an operating system and call `lv_task_handler` in an task, as it won't actually measure the time the OS spends in an idle thread.
|
||||
|
||||
## Asynchronous calls
|
||||
|
||||
In some cases, you can't do an action immediately. For example, you can't delete an object right now because something else is still using it or you don't want to block the execution now.
|
||||
For these cases, you can use the `lv_async_call(my_function, data_p)` to make `my_function` be called on the next call of `lv_task_handler`. `data_p` will be passed to function when it's called.
|
||||
Note that, only the pointer of the data is saved so you need to ensure that the variable will be "alive" while the function is called. You can use *static*, global or dynamically allocated data.
|
||||
|
||||
For example:
|
||||
```c
|
||||
void my_screen_clean_up(void * scr)
|
||||
{
|
||||
/*Free some resources related to `scr`*/
|
||||
|
||||
/*Finally delete the screen*/
|
||||
lv_obj_del(scr);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
/*Do somethings with the object on the current screen*/
|
||||
|
||||
/*Delete screen on next call of `lv_task_handler`. So not now.*/
|
||||
lv_async_call(my_screen_clean_up, lv_scr_act());
|
||||
|
||||
/*The screen is still valid so you can do other things with it*/
|
||||
|
||||
```
|
||||
|
||||
If you just want to delete an object, and don't need to clean anything up in `my_screen_cleanup`, you could just use `lv_obj_del_async`, which will delete the object on the next call to `lv_task_handler`.
|
||||
|
||||
## API
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_task.h
|
||||
:project: lvgl
|
||||
|
||||
.. doxygenfile:: lv_async.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,179 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/porting/display.md
|
||||
```
|
||||
# Display interface
|
||||
|
||||
To set up a display an `lv_disp_buf_t` and an `lv_disp_drv_t` variables have to be initialized.
|
||||
- **lv_disp_buf_t** contains internal graphic buffer(s).
|
||||
- **lv_disp_drv_t** contains callback functions to interact with the display and manipulate drawing related things.
|
||||
|
||||
|
||||
## Display buffer
|
||||
|
||||
`lv_disp_buf_t` can be initialized like this:
|
||||
```c
|
||||
/*A static or global variable to store the buffers*/
|
||||
static lv_disp_buf_t disp_buf;
|
||||
|
||||
/*Static or global buffer(s). The second buffer is optional*/
|
||||
static lv_color_t buf_1[MY_DISP_HOR_RES * 10];
|
||||
static lv_color_t buf_2[MY_DISP_HOR_RES * 10];
|
||||
|
||||
/*Initialize `disp_buf` with the buffer(s) */
|
||||
lv_disp_buf_init(&disp_buf, buf_1, buf_2, MY_DISP_HOR_RES*10);
|
||||
```
|
||||
|
||||
There are 3 possible configurations regarding the buffer size:
|
||||
1. **One buffer** LVGL draws the content of the screen into a buffer and sends it to the display.
|
||||
The buffer can be smaller than the screen. In this case, the larger areas will be redrawn in multiple parts.
|
||||
If only small areas changes (e.g. button press) then only those areas will be refreshed.
|
||||
2. **Two non-screen-sized buffers** having two buffers LVGL can draw into one buffer while the content of the other buffer is sent to display in the background.
|
||||
DMA or other hardware should be used to transfer the data to the display to let the CPU draw meanwhile.
|
||||
This way the rendering and refreshing of the display become parallel.
|
||||
Similarly to the *One buffer*, LVGL will draw the display's content in chunks if the buffer is smaller than the area to refresh.
|
||||
3. **Two screen-sized buffers**.
|
||||
In contrast to *Two non-screen-sized buffers* LVGL will always provide the whole screen's content not only chunks.
|
||||
This way the driver can simply change the address of the frame buffer to the buffer received from LVGL.
|
||||
Therefore this method works the best when the MCU has an LCD/TFT interface and the frame buffer is just a location in the RAM.
|
||||
|
||||
You can measure the performance of your display configuration using the [benchmark example](https://github.com/lvgl/lv_examples/tree/master/src/lv_demo_benchmark).
|
||||
|
||||
## Display driver
|
||||
|
||||
Once the buffer initialization is ready the display drivers need to be initialized. In the most simple case only the following two fields of `lv_disp_drv_t` needs to be set:
|
||||
- **buffer** pointer to an initialized `lv_disp_buf_t` variable.
|
||||
- **flush_cb** a callback function to copy a buffer's content to a specific area of the display. `lv_disp_flush_ready()` needs to be called when flushing is ready. LVGL might render the screen in multiple chunks and therefore call `flush_cb` multiple times. To see which is the last chunk of rendering use `lv_disp_flush_is_last()`.
|
||||
|
||||
There are some optional data fields:
|
||||
- **hor_res** horizontal resolution of the display. (`LV_HOR_RES_MAX` by default from *lv_conf.h*).
|
||||
- **ver_res** vertical resolution of the display. (`LV_VER_RES_MAX` by default from *lv_conf.h*).
|
||||
- **color_chroma_key** a color which will be drawn as transparent on chrome keyed images. `LV_COLOR_TRANSP` by default from *lv_conf.h*).
|
||||
- **user_data** custom user data for the driver. Its type can be modified in lv_conf.h.
|
||||
- **anti-aliasing** use anti-aliasing (edge smoothing). `LV_ANTIALIAS` by default from *lv_conf.h*.
|
||||
- **rotated** and **sw_rotate** See the [rotation](#rotation) section below.
|
||||
- **screen_transp** if `1` the screen can have transparent or opaque style. `LV_COLOR_SCREEN_TRANSP` needs to enabled in *lv_conf.h*.
|
||||
|
||||
To use a GPU the following callbacks can be used:
|
||||
- **gpu_fill_cb** fill an area in memory with colors.
|
||||
- **gpu_blend_cb** blend two memory buffers using opacity.
|
||||
- **gpu_wait_cb** if any GPU function return, while the GPU is still working LVGL, will use this function when required the be sure GPU rendering is ready.
|
||||
|
||||
Note that, these functions need to draw to the memory (RAM) and not your display directly.
|
||||
|
||||
Some other optional callbacks to make easier and more optimal to work with monochrome, grayscale or other non-standard RGB displays:
|
||||
- **rounder_cb** round the coordinates of areas to redraw. E.g. a 2x2 px can be converted to 2x8.
|
||||
It can be used if the display controller can refresh only areas with specific height or width (usually 8 px height with monochrome displays).
|
||||
- **set_px_cb** a custom function to write the *display buffer*.
|
||||
It can be used to store the pixels more compactly if the display has a special color format. (e.g. 1-bit monochrome, 2-bit grayscale etc.)
|
||||
This way the buffers used in `lv_disp_buf_t` can be smaller to hold only the required number of bits for the given area size. `set_px_cb` is not working with `Two screen-sized buffers` display buffer configuration.
|
||||
- **monitor_cb** a callback function tells how many pixels were refreshed in how much time.
|
||||
- **clean_dcache_cb** a callback for cleaning any caches related to the display
|
||||
|
||||
To set the fields of *lv_disp_drv_t* variable it needs to be initialized with `lv_disp_drv_init(&disp_drv)`.
|
||||
And finally to register a display for LVGL `lv_disp_drv_register(&disp_drv)` needs to be called.
|
||||
|
||||
All together it looks like this:
|
||||
```c
|
||||
lv_disp_drv_t disp_drv; /*A variable to hold the drivers. Can be local variable*/
|
||||
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
|
||||
disp_drv.buffer = &disp_buf; /*Set an initialized buffer*/
|
||||
disp_drv.flush_cb = my_flush_cb; /*Set a flush callback to draw to the display*/
|
||||
lv_disp_t * disp;
|
||||
disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created display objects*/
|
||||
```
|
||||
|
||||
Here some simple examples of the callbacks:
|
||||
```c
|
||||
void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
|
||||
{
|
||||
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
|
||||
int32_t x, y;
|
||||
for(y = area->y1; y <= area->y2; y++) {
|
||||
for(x = area->x1; x <= area->x2; x++) {
|
||||
put_px(x, y, *color_p)
|
||||
color_p++;
|
||||
}
|
||||
}
|
||||
|
||||
/* IMPORTANT!!!
|
||||
* Inform the graphics library that you are ready with the flushing*/
|
||||
lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
||||
void my_gpu_fill_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, const lv_area_t * dest_area, const lv_area_t * fill_area, lv_color_t color);
|
||||
{
|
||||
/*It's an example code which should be done by your GPU*/
|
||||
uint32_t x, y;
|
||||
dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
|
||||
|
||||
for(y = fill_area->y1; y < fill_area->y2; y++) {
|
||||
for(x = fill_area->x1; x < fill_area->x2; x++) {
|
||||
dest_buf[x] = color;
|
||||
}
|
||||
dest_buf+=dest_width; /*Go to the next line*/
|
||||
}
|
||||
}
|
||||
|
||||
void my_gpu_blend_cb(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
|
||||
{
|
||||
/*It's an example code which should be done by your GPU*/
|
||||
uint32_t i;
|
||||
for(i = 0; i < length; i++) {
|
||||
dest[i] = lv_color_mix(dest[i], src[i], opa);
|
||||
}
|
||||
}
|
||||
|
||||
void my_rounder_cb(lv_disp_drv_t * disp_drv, lv_area_t * area)
|
||||
{
|
||||
/* Update the areas as needed. Can be only larger.
|
||||
* For example to always have lines 8 px height:*/
|
||||
area->y1 = area->y1 & 0x07;
|
||||
area->y2 = (area->y2 & 0x07) + 8;
|
||||
}
|
||||
|
||||
void my_set_px_cb(lv_disp_drv_t * disp_drv, uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
/* Write to the buffer as required for the display.
|
||||
* Write only 1-bit for monochrome displays mapped vertically:*/
|
||||
buf += buf_w * (y >> 3) + x;
|
||||
if(lv_color_brightness(color) > 128) (*buf) |= (1 << (y % 8));
|
||||
else (*buf) &= ~(1 << (y % 8));
|
||||
}
|
||||
|
||||
void my_monitor_cb(lv_disp_drv_t * disp_drv, uint32_t time, uint32_t px)
|
||||
{
|
||||
printf("%d px refreshed in %d ms\n", time, ms);
|
||||
}
|
||||
|
||||
void my_clean_dcache_cb(lv_disp_drv_t * disp_drv, uint32)
|
||||
{
|
||||
/* Example for Cortex-M (CMSIS) */
|
||||
SCB_CleanInvalidateDCache();
|
||||
}
|
||||
```
|
||||
|
||||
## Rotation
|
||||
|
||||
LVGL supports rotation of the display in 90 degree increments. You can select whether you'd like software rotation or hardware rotation.
|
||||
|
||||
If you select software rotation (`sw_rotate` flag set to 1), LVGL will perform the rotation for you. Your driver can and should assume that the screen width and height have not changed. Simply flush pixels to the display as normal. Software rotation requires no additional logic in your `flush_cb` callback.
|
||||
|
||||
There is a noticeable amount of overhead to performing rotation in software, which is why hardware rotation is also available. In this mode, LVGL draws into the buffer as though your screen now has the width and height inverted. You are responsible for rotating the provided pixels yourself.
|
||||
|
||||
The default rotation of your display when it is initialized can be set using the `rotated` flag. The available options are `LV_DISP_ROT_NONE`, `LV_DISP_ROT_90`, `LV_DISP_ROT_180`, or `LV_DISP_ROT_270`. The rotation values are relative to how you would rotate the physical display in the clockwise direction. Thus, `LV_DISP_ROT_90` means you rotate the hardware 90 degrees clockwise, and the display rotates 90 degrees counterclockwise to compensate.
|
||||
|
||||
(Note for users upgrading from 7.10.0 and older: these new rotation enum values match up with the old 0/1 system for rotating 90 degrees, so legacy code should continue to work as expected. Software rotation is also disabled by default for compatibility.)
|
||||
|
||||
Display rotation can also be changed at runtime using the `lv_disp_set_rotation(disp, rot)` API.
|
||||
|
||||
Support for software rotation is a new feature, so there may be some glitches/bugs depending on your configuration. If you encounter a problem please open an issue on [GitHub](https://github.com/lvgl/lvgl/issues).
|
||||
|
||||
## API
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_hal_disp.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
@@ -0,0 +1,203 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/porting/indev.md
|
||||
```
|
||||
# Input device interface
|
||||
|
||||
## Types of input devices
|
||||
|
||||
To set up an input device an `lv_indev_drv_t` variable has to be initialized:
|
||||
|
||||
```c
|
||||
lv_indev_drv_t indev_drv;
|
||||
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
|
||||
indev_drv.type =... /*See below.*/
|
||||
indev_drv.read_cb =... /*See below.*/
|
||||
/*Register the driver in LVGL and save the created input device object*/
|
||||
lv_indev_t * my_indev = lv_indev_drv_register(&indev_drv);
|
||||
```
|
||||
|
||||
**type** can be
|
||||
- **LV_INDEV_TYPE_POINTER** touchpad or mouse
|
||||
- **LV_INDEV_TYPE_KEYPAD** keyboard or keypad
|
||||
- **LV_INDEV_TYPE_ENCODER** encoder with left, right, push options
|
||||
- **LV_INDEV_TYPE_BUTTON** external buttons pressing the screen
|
||||
|
||||
**read_cb** is a function pointer which will be called periodically to report the current state of an input device.
|
||||
It can also buffer data and return `false` when no more data to be read or `true` when the buffer is not empty.
|
||||
|
||||
|
||||
Visit [Input devices](/overview/indev) to learn more about input devices in general.
|
||||
|
||||
|
||||
### Touchpad, mouse or any pointer
|
||||
Input devices which can click points of the screen belong to this category.
|
||||
|
||||
```c
|
||||
indev_drv.type = LV_INDEV_TYPE_POINTER;
|
||||
indev_drv.read_cb = my_input_read;
|
||||
|
||||
...
|
||||
|
||||
bool my_input_read(lv_indev_drv_t * drv, lv_indev_data_t*data)
|
||||
{
|
||||
data->point.x = touchpad_x;
|
||||
data->point.y = touchpad_y;
|
||||
data->state = LV_INDEV_STATE_PR or LV_INDEV_STATE_REL;
|
||||
return false; /*No buffering now so no more data read*/
|
||||
}
|
||||
```
|
||||
|
||||
``` important:: Touchpad drivers must return the last X/Y coordinates even when the state is *LV_INDEV_STATE_REL*.
|
||||
```
|
||||
|
||||
To set a mouse cursor use `lv_indev_set_cursor(my_indev, &img_cursor)`. (`my_indev` is the return value of `lv_indev_drv_register`)
|
||||
|
||||
### Keypad or keyboard
|
||||
|
||||
Full keyboards with all the letters or simple keypads with a few navigation buttons belong here.
|
||||
|
||||
To use a keyboard/keypad:
|
||||
- Register a `read_cb` function with `LV_INDEV_TYPE_KEYPAD` type.
|
||||
- Enable `LV_USE_GROUP` in *lv_conf.h*
|
||||
- An object group has to be created: `lv_group_t * g = lv_group_create()` and objects have to be added to it with `lv_group_add_obj(g, obj)`
|
||||
- The created group has to be assigned to an input device: `lv_indev_set_group(my_indev, g)` (`my_indev` is the return value of `lv_indev_drv_register`)
|
||||
- Use `LV_KEY_...` to navigate among the objects in the group. See `lv_core/lv_group.h` for the available keys.
|
||||
|
||||
```c
|
||||
indev_drv.type = LV_INDEV_TYPE_KEYPAD;
|
||||
indev_drv.read_cb = keyboard_read;
|
||||
|
||||
...
|
||||
|
||||
bool keyboard_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
|
||||
data->key = last_key(); /*Get the last pressed or released key*/
|
||||
|
||||
if(key_pressed()) data->state = LV_INDEV_STATE_PR;
|
||||
else data->state = LV_INDEV_STATE_REL;
|
||||
|
||||
return false; /*No buffering now so no more data read*/
|
||||
}
|
||||
```
|
||||
|
||||
### Encoder
|
||||
With an encoder you can do 4 things:
|
||||
1. Press its button
|
||||
2. Long-press its button
|
||||
3. Turn left
|
||||
4. Turn right
|
||||
|
||||
In short, the Encoder input devices work like this:
|
||||
- By turning the encoder you can focus on the next/previous object.
|
||||
- When you press the encoder on a simple object (like a button), it will be clicked.
|
||||
- If you press the encoder on a complex object (like a list, message box, etc.) the object will go to edit mode whereby turning the encoder you can navigate inside the object.
|
||||
- To leave edit mode press long the button.
|
||||
|
||||
|
||||
To use an *Encoder* (similarly to the *Keypads*) the objects should be added to groups.
|
||||
|
||||
|
||||
```c
|
||||
indev_drv.type = LV_INDEV_TYPE_ENCODER;
|
||||
indev_drv.read_cb = encoder_read;
|
||||
|
||||
...
|
||||
|
||||
bool encoder_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
|
||||
data->enc_diff = enc_get_new_moves();
|
||||
|
||||
if(enc_pressed()) data->state = LV_INDEV_STATE_PR;
|
||||
else data->state = LV_INDEV_STATE_REL;
|
||||
|
||||
return false; /*No buffering now so no more data read*/
|
||||
}
|
||||
```
|
||||
#### Using buttons with Encoder logic
|
||||
In addition to standard encoder behavior, you can also utilise its logic to navigate(focus) and edit widgets using buttons.
|
||||
This is especially handy if you have only few buttons avalible, or you want to use other buttons in addition to encoder wheel.
|
||||
|
||||
You need to have 3 buttons avalible:
|
||||
- **LV_KEY_ENTER** will simulate press or pushing of the encoder button
|
||||
- **LV_KEY_LEFT** will simulate turnuing encoder left
|
||||
- **LV_KEY_RIGHT** will simulate turnuing encoder right
|
||||
- other keys will be passed to the focused widget
|
||||
|
||||
If you hold the keys it will simulate encoder click with period specified in `indev_drv.long_press_rep_time`.
|
||||
|
||||
```c
|
||||
indev_drv.type = LV_INDEV_TYPE_ENCODER;
|
||||
indev_drv.read_cb = encoder_with_keys_read;
|
||||
|
||||
...
|
||||
|
||||
bool encoder_with_keys_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
|
||||
data->key = last_key(); /*Get the last pressed or released key*/
|
||||
/* use LV_KEY_ENTER for encoder press */
|
||||
if(key_pressed()) data->state = LV_INDEV_STATE_PR;
|
||||
else {
|
||||
data->state = LV_INDEV_STATE_REL;
|
||||
/* Optionally you can also use enc_diff, if you have encoder*/
|
||||
data->enc_diff = enc_get_new_moves();
|
||||
}
|
||||
|
||||
return false; /*No buffering now so no more data read*/
|
||||
}
|
||||
```
|
||||
|
||||
### Button
|
||||
*Buttons* mean external "hardware" buttons next to the screen which are assigned to specific coordinates of the screen.
|
||||
If a button is pressed it will simulate the pressing on the assigned coordinate. (Similarly to a touchpad)
|
||||
|
||||
To assign buttons to coordinates use `lv_indev_set_button_points(my_indev, points_array)`.
|
||||
`points_array` should look like `const lv_point_t points_array[] = { {12,30},{60,90}, ...}`
|
||||
|
||||
``` important:: The points_array can't go out of scope. Either declare it as a global variable or as a static variable inside a function.
|
||||
```
|
||||
|
||||
```c
|
||||
indev_drv.type = LV_INDEV_TYPE_BUTTON;
|
||||
indev_drv.read_cb = button_read;
|
||||
|
||||
...
|
||||
|
||||
bool button_read(lv_indev_drv_t * drv, lv_indev_data_t*data){
|
||||
static uint32_t last_btn = 0; /*Store the last pressed button*/
|
||||
int btn_pr = my_btn_read(); /*Get the ID (0,1,2...) of the pressed button*/
|
||||
if(btn_pr >= 0) { /*Is there a button press? (E.g. -1 indicated no button was pressed)*/
|
||||
last_btn = btn_pr; /*Save the ID of the pressed button*/
|
||||
data->state = LV_INDEV_STATE_PR; /*Set the pressed state*/
|
||||
} else {
|
||||
data->state = LV_INDEV_STATE_REL; /*Set the released state*/
|
||||
}
|
||||
|
||||
data->btn = last_btn; /*Save the last button*/
|
||||
|
||||
return false; /*No buffering now so no more data read*/
|
||||
}
|
||||
```
|
||||
|
||||
## Other features
|
||||
|
||||
Besides `read_cb` a `feedback_cb` callback can be also specified in `lv_indev_drv_t`.
|
||||
`feedback_cb` is called when any type of event is sent by the input devices. (independently from its type). It allows making feedback for the user e.g. to play a sound on `LV_EVENT_CLICK`.
|
||||
|
||||
The default value of the following parameters can be set in *lv_conf.h* but the default value can be overwritten in `lv_indev_drv_t`:
|
||||
- **drag_limit** Number of pixels to slide before actually drag the object
|
||||
- **drag_throw** Drag throw slow-down in [%]. Greater value means faster slow-down
|
||||
- **long_press_time** Press time to send `LV_EVENT_LONG_PRESSED` (in milliseconds)
|
||||
- **long_press_rep_time** Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds)
|
||||
- **read_task** pointer to the `lv_task` which reads the input device. Its parameters can be changed by `lv_task_...()` functions
|
||||
|
||||
|
||||
Every Input device is associated with a display. By default, a new input device is added to the lastly created or the explicitly selected (using `lv_disp_set_default()`) display.
|
||||
The associated display is stored and can be changed in `disp` field of the driver.
|
||||
|
||||
|
||||
## API
|
||||
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_hal_indev.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||