CARPLAY版本整理

This commit is contained in:
2025-01-21 16:49:37 +08:00
commit f0fb64e4e6
26542 changed files with 13719676 additions and 0 deletions

View File

@ -0,0 +1,420 @@
/**
* @file lv_disp.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_disp.h"
#include "../lv_misc/lv_math.h"
#include "../lv_core/lv_refr.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_USE_ANIMATION
static void scr_load_anim_start(lv_anim_t * a);
static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v);
static void scr_anim_ready(lv_anim_t * a);
#endif
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Return with a pointer to the active screen
* @param disp pointer to display which active screen should be get. (NULL to use the default
* screen)
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
*/
lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("no display registered to get its active screen");
return NULL;
}
return disp->act_scr;
}
/**
* Return with a pointer to the previous screen. Only used during screen transitions.
* @param disp pointer to display which previous screen should be get. (NULL to use the default
* screen)
* @return pointer to the previous screen object or NULL if not used now
*/
lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("no display registered to get its previous screen");
return NULL;
}
return disp->prev_scr;
}
/**
* Make a screen active
* @param scr pointer to a screen
*/
void lv_disp_load_scr(lv_obj_t * scr)
{
lv_disp_t * d = lv_obj_get_disp(scr);
if(!d) return; /*Shouldn't happen, just to be sure*/
d->act_scr = scr;
lv_obj_invalidate(scr);
}
/**
* Return with the top layer. (Same on every screen and it is above the normal screen layer)
* @param disp pointer to display which top layer should be get. (NULL to use the default screen)
* @return pointer to the top layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("lv_layer_top: no display registered to get its top layer");
return NULL;
}
return disp->top_layer;
}
/**
* Return with the sys. layer. (Same on every screen and it is above the normal screen and the top
* layer)
* @param disp pointer to display which sys. layer should be get. (NULL to use the default screen)
* @return pointer to the sys layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("lv_layer_sys: no display registered to get its sys. layer");
return NULL;
}
return disp->sys_layer;
}
/**
* Assign a screen to a display.
* @param disp pointer to a display where to assign the screen
* @param scr pointer to a screen object to assign
*/
void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr)
{
if(lv_obj_get_parent(scr) != NULL) {
LV_LOG_WARN("lv_disp_assign_screen: try to assign a non-screen object");
return;
}
lv_disp_t * old_disp = lv_obj_get_disp(scr);
if(old_disp == disp) return;
_lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr, true);
}
/**
* Set the background color of a display
* @param disp pointer to a display
* @param color color of the background
*/
void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("no display registered");
return;
}
disp->bg_color = color;
lv_area_t a;
lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
_lv_inv_area(disp, &a);
}
/**
* Set the background image of a display
* @param disp pointer to a display
* @param img_src path to file or pointer to an `lv_img_dsc_t` variable
*/
void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("no display registered");
return;
}
disp->bg_img = img_src;
lv_area_t a;
lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
_lv_inv_area(disp, &a);
}
/**
* Opacity of the background
* @param disp pointer to a display
* @param opa opacity (0..255)
*/
void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("no display registered");
return;
}
disp->bg_opa = opa;
lv_area_t a;
lv_area_set(&a, 0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1);
_lv_inv_area(disp, &a);
}
#if LV_USE_ANIMATION
/**
* Switch screen with animation
* @param scr pointer to the new screen to load
* @param anim_type type of the animation from `lv_scr_load_anim_t`. E.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT`
* @param time time of the animation
* @param delay delay before the transition
* @param auto_del true: automatically delete the old screen
*/
void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del)
{
lv_disp_t * d = lv_obj_get_disp(new_scr);
lv_obj_t * act_scr = lv_scr_act();
if(d->del_prev && act_scr != d->scr_to_load && d->scr_to_load) {
lv_obj_del(act_scr);
lv_disp_load_scr(d->scr_to_load);
lv_anim_del(d->scr_to_load, NULL);
lv_obj_set_pos(d->scr_to_load, 0, 0);
lv_style_remove_prop(lv_obj_get_local_style(d->scr_to_load, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
act_scr = d->scr_to_load;
}
d->scr_to_load = new_scr;
if(d->prev_scr && d->del_prev) {
lv_obj_del(d->prev_scr);
d->prev_scr = NULL;
}
d->del_prev = auto_del;
/*Be sure there is no other animation on the screens*/
lv_anim_del(new_scr, NULL);
lv_anim_del(lv_scr_act(), NULL);
/*Be sure both screens are in a normal position*/
lv_obj_set_pos(new_scr, 0, 0);
lv_obj_set_pos(lv_scr_act(), 0, 0);
lv_style_remove_prop(lv_obj_get_local_style(new_scr, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
lv_style_remove_prop(lv_obj_get_local_style(lv_scr_act(), LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
lv_anim_t a_new;
lv_anim_init(&a_new);
lv_anim_set_var(&a_new, new_scr);
lv_anim_set_start_cb(&a_new, scr_load_anim_start);
lv_anim_set_ready_cb(&a_new, scr_anim_ready);
lv_anim_set_time(&a_new, time);
lv_anim_set_delay(&a_new, delay);
lv_anim_t a_old;
lv_anim_init(&a_old);
lv_anim_set_var(&a_old, d->act_scr);
lv_anim_set_time(&a_old, time);
lv_anim_set_delay(&a_old, delay);
switch(anim_type) {
case LV_SCR_LOAD_ANIM_NONE:
/* Create a dummy animation to apply the delay*/
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_new, 0, 0);
break;
case LV_SCR_LOAD_ANIM_OVER_LEFT:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
break;
case LV_SCR_LOAD_ANIM_OVER_RIGHT:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
break;
case LV_SCR_LOAD_ANIM_OVER_TOP:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
break;
case LV_SCR_LOAD_ANIM_OVER_BOTTOM:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
break;
case LV_SCR_LOAD_ANIM_MOVE_LEFT:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_new, lv_disp_get_hor_res(d), 0);
lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_old, 0, -lv_disp_get_hor_res(d));
break;
case LV_SCR_LOAD_ANIM_MOVE_RIGHT:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_new, -lv_disp_get_hor_res(d), 0);
lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_x);
lv_anim_set_values(&a_old, 0, lv_disp_get_hor_res(d));
break;
case LV_SCR_LOAD_ANIM_MOVE_TOP:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_new, lv_disp_get_ver_res(d), 0);
lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_old, 0, -lv_disp_get_ver_res(d));
break;
case LV_SCR_LOAD_ANIM_MOVE_BOTTOM:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_new, -lv_disp_get_ver_res(d), 0);
lv_anim_set_exec_cb(&a_old, (lv_anim_exec_xcb_t) lv_obj_set_y);
lv_anim_set_values(&a_old, 0, lv_disp_get_ver_res(d));
break;
case LV_SCR_LOAD_ANIM_FADE_ON:
lv_anim_set_exec_cb(&a_new, (lv_anim_exec_xcb_t) opa_scale_anim);
lv_anim_set_values(&a_new, LV_OPA_TRANSP, LV_OPA_COVER);
break;
}
lv_anim_start(&a_new);
lv_anim_start(&a_old);
}
#endif
/**
* Get elapsed time since last user activity on a display (e.g. click)
* @param disp pointer to an display (NULL to get the overall smallest inactivity)
* @return elapsed ticks (milliseconds) since the last activity
*/
uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp)
{
if(disp) return lv_tick_elaps(disp->last_activity_time);
lv_disp_t * d;
uint32_t t = UINT32_MAX;
d = lv_disp_get_next(NULL);
while(d) {
uint32_t elaps = lv_tick_elaps(d->last_activity_time);
t = LV_MATH_MIN(t, elaps);
d = lv_disp_get_next(d);
}
return t;
}
/**
* Manually trigger an activity on a display
* @param disp pointer to an display (NULL to use the default display)
*/
void lv_disp_trig_activity(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("lv_disp_trig_activity: no display registered");
return;
}
disp->last_activity_time = lv_tick_get();
}
/**
* Clean any CPU cache that is related to the display.
* @param disp pointer to an display (NULL to use the default display)
*/
void lv_disp_clean_dcache(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("lv_disp_clean_dcache: no display registered");
return;
}
if(disp->driver.clean_dcache_cb)
disp->driver.clean_dcache_cb(&disp->driver);
}
/**
* Get a pointer to the screen refresher task to
* modify its parameters with `lv_task_...` functions.
* @param disp pointer to a display
* @return pointer to the display refresher task. (NULL on error)
*/
lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) {
LV_LOG_WARN("lv_disp_get_refr_task: no display registered");
return NULL;
}
return disp->refr_task;
}
/**********************
* STATIC FUNCTIONS
**********************/
#if LV_USE_ANIMATION
static void scr_load_anim_start(lv_anim_t * a)
{
lv_disp_t * d = lv_obj_get_disp(a->var);
d->prev_scr = lv_scr_act();
lv_disp_load_scr(a->var);
}
static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v)
{
lv_obj_set_style_local_opa_scale(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v);
}
static void scr_anim_ready(lv_anim_t * a)
{
lv_disp_t * d = lv_obj_get_disp(a->var);
if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr);
d->prev_scr = NULL;
d->scr_to_load = NULL;
lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
}
#endif

View File

