add the optional VDB write interface to the display driver (vdb_wr)

This commit is contained in:
Gabor Kiss-Vamosi
2018-08-04 01:46:00 +02:00
parent fbf0303b2d
commit f968792286
12 changed files with 213 additions and 99 deletions

View File

@@ -38,8 +38,9 @@
* Required for buffered drawing, opacity and anti-aliasing
* VDB makes the double buffering, you don't need to deal with it!
* Typical size: ~1/10 screen */
#define LV_VDB_SIZE (20 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/
#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/
#define LV_VDB_SIZE (8 * LV_HOR_RES) /*Size of VDB in pixel count (1/10 screen size is good for first)*/
#define LV_VDB_PX_BPP LV_COLOR_SIZE /*Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays. (Set `disp_drv->vdb_wr` and `disp_drv->vdb_rd` too)*/
#define LV_VDB_ADR 0 /*Place VDB to a specific address (e.g. in external RAM) (0: allocate automatically into RAM)*/
/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing (optional)
* The flushing should use DMA to write the frame buffer in the background*/

View File

@@ -286,8 +286,34 @@ static void lv_refr_area_with_vdb(const lv_area_t * area_p)
lv_coord_t y2 = area_p->y2 >= LV_VER_RES ? y2 = LV_VER_RES - 1 : area_p->y2;
uint32_t max_row = (uint32_t) LV_VDB_SIZE / w;
if(max_row > h) max_row = h;
/*Round down the lines of VDB if rounding is added*/
if(round_cb) {
/**/
lv_area_t tmp;
tmp.x1 = 0;
tmp.x2 = 0;
tmp.y1 = 0;
tmp.y2 = max_row;
lv_coord_t y_tmp = max_row;
do {
tmp.y2 = y_tmp;
round_cb(&tmp);
y_tmp --; /*Decrement the number of line until it is rounded to a smaller value the original. */
} while(tmp.y2 > max_row && y_tmp != 0);
if(y_tmp == 0) {
LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to small VDB)");
return;
} else {
max_row = tmp.y2;
}
}
/*Always use the full row*/
uint32_t row;
lv_coord_t row_last = 0;

View File

@@ -94,7 +94,7 @@ void lv_style_init(void)
lv_style_scr.body.shadow.width = 0;
lv_style_scr.text.opa = LV_OPA_COVER;
lv_style_scr.text.color = LV_COLOR_MAKE(0x30, 0x30, 0x30);
lv_style_scr.text.color = LV_COLOR_BLACK;//MAKE(0x30, 0x30, 0x30);
lv_style_scr.text.font = LV_FONT_DEFAULT;
lv_style_scr.text.letter_space = 2;
lv_style_scr.text.line_space = 2;
@@ -115,7 +115,7 @@ void lv_style_init(void)
lv_style_plain_color.text.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.image.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.line.color = LV_COLOR_MAKE(0xf0, 0xf0, 0xf0);
lv_style_plain_color.body.main_color = LV_COLOR_MAKE(0x55, 0x96, 0xd8);
lv_style_plain_color.body.main_color = LV_COLOR_BLACK;//LV_COLOR_MAKE(0x55, 0x96, 0xd8);
lv_style_plain_color.body.grad_color = lv_style_plain_color.body.main_color;
/*Pretty style */

View File

