add the md files from the docs repo to start updating them to v8
This commit is contained in:
126
docs/overview/animation.md
Normal file
126
docs/overview/animation.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
215
docs/overview/display.md
Normal file
215
docs/overview/display.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
100
docs/overview/drawing.md
Normal file
100
docs/overview/drawing.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
133
docs/overview/event.md
Normal file
133
docs/overview/event.md
Normal file
@@ -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.
|
||||
|
||||
116
docs/overview/file-system.md
Normal file
116
docs/overview/file-system.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
255
docs/overview/font.md
Normal file
255
docs/overview/font.md
Normal file
@@ -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*/
|
||||
}
|
||||
```
|
||||
357
docs/overview/image.md
Normal file
357
docs/overview/image.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
112
docs/overview/indev.md
Normal file
112
docs/overview/indev.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
27
docs/overview/index.md
Normal file
27
docs/overview/index.md
Normal file
@@ -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
|
||||
```
|
||||
|
||||
60
docs/overview/layer.md
Normal file
60
docs/overview/layer.md
Normal file
@@ -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.
|
||||
195
docs/overview/object.md
Normal file
195
docs/overview/object.md
Normal file
@@ -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).
|
||||
|
||||
511
docs/overview/style.md
Normal file
511
docs/overview/style.md
Normal file
@@ -0,0 +1,511 @@
|
||||
```eval_rst
|
||||
.. include:: /header.rst
|
||||
:github_url: |github_link_base|/overview/style.md
|
||||
```
|
||||
# Styles
|
||||
|
||||
|
||||
*Styles* are used to set the appearance of the objects. Styles in lvgl are heavily inspired by CSS. The concept in nutshell is the following:
|
||||
- A style is an `lv_style_t` variable which can hold properties, for example border width, text color and so on. It's similar to `class` in CSS.
|
||||
- Not all properties have to be specified. Unspecified properties will use a default value.
|
||||
- Styles can be assigned to objects to change their appearance.
|
||||
- A style can be used by any number of objects.
|
||||
- Styles can be cascaded which means multiple styles can be assigned to an object and each style can have different properties.
|
||||
For example `style_btn` can result in a default gray button and `style_btn_red` can add only a `background-color=red` to overwrite the background color.
|
||||
- Later added styles have higher precedence. It means if a property is specified in two styles the later added will be used.
|
||||
- Some properties (e.g. text color) can be inherited from the parent(s) if it's not specified in the object.
|
||||
- Objects can have local styles that have higher precedence than "normal" styles.
|
||||
- Unlike CSS (where pseudo-classes describes different states, e.g. `:hover`), in lvgl a property is assigned to a given state. (I.e. not the "class" is related to state but every single property has a state)
|
||||
- Transitions can be applied when the object changes state.
|
||||
|
||||
|
||||
## States
|
||||
The objects can be in the following states:
|
||||
- **LV_STATE_DEFAULT** (0x00): Normal, released
|
||||
- **LV_STATE_CHECKED** (0x01): Toggled or checked
|
||||
- **LV_STATE_FOCUSED** (0x02): Focused via keypad or encoder or clicked via touchpad/mouse
|
||||
- **LV_STATE_EDITED** (0x04): Edit by an encoder
|
||||
- **LV_STATE_HOVERED** (0x08): Hovered by mouse (not supported now)
|
||||
- **LV_STATE_PRESSED** (0x10): Pressed
|
||||
- **LV_STATE_DISABLED** (0x20): Disabled or inactive
|
||||
|
||||
Combination of states is also possible, for example `LV_STATE_FOCUSED | LV_STATE_PRESSED`.
|
||||
|
||||
The style properties can be defined in every state and state combination. For example, setting a different background color for default and pressed state.
|
||||
If a property is not defined in a state the best matching state's property will be used. Typically it means the property with `LV_STATE_DEFAULT` state.˛
|
||||
If the property is not set even for the default state the default value will be used. (See later)
|
||||
|
||||
But what does the "best matching state's property" really means?
|
||||
States have a precedence which is shown by their value (see in the above list). A higher value means higher precedence.
|
||||
To determine which state's property to use let's use an example. Let's see the background color is defined like this:
|
||||
- `LV_STATE_DEFAULT`: white
|
||||
- `LV_STATE_PRESSED`: gray
|
||||
- `LV_STATE_FOCUSED`: red
|
||||
|
||||
1. By the default the object is in default state, so it's a simple case: the property is perfectly defined in the object's current state as white
|
||||
2. When the object is pressed there are 2 related properties: default with white (default is related to every state) and pressed with gray.
|
||||
The pressed state has 0x10 precedence which is higher than the default state's 0x00 precedence, so gray color will be used.
|
||||
3. When the object is focused the same thing happens as in pressed state and red color will be used. (Focused state has higher precedence than default state).
|
||||
4. When the object is focused and pressed both gray and red would work, but the pressed state has higher precedence than focused so gray color will be used.
|
||||
5. It's possible to set e.g rose color for `LV_STATE_PRESSED | LV_STATE_FOCUSED`.
|
||||
In this case, this combined state has 0x02 + 0x10 = 0x12 precedence, which higher than the pressed states precedence so rose color would be used.
|
||||
6. When the object is checked there is no property to set the background color for this state. So in lack of a better option, the object remains white from the default state's property.
|
||||
|
||||
Some practical notes:
|
||||
- If you want to set a property for all state (e.g. red background color) just set it for the default state. If the object can't find a property for its current state it will fall back to the default state's property.
|
||||
- Use ORed states to describe the properties for complex cases. (E.g. pressed + checked + focused)
|
||||
- It might be a good idea to use different style elements for different states.
|
||||
For example, finding background colors for released, pressed, checked + pressed, focused, focused + pressed, focused + pressed + checked, etc states is quite difficult.
|
||||
Instead, for example, use the background color for pressed and checked states and indicate the focused state with a different border color.
|
||||
|
||||
## Cascading styles
|
||||
It's not required to set all the properties in one style. It's possible to add more styles to an object and let the later added style to modify or extend the properties in the other styles.
|
||||
For example, create a general gray button style and create a new for red buttons where only the new background color is set.
|
||||
|
||||
It's the same concept when in CSS all the used classes are listed like `<div class=".btn .btn-red">`.
|
||||
|
||||
The later added styles have higher precedence over the earlier ones. So in the gray/red button example above, the normal button style should be added first and the red style second.
|
||||
However, the precedence coming from states are still taken into account.
|
||||
So let's examine the following case:
|
||||
- the basic button style defines dark-gray color for default state and light-gray color pressed state
|
||||
- the red button style defines the background color as red only in the default state
|
||||
|
||||
In this case, when the button is released (it's in default state) it will be red because a perfect match is found in the lastly added style (red style).
|
||||
When the button is pressed the light-gray color is a better match because it describes the current state perfectly, so the button will be light-gray.
|
||||
|
||||
## Inheritance
|
||||
Some properties (typically that are related to texts) can be inherited from the parent object's styles. Inheritance is applied only if the given property is not set in the object's styles (even in default state).
|
||||
In this case, if the property is inheritable, the property's value will be searched in the parent too until a part can tell a value for the property. The parents will use their own state to tell the value.
|
||||
So is button is pressed, and text color comes from here, the pressed text color will be used.
|
||||
|
||||
|
||||
## Parts
|
||||
Objects can have *parts* which can have their own style. For example a [page](/widgets/page) has four parts:
|
||||
- Background
|
||||
- Scrollable
|
||||
- Scrollbar
|
||||
- Edge flash
|
||||
|
||||
There is three types of object parts **main**, **virtual** and **real**.
|
||||
|
||||
The main part is usually the background and largest part of the object. Some object has only a main part. For example, a button has only a background.
|
||||
|
||||
The virtual parts are additional parts just drawn on the fly to the main part. There is no "real" object behind them.
|
||||
For example, the page's scrollbar is not a real object, it's just drawn when the page's background is drawn.
|
||||
The virtual parts always have the same state as the main part.
|
||||
If the property can be inherited, the main part will be also considered before going to the parent.
|
||||
|
||||
The real parts are real objects created and managed by the main object. For example, the page's scrollable part is real object.
|
||||
Real parts can be in different state than the main part.
|
||||
|
||||
To see which parts an object has visit their documentation page.
|
||||
|
||||
## Initialize styles and set/get properties
|
||||
|
||||
Styles are stored in `lv_style_t` variables. Style variables should be `static`, global or dynamically allocated. In other words they can not be local variables in functions which are destroyed when the function exists.
|
||||
Before using a style it should be initialized with `lv_style_init(&my_style)`.
|
||||
After initializing the style properties can be set or added to it.
|
||||
Property set functions looks like this: `lv_style_set_<property_name>(&style, <state>, <value>);`
|
||||
For example the [above mentioned](#states) example looks like this:
|
||||
```c
|
||||
static lv_style_t style1;
|
||||
lv_style_set_bg_color(&style1, LV_STATE_DEFAULT, LV_COLOR_WHITE);
|
||||
lv_style_set_bg_color(&style1, LV_STATE_PRESSED, LV_COLOR_GRAY);
|
||||
lv_style_set_bg_color(&style1, LV_STATE_FOCUSED, LV_COLOR_RED);
|
||||
lv_style_set_bg_color(&style1, LV_STATE_FOCUSED | LV_STATE_PRESSED, lv_color_hex(0xf88));
|
||||
```
|
||||
|
||||
It's possible to copy a style with `lv_style_copy(&style_destination, &style_source)`. After copy properties still can be added freely.
|
||||
|
||||
To remove a property use:
|
||||
|
||||
```c
|
||||
lv_style_remove_prop(&style, LV_STYLE_BG_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS));
|
||||
```
|
||||
|
||||
To get the value from style in a given state functions with the following prototype are available: `_lv_style_get_color/int/opa/ptr(&style, <prop>, <result buf>);`.
|
||||
The best matching property will be selected and it's precedence will be returned. `-1` will be returned if the property is not found.
|
||||
|
||||
The form of the function (`...color/int/opa/ptr`) should be used according to the type of `<prop>`.
|
||||
|
||||
For example:
|
||||
|
||||
```c
|
||||
lv_color_t color;
|
||||
int16_t res;
|
||||
res = _lv_style_get_color(&style1, LV_STYLE_BG_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS), &color);
|
||||
if(res >= 0) {
|
||||
//the bg_color is loaded into `color`
|
||||
}
|
||||
```
|
||||
|
||||
To reset a style (free all it's data) use
|
||||
```c
|
||||
lv_style_reset(&style);
|
||||
```
|
||||
|
||||
## Managing style list
|
||||
A style on its own not that useful. It should be assigned to an object to take its effect.
|
||||
Every part of the objects stores a *style list* which is the list of assigned styles.
|
||||
|
||||
To add a style to an object use `lv_obj_add_style(obj, <part>, &style)`
|
||||
For example:
|
||||
```c
|
||||
lv_obj_add_style(btn, LV_BTN_PART_MAIN, &btn); /*Default button style*/
|
||||
lv_obj_add_style(btn, LV_BTN_PART_MAIN, &btn_red); /*Overwrite only a some colors to red*/
|
||||
```
|
||||
|
||||
An objects style list can be reset with `lv_obj_reset_style_list(obj, <part>)`
|
||||
|
||||
If a style which is already assigned to an object changes (i.e. one of it's property is set to a new value) the objects using that style should be notified with `lv_obj_refresh_style(obj, part, property)`. To refresh all parts and proeprties use `lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL)`.
|
||||
|
||||
To get a final value of property, including cascading, inheritance, local styles and transitions (see below), get functions like this can be used: `lv_obj_get_style_<property_name>(obj, <part>)`.
|
||||
These functions uses the object's current state and if no better candidate returns a default value.
|
||||
For example:
|
||||
```c
|
||||
lv_color_t color = lv_obj_get_style_bg_color(btn, LV_BTN_PART_MAIN);
|
||||
```
|
||||
|
||||
## Local styles
|
||||
In the object's style lists, so-called local properties can be stored as well. It's the same concept than CSS's `<div style="color:red">`.
|
||||
The local style is the same as a normal style, but it belongs only to a given object and can not be shared with other objects.
|
||||
To set a local property use functions like `lv_obj_set_style_local_<property_name>(obj, <part>, <state>, <value>);`
|
||||
For example:
|
||||
```c
|
||||
lv_obj_set_style_local_bg_color(btn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED);
|
||||
```
|
||||
|
||||
## Transitions
|
||||
By default, when an object changes state (e.g. it's pressed) the new properties from the new state are set immediately. However, with transitions it's possible to play an animation on state change.
|
||||
For example, on pressing a button its background color can be animated to the pressed color over 300 ms.
|
||||
|
||||
The parameters of the transitions are stored in the styles. It's possible to set
|
||||
- the time of the transition
|
||||
- the delay before starting the transition
|
||||
- the animation path (also known as timing function)
|
||||
- the properties to animate
|
||||
|
||||
The transition properties can be defined for each state.
|
||||
For example, setting 500 ms transition time in default state will mean that when the object goes to default state 500 ms transition time will be applied.
|
||||
Setting 100 ms transition time in the pressed state will mean a 100 ms transition time when going to presses state.
|
||||
So this example configuration will result in fast going to presses state and slow going back to default.
|
||||
|
||||
## Properties
|
||||
|
||||
The following properties can be used in the styles.
|
||||
|
||||
### Mixed properties
|
||||
- **radius** (`lv_style_int_t`): Set the radius of the background. 0: no radius, `LV_RADIUS_CIRCLE`: maximal radius. Default value: 0.
|
||||
- **clip_corner** (`bool`): `true`: enable to clip the overflowed content on the rounded (radius > 0) corners. Default value: `false`.
|
||||
- **size** (`lv_style_int_t`): Size of internal elements of the widgets. See the documentation of the widgets if this property is used or not. Default value: `LV_DPI / 20`.
|
||||
- **transform_width** (`lv_style_int_t`): Make the object wider on both sides with this value. Default value: 0.
|
||||
- **transform_height** (`lv_style_int_t`) Make the object higher on both sides with this value. Default value: 0.
|
||||
- **transform_angle** (`lv_style_int_t`): Rotate the image-like objects. It's uinit is 0.1 deg, for 45 deg use 450. Default value: 0.
|
||||
- **transform_zoom** (`lv_style_int_t`) Zoom image-like objects. 256 (or `LV_IMG_ZOOM_NONE`) for normal size, 128 half size, 512 double size, ans so on. Default value: `LV_IMG_ZOOM_NONE`.
|
||||
- **opa_scale** (`lv_style_int_t`): Inherited. Scale down all opacity values of the object by this factor. As it's inherited the children objects will be affected too. Default value: `LV_OPA_COVER`.
|
||||
|
||||
### Padding and margin properties
|
||||
*Padding* sets the space on the inner sides of the edges. It means "I don't want my children too close to my sides, so keep this space".
|
||||
*Padding inner* set the "gap" between the children.
|
||||
*Margin* sets the space on the outer side of the edges. It means "I want this space around me".
|
||||
|
||||
These properties are typically used by [Container](/widgets/cont) object if [layout](/widgets/cont#layout) or
|
||||
[auto fit](/widgets/cont#auto-fit) is enabled.
|
||||
However other widgets also use them to set spacing. See the documentation of the widgets for the details.
|
||||
- **pad_top** (`lv_style_int_t`): Set the padding on the top. Default value: 0.
|
||||
- **pad_bottom** (`lv_style_int_t`): Set the padding on the bottom. Default value: 0.
|
||||
- **pad_left** (`lv_style_int_t`): Set the padding on the left. Default value: 0.
|
||||
- **pad_right** (`lv_style_int_t`): Set the padding on the right. Default value: 0.
|
||||
- **pad_inner** (`lv_style_int_t`): Set the padding inside the object between children. Default value: 0.
|
||||
- **margin_top** (`lv_style_int_t`): Set the margin on the top. Default value: 0.
|
||||
- **margin_bottom** (`lv_style_int_t`): Set the margin on the bottom. Default value: 0.
|
||||
- **margin_left** (`lv_style_int_t`): Set the margin on the left. Default value: 0.
|
||||
- **margin_right** (`lv_style_int_t`): Set the margin on the right. Default value: 0.
|
||||
|
||||
### Background properties
|
||||
The background is a simple rectangle which can have gradient and `radius` rounding.
|
||||
- **bg_color** (`lv_color_t`) Specifies the color of the background. Default value: `LV_COLOR_WHITE`.
|
||||
- **bg_opa** (`lv_opa_t`) Specifies opacity of the background. Default value: `LV_OPA_TRANSP`.
|
||||
- **bg_grad_color** (`lv_color_t`) Specifies the color of the background's gradient. The color on the right or bottom is `bg_grad_dir != LV_GRAD_DIR_NONE`. Default value: `LV_COLOR_WHITE`.
|
||||
- **bg_main_stop** (`uint8_t`): Specifies where should the gradient start. 0: at left/top most position, 255: at right/bottom most position. Default value: 0.
|
||||
- **bg_grad_stop** (`uint8_t`): Specifies where should the gradient stop. 0: at left/top most position, 255: at right/bottom most position. Default value: 255.
|
||||
- **bg_grad_dir** (`lv_grad_dir_t`) Specifies the direction of the gradient. Can be `LV_GRAD_DIR_NONE/HOR/VER`. Default value: `LV_GRAD_DIR_NONE`.
|
||||
- **bg_blend_mode** (`lv_blend_mode_t`): Set the blend mode the background. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_1.*
|
||||
:alt: Styling the background in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_1.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Border properties
|
||||
The border is drawn on top of the *background*. It has `radius` rounding.
|
||||
- **border_color** (`lv_color_t`) Specifies the color of the border. Default value: `LV_COLOR_BLACK`.
|
||||
- **border_opa** (`lv_opa_t`) Specifies opacity of the border. Default value: `LV_OPA_COVER`.
|
||||
- **border_width** (`lv_style_int_t`): Set the width of the border. Default value: 0.
|
||||
- **border_side** (`lv_border_side_t`) Specifies which sides of the border to draw. Can be `LV_BORDER_SIDE_NONE/LEFT/RIGHT/TOP/BOTTOM/FULL`. ORed values are also possible. Default value: `LV_BORDER_SIDE_FULL`.
|
||||
- **border_post** (`bool`): If `true` the border will be drawn after all children have been drawn. Default value: `false`.
|
||||
- **border_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the border. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_2.*
|
||||
:alt: Styling the border in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_2.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Outline properties
|
||||
The outline is similar to *border* but is drawn outside of the object.
|
||||
- **outline_color** (`lv_color_t`) Specifies the color of the outline. Default value: `LV_COLOR_BLACK`.
|
||||
- **outline_opa** (`lv_opa_t`) Specifies opacity of the outline. Default value: `LV_OPA_COVER`.
|
||||
- **outline_width** (`lv_style_int_t`): Set the width of the outline. Default value: 0.
|
||||
- **outline_pad** (`lv_style_int_t`) Set the space between the object and the outline. Default value: 0.
|
||||
- **outline_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the outline. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_3.*
|
||||
:alt: Styling the outline in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_3.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Shadow properties
|
||||
The shadow is a blurred area under the object.
|
||||
- **shadow_color** (`lv_color_t`) Specifies the color of the shadow. Default value: `LV_COLOR_BLACK`.
|
||||
- **shadow_opa** (`lv_opa_t`) Specifies opacity of the shadow. Default value: `LV_OPA_TRANSP`.
|
||||
- **shadow_width** (`lv_style_int_t`): Set the width (blur size) of the outline. Default value: 0.
|
||||
- **shadow_ofs_x** (`lv_style_int_t`): Set the an X offset for the shadow. Default value: 0.
|
||||
- **shadow_ofs_y** (`lv_style_int_t`): Set the an Y offset for the shadow. Default value: 0.
|
||||
- **shadow_spread** (`lv_style_int_t`): make the shadow larger than the background in every direction by this value. Default value: 0.
|
||||
- **shadow_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the shadow. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_4.*
|
||||
:alt: Styling the shadow in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_4.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Pattern properties
|
||||
The pattern is an image (or symbol) drawn in the middle of the background or repeated to fill the whole background.
|
||||
- **pattern_image** (`const void *`): Pointer to an `lv_img_dsc_t` variable, a path to an image file or a symbol. Default value: `NULL`.
|
||||
- **pattern_opa** (`lv_opa_t`): Specifies opacity of the pattern. Default value: `LV_OPA_COVER`.
|
||||
- **pattern_recolor** (`lv_color_t`): Mix this color to the pattern image. In case of symbols (texts) it will be the text color. Default value: `LV_COLOR_BLACK`.
|
||||
- **pattern_recolor_opa** (`lv_opa_t`): Intensity of recoloring. Default value: `LV_OPA_TRANSP` (no recoloring).
|
||||
- **pattern_repeat** (`bool`): `true`: the pattern will be repeated as a mosaic. `false`: place the pattern in the middle of the background. Default value: `false`.
|
||||
- **pattern_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the pattern. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_5.*
|
||||
:alt: Styling the shadow in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_5.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Value properties
|
||||
Value is an arbitrary text drawn to the background. It can be a lightweighted replacement of creating label objects.
|
||||
|
||||
- **value_str** (`const char *`): Pointer to text to display. Only the pointer is saved! (Don't use local variable with lv_style_set_value_str, instead use static, global or dynamically allocated data). Default value: `NULL`.
|
||||
- **value_color** (`lv_color_t`): Color of the text. Default value: `LV_COLOR_BLACK`.
|
||||
- **value_opa** (`lv_opa_t`): Opacity of the text. Default value: `LV_OPA_COVER`.
|
||||
- **value_font** (`const lv_font_t *`): Pointer to font of the text. Default value: `NULL`.
|
||||
- **value_letter_space** (`lv_style_int_t`): Letter space of the text. Default value: 0.
|
||||
- **value_line_space** (`lv_style_int_t`): Line space of the text. Default value: 0.
|
||||
- **value_align** (`lv_align_t`): Alignment of the text. Can be `LV_ALIGN_...`. Default value: `LV_ALIGN_CENTER`.
|
||||
- **value_ofs_x** (`lv_style_int_t`): X offset from the original position of the alignment. Default value: 0.
|
||||
- **value_ofs_y** (`lv_style_int_t`): Y offset from the original position of the alignment. Default value: 0.
|
||||
- **value_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the text. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_6.*
|
||||
:alt: Styling the value text in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_6.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Text properties
|
||||
Properties for textual object.
|
||||
- **text_color** (`lv_color_t`): Color of the text. Default value: `LV_COLOR_BLACK`.
|
||||
- **text_opa** (`lv_opa_t`): Opacity of the text. Default value: `LV_OPA_COVER`.
|
||||
- **text_font** (`const lv_font_t *`): Pointer to font of the text. Default value: `NULL`.
|
||||
- **text_letter_space** (`lv_style_int_t`): Letter space of the text. Default value: 0.
|
||||
- **text_line_space** (`lv_style_int_t`): Line space of the text. Default value: 0.
|
||||
- **text_decor** (`lv_text_decor_t`): Add text decoration. Can be `LV_TEXT_DECOR_NONE/UNDERLINE/STRIKETHROUGH`. Default value: `LV_TEXT_DECOR_NONE`.
|
||||
- **text_sel_color** (`lv_color_t`): Set color of the text selection. Default value: `LV_COLOR_BLACK`
|
||||
- **text_sel_bg_color** (`lv_color_t`): Set background color of text selection. Default value: `LV_COLOR_BLUE`
|
||||
- **text_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the text. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_7.*
|
||||
:alt: Styling a text in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_7.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Line properties
|
||||
Properties of lines.
|
||||
- **line_color** (`lv_color_t`): Color of the line. Default value: `LV_COLOR_BLACK`
|
||||
- **line_opa** (`lv_opa_t`): Opacity of the line. Default value: `LV_OPA_COVER`
|
||||
- **line_width** (`lv_style_int_t`): Width of the line. Default value: 0.
|
||||
- **line_dash_width** (`lv_style_int_t`): Width of dash. Dashing is drawn only for horizontal or vertical lines. 0: disable dash. Default value: 0.
|
||||
- **line_dash_gap** (`lv_style_int_t`): Gap between two dash line. Dashing is drawn only for horizontal or vertical lines. 0: disable dash. Default value: 0.
|
||||
- **line_rounded** (`bool`): `true`: draw rounded line endings. Default value: `false`.
|
||||
- **line_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the line. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_8.*
|
||||
:alt: Styling a line in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_8.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Image properties
|
||||
Properties of image.
|
||||
- **image_recolor** (`lv_color_t`): Mix this color to the pattern image. In case of symbols (texts) it will be the text color. Default value: `LV_COLOR_BLACK`
|
||||
- **image_recolor_opa** (`lv_opa_t`): Intensity of recoloring. Default value: `LV_OPA_TRANSP` (no recoloring). Default value: `LV_OPA_TRANSP`
|
||||
- **image_opa** (`lv_opa_t`): Opacity of the image. Default value: `LV_OPA_COVER`
|
||||
- **image_blend_mode** (`lv_blend_mode_t`): Set the blend mode of the image. Can be `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE`). Default value: `LV_BLEND_MODE_NORMAL`.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_9.*
|
||||
:alt: Styling an image in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_9.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Transition properties
|
||||
Properties to describe state change animations.
|
||||
- **transition_time** (`lv_style_int_t`): Time of the transition. Default value: 0.
|
||||
- **transition_delay** (`lv_style_int_t`): Delay before the transition. Default value: 0.
|
||||
- **transition_prop_1** (`property name`): A property on which transition should be applied. Use the property name with upper case with `LV_STYLE_` prefix, e.g. `LV_STYLE_BG_COLOR`. Default value: 0 (none).
|
||||
- **transition_prop_2** (`property name`): Same as *transition_1* just for another property. Default value: 0 (none).
|
||||
- **transition_prop_3** (`property name`): Same as *transition_1* just for another property. Default value: 0 (none).
|
||||
- **transition_prop_4** (`property name`): Same as *transition_1* just for another property. Default value: 0 (none).
|
||||
- **transition_prop_5** (`property name`): Same as *transition_1* just for another property. Default value: 0 (none).
|
||||
- **transition_prop_6** (`property name`): Same as *transition_1* just for another property. Default value: 0 (none).
|
||||
- **transition_path** (`lv_anim_path_t`): An animation path for the transition. (Needs to be static or global variable because only its pointer is saved).
|
||||
Default value: `lv_anim_path_def` (linear path).
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_10.*
|
||||
:alt: Styling an transitions in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_10.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
### Scale properties
|
||||
Auxiliary properties for scale-like elements. Scales have a normal and end region.
|
||||
As the name implies the end region is the end of the scale where can be critical values or inactive values. The normal region is before the end region.
|
||||
Both regions could have different properties.
|
||||
- **scale_grad_color** (`lv_color_t`): In normal region make gradient to this color on the scale lines. Default value: `LV_COLOR_BLACK`.
|
||||
- **scale_end_color** (`lv_color_t`): Color of the scale lines in the end region. Default value: `LV_COLOR_BLACK`.
|
||||
- **scale_width** (`lv_style_int_t`): Width of the scale. Default value: `LV_DPI / 8`. Default value: `LV_DPI / 8`.
|
||||
- **scale_border_width** (`lv_style_int_t`): Width of a border drawn on the outer side of the scale in the normal region. Default value: 0.
|
||||
- **scale_end_border_width** (`lv_style_int_t`): Width of a border drawn on the outer side of the scale in the end region. Default value: 0.
|
||||
- **scale_end_line_width** (`lv_style_int_t`): Width of a scale lines in the end region. Default value: 0.
|
||||
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_style/lv_ex_style_11.*
|
||||
:alt: Styling a scale in lvgl
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_style/lv_ex_style_11.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
In the documentation of the widgets you will see sentences like "The widget use the typical background properties". The "typical background" properties are:
|
||||
- Background
|
||||
- Border
|
||||
- Outline
|
||||
- Shadow
|
||||
- Pattern
|
||||
- Value
|
||||
|
||||
## Themes
|
||||
Themes are a collection of styles. There is always an active theme whose styles are automatically applied when an object is created.
|
||||
It gives a default appearance to UI which can be modified by adding further styles.
|
||||
|
||||
The default theme is set in `lv_conf.h` with `LV_THEME_...` defines. Every theme has the following properties
|
||||
- primary color
|
||||
- secondary color
|
||||
- small font
|
||||
- normal font
|
||||
- subtitle font
|
||||
- title font
|
||||
- flags (specific to the given theme)
|
||||
|
||||
It up to the theme how to use these properties.
|
||||
|
||||
There are 3 built-in themes:
|
||||
- empty: no default styles are added
|
||||
- material: an impressive, modern theme - mono: simple black and white theme for monochrome displays
|
||||
- template: a very simple theme which can be copied to create a custom theme
|
||||
|
||||
### Extending themes
|
||||
|
||||
Built-in themes can be extended by custom theme. If a custom theme is created a "base theme" can be selected. The base theme's styles will be added before the custom theme. Any number of themes can be chained this was. E.g. material theme -> custom theme -> dark theme.
|
||||
|
||||
Here is an example about how to create a custom theme based on the currently active built-in theme.
|
||||
```c
|
||||
/*Get the current theme (e.g. material). It will be the base of the custom theme.*/
|
||||
lv_theme_t * base_theme = lv_theme_get_act();
|
||||
|
||||
/*Initialize a custom theme*/
|
||||
static lv_theme_t custom_theme; /*Declare a theme*/
|
||||
lv_theme_copy(&custom_theme, base_theme); /*Initialize the custom theme from the base theme*/
|
||||
lv_theme_set_apply_cb(&custom_theme, custom_apply_cb); /*Set a custom theme apply callback*/
|
||||
lv_theme_set_base(custom_theme, base_theme); /*Set the base theme of the csutom theme*/
|
||||
|
||||
/*Initialize styles for the new theme*/
|
||||
static lv_style_t style1;
|
||||
lv_style_init(&style1);
|
||||
lv_style_set_bg_color(&style1, LV_STATE_DEFAULT, custom_theme.color_primary);
|
||||
|
||||
...
|
||||
|
||||
/*Add a custom apply callback*/
|
||||
static void custom_apply_cb(lv_theme_t * th, lv_obj_t * obj, lv_theme_style_t name)
|
||||
{
|
||||
lv_style_list_t * list;
|
||||
|
||||
switch(name) {
|
||||
case LV_THEME_BTN:
|
||||
list = lv_obj_get_style_list(obj, LV_BTN_PART_MAIN);
|
||||
_lv_style_list_add_style(list, &my_style);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
### Styling a button
|
||||
```eval_rst
|
||||
.. image:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_2.*
|
||||
:alt: Styling a button in LVGL
|
||||
|
||||
.. literalinclude:: /lv_examples/src/lv_ex_get_started/lv_ex_get_started_2.c
|
||||
:language: c
|
||||
```
|
||||
|
||||
## API
|
||||
```eval_rst
|
||||
|
||||
.. doxygenfile:: lv_style.h
|
||||
:project: lvgl
|
||||
|
||||
.. doxygenfile:: lv_theme.h
|
||||
:project: lvgl
|
||||
|
||||
```
|
||||
103
docs/overview/task.md
Normal file
103
docs/overview/task.md
Normal file
@@ -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
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user