@ -0,0 +1,226 @@
/**
* @file lv_disp.h
*
*/
#ifndef LV_DISP_H
#define LV_DISP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_hal/lv_hal.h"
#include "lv_obj.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum {
LV_SCR_LOAD_ANIM_NONE,
LV_SCR_LOAD_ANIM_OVER_LEFT,
LV_SCR_LOAD_ANIM_OVER_RIGHT,
LV_SCR_LOAD_ANIM_OVER_TOP,
LV_SCR_LOAD_ANIM_OVER_BOTTOM,
LV_SCR_LOAD_ANIM_MOVE_LEFT,
LV_SCR_LOAD_ANIM_MOVE_RIGHT,
LV_SCR_LOAD_ANIM_MOVE_TOP,
LV_SCR_LOAD_ANIM_MOVE_BOTTOM,
LV_SCR_LOAD_ANIM_FADE_ON,
} lv_scr_load_anim_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Return with a pointer to the active screen
* @param disp pointer to display which active screen should be get. (NULL to use the default
* screen)
* @return pointer to the active screen object (loaded by 'lv_scr_load()')
*/
lv_obj_t * lv_disp_get_scr_act(lv_disp_t * disp);
/**
* Return with a pointer to the previous screen. Only used during screen transitions.
* @param disp pointer to display which previous screen should be get. (NULL to use the default
* screen)
* @return pointer to the previous screen object or NULL if not used now
*/
lv_obj_t * lv_disp_get_scr_prev(lv_disp_t * disp);
/**
* Make a screen active
* @param scr pointer to a screen
*/
void lv_disp_load_scr(lv_obj_t * scr);
/**
* Return with the top layer. (Same on every screen and it is above the normal screen layer)
* @param disp pointer to display which top layer should be get. (NULL to use the default screen)
* @return pointer to the top layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_disp_get_layer_top(lv_disp_t * disp);
/**
* Return with the sys. layer. (Same on every screen and it is above the normal screen and the top
* layer)
* @param disp pointer to display which sys. layer should be get. (NULL to use the default screen)
* @return pointer to the sys layer object (transparent screen sized lv_obj)
*/
lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp);
/**
* Assign a screen to a display.
* @param disp pointer to a display where to assign the screen
* @param scr pointer to a screen object to assign
*/
void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr);
/**
* Set the background color of a display
* @param disp pointer to a display
* @param color color of the background
*/
void lv_disp_set_bg_color(lv_disp_t * disp, lv_color_t color);
/**
* Set the background image of a display
* @param disp pointer to a display
* @param img_src path to file or pointer to an `lv_img_dsc_t` variable
*/
void lv_disp_set_bg_image(lv_disp_t * disp, const void * img_src);
/**
* Opacity of the background
* @param disp pointer to a display
* @param opa opacity (0..255)
*/
void lv_disp_set_bg_opa(lv_disp_t * disp, lv_opa_t opa);
#if LV_USE_ANIMATION
/**
* Switch screen with animation
* @param scr pointer to the new screen to load
* @param anim_type type of the animation from `lv_scr_load_anim_t`. E.g. `LV_SCR_LOAD_ANIM_MOVE_LEFT`
* @param time time of the animation
* @param delay delay before the transition
* @param auto_del true: automatically delete the old screen
*/
void lv_scr_load_anim(lv_obj_t * scr, lv_scr_load_anim_t anim_type, uint32_t time, uint32_t delay, bool auto_del);
#endif
/**
* Get elapsed time since last user activity on a display (e.g. click)
* @param disp pointer to an display (NULL to get the overall smallest inactivity)
* @return elapsed ticks (milliseconds) since the last activity
*/
uint32_t lv_disp_get_inactive_time(const lv_disp_t * disp);
/**
* Manually trigger an activity on a display
* @param disp pointer to an display (NULL to use the default display)
*/
void lv_disp_trig_activity(lv_disp_t * disp);
/**
* Clean any CPU cache that is related to the display.
* @param disp pointer to an display (NULL to use the default display)
*/
void lv_disp_clean_dcache(lv_disp_t * disp);
/**
* Get a pointer to the screen refresher task to
* modify its parameters with `lv_task_...` functions.
* @param disp pointer to a display
* @return pointer to the display refresher task. (NULL on error)
*/
lv_task_t * _lv_disp_get_refr_task(lv_disp_t * disp);
/*------------------------------------------------
* To improve backward compatibility
* Recommended only if you have one display
*------------------------------------------------*/
/**
* Get the active screen of the default display
* @return pointer to the active screen
*/
static inline lv_obj_t * lv_scr_act(void)
{
return lv_disp_get_scr_act(lv_disp_get_default());
}
/**
* Get the top layer of the default display
* @return pointer to the top layer
*/
static inline lv_obj_t * lv_layer_top(void)
{
return lv_disp_get_layer_top(lv_disp_get_default());
}
/**
* Get the active screen of the default display
* @return pointer to the sys layer
*/
static inline lv_obj_t * lv_layer_sys(void)
{
return lv_disp_get_layer_sys(lv_disp_get_default());
}
static inline void lv_scr_load(lv_obj_t * scr)
{
lv_disp_load_scr(scr);
}
/**********************
* MACROS
**********************/
/*------------------------------------------------
* To improve backward compatibility
* Recommended only if you have one display
*------------------------------------------------*/
#ifndef LV_HOR_RES
/**
* The horizontal resolution of the currently active display.
*/
#define LV_HOR_RES lv_disp_get_hor_res(lv_disp_get_default())
#endif
#ifndef LV_VER_RES
/**
* The vertical resolution of the currently active display.
*/
#define LV_VER_RES lv_disp_get_ver_res(lv_disp_get_default())
#endif
/**
* Same as Android's DIP. (Different name is chosen to avoid mistype between LV_DPI and LV_DIP)
* 1 dip is 1 px on a 160 DPI screen
* 1 dip is 2 px on a 320 DPI screen
* https://stackoverflow.com/questions/2025282/what-is-the-difference-between-px-dip-dp-and-sp
*/
#define LV_DPX(n) (n == 0 ? 0 :LV_MATH_MAX((( lv_disp_get_dpi(NULL) * (n) + 80) / 160), 1)) /*+80 for rounding*/
static inline lv_coord_t lv_dpx(lv_coord_t n)
{
return LV_DPX(n);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_DISP_H*/

View File

@ -0,0 +1,531 @@
/**
* @file lv_group.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_group.h"
#if LV_USE_GROUP != 0
#include <stddef.h>
#include "../lv_misc/lv_debug.h"
#include "../lv_themes/lv_theme.h"
#include "../lv_misc/lv_gc.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *),
void * (*move)(const lv_ll_t *, const void *));
static void lv_group_refocus(lv_group_t * g);
static void obj_to_foreground(lv_obj_t * obj);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Init. the group module
*/
void _lv_group_init(void)
{
_lv_ll_init(&LV_GC_ROOT(_lv_group_ll), sizeof(lv_group_t));
}
/**
* Create a new object group
* @return pointer to the new object group
*/
lv_group_t * lv_group_create(void)
{
lv_group_t * group = _lv_ll_ins_head(&LV_GC_ROOT(_lv_group_ll));
LV_ASSERT_MEM(group);
if(group == NULL) return NULL;
_lv_ll_init(&group->obj_ll, sizeof(lv_obj_t *));
group->obj_focus = NULL;
group->frozen = 0;
group->focus_cb = NULL;
group->click_focus = 1;
group->editing = 0;
group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV;
group->wrap = 1;
#if LV_USE_USER_DATA
_lv_memset_00(&group->user_data, sizeof(lv_group_user_data_t));
#endif
return group;
}
/**
* Delete a group object
* @param group pointer to a group
*/
void lv_group_del(lv_group_t * group)
{
/*Defocus the currently focused object*/
if(group->obj_focus != NULL) {
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
}
/*Remove the objects from the group*/
lv_obj_t ** obj;
_LV_LL_READ(group->obj_ll, obj) {
(*obj)->group_p = NULL;
}
_lv_ll_clear(&(group->obj_ll));
_lv_ll_remove(&LV_GC_ROOT(_lv_group_ll), group);
lv_mem_free(group);
}
/**
* Add an object to a group
* @param group pointer to a group
* @param obj pointer to an object to add
*/
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj)
{
if(group == NULL) return;
/*Do not add the object twice*/
lv_obj_t ** obj_i;
_LV_LL_READ(group->obj_ll, obj_i) {
if((*obj_i) == obj) {
LV_LOG_INFO("lv_group_add_obj: the object is already added to this group");
return;
}
}
/*If the object is already in a group and focused then defocus it*/
if(obj->group_p) {
if(lv_obj_is_focused(obj)) {
lv_group_refocus(obj->group_p);
LV_LOG_INFO("lv_group_add_obj: assign object to an other group");
}
}
obj->group_p = group;
lv_obj_t ** next = _lv_ll_ins_tail(&group->obj_ll);
LV_ASSERT_MEM(next);
if(next == NULL) return;
*next = obj;
/* If the head and the tail is equal then there is only one object in the linked list.
* In this case automatically activate it*/
if(_lv_ll_get_head(&group->obj_ll) == next) {
lv_group_refocus(group);
}
}
/**
* Remove an object from its group
* @param obj pointer to an object to remove
*/
void lv_group_remove_obj(lv_obj_t * obj)
{
lv_group_t * g = obj->group_p;
if(g == NULL) return;
/*Focus on the next object*/
if(*g->obj_focus == obj) {
if(g->frozen) g->frozen = 0;
/*If this is the only object in the group then focus to nothing.*/
if(_lv_ll_get_head(&g->obj_ll) == g->obj_focus && _lv_ll_get_tail(&g->obj_ll) == g->obj_focus) {
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
}
/*If there more objects in the group then focus to the next/prev object*/
else {
lv_group_refocus(g);
}
}
/* If the focuses object is still the same then it was the only object in the group but it will
* be deleted. Set the `obj_focus` to NULL to get back to the initial state of the group with
* zero objects*/
if(*g->obj_focus == obj) {
g->obj_focus = NULL;
}
/*Search the object and remove it from its group */
lv_obj_t ** i;
_LV_LL_READ(g->obj_ll, i) {
if(*i == obj) {
_lv_ll_remove(&g->obj_ll, i);
lv_mem_free(i);
obj->group_p = NULL;
break;
}
}
}
/**
* Remove all objects from a group
* @param group pointer to a group
*/
void lv_group_remove_all_objs(lv_group_t * group)
{
/*Defocus the currently focused object*/
if(group->obj_focus != NULL) {
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_obj_invalidate(*group->obj_focus);
group->obj_focus = NULL;
}
/*Remove the objects from the group*/
lv_obj_t ** obj;
_LV_LL_READ(group->obj_ll, obj) {
(*obj)->group_p = NULL;
}
_lv_ll_clear(&(group->obj_ll));
}
/**
* Focus on an object (defocus the current)
* @param obj pointer to an object to focus on
*/
void lv_group_focus_obj(lv_obj_t * obj)
{
if(obj == NULL) return;
lv_group_t * g = obj->group_p;
if(g == NULL) return;
if(g->frozen != 0) return;
if(g->obj_focus != NULL && obj == *g->obj_focus) return;
/*On defocus edit mode must be leaved*/
lv_group_set_editing(g, false);
lv_obj_t ** i;
_LV_LL_READ(g->obj_ll, i) {
if(*i == obj) {
if(g->obj_focus != NULL) {
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_res_t res = lv_event_send(*g->obj_focus, LV_EVENT_DEFOCUSED, NULL);
if(res != LV_RES_OK) return;
lv_obj_invalidate(*g->obj_focus);
}
g->obj_focus = i;
if(g->obj_focus != NULL) {
(*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_FOCUS, NULL);
if(g->focus_cb) g->focus_cb(g);
lv_res_t res = lv_event_send(*g->obj_focus, LV_EVENT_FOCUSED, NULL);
if(res != LV_RES_OK) return;
lv_obj_invalidate(*g->obj_focus);
/*If the object or its parent has `top == true` bring it to the foreground*/
obj_to_foreground(*g->obj_focus);
}
break;
}
}
}
/**
* Focus the next object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_next(lv_group_t * group)
{
focus_next_core(group, _lv_ll_get_head, _lv_ll_get_next);
}
/**
* Focus the previous object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_prev(lv_group_t * group)
{
focus_next_core(group, _lv_ll_get_tail, _lv_ll_get_prev);
}
/**
* Do not let to change the focus from the current object
* @param group pointer to a group
* @param en true: freeze, false: release freezing (normal mode)
*/
void lv_group_focus_freeze(lv_group_t * group, bool en)
{
if(en == false)
group->frozen = 0;
else
group->frozen = 1;
}
/**
* Send a control character to the focuses object of a group
* @param group pointer to a group
* @param c a character (use LV_KEY_.. to navigate)
* @return result of focused object in group.
*/
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c)
{
lv_obj_t * act = lv_group_get_focused(group);
if(act == NULL) return LV_RES_OK;
lv_res_t res;
res = act->signal_cb(act, LV_SIGNAL_CONTROL, &c);
if(res != LV_RES_OK) return res;
res = lv_event_send(act, LV_EVENT_KEY, &c);
if(res != LV_RES_OK) return res;
return res;
}
/**
* Set a function for a group which will be called when a new object is focused
* @param group pointer to a group
* @param focus_cb the call back function or NULL if unused
*/
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb)
{
group->focus_cb = focus_cb;
}
/**
* Manually set the current mode (edit or navigate).
* @param group pointer to group
* @param edit: true: edit mode; false: navigate mode
*/
void lv_group_set_editing(lv_group_t * group, bool edit)
{
if(group == NULL) return;
uint8_t en_val = edit ? 1 : 0;
if(en_val == group->editing) return; /*Do not set the same mode again*/
group->editing = en_val;
lv_obj_t * focused = lv_group_get_focused(group);
if(focused) {
focused->signal_cb(focused, LV_SIGNAL_FOCUS, NULL); /*Focus again to properly leave/open edit/navigate mode*/
lv_res_t res = lv_event_send(*group->obj_focus, LV_EVENT_FOCUSED, NULL);
if(res != LV_RES_OK) return;
lv_obj_invalidate(focused);
}
}
/**
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
* @param group pointer to group
* @param en: true: enable `click_focus`
*/
void lv_group_set_click_focus(lv_group_t * group, bool en)
{
group->click_focus = en ? 1 : 0;
}
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy)
{
group->refocus_policy = policy & 0x01;
}
/**
* Set whether focus next/prev will allow wrapping from first->last or last->first.
* @param group pointer to group
* @param en: true: enable `wrap`
*/
void lv_group_set_wrap(lv_group_t * group, bool en)
{
group->wrap = en ? 1 : 0;
}
/**
* Get the focused object or NULL if there isn't one
* @param group pointer to a group
* @return pointer to the focused object
*/
lv_obj_t * lv_group_get_focused(const lv_group_t * group)
{
if(!group) return NULL;
if(group->obj_focus == NULL) return NULL;
return *group->obj_focus;
}
#if LV_USE_USER_DATA
/**
* Get a pointer to the group's user data
* @param group pointer to an group
* @return pointer to the user data
*/
lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group)
{
return &group->user_data;
}
#endif
/**
* Get the focus callback function of a group
* @param group pointer to a group
* @return the call back function or NULL if not set
*/
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group)
{
if(!group) return NULL;
return group->focus_cb;
}
/**
* Get the current mode (edit or navigate).
* @param group pointer to group
* @return true: edit mode; false: navigate mode
*/
bool lv_group_get_editing(const lv_group_t * group)
{
if(!group) return false;
return group->editing ? true : false;
}
/**
* Get the `click_focus` attribute.
* @param group pointer to group
* @return true: `click_focus` is enabled; false: disabled
*/
bool lv_group_get_click_focus(const lv_group_t * group)
{
if(!group) return false;
return group->click_focus ? true : false;
}
/**
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
bool lv_group_get_wrap(lv_group_t * group)
{
if(!group) return false;
return group->wrap ? true : false;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_group_refocus(lv_group_t * g)
{
/*Refocus must temporarily allow wrapping to work correctly*/
uint8_t temp_wrap = g->wrap;
g->wrap = 1;
if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_NEXT)
lv_group_focus_next(g);
else if(g->refocus_policy == LV_GROUP_REFOCUS_POLICY_PREV)
lv_group_focus_prev(g);
/*Restore wrap property*/
g->wrap = temp_wrap;
}
static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *),
void * (*move)(const lv_ll_t *, const void *))
{
if(group->frozen) return;
lv_obj_t ** obj_next = group->obj_focus;
lv_obj_t ** obj_sentinel = NULL;
bool can_move = true;
bool can_begin = true;
for(;;) {
if(obj_next == NULL) {
if(group->wrap || obj_sentinel == NULL) {
if(!can_begin) return;
obj_next = begin(&group->obj_ll);
can_move = false;
can_begin = false;
}
else {
/*Currently focused object is the last/first in the group, keep it that way*/
return;
}
}
if(obj_sentinel == NULL) {
obj_sentinel = obj_next;
if(obj_sentinel == NULL) return; /*Group is empty*/
}
if(can_move) {
obj_next = move(&group->obj_ll, obj_next);
/*Give up if we walked the entire list and haven't found another visible object*/
if(obj_next == obj_sentinel) return;
}
can_move = true;
if(obj_next == NULL) continue;
if(lv_obj_get_state(*obj_next, LV_OBJ_PART_MAIN) & LV_STATE_DISABLED) continue;
/*Hidden and disabled objects don't receive focus*/
if(!lv_obj_get_hidden(*obj_next)) break;
}
if(obj_next == group->obj_focus) return; /*There's only one visible object and it's already focused*/
if(group->obj_focus) {
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_DEFOCUS, NULL);
lv_res_t res = lv_event_send(*group->obj_focus, LV_EVENT_DEFOCUSED, NULL);
if(res != LV_RES_OK) return;
lv_obj_invalidate(*group->obj_focus);
}
group->obj_focus = obj_next;
(*group->obj_focus)->signal_cb(*group->obj_focus, LV_SIGNAL_FOCUS, NULL);
lv_res_t res = lv_event_send(*group->obj_focus, LV_EVENT_FOCUSED, NULL);
if(res != LV_RES_OK) return;
/*If the object or its parent has `top == true` bring it to the foreground*/
obj_to_foreground(*group->obj_focus);
lv_obj_invalidate(*group->obj_focus);
if(group->focus_cb) group->focus_cb(group);
}
static void obj_to_foreground(lv_obj_t * obj)
{
/*Search for 'top' attribute*/
lv_obj_t * i = obj;
lv_obj_t * last_top = NULL;
while(i != NULL) {
if(i->top != 0) last_top = i;
i = lv_obj_get_parent(i);
}
if(last_top != NULL) {
/*Move the last_top object to the foreground*/
lv_obj_move_foreground(last_top);
}
}
#endif /*LV_USE_GROUP != 0*/