@@ -21,9 +21,9 @@
* TYPEDEFS
**********************/
typedef enum {
LV_VDB_STATE_FREE = 0,
LV_VDB_STATE_ACTIVE,
LV_VDB_STATE_FLUSH,
LV_VDB_STATE_FREE = 0, /*Not used*/
LV_VDB_STATE_ACTIVE, /*Being used to render*/
LV_VDB_STATE_FLUSH, /*Flushing pixels from it*/
} lv_vdb_state_t;
/**********************
@@ -40,21 +40,21 @@ typedef enum {
static volatile lv_vdb_state_t vdb_state = LV_VDB_STATE_ACTIVE;
# if LV_VDB_ADR == 0
/*If the buffer address is not specified simply allocate it*/
static lv_color_t vdb_buf[LV_VDB_SIZE];
static lv_vdb_t vdb = {.buf = vdb_buf};
# else
static uint8_t vdb_buf[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3];
static lv_vdb_t vdb = {.buf = (lv_color_t*)vdb_buf};
# else /*LV_VDB_ADR != 0*/
/*If the buffer address is specified use that address*/
static lv_vdb_t vdb = {.buf = (lv_color_t *)LV_VDB_ADR};
# endif
#else
#else /*LV_VDB_DOUBLE != 0*/
/*Double VDB*/
static volatile lv_vdb_state_t vdb_state[2] = {LV_VDB_STATE_FREE, LV_VDB_STATE_FREE};
# if LV_VDB_ADR == 0
/*If the buffer address is not specified simply allocate it*/
static lv_color_t vdb_buf1[LV_VDB_SIZE];
static lv_color_t vdb_buf2[LV_VDB_SIZE];
static lv_vdb_t vdb[2] = {{.buf = vdb_buf1}, {.buf = vdb_buf2}};
# else
static uint8_t vdb_buf1[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3];
static uint8_t vdb_buf2[(LV_VDB_SIZE * LV_VDB_PX_BPP) >> 3];
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *) vdb_buf1}, {.buf = (lv_color_t *) vdb_buf2}};
# else /*LV_VDB_ADR != 0*/
/*If the buffer address is specified use that address*/
static lv_vdb_t vdb[2] = {{.buf = (lv_color_t *)LV_VDB_ADR}, {.buf = (lv_color_t *)LV_VDB2_ADR}};
# endif

View File

@@ -53,10 +53,8 @@ lv_vdb_t * lv_vdb_get(void);
*/
void lv_vdb_flush(void);
/**
* In 'LV_VDB_DOUBLE' mode has to be called when 'disp_map()'
* is ready with copying the map to a frame buffer.
* Call in the display driver's 'disp_flush' function when the flushing is finished
*/
void lv_flush_ready(void);

View File

