mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
Merge branch 'dev'
This commit is contained in:
commit
975ab3f4cc
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,17 @@
|
||||
# Changelog
|
||||
|
||||
## v7.1.0 (under development)
|
||||
*Available in the `dev` branch*
|
||||
|
||||
### New features
|
||||
- Add `focus_parent` attribute to `lv_obj`
|
||||
- Allow using buttons in encoder input device
|
||||
- Add lv_btnmatrix_set/get_align capability
|
||||
- DMA2D: Remove dependency on ST CubeMX HAL
|
||||
- Added `max_used` propriety to `lv_mem_monitor_t` struct
|
||||
|
||||
### Bugfixes
|
||||
- None
|
||||
|
||||
## v7.0.2 (16.06.2020)
|
||||
|
||||
|
@ -178,6 +178,9 @@ typedef void * lv_group_user_data_t;
|
||||
/* 1: Enable GPU interface*/
|
||||
#define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */
|
||||
#define LV_USE_GPU_STM32_DMA2D 0
|
||||
/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor
|
||||
e.g. "stm32f769xx.h" or "stm32f429xx.h" */
|
||||
#define LV_GPU_DMA2D_CMSIS_INCLUDE
|
||||
|
||||
/* 1: Enable file system (might be required for images */
|
||||
#define LV_USE_FILESYSTEM 1
|
||||
@ -249,6 +252,10 @@ typedef void * lv_img_decoder_user_data_t;
|
||||
*/
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
|
||||
|
||||
/* Prefix variables that are used in GPU accelerated operations, often these need to be
|
||||
* placed in RAM sections that are DMA accessible */
|
||||
#define LV_ATTRIBUTE_DMA
|
||||
|
||||
/*===================
|
||||
* HAL settings
|
||||
*==================*/
|
||||
|
@ -176,6 +176,15 @@ static inline lv_obj_t * lv_page_get_scrl(lv_obj_t * page)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_USE_WIN
|
||||
|
||||
static inline lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src)
|
||||
{
|
||||
return lv_win_add_btn_right(win, img_src);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*LV_USE_API_EXTENSION_V6*/
|
||||
|
||||
/**********************
|
||||
|
@ -363,6 +363,12 @@
|
||||
#define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning
|
||||
#endif
|
||||
|
||||
/* Prefix variables that are used in GPU accelerated operations, often these need to be
|
||||
* placed in RAM sections that are DMA accessible */
|
||||
#ifndef LV_ATTRIBUTE_DMA
|
||||
#define LV_ATTRIBUTE_DMA
|
||||
#endif
|
||||
|
||||
/*===================
|
||||
* HAL settings
|
||||
*==================*/
|
||||
|
@ -607,8 +607,158 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
indev_obj_act = lv_group_get_focused(g);
|
||||
if(indev_obj_act == NULL) return;
|
||||
|
||||
/*Process the steps first. They are valid only with released button*/
|
||||
if(data->state == LV_INDEV_STATE_REL) {
|
||||
/*Process the steps they are valid only with released button*/
|
||||
if(data->state != LV_INDEV_STATE_REL) {
|
||||
data->enc_diff = 0;
|
||||
}
|
||||
|
||||
/*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
|
||||
indev_obj_act = lv_group_get_focused(g);
|
||||
if(indev_obj_act == NULL) return;
|
||||
|
||||
/*Button press happened*/
|
||||
if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_REL) {
|
||||
|
||||
i->proc.pr_timestamp = lv_tick_get();
|
||||
|
||||
if (data->key == LV_KEY_ENTER) {
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
if(lv_group_get_editing(g) == true || editable == false) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
} else if(data->key == LV_KEY_LEFT) {
|
||||
/*emulate encoder left*/
|
||||
data->enc_diff--;
|
||||
} else if(data->key == LV_KEY_RIGHT) {
|
||||
/*emulate encoder right*/
|
||||
data->enc_diff++;
|
||||
} else if(data->key == LV_KEY_ESC) {
|
||||
/*Send the ESC as a normal KEY*/
|
||||
lv_group_send_data(g, LV_KEY_ESC);
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CANCEL, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
/*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
|
||||
else {
|
||||
lv_group_send_data(g, data->key);
|
||||
}
|
||||
}
|
||||
/*Pressing*/
|
||||
else if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_PR) {
|
||||
/* Long press*/
|
||||
if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver.long_press_time) {
|
||||
|
||||
i->proc.long_pr_sent = 1;
|
||||
i->proc.longpr_rep_timestamp = lv_tick_get();
|
||||
|
||||
if (data->key == LV_KEY_ENTER) {
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
/*On enter long press toggle edit mode.*/
|
||||
if(editable) {
|
||||
/*Don't leave edit mode if there is only one object (nowhere to navigate)*/
|
||||
if(_lv_ll_is_empty(&g->obj_ll) == false) {
|
||||
lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
|
||||
}
|
||||
}
|
||||
/*If not editable then just send a long press signal*/
|
||||
else {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
}
|
||||
|
||||
i->proc.long_pr_sent = 1;
|
||||
}
|
||||
/*Long press repeated time has elapsed?*/
|
||||
else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver.long_press_rep_time) {
|
||||
|
||||
i->proc.longpr_rep_timestamp = lv_tick_get();
|
||||
|
||||
if(data->key == LV_KEY_ENTER) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS_REP, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
else if(data->key == LV_KEY_LEFT) {
|
||||
/*emulate encoder left*/
|
||||
data->enc_diff--;
|
||||
} else if(data->key == LV_KEY_RIGHT) {
|
||||
/*emulate encoder right*/
|
||||
data->enc_diff++;
|
||||
} else {
|
||||
lv_group_send_data(g, data->key);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
/*Release happened*/
|
||||
else if(data->state == LV_INDEV_STATE_REL && last_state == LV_INDEV_STATE_PR) {
|
||||
|
||||
if (data->key == LV_KEY_ENTER) {
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
/*The button was released on a non-editable object. Just send enter*/
|
||||
if(editable == false) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
/*An object is being edited and the button is released. */
|
||||
else if(g->editing) {
|
||||
/*Ignore long pressed enter release because it comes from mode switch*/
|
||||
if(!i->proc.long_pr_sent || _lv_ll_is_empty(&g->obj_ll)) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_group_send_data(g, LV_KEY_ENTER);
|
||||
}
|
||||
}
|
||||
/*If the focused object is editable and now in navigate mode then on enter switch edit
|
||||
mode*/
|
||||
else if(editable && !g->editing && !i->proc.long_pr_sent) {
|
||||
lv_group_set_editing(g, true); /*Set edit mode*/
|
||||
}
|
||||
}
|
||||
|
||||
i->proc.pr_timestamp = 0;
|
||||
i->proc.long_pr_sent = 0;
|
||||
}
|
||||
indev_obj_act = NULL;
|
||||
|
||||
/*if encoder steps or simulated steps via left/right keys*/
|
||||
if (data->enc_diff != 0) {
|
||||
/*In edit mode send LEFT/RIGHT keys*/
|
||||
if(lv_group_get_editing(g)) {
|
||||
int32_t s;
|
||||
@ -631,96 +781,6 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
|
||||
}
|
||||
}
|
||||
|
||||
/*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
|
||||
indev_obj_act = lv_group_get_focused(g);
|
||||
if(indev_obj_act == NULL) return;
|
||||
|
||||
/*Button press happened*/
|
||||
if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_REL) {
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
i->proc.pr_timestamp = lv_tick_get();
|
||||
if(lv_group_get_editing(g) == true || editable == false) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
}
|
||||
/*Pressing*/
|
||||
else if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_PR) {
|
||||
if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver.long_press_time) {
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
/*On enter long press toggle edit mode.*/
|
||||
if(editable) {
|
||||
/*Don't leave edit mode if there is only one object (nowhere to navigate)*/
|
||||
if(_lv_ll_is_empty(&g->obj_ll) == false) {
|
||||
lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/
|
||||
}
|
||||
}
|
||||
/*If not editable then just send a long press signal*/
|
||||
else {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
i->proc.long_pr_sent = 1;
|
||||
}
|
||||
}
|
||||
/*Release happened*/
|
||||
else if(data->state == LV_INDEV_STATE_REL && last_state == LV_INDEV_STATE_PR) {
|
||||
|
||||
bool editable = false;
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
|
||||
|
||||
/*The button was released on a non-editable object. Just send enter*/
|
||||
if(editable == false) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
}
|
||||
/*An object is being edited and the button is released. */
|
||||
else if(g->editing) {
|
||||
/*Ignore long pressed enter release because it comes from mode switch*/
|
||||
if(!i->proc.long_pr_sent || _lv_ll_is_empty(&g->obj_ll)) {
|
||||
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
|
||||
if(indev_reset_check(&i->proc)) return;
|
||||
|
||||
lv_group_send_data(g, LV_KEY_ENTER);
|
||||
}
|
||||
}
|
||||
/*If the focused object is editable and now in navigate mode then on enter switch edit
|
||||
mode*/
|
||||
else if(editable && !g->editing && !i->proc.long_pr_sent) {
|
||||
lv_group_set_editing(g, true); /*Set edit mode*/
|
||||
}
|
||||
|
||||
i->proc.pr_timestamp = 0;
|
||||
i->proc.long_pr_sent = 0;
|
||||
}
|
||||
indev_obj_act = NULL;
|
||||
#else
|
||||
(void)data; /*Unused*/
|
||||
(void)i; /*Unused*/
|
||||
@ -1092,8 +1152,9 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
|
||||
static void indev_click_focus(lv_indev_proc_t * proc)
|
||||
{
|
||||
/*Handle click focus*/
|
||||
lv_obj_t * obj_to_focus = lv_obj_get_focused_obj(indev_obj_act);
|
||||
if(lv_obj_is_protected(indev_obj_act, LV_PROTECT_CLICK_FOCUS) == false &&
|
||||
proc->types.pointer.last_pressed != indev_obj_act) {
|
||||
proc->types.pointer.last_pressed != obj_to_focus) {
|
||||
#if LV_USE_GROUP
|
||||
lv_group_t * g_act = lv_obj_get_group(indev_obj_act);
|
||||
lv_group_t * g_prev = proc->types.pointer.last_pressed ? lv_obj_get_group(proc->types.pointer.last_pressed) : NULL;
|
||||
@ -1172,7 +1233,7 @@ static void indev_click_focus(lv_indev_proc_t * proc)
|
||||
lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, NULL);
|
||||
if(indev_reset_check(proc)) return;
|
||||
#endif
|
||||
proc->types.pointer.last_pressed = indev_obj_act;
|
||||
proc->types.pointer.last_pressed = obj_to_focus;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,10 @@
|
||||
|
||||
#include LV_THEME_DEFAULT_INCLUDE
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
#include "../lv_gpu/lv_gpu_stm32_dma2d.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@ -140,6 +144,11 @@ void lv_init(void)
|
||||
_lv_group_init();
|
||||
#endif
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
/*Initialize DMA2D GPU*/
|
||||
lv_gpu_stm32_dma2d_init();
|
||||
#endif
|
||||
|
||||
_lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(lv_style_trans_t));
|
||||
|
||||
_lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t));
|
||||
@ -298,6 +307,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
|
||||
|
||||
#if LV_USE_GROUP
|
||||
new_obj->group_p = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
/*Set attributes*/
|
||||
@ -312,6 +322,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
|
||||
new_obj->protect = LV_PROTECT_NONE;
|
||||
new_obj->parent_event = 0;
|
||||
new_obj->gesture_parent = parent ? 1 : 0;
|
||||
new_obj->focus_parent = 0;
|
||||
new_obj->state = LV_STATE_DEFAULT;
|
||||
|
||||
new_obj->ext_attr = NULL;
|
||||
@ -1543,6 +1554,31 @@ void lv_obj_set_gesture_parent(lv_obj_t * obj, bool en)
|
||||
obj->gesture_parent = (en == true ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable to use parent for focus state.
|
||||
* When object is focused the parent will get the state instead (visual only)
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the 'focus parent' for the object
|
||||
*/
|
||||
void lv_obj_set_focus_parent(lv_obj_t * obj, bool en)
|
||||
{
|
||||
if (lv_obj_is_focused(obj)) {
|
||||
if (en) {
|
||||
obj->focus_parent = 1;
|
||||
lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
lv_obj_set_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED);
|
||||
}
|
||||
else {
|
||||
lv_obj_clear_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
lv_obj_set_state(obj, LV_STATE_FOCUSED);
|
||||
obj->focus_parent = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj->focus_parent = (en == true ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the events to the parent too
|
||||
* @param obj pointer to an object
|
||||
@ -2744,6 +2780,16 @@ bool lv_obj_get_gesture_parent(const lv_obj_t * obj)
|
||||
return obj->gesture_parent == 0 ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the focus parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: focus parent is enabled
|
||||
*/
|
||||
bool lv_obj_get_focus_parent(const lv_obj_t * obj)
|
||||
{
|
||||
return obj->focus_parent == 0 ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the drag parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
@ -3638,6 +3684,23 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area
|
||||
return LV_DESIGN_RES_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the really focused object by taking `focus_parent` into account.
|
||||
* @param obj the start object
|
||||
* @return the object to really focus
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj)
|
||||
{
|
||||
if(obj == NULL) return NULL;
|
||||
const lv_obj_t * focus_obj = obj;
|
||||
while(lv_obj_get_focus_parent(focus_obj) != false && focus_obj != NULL) {
|
||||
focus_obj = lv_obj_get_parent(focus_obj);
|
||||
}
|
||||
|
||||
return (lv_obj_t*)focus_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal function of the basic object
|
||||
* @param obj pointer to an object
|
||||
@ -3686,14 +3749,26 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)
|
||||
if(lv_group_get_editing(lv_obj_get_group(obj))) {
|
||||
uint8_t state = LV_STATE_FOCUSED;
|
||||
state |= LV_STATE_EDITED;
|
||||
|
||||
/*if using focus mode, change target to parent*/
|
||||
obj = lv_obj_get_focused_obj(obj);
|
||||
|
||||
lv_obj_add_state(obj, state);
|
||||
}
|
||||
else {
|
||||
|
||||
/*if using focus mode, change target to parent*/
|
||||
obj = lv_obj_get_focused_obj(obj);
|
||||
|
||||
lv_obj_add_state(obj, LV_STATE_FOCUSED);
|
||||
lv_obj_clear_state(obj, LV_STATE_EDITED);
|
||||
}
|
||||
}
|
||||
else if(sign == LV_SIGNAL_DEFOCUS) {
|
||||
|
||||
/*if using focus mode, change target to parent*/
|
||||
obj = lv_obj_get_focused_obj(obj);
|
||||
|
||||
lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED);
|
||||
}
|
||||
#endif
|
||||
@ -4063,4 +4138,3 @@ static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_fin
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -221,7 +221,8 @@ typedef struct _lv_obj_t {
|
||||
uint8_t top : 1; /**< 1: If the object or its children is clicked it goes to the foreground*/
|
||||
uint8_t parent_event : 1; /**< 1: Send the object's events to the parent too. */
|
||||
uint8_t adv_hittest : 1; /**< 1: Use advanced hit-testing (slower) */
|
||||
uint8_t gesture_parent : 1; /**< 1: Parent will be gesture instead*/
|
||||
uint8_t gesture_parent : 1; /**< 1: Parent will be gesture instead*/
|
||||
uint8_t focus_parent : 1; /**< 1: Parent will be focused instead*/
|
||||
|
||||
lv_drag_dir_t drag_dir : 3; /**< Which directions the object can be dragged in */
|
||||
lv_bidi_dir_t base_dir : 2; /**< Base direction of texts related to this object */
|
||||
@ -685,6 +686,14 @@ void lv_obj_set_drag_throw(lv_obj_t * obj, bool en);
|
||||
*/
|
||||
void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable to use parent for focus state.
|
||||
* When object is focused the parent will get the state instead (visual only)
|
||||
* @param obj pointer to an object
|
||||
* @param en true: enable the 'focus parent' for the object
|
||||
*/
|
||||
void lv_obj_set_focus_parent(lv_obj_t * obj, bool en);
|
||||
|
||||
/**
|
||||
* Enable to use parent for gesture related operations.
|
||||
* If trying to gesture the object the parent will be moved instead
|
||||
@ -1187,6 +1196,15 @@ bool lv_obj_get_drag_throw(const lv_obj_t * obj);
|
||||
*/
|
||||
bool lv_obj_get_drag_parent(const lv_obj_t * obj);
|
||||
|
||||
|
||||
/**
|
||||
* Get the focus parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
* @return true: focus parent is enabled
|
||||
*/
|
||||
bool lv_obj_get_focus_parent(const lv_obj_t * obj);
|
||||
|
||||
|
||||
/**
|
||||
* Get the drag parent attribute of an object
|
||||
* @param obj pointer to an object
|
||||
@ -1318,6 +1336,13 @@ void * lv_obj_get_group(const lv_obj_t * obj);
|
||||
*/
|
||||
bool lv_obj_is_focused(const lv_obj_t * obj);
|
||||
|
||||
/**
|
||||
* Get the really focused object by taking `focus_parent` into account.
|
||||
* @param obj the start object
|
||||
* @return the object to really focus
|
||||
*/
|
||||
lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj);
|
||||
|
||||
/*-------------------
|
||||
* OTHER FUNCTIONS
|
||||
*------------------*/
|
||||
|
@ -199,6 +199,99 @@ _LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_END_COLOR, scale_end_color, lv_color_t, _col
|
||||
|
||||
#undef _LV_OBJ_STYLE_SET_GET_DECLARE
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_pad_all(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_pad_top(obj, part, state, value);
|
||||
lv_obj_set_style_local_pad_bottom(obj, part, state, value);
|
||||
lv_obj_set_style_local_pad_left(obj, part, state, value);
|
||||
lv_obj_set_style_local_pad_right(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_pad_all(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_pad_top(style, state, value);
|
||||
lv_style_set_pad_bottom(style, state, value);
|
||||
lv_style_set_pad_left(style, state, value);
|
||||
lv_style_set_pad_right(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_pad_hor(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_pad_left(obj, part, state, value);
|
||||
lv_obj_set_style_local_pad_right(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_pad_hor(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_pad_left(style, state, value);
|
||||
lv_style_set_pad_right(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_pad_ver(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_pad_top(obj, part, state, value);
|
||||
lv_obj_set_style_local_pad_bottom(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_pad_ver(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_pad_top(style, state, value);
|
||||
lv_style_set_pad_bottom(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_margin_all(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_margin_top(obj, part, state, value);
|
||||
lv_obj_set_style_local_margin_bottom(obj, part, state, value);
|
||||
lv_obj_set_style_local_margin_left(obj, part, state, value);
|
||||
lv_obj_set_style_local_margin_right(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_margin_all(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_margin_top(style, state, value);
|
||||
lv_style_set_margin_bottom(style, state, value);
|
||||
lv_style_set_margin_left(style, state, value);
|
||||
lv_style_set_margin_right(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_margin_hor(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_margin_left(obj, part, state, value);
|
||||
lv_obj_set_style_local_margin_right(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_margin_hor(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_margin_left(style, state, value);
|
||||
lv_style_set_margin_right(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_obj_set_style_local_margin_ver(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_obj_set_style_local_margin_top(obj, part, state, value);
|
||||
lv_obj_set_style_local_margin_bottom(obj, part, state, value);
|
||||
}
|
||||
|
||||
|
||||
static inline void lv_style_set_margin_ver(lv_style_t * style, lv_state_t state, lv_style_int_t value)
|
||||
{
|
||||
lv_style_set_margin_top(style, state, value);
|
||||
lv_style_set_margin_bottom(style, state, value);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
@ -60,6 +60,10 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_GPU || LV_USE_GPU_STM32_DMA2D
|
||||
LV_ATTRIBUTE_DMA static lv_color_t blend_buf[LV_HOR_RES_MAX];
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
@ -338,7 +342,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
|
||||
else {
|
||||
#if LV_USE_GPU
|
||||
if(disp->driver.gpu_blend_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) {
|
||||
static lv_color_t blend_buf[LV_HOR_RES_MAX];
|
||||
for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full;
|
||||
|
||||
for(y = draw_area->y1; y <= draw_area->y2; y++) {
|
||||
@ -352,7 +355,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
if(lv_area_get_size(draw_area) >= 240) {
|
||||
static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0};
|
||||
if(blend_buf[0].full != color.full) lv_color_fill(blend_buf, color, LV_HOR_RES_MAX);
|
||||
|
||||
lv_coord_t line_h = LV_HOR_RES_MAX / draw_area_w;
|
||||
|
@ -528,8 +528,8 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t
|
||||
LV_UNUSED(pivot);
|
||||
res->x1 = 0;
|
||||
res->y1 = 0;
|
||||
res->x2 = w;
|
||||
res->y2 = h;
|
||||
res->x2 = w - 1;
|
||||
res->y2 = h - 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -11,19 +11,14 @@
|
||||
|
||||
#if LV_USE_GPU_STM32_DMA2D
|
||||
|
||||
#if defined(STM32F4)
|
||||
#include "stm32f4xx_hal.h"
|
||||
#elif defined(STM32F7)
|
||||
#include "stm32f7xx_hal.h"
|
||||
#else
|
||||
#error "Not supported STM32 family to use DMA2D"
|
||||
#endif
|
||||
#include LV_GPU_DMA2D_CMSIS_INCLUDE
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_COLOR_16_SWAP
|
||||
// TODO: F7 has red blue swap bit in control register for all layers and output
|
||||
#error "Can't use DMA2D with LV_COLOR_16_SWAP 1"
|
||||
#endif
|
||||
|
||||
@ -32,11 +27,9 @@
|
||||
#endif
|
||||
|
||||
#if LV_COLOR_DEPTH == 16
|
||||
#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565
|
||||
#define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565
|
||||
#define DMA2D_COLOR_FORMAT DMA2D_RGB565
|
||||
#elif LV_COLOR_DEPTH == 32
|
||||
#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_ARGB8888
|
||||
#define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888
|
||||
#define DMA2D_COLOR_FORMAT DMA2D_ARGB8888
|
||||
#else
|
||||
/*Can't use GPU with other formats*/
|
||||
#endif
|
||||
@ -54,7 +47,6 @@ static void dma2d_wait(void);
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static DMA2D_HandleTypeDef hdma2d;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -64,6 +56,21 @@ static DMA2D_HandleTypeDef hdma2d;
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Turn on the peripheral and set output color mode, this only needs to be done once
|
||||
*/
|
||||
void lv_gpu_stm32_dma2d_init(void)
|
||||
{
|
||||
/* Enable DMA2D clock */
|
||||
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
|
||||
|
||||
/* Delay after setting peripheral clock */
|
||||
volatile uint32_t temp = RCC->AHB1ENR;
|
||||
|
||||
/* set output colour mode */
|
||||
DMA2D->OPFCCR = DMA2D_COLOR_FORMAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill an area in the buffer with a color
|
||||
* @param buf a buffer which should be filled
|
||||
@ -77,18 +84,16 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo
|
||||
{
|
||||
invalidate_cache();
|
||||
|
||||
hdma2d.Instance = DMA2D;
|
||||
hdma2d.Init.Mode = DMA2D_R2M;
|
||||
hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT;
|
||||
hdma2d.Init.OutputOffset = buf_w - fill_w;
|
||||
hdma2d.LayerCfg[1].InputAlpha = DMA2D_NO_MODIF_ALPHA;
|
||||
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT;
|
||||
hdma2d.LayerCfg[1].InputOffset = 0;
|
||||
DMA2D->CR = 0x30000;
|
||||
DMA2D->OMAR = (uint32_t)buf;
|
||||
/* as input color mode is same as output we don't need to convert here do we? */
|
||||
DMA2D->OCOLR = color.full;
|
||||
DMA2D->OOR = buf_w - fill_w;
|
||||
DMA2D->NLR = (fill_w << DMA2D_NLR_PL_Pos) | (fill_h << DMA2D_NLR_NL_Pos);
|
||||
|
||||
/* start transfer */
|
||||
DMA2D->CR |= DMA2D_CR_START_Msk;
|
||||
|
||||
/* DMA2D Initialization */
|
||||
HAL_DMA2D_Init(&hdma2d);
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
|
||||
HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h);
|
||||
dma2d_wait();
|
||||
}
|
||||
|
||||
@ -106,6 +111,7 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo
|
||||
void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask,
|
||||
lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h)
|
||||
{
|
||||
#if 0
|
||||
invalidate_cache();
|
||||
|
||||
/* Configure the DMA2D Mode, Color Mode and line output offset */
|
||||
@ -134,6 +140,7 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
|
||||
HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h);
|
||||
dma2d_wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,22 +158,17 @@ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_
|
||||
{
|
||||
invalidate_cache();
|
||||
|
||||
hdma2d.Instance = DMA2D;
|
||||
hdma2d.Init.Mode = DMA2D_M2M;
|
||||
hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT;
|
||||
hdma2d.Init.OutputOffset = buf_w - copy_w;
|
||||
DMA2D->CR = 0;
|
||||
/* copy output colour mode, this register controls both input and output colour format */
|
||||
DMA2D->FGPFCCR = DMA2D_COLOR_FORMAT;
|
||||
DMA2D->FGMAR = (uint32_t)map;
|
||||
DMA2D->FGOR = map_w - copy_w;
|
||||
DMA2D->OMAR = (uint32_t)buf;
|
||||
DMA2D->OOR = buf_w - copy_w;
|
||||
DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
|
||||
|
||||
/* Foreground layer */
|
||||
hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
|
||||
hdma2d.LayerCfg[1].InputAlpha = 0xFF;
|
||||
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT;
|
||||
hdma2d.LayerCfg[1].InputOffset = map_w - copy_w;
|
||||
|
||||
/* DMA2D Initialization */
|
||||
HAL_DMA2D_Init(&hdma2d);
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 0);
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
|
||||
HAL_DMA2D_Start(&hdma2d, (uint32_t)map, (uint32_t)buf, copy_w, copy_h);
|
||||
/* start transfer */
|
||||
DMA2D->CR |= DMA2D_CR_START_Msk;
|
||||
dma2d_wait();
|
||||
}
|
||||
|
||||
@ -185,28 +187,26 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color
|
||||
lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h)
|
||||
{
|
||||
invalidate_cache();
|
||||
DMA2D->CR = 0x20000;
|
||||
|
||||
hdma2d.Instance = DMA2D;
|
||||
hdma2d.Init.Mode = DMA2D_M2M_BLEND;
|
||||
hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT;
|
||||
hdma2d.Init.OutputOffset = buf_w - copy_w;
|
||||
DMA2D->BGPFCCR = DMA2D_COLOR_FORMAT;
|
||||
DMA2D->BGMAR = (uint32_t)buf;
|
||||
DMA2D->BGOR = buf_w - copy_w;
|
||||
|
||||
/* Background layer */
|
||||
hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
|
||||
hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT;
|
||||
hdma2d.LayerCfg[0].InputOffset = buf_w - copy_w;
|
||||
DMA2D->FGPFCCR = (uint32_t)DMA2D_COLOR_FORMAT
|
||||
/* alpha mode 2, replace with foreground * alpha value */
|
||||
| (2 << DMA2D_FGPFCCR_AM_Pos)
|
||||
/* alpha value */
|
||||
| (opa << DMA2D_FGPFCCR_ALPHA_Pos);
|
||||
DMA2D->FGMAR = (uint32_t)map;
|
||||
DMA2D->FGOR = map_w - copy_w;
|
||||
|
||||
/* Foreground layer */
|
||||
hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
|
||||
hdma2d.LayerCfg[1].InputAlpha = opa;
|
||||
hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT;
|
||||
hdma2d.LayerCfg[1].InputOffset = map_w - copy_w;
|
||||
DMA2D->OMAR = (uint32_t)buf;
|
||||
DMA2D->OOR = buf_w - copy_w;
|
||||
DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
|
||||
|
||||
/* DMA2D Initialization */
|
||||
HAL_DMA2D_Init(&hdma2d);
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 0);
|
||||
HAL_DMA2D_ConfigLayer(&hdma2d, 1);
|
||||
HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h);
|
||||
/* start transfer */
|
||||
DMA2D->CR |= DMA2D_CR_START_Msk;
|
||||
dma2d_wait();
|
||||
}
|
||||
|
||||
@ -226,7 +226,7 @@ static void invalidate_cache(void)
|
||||
static void dma2d_wait(void)
|
||||
{
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
while(HAL_DMA2D_PollForTransfer(&hdma2d, 0) == HAL_TIMEOUT) {
|
||||
while(DMA2D->CR & DMA2D_CR_START_Msk) {
|
||||
if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver);
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,12 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define DMA2D_ARGB8888 0
|
||||
#define DMA2D_RGB888 1
|
||||
#define DMA2D_RGB565 2
|
||||
#define DMA2D_ARGB1555 3
|
||||
#define DMA2D_ARGB4444 4
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
@ -28,6 +34,11 @@ extern "C" {
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Turn on the peripheral and set output color mode, this only needs to be done once
|
||||
*/
|
||||
void lv_gpu_stm32_dma2d_init(void);
|
||||
|
||||
/**
|
||||
* Fill an area in the buffer with a color
|
||||
* @param buf a buffer which should be filled
|
||||
|
@ -143,6 +143,11 @@ bool _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data)
|
||||
else if(indev->driver.type == LV_INDEV_TYPE_KEYPAD) {
|
||||
data->key = indev->proc.types.keypad.last_key;
|
||||
}
|
||||
/*For compatibility assume that used button was enter (encoder push) */
|
||||
else if(indev->driver.type == LV_INDEV_TYPE_ENCODER) {
|
||||
data->key = LV_KEY_ENTER;
|
||||
data->enc_diff = 0;
|
||||
}
|
||||
|
||||
if(indev->driver.read_cb) {
|
||||
LV_LOG_TRACE("idnev read started");
|
||||
|
@ -85,7 +85,7 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/
|
||||
|
||||
static uint32_t mem_max_size; /*Tracks the maximum total size of memory ever used from the internal heap*/
|
||||
|
||||
static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE];
|
||||
static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE];
|
||||
@ -118,10 +118,11 @@ void _lv_mem_init(void)
|
||||
/*Allocate a large array to store the dynamically allocated data*/
|
||||
static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)];
|
||||
work_mem = (uint8_t *)work_mem_int;
|
||||
mem_max_size = 0;
|
||||
#else
|
||||
work_mem = (uint8_t *)LV_MEM_ADR;
|
||||
#endif
|
||||
|
||||
|
||||
lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem;
|
||||
full->header.s.used = 0;
|
||||
/*The total mem size id reduced by the first header and the close patterns */
|
||||
@ -200,7 +201,18 @@ void * lv_mem_alloc(size_t size)
|
||||
if(alloc != NULL) _lv_memset(alloc, 0xaa, size);
|
||||
#endif
|
||||
|
||||
if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory");
|
||||
if(alloc == NULL) {
|
||||
LV_LOG_WARN("Couldn't allocate memory");
|
||||
}else{
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/* just a safety check, should always be true */
|
||||
if ((uintptr_t) alloc > (uintptr_t) work_mem) {
|
||||
if ((((uintptr_t) alloc - (uintptr_t) work_mem) + size) > mem_max_size) {
|
||||
mem_max_size = ((uintptr_t) alloc - (uintptr_t) work_mem) + size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return alloc;
|
||||
}
|
||||
@ -424,6 +436,7 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p)
|
||||
e = ent_get_next(e);
|
||||
}
|
||||
mon_p->total_size = LV_MEM_SIZE;
|
||||
mon_p->max_used = mem_max_size;
|
||||
mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size;
|
||||
if(mon_p->free_size > 0) {
|
||||
mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size;
|
||||
|
@ -41,6 +41,7 @@ typedef struct {
|
||||
uint32_t free_size; /**< Size of available memory */
|
||||
uint32_t free_biggest_size;
|
||||
uint32_t used_cnt;
|
||||
uint32_t max_used; /**< Max size of Heap memory used */
|
||||
uint8_t used_pct; /**< Percentage used */
|
||||
uint8_t frag_pct; /**< Amount of fragmentation */
|
||||
} lv_mem_monitor_t;
|
||||
|
@ -422,6 +422,23 @@ void lv_btnmatrix_set_one_check(lv_obj_t * btnm, bool one_chk)
|
||||
make_one_button_toggled(btnm, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the align of the map text (left, right or center)
|
||||
* @param btnm pointer to a btnmatrix object
|
||||
* @param align LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER
|
||||
*/
|
||||
void lv_btnmatrix_set_align(lv_obj_t* btnm, lv_label_align_t align)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnmatrix_ext_t* ext = lv_obj_get_ext_attr(btnm);
|
||||
if (ext->align == align) return;
|
||||
|
||||
ext->align = align;
|
||||
|
||||
lv_obj_invalidate(btnm);
|
||||
}
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
@ -563,6 +580,32 @@ bool lv_btnmatrix_get_one_check(const lv_obj_t * btnm)
|
||||
return ext->one_check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the align attribute
|
||||
* @param btnm pointer to a btnmatrix object
|
||||
* @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER
|
||||
*/
|
||||
lv_label_align_t lv_btnmatrix_get_align(const lv_obj_t* btnm)
|
||||
{
|
||||
LV_ASSERT_OBJ(btnm, LV_OBJX_NAME);
|
||||
|
||||
lv_btnmatrix_ext_t* ext = lv_obj_get_ext_attr(btnm);
|
||||
|
||||
lv_label_align_t align = ext->align;
|
||||
|
||||
if (align == LV_LABEL_ALIGN_AUTO) {
|
||||
#if LV_USE_BIDI
|
||||
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm);
|
||||
if (base_dir == LV_BIDI_DIR_RTL) align = LV_LABEL_ALIGN_RIGHT;
|
||||
else align = LV_LABEL_ALIGN_LEFT;
|
||||
#else
|
||||
align = LV_LABEL_ALIGN_LEFT;
|
||||
#endif
|
||||
}
|
||||
|
||||
return align;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@ -598,7 +641,10 @@ static lv_design_res_t lv_btnmatrix_design(lv_obj_t * btnm, const lv_area_t * cl
|
||||
uint16_t btn_i = 0;
|
||||
uint16_t txt_i = 0;
|
||||
lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE;
|
||||
if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR;
|
||||
if (ext->recolor) txt_flag |= LV_TXT_FLAG_RECOLOR;
|
||||
lv_label_align_t align = lv_btnmatrix_get_align(btnm);
|
||||
if (align == LV_LABEL_ALIGN_CENTER) txt_flag |= LV_TXT_FLAG_CENTER;
|
||||
if (align == LV_LABEL_ALIGN_RIGHT) txt_flag |= LV_TXT_FLAG_RIGHT;
|
||||
|
||||
lv_draw_rect_dsc_t draw_rect_rel_dsc;
|
||||
lv_draw_label_dsc_t draw_label_rel_dsc;
|
||||
|
@ -59,6 +59,7 @@ typedef struct {
|
||||
uint16_t btn_id_act; /*Index of the active button (being pressed/released etc) or LV_BTNMATRIX_BTN_NONE */
|
||||
uint8_t recolor : 1; /*Enable button recoloring*/
|
||||
uint8_t one_check : 1; /*Single button toggled at once*/
|
||||
uint8_t align : 2; /*Align type from 'lv_label_align_t'*/
|
||||
} lv_btnmatrix_ext_t;
|
||||
|
||||
enum {
|
||||
@ -169,6 +170,13 @@ void lv_btnmatrix_set_btn_width(lv_obj_t * btnm, uint16_t btn_id, uint8_t width)
|
||||
* @param one_chk Whether "one check" mode is enabled
|
||||
*/
|
||||
void lv_btnmatrix_set_one_check(lv_obj_t * btnm, bool one_chk);
|
||||
|
||||
/**
|
||||
* Set the align of the map text (left, right or center)
|
||||
* @param btnm pointer to a btnmatrix object
|
||||
* @param align LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER
|
||||
*/
|
||||
void lv_btnmatrix_set_align(lv_obj_t* btnm, lv_label_align_t align);
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
@ -236,6 +244,14 @@ bool lv_btnmatrix_get_btn_ctrl(lv_obj_t * btnm, uint16_t btn_id, lv_btnmatrix_ct
|
||||
* @return whether "one toggle" mode is enabled
|
||||
*/
|
||||
bool lv_btnmatrix_get_one_check(const lv_obj_t * btnm);
|
||||
|
||||
/**
|
||||
* Get the align attribute
|
||||
* @param btnm pointer to a btnmatrix object
|
||||
* @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER
|
||||
*/
|
||||
lv_label_align_t lv_btnmatrix_get_align(const lv_obj_t* btnm);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
@ -712,6 +712,11 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param)
|
||||
if(ext->last_sel_btn) lv_list_focus_btn(list, ext->last_sel_btn);
|
||||
else lv_list_focus_btn(list, lv_list_get_next_btn(list, NULL));
|
||||
}
|
||||
if(indev_type == LV_INDEV_TYPE_ENCODER && lv_group_get_editing(g) == false) {
|
||||
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
|
||||
if(ext->act_sel_btn) lv_obj_clear_state(ext->act_sel_btn, LV_STATE_PRESSED);
|
||||
if(ext->last_sel_btn) lv_obj_clear_state(ext->last_sel_btn, LV_STATE_PRESSED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(sign == LV_SIGNAL_DEFOCUS) {
|
||||
@ -811,8 +816,10 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para
|
||||
else if(sign == LV_SIGNAL_CLEANUP) {
|
||||
#if LV_USE_GROUP
|
||||
lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn));
|
||||
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
|
||||
lv_obj_t * sel = lv_list_get_btn_selected(list);
|
||||
if(sel == btn) lv_list_focus_btn(list, lv_list_get_next_btn(list, btn));
|
||||
if(ext->last_sel_btn == btn) ext->last_sel_btn = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -485,6 +485,9 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, lv_anim_enable_t anim_
|
||||
lv_anim_del(ext->scrl, (lv_anim_exec_xcb_t)lv_obj_set_y);
|
||||
#endif
|
||||
|
||||
/*if using focus mode, change target to parent*/
|
||||
obj = lv_obj_get_focused_obj(obj);
|
||||
|
||||
|
||||
/*If obj is higher then the page focus where the "error" is smaller*/
|
||||
lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1;
|
||||
|
@ -23,6 +23,22 @@
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/** Extended data of win_btn*/
|
||||
typedef struct {
|
||||
/** Ext. of ancestor*/
|
||||
lv_btn_ext_t btn;
|
||||
|
||||
/** Which side of the header should the button be aligned to.
|
||||
* 0: Align to right (default), 1: Align to left */
|
||||
uint8_t alignment_in_header : 1;
|
||||
} lv_win_btn_ext_t;
|
||||
|
||||
enum {
|
||||
LV_WIN_BTN_ALIGN_RIGHT = 0, /**< Align button to right of the header */
|
||||
LV_WIN_BTN_ALIGN_LEFT /**< Align button to left of the header */
|
||||
};
|
||||
typedef uint8_t lv_win_btn_align_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
@ -30,6 +46,9 @@ static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param);
|
||||
static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * clip_area, lv_design_mode_t mode);
|
||||
static lv_style_list_t * lv_win_get_style(lv_obj_t * win, uint8_t part);
|
||||
static void lv_win_realign(lv_obj_t * win);
|
||||
static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src);
|
||||
static void lv_win_btn_set_alignment(lv_obj_t * par, const lv_win_btn_align_t alignment);
|
||||
static lv_win_btn_align_t lv_win_btn_get_alignment(const lv_obj_t * par);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -166,23 +185,39 @@ void lv_win_clean(lv_obj_t * win)
|
||||
* Add control button to the header of the window
|
||||
* @param win pointer to a window object
|
||||
* @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
|
||||
* @param alignment button alignment on the header
|
||||
* @return pointer to the created button object
|
||||
*/
|
||||
lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src)
|
||||
lv_obj_t * lv_win_add_btn_right(lv_obj_t * win, const void * img_src)
|
||||
{
|
||||
LV_ASSERT_OBJ(win, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(img_src);
|
||||
|
||||
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
|
||||
|
||||
lv_obj_t * btn = lv_btn_create(ext->header, NULL);
|
||||
lv_theme_apply(btn, LV_THEME_WIN_BTN);
|
||||
lv_coord_t btn_size = lv_obj_get_height_fit(ext->header);
|
||||
lv_obj_set_size(btn, btn_size, btn_size);
|
||||
lv_obj_t * btn = lv_win_btn_create(ext->header, img_src);
|
||||
lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_RIGHT);
|
||||
|
||||
lv_obj_t * img = lv_img_create(btn, NULL);
|
||||
lv_obj_set_click(img, false);
|
||||
lv_img_set_src(img, img_src);
|
||||
lv_win_realign(win);
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add control button on the left side of the window header
|
||||
* @param win pointer to a window object
|
||||
* @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
|
||||
* @return pointer to the created button object
|
||||
*/
|
||||
lv_obj_t * lv_win_add_btn_left(lv_obj_t * win, const void * img_src)
|
||||
{
|
||||
LV_ASSERT_OBJ(win, LV_OBJX_NAME);
|
||||
LV_ASSERT_NULL(img_src);
|
||||
|
||||
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
|
||||
|
||||
lv_obj_t * btn = lv_win_btn_create(ext->header, img_src);
|
||||
lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_LEFT);
|
||||
|
||||
lv_win_realign(win);
|
||||
|
||||
@ -501,7 +536,8 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t *
|
||||
lv_obj_t * win = lv_obj_get_parent(header);
|
||||
lv_win_ext_t * ext = lv_obj_get_ext_attr(win);
|
||||
|
||||
lv_style_int_t left = lv_obj_get_style_pad_left(header, LV_OBJ_PART_MAIN);
|
||||
lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER);
|
||||
lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER);
|
||||
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
lv_draw_label_dsc_init(&label_dsc);
|
||||
@ -510,13 +546,29 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t *
|
||||
lv_area_t txt_area;
|
||||
lv_point_t txt_size;
|
||||
|
||||
|
||||
_lv_txt_get_size(&txt_size, ext->title_txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX,
|
||||
label_dsc.flag);
|
||||
|
||||
txt_area.x1 = header->coords.x1 + left;
|
||||
lv_obj_t * btn = NULL;
|
||||
|
||||
lv_coord_t btn_h = lv_obj_get_height_fit(header);
|
||||
lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h;
|
||||
|
||||
/*Get x position of the title (should be on the right of the buttons on the left)*/
|
||||
|
||||
lv_coord_t left_btn_offset = 0;
|
||||
btn = lv_obj_get_child_back(ext->header, NULL);
|
||||
while(btn != NULL) {
|
||||
if (LV_WIN_BTN_ALIGN_LEFT == lv_win_btn_get_alignment(btn)) {
|
||||
left_btn_offset += btn_w + header_inner;
|
||||
}
|
||||
|
||||
btn = lv_obj_get_child_back(header, btn);
|
||||
}
|
||||
|
||||
txt_area.x1 = header->coords.x1 + header_left + left_btn_offset;
|
||||
txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2;
|
||||
txt_area.x2 = txt_area.x1 + txt_size.x;
|
||||
txt_area.x2 = txt_area.x1 + txt_size.x + left_btn_offset;
|
||||
txt_area.y2 = txt_area.y1 + txt_size.y;
|
||||
|
||||
lv_draw_label(&txt_area, clip_area, &label_dsc, ext->title_txt, NULL);
|
||||
@ -644,23 +696,52 @@ static void lv_win_realign(lv_obj_t * win)
|
||||
lv_obj_set_width(ext->header, lv_obj_get_width(win));
|
||||
|
||||
lv_obj_t * btn;
|
||||
lv_obj_t * btn_prev = NULL;
|
||||
lv_obj_t * btn_prev_at_left = NULL;
|
||||
lv_obj_t * btn_prev_at_right = NULL;
|
||||
|
||||
bool is_header_right_side_empty = true;
|
||||
bool is_header_left_side_empty = true;
|
||||
|
||||
lv_coord_t btn_h = lv_obj_get_height_fit(ext->header);
|
||||
lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h;
|
||||
lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER);
|
||||
lv_style_int_t header_right = lv_obj_get_style_pad_right(win, LV_WIN_PART_HEADER);
|
||||
lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER);
|
||||
|
||||
/*Refresh the size of all control buttons*/
|
||||
btn = lv_obj_get_child_back(ext->header, NULL);
|
||||
while(btn != NULL) {
|
||||
lv_obj_set_size(btn, btn_h, btn_w);
|
||||
if(btn_prev == NULL) {
|
||||
lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, -header_right, 0);
|
||||
lv_obj_set_size(btn, btn_w, btn_h);
|
||||
uint8_t btn_alignment = lv_win_btn_get_alignment(btn);
|
||||
|
||||
if (LV_WIN_BTN_ALIGN_RIGHT == btn_alignment) {
|
||||
if (is_header_right_side_empty) {
|
||||
/* Align the button to the right of the header */
|
||||
lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, -header_right, 0);
|
||||
|
||||
is_header_right_side_empty = false;
|
||||
} else {
|
||||
/* Align the button to the left of the previous button */
|
||||
lv_obj_align(btn, btn_prev_at_right, LV_ALIGN_OUT_LEFT_MID, -header_inner, 0);
|
||||
}
|
||||
|
||||
btn_prev_at_right = btn;
|
||||
}
|
||||
else {
|
||||
lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_inner, 0);
|
||||
else if (LV_WIN_BTN_ALIGN_LEFT == btn_alignment) {
|
||||
if (is_header_left_side_empty) {
|
||||
/* Align the button to the right of the header */
|
||||
lv_obj_align(btn, ext->header, LV_ALIGN_IN_LEFT_MID, header_left, 0);
|
||||
|
||||
is_header_left_side_empty = false;
|
||||
} else {
|
||||
/* Align the button to the right of the previous button */
|
||||
lv_obj_align(btn, btn_prev_at_left, LV_ALIGN_OUT_RIGHT_MID, header_inner, 0);
|
||||
}
|
||||
|
||||
btn_prev_at_left = btn;
|
||||
}
|
||||
btn_prev = btn;
|
||||
btn = lv_obj_get_child_back(ext->header, btn);
|
||||
|
||||
btn = lv_obj_get_child_back(ext->header, btn);
|
||||
}
|
||||
|
||||
lv_obj_set_pos(ext->header, 0, 0);
|
||||
@ -669,4 +750,54 @@ static void lv_win_realign(lv_obj_t * win)
|
||||
lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
|
||||
}
|
||||
|
||||
static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src)
|
||||
{
|
||||
LV_LOG_TRACE("win btn create started");
|
||||
|
||||
lv_obj_t * win_btn;
|
||||
|
||||
win_btn = lv_btn_create(par, NULL);
|
||||
LV_ASSERT_MEM(win_btn);
|
||||
if(win_btn == NULL) return NULL;
|
||||
|
||||
/*Allocate the extended data*/
|
||||
lv_win_btn_ext_t * ext = lv_obj_allocate_ext_attr(win_btn, sizeof(lv_win_btn_ext_t));
|
||||
LV_ASSERT_MEM(ext);
|
||||
if(ext == NULL) {
|
||||
lv_obj_del(win_btn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ext->alignment_in_header = LV_WIN_BTN_ALIGN_RIGHT;
|
||||
|
||||
lv_obj_set_click(win_btn, true);
|
||||
lv_win_btn_set_alignment(win_btn, LV_WIN_BTN_ALIGN_RIGHT);
|
||||
|
||||
lv_theme_apply(win_btn, LV_THEME_WIN_BTN);
|
||||
lv_coord_t btn_size = lv_obj_get_height_fit(par);
|
||||
lv_obj_set_size(win_btn, btn_size, btn_size);
|
||||
|
||||
lv_obj_t * img = lv_img_create(win_btn, NULL);
|
||||
lv_obj_set_click(img, false);
|
||||
lv_img_set_src(img, img_src);
|
||||
|
||||
LV_LOG_INFO("win btn created");
|
||||
|
||||
return win_btn;
|
||||
}
|
||||
|
||||
static void lv_win_btn_set_alignment(lv_obj_t * win_btn, const uint8_t alignment)
|
||||
{
|
||||
lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn);
|
||||
|
||||
ext->alignment_in_header = alignment;
|
||||
}
|
||||
|
||||
static uint8_t lv_win_btn_get_alignment(const lv_obj_t * win_btn)
|
||||
{
|
||||
lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn);
|
||||
|
||||
return ext->alignment_in_header;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -92,12 +92,20 @@ void lv_win_clean(lv_obj_t * win);
|
||||
*=====================*/
|
||||
|
||||
/**
|
||||
* Add control button to the header of the window
|
||||
* Add control button on the right side of the window header
|
||||
* @param win pointer to a window object
|
||||
* @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
|
||||
* @return pointer to the created button object
|
||||
*/
|
||||
lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src);
|
||||
lv_obj_t * lv_win_add_btn_right(lv_obj_t * win, const void * img_src);
|
||||
|
||||
/**
|
||||
* Add control button on the left side of the window header
|
||||
* @param win pointer to a window object
|
||||
* @param img_src an image source ('lv_img_t' variable, path to file or a symbol)
|
||||
* @return pointer to the created button object
|
||||
*/
|
||||
lv_obj_t * lv_win_add_btn_left(lv_obj_t * win, const void * img_src);
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
|
Loading…
x
Reference in New Issue
Block a user