View File

@ -0,0 +1,241 @@
/**
* @file lv_group.h
*
*/
#ifndef LV_GROUP_H
#define LV_GROUP_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
/*********************
* DEFINES
*********************/
/*Predefined keys to control the focused object via lv_group_send(group, c)*/
/*For compatibility in signal function define the keys regardless to `LV_USE_GROUP`*/
enum {
LV_KEY_UP = 17, /*0x11*/
LV_KEY_DOWN = 18, /*0x12*/
LV_KEY_RIGHT = 19, /*0x13*/
LV_KEY_LEFT = 20, /*0x14*/
LV_KEY_ESC = 27, /*0x1B*/
LV_KEY_DEL = 127, /*0x7F*/
LV_KEY_BACKSPACE = 8, /*0x08*/
LV_KEY_ENTER = 10, /*0x0A, '\n'*/
LV_KEY_NEXT = 9, /*0x09, '\t'*/
LV_KEY_PREV = 11, /*0x0B, '*/
LV_KEY_HOME = 2, /*0x02, STX*/
LV_KEY_END = 3, /*0x03, ETX*/
};
typedef uint8_t lv_key_t;
#if LV_USE_GROUP != 0
/**********************
* TYPEDEFS
**********************/
struct _lv_group_t;
typedef void (*lv_group_style_mod_cb_t)(struct _lv_group_t *, lv_style_t *);
typedef void (*lv_group_focus_cb_t)(struct _lv_group_t *);
/**
* Groups can be used to logically hold objects so that they can be individually focused.
* They are NOT for laying out objects on a screen (try `lv_cont` for that).
*/
typedef struct _lv_group_t {
lv_ll_t obj_ll; /**< Linked list to store the objects in the group */
lv_obj_t ** obj_focus; /**< The object in focus*/
lv_group_focus_cb_t focus_cb; /**< A function to call when a new object is focused (optional)*/
#if LV_USE_USER_DATA
lv_group_user_data_t user_data;
#endif
uint8_t frozen : 1; /**< 1: can't focus to new object*/
uint8_t editing : 1; /**< 1: Edit mode, 0: Navigate mode*/
uint8_t click_focus : 1; /**< 1: If an object in a group is clicked by an indev then it will be
focused */
uint8_t refocus_policy : 1; /**< 1: Focus prev if focused on deletion. 0: Focus next if focused on
deletion.*/
uint8_t wrap : 1; /**< 1: Focus next/prev can wrap at end of list. 0: Focus next/prev stops at end
of list.*/
} lv_group_t;
enum { LV_GROUP_REFOCUS_POLICY_NEXT = 0, LV_GROUP_REFOCUS_POLICY_PREV = 1 };
typedef uint8_t lv_group_refocus_policy_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Init. the group module
* @remarks Internal function, do not call directly.
*/
void _lv_group_init(void);
/**
* Create a new object group
* @return pointer to the new object group
*/
lv_group_t * lv_group_create(void);
/**
* Delete a group object
* @param group pointer to a group
*/
void lv_group_del(lv_group_t * group);
/**
* Add an object to a group
* @param group pointer to a group
* @param obj pointer to an object to add
*/
void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);
/**
* Remove an object from its group
* @param obj pointer to an object to remove
*/
void lv_group_remove_obj(lv_obj_t * obj);
/**
* Remove all objects from a group
* @param group pointer to a group
*/
void lv_group_remove_all_objs(lv_group_t * group);
/**
* Focus on an object (defocus the current)
* @param obj pointer to an object to focus on
*/
void lv_group_focus_obj(lv_obj_t * obj);
/**
* Focus the next object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_next(lv_group_t * group);
/**
* Focus the previous object in a group (defocus the current)
* @param group pointer to a group
*/
void lv_group_focus_prev(lv_group_t * group);
/**
* Do not let to change the focus from the current object
* @param group pointer to a group
* @param en true: freeze, false: release freezing (normal mode)
*/
void lv_group_focus_freeze(lv_group_t * group, bool en);
/**
* Send a control character to the focuses object of a group
* @param group pointer to a group
* @param c a character (use LV_KEY_.. to navigate)
* @return result of focused object in group.
*/
lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c);
/**
* Set a function for a group which will be called when a new object is focused
* @param group pointer to a group
* @param focus_cb the call back function or NULL if unused
*/
void lv_group_set_focus_cb(lv_group_t * group, lv_group_focus_cb_t focus_cb);
/**
* Set whether the next or previous item in a group is focused if the currently focused obj is
* deleted.
* @param group pointer to a group
* @param new refocus policy enum
*/
void lv_group_set_refocus_policy(lv_group_t * group, lv_group_refocus_policy_t policy);
/**
* Manually set the current mode (edit or navigate).
* @param group pointer to group
* @param edit: true: edit mode; false: navigate mode
*/
void lv_group_set_editing(lv_group_t * group, bool edit);
/**
* Set the `click_focus` attribute. If enabled then the object will be focused then it is clicked.
* @param group pointer to group
* @param en: true: enable `click_focus`
*/
void lv_group_set_click_focus(lv_group_t * group, bool en);
/**
* Set whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
void lv_group_set_wrap(lv_group_t * group, bool en);
/**
* Get the focused object or NULL if there isn't one
* @param group pointer to a group
* @return pointer to the focused object
*/
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
#if LV_USE_USER_DATA
/**
* Get a pointer to the group's user data
* @param group pointer to an group
* @return pointer to the user data
*/
lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group);
#endif
/**
* Get the focus callback function of a group
* @param group pointer to a group
* @return the call back function or NULL if not set
*/
lv_group_focus_cb_t lv_group_get_focus_cb(const lv_group_t * group);
/**
* Get the current mode (edit or navigate).
* @param group pointer to group
* @return true: edit mode; false: navigate mode
*/
bool lv_group_get_editing(const lv_group_t * group);
/**
* Get the `click_focus` attribute.
* @param group pointer to group
* @return true: `click_focus` is enabled; false: disabled
*/
bool lv_group_get_click_focus(const lv_group_t * group);
/**
* Get whether focus next/prev will allow wrapping from first->last or last->first object.
* @param group pointer to group
* @param en: true: wrapping enabled; false: wrapping disabled
*/
bool lv_group_get_wrap(lv_group_t * group);
/**********************
* MACROS
**********************/
#endif /*LV_USE_GROUP != 0*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_GROUP_H*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/**
* @file lv_indev.h
*
*/
#ifndef LV_INDEV_H
#define LV_INDEV_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
#include "../lv_hal/lv_hal_indev.h"
#include "../lv_core/lv_group.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the display input device subsystem
*/
void _lv_indev_init(void);
/**
* Called periodically to read the input devices
* @param task pointer to the task itself
*/
void _lv_indev_read_task(lv_task_t * task);
/**
* Get the currently processed input device. Can be used in action functions too.
* @return pointer to the currently processed input device or NULL if no input device processing
* right now
*/
lv_indev_t * lv_indev_get_act(void);
/**
* Get the type of an input device
* @param indev pointer to an input device
* @return the type of the input device from `lv_hal_indev_type_t` (`LV_INDEV_TYPE_...`)
*/
lv_indev_type_t lv_indev_get_type(const lv_indev_t * indev);
/**
* Reset one or all input devices
* @param indev pointer to an input device to reset or NULL to reset all of them
* @param obj pointer to an object which triggers the reset.
*/
void lv_indev_reset(lv_indev_t * indev, lv_obj_t * obj);
/**
* Reset the long press state of an input device
* @param indev_proc pointer to an input device
*/
void lv_indev_reset_long_press(lv_indev_t * indev);
/**
* Enable or disable an input devices
* @param indev pointer to an input device
* @param en true: enable; false: disable
*/
void lv_indev_enable(lv_indev_t * indev, bool en);
/**
* Set a cursor for a pointer input device (for LV_INPUT_TYPE_POINTER and LV_INPUT_TYPE_BUTTON)
* @param indev pointer to an input device
* @param cur_obj pointer to an object to be used as cursor
*/
void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj);
#if LV_USE_GROUP
/**
* Set a destination group for a keypad input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group);
#endif
/**
* Set the an array of points for LV_INDEV_TYPE_BUTTON.
* These points will be assigned to the buttons to press a specific point on the screen
* @param indev pointer to an input device
* @param group point to a group
*/
void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t points[]);
/**
* Get the last point of an input device (for LV_INDEV_TYPE_POINTER and LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the result
*/
void lv_indev_get_point(const lv_indev_t * indev, lv_point_t * point);
/**
* Get the current gesture direct
* @param indev pointer to an input device
* @return current gesture direct
*/
lv_gesture_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev);
/**
* Get the last pressed key of an input device (for LV_INDEV_TYPE_KEYPAD)
* @param indev pointer to an input device
* @return the last pressed key (0 on error)
*/
uint32_t lv_indev_get_key(const lv_indev_t * indev);
/**
* Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and
* LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @return true: drag is in progress
*/
bool lv_indev_is_dragging(const lv_indev_t * indev);
/**
* Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and
* LV_INDEV_TYPE_BUTTON)
* @param indev pointer to an input device
* @param point pointer to a point to store the vector
*/
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point);
/**
* Manually finish dragging.
* `LV_SIGNAL_DRAG_END` and `LV_EVENT_DRAG_END` will be sent.
* @param indev pointer to an input device
* @return `LV_RES_INV` if the object being dragged was deleted. Else `LV_RES_OK`.
*/
lv_res_t lv_indev_finish_drag(lv_indev_t * indev);
/**
* Do nothing until the next release
* @param indev pointer to an input device
*/
void lv_indev_wait_release(lv_indev_t * indev);
/**
* Gets a pointer to the currently active object in indev proc functions.
* NULL if no object is currently being handled or if groups aren't used.
* @return pointer to currently active object
*/
lv_obj_t * lv_indev_get_obj_act(void);
/**
* Search the most top, clickable object by a point
* @param obj pointer to a start object, typically the screen
* @param point pointer to a point for searching the most top child
* @return pointer to the found object or NULL if there was no suitable object
*/
lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point);
/**
* Get a pointer to the indev read task to
* modify its parameters with `lv_task_...` functions.
* @param indev pointer to an inout device
* @return pointer to the indev read refresher task. (NULL on error)
*/
lv_task_t * lv_indev_get_read_task(lv_disp_t * indev);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_INDEV_H*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,270 @@
/**
* @file lv_obj_style_dec.h
*
*/
#ifndef LV_OBJ_STYLE_DEC_H
#define LV_OBJ_STYLE_DEC_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* DEFINES
*********************/
/**
* Macro to declare the most important style set/get API functions.
*
* Get the value of a style property from an object in the object's current state
* -----------------------------------------------------------------------------
* - Get the value of a style property from an object in the object's current state.
* - Transition animation is taken into account.
* - If the property is not set in the object's styles check the parent(s) if the property can be inherited
* - If still not found return a default value.
* - For example:
* `lv_style_int_t w = lv_obj_get_style_border_width(btn1, LV_BTN_PART_MAIN);`
*
* Set a local style property for an object in a given state
* ---------------------------------------------------------
* - For example:
* `lv_obj_set_style_local_border_width(btn1, LV_BTN_PART_MAIN, LV_STATE_PRESSED, 2);`
*
* Get the value from a style in a given state
* -------------------------------------------
* - The same rules applies to the return value then for "lv_obj_get_style_local_...()" above
* - For example
* `int16_t weight = lv_style_get_border_width(&style1, LV_STATE_PRESSED, &result);`
* `if(weight > 0) ...the property is found and loaded into result...`
* Set a value in a style in a given state
* ---------------------------------------
* - For example
* `lv_style_set_border_width(&style1, LV_STATE_PRESSED, 2);`
*/
#ifdef __cplusplus
#define _OBJ_GET_STYLE(prop_name, func_name, value_type, style_type) \
static inline value_type lv_obj_get_style_##func_name(const lv_obj_t * obj, uint8_t part) \
{ \
return (value_type)_lv_obj_get_style##style_type(obj, part, LV_STYLE_##prop_name); \
}
#else
#define _OBJ_GET_STYLE(prop_name, func_name, value_type, style_type) \
static inline value_type lv_obj_get_style_##func_name(const lv_obj_t * obj, uint8_t part) \
{ \
return _lv_obj_get_style##style_type(obj, part, LV_STYLE_##prop_name); \
}
#endif
#define _OBJ_SET_STYLE_LOCAL(prop_name, func_name, value_type, style_type) \
static inline void lv_obj_set_style_local_##func_name(lv_obj_t * obj, uint8_t part, lv_state_t state, value_type value) \
{ \
_lv_obj_set_style_local##style_type(obj, part, LV_STYLE_##prop_name | (state << LV_STYLE_STATE_POS), value); \
}
#define _OBJ_SET_STYLE(prop_name, func_name, value_type, style_type) \
static inline void lv_style_set_##func_name(lv_style_t * style, lv_state_t state, value_type value) \
{ \
_lv_style_set##style_type(style, LV_STYLE_##prop_name | (state << LV_STYLE_STATE_POS), value); \
}
#define _LV_OBJ_STYLE_SET_GET_DECLARE(prop_name, func_name, value_type, style_type) \
_OBJ_GET_STYLE(prop_name, func_name, value_type, style_type) \
_OBJ_SET_STYLE_LOCAL(prop_name, func_name, value_type, style_type) \
_OBJ_SET_STYLE(prop_name, func_name, value_type, style_type)
_LV_OBJ_STYLE_SET_GET_DECLARE(RADIUS, radius, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(CLIP_CORNER, clip_corner, bool, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SIZE, size, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSFORM_WIDTH, transform_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSFORM_HEIGHT, transform_height, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSFORM_ANGLE, transform_angle, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSFORM_ZOOM, transform_zoom, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(OPA_SCALE, opa_scale, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(PAD_TOP, pad_top, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PAD_BOTTOM, pad_bottom, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PAD_LEFT, pad_left, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PAD_RIGHT, pad_right, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PAD_INNER, pad_inner, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(MARGIN_TOP, margin_top, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(MARGIN_BOTTOM, margin_bottom, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(MARGIN_LEFT, margin_left, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(MARGIN_RIGHT, margin_right, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_BLEND_MODE, bg_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_MAIN_STOP, bg_main_stop, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_GRAD_STOP, bg_grad_stop, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_GRAD_DIR, bg_grad_dir, lv_grad_dir_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_COLOR, bg_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_GRAD_COLOR, bg_grad_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(BG_OPA, bg_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_WIDTH, border_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_SIDE, border_side, lv_border_side_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_BLEND_MODE, border_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_POST, border_post, bool, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_COLOR, border_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(BORDER_OPA, border_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(OUTLINE_WIDTH, outline_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(OUTLINE_PAD, outline_pad, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(OUTLINE_BLEND_MODE, outline_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(OUTLINE_COLOR, outline_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(OUTLINE_OPA, outline_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_WIDTH, shadow_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_OFS_X, shadow_ofs_x, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_OFS_Y, shadow_ofs_y, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_SPREAD, shadow_spread, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_BLEND_MODE, shadow_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_COLOR, shadow_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(SHADOW_OPA, shadow_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_REPEAT, pattern_repeat, bool, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_BLEND_MODE, pattern_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_RECOLOR, pattern_recolor, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_OPA, pattern_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_RECOLOR_OPA, pattern_recolor_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(PATTERN_IMAGE, pattern_image, const void *, _ptr)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_LETTER_SPACE, value_letter_space, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_LINE_SPACE, value_line_space, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_BLEND_MODE, value_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_OFS_X, value_ofs_x, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_OFS_Y, value_ofs_y, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_ALIGN, value_align, lv_align_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_COLOR, value_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_OPA, value_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_FONT, value_font, const lv_font_t *, _ptr)
_LV_OBJ_STYLE_SET_GET_DECLARE(VALUE_STR, value_str, const char *, _ptr)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_LETTER_SPACE, text_letter_space, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_LINE_SPACE, text_line_space, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_DECOR, text_decor, lv_text_decor_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_BLEND_MODE, text_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_COLOR, text_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_SEL_COLOR, text_sel_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_SEL_BG_COLOR, text_sel_bg_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_OPA, text_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(TEXT_FONT, text_font, const lv_font_t *, _ptr)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_WIDTH, line_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_BLEND_MODE, line_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_DASH_WIDTH, line_dash_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_DASH_GAP, line_dash_gap, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_ROUNDED, line_rounded, bool, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_COLOR, line_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(LINE_OPA, line_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(IMAGE_BLEND_MODE, image_blend_mode, lv_blend_mode_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(IMAGE_RECOLOR, image_recolor, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(IMAGE_OPA, image_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(IMAGE_RECOLOR_OPA, image_recolor_opa, lv_opa_t, _opa)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_TIME, transition_time, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_DELAY, transition_delay, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_1, transition_prop_1, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_2, transition_prop_2, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_3, transition_prop_3, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_4, transition_prop_4, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_5, transition_prop_5, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PROP_6, transition_prop_6, lv_style_int_t, _int)
#if LV_USE_ANIMATION
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PATH, transition_path, const lv_anim_path_t *, _ptr)
#else
/*For compatibility*/
_LV_OBJ_STYLE_SET_GET_DECLARE(TRANSITION_PATH, transition_path, const void *, _ptr)
#endif
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_WIDTH, scale_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_BORDER_WIDTH, scale_border_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_END_BORDER_WIDTH, scale_end_border_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_END_LINE_WIDTH, scale_end_line_width, lv_style_int_t, _int)
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_GRAD_COLOR, scale_grad_color, lv_color_t, _color)
_LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_END_COLOR, scale_end_color, lv_color_t, _color)
#undef _LV_OBJ_STYLE_SET_GET_DECLARE
#undef _OBJ_SET_STYLE_LOCAL
#undef _OBJ_SET_STYLE
#undef _OBJ_GET_STYLE
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
#endif /*LV_OBJ_STYLE_DEC_H*/

View File

@ -0,0 +1,982 @@
/**
* @file lv_refr.c
*
*/
/*********************
* INCLUDES
*********************/
#include "FreeRTOS.h"
#include "task.h"
#include <stddef.h>
#include "lv_refr.h"
#include "lv_disp.h"
#include "../lv_hal/lv_hal_tick.h"
#include "../lv_hal/lv_hal_disp.h"
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_gc.h"
#include "../lv_draw/lv_draw.h"
#include "../lv_font/lv_font_fmt_txt.h"
#include "../lv_gpu/lv_gpu_stm32_dma2d.h"
#if LV_USE_PERF_MONITOR
#include "../lv_widgets/lv_label.h"
#endif
#include "vg_driver.h"
/*********************
* DEFINES
*********************/
/* Draw translucent random colored areas on the invalidated (redrawn) areas*/
#define MASK_AREA_DEBUG 0
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_refr_join_area(void);
static void lv_refr_areas(void);
static void lv_refr_area(const lv_area_t * area_p);
static void lv_refr_area_part(const lv_area_t * area_p);
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p);
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p);
static void lv_refr_vdb_flush(void);
/**********************
* STATIC VARIABLES
**********************/
static uint32_t px_num;
static lv_disp_t * disp_refr; /*Display being refreshed*/
#if LV_USE_PERF_MONITOR
static uint32_t fps_sum_cnt;
static uint32_t fps_sum_all;
#endif
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the screen refresh subsystem
*/
void _lv_refr_init(void)
{
/*Nothing to do*/
}
/**
* Redraw the invalidated areas now.
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process
* can prevent the call of `lv_task_handler`. In this case if the GUI is updated in the process
* (e.g. progress bar) this function can be called when the screen should be updated.
* @param disp pointer to display to refresh. NULL to refresh all displays.
*/
void lv_refr_now(lv_disp_t * disp)
{
#if LV_USE_ANIMATION
lv_anim_refr_now();
#endif
if(disp) {
_lv_disp_refr_task(disp->refr_task);
}
else {
lv_disp_t * d;
d = lv_disp_get_next(NULL);
while(d) {
_lv_disp_refr_task(d->refr_task);
d = lv_disp_get_next(d);
}
}
}
/**
* Invalidate an area on display to redraw it
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
* @param disp pointer to display where the area should be invalidated (NULL can be used if there is
* only one display)
*/
void _lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p)
{
if(!disp) disp = lv_disp_get_default();
if(!disp) return;
/*Clear the invalidate buffer if the parameter is NULL*/
if(area_p == NULL) {
disp->inv_p = 0;
return;
}
lv_area_t scr_area;
scr_area.x1 = 0;
scr_area.y1 = 0;
scr_area.x2 = lv_disp_get_hor_res(disp) - 1;
scr_area.y2 = lv_disp_get_ver_res(disp) - 1;
lv_area_t com_area;
bool suc;
suc = _lv_area_intersect(&com_area, area_p, &scr_area);
/*The area is truncated to the screen*/
if(suc != false) {
if(disp->driver.rounder_cb) disp->driver.rounder_cb(&disp->driver, &com_area);
/*Save only if this area is not in one of the saved areas*/
uint16_t i;
for(i = 0; i < disp->inv_p; i++) {
if(_lv_area_is_in(&com_area, &disp->inv_areas[i], 0) != false) return;
}
/*Save the area*/
if(disp->inv_p < LV_INV_BUF_SIZE) {
lv_area_copy(&disp->inv_areas[disp->inv_p], &com_area);
}
else { /*If no place for the area add the screen*/
disp->inv_p = 0;
lv_area_copy(&disp->inv_areas[disp->inv_p], &scr_area);
}
disp->inv_p++;
lv_task_set_prio(disp->refr_task, LV_REFR_TASK_PRIO);
}
}
/**
* Get the display which is being refreshed
* @return the display being refreshed
*/
lv_disp_t * _lv_refr_get_disp_refreshing(void)
{
return disp_refr;
}
/**
* Set the display which is being refreshed.
* It shouldn't be used directly by the user.
* It can be used to trick the drawing functions about there is an active display.
* @param the display being refreshed
*/
void _lv_refr_set_disp_refreshing(lv_disp_t * disp)
{
disp_refr = disp;
}
/**
* Called periodically to handle the refreshing
* @param task pointer to the task itself
*/
void _lv_disp_refr_task(lv_task_t * task)
{
LV_LOG_TRACE("lv_refr_task: started");
uint32_t start = lv_tick_get();
uint32_t elaps = 0;
disp_refr = task->user_data;
#if LV_USE_PERF_MONITOR == 0
/* Ensure the task does not run again automatically.
* This is done before refreshing in case refreshing invalidates something else.
*/
lv_task_set_prio(task, LV_TASK_PRIO_OFF);
#endif
/*Do nothing if there is no active screen*/
if(disp_refr->act_scr == NULL) {
disp_refr->inv_p = 0;
return;
}
lv_refr_join_area();
lv_refr_areas();
/*If refresh happened ...*/
if(disp_refr->inv_p != 0) {
/* In true double buffered mode copy the refreshed areas to the new VDB to keep it up to date.
* With set_px_cb we don't know anything about the buffer (even it's size) so skip copying.*/
if(lv_disp_is_true_double_buf(disp_refr)) {
if(disp_refr->driver.set_px_cb) {
LV_LOG_WARN("Can't handle 2 screen sized buffers with set_px_cb. Display is not refreshed.");
}
else {
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
/*Flush the content of the VDB*/
lv_refr_vdb_flush();
/* With true double buffering the flushing should be only the address change of the
* current frame buffer. Wait until the address change is ready and copy the changed
* content to the other frame buffer (new active VDB) to keep the buffers synchronized*/
while(vdb->flushing);
#if LCD_ROTATE_ANGLE == LCD_ROTATE_ANGLE_0
lv_color_t * copy_buf = NULL;
#if LV_USE_GPU_STM32_DMA2D
LV_UNUSED(copy_buf);
#else
copy_buf = _lv_mem_buf_get(disp_refr->driver.hor_res * sizeof(lv_color_t));
#endif
uint8_t * buf_act = (uint8_t *)vdb->buf_act;
uint8_t * buf_ina = (uint8_t *)vdb->buf_act == vdb->buf1 ? vdb->buf2 : vdb->buf1;
lv_coord_t hres = lv_disp_get_hor_res(disp_refr);
uint16_t a;
for(a = 0; a < disp_refr->inv_p; a++) {
#if defined(VG_DRIVER) && !defined(LVGL_VG_GPU) && !defined(REVERSE_TRACK)
/* don't update the vg area */
if (disp_refr->inv_areas[a].x1 == xm_vg_get_offset_x() &&
disp_refr->inv_areas[a].y1 == xm_vg_get_offset_y() &&
disp_refr->inv_areas[a].x2 == xm_vg_get_offset_x() + xm_vg_get_width() - 1 &&
disp_refr->inv_areas[a].y2 == xm_vg_get_offset_y() + xm_vg_get_height() - 1) {
continue;
}
#endif
if(disp_refr->inv_area_joined[a] == 0) {
uint32_t start_offs =
(hres * disp_refr->inv_areas[a].y1 + disp_refr->inv_areas[a].x1) * sizeof(lv_color_t);
#if LV_USE_GPU_STM32_DMA2D
lv_gpu_stm32_dma2d_copy((lv_color_t *)(buf_act + start_offs), disp_refr->driver.hor_res,
(lv_color_t *)(buf_ina + start_offs), disp_refr->driver.hor_res,
lv_area_get_width(&disp_refr->inv_areas[a]),
lv_area_get_height(&disp_refr->inv_areas[a]));
#else
lv_coord_t y;
uint32_t line_length = lv_area_get_width(&disp_refr->inv_areas[a]) * sizeof(lv_color_t);
for(y = disp_refr->inv_areas[a].y1; y <= disp_refr->inv_areas[a].y2; y++) {
/* The frame buffer is probably in an external RAM where sequential access is much faster.
* So first copy a line into a buffer and write it back the ext. RAM */
_lv_memcpy(copy_buf, buf_ina + start_offs, line_length);
_lv_memcpy(buf_act + start_offs, copy_buf, line_length);
start_offs += hres * sizeof(lv_color_t);
}
#endif
}
}
if(copy_buf) _lv_mem_buf_release(copy_buf);
#endif
}
} /*End of true double buffer handling*/
/*Clean up*/
_lv_memset_00(disp_refr->inv_areas, sizeof(disp_refr->inv_areas));
_lv_memset_00(disp_refr->inv_area_joined, sizeof(disp_refr->inv_area_joined));
disp_refr->inv_p = 0;
elaps = lv_tick_elaps(start);
/*Call monitor cb if present*/
if(disp_refr->driver.monitor_cb) {
disp_refr->driver.monitor_cb(&disp_refr->driver, elaps, px_num);
}
}
_lv_mem_buf_free_all();
_lv_font_clean_up_fmt_txt();
#if LV_USE_PERF_MONITOR && LV_USE_LABEL
static lv_obj_t * perf_label = NULL;
if(perf_label == NULL) {
perf_label = lv_label_create(lv_layer_sys(), NULL);
lv_label_set_align(perf_label, LV_LABEL_ALIGN_RIGHT);
lv_obj_set_style_local_bg_opa(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_COVER);
lv_obj_set_style_local_bg_color(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
lv_obj_set_style_local_text_color(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_obj_set_style_local_pad_top(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_pad_bottom(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_pad_left(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_obj_set_style_local_pad_right(perf_label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, 3);
lv_label_set_text(perf_label, "?");
lv_obj_align(perf_label, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
}
static uint32_t perf_last_time = 0;
static uint32_t elaps_sum = 0;
static uint32_t frame_cnt = 0;
if(lv_tick_elaps(perf_last_time) < 300) {
if(px_num > 5000) {
elaps_sum += elaps;
frame_cnt ++;
}
}
else {
perf_last_time = lv_tick_get();
uint32_t fps_limit = 1000 / disp_refr->refr_task->period;
uint32_t fps;
if(elaps_sum == 0) elaps_sum = 1;
if(frame_cnt == 0) fps = fps_limit;
else fps = (1000 * frame_cnt) / elaps_sum;
elaps_sum = 0;
frame_cnt = 0;
if(fps > fps_limit) fps = fps_limit;
fps_sum_all += fps;
fps_sum_cnt ++;
#if configGENERATE_RUN_TIME_STATS == 1
uint32_t total_time = portGET_RUN_TIME_COUNTER_VALUE() / 100;
uint32_t idle_time = ulTaskGetIdleRunTimeCounter();
uint32_t cpu = 100 - idle_time / total_time;
#else
uint32_t cpu = 100 - lv_task_get_idle();
#endif
lv_label_set_text_fmt(perf_label, "%d FPS\n%d%% CPU", fps, cpu);
lv_obj_align(perf_label, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0);
}
#endif
LV_LOG_TRACE("lv_refr_task: ready");
}
#if LV_USE_PERF_MONITOR
uint32_t lv_refr_get_fps_avg(void)
{
return fps_sum_all / fps_sum_cnt;
}
#endif
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Join the areas which has got common parts
*/
static void lv_refr_join_area(void)
{
uint32_t join_from;
uint32_t join_in;
lv_area_t joined_area;
for(join_in = 0; join_in < disp_refr->inv_p; join_in++) {
if(disp_refr->inv_area_joined[join_in] != 0) continue;
/*Check all areas to join them in 'join_in'*/
for(join_from = 0; join_from < disp_refr->inv_p; join_from++) {
/*Handle only unjoined areas and ignore itself*/
if(disp_refr->inv_area_joined[join_from] != 0 || join_in == join_from) {
continue;
}
/*Check if the areas are on each other*/
if(_lv_area_is_on(&disp_refr->inv_areas[join_in], &disp_refr->inv_areas[join_from]) == false) {
continue;
}
_lv_area_join(&joined_area, &disp_refr->inv_areas[join_in], &disp_refr->inv_areas[join_from]);
/*Join two area only if the joined area size is smaller*/
if(lv_area_get_size(&joined_area) < (lv_area_get_size(&disp_refr->inv_areas[join_in]) +
lv_area_get_size(&disp_refr->inv_areas[join_from]))) {
lv_area_copy(&disp_refr->inv_areas[join_in], &joined_area);
/*Mark 'join_form' is joined into 'join_in'*/
disp_refr->inv_area_joined[join_from] = 1;
}
}
}
}
/**
* Refresh the joined areas
*/
static void lv_refr_areas(void)
{
px_num = 0;
if(disp_refr->inv_p == 0) return;
/*Find the last area which will be drawn*/
int32_t i;
int32_t last_i = 0;
for(i = disp_refr->inv_p - 1; i >= 0; i--) {
if(disp_refr->inv_area_joined[i] == 0) {
last_i = i;
break;
}
}
disp_refr->driver.buffer->last_area = 0;
disp_refr->driver.buffer->last_part = 0;
for(i = 0; i < disp_refr->inv_p; i++) {
/*Refresh the unjoined areas*/
if(disp_refr->inv_area_joined[i] == 0) {
if(i == last_i) disp_refr->driver.buffer->last_area = 1;
disp_refr->driver.buffer->last_part = 0;
lv_refr_area(&disp_refr->inv_areas[i]);
px_num += lv_area_get_size(&disp_refr->inv_areas[i]);
}
}
}
/**
* Refresh an area if there is Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
static void lv_refr_area(const lv_area_t * area_p)
{
/*True double buffering: there are two screen sized buffers. Just redraw directly into a
* buffer*/
if(lv_disp_is_true_double_buf(disp_refr)) {
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
vdb->area.x1 = 0;
vdb->area.x2 = lv_disp_get_hor_res(disp_refr) - 1;
vdb->area.y1 = 0;
vdb->area.y2 = lv_disp_get_ver_res(disp_refr) - 1;
disp_refr->driver.buffer->last_part = 1;
lv_refr_area_part(area_p);
}
/*The buffer is smaller: refresh the area in parts*/
else {
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
/*Calculate the max row num*/
lv_coord_t w = lv_area_get_width(area_p);
lv_coord_t h = lv_area_get_height(area_p);
lv_coord_t y2 =
area_p->y2 >= lv_disp_get_ver_res(disp_refr) ? lv_disp_get_ver_res(disp_refr) - 1 : area_p->y2;
int32_t max_row = (uint32_t)vdb->size / w;
if(max_row > h) max_row = h;
/*Round down the lines of VDB if rounding is added*/
if(disp_refr->driver.rounder_cb) {
lv_area_t tmp;
tmp.x1 = 0;
tmp.x2 = 0;
tmp.y1 = 0;
lv_coord_t h_tmp = max_row;
do {
tmp.y2 = h_tmp - 1;
disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);
/*If this height fits into `max_row` then fine*/
if(lv_area_get_height(&tmp) <= max_row) break;
/*Decrement the height of the area until it fits into `max_row` after rounding*/
h_tmp--;
} while(h_tmp > 0);
if(h_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 + 1;
}
}
/*Always use the full row*/
lv_coord_t row;
lv_coord_t row_last = 0;
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
/*Calc. the next y coordinates of VDB*/
vdb->area.x1 = area_p->x1;
vdb->area.x2 = area_p->x2;
vdb->area.y1 = row;
vdb->area.y2 = row + max_row - 1;
if(vdb->area.y2 > y2) vdb->area.y2 = y2;
row_last = vdb->area.y2;
if(y2 == row_last) disp_refr->driver.buffer->last_part = 1;
lv_refr_area_part(area_p);
}
/*If the last y coordinates are not handled yet ...*/
if(y2 != row_last) {
/*Calc. the next y coordinates of VDB*/
vdb->area.x1 = area_p->x1;
vdb->area.x2 = area_p->x2;
vdb->area.y1 = row;
vdb->area.y2 = y2;
disp_refr->driver.buffer->last_part = 1;
lv_refr_area_part(area_p);
}
}
}
/**
* Refresh a part of an area which is on the actual Virtual Display Buffer
* @param area_p pointer to an area to refresh
*/
static void lv_refr_area_part(const lv_area_t * area_p)
{
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
/*In non double buffered mode, before rendering the next part wait until the previous image is
* flushed*/
if(lv_disp_is_double_buf(disp_refr) == false) {
while(vdb->flushing) {
if(disp_refr->driver.wait_cb) disp_refr->driver.wait_cb(&disp_refr->driver);
}
}
lv_obj_t * top_act_scr = NULL;
lv_obj_t * top_prev_scr = NULL;
/*Get the new mask from the original area and the act. VDB
It will be a part of 'area_p'*/
lv_area_t start_mask;
_lv_area_intersect(&start_mask, area_p, &vdb->area);
/*Get the most top object which is not covered by others*/
top_act_scr = lv_refr_get_top_obj(&start_mask, lv_disp_get_scr_act(disp_refr));
if(disp_refr->prev_scr) {
top_prev_scr = lv_refr_get_top_obj(&start_mask, disp_refr->prev_scr);
}
/*Draw a display background if there is no top object*/
if(top_act_scr == NULL && top_prev_scr == NULL) {
if(disp_refr->bg_img) {
lv_draw_img_dsc_t dsc;
lv_draw_img_dsc_init(&dsc);
dsc.opa = disp_refr->bg_opa;
lv_img_header_t header;
lv_res_t res;
res = lv_img_decoder_get_info(disp_refr->bg_img, &header);
if(res == LV_RES_OK) {
lv_area_t a;
lv_area_set(&a, 0, 0, header.w - 1, header.h - 1);
lv_draw_img(&a, &start_mask, disp_refr->bg_img, &dsc);
}
else {
LV_LOG_WARN("Can't draw the background image")
}
}
else {
lv_draw_rect_dsc_t dsc;
lv_draw_rect_dsc_init(&dsc);
dsc.bg_color = disp_refr->bg_color;
dsc.bg_opa = disp_refr->bg_opa;
lv_draw_rect(&start_mask, &start_mask, &dsc);
}
}
/*Refresh the previous screen if any*/
if(disp_refr->prev_scr) {
/*Get the most top object which is not covered by others*/
if(top_prev_scr == NULL) {
top_prev_scr = disp_refr->prev_scr;
}
/*Do the refreshing from the top object*/
lv_refr_obj_and_children(top_prev_scr, &start_mask);
}
if(top_act_scr == NULL) {
top_act_scr = disp_refr->act_scr;
}
/*Do the refreshing from the top object*/
lv_refr_obj_and_children(top_act_scr, &start_mask);
/*Also refresh top and sys layer unconditionally*/
lv_refr_obj_and_children(lv_disp_get_layer_top(disp_refr), &start_mask);
lv_refr_obj_and_children(lv_disp_get_layer_sys(disp_refr), &start_mask);
/* In true double buffered mode flush only once when all areas were rendered.
* In normal mode flush after every area */
if(lv_disp_is_true_double_buf(disp_refr) == false) {
lv_refr_vdb_flush();
}
}
/**
* Search the most top object which fully covers an area
* @param area_p pointer to an area
* @param obj the first object to start the searching (typically a screen)
* @return
*/
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
{
lv_obj_t * found_p = NULL;
/*If this object is fully cover the draw area check the children too */
if(_lv_area_is_in(area_p, &obj->coords, 0) && obj->hidden == 0) {
lv_design_res_t design_res = obj->design_cb(obj, area_p, LV_DESIGN_COVER_CHK);
if(design_res == LV_DESIGN_RES_MASKED) return NULL;
#if LV_USE_OPA_SCALE
if(design_res == LV_DESIGN_RES_COVER && lv_obj_get_style_opa_scale(obj, LV_OBJ_PART_MAIN) != LV_OPA_COVER) {
design_res = LV_DESIGN_RES_NOT_COVER;
}
#endif
lv_obj_t * i;
_LV_LL_READ(obj->child_ll, i) {
found_p = lv_refr_get_top_obj(area_p, i);
/*If a children is ok then break*/
if(found_p != NULL) {
break;
}
}
/*If no better children use this object*/
if(found_p == NULL) {
if(design_res == LV_DESIGN_RES_COVER) {
found_p = obj;
}
}
}
return found_p;
}
/**
* Make the refreshing from an object. Draw all its children and the youngers too.
* @param top_p pointer to an objects. Start the drawing from it.
* @param mask_p pointer to an area, the objects will be drawn only here
*/
static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
{
/* Normally always will be a top_obj (at least the screen)
* but in special cases (e.g. if the screen has alpha) it won't.
* In this case use the screen directly */
if(top_p == NULL) top_p = lv_disp_get_scr_act(disp_refr);
if(top_p == NULL) return; /*Shouldn't happen*/
/*Refresh the top object and its children*/
lv_refr_obj(top_p, mask_p);
/*Draw the 'younger' sibling objects because they can be on top_obj */
lv_obj_t * par;
lv_obj_t * border_p = top_p;
par = lv_obj_get_parent(top_p);
/*Do until not reach the screen*/
while(par != NULL) {
/*object before border_p has to be redrawn*/
lv_obj_t * i = _lv_ll_get_prev(&(par->child_ll), border_p);
while(i != NULL) {
/*Refresh the objects*/
lv_refr_obj(i, mask_p);
i = _lv_ll_get_prev(&(par->child_ll), i);
}
/*Call the post draw design function of the parents of the to object*/
if(par->design_cb) par->design_cb(par, mask_p, LV_DESIGN_DRAW_POST);
/*The new border will be there last parents,
*so the 'younger' brothers of parent will be refreshed*/
border_p = par;
/*Go a level deeper*/
par = lv_obj_get_parent(par);
}
}
/**
* Refresh an object an all of its children. (Called recursively)
* @param obj pointer to an object to refresh
* @param mask_ori_p pointer to an area, the objects will be drawn only here
*/
static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
{
/*Do not refresh hidden objects*/
if(obj->hidden != 0) return;
bool union_ok; /* Store the return value of area_union */
/* Truncate the original mask to the coordinates of the parent
* because the parent and its children are visible only here */
lv_area_t obj_mask;
lv_area_t obj_ext_mask;
lv_area_t obj_area;
lv_coord_t ext_size = obj->ext_draw_pad;
lv_obj_get_coords(obj, &obj_area);
obj_area.x1 -= ext_size;
obj_area.y1 -= ext_size;
obj_area.x2 += ext_size;
obj_area.y2 += ext_size;
union_ok = _lv_area_intersect(&obj_ext_mask, mask_ori_p, &obj_area);
/*Draw the parent and its children only if they ore on 'mask_parent'*/
if(union_ok != false) {
/* Redraw the object */
if(obj->design_cb) obj->design_cb(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN);
#if MASK_AREA_DEBUG
static lv_color_t debug_color = LV_COLOR_RED;
lv_draw_rect_dsc_t draw_dsc;
lv_draw_rect_dsc_init(&draw_dsc);
draw_dsc.bg_color.full = debug_color.full;
draw_dsc.bg_opa = LV_OPA_20;
draw_dsc.border_width = 2;
draw_dsc.border_opa = LV_OPA_50;
draw_dsc.border_color.full = (debug_color.full + 0x13) * 9;
lv_draw_rect(&obj_ext_mask, &obj_ext_mask, &draw_dsc);
debug_color.full *= 17;
debug_color.full += 0xA1;
#if LV_COLOR_DEPTH == 32
debug_color.ch.alpha = 0xff;
#endif
#endif
/*Create a new 'obj_mask' without 'ext_size' because the children can't be visible there*/
lv_obj_get_coords(obj, &obj_area);
union_ok = _lv_area_intersect(&obj_mask, mask_ori_p, &obj_area);
if(union_ok != false) {
lv_area_t mask_child; /*Mask from obj and its child*/
lv_obj_t * child_p;
lv_area_t child_area;
_LV_LL_READ_BACK(obj->child_ll, child_p) {
lv_obj_get_coords(child_p, &child_area);
ext_size = child_p->ext_draw_pad;
child_area.x1 -= ext_size;
child_area.y1 -= ext_size;
child_area.x2 += ext_size;
child_area.y2 += ext_size;
/* Get the union (common parts) of original mask (from obj)
* and its child */
union_ok = _lv_area_intersect(&mask_child, &obj_mask, &child_area);
#if defined(VG_DRIVER) && !defined(LVGL_VG_GPU) && !defined(REVERSE_TRACK)
/* when the refresh area is vg area, only draw the vg and it's childs */
if (mask_ori_p->x1 == xm_vg_get_offset_x() && mask_ori_p->y1 == xm_vg_get_offset_y()
&& mask_ori_p->x2 == xm_vg_get_offset_x() + xm_vg_get_width() - 1
&& mask_ori_p->y2 == xm_vg_get_offset_y() + xm_vg_get_height() - 1) {
if (child_area.x1 != mask_ori_p->x1 || child_area.y1 != mask_ori_p->y1
|| child_area.x2 != mask_ori_p->x2 || child_area.y2 != mask_ori_p->y2)
continue;
}
#endif
/*If the parent and the child has common area then refresh the child */
if(union_ok) {
/*Refresh the next children*/
lv_refr_obj(child_p, &mask_child);
}
}
}
/* If all the children are redrawn make 'post draw' design */
if(obj->design_cb) obj->design_cb(obj, &obj_ext_mask, LV_DESIGN_DRAW_POST);
}
}
static void lv_refr_vdb_rotate_180(lv_disp_drv_t * drv, lv_area_t * area, lv_color_t * color_p)
{
lv_coord_t area_w = lv_area_get_width(area);
lv_coord_t area_h = lv_area_get_height(area);
uint32_t total = area_w * area_h;
/* Swap the beginning and end values */
lv_color_t tmp;
uint32_t i = total - 1, j = 0;
while(i > j) {
tmp = color_p[i];
color_p[i] = color_p[j];
color_p[j] = tmp;
i--;
j++;
}
lv_coord_t tmp_coord;
tmp_coord = area->y2;
area->y2 = drv->ver_res - area->y1 - 1;
area->y1 = drv->ver_res - tmp_coord - 1;
tmp_coord = area->x2;
area->x2 = drv->hor_res - area->x1 - 1;
area->x1 = drv->hor_res - tmp_coord - 1;
}
static LV_ATTRIBUTE_FAST_MEM void lv_refr_vdb_rotate_90(bool invert_i, lv_coord_t area_w, lv_coord_t area_h,
lv_color_t * orig_color_p, lv_color_t * rot_buf)
{
uint32_t invert = (area_w * area_h) - 1;
uint32_t initial_i = ((area_w - 1) * area_h);
for(lv_coord_t y = 0; y < area_h; y++) {
uint32_t i = initial_i + y;
if(invert_i)
i = invert - i;
for(lv_coord_t x = 0; x < area_w; x++) {
rot_buf[i] = *(orig_color_p++);
if(invert_i)
i += area_h;
else
i -= area_h;
}
}
}
/**
* Helper function for lv_refr_vdb_rotate_90_sqr. Given a list of four numbers, rotate the entire list to the left.
*/
static inline void lv_vdb_rotate4(lv_color_t * a, lv_color_t * b, lv_color_t * c, lv_color_t * d)
{
lv_color_t tmp;
tmp = *a;
*a = *b;
*b = *c;
*c = *d;
*d = tmp;
}
/**
* Rotate a square image 90/270 degrees in place.
* @note inspired by https://stackoverflow.com/a/43694906
*/
static void lv_refr_vdb_rotate_90_sqr(bool is_270, lv_coord_t w, lv_color_t * color_p)
{
for(lv_coord_t i = 0; i < w / 2; i++) {
for(lv_coord_t j = 0; j < (w + 1) / 2; j++) {
lv_coord_t inv_i = (w - 1) - i;
lv_coord_t inv_j = (w - 1) - j;
if(is_270) {
lv_vdb_rotate4(
&color_p[i * w + j],
&color_p[inv_j * w + i],
&color_p[inv_i * w + inv_j],
&color_p[j * w + inv_i]
);
}
else {
lv_vdb_rotate4(
&color_p[i * w + j],
&color_p[j * w + inv_i],
&color_p[inv_i * w + inv_j],
&color_p[inv_j * w + i]
);
}
}
}
}
/**
* Rotate the VDB to the display's native orientation.
*/
static void lv_refr_vdb_rotate(lv_area_t * area, lv_color_t * color_p)
{
lv_disp_drv_t * drv = &disp_refr->driver;
if(lv_disp_is_true_double_buf(disp_refr) && drv->sw_rotate) {
LV_LOG_ERROR("cannot rotate a true double-buffered display!");
return;
}
if(drv->rotated == LV_DISP_ROT_180) {
lv_refr_vdb_rotate_180(drv, area, color_p);
drv->flush_cb(drv, area, color_p);
}
else if(drv->rotated == LV_DISP_ROT_90 || drv->rotated == LV_DISP_ROT_270) {
/*Allocate a temporary buffer to store rotated image */
lv_color_t * rot_buf = NULL;
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
lv_coord_t area_w = lv_area_get_width(area);
lv_coord_t area_h = lv_area_get_height(area);
/*Determine the maximum number of rows that can be rotated at a time*/
lv_coord_t max_row = LV_MATH_MIN((lv_coord_t)((LV_DISP_ROT_MAX_BUF / sizeof(lv_color_t)) / area_w), area_h);
lv_coord_t init_y_off;
init_y_off = area->y1;
if(drv->rotated == LV_DISP_ROT_90) {
area->y2 = drv->ver_res - area->x1 - 1;
area->y1 = area->y2 - area_w + 1;
}
else {
area->y1 = area->x1;
area->y2 = area->y1 + area_w - 1;
}
vdb->flushing = 0;
/*Rotate the screen in chunks, flushing after each one*/
lv_coord_t row = 0;
while(row < area_h) {
lv_coord_t height = LV_MATH_MIN(max_row, area_h - row);
vdb->flushing = 1;
if((row == 0) && (area_h >= area_w)) {
/*Rotate the initial area as a square*/
height = area_w;
lv_refr_vdb_rotate_90_sqr(drv->rotated == LV_DISP_ROT_270, area_w, color_p);
if(drv->rotated == LV_DISP_ROT_90) {
area->x1 = init_y_off;
area->x2 = init_y_off + area_w - 1;
}
else {
area->x2 = drv->hor_res - 1 - init_y_off;
area->x1 = area->x2 - area_w + 1;
}
}
else {
/*Rotate other areas using a maximum buffer size*/
if(rot_buf == NULL)
rot_buf = _lv_mem_buf_get(LV_DISP_ROT_MAX_BUF);
lv_refr_vdb_rotate_90(drv->rotated == LV_DISP_ROT_270, area_w, height, color_p, rot_buf);
if(drv->rotated == LV_DISP_ROT_90) {
area->x1 = init_y_off + row;
area->x2 = init_y_off + row + height - 1;
}
else {
area->x2 = drv->hor_res - 1 - init_y_off - row;
area->x1 = area->x2 - height + 1;
}
}
/*Flush the completed area to the display*/
drv->flush_cb(drv, area, rot_buf == NULL ? color_p : rot_buf);
/*FIXME: Rotation forces legacy behavior where rendering and flushing are done serially*/
while(vdb->flushing) {
if(drv->wait_cb) drv->wait_cb(drv);
}
color_p += area_w * height;
row += height;
}
/*Free the allocated buffer at the end if necessary*/
if(rot_buf != NULL)
_lv_mem_buf_release(rot_buf);
}
}
/**
* Flush the content of the VDB
*/
static void lv_refr_vdb_flush(void)
{
lv_disp_buf_t * vdb = lv_disp_get_buf(disp_refr);
lv_color_t * color_p = vdb->buf_act;
/*In double buffered mode wait until the other buffer is flushed before flushing the current
* one*/
if(lv_disp_is_double_buf(disp_refr)) {
while(vdb->flushing) {
if(disp_refr->driver.wait_cb) disp_refr->driver.wait_cb(&disp_refr->driver);
}
}
vdb->flushing = 1;
if(disp_refr->driver.buffer->last_area && disp_refr->driver.buffer->last_part) vdb->flushing_last = 1;
else vdb->flushing_last = 0;
/*Flush the rendered content to the display*/
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
if(disp->driver.gpu_wait_cb) disp->driver.gpu_wait_cb(&disp->driver);
if(disp->driver.flush_cb) {
/*Rotate the buffer to the display's native orientation if necessary*/
if(disp->driver.rotated != LV_DISP_ROT_NONE && disp->driver.sw_rotate) {
lv_refr_vdb_rotate(&vdb->area, vdb->buf_act);
}
else {
disp->driver.flush_cb(&disp->driver, &vdb->area, color_p);
}
}
if(vdb->buf1 && vdb->buf2) {
if(vdb->buf_act == vdb->buf1)
vdb->buf_act = vdb->buf2;
else
vdb->buf_act = vdb->buf1;
}
}

View File

@ -0,0 +1,103 @@
/**
* @file lv_refr.h
*
*/
#ifndef LV_REFR_H
#define LV_REFR_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_obj.h"
#include <stdbool.h>
/*********************
* DEFINES
*********************/
#define LV_REFR_TASK_PRIO LV_TASK_PRIO_MID
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the screen refresh subsystem
*/
void _lv_refr_init(void);
/**
* Redraw the invalidated areas now.
* Normally the redrawing is periodically executed in `lv_task_handler` but a long blocking process
* can prevent the call of `lv_task_handler`. In this case if the GUI is updated in the process
* (e.g. progress bar) this function can be called when the screen should be updated.
* @param disp pointer to display to refresh. NULL to refresh all displays.
*/
void lv_refr_now(lv_disp_t * disp);
/**
* Invalidate an area on display to redraw it
* @param area_p pointer to area which should be invalidated (NULL: delete the invalidated areas)
* @param disp pointer to display where the area should be invalidated (NULL can be used if there is
* only one display)
*/
void _lv_inv_area(lv_disp_t * disp, const lv_area_t * area_p);
/**
* Get the display which is being refreshed
* @return the display being refreshed
*/
lv_disp_t * _lv_refr_get_disp_refreshing(void);
/**
* Set the display which is being refreshed.
* It shouldn't be used directly by the user.
* It can be used to trick the drawing functions about there is an active display.
* @param the display being refreshed
*/
void _lv_refr_set_disp_refreshing(lv_disp_t * disp);
#if LV_USE_PERF_MONITOR
/**
* Get the average FPS since start up
* @return the average FPS
*/
uint32_t lv_refr_get_fps_avg(void);
#endif
/**
* Called periodically to handle the refreshing
* @param task pointer to the task itself
*/
void _lv_disp_refr_task(lv_task_t * task);
/**********************
* STATIC FUNCTIONS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_REFR_H*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,632 @@
/**
* @file lv_style.h
*
*/
#ifndef LV_STYLE_H
#define LV_STYLE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include <stdbool.h>
#include "../lv_font/lv_font.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_anim.h"
#include "../lv_misc/lv_types.h"
#include "../lv_misc/lv_debug.h"
#include "../lv_draw/lv_draw_blend.h"
/*********************
* DEFINES
*********************/
#define LV_RADIUS_CIRCLE (0x7FFF) /**< A very big radius to always draw as circle*/
LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE);
#define LV_DEBUG_STYLE_SENTINEL_VALUE 0x2288AAEE
#define LV_DEBUG_STYLE_LIST_SENTINEL_VALUE 0x9977CCBB
#define LV_STYLE_PROP_INIT(name, group, id, attr) name = (((group << 4) + id) | ((attr) << 8))
#define LV_STYLE_ID_MASK 0x00FF
#define LV_STYLE_ATTR_NONE 0
#define LV_STYLE_ATTR_INHERIT (1 << 7)
#define _LV_STYLE_CLOSING_PROP 0xFF
#define LV_STYLE_TRANS_NUM_MAX 6
#define LV_STYLE_PROP_ALL 0xFF
/**********************
* TYPEDEFS
**********************/
/*Border types (Use 'OR'ed values)*/
enum {
LV_BORDER_SIDE_NONE = 0x00,
LV_BORDER_SIDE_BOTTOM = 0x01,
LV_BORDER_SIDE_TOP = 0x02,
LV_BORDER_SIDE_LEFT = 0x04,
LV_BORDER_SIDE_RIGHT = 0x08,
LV_BORDER_SIDE_FULL = 0x0F,
LV_BORDER_SIDE_INTERNAL = 0x10, /**< FOR matrix-like objects (e.g. Button matrix)*/
_LV_BORDER_SIDE_LAST
};
typedef uint8_t lv_border_side_t;
enum {
LV_GRAD_DIR_NONE,
LV_GRAD_DIR_VER,
LV_GRAD_DIR_HOR,
_LV_GRAD_DIR_LAST
};
typedef uint8_t lv_grad_dir_t;
/*Text decorations (Use 'OR'ed values)*/
enum {
LV_TEXT_DECOR_NONE = 0x00,
LV_TEXT_DECOR_UNDERLINE = 0x01,
LV_TEXT_DECOR_STRIKETHROUGH = 0x02,
_LV_TEXT_DECOR_LAST
};
typedef uint8_t lv_text_decor_t;
typedef uint8_t lv_style_attr_t;
#define LV_STYLE_ATTR_GET_INHERIT(f) ((f)&0x80)
#define LV_STYLE_ATTR_GET_STATE(f) ((f)&0x7F)
#define LV_STYLE_ID_VALUE 0x0 /*max 9 pcs*/
#define LV_STYLE_ID_COLOR 0x9 /*max 3 pcs*/
#define LV_STYLE_ID_OPA 0xC /*max 2 pcs*/
#define LV_STYLE_ID_PTR 0xE /*max 2 pcs*/
enum {
/*Skip 0th property*/
LV_STYLE_PROP_INIT(LV_STYLE_RADIUS, 0x0, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_CLIP_CORNER, 0x0, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SIZE, 0x0, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_WIDTH, 0x0, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_HEIGHT, 0x0, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ANGLE, 0x0, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSFORM_ZOOM, 0x0, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OPA_SCALE, 0x0, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_PAD_TOP, 0x1, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PAD_BOTTOM, 0x1, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PAD_LEFT, 0x1, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PAD_RIGHT, 0x1, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PAD_INNER, 0x1, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_TOP, 0x1, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_BOTTOM, 0x1, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_LEFT, 0x1, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_MARGIN_RIGHT, 0x1, LV_STYLE_ID_VALUE + 8, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_BLEND_MODE, 0x2, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_MAIN_STOP, 0x2, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_STOP, 0x2, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_DIR, 0x2, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_COLOR, 0x2, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_GRAD_COLOR, 0x2, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BG_OPA, 0x2, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_WIDTH, 0x3, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_SIDE, 0x3, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_BLEND_MODE, 0x3, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_POST, 0x3, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_COLOR, 0x3, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_BORDER_OPA, 0x3, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_WIDTH, 0x4, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_PAD, 0x4, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_BLEND_MODE, 0x4, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_COLOR, 0x4, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_OUTLINE_OPA, 0x4, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_WIDTH, 0x5, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OFS_X, 0x5, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OFS_Y, 0x5, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_SPREAD, 0x5, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_BLEND_MODE, 0x5, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_COLOR, 0x5, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SHADOW_OPA, 0x5, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_BLEND_MODE, 0x6, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_REPEAT, 0x6, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_RECOLOR, 0x6, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_OPA, 0x6, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_RECOLOR_OPA, 0x6, LV_STYLE_ID_OPA + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_PATTERN_IMAGE, 0x6, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_LETTER_SPACE, 0x7, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_LINE_SPACE, 0x7, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_BLEND_MODE, 0x7, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OFS_X, 0x7, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OFS_Y, 0x7, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_ALIGN, 0x7, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_COLOR, 0x7, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_OPA, 0x7, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_FONT, 0x7, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_VALUE_STR, 0x7, LV_STYLE_ID_PTR + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_LETTER_SPACE, 0x8, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_LINE_SPACE, 0x8, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_DECOR, 0x8, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_BLEND_MODE, 0x8, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_COLOR, 0x8, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_SEL_COLOR, 0x8, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_SEL_BG_COLOR, 0x8, LV_STYLE_ID_COLOR + 2, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_OPA, 0x8, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TEXT_FONT, 0x8, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_WIDTH, 0x9, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_BLEND_MODE, 0x9, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_DASH_WIDTH, 0x9, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_DASH_GAP, 0x9, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_ROUNDED, 0x9, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_COLOR, 0x9, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_LINE_OPA, 0x9, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_BLEND_MODE, 0xA, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_RECOLOR, 0xA, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_OPA, 0xA, LV_STYLE_ID_OPA + 0, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_IMAGE_RECOLOR_OPA, 0xA, LV_STYLE_ID_OPA + 1, LV_STYLE_ATTR_INHERIT),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_TIME, 0xB, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_DELAY, 0xB, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_1, 0xB, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_2, 0xB, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_3, 0xB, LV_STYLE_ID_VALUE + 4, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_4, 0xB, LV_STYLE_ID_VALUE + 5, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_5, 0xB, LV_STYLE_ID_VALUE + 6, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PROP_6, 0xB, LV_STYLE_ID_VALUE + 7, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_TRANSITION_PATH, 0xB, LV_STYLE_ID_PTR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_WIDTH, 0xC, LV_STYLE_ID_VALUE + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_BORDER_WIDTH, 0xC, LV_STYLE_ID_VALUE + 1, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_BORDER_WIDTH, 0xC, LV_STYLE_ID_VALUE + 2, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_LINE_WIDTH, 0xC, LV_STYLE_ID_VALUE + 3, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_GRAD_COLOR, 0xC, LV_STYLE_ID_COLOR + 0, LV_STYLE_ATTR_NONE),
LV_STYLE_PROP_INIT(LV_STYLE_SCALE_END_COLOR, 0xC, LV_STYLE_ID_COLOR + 1, LV_STYLE_ATTR_NONE),
};
typedef uint16_t lv_style_property_t;
#define LV_STYLE_STATE_POS 8
#define LV_STYLE_STATE_MASK 0x7F00
#define LV_STYLE_INHERIT_MASK 0x8000
typedef uint16_t lv_style_state_t;
typedef struct {
uint8_t * map;
#if LV_USE_ASSERT_STYLE
uint32_t sentinel;
#endif
} lv_style_t;
typedef int16_t lv_style_int_t;
typedef struct {
lv_style_t ** style_list;
#if LV_USE_ASSERT_STYLE
uint32_t sentinel;
#endif
uint32_t style_cnt : 6;
uint32_t has_local : 1;
uint32_t has_trans : 1;
uint32_t skip_trans : 1; /*1: Temporally skip the transition style if any*/
uint32_t ignore_trans : 1; /*1: Mark that this style list shouldn't receive transitions at all*/
uint32_t valid_cache : 1; /*1: The cache is valid and can be used*/
uint32_t ignore_cache : 1; /*1: Ignore cache while getting value of properties*/
uint32_t radius_zero : 1;
uint32_t opa_scale_cover : 1;
uint32_t clip_corner_off : 1;
uint32_t transform_all_zero : 1;
uint32_t pad_all_zero : 1;
uint32_t margin_all_zero : 1;
uint32_t blend_mode_all_normal : 1;
uint32_t bg_opa_transp : 1;
uint32_t bg_opa_cover : 1;
uint32_t border_width_zero : 1;
uint32_t border_side_full : 1;
uint32_t border_post_off : 1;
uint32_t outline_width_zero : 1;
uint32_t pattern_img_null : 1;
uint32_t shadow_width_zero : 1;
uint32_t value_txt_str : 1;
uint32_t img_recolor_opa_transp : 1;
uint32_t text_space_zero : 1;
uint32_t text_decor_none : 1;
uint32_t text_font_normal : 1;
} lv_style_list_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize a style
* @param style pointer to a style to initialize
*/
void lv_style_init(lv_style_t * style);
/**
* Copy a style with all its properties
* @param style_dest pointer to the destination style. (Should be initialized with `lv_style_init()`)
* @param style_src pointer to the source (to copy )style
*/
void lv_style_copy(lv_style_t * style_dest, const lv_style_t * style_src);
/**
* Initialize a style list
* @param list a style list to initialize
*/
void lv_style_list_init(lv_style_list_t * list);
/**
* Copy a style list with all its styles and local style properties
* @param list_dest pointer to the destination style list. (should be initialized with `lv_style_list_init()`)
* @param list_src pointer to the source (to copy) style list.
*/
void lv_style_list_copy(lv_style_list_t * list_dest, const lv_style_list_t * list_src);
/**
* Add a style to a style list.
* Only the style pointer will be saved so the shouldn't be a local variable.
* (It should be static, global or dynamically allocated)
* @param list pointer to a style list
* @param style pointer to a style to add
*/
void _lv_style_list_add_style(lv_style_list_t * list, lv_style_t * style);
/**
* Remove a style from a style list
* @param style_list pointer to a style list
* @param style pointer to a style to remove
*/
void _lv_style_list_remove_style(lv_style_list_t * list, lv_style_t * style);
/**
* Remove all styles added from style list, clear the local style, transition style and free all allocated memories.
* Leave `ignore_trans` flag as it is.
* @param list pointer to a style list.
*/
void _lv_style_list_reset(lv_style_list_t * style_list);
static inline lv_style_t * lv_style_list_get_style(lv_style_list_t * list, uint8_t id)
{
if(list->has_trans && list->skip_trans) id++;
if(list->style_cnt == 0 || id >= list->style_cnt) return NULL;
return list->style_list[id];
}
/**
* Clear all properties from a style and all allocated memories.
* @param style pointer to a style
*/
void lv_style_reset(lv_style_t * style);
/**
* Get the size of the properties in a style in bytes
* @param style pointer to a style
* @return size of the properties in bytes
*/
uint16_t _lv_style_get_mem_size(const lv_style_t * style);
/**
* Copy a style to an other
* @param dest pointer to the destination style
* @param src pointer to the source style
*/
void lv_style_copy(lv_style_t * dest, const lv_style_t * src);
/**
* Remove a property from a style
* @param style pointer to a style
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @return true: the property was found and removed; false: the property wasn't found
*/
bool lv_style_remove_prop(lv_style_t * style, lv_style_property_t prop);
/**
* Set an integer typed property in a style.
* @param style pointer to a style where the property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note shouldn't be used directly. Use the specific property set functions instead.
* For example: `lv_style_set_border_width()`
* @note for performance reasons it's not checked if the property really has integer type
*/
void _lv_style_set_int(lv_style_t * style, lv_style_property_t prop, lv_style_int_t value);
/**
* Set a color typed property in a style.
* @param style pointer to a style where the property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note shouldn't be used directly. Use the specific property set functions instead.
* For example: `lv_style_set_border_color()`
* @note for performance reasons it's not checked if the property really has color type
*/
void _lv_style_set_color(lv_style_t * style, lv_style_property_t prop, lv_color_t color);
/**
* Set an opacity typed property in a style.
* @param style pointer to a style where the property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note shouldn't be used directly. Use the specific property set functions instead.
* For example: `lv_style_set_border_opa()`
* @note for performance reasons it's not checked if the property really has opacity type
*/
void _lv_style_set_opa(lv_style_t * style, lv_style_property_t prop, lv_opa_t opa);
/**
* Set a pointer typed property in a style.
* @param style pointer to a style where the property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_TEXT_POINTER | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note shouldn't be used directly. Use the specific property set functions instead.
* For example: `lv_style_set_border_width()`
* @note for performance reasons it's not checked if the property really has pointer type
*/
void _lv_style_set_ptr(lv_style_t * style, lv_style_property_t prop, const void * p);
/**
* Get an integer typed property from a style.
* @param style pointer to a style from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result value
* @return -1: the property wasn't found in the style.
* The matching state bits of the desired state (in `prop`) and the best matching property's state
* Higher value means match in higher precedence state.
* @note shouldn't be used directly. Use the specific property get functions instead.
* For example: `lv_style_get_border_width()`
* @note for performance reasons it's not checked if the property really has integer type
*/
int16_t _lv_style_get_int(const lv_style_t * style, lv_style_property_t prop, lv_style_int_t * res);
/**
* Get a color typed property from a style.
* @param style pointer to a style from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result value
* @return -1: the property wasn't found in the style.
* The matching state bits of the desired state (in `prop`) and the best matching property's state
* Higher value means match in higher precedence state.
* @note shouldn't be used directly. Use the specific property get functions instead.
* For example: `lv_style_get_border_color()`
* @note for performance reasons it's not checked if the property really has color type
*/
int16_t _lv_style_get_color(const lv_style_t * style, lv_style_property_t prop, lv_color_t * res);
/**
* Get an opacity typed property from a style.
* @param style pointer to a style from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result value
* @return -1: the property wasn't found in the style.
* The matching state bits of the desired state (in `prop`) and the best matching property's state
* Higher value means match in higher precedence state.
* @note shouldn't be used directly. Use the specific property get functions instead.
* For example: `lv_style_get_border_opa()`
* @note for performance reasons it's not checked if the property really has opacity type
*/
int16_t _lv_style_get_opa(const lv_style_t * style, lv_style_property_t prop, lv_opa_t * res);
/**
* Get a pointer typed property from a style.
* @param style pointer to a style from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result value
* @return -1: the property wasn't found in the style.
* The matching state bits of the desired state (in `prop`) and the best matching property's state
* Higher value means match in higher precedence state.
* @note shouldn't be used directly. Use the specific property get functions instead.
* For example: `lv_style_get_text_font()`
* @note for performance reasons it's not checked if the property really has pointer type
*/
int16_t _lv_style_get_ptr(const lv_style_t * style, lv_style_property_t prop, const void ** res);
/**
* Get the local style of a style list
* @param list pointer to a style list where the local property should be set
* @return pointer to the local style if exists else `NULL`.
*/
lv_style_t * lv_style_list_get_local_style(lv_style_list_t * list);
/**
* Get the transition style of a style list
* @param list pointer to a style list where the transition property should be set
* @return pointer to the transition style if exists else `NULL`.
*/
lv_style_t * _lv_style_list_get_transition_style(lv_style_list_t * list);
/**
* Allocate the transition style in a style list. If already exists simply return it.
* @param list pointer to a style list
* @return the transition style of a style list
*/
lv_style_t * _lv_style_list_add_trans_style(lv_style_list_t * list);
/**
* Set a local integer typed property in a style list.
* @param list pointer to a style list where the local property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note for performance reasons it's not checked if the property really has integer type
*/
void _lv_style_list_set_local_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t value);
/**
* Set a local color typed property in a style list.
* @param list pointer to a style list where the local property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note for performance reasons it's not checked if the property really has color type
*/
void _lv_style_list_set_local_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t value);
/**
* Set a local opacity typed property in a style list.
* @param list pointer to a style list where the local property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note for performance reasons it's not checked if the property really has opacity type
*/
void _lv_style_list_set_local_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t value);
/**
* Set a local pointer typed property in a style list.
* @param list pointer to a style list where the local property should be set
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param value the value to set
* @note for performance reasons it's not checked if the property really has pointer type
*/
void _lv_style_list_set_local_ptr(lv_style_list_t * list, lv_style_property_t prop, const void * value);
/**
* Get an integer typed property from a style list.
* It will return the property which match best with given state.
* @param list pointer to a style list from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result
* @return LV_RES_OK: there was a matching property in the list
* LV_RES_INV: there was NO matching property in the list
* @note for performance reasons it's not checked if the property really has integer type
*/
lv_res_t _lv_style_list_get_int(lv_style_list_t * list, lv_style_property_t prop, lv_style_int_t * res);
/**
* Get a color typed property from a style list.
* It will return the property which match best with given state.
* @param list pointer to a style list from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result
* @return LV_RES_OK: there was a matching property in the list
* LV_RES_INV: there was NO matching property in the list
* @note for performance reasons it's not checked if the property really has color type
*/
lv_res_t _lv_style_list_get_color(lv_style_list_t * list, lv_style_property_t prop, lv_color_t * res);
/**
* Get an opacity typed property from a style list.
* It will return the property which match best with given state.
* @param list pointer to a style list from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result
* @return LV_RES_OK: there was a matching property in the list
* LV_RES_INV: there was NO matching property in the list
* @note for performance reasons it's not checked if the property really has opacity type
*/
lv_res_t _lv_style_list_get_opa(lv_style_list_t * list, lv_style_property_t prop, lv_opa_t * res);
/**
* Get a pointer typed property from a style list.
* It will return the property which match best with given state.
* @param list pointer to a style list from where the property should be get
* @param prop a style property ORed with a state.
* E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)`
* @param res pointer to a buffer to store the result
* @return LV_RES_OK: there was a matching property in the list
* LV_RES_INV: there was NO matching property in the list
* @note for performance reasons it's not checked if the property really has pointer type
*/
lv_res_t _lv_style_list_get_ptr(lv_style_list_t * list, lv_style_property_t prop, const void ** res);
/**
* Check whether a style is valid (initialized correctly)
* @param style pointer to a style
* @return true: valid
*/
bool lv_debug_check_style(const lv_style_t * style);
/**
* Check whether a style list is valid (initialized correctly)
* @param list pointer to a style list
* @return true: valid
*/
bool lv_debug_check_style_list(const lv_style_list_t * list);
/*************************
* GLOBAL VARIABLES
*************************/
/**********************
* MACROS
**********************/
/**
* Create and initialize a `static` style
* Example:
* LV_STYLE_CREATE(my_style, &style_to_copy);
* is equivalent to
* static lv_style_t my_style;
* lv_style_init(&my_style);
* lv_style_copy(&my_style, &style_to_copy);
*/
#define LV_STYLE_CREATE(name, copy_p) static lv_style_t name; lv_style_init(&name); lv_style_copy(&name, copy_p)
#if LV_USE_DEBUG
# ifndef LV_DEBUG_IS_STYLE
# define LV_DEBUG_IS_STYLE(style_p) (lv_debug_check_style(style_p))
# endif
# ifndef LV_DEBUG_IS_STYLE_LIST
# define LV_DEBUG_IS_STYLE_LIST(list_p) (lv_debug_check_style_list(list_p))
# endif
# if LV_USE_ASSERT_STYLE
# ifndef LV_ASSERT_STYLE
# define LV_ASSERT_STYLE(style_p) LV_DEBUG_ASSERT(LV_DEBUG_IS_STYLE(style_p), "Invalid style", style_p);
# endif
# ifndef LV_ASSERT_STYLE_LIST
# define LV_ASSERT_STYLE_LIST(list_p) LV_DEBUG_ASSERT(LV_DEBUG_IS_STYLE_LIST(list_p), "Invalid style list", list_p);
# endif
# else
# define LV_ASSERT_STYLE(style_p)
# define LV_ASSERT_STYLE_LIST(list_p)
# endif
#else
# define LV_ASSERT_STYLE(p)
# define LV_ASSERT_STYLE_LIST(p)
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_STYLE_H*/