@@ -75,13 +75,18 @@ void lv_vpx(lv_coord_t x, lv_coord_t y, const lv_area_t * mask_p, lv_color_t col
/*Make the coordinates relative to VDB*/
x -= vdb_p->area.x1;
y -= vdb_p->area.y1;
lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x;
if(opa == LV_OPA_COVER) {
*vdb_px_p = color;
} else {
*vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);
}
lv_disp_t * disp = lv_disp_get_active();
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t*)vdb_p->buf, vdb_width, x, y, color, opa);
} else {
lv_color_t * vdb_px_p = vdb_p->buf + y * vdb_width + x;
if(opa == LV_OPA_COVER) {
*vdb_px_p = color;
} else {
*vdb_px_p = lv_color_mix(color, *vdb_px_p, opa);
}
}
}
@@ -126,7 +131,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_coord_t w = lv_area_get_width(&vdb_rel_a);
/*Don't use hw. acc. for every small fill (because of the init overhead)*/
if(w < VFILL_HW_ACC_SIZE_LIMIT) {
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
/*Not opaque fill*/
else if(opa == LV_OPA_COVER) {
@@ -160,7 +165,7 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
}
/*Else use sw fill if no better option*/
else {
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
}
@@ -185,12 +190,12 @@ void lv_vfill(const lv_area_t * cords_p, const lv_area_t * mask_p,
}
/*Use sw fill with opa if no better option*/
else {
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
}
}
#else
sw_color_fill(&vdb_p->area, vdb_buf_tmp, &vdb_rel_a, color, opa);
sw_color_fill(&vdb_p->area, vdb_p->buf, &vdb_rel_a, color, opa);
#endif
}
@@ -207,7 +212,6 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
const lv_font_t * font_p, uint32_t letter,
lv_color_t color, lv_opa_t opa)
{
static uint8_t bpp1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
static uint8_t bpp2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
static uint8_t bpp4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
@@ -291,7 +295,10 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
/*Move on the map too*/
map_p += (row_start * width_byte_bpp) + ((col_start * bpp) >> 3);
lv_disp_t * disp = lv_disp_get_active();
uint8_t letter_px;
lv_opa_t px_opa;
for(row = row_start; row < row_end; row ++) {
col_byte_cnt = 0;
col_bit = (col_start * bpp) % 8;
@@ -299,13 +306,21 @@ void lv_vletter(const lv_point_t * pos_p, const lv_area_t * mask_p,
for(col = col_start; col < col_end; col ++) {
letter_px = (*map_p & mask) >> (8 - col_bit - bpp);
if(letter_px != 0) {
if(opa == LV_OPA_COVER) {
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, bpp == 8 ? letter_px : bpp_opa_table[letter_px]);
} else {
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, bpp == 8 ?
(uint16_t)((uint16_t)letter_px * opa) >> 8 :
(uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8);
}
if(opa == LV_OPA_COVER) {
px_opa = bpp == 8 ? letter_px : bpp_opa_table[letter_px];
} else {
px_opa = bpp == 8 ?
(uint16_t)((uint16_t)letter_px * opa) >> 8 :
(uint16_t)((uint16_t)bpp_opa_table[letter_px] * opa) >> 8;
}
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t*)vdb_p->buf, vdb_width,
(col + pos_x) - vdb_p->area.x1, (row + pos_y) - vdb_p->area.y1,
color, px_opa);
} else {
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
}
}
vdb_buf_tmp++;
@@ -341,6 +356,7 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
const uint8_t * map_p, lv_opa_t opa, bool chroma_key, bool alpha_byte,
lv_color_t recolor, lv_opa_t recolor_opa)
{
lv_area_t masked_a;
bool union_ok;
lv_vdb_t * vdb_p = lv_vdb_get();
@@ -379,22 +395,38 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
lv_coord_t row;
lv_coord_t map_useful_w = lv_area_get_width(&masked_a);
lv_disp_t * disp = lv_disp_get_active();
/*The simplest case just copy the pixels into the VDB*/
if(chroma_key == false && alpha_byte == false && opa == LV_OPA_COVER && recolor_opa == LV_OPA_TRANSP) {
for(row = masked_a.y1; row <= masked_a.y2; row++) {
/*Use the custom VDB write function is exists*/
if(disp->driver.vdb_wr) {
lv_coord_t col;
for(row = masked_a.y1; row <= masked_a.y2; row++) {
for(col = 0; col < map_useful_w; col++) {
lv_color_t px_color = (lv_color_t) *((lv_color_t *)&map_p[(uint32_t)col * px_size_byte]);
disp->driver.vdb_wr((uint8_t*)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa);
}
map_p += map_width * px_size_byte; /*Next row on the map*/
}
}
/*Normal native VDB*/
else {
for(row = masked_a.y1; row <= masked_a.y2; row++) {
#if USE_LV_GPU
if(lv_disp_is_mem_blend_supported() == false) {
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
} else {
lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
}
if(lv_disp_is_mem_blend_supported() == false) {
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
} else {
lv_disp_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
}
#else
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
#endif
map_p += map_width * px_size_byte; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
map_p += map_width * px_size_byte; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
}
/*In the other cases every pixel need to be checked one-by-one*/
@@ -431,29 +463,36 @@ void lv_vmap(const lv_area_t * cords_p, const lv_area_t * mask_p,
/*Re-color the pixel if required*/
if(recolor_opa != LV_OPA_TRANSP) {
if(last_img_px.full != px_color.full) { /*Minor acceleration: calculate only for new colors (save the last)*/
last_img_px = px_color;
recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
}
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full;
else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result);
/*Handle custom VDB write is present*/
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t*)vdb_p->buf, vdb_width, col + masked_a.x1, row, recolored_px, opa_result);
}
/*Normal native VDB write*/
else {
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col].full = recolored_px.full;
else vdb_buf_tmp[col] = lv_color_mix(recolored_px, vdb_buf_tmp[col], opa_result);
}
} else {
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;
else vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
/*Handle custom VDB write is present*/
if(disp->driver.vdb_wr) {
disp->driver.vdb_wr((uint8_t*)vdb_p->buf, vdb_width, col + masked_a.x1, row, px_color, opa_result);
}
/*Normal native VDB write*/
else {
if(opa_result == LV_OPA_COVER) vdb_buf_tmp[col] = px_color;
else vdb_buf_tmp[col] = lv_color_mix(px_color, vdb_buf_tmp[col], opa_result);
}
}
}
/*Next row on the map*/
map_p += map_width * px_size_byte;
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
map_p += map_width * px_size_byte; /*Next row on the map*/
vdb_buf_tmp += vdb_width; /*Next row on the VDB*/
}
}
}
/**********************
@@ -489,44 +528,55 @@ static void sw_mem_blend(lv_color_t * dest, const lv_color_t * src, uint32_t len
*/
static void sw_color_fill(lv_area_t * mem_area, lv_color_t * mem, const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)
{
/*Set all row in vdb to the given color*/
lv_coord_t row;
lv_coord_t col;
lv_coord_t mem_width = lv_area_get_width(mem_area);
/*Run simpler function without opacity*/
if(opa == LV_OPA_COVER) {
/*Fill the first row with 'color'*/
for(col = fill_area->x1; col <= fill_area->x2; col++) {
mem[col] = color;
}
lv_disp_t * disp = lv_disp_get_active();
if(disp->driver.vdb_wr) {
for(col = fill_area->x1; col <= fill_area->x2; col++) {
for(row = fill_area->y1; row <= fill_area->y2; row++) {
disp->driver.vdb_wr((uint8_t*)mem, mem_width, col, row, color, opa);
}
}
} else {
mem += fill_area->y1 * mem_width; /*Go to the first row*/
/*Copy the first row to all other rows*/
lv_color_t * mem_first = &mem[fill_area->x1];
lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t);
mem += mem_width;
/*Run simpler function without opacity*/
if(opa == LV_OPA_COVER) {
for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) {
memcpy(&mem[fill_area->x1], mem_first, copy_size);
mem += mem_width;
}
}
/*Calculate with alpha too*/
else {
lv_color_t bg_tmp = LV_COLOR_BLACK;
lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);
for(row = fill_area->y1; row <= fill_area->y2; row++) {
for(col = fill_area->x1; col <= fill_area->x2; col++) {
/*If the bg color changed recalculate the result color*/
if(mem[col].full != bg_tmp.full) {
bg_tmp = mem[col];
opa_tmp = lv_color_mix(color, bg_tmp, opa);
}
mem[col] = opa_tmp;
}
mem += mem_width;
}
/*Fill the first row with 'color'*/
for(col = fill_area->x1; col <= fill_area->x2; col++) {
mem[col] = color;
}
/*Copy the first row to all other rows*/
lv_color_t * mem_first = &mem[fill_area->x1];
lv_coord_t copy_size = (fill_area->x2 - fill_area->x1 + 1) * sizeof(lv_color_t);
mem += mem_width;
for(row = fill_area->y1 + 1; row <= fill_area->y2; row++) {
memcpy(&mem[fill_area->x1], mem_first, copy_size);
mem += mem_width;
}
}
/*Calculate with alpha too*/
else {
lv_color_t bg_tmp = LV_COLOR_BLACK;
lv_color_t opa_tmp = lv_color_mix(color, bg_tmp, opa);
for(row = fill_area->y1; row <= fill_area->y2; row++) {
for(col = fill_area->x1; col <= fill_area->x2; col++) {
/*If the bg color changed recalculate the result color*/
if(mem[col].full != bg_tmp.full) {
bg_tmp = mem[col];
opa_tmp = lv_color_mix(color, bg_tmp, opa);
}
mem[col] = opa_tmp;
}
mem += mem_width;
}
}
}
}

View File

@@ -57,6 +57,10 @@ void lv_disp_drv_init(lv_disp_drv_t * driver)
driver->mem_blend = NULL;
driver->mem_fill = NULL;
#endif
#if LV_VDB_SIZE
driver->vdb_wr = NULL;
#endif
}
/**
@@ -224,6 +228,7 @@ bool lv_disp_is_mem_fill_supported(void)
if(active->driver.mem_fill) return true;
else return false;
}
#endif
/**********************

View File

@@ -19,6 +19,7 @@ extern "C" {
#include <stdbool.h>
#include "lv_hal.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
/*********************
* DEFINES
@@ -41,6 +42,7 @@ typedef struct _disp_drv_t {
/*Write pixel map (e.g. image) to the display*/
void (*disp_map)(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p);
/*Optional interface functions to use GPU*/
#if USE_LV_GPU
/*Blend two memories using opacity (GPU only)*/
void (*mem_blend)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
@@ -49,6 +51,10 @@ typedef struct _disp_drv_t {
void (*mem_fill)(lv_color_t * dest, uint32_t length, lv_color_t color);
#endif
#if LV_VDB_SIZE
/*Optional: Set a pixel in a buffer according to the requirements of the display*/
void (*vdb_wr)(uint8_t * buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y, lv_color_t color, lv_opa_t opa);
#endif
} lv_disp_drv_t;
typedef struct _disp_t {

View File

@@ -57,6 +57,17 @@ extern "C" {
#define LV_OPA_100 255
#define LV_OPA_COVER 255
#if LV_COLOR_DEPTH == 1
#define LV_COLOR_SIZE 8
#elif LV_COLOR_DEPTH == 8
#define LV_COLOR_SIZE 8
#elif LV_COLOR_DEPTH == 16
#define LV_COLOR_SIZE 16
#elif LV_COLOR_DEPTH == 24
#define LV_COLOR_SIZE 32
#else
#error "Invalid color depth (LV_COLOR_DEPTH in lv_conf.h)"
#endif
/**********************
* TYPEDEFS

View File

@@ -249,6 +249,18 @@ lv_img_src_t lv_img_get_src_type(const void * src)
else return LV_IMG_SRC_UNKNOWN;
}
/**
* Get the source of the image
* @param img pointer to an image object
* @return the image source (symbol, file name or C array)
*/
const void * lv_img_get_src(lv_obj_t * img)
{
lv_img_ext_t * ext = lv_obj_get_ext_attr(img);
return ext->src;
}
/**
* Get the name of the file set for an image
* @param img pointer to an image

View File

@@ -125,6 +125,12 @@ static inline void lv_img_set_upscale(lv_obj_t * img, bool upcale)
*/
lv_img_src_t lv_img_get_src_type(const void * src);
/**
* Get the source of the image
* @param img pointer to an image object
* @return the image source (symbol, file name or C array)
*/
const void * lv_img_get_src(lv_obj_t * img);
/**
* Get the name of the file set for an image

View File

@@ -119,16 +119,16 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy)
} else {
lv_list_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
lv_obj_t * copy_btn = lv_obj_get_child_back(lv_page_get_scrl(copy), NULL);
lv_obj_t * new_btn;
lv_obj_t * copy_btn = get_prev_btn(copy, NULL);
while(copy_btn) {
new_btn = lv_btn_create(new_list, copy_btn);
const void * img_src = NULL;
#if USE_LV_IMG
lv_obj_t * copy_img = lv_list_get_btn_img(copy_btn);
if(copy_img) lv_img_create(new_btn, copy_img);
if(copy_img) img_src = lv_img_get_src(copy_img);
#endif
lv_label_create(new_btn, lv_list_get_btn_label(copy_btn));
copy_btn = lv_obj_get_child_back(lv_page_get_scrl(copy), copy_btn);
lv_list_add(new_list, img_src, lv_list_get_btn_text(copy_btn), lv_btn_get_action(copy_btn, LV_BTN_ACTION_CLICK));
// new_btn = lv_btn_create(new_list, copy_btn);
copy_btn = get_prev_btn(copy, copy_btn);
}
lv_list_set_style(new_list, LV_LIST_STYLE_BTN_REL, copy_ext->styles_btn[LV_BTN_STATE_REL]);
@@ -684,10 +684,9 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para
btn_i = get_next_btn(list, btn_i);
}
/*Make the released button "selected"*/
lv_list_set_btn_selected(list, btn);
}
/*Make the released button "selected"*/
lv_list_set_btn_selected(list, btn);
/* If `click_focus == 1` then LV_SIGNAL_FOCUS need to know which button triggered the focus
* to mark it as selected (pressed state)*/