Merge branch 'dev-6.0' into tri

This commit is contained in:
Gabor Kiss-Vamosi
2019-05-31 06:42:05 +02:00
97 changed files with 4379 additions and 2269 deletions

View File

@@ -39,7 +39,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 100
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4

View File

@@ -120,6 +120,9 @@
/*1: Enable the Animations */
#define LV_USE_ANIMATION 1
#if LV_USE_ANIMATION
typedef void * lv_anim_user_data_t;
#endif
/* 1: Enable shadow drawing*/
#define LV_USE_SHADOW 1
@@ -142,11 +145,11 @@ typedef void * lv_group_user_data_t;
/* 1: Enable alpha indexed images */
#define LV_IMG_CF_ALPHA 1
/*1: Add a `user_data` to drivers and objects*/
#define LV_USE_USER_DATA_SINGLE 1
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
typedef void * lv_img_decoder_user_data_t;
/*1: Add separate `user_data` for every callback*/
#define LV_USE_USER_DATA_MULTI 0
/*1: Add a `user_data` to drivers and objects*/
#define LV_USE_USER_DATA 1
/*=====================
* Compiler settings
@@ -157,6 +160,11 @@ typedef void * lv_group_user_data_t;
/* Define a custom attribute to `lv_task_handler` function */
#define LV_ATTRIBUTE_TASK_HANDLER
/* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
* E.g. __attribute__((aligned(4))) */
#define LV_ATTRIBUTE_MEM_ALIGN
/* 1: Variable length array is supported*/
#define LV_COMPILER_VLA_SUPPORTED 1
@@ -176,7 +184,7 @@ typedef void * lv_group_user_data_t;
#endif /*LV_TICK_CUSTOM*/
typedef void * lv_disp_drv_user_data_t; /*Type of user data in the display driver*/
typedef void * lv_indev_drv_user_data_t; /*Type of user data in the display driver*/
typedef void * lv_indev_drv_user_data_t; /*Type of user data in the input device driver*/
/*================
* Log settings
@@ -255,6 +263,13 @@ typedef void * lv_indev_drv_user_data_t; /*Type of user data in the d
* Text settings
*=================*/
/* Select a character encoding for strings.
* Your IDE or editor should have the same character encoding
* - LV_TXT_ENC_UTF8
* - LV_TXT_ENC_ASCII
* */
#define LV_TXT_ENC LV_TXT_ENC_UTF8
/*Can break (wrap) texts on these chars*/
#define LV_TXT_BREAK_CHARS " ,.;:-_"
@@ -354,6 +369,7 @@ typedef void * lv_obj_user_data_t;
/*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_ROLL/ROLL_CIRC' mode*/
# define LV_LABEL_DEF_SCROLL_SPEED 25
# define LV_LABEL_WAIT_CHAR_COUNT 3 /* Waiting period at beginning/end of animation cycle */
# define LV_LABEL_TEXT_SEL 1 /*Enable selecting text of the label */
#endif
/*LED (dependencies: -)*/
@@ -378,7 +394,7 @@ typedef void * lv_obj_user_data_t;
/*Page (dependencies: lv_cont)*/
#define LV_USE_PAGE 1
/*Preload (dependencies: lv_arc)*/
/*Preload (dependencies: lv_arc, lv_anim)*/
#define LV_USE_PRELOAD 1
#if LV_USE_PRELOAD != 0
# define LV_PRELOAD_DEF_ARC_LENGTH 60 /*[deg]*/
@@ -408,8 +424,8 @@ typedef void * lv_obj_user_data_t;
/*Text area (dependencies: lv_label, lv_page)*/
#define LV_USE_TA 1
#if LV_USE_TA != 0
# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
# define LV_TA_DEF_CURSOR_BLINK_TIME 400 /*ms*/
# define LV_TA_DEF_PWD_SHOW_TIME 1500 /*ms*/
#endif
/*Table (dependencies: lv_label)*/

View File

@@ -169,6 +169,8 @@
#ifndef LV_USE_ANIMATION
#define LV_USE_ANIMATION 1
#endif
#if LV_USE_ANIMATION
#endif
/* 1: Enable shadow drawing*/
#ifndef LV_USE_SHADOW
@@ -202,14 +204,11 @@
#define LV_IMG_CF_ALPHA 1
#endif
/*1: Add a `user_data` to drivers and objects*/
#ifndef LV_USE_USER_DATA_SINGLE
#define LV_USE_USER_DATA_SINGLE 1
#endif
/*Declare the type of the user data of image decoder (can be e.g. `void *`, `int`, `struct`)*/
/*1: Add separate `user_data` for every callback*/
#ifndef LV_USE_USER_DATA_MULTI
#define LV_USE_USER_DATA_MULTI 0
/*1: Add a `user_data` to drivers and objects*/
#ifndef LV_USE_USER_DATA
#define LV_USE_USER_DATA 1
#endif
/*=====================
@@ -225,6 +224,13 @@
#define LV_ATTRIBUTE_TASK_HANDLER
#endif
/* With size optimization (-Os) the compiler might not align data to
* 4 or 8 byte boundary. This alignment will be explicitly applied where needed.
* E.g. __attribute__((aligned(4))) */
#ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN
#endif
/* 1: Variable length array is supported*/
#ifndef LV_COMPILER_VLA_SUPPORTED
#define LV_COMPILER_VLA_SUPPORTED 1
@@ -393,6 +399,15 @@
* Text settings
*=================*/
/* Select a character encoding for strings.
* Your IDE or editor should have the same character encoding
* - LV_TXT_ENC_UTF8
* - LV_TXT_ENC_ASCII
* */
#ifndef LV_TXT_ENC
#define LV_TXT_ENC LV_TXT_ENC_UTF8
#endif
/*Can break (wrap) texts on these chars*/
#ifndef LV_TXT_BREAK_CHARS
#define LV_TXT_BREAK_CHARS " ,.;:-_"
@@ -545,6 +560,9 @@
#ifndef LV_LABEL_WAIT_CHAR_COUNT
# define LV_LABEL_WAIT_CHAR_COUNT 3 /* Waiting period at beginning/end of animation cycle */
#endif
#ifndef LV_LABEL_TEXT_SEL
# define LV_LABEL_TEXT_SEL 1 /*Enable selecting text of the label */
#endif
#endif
/*LED (dependencies: -)*/
@@ -583,7 +601,7 @@
#define LV_USE_PAGE 1
#endif
/*Preload (dependencies: lv_arc)*/
/*Preload (dependencies: lv_arc, lv_anim)*/
#ifndef LV_USE_PRELOAD
#define LV_USE_PRELOAD 1
#endif
@@ -635,11 +653,11 @@
#define LV_USE_TA 1
#endif
#if LV_USE_TA != 0
#ifndef LV_TA_CURSOR_BLINK_TIME
# define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
#ifndef LV_TA_DEF_CURSOR_BLINK_TIME
# define LV_TA_DEF_CURSOR_BLINK_TIME 400 /*ms*/
#endif
#ifndef LV_TA_PWD_SHOW_TIME
# define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
#ifndef LV_TA_DEF_PWD_SHOW_TIME
# define LV_TA_DEF_PWD_SHOW_TIME 1500 /*ms*/
#endif
#endif

View File

@@ -112,7 +112,7 @@ void lv_disp_assign_screen(lv_disp_t * disp, lv_obj_t * scr)
if(old_disp == disp) return;
lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr);
lv_ll_chg_list(&old_disp->scr_ll, &disp->scr_ll, scr, true);
}
/**

View File

@@ -74,16 +74,10 @@ lv_group_t * lv_group_create(void)
group->refocus_policy = LV_GROUP_REFOCUS_POLICY_PREV;
group->wrap = 1;
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
memset(&group->user_data, 0, sizeof(lv_group_user_data_t));
#endif
#if LV_USE_USER_DATA_MULTI
memset(&group->focus_user_data, 0, sizeof(lv_group_user_data_t));
memset(&group->style_mod_user_data, 0, sizeof(lv_group_user_data_t));
memset(&group->style_mod_edit_user_data, 0, sizeof(lv_group_user_data_t));
#endif
/*Initialize style modification callbacks from current theme*/
refresh_theme(group, lv_theme_get_current());
@@ -110,6 +104,7 @@ void lv_group_del(lv_group_t * group)
}
lv_ll_clear(&(group->obj_ll));
lv_ll_rem(&LV_GC_ROOT(_lv_group_ll), group);
lv_mem_free(group);
}
@@ -198,6 +193,28 @@ 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)
{
/*Defocus the 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
@@ -284,17 +301,25 @@ 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;
return act->signal_cb(act, LV_SIGNAL_CONTROL, &c);
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 modify the object's style if it is in focus
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
* @param style_mod_cb the style modifier function pointer
*/
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_cb_t style_mod_cb)
{
group->style_mod = style_mod_func;
group->style_mod_cb = style_mod_cb;
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
}
@@ -303,9 +328,9 @@ void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t sty
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
*/
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func)
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_cb_t style_mod_edit_cb)
{
group->style_mod_edit = style_mod_func;
group->style_mod_edit_cb = style_mod_edit_cb;
if(group->obj_focus != NULL) lv_obj_invalidate(*group->obj_focus);
}
@@ -380,9 +405,9 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style)
lv_style_copy(&group->style_tmp, style);
if(group->editing) {
if(group->style_mod_edit) group->style_mod_edit(group, &group->style_tmp);
if(group->style_mod_edit_cb) group->style_mod_edit_cb(group, &group->style_tmp);
} else {
if(group->style_mod) group->style_mod(group, &group->style_tmp);
if(group->style_mod_cb) group->style_mod_cb(group, &group->style_tmp);
}
return &group->style_tmp;
}
@@ -400,7 +425,7 @@ lv_obj_t * lv_group_get_focused(const lv_group_t * group)
return *group->obj_focus;
}
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
/**
* Get a pointer to the group's user data
* @param group pointer to an group
@@ -417,10 +442,10 @@ lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group)
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group)
lv_group_style_mod_cb_t lv_group_get_style_mod_cb(const lv_group_t * group)
{
if(!group) return false;
return group->style_mod;
return group->style_mod_cb;
}
/**
@@ -428,10 +453,10 @@ lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group)
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group)
lv_group_style_mod_cb_t lv_group_get_style_mod_edit_cb(const lv_group_t * group)
{
if(!group) return false;
return group->style_mod_edit;
return group->style_mod_edit_cb;
}
/**
@@ -581,11 +606,11 @@ static void style_mod_edit_def(lv_group_t * group, lv_style_t * style)
static void refresh_theme(lv_group_t * g, lv_theme_t * th)
{
g->style_mod = style_mod_def;
g->style_mod_edit = style_mod_edit_def;
g->style_mod_cb = style_mod_def;
g->style_mod_edit_cb = style_mod_edit_def;
if(th) {
if(th->group.style_mod) g->style_mod = th->group.style_mod;
if(th->group.style_mod_edit) g->style_mod_edit = th->group.style_mod_edit;
if(th->group.style_mod_cb) g->style_mod_cb = th->group.style_mod_cb;
if(th->group.style_mod_edit_cb) g->style_mod_edit_cb = th->group.style_mod_edit_cb;
}
}
@@ -668,10 +693,7 @@ static void obj_to_foreground(lv_obj_t * obj)
if(last_top != NULL) {
/*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
lv_obj_invalidate(last_top);
lv_obj_move_foreground(last_top);
}
}

View File

@@ -25,19 +25,23 @@ extern "C" {
* 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_GROUP*/
#define LV_KEY_UP 17 /*0x11*/
#define LV_KEY_DOWN 18 /*0x12*/
#define LV_KEY_RIGHT 19 /*0x13*/
#define LV_KEY_LEFT 20 /*0x14*/
#define LV_KEY_ESC 27 /*0x1B*/
#define LV_KEY_DEL 127 /*0x7F*/
#define LV_KEY_BACKSPACE 8 /*0x08*/
#define LV_KEY_ENTER 10 /*0x0A, '\n'*/
#define LV_KEY_NEXT 9 /*0x09, '\t'*/
#define LV_KEY_PREV 11 /*0x0B, '*/
#define LV_KEY_HOME 2 /*0x02, STX*/
#define LV_KEY_END 3 /*0x03, ETX*/
/*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
/**********************
@@ -45,29 +49,22 @@ extern "C" {
**********************/
struct _lv_group_t;
typedef void (*lv_group_style_mod_func_t)(struct _lv_group_t *, lv_style_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 *);
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_style_mod_func_t
style_mod; /*A function which modifies the style of the focused object*/
lv_group_style_mod_func_t
style_mod_edit; /*A function which modifies the style of the focused object*/
lv_group_style_mod_cb_t style_mod_cb; /*A function to modifies the style of the focused object*/
lv_group_style_mod_cb_t style_mod_edit_cb; /*A function which modifies the style of the edited object*/
lv_group_focus_cb_t focus_cb; /*A function to call when a new object is focused (optional)*/
lv_style_t style_tmp; /*Stores the modified style of the focused object */
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
lv_group_user_data_t user_data;
#endif
#if LV_USE_USER_DATA_MULTI
lv_group_user_data_t focus_user_data;
lv_group_user_data_t style_mod_user_data;
lv_group_user_data_t style_mod_edit_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
@@ -116,6 +113,12 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj);
*/
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
@@ -152,16 +155,16 @@ lv_res_t lv_group_send_data(lv_group_t * group, uint32_t c);
/**
* Set a function for a group which will modify the object's style if it is in focus
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
* @param style_mod_cb the style modifier function pointer
*/
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
void lv_group_set_style_mod_cb(lv_group_t * group, lv_group_style_mod_cb_t style_mod_cb);
/**
* Set a function for a group which will modify the object's style if it is in focus in edit mode
* @param group pointer to a group
* @param style_mod_func the style modifier function pointer
* @param style_mod_edit_cb the style modifier function pointer
*/
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_func_t style_mod_func);
void lv_group_set_style_mod_edit_cb(lv_group_t * group, lv_group_style_mod_cb_t style_mod_edit_cb);
/**
* Set a function for a group which will be called when a new object is focused
@@ -214,7 +217,7 @@ lv_style_t * lv_group_mod_style(lv_group_t * group, const lv_style_t * style);
*/
lv_obj_t * lv_group_get_focused(const lv_group_t * group);
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
/**
* Get a pointer to the group's user data
* @param group pointer to an group
@@ -229,14 +232,14 @@ lv_group_user_data_t * lv_group_get_user_data(lv_group_t * group);
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_cb(const lv_group_t * group);
lv_group_style_mod_cb_t lv_group_get_style_mod_cb(const lv_group_t * group);
/**
* Get a the style modifier function of a group in edit mode
* @param group pointer to a group
* @return pointer to the style modifier function
*/
lv_group_style_mod_func_t lv_group_get_style_mod_edit_cb(const lv_group_t * group);
lv_group_style_mod_cb_t lv_group_get_style_mod_edit_cb(const lv_group_t * group);
/**
* Get the focus callback function of a group

View File

@@ -42,11 +42,13 @@ static void indev_proc_reset_query_handler(lv_indev_t * indev);
static lv_obj_t * indev_search_obj(const lv_indev_proc_t * proc, lv_obj_t * obj);
static void indev_drag(lv_indev_proc_t * state);
static void indev_drag_throw(lv_indev_proc_t * proc);
static bool indev_reset_check(lv_indev_proc_t *proc);
/**********************
* STATIC VARIABLES
**********************/
static lv_indev_t * indev_act;
static lv_obj_t * indev_obj_act = NULL;
/**********************
* MACROS
@@ -68,13 +70,13 @@ void lv_indev_init(void)
* Called periodically to read the input devices
* @param param pointer to and input device to read
*/
void lv_indev_read_task(void * param)
void lv_indev_read_task(lv_task_t * task)
{
LV_LOG_TRACE("indev read task started");
lv_indev_data_t data;
indev_act = param;
indev_act = task->user_data;
/*Read and process all indevs*/
if(indev_act->driver.disp == NULL) return; /*Not assigned to any displays*/
@@ -90,12 +92,17 @@ void lv_indev_read_task(void * param)
/*The active object might deleted even in the read function*/
indev_proc_reset_query_handler(indev_act);
indev_obj_act = NULL;
indev_act->proc.state = data.state;
/*Save the last activity time*/
if(indev_act->proc.state == LV_INDEV_STATE_PR) {
indev_act->driver.disp->last_activity_time = lv_tick_get();
} else if(indev_act->driver.type == LV_INDEV_TYPE_ENCODER && data.enc_diff) {
indev_act->driver.disp->last_activity_time = lv_tick_get();
}
if(indev_act->driver.type == LV_INDEV_TYPE_POINTER) {
indev_pointer_proc(indev_act, &data);
} else if(indev_act->driver.type == LV_INDEV_TYPE_KEYPAD) {
@@ -111,6 +118,7 @@ void lv_indev_read_task(void * param)
/*End of indev processing, so no act indev*/
indev_act = NULL;
indev_obj_act = NULL;
LV_LOG_TRACE("indev read task finished");
}
@@ -219,16 +227,6 @@ void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points)
}
}
/**
* Set feedback callback for indev.
* @param indev pointer to an input device
* @param feedback feedback callback
*/
void lv_indev_set_feedback(lv_indev_t * indev, lv_indev_feedback_t feedback)
{
indev->feedback = feedback;
}
/**
* 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
@@ -295,16 +293,6 @@ void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point)
}
}
/**
* Get feedback callback for indev.
* @param indev pointer to an input device
* @return feedback callback
*/
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t * indev)
{
return indev->feedback;
}
/**
* Do nothing until the next release
* @param indev pointer to an input device
@@ -330,6 +318,15 @@ lv_task_t * lv_indev_get_read_task(lv_disp_t * indev)
return indev->refr_task;
}
/**
* Gets a pointer to the currently active object in the currently processed input device.
* @return pointer to currently active object or NULL if no active object
*/
lv_obj_t * lv_indev_get_obj_act(void)
{
return indev_obj_act;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -380,8 +377,8 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
lv_group_t * g = i->group;
if(g == NULL) return;
lv_obj_t * focused = lv_group_get_focused(g);
if(focused == NULL) return;
indev_obj_act = lv_group_get_focused(g);
if(indev_obj_act == NULL) return;
/*Save the last key to compare it with the current latter on RELEASE*/
uint32_t prev_key = i->proc.types.keypad.last_key;
@@ -405,30 +402,30 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
/*Send the ENTER as a normal KEY*/
lv_group_send_data(g, LV_KEY_ENTER);
focused->signal_cb(focused, LV_SIGNAL_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(focused, LV_EVENT_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
} else if(data->key == LV_KEY_ESC) {
/*Send the ESC as a normal KEY*/
lv_group_send_data(g, LV_KEY_ESC);
lv_event_send(focused, LV_EVENT_CANCEL, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CANCEL, NULL);
if(indev_reset_check(&i->proc)) return;
}
/*Move the focus on NEXT*/
else if(data->key == LV_KEY_NEXT) {
lv_group_set_editing(g,
false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_next(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(indev_reset_check(&i->proc)) return;
}
/*Move the focus on PREV*/
else if(data->key == LV_KEY_PREV) {
lv_group_set_editing(g,
false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_prev(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(indev_reset_check(&i->proc)) return;
}
/*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/
else {
@@ -443,10 +440,10 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
i->proc.long_pr_sent = 1;
if(data->key == LV_KEY_ENTER) {
i->proc.longpr_rep_timestamp = lv_tick_get();
focused->signal_cb(focused, LV_SIGNAL_LONG_PRESS, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(focused, LV_EVENT_LONG_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
}
}
/*Long press repeated time has elapsed?*/
@@ -457,29 +454,29 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
/*Send LONG_PRESS_REP on ENTER*/
if(data->key == LV_KEY_ENTER) {
focused->signal_cb(focused, LV_SIGNAL_LONG_PRESS_REP, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(focused, LV_EVENT_LONG_PRESSED_REPEAT, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS_REP, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, NULL);
if(indev_reset_check(&i->proc)) return;
}
/*Move the focus on NEXT again*/
else if(data->key == LV_KEY_NEXT) {
lv_group_set_editing(
g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_next(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(indev_reset_check(&i->proc)) return;
}
/*Move the focus on PREV again*/
else if(data->key == LV_KEY_PREV) {
lv_group_set_editing(
g, false); /*Editing is not used by KEYPAD is be sure it is disabled*/
lv_group_focus_prev(g);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(indev_reset_check(&i->proc)) return;
}
/*Just send other keys again to the object (e.g. 'A' or `LV_GORUP_KEY_RIGHT)*/
else {
lv_group_send_data(g, data->key);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(indev_reset_check(&i->proc)) return;
}
}
}
@@ -489,23 +486,24 @@ static void indev_keypad_proc(lv_indev_t * i, lv_indev_data_t * data)
data->key = prev_key;
if(data->key == LV_KEY_ENTER) {
focused->signal_cb(focused, LV_SIGNAL_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
if(i->proc.long_pr_sent == 0) {
lv_event_send(focused, LV_EVENT_SHORT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
}
lv_event_send(focused, LV_EVENT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
}
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
}
indev_obj_act = NULL;
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
@@ -530,11 +528,17 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
i->proc.types.keypad.last_state = LV_INDEV_STATE_REL; /*To skip the processing of release*/
}
/* Save the last keys before anything else.
* They need to be already saved if the the function returns for any reason*/
lv_indev_state_t last_state = i->proc.types.keypad.last_state;
i->proc.types.keypad.last_state = data->state;
i->proc.types.keypad.last_key = data->key;
lv_group_t * g = i->group;
if(g == NULL) return;
lv_obj_t * focused = lv_group_get_focused(g);
if(focused == NULL) return;
indev_obj_act = lv_group_get_focused(g);
if(indev_obj_act == NULL) return;
/*Process the steps first. They are valid only with released button*/
if(data->state == LV_INDEV_STATE_REL) {
@@ -559,30 +563,30 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
}
/*Refresh the focused object. It might change due to lv_group_focus_prev/next*/
focused = lv_group_get_focused(g);
if(focused == NULL) return;
indev_obj_act = lv_group_get_focused(g);
if(indev_obj_act == NULL) return;
/*Button press happened*/
if(data->state == LV_INDEV_STATE_PR && i->proc.types.keypad.last_state == LV_INDEV_STATE_REL) {
if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_REL) {
bool editable = false;
focused->signal_cb(focused, LV_SIGNAL_GET_EDITABLE, &editable);
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
i->proc.pr_timestamp = lv_tick_get();
if(lv_group_get_editing(g) == true || editable == false) {
focused->signal_cb(focused, LV_SIGNAL_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
}
}
/*Pressing*/
else if(data->state == LV_INDEV_STATE_PR &&
i->proc.types.keypad.last_state == LV_INDEV_STATE_PR) {
last_state == LV_INDEV_STATE_PR) {
if(i->proc.long_pr_sent == 0 &&
lv_tick_elaps(i->proc.pr_timestamp) > i->driver.long_press_time) {
bool editable = false;
focused->signal_cb(focused, LV_SIGNAL_GET_EDITABLE, &editable);
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
/*On enter long press toggle edit mode.*/
if(editable) {
@@ -595,50 +599,50 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
}
/*If not editable then just send a long press signal*/
else {
focused->signal_cb(focused, LV_SIGNAL_LONG_PRESS, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(focused, LV_EVENT_LONG_PRESSED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL);
if(indev_reset_check(&i->proc)) return;
}
i->proc.long_pr_sent = 1;
}
}
/*Release happened*/
else if(data->state == LV_INDEV_STATE_REL &&
i->proc.types.keypad.last_state == LV_INDEV_STATE_PR) {
last_state == LV_INDEV_STATE_PR) {
bool editable = false;
focused->signal_cb(focused, LV_SIGNAL_GET_EDITABLE, &editable);
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable);
/*The button was released on a non-editable object. Just send enter*/
if(editable == false) {
focused->signal_cb(focused, LV_SIGNAL_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
if(i->proc.long_pr_sent == 0) lv_event_send(focused, LV_EVENT_SHORT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
}
/*An object is being edited and the button is released. */
else if(g->editing) {
/*Ignore long pressed enter release because it comes from mode switch*/
if(!i->proc.long_pr_sent || lv_ll_is_empty(&g->obj_ll)) {
focused->signal_cb(focused, LV_SIGNAL_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_SHORT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_CLICKED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_event_send(focused, LV_EVENT_RELEASED, NULL);
if(i->proc.reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
if(indev_reset_check(&i->proc)) return;
lv_group_send_data(g, LV_KEY_ENTER);
}
@@ -652,9 +656,7 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data)
i->proc.pr_timestamp = 0;
i->proc.long_pr_sent = 0;
}
i->proc.types.keypad.last_state = data->state;
i->proc.types.keypad.last_key = data->key;
indev_obj_act = NULL;
#else
(void)data; /*Unused*/
(void)i; /*Unused*/
@@ -693,50 +695,50 @@ static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data)
*/
static void indev_proc_press(lv_indev_proc_t * proc)
{
lv_obj_t * pr_obj = proc->types.pointer.act_obj;
indev_obj_act = proc->types.pointer.act_obj;
if(proc->wait_until_release != 0) return;
lv_disp_t * disp = indev_act->driver.disp;
/*If there is no last object then search*/
if(proc->types.pointer.act_obj == NULL) {
pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp));
if(indev_obj_act == NULL) {
indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp));
}
/*If there is last object but it is not dragged and not protected also search*/
else if(proc->types.pointer.drag_in_prog == 0 &&
lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_PRESS_LOST) ==
false) { /*Now types.pointer.act_obj != NULL*/
pr_obj = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(pr_obj == NULL) pr_obj = indev_search_obj(proc, lv_disp_get_scr_act(disp));
lv_obj_is_protected(indev_obj_act, LV_PROTECT_PRESS_LOST) == false) {
indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_sys(disp));
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_layer_top(disp));
if(indev_obj_act == NULL) indev_obj_act = indev_search_obj(proc, lv_disp_get_scr_act(disp));
}
/*If a dragable or a protected object was the last then keep it*/
else {
}
/*If a new object was found reset some variables and send a pressed signal*/
if(pr_obj != proc->types.pointer.act_obj) {
if(indev_obj_act != proc->types.pointer.act_obj) {
proc->types.pointer.last_point.x = proc->types.pointer.act_point.x;
proc->types.pointer.last_point.y = proc->types.pointer.act_point.y;
/*If a new object found the previous was lost, so send a signal*/
if(proc->types.pointer.act_obj != NULL) {
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj,
LV_SIGNAL_PRESS_LOST, indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_PRESS_LOST, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
/*Save the obj because in special cases `act_obj` can change in the signal function*/
lv_obj_t * last_obj = proc->types.pointer.act_obj;
last_obj->signal_cb(last_obj, LV_SIGNAL_PRESS_LOST, indev_act);
if(indev_reset_check(proc)) return;
lv_event_send(last_obj, LV_EVENT_PRESS_LOST, NULL);
if(indev_reset_check(proc)) return;
}
proc->types.pointer.act_obj = pr_obj; /*Save the pressed object*/
proc->types.pointer.last_obj =
proc->types.pointer.act_obj; /*Refresh the types.pointer.last_obj*/
proc->types.pointer.act_obj = indev_obj_act; /*Save the pressed object*/
proc->types.pointer.last_obj = indev_obj_act;
if(proc->types.pointer.act_obj != NULL) {
if(indev_obj_act != NULL) {
/* Save the time when the obj pressed.
* It is necessary to count the long press time.*/
proc->pr_timestamp = lv_tick_get();
@@ -749,27 +751,24 @@ static void indev_proc_press(lv_indev_proc_t * proc)
proc->types.pointer.vect.y = 0;
/*Search for 'top' attribute*/
lv_obj_t * i = proc->types.pointer.act_obj;
lv_obj_t * i = indev_obj_act;
lv_obj_t * last_top = NULL;
while(i != NULL) {
if(i->top != 0) last_top = i;
if(i->top) last_top = i;
i = lv_obj_get_parent(i);
}
if(last_top != NULL) {
/*Move the last_top object to the foreground*/
lv_obj_t * par = lv_obj_get_parent(last_top);
/*After list change it will be the new head*/
lv_ll_chg_list(&par->child_ll, &par->child_ll, last_top);
lv_obj_invalidate(last_top);
lv_obj_move_foreground(last_top);
}
/*Send a signal about the press*/
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_PRESSED,
indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_PRESSED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, indev_act);
if(indev_reset_check(proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL);
if(indev_reset_check(proc)) return;
}
}
@@ -794,24 +793,23 @@ static void indev_proc_press(lv_indev_proc_t * proc)
proc->types.pointer.drag_throw_vect.y += (proc->types.pointer.vect.y * 4) >> 3;
/*If there is active object and it can be dragged run the drag*/
if(proc->types.pointer.act_obj != NULL) {
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_PRESSING,
indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_PRESSING, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
if(indev_obj_act != NULL) {
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSING, indev_act);
if(indev_reset_check(proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_PRESSING, NULL);
if(indev_reset_check(proc)) return;
indev_drag(proc);
if(proc->reset_query != 0) return;
if(indev_reset_check(proc)) return;
/*If there is no drag then check for long press time*/
if(proc->types.pointer.drag_in_prog == 0 && proc->long_pr_sent == 0) {
/*Send a signal about the long press if enough time elapsed*/
if(lv_tick_elaps(proc->pr_timestamp) > indev_act->driver.long_press_time) {
pr_obj->signal_cb(pr_obj, LV_SIGNAL_LONG_PRESS, indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(pr_obj, LV_EVENT_LONG_PRESSED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, indev_act);
if(indev_reset_check(proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL);
if(indev_reset_check(proc)) return;
/*Mark the signal sending to do not send it again*/
proc->long_pr_sent = 1;
@@ -822,12 +820,12 @@ static void indev_proc_press(lv_indev_proc_t * proc)
}
/*Send long press repeated signal*/
if(proc->types.pointer.drag_in_prog == 0 && proc->long_pr_sent == 1) {
/*Send a signal about the long press repeate if enough time elapsed*/
/*Send a signal about the long press repeat if enough time elapsed*/
if(lv_tick_elaps(proc->longpr_rep_timestamp) > indev_act->driver.long_press_rep_time) {
pr_obj->signal_cb(pr_obj, LV_SIGNAL_LONG_PRESS_REP, indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(pr_obj, LV_EVENT_LONG_PRESSED_REPEAT, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS_REP, indev_act);
if(indev_reset_check(proc)) return;
lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, NULL);
if(indev_reset_check(proc)) return;
proc->longpr_rep_timestamp = lv_tick_get();
}
}
@@ -847,76 +845,73 @@ static void indev_proc_release(lv_indev_proc_t * proc)
proc->longpr_rep_timestamp = 0;
proc->wait_until_release = 0;
}
indev_obj_act = proc->types.pointer.act_obj;
/*Forget the act obj and send a released signal */
if(proc->types.pointer.act_obj) {
if(indev_obj_act) {
/* If the object was protected against press lost then it possible that
* the object is already not pressed but still it is the `act_obj`.
* In this case send the `LV_SIGNAL_RELEASED/CLICKED` instead of `LV_SIGNAL_PRESS_LOST` if
* the indev is ON the `types.pointer.act_obj` */
if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_PRESS_LOST)) {
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_RELEASED,
indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
if(lv_obj_is_protected(indev_obj_act, LV_PROTECT_PRESS_LOST)) {
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, indev_act);
if(indev_reset_check(proc)) return;
if(proc->types.pointer.drag_in_prog == 0) {
if(proc->long_pr_sent == 0) {
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_SHORT_CLICKED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
if(indev_reset_check(proc)) return;
}
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_CLICKED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
if(indev_reset_check(proc)) return;
}
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_RELEASED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
if(indev_reset_check(proc)) return;
}
/* The simple case: `act_obj` was not protected against press lost.
* If it is already not pressed then was `indev_proc_press` would set `act_obj = NULL`*/
else {
proc->types.pointer.act_obj->signal_cb(proc->types.pointer.act_obj, LV_SIGNAL_RELEASED,
indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, indev_act);
if(indev_reset_check(proc)) return;
if(proc->long_pr_sent == 0 && proc->types.pointer.drag_in_prog == 0) {
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_SHORT_CLICKED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL);
if(indev_reset_check(proc)) return;
}
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_CLICKED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL);
if(indev_reset_check(proc)) return;
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_RELEASED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL);
if(indev_reset_check(proc)) return;
}
if(proc->reset_query != 0) return;
if(indev_reset_check(proc)) return;
/*Handle click focus*/
/*Handle click focus*/
#if LV_USE_GROUP
/*Edit mode is not used by POINTER devices. So leave edit mode if we are in it*/
lv_group_t * g = lv_obj_get_group(proc->types.pointer.act_obj);
if(lv_group_get_editing(g)) lv_group_set_editing(g, false);
lv_group_t * g = lv_obj_get_group(indev_obj_act);
/*Check, if the parent is in a group focus on it.*/
if(lv_obj_is_protected(proc->types.pointer.act_obj, LV_PROTECT_CLICK_FOCUS) ==
false) { /*Respect the click focus protection*/
lv_obj_t * parent = proc->types.pointer.act_obj;
/*Respect the click focus protection*/
if(lv_obj_is_protected(indev_obj_act, LV_PROTECT_CLICK_FOCUS) == false) {
lv_obj_t * parent = indev_obj_act;
while(g == NULL) {
parent = lv_obj_get_parent(parent);
if(parent == NULL) break;
if(lv_obj_is_protected(
parent,
LV_PROTECT_CLICK_FOCUS)) { /*Ignore is the protected against click focus*/
/*Ignore is the protected against click focus*/
if(lv_obj_is_protected(parent, LV_PROTECT_CLICK_FOCUS)) {
parent = NULL;
break;
}
g = lv_obj_get_group(parent);
}
/* If a pareit is in a group make it focused.
/* If a parent is in a group make it focused.
* `LV_EVENT_FOCUSED/DEFOCUSED` will be sent by `lv_group_focus_obj`*/
if(g && parent) {
if(lv_group_get_click_focus(g)) {
@@ -929,18 +924,17 @@ static void indev_proc_release(lv_indev_proc_t * proc)
/* Send defocus to the lastly "active" object and foucus to the new one.
* If the one of them is in group then it possible that `lv_group_focus_obj` alraedy sent
* a focus/defucus signal because of `click focus`*/
if(proc->types.pointer.last_pressed != proc->types.pointer.act_obj) {
if(proc->types.pointer.last_pressed != indev_obj_act) {
lv_event_send(proc->types.pointer.last_pressed, LV_EVENT_DEFOCUSED, NULL);
if(proc->reset_query)
return; /*Not so strict as it's only the previous object and indev not uses it.*/
if(indev_reset_check(proc)) return;
lv_event_send(proc->types.pointer.act_obj, LV_EVENT_FOCUSED, NULL);
if(proc->reset_query) return; /*The object might be deleted*/
if(indev_reset_check(proc)) return;
proc->types.pointer.last_pressed = proc->types.pointer.act_obj;
proc->types.pointer.last_pressed = indev_obj_act;
}
if(proc->reset_query != 0) return;
if(indev_reset_check(proc)) return;
proc->types.pointer.act_obj = NULL;
proc->pr_timestamp = 0;
proc->longpr_rep_timestamp = 0;
@@ -950,7 +944,7 @@ static void indev_proc_release(lv_indev_proc_t * proc)
* In case of reset query ignore the remaining parts.*/
if(proc->types.pointer.last_obj != NULL && proc->reset_query == 0) {
indev_drag_throw(proc);
if(proc->reset_query != 0) return;
if(indev_reset_check(proc)) return;
}
}
@@ -977,6 +971,7 @@ static void indev_proc_reset_query_handler(lv_indev_t * indev)
indev->proc.types.pointer.drag_throw_vect.x = 0;
indev->proc.types.pointer.drag_throw_vect.y = 0;
indev->proc.reset_query = 0;
indev_obj_act = NULL;
}
}
/**
@@ -1113,7 +1108,9 @@ static void indev_drag(lv_indev_proc_t * state)
/*Send the drag begin signal on first move*/
if(state->types.pointer.drag_in_prog == 0) {
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act);
if(state->reset_query != 0) return;
if(indev_reset_check(state)) return;
lv_event_send(drag_obj, LV_EVENT_DRAG_BEGIN, NULL);
if(indev_reset_check(state)) return;
}
state->types.pointer.drag_in_prog = 1;
@@ -1159,6 +1156,10 @@ static void indev_drag_throw(lv_indev_proc_t * proc)
if(lv_obj_get_drag_throw(drag_obj) == false) {
proc->types.pointer.drag_in_prog = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL);
if(indev_reset_check(proc)) return;
lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL);
return;
}
@@ -1196,7 +1197,9 @@ static void indev_drag_throw(lv_indev_proc_t * proc)
proc->types.pointer.drag_throw_vect.x = 0;
proc->types.pointer.drag_throw_vect.y = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
if(indev_reset_check(proc)) return;
lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL);
if(indev_reset_check(proc)) return;
}
}
/*If the types.pointer.vectors become 0 -> types.pointer.drag_in_prog = 0 and send a drag end
@@ -1204,6 +1207,22 @@ static void indev_drag_throw(lv_indev_proc_t * proc)
else {
proc->types.pointer.drag_in_prog = 0;
drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act);
if(proc->reset_query) return; /*The object might be deleted*/
if(indev_reset_check(proc)) return;
lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL);
if(indev_reset_check(proc)) return;
}
}
/**
* Checks if the reset_query flag has been set. If so, perform necessary global indev cleanup actions
* @param proc pointer to an input device 'proc'
* return true if indev query should be immediately truncated.
*/
static bool indev_reset_check(lv_indev_proc_t *proc)
{
if(proc->reset_query) {
indev_obj_act = NULL;
}
return proc->reset_query ? true : false;
}

View File

@@ -36,9 +36,9 @@ void lv_indev_init(void);
/**
* Called periodically to read the input devices
* @param param pointer to and input device to read
* @param task pointer to the task itself
*/
void lv_indev_read_task(void * param);
void lv_indev_read_task(lv_task_t * task);
/**
* Get the currently processed input device. Can be used in action functions too.
@@ -97,13 +97,6 @@ void lv_indev_set_group(lv_indev_t * indev, lv_group_t * group);
*/
void lv_indev_set_button_points(lv_indev_t * indev, const lv_point_t * points);
/**
* Set feedback callback for indev.
* @param indev pointer to an input device
* @param feedback feedback callback
*/
void lv_indev_set_feedback(lv_indev_t * indev, lv_indev_feedback_t feedback);
/**
* 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
@@ -134,13 +127,6 @@ bool lv_indev_is_dragging(const lv_indev_t * indev);
*/
void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point);
/**
* Get feedback callback for indev.
* @param indev pointer to an input device
* @return feedback callback
*/
lv_indev_feedback_t lv_indev_get_feedback(const lv_indev_t * indev);
/**
* Do nothing until the next release
* @param indev pointer to an input device
@@ -155,6 +141,13 @@ void lv_indev_wait_release(lv_indev_t * indev);
*/
lv_task_t * lv_indev_get_read_task(lv_disp_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 );
/**********************
* MACROS
**********************/

View File

@@ -34,6 +34,12 @@
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_event_temp_data
{
lv_obj_t * obj;
bool deleted;
struct _lv_event_temp_data * prev;
}lv_event_temp_data_t;
/**********************
* STATIC PROTOTYPES
@@ -42,6 +48,7 @@ static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coor
static void report_style_mod_core(void * style_p, lv_obj_t * obj);
static void refresh_children_style(lv_obj_t * obj);
static void delete_children(lv_obj_t * obj);
static void lv_event_mark_deleted(lv_obj_t * obj);
static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param);
@@ -49,9 +56,9 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param);
* STATIC VARIABLES
**********************/
static bool lv_initialized = false;
static lv_obj_t * event_act_obj; /*Stores the which event is currently being executed*/
static bool event_act_obj_deleted; /*Shows that the object was deleted in the event function*/
static const void * event_act_data; /*Stores the data passed to the event*/
static lv_event_temp_data_t * event_temp_data_head;
static const void * event_act_data;
/**********************
* MACROS
**********************/
@@ -75,7 +82,7 @@ void lv_init(void)
/*Initialize the lv_misc modules*/
lv_mem_init();
lv_task_init();
lv_task_core_init();
#if LV_USE_FILESYSTEM
lv_fs_init();
@@ -83,7 +90,7 @@ void lv_init(void)
lv_font_init();
#if LV_USE_ANIMATION
lv_anim_init();
lv_anim_core_init();
#endif
#if LV_USE_GROUP
@@ -102,6 +109,8 @@ void lv_init(void)
/*Init the input device handling*/
lv_indev_init();
lv_img_decoder_init();
lv_initialized = true;
LV_LOG_INFO("lv_init ready");
}
@@ -176,14 +185,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
new_obj->event_cb = NULL;
/*Init. user date*/
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t));
#endif
#if LV_USE_USER_DATA_MULTI
memset(&new_obj->event_user_data, 0, sizeof(lv_obj_user_data_t));
memset(&new_obj->signal_user_data, 0, sizeof(lv_obj_user_data_t));
memset(&new_obj->design_user_data, 0, sizeof(lv_obj_user_data_t));
#endif
#if LV_USE_GROUP
new_obj->group_p = NULL;
@@ -199,6 +203,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
new_obj->opa_scale_en = 0;
new_obj->opa_scale = LV_OPA_COVER;
new_obj->parent_event = 0;
new_obj->reserved = 0;
new_obj->ext_attr = NULL;
@@ -208,7 +213,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
else {
LV_LOG_TRACE("Object create started");
new_obj = lv_ll_ins_head(&(parent)->child_ll);
new_obj = lv_ll_ins_head(&parent->child_ll);
lv_mem_assert(new_obj);
if(new_obj == NULL) return NULL;
@@ -263,14 +268,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
#endif
/*Init. user date*/
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
memset(&new_obj->user_data, 0, sizeof(lv_obj_user_data_t));
#endif
#if LV_USE_USER_DATA_MULTI
memset(&new_obj->event_user_data, 0, sizeof(lv_obj_user_data_t));
memset(&new_obj->signal_user_data, 0, sizeof(lv_obj_user_data_t));
memset(&new_obj->design_user_data, 0, sizeof(lv_obj_user_data_t));
#endif
#if LV_USE_GROUP
new_obj->group_p = NULL;
@@ -307,15 +307,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
#endif
/*Set free data*/
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
memcpy(&new_obj->user_data, &copy->user_data, sizeof(lv_obj_user_data_t));
#endif
#if LV_USE_USER_DATA_MULTI
memcpy(&new_obj->event_user_data, &copy->event_user_data, sizeof(lv_obj_user_data_t));
memcpy(&new_obj->signal_user_data, &copy->signal_user_data, sizeof(lv_obj_user_data_t));
memcpy(&new_obj->design_user_data, &copy->design_user_data, sizeof(lv_obj_user_data_t));
#endif
/*Copy realign*/
#if LV_USE_OBJ_REALIGN
new_obj->realign.align = copy->realign.align;
@@ -352,7 +346,12 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
}
#endif
lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy));
/*Set the same coordinates for non screen objects*/
if(lv_obj_get_parent(copy) != NULL && parent != NULL) {
lv_obj_set_pos(new_obj, lv_obj_get_x(copy), lv_obj_get_y(copy));
} else {
lv_obj_set_pos(new_obj, 0, 0);
}
LV_LOG_INFO("Object create ready");
}
@@ -377,17 +376,10 @@ lv_res_t lv_obj_del(lv_obj_t * obj)
{
lv_obj_invalidate(obj);
if(event_act_obj == obj && event_act_obj_deleted == false) event_act_obj_deleted = true;
/*Delete from the group*/
/*Delete from the group*/
#if LV_USE_GROUP
bool was_focused = false;
lv_group_t * group = lv_obj_get_group(obj);
if(group) {
if(lv_group_get_focused(group) == obj) was_focused = true;
lv_group_remove_obj(obj);
}
if(group) lv_group_remove_obj(obj);
#endif
/*Remove the animations from this object*/
@@ -410,6 +402,11 @@ lv_res_t lv_obj_del(lv_obj_t * obj)
i = i_next;
}
/*Let the user free the resources used in `LV_EVENT_DELETE`*/
lv_event_send(obj, LV_EVENT_DELETE, NULL);
lv_event_mark_deleted(obj);
/*Remove the object from parent's children list*/
lv_obj_t * par = lv_obj_get_parent(obj);
if(par == NULL) { /*It is a screen*/
@@ -419,16 +416,18 @@ lv_res_t lv_obj_del(lv_obj_t * obj)
lv_ll_rem(&(par->child_ll), obj);
}
/* Reset all input devices if
* the object to delete is used*/
/* Reset all input devices if the object to delete is used*/
lv_indev_t * indev = lv_indev_get_next(NULL);
while(indev) {
if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) {
lv_indev_reset(indev);
}
if(indev->proc.types.pointer.last_pressed == obj) {
indev->proc.types.pointer.last_pressed = NULL;
}
#if LV_USE_GROUP
if(indev->group == group && was_focused) {
if(indev->group == group && obj == lv_indev_get_obj_act() ) {
lv_indev_reset(indev);
}
#endif
@@ -540,7 +539,7 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)
lv_obj_t * old_par = obj->par;
lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj);
lv_ll_chg_list(&obj->par->child_ll, &parent->child_ll, obj, true);
obj->par = parent;
lv_obj_set_pos(obj, old_pos.x, old_pos.y);
@@ -553,6 +552,48 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent)
lv_obj_invalidate(obj);
}
/**
* Move and object to the foreground
* @param obj pointer to an object
*/
void lv_obj_move_foreground(lv_obj_t * obj)
{
lv_obj_t * parent = lv_obj_get_parent(obj);
/*Do nothing of already in the foreground*/
if(lv_ll_get_head(&parent->child_ll) == obj) return;
lv_obj_invalidate(parent);
lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, true);
/*Notify the new parent about the child*/
parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
lv_obj_invalidate(parent);
}
/**
* Move and object to the background
* @param obj pointer to an object
*/
void lv_obj_move_background(lv_obj_t * obj)
{
lv_obj_t * parent = lv_obj_get_parent(obj);
/*Do nothing of already in the background*/
if(lv_ll_get_tail(&parent->child_ll) == obj) return;
lv_obj_invalidate(parent);
lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, false);
/*Notify the new parent about the child*/
parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj);
lv_obj_invalidate(parent);
}
/*--------------------
* Coordinate set
* ------------------*/
@@ -1040,9 +1081,10 @@ void lv_obj_set_ext_click_area(lv_obj_t * obj, uint8_t w, uint8_t h)
}
#endif
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
/**
* Set the size of an extended clickable area
* If TINY mode is used, only the largest of the horizontal and vertical padding
* values are considered.
* @param obj pointer to an object
* @param left extended clickable are on the left [px]
* @param right extended clickable are on the right [px]
@@ -1051,12 +1093,16 @@ void lv_obj_set_ext_click_area(lv_obj_t * obj, uint8_t w, uint8_t h)
*/
void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t left, lv_coord_t right, lv_coord_t top, lv_coord_t bottom)
{
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
obj->ext_click_pad.x1 = left;
obj->ext_click_pad.x2 = right;
obj->ext_click_pad.y1 = top;
obj->ext_click_pad.y2 = bottom;
}
#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
obj->ext_click_pad_hor = LV_MATH_MAX(left, right);
obj->ext_click_pad_ver = LV_MATH_MAX(top, bottom);
#endif
}
/*---------------------
* Appearance set
@@ -1256,11 +1302,11 @@ void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot)
* Set a an event handler function for an object.
* Used by the user to react on event which happens with the object.
* @param obj pointer to an object
* @param cb the new event function
* @param event_cb the new event function
*/
void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t cb)
void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb)
{
obj->event_cb = cb;
obj->event_cb = event_cb;
}
/**
@@ -1274,31 +1320,55 @@ lv_res_t lv_event_send(lv_obj_t * obj, lv_event_t event, const void * data)
{
if(obj == NULL) return LV_RES_OK;
/*If the event was send from an other event save the current states to restore it at the end*/
lv_obj_t * prev_obj_act = event_act_obj;
bool prev_obj_act_deleted = event_act_obj_deleted;
const void * prev_data = event_act_data;
lv_res_t res;
res = lv_event_send_func(obj->event_cb, obj, event, data);
return res;
}
event_act_obj = obj;
event_act_obj_deleted = false;
event_act_data = data;
/**
* Call an event function with an object, event, and data.
* @param event_cb an event callback function. If `NULL` `LV_RES_OK` will return without any actions.
* @param obj pointer to an object to associate with the event (can be `NULL` to simply call the `event_cb`)
* @param event an event
* @param data pointer to a custom data
* @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
*/
lv_res_t lv_event_send_func(lv_event_cb_t event_cb, lv_obj_t * obj, lv_event_t event, const void * data)
{
lv_event_temp_data_t event_temp_data;
event_temp_data.obj = obj;
event_temp_data.deleted = false;
event_temp_data.prev = NULL;
if(obj->event_cb) obj->event_cb(obj, event);
if(event_temp_data_head == NULL) {
event_temp_data_head = &event_temp_data;
} else {
event_temp_data.prev = event_temp_data_head;
event_temp_data_head = &event_temp_data;
}
bool deleted = event_act_obj_deleted;
event_temp_data_head = &event_temp_data;
/*Restore the previous states*/
event_act_obj = prev_obj_act;
event_act_obj_deleted = prev_obj_act_deleted;
event_act_data = prev_data;
event_act_data = data;
if(deleted) {
if(event_cb) event_cb(obj, event);
/*Remove this element from the list*/
event_temp_data_head = event_temp_data_head->prev;
if(event_temp_data.deleted) {
event_act_data = NULL;
return LV_RES_INV;
}
if(obj->parent_event && obj->par) {
lv_res_t res = lv_event_send(obj->par, event, data);
if(res != LV_RES_OK) return LV_RES_INV;
if(obj) {
if(obj->parent_event && obj->par) {
lv_res_t res = lv_event_send(obj->par, event, data);
if(res != LV_RES_OK) {
event_act_data = NULL;
return LV_RES_INV;
}
}
}
return LV_RES_OK;
@@ -1319,9 +1389,9 @@ const void * lv_event_get_data(void)
* @param obj pointer to an object
* @param cb the new signal function
*/
void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t cb)
void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t signal_cb)
{
obj->signal_cb = cb;
obj->signal_cb = signal_cb;
}
/**
@@ -1337,11 +1407,11 @@ void lv_signal_send(lv_obj_t * obj, lv_signal_t signal, void * param)
/**
* Set a new design function for an object
* @param obj pointer to an object
* @param cb the new design function
* @param design_cb the new design function
*/
void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t cb)
void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t design_cb)
{
obj->design_cb = cb;
obj->design_cb = design_cb;
}
/*----------------
@@ -1373,87 +1443,6 @@ void lv_obj_refresh_ext_draw_pad(lv_obj_t * obj)
lv_obj_invalidate(obj);
}
#if LV_USE_ANIMATION
/**
* Animate an object
* @param obj pointer to an object to animate
* @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT
* @param time time of animation in milliseconds
* @param delay delay before the animation in milliseconds
* @param cb a function to call when the animation is ready
*/
void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay,
void (*cb)(lv_obj_t *))
{
lv_obj_t * par = lv_obj_get_parent(obj);
/*Get the direction*/
bool out = (type & LV_ANIM_DIR_MASK) == LV_ANIM_IN ? false : true;
type = type & (~LV_ANIM_DIR_MASK);
lv_anim_t a;
a.var = obj;
a.time = time;
a.act_time = (int32_t)-delay;
a.end_cb = (void (*)(void *))cb;
a.path = lv_anim_path_linear;
a.playback_pause = 0;
a.repeat_pause = 0;
a.playback = 0;
a.repeat = 0;
/*Init to ANIM_IN*/
switch(type) {
case LV_ANIM_FLOAT_LEFT:
a.fp = (void (*)(void *, int32_t))lv_obj_set_x;
a.start = -lv_obj_get_width(obj);
a.end = lv_obj_get_x(obj);
break;
case LV_ANIM_FLOAT_RIGHT:
a.fp = (void (*)(void *, int32_t))lv_obj_set_x;
a.start = lv_obj_get_width(par);
a.end = lv_obj_get_x(obj);
break;
case LV_ANIM_FLOAT_TOP:
a.fp = (void (*)(void *, int32_t))lv_obj_set_y;
a.start = -lv_obj_get_height(obj);
a.end = lv_obj_get_y(obj);
break;
case LV_ANIM_FLOAT_BOTTOM:
a.fp = (void (*)(void *, int32_t))lv_obj_set_y;
a.start = lv_obj_get_height(par);
a.end = lv_obj_get_y(obj);
break;
case LV_ANIM_GROW_H:
a.fp = (void (*)(void *, int32_t))lv_obj_set_width;
a.start = 0;
a.end = lv_obj_get_width(obj);
break;
case LV_ANIM_GROW_V:
a.fp = (void (*)(void *, int32_t))lv_obj_set_height;
a.start = 0;
a.end = lv_obj_get_height(obj);
break;
case LV_ANIM_NONE:
a.fp = NULL;
a.start = 0;
a.end = 0;
break;
default: break;
}
/*Swap start and end in case of ANIM OUT*/
if(out != false) {
int32_t tmp = a.start;
a.start = a.end;
a.end = tmp;
}
lv_anim_create(&a);
}
#endif
/*=======================
* Getter functions
*======================*/
@@ -1573,6 +1562,22 @@ uint16_t lv_obj_count_children(const lv_obj_t * obj)
return cnt;
}
/** Recursively count the children of an object
* @param obj pointer to an object
* @return children number of 'obj'
*/
uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj){
lv_obj_t * i;
uint16_t cnt = 0;
LV_LL_READ(obj->child_ll, i) {
cnt++; // Count the child
cnt += lv_obj_count_children_recursive(i); // recursively count children's children
}
return cnt;
}
/*---------------------
* Coordinate get
*--------------------*/
@@ -1674,39 +1679,69 @@ bool lv_obj_get_auto_realign(lv_obj_t * obj)
#endif
}
/**
* Get the left padding of extended clickable area
* @param obj pointer to an object
* @return the extended left padding
*/
lv_coord_t lv_obj_get_ext_click_pad_left(const lv_obj_t * obj)
{
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
/**
* Get the horizontal padding of extended clickable area
* @param obj pointer to an object
* @return the horizontal padding
*/
uint8_t lv_obj_get_ext_click_pad_hor(const lv_obj_t * obj)
{
return obj->ext_click_pad_hor;
#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
return obj->ext_click_pad.x1;
#else
return 0;
#endif
}
/**
* Get the vertical padding of extended clickable area
* Get the right padding of extended clickable area
* @param obj pointer to an object
* @return the vertical padding
* @return the extended right padding
*/
uint8_t lv_obj_get_ext_click_pad_ver(const lv_obj_t * obj)
lv_coord_t lv_obj_get_ext_click_pad_right(const lv_obj_t * obj)
{
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
return obj->ext_click_pad_hor;
#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
return obj->ext_click_pad.x2;
#else
return 0;
#endif
}
/**
* Get the top padding of extended clickable area
* @param obj pointer to an object
* @return the extended top padding
*/
lv_coord_t lv_obj_get_ext_click_pad_top(const lv_obj_t * obj)
{
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
return obj->ext_click_pad_ver;
}
#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
return obj->ext_click_pad.y1;
#else
return 0;
#endif
}
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
/**
* Get the horizontal padding of extended clickable area
* Get the bottom padding of extended clickable area
* @param obj pointer to an object
* @return the horizontal padding
* @return the extended bottom padding
*/
const lv_area_t * lv_obj_get_ext_click_pad(const lv_obj_t * obj)
lv_coord_t lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj)
{
return &obj->ext_click_pad;
}
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
return obj->ext_click_pad_ver
#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
return obj->ext_click_pad.y2;
#else
return 0;
#endif
}
/**
* Get the extended size attribute of an object
@@ -1970,16 +2005,37 @@ void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf)
}
}
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
/**
* Get the object's user data
* @param obj pointer to an object
* @return user data
*/
lv_obj_user_data_t lv_obj_get_user_data(lv_obj_t * obj)
{
return obj->user_data;
}
/**
* Get a pointer to the object's user data
* @param obj pointer to an object
* @return pointer to the user data
*/
lv_obj_user_data_t * lv_obj_get_user_data(lv_obj_t * obj)
lv_obj_user_data_t *lv_obj_get_user_data_ptr(lv_obj_t * obj)
{
return &obj->user_data;
}
/**
* Set the object's user data. The data will be copied.
* @param obj pointer to an object
* @param data user data
*/
void lv_obj_set_user_data(lv_obj_t * obj, lv_obj_user_data_t data)
{
memcpy(&obj->user_data, &data, sizeof(lv_obj_user_data_t));
}
#endif
#if LV_USE_GROUP
@@ -1994,7 +2050,7 @@ void * lv_obj_get_group(const lv_obj_t * obj)
}
/**
* Tell whether the ohe object is the focused object of a group or not.
* Tell whether the object is the focused object of a group or not.
* @param obj pointer to an object
* @return true: the object is focused, false: the object is not focused or not in a group
*/
@@ -2025,12 +2081,12 @@ static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mo
{
if(mode == LV_DESIGN_COVER_CHK) {
/*Most trivial test. The mask is fully IN the object? If no it surely not covers it*/
/*Most trivial test. Is the mask fully IN the object? If no it surely doesn't cover it*/
if(lv_area_is_in(mask_p, &obj->coords) == false) return false;
/*Can cover the area only if fully solid (no opacity)*/
const lv_style_t * style = lv_obj_get_style(obj);
if(style->body.opa != LV_OPA_COVER) return false;
if(style->body.opa < LV_OPA_MAX) return false;
/* Because of the radius it is not sure the area is covered
* Check the areas where there is no radius*/
@@ -2078,7 +2134,9 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param)
lv_indev_t * indev_act = lv_indev_get_act();
if(sign > _LV_SIGNAL_FEEDBACK_SECTION_START && sign < _LV_SIGNAL_FEEDBACK_SECTION_END) {
if(indev_act != NULL && indev_act->feedback != NULL) indev_act->feedback(indev_act, sign);
if(indev_act != NULL) {
if(indev_act->driver.feedback_cb) indev_act->driver.feedback_cb(&indev_act->driver, sign);
}
}
if(sign == LV_SIGNAL_CHILD_CHG) {
@@ -2161,9 +2219,6 @@ static void refresh_children_style(lv_obj_t * obj)
*/
static void delete_children(lv_obj_t * obj)
{
if(event_act_obj == obj && event_act_obj_deleted == false) event_act_obj_deleted = true;
lv_obj_t * i;
lv_obj_t * i_next;
i = lv_ll_get_head(&(obj->child_ll));
@@ -2172,15 +2227,11 @@ static void delete_children(lv_obj_t * obj)
* the object still has access to all children during the
* LV_SIGNAL_DEFOCUS call*/
#if LV_USE_GROUP
bool was_focused = false;
lv_group_t * group = lv_obj_get_group(obj);
if(group) {
if(lv_group_get_focused(obj->group_p) == obj) was_focused = true;
lv_group_remove_obj(obj);
}
if(group) lv_group_remove_obj(obj);
#endif
while(i != NULL) {
/*Get the next object before delete this*/
i_next = lv_ll_get_next(&(obj->child_ll), i);
@@ -2192,6 +2243,11 @@ static void delete_children(lv_obj_t * obj)
i = i_next;
}
/*Let the suer free the resources used in `LV_EVENT_DELETE`*/
lv_event_send(obj, LV_EVENT_DELETE, NULL);
lv_event_mark_deleted(obj);
/*Remove the animations from this object*/
#if LV_USE_ANIMATION
lv_anim_del(obj, NULL);
@@ -2204,8 +2260,12 @@ static void delete_children(lv_obj_t * obj)
if(indev->proc.types.pointer.act_obj == obj || indev->proc.types.pointer.last_obj == obj) {
lv_indev_reset(indev);
}
if(indev->proc.types.pointer.last_pressed == obj) {
indev->proc.types.pointer.last_pressed = NULL;
}
#if LV_USE_GROUP
if(indev->group == group && was_focused) {
if(indev->group == group && obj == lv_indev_get_obj_act() ) {
lv_indev_reset(indev);
}
#endif
@@ -2223,3 +2283,13 @@ static void delete_children(lv_obj_t * obj)
if(obj->ext_attr != NULL) lv_mem_free(obj->ext_attr);
lv_mem_free(obj); /*Free the object itself*/
}
static void lv_event_mark_deleted(lv_obj_t * obj)
{
lv_event_temp_data_t * t = event_temp_data_head;
while(t) {
if(t->obj == obj) t->deleted = true;
t = t->prev;
}
}

View File

@@ -22,6 +22,7 @@ extern "C" {
#include <stddef.h>
#include <stdbool.h>
#include "lv_style.h"
#include "../lv_misc/lv_types.h"
#include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_ll.h"
@@ -44,10 +45,6 @@ extern "C" {
#define LV_MAX_ANCESTOR_NUM 8
#define LV_ANIM_IN 0x00 /*Animation to show an object. 'OR' it with lv_anim_builtin_t*/
#define LV_ANIM_OUT 0x80 /*Animation to hide an object. 'OR' it with lv_anim_builtin_t*/
#define LV_ANIM_DIR_MASK 0x80 /*ANIM_IN/ANIM_OUT mask*/
#define LV_EXT_CLICK_AREA_OFF 0
#define LV_EXT_CLICK_AREA_TINY 1
#define LV_EXT_CLICK_AREA_FULL 2
@@ -68,13 +65,6 @@ typedef uint8_t lv_design_mode_t;
typedef bool (*lv_design_cb_t)(struct _lv_obj_t * obj, const lv_area_t * mask_p,
lv_design_mode_t mode);
enum {
LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action
function or an operation was failed*/
LV_RES_OK, /*The object is valid (no deleted) after the action*/
};
typedef uint8_t lv_res_t;
enum {
LV_EVENT_PRESSED, /*The object has been pressed*/
LV_EVENT_PRESSING, /*The object is being pressed (called continuously while pressing)*/
@@ -85,11 +75,10 @@ enum {
`LV_INDEV_LONG_PRESS_REP_TIME` ms. Not called if dragged.*/
LV_EVENT_CLICKED, /*Called on release if not dragged (regardless to long press)*/
LV_EVENT_RELEASED, /*Called in every cases when the object has been released*/
LV_EVENT_LONG_HOVER_IN, /*TODO*/
LV_EVENT_LONG_HOVER_OUT, /*TODO*/
LV_EVENT_DRAG_BEGIN,
LV_EVENT_DRAG_END,
LV_EVENT_DRAG_THROW_BEGIN,
LV_EVENT_KEY,
LV_EVENT_FOCUSED,
LV_EVENT_DEFOCUSED,
LV_EVENT_VALUE_CHANGED,
@@ -98,6 +87,7 @@ enum {
LV_EVENT_REFRESH,
LV_EVENT_APPLY, /*"Ok", "Apply" or similar specific button has clicked*/
LV_EVENT_CANCEL, /*"Close", "Cancel" or similar specific button has clicked*/
LV_EVENT_DELETE,
};
typedef uint8_t lv_event_t;
@@ -209,34 +199,30 @@ typedef struct _lv_obj_t
#endif
/*Attributes and states*/
uint8_t click : 1; /*1: Can be pressed by an input device*/
uint8_t drag : 1; /*1: Enable the dragging*/
uint8_t click :1; /*1: Can be pressed by an input device*/
uint8_t drag :1; /*1: Enable the dragging*/
uint8_t drag_throw :1; /*1: Enable throwing with drag*/
uint8_t drag_parent :1; /*1: Parent will be dragged instead*/
uint8_t hidden :1; /*1: Object is hidden*/
uint8_t top :1; /*1: If the object or its children is clicked it goes to the foreground*/
uint8_t opa_scale_en :1; /*1: opa_scale is set*/
uint8_t parent_event :1; /*1: Send the object's events to the parent too. */
lv_drag_dir_t drag_dir : 2; /* Which directions the object can be dragged in */
uint8_t drag_throw : 1; /*1: Enable throwing with drag*/
uint8_t drag_parent : 1; /*1: Parent will be dragged instead*/
uint8_t hidden : 1; /*1: Object is hidden*/
uint8_t top : 1; /*1: If the object or its children is clicked it goes to the foreground*/
uint8_t opa_scale_en : 1; /*1: opa_scale is set*/
uint8_t parent_event : 1; /*1: Send the object's events to the parent too. */
uint8_t reserved :6; /*Reserved for future use*/
uint8_t protect; /*Automatically happening actions can be prevented. 'OR'ed values from
`lv_protect_t`*/
lv_opa_t opa_scale; /*Scale down the opacity by this factor. Effects all children as well*/
lv_coord_t ext_draw_pad; /*EXTtend the size in every direction for drawing. */
#if LV_USE_OBJ_REALIGN
lv_reailgn_t realign;
#endif
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
lv_obj_user_data_t user_data;
#endif
#if LV_USE_USER_DATA_MULTI
lv_obj_user_data_t event_user_data;
lv_obj_user_data_t signal_user_data;
lv_obj_user_data_t design_user_data;
#endif
} lv_obj_t;
/*Protect some attributes (max. 8 bit)*/
@@ -260,17 +246,6 @@ typedef struct
... [x]: "lv_obj" */
} lv_obj_type_t;
enum {
LV_ANIM_NONE = 0,
LV_ANIM_FLOAT_TOP, /*Float from/to the top*/
LV_ANIM_FLOAT_LEFT, /*Float from/to the left*/
LV_ANIM_FLOAT_BOTTOM, /*Float from/to the bottom*/
LV_ANIM_FLOAT_RIGHT, /*Float from/to the right*/
LV_ANIM_GROW_H, /*Grow/shrink horizontally*/
LV_ANIM_GROW_V, /*Grow/shrink vertically*/
};
typedef uint8_t lv_anim_builtin_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
@@ -327,6 +302,18 @@ void lv_obj_invalidate(const lv_obj_t * obj);
*/
void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent);
/**
* Move and object to the foreground
* @param obj pointer to an object
*/
void lv_obj_move_foreground(lv_obj_t * obj);
/**
* Move and object to the background
* @param obj pointer to an object
*/
void lv_obj_move_background(lv_obj_t * obj);
/*--------------------
* Coordinate set
* ------------------*/
@@ -411,17 +398,6 @@ void lv_obj_realign(lv_obj_t * obj);
*/
void lv_obj_set_auto_realign(lv_obj_t * obj, bool en);
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
/**
* Set the size of an extended clickable area
* @param obj pointer to an object
* @param w extended width to both sides
* @param h extended height to both sides
*/
void lv_obj_set_ext_click_area(lv_obj_t * obj, uint8_t w, uint8_t h);
#endif
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
/**
* Set the size of an extended clickable area
* @param obj pointer to an object
@@ -431,7 +407,6 @@ void lv_obj_set_ext_click_area(lv_obj_t * obj, uint8_t w, uint8_t h);
* @param bottom extended clickable are on the bottom [px]
*/
void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t left, lv_coord_t right, lv_coord_t top, lv_coord_t bottom);
#endif
/*---------------------
* Appearance set
@@ -551,9 +526,9 @@ void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot);
* Set a an event handler function for an object.
* Used by the user to react on event which happens with the object.
* @param obj pointer to an object
* @param cb the new event function
* @param event_cb the new event function
*/
void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t cb);
void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb);
/**
* Send an event to the object
@@ -564,6 +539,16 @@ void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t cb);
*/
lv_res_t lv_event_send(lv_obj_t * obj, lv_event_t event, const void * data);
/**
* Call an event function with an object, event, and data.
* @param event_cb an event callback function
* @param obj pointer to an object to associate with the event (can be `NULL` to simply call the `event_cb`)
* @param event an event
* @param data pointer to a custom data
* @return LV_RES_OK: `obj` was not deleted in the event; LV_RES_INV: `obj` was deleted in the event
*/
lv_res_t lv_event_send_func(lv_event_cb_t event_cb, lv_obj_t * obj, lv_event_t event, const void * data);
/**
* Get the `data` parameter of the current event
* @return the `data` parameter
@@ -574,9 +559,9 @@ const void * lv_event_get_data(void);
* Set the a signal function of an object. Used internally by the library.
* Always call the previous signal function in the new.
* @param obj pointer to an object
* @param cb the new signal function
* @param signal_cb the new signal function
*/
void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t cb);
void lv_obj_set_signal_cb(lv_obj_t * obj, lv_signal_cb_t signal_cb);
/**
* Send an event to the object
@@ -588,9 +573,9 @@ void lv_signal_send(lv_obj_t * obj, lv_signal_t signal, void * param);
/**
* Set a new design function for an object
* @param obj pointer to an object
* @param cb the new design function
* @param design_cb the new design function
*/
void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t cb);
void lv_obj_set_design_cb(lv_obj_t * obj, lv_design_cb_t design_cb);
/*----------------
* Other set
@@ -610,19 +595,6 @@ void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size);
*/
void lv_obj_refresh_ext_draw_pad(lv_obj_t * obj);
#if LV_USE_ANIMATION
/**
* Animate an object
* @param obj pointer to an object to animate
* @param type type of animation from 'lv_anim_builtin_t'. 'OR' it with ANIM_IN or ANIM_OUT
* @param time time of animation in milliseconds
* @param delay delay before the animation in milliseconds
* @param cb a function to call when the animation is ready
*/
void lv_obj_animate(lv_obj_t * obj, lv_anim_builtin_t type, uint16_t time, uint16_t delay,
void (*cb)(lv_obj_t *));
#endif
/*=======================
* Getter functions
*======================*/
@@ -677,6 +649,12 @@ lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child);
*/
uint16_t lv_obj_count_children(const lv_obj_t * obj);
/** Recursively count the children of an object
* @param obj pointer to an object
* @return children number of 'obj'
*/
uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj);
/*---------------------
* Coordinate get
*--------------------*/
@@ -737,32 +715,33 @@ lv_coord_t lv_obj_get_height_fit(lv_obj_t * obj);
*/
bool lv_obj_get_auto_realign(lv_obj_t * obj);
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY
/**
* Get the horizontal padding of extended clickable area
* Get the left padding of extended clickable area
* @param obj pointer to an object
* @return the horizontal padding
* @return the extended left padding
*/
uint8_t lv_obj_get_ext_click_pad_hor(const lv_obj_t * obj);
lv_coord_t lv_obj_get_ext_click_pad_left(const lv_obj_t * obj);
/**
* Get the vertical padding of extended clickable area
* Get the right padding of extended clickable area
* @param obj pointer to an object
* @return the vertical padding
* @return the extended right padding
*/
uint8_t lv_obj_get_ext_click_pad_ver(const lv_obj_t * obj);
lv_coord_t lv_obj_get_ext_click_pad_right(const lv_obj_t * obj);
#endif
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
/**
* Get the horizontal padding of extended clickable area
* Get the top padding of extended clickable area
* @param obj pointer to an object
* @return the horizontal padding
* @return the extended top padding
*/
const lv_area_t * lv_obj_get_ext_click_pad(const lv_obj_t * obj);
#endif
lv_coord_t lv_obj_get_ext_click_pad_top(const lv_obj_t * obj);
/**
* Get the bottom padding of extended clickable area
* @param obj pointer to an object
* @return the extended bottom padding
*/
lv_coord_t lv_obj_get_ext_click_pad_bottom(const lv_obj_t * obj);
/**
* Get the extended size attribute of an object
@@ -912,13 +891,28 @@ void * lv_obj_get_ext_attr(const lv_obj_t * obj);
*/
void lv_obj_get_type(lv_obj_t * obj, lv_obj_type_t * buf);
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
/**
* Get the object's user data
* @param obj pointer to an object
* @return user data
*/
lv_obj_user_data_t lv_obj_get_user_data(lv_obj_t * obj);
/**
* Get a pointer to the object's user data
* @param obj pointer to an object
* @return pointer to the user data
*/
lv_obj_user_data_t * lv_obj_get_user_data(lv_obj_t * obj);
lv_obj_user_data_t *lv_obj_get_user_data_ptr(lv_obj_t * obj);
/**
* Set the object's user data. The data will be copied.
* @param obj pointer to an object
* @param data user data
*/
void lv_obj_set_user_data(lv_obj_t * obj, lv_obj_user_data_t data);
#endif
#if LV_USE_GROUP
@@ -942,6 +936,22 @@ bool lv_obj_is_focused(const lv_obj_t * obj);
* MACROS
**********************/
/**
* Helps to quickly declare an event callback function.
* Will be expanded to: `void <name> (lv_obj_t * obj, lv_event_t e)`
*
* Examples:
* static LV_EVENT_CB_DECLARE(my_event1); //Protoype declaration
*
* static LV_EVENT_CB_DECLARE(my_event1)
* {
* if(e == LV_EVENT_CLICKED) {
* lv_obj_set_hidden(obj ,true);
* }
* }
*/
#define LV_EVENT_CB_DECLARE(name) void name(lv_obj_t * obj, lv_event_t e)
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -14,6 +14,7 @@
#include "../lv_misc/lv_task.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_gc.h"
#include "../lv_draw/lv_draw_basic.h"
#if defined(LV_GC_INCLUDE)
#include LV_GC_INCLUDE
@@ -22,6 +23,8 @@
/*********************
* DEFINES
*********************/
/* Draw translucent random colored areas on the invalidated (redrawn) areas*/
#define MASK_AREA_DEBUG 0
/**********************
* TYPEDEFS
@@ -69,7 +72,12 @@ void lv_refr_init(void)
*/
void lv_refr_now(void)
{
lv_disp_refr_task(NULL);
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);
}
}
/**
@@ -132,15 +140,15 @@ lv_disp_t * lv_refr_get_disp_refreshing(void)
/**
* Called periodically to handle the refreshing
* @param param point to a `lv_disp_t` to refresh
* @param task pointer to the task itself
*/
void lv_disp_refr_task(void * param)
void lv_disp_refr_task(lv_task_t * task)
{
LV_LOG_TRACE("lv_refr_task: started");
uint32_t start = lv_tick_get();
disp_refr = param;
disp_refr = task->user_data;
lv_refr_join_area();
@@ -359,8 +367,7 @@ static void lv_refr_area_part(const lv_area_t * area_p)
/*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)
;
while(vdb->flushing);
}
lv_obj_t * top_p;
@@ -457,6 +464,9 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
i = lv_ll_get_prev(&(par->child_ll), i);
}
/*Call the post draw design function of the parents of the to object*/
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;
@@ -464,12 +474,6 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
par = lv_obj_get_parent(par);
}
/*Call the post draw design function of the parents of the to object*/
par = lv_obj_get_parent(top_p);
while(par != NULL) {
par->design_cb(par, mask_p, LV_DESIGN_DRAW_POST);
par = lv_obj_get_parent(par);
}
}
/**
@@ -501,8 +505,13 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
/* Redraw the object */
obj->design_cb(obj, &obj_ext_mask, LV_DESIGN_DRAW_MAIN);
// usleep(5 * 1000); /*DEBUG: Wait after every object draw to see the order of drawing*/
#if MASK_AREA_DEBUG
static lv_color_t debug_color = LV_COLOR_RED;
lv_draw_fill(&obj_ext_mask, &obj_ext_mask, debug_color, LV_OPA_50);
debug_color.full *= 17;
debug_color.full += 0xA1;
#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);

View File

@@ -69,9 +69,9 @@ lv_disp_t * lv_refr_get_disp_refreshing(void);
/**
* Called periodically to handle the refreshing
* @param param point to a `lv_disp_t` to refresh
* @param task pointer to the task itself
*/
void lv_disp_refr_task(void * param);
void lv_disp_refr_task(lv_task_t * task);
/**********************
* STATIC FUNCTIONS

View File

@@ -8,6 +8,7 @@
*********************/
#include "lv_obj.h"
#include "../lv_misc/lv_mem.h"
#include "../lv_misc/lv_anim.h"
/*********************
* DEFINES
@@ -26,23 +27,13 @@
/**********************
* TYPEDEFS
**********************/
#if LV_USE_ANIMATION
typedef struct
{
lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it
will be modified too*/
lv_style_t style_end;
lv_style_t * style_anim;
void (*end_cb)(void *);
} lv_style_anim_dsc_t;
#endif
/**********************
* STATIC PROTOTYPES
**********************/
#if LV_USE_ANIMATION
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val);
static void style_animation_common_end_cb(void * ptr);
static void style_animator(lv_style_anim_dsc_t * dsc, lv_anim_value_t val);
static void style_animation_common_end_cb(lv_anim_t * a);
#endif
/**********************
@@ -286,44 +277,38 @@ void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t *
#if LV_USE_ANIMATION
/**
* Create an animation from a pre-configured 'lv_style_anim_t' variable
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in
* `lv_anim_del(dsc, NULL)`)
*/
void * lv_style_anim_create(lv_style_anim_t * anim)
void lv_style_anim_init(lv_anim_t * a)
{
lv_style_anim_dsc_t * dsc;
dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));
lv_mem_assert(dsc);
if(dsc == NULL) return NULL;
lv_anim_init(a);
a->start = 0;
a->end = STYLE_MIX_MAX;
a->exec_cb = (lv_anim_exec_cb_t)style_animator;
a->path_cb = lv_anim_path_linear;
a->ready_cb = style_animation_common_end_cb;
dsc->style_anim = anim->style_anim;
memcpy(&dsc->style_start, anim->style_start, sizeof(lv_style_t));
memcpy(&dsc->style_end, anim->style_end, sizeof(lv_style_t));
memcpy(dsc->style_anim, anim->style_start, sizeof(lv_style_t));
dsc->end_cb = anim->end_cb;
lv_style_anim_dsc_t * dsc;
dsc = lv_mem_alloc(sizeof(lv_style_anim_dsc_t));
lv_mem_assert(dsc);
if(dsc == NULL) return;
dsc->ready_cb = NULL;
dsc->style_anim = NULL;
lv_style_copy(&dsc->style_start, &lv_style_plain);
lv_style_copy(&dsc->style_end, &lv_style_plain);
lv_anim_t a;
a.var = (void *)dsc;
a.start = 0;
a.end = STYLE_MIX_MAX;
a.fp = (lv_anim_fp_t)style_animator;
a.path = lv_anim_path_linear;
a.end_cb = style_animation_common_end_cb;
a.act_time = anim->act_time;
a.time = anim->time;
a.playback = anim->playback;
a.playback_pause = anim->playback_pause;
a.repeat = anim->repeat;
a.repeat_pause = anim->repeat_pause;
a->var = (void *)dsc;
lv_anim_create(&a);
return dsc;
}
void lv_style_anim_set_styles(lv_anim_t * a, lv_style_t * to_anim, const lv_style_t * start, const lv_style_t * end)
{
lv_style_anim_dsc_t * dsc = a->var;
dsc->style_anim = to_anim;
memcpy(&dsc->style_start, start, sizeof(lv_style_t));
memcpy(&dsc->style_end, end, sizeof(lv_style_t));
memcpy(dsc->style_anim, start, sizeof(lv_style_t));
}
#endif
/**********************
* STATIC FUNCTIONS
@@ -332,9 +317,9 @@ void * lv_style_anim_create(lv_style_anim_t * anim)
/**
* Used by the style animations to set the values of a style according to start and end style.
* @param dsc the 'animated variable' set by lv_style_anim_create()
* @param val the current state of the animation between 0 and LV_STYLE_ANIM_RES
* @param val the current state of the animation between 0 and LV_ANIM_RESOLUTION
*/
static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
static void style_animator(lv_style_anim_dsc_t * dsc, lv_anim_value_t val)
{
const lv_style_t * start = &dsc->style_start;
const lv_style_t * end = &dsc->style_end;
@@ -348,13 +333,15 @@ static void style_animator(lv_style_anim_dsc_t * dsc, int32_t val)
/**
* Called when a style animation is ready
* It called the user defined call back and free the allocated memories
* @param ptr the 'animated variable' set by lv_style_anim_create()
* @param a pointer to the animation
*/
static void style_animation_common_end_cb(void * ptr)
static void style_animation_common_end_cb(lv_anim_t * a)
{
lv_style_anim_dsc_t * dsc = ptr; /*To avoid casting*/
if(dsc->end_cb) dsc->end_cb(dsc);
(void) a; /*Unused*/
lv_style_anim_dsc_t * dsc = a->var; /*To avoid casting*/
if(dsc->ready_cb) dsc->ready_cb(a);
lv_mem_free(dsc);
}

View File

@@ -112,32 +112,12 @@ typedef struct
#if LV_USE_ANIMATION
typedef struct
{
const lv_style_t * style_start; /*Pointer to the starting style*/
const lv_style_t * style_end; /*Pointer to the destination style*/
lv_style_t * style_anim; /*Pointer to a style to animate*/
lv_anim_cb_t end_cb; /*Call it when the animation is ready (NULL if unused)*/
int16_t time; /*Animation time in ms*/
int16_t act_time; /*Current time in animation. Set to negative to make delay.*/
uint16_t playback_pause; /*Wait before play back*/
uint16_t repeat_pause; /*Wait before repeat*/
uint8_t playback : 1; /*When the animation is ready play it back*/
uint8_t repeat : 1; /*Repeat the animation infinitely*/
} lv_style_anim_t;
/* Example initialization
lv_style_anim_t a;
a.style_anim = &style_to_anim;
a.style_start = &style_1;
a.style_end = &style_2;
a.act_time = 0;
a.time = 1000;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
a.end_cb = NULL;
lv_style_anim_create(&a);
*/
lv_style_t style_start; /*Save not only pointers because can be same as 'style_anim' then it
will be modified too*/
lv_style_t style_end;
lv_style_t * style_anim;
lv_anim_ready_cb_t ready_cb;
} lv_style_anim_dsc_t;
#endif
/**********************
@@ -169,12 +149,124 @@ void lv_style_mix(const lv_style_t * start, const lv_style_t * end, lv_style_t *
#if LV_USE_ANIMATION
/**
* Create an animation from a pre-configured 'lv_style_anim_t' variable
* @param anim pointer to a pre-configured 'lv_style_anim_t' variable (will be copied)
* @return pointer to a descriptor. Really this variable will be animated. (Can be used in
* `lv_anim_del(dsc, NULL)`)
* Initialize an animation variable.
* E.g.:
* lv_anim_t a;
* lv_style_anim__init(&a);
* lv_style_anim_set_...(&a);
* lv_style_anim_create(&a);
* @param a pointer to an `lv_anim_t` variable to initialize
*/
void * lv_style_anim_create(lv_style_anim_t * anim);
void lv_style_anim_init(lv_anim_t * a);
/**
*
* @param a pointer to an initialized `lv_anim_t` variable
* @param to_anim pointer to the style to animate
* @param start pointer to a style to animate from (start value)
* @param end pointer to a style to animate to (end value)
*/
void lv_style_anim_set_styles(lv_anim_t * a, lv_style_t * to_anim, const lv_style_t * start, const lv_style_t * end);
/**
* Set the duration and delay of an animation
* @param a pointer to an initialized `lv_anim_t` variable
* @param duration duration of the animation in milliseconds
* @param delay delay before the animation in milliseconds
*/
static inline void lv_style_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay)
{
lv_anim_set_time(a, duration, delay);
}
/**
* Set a function call when the animation is ready
* @param a pointer to an initialized `lv_anim_t` variable
* @param ready_cb a function call when the animation is ready
*/
static inline void lv_style_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_cb)
{
lv_style_anim_dsc_t * dsc = a->var;
dsc->ready_cb = ready_cb;
}
/**
* Make the animation to play back to when the forward direction is ready
* @param a pointer to an initialized `lv_anim_t` variable
* @param wait_time time in milliseconds to wait before starting the back direction
*/
static inline void lv_style_anim_set_playback(lv_anim_t * a, uint16_t wait_time)
{
lv_anim_set_playback(a, wait_time);
}
/**
* Disable playback. (Disabled after `lv_anim_init()`)
* @param a pointer to an initialized `lv_anim_t` variable
*/
static inline void lv_style_anim_clear_playback(lv_anim_t * a)
{
lv_anim_clear_playback(a);
}
/**
* Make the animation to start again when ready.
* @param a pointer to an initialized `lv_anim_t` variable
* @param wait_time time in milliseconds to wait before starting the animation again
*/
static inline void lv_style_anim_set_repeat(lv_anim_t * a, uint16_t wait_time)
{
lv_anim_set_repeat(a, wait_time);
}
/**
* Disable repeat. (Disabled after `lv_anim_init()`)
* @param a pointer to an initialized `lv_anim_t` variable
*/
static inline void lv_style_anim_clear_repeat(lv_anim_t * a)
{
lv_anim_clear_repeat(a);
}
/**
* Set a user specific data for the animation
* @param a pointer to an initialized `lv_anim_t` variable
* @param user_data the user data
*/
static inline void lv_style_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data)
{
lv_anim_set_user_data(a, user_data);
}
/**
* Get the user data
* @param a pointer to an initialized `lv_anim_t` variable
* @return the user data
*/
static inline lv_anim_user_data_t lv_style_anim_get_user_data(lv_anim_t * a)
{
return lv_anim_get_user_data(a);
}
/**
* Get pointer to the user data
* @param a pointer to an initialized `lv_anim_t` variable
* @return pointer to the user data
*/
static inline lv_anim_user_data_t * lv_style_anim_get_user_data_ptr(lv_anim_t * a)
{
return lv_anim_get_user_data_ptr(a);
}
/**
* Create an animation
* @param a an initialized 'anim_t' variable. Not required after call.
*/
static inline void lv_style_anim_create(lv_anim_t * a)
{
lv_anim_create(a);
}
#endif
/*************************

View File

@@ -21,30 +21,16 @@ extern "C" {
#include "../lv_core/lv_style.h"
#include "../lv_misc/lv_txt.h"
#include "lv_img_decoder.h"
/*********************
* DEFINES
*********************/
/*If image pixels contains alpha we need to know how much byte is a pixel*/
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
#define LV_IMG_PX_SIZE_ALPHA_BYTE 2
#elif LV_COLOR_DEPTH == 16
#define LV_IMG_PX_SIZE_ALPHA_BYTE 3
#elif LV_COLOR_DEPTH == 32
#define LV_IMG_PX_SIZE_ALPHA_BYTE 4
#endif
/**********************
* TYPEDEFS
**********************/
enum {
LV_IMG_SRC_VARIABLE,
LV_IMG_SRC_FILE,
LV_IMG_SRC_SYMBOL,
LV_IMG_SRC_UNKNOWN,
};
typedef uint8_t lv_img_src_t;
/**********************
* GLOBAL PROTOTYPES

View File

@@ -6,6 +6,7 @@ CSRCS += lv_draw_line.c
CSRCS += lv_draw_img.c
CSRCS += lv_draw_arc.c
CSRCS += lv_draw_triangle.c
CSRCS += lv_img_decoder.c
DEPPATH += --dep-path $(LVGL_DIR)/lvgl/src/lv_draw
VPATH += :$(LVGL_DIR)/lvgl/src/lv_draw

View File

@@ -128,7 +128,9 @@ void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_color_
union_ok = lv_area_intersect(&res_a, cords_p, mask_p);
/*If there are common part of the three area then draw to the vdb*/
if(union_ok == false) return;
if(union_ok == false) {
return;
}
lv_disp_t * disp = lv_refr_get_disp_refreshing();
lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
@@ -158,7 +160,7 @@ void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_color_
else if(opa == LV_OPA_COVER) {
/*Use hw fill if present*/
if(disp->driver.mem_fill_cb) {
disp->driver.mem_fill_cb(vdb->buf_act, &vdb->area, &vdb_rel_a, color);
disp->driver.mem_fill_cb(&disp->driver, vdb->buf_act, &vdb->area, &vdb_rel_a, color);
}
/*Use hw blend if present and the area is not too small*/
else if(lv_area_get_height(&vdb_rel_a) > VFILL_HW_ACC_SIZE_LIMIT &&
@@ -175,7 +177,7 @@ void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_color_
/*Blend the filled line to every line VDB line-by-line*/
lv_coord_t row;
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
disp->driver.mem_blend_cb(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
disp->driver.mem_blend_cb(&disp->driver, &vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
vdb_buf_tmp += vdb_width;
}
@@ -200,7 +202,7 @@ void lv_draw_fill(const lv_area_t * cords_p, const lv_area_t * mask_p, lv_color_
}
lv_coord_t row;
for(row = vdb_rel_a.y1; row <= vdb_rel_a.y2; row++) {
disp->driver.mem_blend_cb(&vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
disp->driver.mem_blend_cb(&disp->driver, &vdb_buf_tmp[vdb_rel_a.x1], color_array_tmp, w, opa);
vdb_buf_tmp += vdb_width;
}
@@ -290,10 +292,13 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
lv_coord_t col, row;
uint8_t col_bit;
uint8_t col_byte_cnt;
uint8_t width_byte_scr =
letter_w >> 3; /*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
/*Width in bytes (on the screen finally) (e.g. w = 11 -> 2 bytes wide)*/
uint8_t width_byte_scr = letter_w >> 3;
if(letter_w & 0x7) width_byte_scr++;
uint8_t width_byte_bpp = (letter_w * bpp) >> 3; /*Letter width in byte. Real width in the font*/
/*Letter width in byte. Real width in the font*/
uint8_t width_byte_bpp = (letter_w * bpp) >> 3;
if((letter_w * bpp) & 0x7) width_byte_bpp++;
/* Calculate the col/row start/end on the map*/
@@ -331,13 +336,16 @@ void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * mask_p, const lv
disp->driver.set_px_cb(&disp->driver, (uint8_t *)vdb->buf_act, vdb_width,
(col + pos_x) - vdb->area.x1,
(row + pos_y) - vdb->area.y1, color, px_opa);
} else {
} else if (vdb_buf_tmp->full != color.full) {
if(px_opa > LV_OPA_MAX) *vdb_buf_tmp = color;
else if(px_opa > LV_OPA_MIN) {
#if LV_COLOR_SCREEN_TRANSP == 0
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
*vdb_buf_tmp = lv_color_mix(color, *vdb_buf_tmp, px_opa);
#else
*vdb_buf_tmp =
color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa);
*vdb_buf_tmp =
color_mix_2_alpha(*vdb_buf_tmp, (*vdb_buf_tmp).alpha, color, px_opa);
#endif
}
}
}
@@ -441,7 +449,7 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, const uint
if(disp->driver.mem_blend_cb == false) {
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
} else {
disp->driver.mem_blend_cb(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
disp->driver.mem_blend_cb(&disp->driver, vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
}
#else
sw_mem_blend(vdb_buf_tmp, (lv_color_t *)map_p, map_useful_w, opa);
@@ -454,7 +462,6 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, const uint
/*In the other cases every pixel need to be checked one-by-one*/
else {
lv_color_t chroma_key_color = LV_COLOR_TRANSP;
lv_coord_t col;
lv_color_t last_img_px = LV_COLOR_BLACK;
lv_color_t recolored_px = lv_color_mix(recolor, last_img_px, recolor_opa);
@@ -485,7 +492,7 @@ void lv_draw_map(const lv_area_t * cords_p, const lv_area_t * mask_p, const uint
}
/*Handle chroma key*/
if(chroma_key && px_color.full == chroma_key_color.full) continue;
if(chroma_key && px_color.full == disp->driver.color_chroma_key.full) continue;
/*Re-color the pixel if required*/
if(recolor_opa != LV_OPA_TRANSP) {

View File

@@ -7,7 +7,7 @@
* INCLUDES
*********************/
#include "lv_draw_img.h"
#include "../lv_misc/lv_fs.h"
#include "../lv_misc/lv_log.h"
/*********************
* DEFINES
@@ -23,33 +23,9 @@
static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src,
const lv_style_t * style, lv_opa_t opa_scale);
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style);
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static void lv_img_decoder_close(void);
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf);
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf);
/**********************
* STATIC VARIABLES
**********************/
static bool decoder_custom;
static const void * decoder_src;
static lv_img_src_t decoder_src_type;
static lv_img_header_t decoder_header;
static const lv_style_t * decoder_style;
#if LV_USE_FILESYSTEM
static lv_fs_file_t decoder_file;
#endif
#if LV_IMG_CF_INDEXED
static lv_color_t decoder_index_map[256];
#endif
static lv_img_decoder_info_f_t lv_img_decoder_info_custom;
static lv_img_decoder_open_f_t lv_img_decoder_open_custom;
static lv_img_decoder_read_line_f_t lv_img_decoder_read_line_custom;
static lv_img_decoder_close_f_t lv_img_decoder_close_custom;
/**********************
* MACROS
@@ -90,63 +66,6 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void *
}
}
/**
* Initialize and `lv_img_dsc_t` variable with the image's info
* @param src variable, filename or symbol
* @param header store the result here
* @return LV_RES_OK: succeeded; LV_RES_INV: failed
*/
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header)
{
header->always_zero = 0;
/*Try to get info with the custom functions first*/
if(lv_img_decoder_info_custom) {
lv_res_t custom_res;
custom_res = lv_img_decoder_info_custom(src, header);
if(custom_res == LV_RES_OK) return LV_RES_OK; /*Custom info has supported this source*/
}
lv_img_src_t src_type = lv_img_src_get_type(src);
if(src_type == LV_IMG_SRC_VARIABLE) {
header->w = ((lv_img_dsc_t *)src)->header.w;
header->h = ((lv_img_dsc_t *)src)->header.h;
header->cf = ((lv_img_dsc_t *)src)->header.cf;
}
#if LV_USE_FILESYSTEM
else if(src_type == LV_IMG_SRC_FILE) {
lv_fs_file_t file;
lv_fs_res_t res;
uint32_t rn;
res = lv_fs_open(&file, src, LV_FS_MODE_RD);
if(res == LV_FS_RES_OK) {
res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
lv_fs_close(&file);
}
/*Create a dummy header on fs error*/
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
header->w = LV_DPI;
header->h = LV_DPI;
header->cf = LV_IMG_CF_UNKNOWN;
return LV_RES_INV;
}
}
#endif
else if(src_type == LV_IMG_SRC_SYMBOL) {
/*The size depend on the font but it is unknown here. It should be handled outside of the
* function*/
header->w = 1;
header->h = 1;
/* Symbols always have transparent parts. Important because of cover check in the design
* function. The actual value doesn't matter because lv_draw_label will draw it*/
header->cf = LV_IMG_CF_ALPHA_1BIT;
} else {
LV_LOG_WARN("Image get info found unknown src type");
return LV_RES_INV;
}
return LV_RES_OK;
}
/**
* Get the color of an image's pixel
* @param dsc an image descriptor
@@ -512,24 +431,6 @@ lv_img_src_t lv_img_src_get_type(const void * src)
return img_src_type;
}
/**
* Set custom decoder functions. See the typdefs of the function typed above for more info about
* them
* @param info_fp info get function
* @param open_fp open function
* @param read_fp read line function
* @param close_fp clode function
*/
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
lv_img_decoder_read_line_f_t read_fp,
lv_img_decoder_close_f_t close_fp)
{
lv_img_decoder_info_custom = info_fp;
lv_img_decoder_open_custom = open_fp;
lv_img_decoder_read_line_custom = read_fp;
lv_img_decoder_close_custom = close_fp;
}
/**********************
* STATIC FUNCTIONS
**********************/
@@ -552,20 +453,20 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
lv_img_header_t header;
lv_res_t header_res;
header_res = lv_img_dsc_get_info(src, &header);
header_res = lv_img_decoder_get_info(src, &header);
if(header_res != LV_RES_OK) {
LV_LOG_WARN("Image draw can't get image info");
lv_img_decoder_close();
return LV_RES_INV;
}
bool chroma_keyed = lv_img_color_format_is_chroma_keyed(header.cf);
bool alpha_byte = lv_img_color_format_has_alpha(header.cf);
const uint8_t * img_data = lv_img_decoder_open(src, style);
lv_img_decoder_dsc_t dsc;
const uint8_t * img_data = lv_img_decoder_open(&dsc, src, style);
if(img_data == LV_IMG_DECODER_OPEN_FAIL) {
LV_LOG_WARN("Image draw cannot open the image resource");
lv_img_decoder_close();
lv_img_decoder_close(&dsc);
return LV_RES_INV;
}
@@ -593,9 +494,9 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
lv_coord_t row;
lv_res_t read_res;
for(row = mask_com.y1; row <= mask_com.y2; row++) {
read_res = lv_img_decoder_read_line(x, y, width, buf);
read_res = lv_img_decoder_read_line(&dsc, x, y, width, buf);
if(read_res != LV_RES_OK) {
lv_img_decoder_close();
lv_img_decoder_close(&dsc);
LV_LOG_WARN("Image draw can't read the line");
return LV_RES_INV;
}
@@ -607,412 +508,7 @@ static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mas
}
}
lv_img_decoder_close();
lv_img_decoder_close(&dsc);
return LV_RES_OK;
}
static const uint8_t * lv_img_decoder_open(const void * src, const lv_style_t * style)
{
decoder_custom = false;
/*Try to open with the custom functions first*/
if(lv_img_decoder_open_custom) {
const uint8_t * custom_res;
custom_res = lv_img_decoder_open_custom(src, style);
if(custom_res != LV_IMG_DECODER_OPEN_FAIL) {
decoder_custom =
true; /*Mark that custom decoder function should be used for this img source.*/
return custom_res; /*Custom open supported this source*/
}
}
decoder_src = src;
decoder_style = style;
decoder_src_type = lv_img_src_get_type(src);
lv_res_t header_res;
header_res = lv_img_dsc_get_info(src, &decoder_header);
if(header_res == LV_RES_INV) {
decoder_src = NULL;
decoder_src_type = LV_IMG_SRC_UNKNOWN;
LV_LOG_WARN("Built-in image decoder can't get the header info");
return LV_IMG_DECODER_OPEN_FAIL;
}
/*Open the file if it's a file*/
if(decoder_src_type == LV_IMG_SRC_FILE) {
#if LV_USE_FILESYSTEM
lv_fs_res_t res = lv_fs_open(&decoder_file, src, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder can't open the file");
return LV_IMG_DECODER_OPEN_FAIL;
}
#else
LV_LOG_WARN("Image built-in decoder can read file because LV_USE_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
}
/*Process the different color formats*/
lv_img_cf_t cf = decoder_header.cf;
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
/*In case of uncompressed formats if the image stored in the ROM/RAM simply give it's
* pointer*/
return ((lv_img_dsc_t *)decoder_src)->data;
} else {
/*If it's file it need to be read line by line later*/
return NULL;
}
} else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT ||
cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) {
#if LV_IMG_CF_INDEXED
#if LV_USE_FILESYSTEM
lv_color32_t palette_file[256];
#endif
lv_color32_t * palette_p = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(cf);
uint32_t palette_size = 1 << px_size;
if(decoder_src_type == LV_IMG_SRC_FILE) {
/*Read the palette from file*/
#if LV_USE_FILESYSTEM
lv_fs_seek(&decoder_file, 4); /*Skip the header*/
lv_fs_read(&decoder_file, palette_file, palette_size * sizeof(lv_color32_t), NULL);
palette_p = palette_file;
#else
LV_LOG_WARN(
"Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else {
/*The palette begins in the beginning of the image data. Just point to it.*/
palette_p = (lv_color32_t *)((lv_img_dsc_t *)decoder_src)->data;
}
uint32_t i;
for(i = 0; i < palette_size; i++) {
decoder_index_map[i] =
lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
}
return NULL;
#else
LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT ||
cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) {
#if LV_IMG_CF_ALPHA
return NULL; /*Nothing to process*/
#else
LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else {
LV_LOG_WARN("Image decoder open: unknown color format")
return LV_IMG_DECODER_OPEN_FAIL;
}
}
static lv_res_t lv_img_decoder_read_line(lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
/*Try to read the line with the custom functions*/
if(decoder_custom) {
if(lv_img_decoder_read_line_custom) {
lv_res_t custom_res;
custom_res = lv_img_decoder_read_line_custom(x, y, len, buf);
return custom_res;
} else {
LV_LOG_WARN("Image open with custom decoder but read not supported")
}
return LV_RES_INV; /*It"s an error if not returned earlier*/
}
if(decoder_src_type == LV_IMG_SRC_FILE) {
#if LV_USE_FILESYSTEM
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
lv_fs_res_t res;
if(decoder_header.cf == LV_IMG_CF_TRUE_COLOR ||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
decoder_header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
uint32_t pos = ((y * decoder_header.w + x) * px_size) >> 3;
pos += 4; /*Skip the header*/
res = lv_fs_seek(&decoder_file, pos);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder seek failed");
return false;
}
uint32_t btr = len * (px_size >> 3);
uint32_t br = 0;
lv_fs_read(&decoder_file, buf, btr, &br);
if(res != LV_FS_RES_OK || btr != br) {
LV_LOG_WARN("Built-in image decoder read failed");
return false;
}
} else if(decoder_header.cf == LV_IMG_CF_ALPHA_1BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_2BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_4BIT ||
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT) {
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
} else if(decoder_header.cf == LV_IMG_CF_INDEXED_1BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_2BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_4BIT ||
decoder_header.cf == LV_IMG_CF_INDEXED_8BIT) {
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder read not supports the color format");
return false;
}
#else
LV_LOG_WARN("Image built-in decoder can't read file because LV_USE_FILESYSTEM = 0");
return false;
#endif
} else if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
if(img_dsc->header.cf == LV_IMG_CF_ALPHA_1BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_4BIT ||
img_dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
lv_img_built_in_decoder_line_alpha(x, y, len, buf);
} else if(img_dsc->header.cf == LV_IMG_CF_INDEXED_1BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_4BIT ||
img_dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
lv_img_built_in_decoder_line_indexed(x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder not supports the color format");
return false;
}
}
return true;
}
static void lv_img_decoder_close(void)
{
/*Try to close with the custom functions*/
if(decoder_custom) {
if(lv_img_decoder_close_custom) lv_img_decoder_close_custom();
return;
}
/*It was opened with built-in decoder*/
if(decoder_src) {
#if LV_USE_FILESYSTEM
if(decoder_src_type == LV_IMG_SRC_FILE) {
lv_fs_close(&decoder_file);
}
#endif
decoder_src_type = LV_IMG_SRC_UNKNOWN;
decoder_src = NULL;
}
}
static lv_res_t lv_img_built_in_decoder_line_alpha(lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf)
{
#if LV_IMG_CF_ALPHA
const lv_opa_t alpha1_opa_table[2] = {
0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119, 136, 153,
170, 187, 204, 221, 238, 255};
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
lv_color_t bg_color = decoder_style->image.color;
lv_coord_t i;
for(i = 0; i < len; i++) {
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
#elif LV_COLOR_DEPTH == 32
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
#else
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
#endif
}
const lv_opa_t * opa_table = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
uint32_t ofs = 0;
int8_t pos = 0;
switch(decoder_header.cf) {
case LV_IMG_CF_ALPHA_1BIT:
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(decoder_header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
pos = 7 - (x & 0x7);
opa_table = alpha1_opa_table;
break;
case LV_IMG_CF_ALPHA_2BIT:
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(decoder_header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
pos = 6 - ((x & 0x3) * 2);
opa_table = alpha2_opa_table;
break;
case LV_IMG_CF_ALPHA_4BIT:
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(decoder_header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
pos = 4 - ((x & 0x1) * 4);
opa_table = alpha4_opa_table;
break;
case LV_IMG_CF_ALPHA_8BIT:
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
pos = 0;
break;
}
#if LV_USE_FILESYSTEM
#if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
#else
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
#endif
const uint8_t * data_tmp = NULL;
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
lv_fs_read(&decoder_file, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN(
"Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
for(i = 0; i < len; i++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
decoder_header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN(
"Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_built_in_decoder_line_indexed(lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf)
{
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(decoder_header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
int8_t pos = 0;
uint32_t ofs = 0;
switch(decoder_header.cf) {
case LV_IMG_CF_INDEXED_1BIT:
w = (decoder_header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(decoder_header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
ofs += 8; /*Skip the palette*/
pos = 7 - (x & 0x7);
break;
case LV_IMG_CF_INDEXED_2BIT:
w = (decoder_header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(decoder_header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
ofs += 16; /*Skip the palette*/
pos = 6 - ((x & 0x3) * 2);
break;
case LV_IMG_CF_INDEXED_4BIT:
w = (decoder_header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(decoder_header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
ofs += 64; /*Skip the palette*/
pos = 4 - ((x & 0x1) * 4);
break;
case LV_IMG_CF_INDEXED_8BIT:
w = decoder_header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
ofs += 1024; /*Skip the palette*/
pos = 0;
break;
}
#if LV_USE_FILESYSTEM
#if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
#else
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
#endif
const uint8_t * data_tmp = NULL;
if(decoder_src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = decoder_src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(&decoder_file, ofs + 4); /*+4 to skip the header*/
lv_fs_read(&decoder_file, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN(
"Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
lv_coord_t i;
lv_color_t * cbuf = (lv_color_t *)buf;
for(i = 0; i < len; i++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
cbuf[i] = decoder_index_map[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN(
"Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}

View File

@@ -14,109 +14,15 @@ extern "C" {
* INCLUDES
*********************/
#include "lv_draw.h"
#include "../lv_core/lv_obj.h"
#include "lv_img_decoder.h"
/*********************
* DEFINES
*********************/
#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1))
/**********************
* TYPEDEFS
**********************/
struct _lv_img_t;
typedef struct
{
/* The first 8 bit is very important to distinguish the different source types.
* For more info see `lv_img_get_src_type()` in lv_img.c */
uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/
uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
non-printable character*/
uint32_t reserved : 2; /*Reserved to be used later*/
uint32_t w : 11; /*Width of the image map*/
uint32_t h : 11; /*Height of the image map*/
} lv_img_header_t;
/*Image color format*/
enum {
LV_IMG_CF_UNKNOWN = 0,
LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/
LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder
function*/
LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs
custom decoder function*/
LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/
LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels
will be transparent*/
LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/
LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/
LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/
LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/
};
typedef uint8_t lv_img_cf_t;
/* Image header it is compatible with
* the result image converter utility*/
typedef struct
{
lv_img_header_t header;
uint32_t data_size;
const uint8_t * data;
} lv_img_dsc_t;
/* Decoder function definitions */
/**
* Get info from an image and store in the `header`
* @param src the image source. Can be a pointer to a C array or a file name (Use
* `lv_img_src_get_type` to determine the type)
* @param header store the info here
* @return LV_RES_OK: info written correctly; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_info_f_t)(const void * src, lv_img_header_t * header);
/**
* Open an image for decoding. Prepare it as it is required to read it later
* @param src the image source. Can be a pointer to a C array or a file name (Use
* `lv_img_src_get_type` to determine the type)
* @param style the style of image (maybe it will be required to determine a color or something)
* @return there are 3 possible return values:
* 1) buffer with the decoded image
* 2) if can decode the whole image NULL. decoder_read_line will be called to read the image
* line-by-line 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an
* error occurred
*/
typedef const uint8_t * (*lv_img_decoder_open_f_t)(const void * src, const lv_style_t * style);
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
* Required only if the "open" function can't return with the whole decoded pixel array.
* @param x start x coordinate
* @param y startt y coordinate
* @param len number of pixels to decode
* @param buf a buffer to store the decoded pixels
* @return LV_RES_OK: ok; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_read_line_f_t)(lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf);
/**
* Close the pending decoding. Free resources etc.
*/
typedef void (*lv_img_decoder_close_f_t)(void);
/**********************
* GLOBAL PROTOTYPES
@@ -133,14 +39,6 @@ typedef void (*lv_img_decoder_close_f_t)(void);
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src,
const lv_style_t * style, lv_opa_t opa_scale);
/**
* Initialize and `lv_img_dsc_t` variable with the image's info
* @param src variable, filename or symbol
* @param header store the result here
* @return LV_RES_OK: succeeded; LV_RES_INV: failed
*/
lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header);
/**
* Get the type of an image source
* @param src pointer to an image source:
@@ -151,18 +49,6 @@ lv_res_t lv_img_dsc_get_info(const char * src, lv_img_header_t * header);
*/
lv_img_src_t lv_img_src_get_type(const void * src);
/**
* Set custom decoder functions. See the typdefs of the function typed above for more info about
* them
* @param info_fp info get function
* @param open_fp open function
* @param read_fp read line function
* @param close_fp clode function
*/
void lv_img_decoder_set_custom(lv_img_decoder_info_f_t info_fp, lv_img_decoder_open_f_t open_fp,
lv_img_decoder_read_line_f_t read_fp,
lv_img_decoder_close_f_t close_fp);
/**
* Get the color of an image's pixel
* @param dsc an image descriptor

View File

@@ -50,12 +50,12 @@ static uint8_t hex_char_to_num(char hex);
* @param txt 0 terminated text to write
* @param flag settings for the text from 'txt_flag_t' enum
* @param offset text offset in x and y direction (NULL if unused)
* @param sel_start start index of selected area (-1 if none)
* @param sel_end end index of selected area (-1 if none)
* @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
* @param sel_end end index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
*/
void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style,
lv_opa_t opa_scale, const char * txt, lv_txt_flag_t flag, lv_point_t * offset,
int sel_start, int sel_end)
uint16_t sel_start, uint16_t sel_end)
{
const lv_font_t * font = style->text.font;
lv_coord_t w;
@@ -183,7 +183,7 @@ void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_st
letter_w = lv_font_get_width(font, letter);
if(sel_start != -1 && sel_end != -1) {
if(sel_start != 0xFFFF && sel_end != 0xFFFF) {
int char_ind = lv_encoded_get_char_id(txt, i);
/*Do not draw the rectangle on the character at `sel_start`.*/
if(char_ind > sel_start && char_ind <= sel_end) {

View File

@@ -36,12 +36,12 @@ extern "C" {
* @param txt 0 terminated text to write
* @param flag settings for the text from 'txt_flag_t' enum
* @param offset text offset in x and y direction (NULL if unused)
* @param sel_start start index of selected area (-1 if none)
* @param sel_end end index of selected area (-1 if none)
* @param sel_start start index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
* @param sel_end end index of selected area (`LV_LABEL_TXT_SEL_OFF` if none)
*/
void lv_draw_label(const lv_area_t * coords, const lv_area_t * mask, const lv_style_t * style,
lv_opa_t opa_scale, const char * txt, lv_txt_flag_t flag, lv_point_t * offset,
int sel_start, int sel_end);
uint16_t sel_start, uint16_t sel_end);
/**********************
* MACROS

View File

@@ -85,6 +85,12 @@ void lv_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv
if(style->line.width == 0) return;
if(point1->x == point2->x && point1->y == point2->y) return;
/*Return if the points are out of the mask*/
if(point1->x < mask->x1 && point2->x < mask->x1) return;
if(point1->x > mask->x2 && point2->x > mask->x2) return;
if(point1->y < mask->y1 && point2->y < mask->y1) return;
if(point1->y > mask->y2 && point2->y > mask->y2) return;
line_draw_t main_line;
lv_point_t p1;
lv_point_t p2;
@@ -236,7 +242,9 @@ static void line_draw_skew(line_draw_t * main_line, bool dir_ori, const lv_area_
lv_opa_t opa = opa_scale == LV_OPA_COVER
? style->line.opa
: (uint16_t)((uint16_t)style->line.opa * opa_scale) >> 8;
#if LV_ANTIALIAS
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
#endif
lv_point_t vect_main, vect_norm;
vect_main.x = main_line->p2.x - main_line->p1.x;
vect_main.y = main_line->p2.y - main_line->p1.y;

View File

@@ -86,6 +86,11 @@ void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_sty
lv_draw_shadow(coords, mask, style, opa_scale);
}
#endif
/* If the object is out of the mask there is nothing to draw.
* Draw shadow before it because the shadow is out of `coords`*/
if(lv_area_is_on(coords, mask) == false) return;
if(style->body.opa > LV_OPA_MIN) {
lv_draw_rect_main_mid(coords, mask, style, opa_scale);
@@ -1476,7 +1481,7 @@ static void lv_draw_shadow_full_straight(const lv_area_t * coords, const lv_area
{
bool aa = lv_disp_get_antialiasing(lv_refr_get_disp_refreshing());
lv_coord_t radius = style->body.radius;
lv_coord_t swidth = style->body.shadow.width; // + LV_ANTIALIAS;
lv_coord_t swidth = style->body.shadow.width;
lv_coord_t width = lv_area_get_width(coords);
lv_coord_t height = lv_area_get_height(coords);

View File

@@ -92,6 +92,31 @@ void lv_draw_triangle(const lv_point_t * points, const lv_area_t * mask, const l
void tri_draw_flat(const lv_point_t * points, const lv_area_t * mask, const lv_style_t * style, lv_opa_t opa)
{
/*Return if the points are out of the mask*/
if(points[0].x < mask->x1 &&
points[1].x < mask->x1 &&
points[2].x < mask->x1) {
return;
}
if(points[0].x > mask->x2 &&
points[1].x > mask->x2 &&
points[2].x > mask->x2) {
return;
}
if(points[0].y < mask->y1 &&
points[1].y < mask->y1 &&
points[2].y < mask->y1) {
return;
}
if(points[0].y > mask->y2 &&
points[1].y > mask->y2 &&
points[2].y > mask->y2) {
return;
}
lv_point_t tri[3];
memcpy(tri, points, sizeof(tri));

View File

@@ -0,0 +1,705 @@
/**
* @file lv_img_decoder.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_img_decoder.h"
#include "../lv_draw/lv_draw_img.h"
#include "../lv_misc/lv_ll.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_gc.h"
#if defined(LV_GC_INCLUDE)
#include LV_GC_INCLUDE
#endif /* LV_ENABLE_GC */
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
#if LV_USE_FILESYSTEM
lv_fs_file_t * f;
#endif
lv_color_t * palette;
}lv_img_decoder_built_in_data_t;
/**********************
* STATIC PROTOTYPES
**********************/
static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
static const uint8_t * lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc);
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf);
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
/**
* Initialize the image decoder module
* */
void lv_img_decoder_init(void)
{
lv_ll_init(&LV_GC_ROOT(_lv_img_defoder_ll), sizeof(lv_img_decoder_t));
lv_img_decoder_t * decoder;
/*Create a decoder for the built in color format*/
decoder = lv_img_decoder_create();
if(decoder == NULL) {
LV_LOG_WARN("lv_img_decoder_init: out of memory");
lv_mem_assert(decoder);
return;
}
lv_img_decoder_set_info_cb(decoder, lv_img_decoder_built_in_info);
lv_img_decoder_set_open_cb(decoder, lv_img_decoder_built_in_open);
lv_img_decoder_set_read_line_cb(decoder, lv_img_decoder_built_in_read_line);
lv_img_decoder_set_close_cb(decoder, lv_img_decoder_built_in_close);
}
/**
* Get information about an image.
* Try the created image decoder one by one. Once one is able to get info that info will be used.
* @param src the image source. E.g. file name or variable.
* @param header the image info will be stored here
* @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
*/
lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header)
{
header->always_zero = 0;
lv_res_t res = LV_RES_INV;
lv_img_decoder_t * d;
LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) {
res = LV_RES_INV;
if(d->info_cb) {
res = d->info_cb(d, src, header);
if(res == LV_RES_OK) break;
}
}
return res;
}
/**
* Open an image.
* Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc`
* @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable.
* @param src the image source. Can be
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
* 3) Symbol: E.g. `LV_SYMBOL_OK`
* @param style the style of the image
* @return LV_IMG_DECODER_OPEN_FAIL: can open the image
* NULL: the image is opened but `lv_img_decoder_read_line` needs to be used to get the info line by line
* Else: a pointer to a buffer which holds the uncompressed pixels of the image
*/
const uint8_t * lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style)
{
dsc->style = style;
dsc->src = src;
dsc->src_type = lv_img_src_get_type(src);
dsc->user_data = NULL;
lv_res_t header_res;
header_res = lv_img_decoder_get_info(src, &dsc->header);
if(header_res != LV_RES_OK) return LV_IMG_DECODER_OPEN_FAIL;
const uint8_t * res = NULL;
lv_img_decoder_t * d;
LV_LL_READ(LV_GC_ROOT(_lv_img_defoder_ll), d) {
res = NULL;
dsc->decoder = d;
if(d->open_cb) res = d->open_cb(d, dsc);
if(res != LV_IMG_DECODER_OPEN_FAIL) break;
}
return res;
}
/**
* Read a line from an opened image
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
* @param x start X coordinate (from left)
* @param y start Y coordinate (from top)
* @param len number of pixels to read
* @param buf store the data here
* @return LV_RES_OK: success; LV_RES_INV: an error occurred
*/
lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
lv_res_t res = LV_RES_INV;
if(dsc->decoder->read_line_cb)res = dsc->decoder->read_line_cb(dsc->decoder, dsc, x, y, len, buf);
return res;
}
/**
* Close a decoding session
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
*/
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)
{
if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
}
/**
* Create a new image decoder
* @return pointer to the new image decoder
*/
lv_img_decoder_t * lv_img_decoder_create(void)
{
lv_img_decoder_t * decoder;
decoder = lv_ll_ins_head(&LV_GC_ROOT(_lv_img_defoder_ll));
lv_mem_assert(decoder);
if(decoder == NULL) return NULL;
memset(decoder, 0, sizeof(lv_img_decoder_t));
return decoder;
}
/**
* Delete an image decoder
* @param decoder pointer to an image decoder
*/
void lv_img_decoder_delete(lv_img_decoder_t * decoder)
{
lv_ll_rem(&LV_GC_ROOT(_lv_img_defoder_ll), decoder);
lv_mem_free(decoder);
}
/**
* Set a callback to get information about the image
* @param decoder pointer to an image decoder
* @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
*/
void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb)
{
decoder->info_cb = info_cb;
}
/**
* Set a callback to open an image
* @param decoder pointer to an image decoder
* @param open_cb a function to open an image
*/
void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb)
{
decoder->open_cb = open_cb;
}
/**
* Set a callback to a decoded line of an image
* @param decoder pointer to an image decoder
* @param read_line_cb a function to read a line of an image
*/
void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb)
{
decoder->read_line_cb = read_line_cb;
}
/**
* Set a callback to close a decoding session. E.g. close files and free other resources.
* @param decoder pointer to an image decoder
* @param close_cb a function to close a decoding session
*/
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb)
{
decoder->close_cb = close_cb;
}
/**********************
* STATIC FUNCTIONS
**********************/
static lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
{
(void)decoder; /*Unused*/
lv_img_src_t src_type = lv_img_src_get_type(src);
if(src_type == LV_IMG_SRC_VARIABLE) {
header->w = ((lv_img_dsc_t *)src)->header.w;
header->h = ((lv_img_dsc_t *)src)->header.h;
header->cf = ((lv_img_dsc_t *)src)->header.cf;
}
#if LV_USE_FILESYSTEM
else if(src_type == LV_IMG_SRC_FILE) {
lv_fs_file_t file;
lv_fs_res_t res;
uint32_t rn;
res = lv_fs_open(&file, src, LV_FS_MODE_RD);
if(res == LV_FS_RES_OK) {
res = lv_fs_read(&file, header, sizeof(lv_img_header_t), &rn);
lv_fs_close(&file);
}
/*Create a dummy header on fs error*/
if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
header->w = LV_DPI;
header->h = LV_DPI;
header->cf = LV_IMG_CF_UNKNOWN;
return LV_RES_INV;
}
}
#endif
else if(src_type == LV_IMG_SRC_SYMBOL) {
/*The size depend on the font but it is unknown here. It should be handled outside of the
* function*/
header->w = 1;
header->h = 1;
/* Symbols always have transparent parts. Important because of cover check in the design
* function. The actual value doesn't matter because lv_draw_label will draw it*/
header->cf = LV_IMG_CF_ALPHA_1BIT;
} else {
LV_LOG_WARN("Image get info found unknown src type");
return LV_RES_INV;
}
return LV_RES_OK;
}
static const uint8_t * lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
/*Open the file if it's a file*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
#if LV_USE_FILESYSTEM
lv_fs_file_t f;
lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder can't open the file");
return LV_IMG_DECODER_OPEN_FAIL;
}
/*If the file was open successfully save the file descriptor*/
if(dsc->user_data == NULL) {
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
if(dsc->user_data == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
lv_mem_assert(dsc->user_data);
}
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
user_data->f = lv_mem_alloc(sizeof(f));
if(user_data->f == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
lv_mem_assert(user_data->f);
}
memcpy(user_data->f, &f, sizeof(f));
#else
LV_LOG_WARN("Image built-in decoder cannot read file because LV_USE_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
}
lv_img_cf_t cf = dsc->header.cf;
/*Process true color formats*/
if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
/* In case of uncompressed formats the image stored in the ROM/RAM.
* So simply give its pointer*/
return ((lv_img_dsc_t *)dsc->src)->data;
} else {
/*If it's a file it need to be read line by line later*/
return NULL;
}
}
/*Process indexed images. Build a palette*/
else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT ||
cf == LV_IMG_CF_INDEXED_4BIT || cf == LV_IMG_CF_INDEXED_8BIT) {
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(cf);
uint32_t palette_size = 1 << px_size;
/*Allocate the palette*/
if(dsc->user_data == NULL) {
dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
if(dsc->user_data == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
lv_mem_assert(dsc->user_data);
}
memset(dsc->user_data, 0, sizeof(lv_img_decoder_built_in_data_t));
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
if(user_data->palette == NULL) {
LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
#if LV_USE_FILESYSTEM
lv_mem_assert(user_data->f);
#endif
}
#if LV_USE_FILESYSTEM
lv_color32_t palette_tmp[256];
#endif
lv_color32_t * palette_p;
if(dsc->src_type == LV_IMG_SRC_FILE) {
/*Read the palette from file*/
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, 4); /*Skip the header*/
lv_fs_read(user_data->f, palette_tmp, palette_size * sizeof(lv_color_t), NULL);
palette_p = palette_tmp;
#else
LV_LOG_WARN(
"Image built-in decoder can read the palette because LV_USE_FILESYSTEM = 0");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
} else {
/*The palette begins in the beginning of the image data. Just point to it.*/
palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data;
}
uint32_t i;
for(i = 0; i < palette_size; i++) {
user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
}
return NULL;
#else
LV_LOG_WARN("Indexed (palette) images are not enabled in lv_conf.h. See LV_IMG_CF_INDEXED");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
}
/*Alpha indexed images. */
else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT ||
cf == LV_IMG_CF_ALPHA_4BIT || cf == LV_IMG_CF_ALPHA_8BIT) {
#if LV_IMG_CF_ALPHA
return NULL; /*Nothing to process*/
#else
LV_LOG_WARN("Alpha indexed images are not enabled in lv_conf.h. See LV_IMG_CF_ALPHA");
return LV_IMG_DECODER_OPEN_FAIL;
#endif
}
/*Unknown format. Can't decode it.*/
else {
/*Free the potentially allocated memories*/
lv_img_decoder_built_in_close(decoder, dsc);
LV_LOG_WARN("Image decoder open: unknown color format")
return LV_IMG_DECODER_OPEN_FAIL;
}
}
static lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
(void)decoder; /*Unused*/
lv_res_t res = LV_RES_INV;
if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR ||
dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED)
{
/* For TRUE_COLOR images read line required only for files.
* For variables the image data was returned in `open`*/
if(dsc->src_type == LV_IMG_SRC_FILE) {
res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf);
}
} else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT ||
dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
dsc->header.cf == LV_IMG_CF_ALPHA_4BIT ||
dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf);
} else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT ||
dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
dsc->header.cf == LV_IMG_CF_INDEXED_4BIT ||
dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf);
} else {
LV_LOG_WARN("Built-in image decoder read not supports the color format");
return false;
}
return res;
}
static void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
{
(void)decoder; /*Unused*/
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
if(user_data) {
#if LV_USE_FILESYSTEM
if(user_data->f) lv_mem_free(user_data->f);
#endif
if(user_data->palette) lv_mem_free(user_data->palette);
lv_mem_free(user_data);
dsc->user_data = NULL;
}
}
static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
{
#if LV_USE_FILESYSTEM
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
lv_fs_res_t res;
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3;
pos += 4; /*Skip the header*/
res = lv_fs_seek(user_data->f, pos);
if(res != LV_FS_RES_OK) {
LV_LOG_WARN("Built-in image decoder seek failed");
return LV_RES_INV;
}
uint32_t btr = len * (px_size >> 3);
uint32_t br = 0;
lv_fs_read(user_data->f, buf, btr, &br);
if(res != LV_FS_RES_OK || btr != br) {
LV_LOG_WARN("Built-in image decoder read failed");
return LV_RES_INV;
}
return LV_RES_OK;
#else
LV_LOG_WARN("Image built-in decoder cannot read file because LV_USE_FILESYSTEM = 0");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf)
{
#if LV_IMG_CF_ALPHA
const lv_opa_t alpha1_opa_table[2] = {
0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
68, 85, 102, 119, 136, 153,
170, 187, 204, 221, 238, 255};
/*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
lv_color_t bg_color = dsc->style->image.color;
lv_coord_t i;
for(i = 0; i < len; i++) {
#if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
#elif LV_COLOR_DEPTH == 16
/*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
#elif LV_COLOR_DEPTH == 32
*((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
#else
#error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
#endif
}
const lv_opa_t * opa_table = NULL;
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
uint32_t ofs = 0;
int8_t pos = 0;
switch(dsc->header.cf) {
case LV_IMG_CF_ALPHA_1BIT:
w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(dsc->header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
pos = 7 - (x & 0x7);
opa_table = alpha1_opa_table;
break;
case LV_IMG_CF_ALPHA_2BIT:
w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(dsc->header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
pos = 6 - ((x & 0x3) * 2);
opa_table = alpha2_opa_table;
break;
case LV_IMG_CF_ALPHA_4BIT:
w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(dsc->header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
pos = 4 - ((x & 0x1) * 4);
opa_table = alpha4_opa_table;
break;
case LV_IMG_CF_ALPHA_8BIT:
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
pos = 0;
break;
}
#if LV_USE_FILESYSTEM
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
#if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
#else
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
#endif
const uint8_t * data_tmp = NULL;
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/
lv_fs_read(user_data->f, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN( "Image built-in alpha line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
for(i = 0; i < len; i++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN(
"Image built-in alpha line reader failed because LV_IMG_CF_ALPHA is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}
static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len,
uint8_t * buf)
{
#if LV_IMG_CF_INDEXED
uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf);
uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
lv_coord_t w = 0;
int8_t pos = 0;
uint32_t ofs = 0;
switch(dsc->header.cf) {
case LV_IMG_CF_INDEXED_1BIT:
w = (dsc->header.w >> 3); /*E.g. w = 20 -> w = 2 + 1*/
if(dsc->header.w & 0x7) w++;
ofs += w * y + (x >> 3); /*First pixel*/
ofs += 8; /*Skip the palette*/
pos = 7 - (x & 0x7);
break;
case LV_IMG_CF_INDEXED_2BIT:
w = (dsc->header.w >> 2); /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
if(dsc->header.w & 0x3) w++;
ofs += w * y + (x >> 2); /*First pixel*/
ofs += 16; /*Skip the palette*/
pos = 6 - ((x & 0x3) * 2);
break;
case LV_IMG_CF_INDEXED_4BIT:
w = (dsc->header.w >> 1); /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
if(dsc->header.w & 0x1) w++;
ofs += w * y + (x >> 1); /*First pixel*/
ofs += 64; /*Skip the palette*/
pos = 4 - ((x & 0x1) * 4);
break;
case LV_IMG_CF_INDEXED_8BIT:
w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
ofs += w * y + x; /*First pixel*/
ofs += 1024; /*Skip the palette*/
pos = 0;
break;
}
lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
#if LV_USE_FILESYSTEM
#if LV_COMPILER_VLA_SUPPORTED
uint8_t fs_buf[w];
#else
uint8_t fs_buf[LV_HOR_RES_MAX];
#endif
#endif
const uint8_t * data_tmp = NULL;
if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
const lv_img_dsc_t * img_dsc = dsc->src;
data_tmp = img_dsc->data + ofs;
} else {
#if LV_USE_FILESYSTEM
lv_fs_seek(user_data->f, ofs + 4); /*+4 to skip the header*/
lv_fs_read(user_data->f, fs_buf, w, NULL);
data_tmp = fs_buf;
#else
LV_LOG_WARN(
"Image built-in indexed line reader can't read file because LV_USE_FILESYSTEM = 0");
data_tmp = NULL; /*To avoid warnings*/
return LV_RES_INV;
#endif
}
uint8_t byte_act = 0;
uint8_t val_act;
lv_coord_t i;
lv_color_t * cbuf = (lv_color_t *)buf;
for(i = 0; i < len; i++) {
val_act = (data_tmp[byte_act] & (mask << pos)) >> pos;
cbuf[i] = user_data->palette[val_act];
pos -= px_size;
if(pos < 0) {
pos = 8 - px_size;
data_tmp++;
}
}
return LV_RES_OK;
#else
LV_LOG_WARN(
"Image built-in indexed line reader failed because LV_IMG_CF_INDEXED is 0 in lv_conf.h");
return LV_RES_INV;
#endif
}

View File

@@ -0,0 +1,307 @@
/**
* @file lv_img_decoder.h
*
*/
#ifndef LV_IMG_DEOCER_H
#define LV_IMG_DEOCER_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../../lv_conf.h"
#endif
#include <stdint.h>
#include "../lv_misc/lv_fs.h"
#include "../lv_misc/lv_types.h"
#include "../lv_misc/lv_area.h"
#include "../lv_core/lv_style.h"
/*********************
* DEFINES
*********************/
/*If image pixels contains alpha we need to know how much byte is a pixel*/
#if LV_COLOR_DEPTH == 1 || LV_COLOR_DEPTH == 8
#define LV_IMG_PX_SIZE_ALPHA_BYTE 2
#elif LV_COLOR_DEPTH == 16
#define LV_IMG_PX_SIZE_ALPHA_BYTE 3
#elif LV_COLOR_DEPTH == 32
#define LV_IMG_PX_SIZE_ALPHA_BYTE 4
#endif
#define LV_IMG_DECODER_OPEN_FAIL ((void *)(-1))
/**********************
* TYPEDEFS
**********************/
enum {
LV_IMG_SRC_VARIABLE,
LV_IMG_SRC_FILE,
LV_IMG_SRC_SYMBOL,
LV_IMG_SRC_UNKNOWN,
};
typedef uint8_t lv_img_src_t;
typedef struct
{
/* The first 8 bit is very important to distinguish the different source types.
* For more info see `lv_img_get_src_type()` in lv_img.c */
uint32_t cf : 5; /* Color format: See `lv_img_color_format_t`*/
uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
non-printable character*/
uint32_t reserved : 2; /*Reserved to be used later*/
uint32_t w : 11; /*Width of the image map*/
uint32_t h : 11; /*Height of the image map*/
} lv_img_header_t;
/*Image color format*/
enum {
LV_IMG_CF_UNKNOWN = 0,
LV_IMG_CF_RAW, /*Contains the file as it is. Needs custom decoder function*/
LV_IMG_CF_RAW_ALPHA, /*Contains the file as it is. The image has alpha. Needs custom decoder
function*/
LV_IMG_CF_RAW_CHROMA_KEYED, /*Contains the file as it is. The image is chroma keyed. Needs
custom decoder function*/
LV_IMG_CF_TRUE_COLOR, /*Color format and depth should match with LV_COLOR settings*/
LV_IMG_CF_TRUE_COLOR_ALPHA, /*Same as `LV_IMG_CF_TRUE_COLOR` but every pixel has an alpha byte*/
LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED, /*Same as `LV_IMG_CF_TRUE_COLOR` but LV_COLOR_TRANSP pixels
will be transparent*/
LV_IMG_CF_INDEXED_1BIT, /*Can have 2 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_2BIT, /*Can have 4 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_4BIT, /*Can have 16 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_INDEXED_8BIT, /*Can have 256 different colors in a palette (always chroma keyed)*/
LV_IMG_CF_ALPHA_1BIT, /*Can have one color and it can be drawn or not*/
LV_IMG_CF_ALPHA_2BIT, /*Can have one color but 4 different alpha value*/
LV_IMG_CF_ALPHA_4BIT, /*Can have one color but 16 different alpha value*/
LV_IMG_CF_ALPHA_8BIT, /*Can have one color but 256 different alpha value*/
};
typedef uint8_t lv_img_cf_t;
/* Image header it is compatible with
* the result image converter utility*/
typedef struct
{
lv_img_header_t header;
uint32_t data_size;
const uint8_t * data;
} lv_img_dsc_t;
/* Decoder function definitions */
struct _lv_img_decoder;
struct _lv_img_decoder_dsc;
/**
* Get info from an image and store in the `header`
* @param src the image source. Can be a pointer to a C array or a file name (Use
* `lv_img_src_get_type` to determine the type)
* @param header store the info here
* @return LV_RES_OK: info written correctly; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_info_f_t)(struct _lv_img_decoder * decoder, const void * src, lv_img_header_t * header);
/**
* Open an image for decoding. Prepare it as it is required to read it later
* @param src the image source. Can be a pointer to a C array or a file name (Use
* `lv_img_src_get_type` to determine the type)
* @param style the style of image (maybe it will be required to determine a color or something)
* @return there are 3 possible return values:
* 1) buffer with the decoded image
* 2) if can decode the whole image NULL. decoder_read_line will be called to read the image
* line-by-line
* 3) LV_IMG_DECODER_OPEN_FAIL if the image format is unknown to the decoder or an
* error occurred
*/
typedef const uint8_t * (*lv_img_decoder_open_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc);
/**
* Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
* Required only if the "open" function can't return with the whole decoded pixel array.
* @param x start x coordinate
* @param y start y coordinate
* @param len number of pixels to decode
* @param buf a buffer to store the decoded pixels
* @return LV_RES_OK: ok; LV_RES_INV: failed
*/
typedef lv_res_t (*lv_img_decoder_read_line_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc,
lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
/**
* Close the pending decoding. Free resources etc.
*/
typedef void (*lv_img_decoder_close_f_t)(struct _lv_img_decoder * decoder, struct _lv_img_decoder_dsc * dsc);
typedef struct _lv_img_decoder {
lv_img_decoder_info_f_t info_cb;
lv_img_decoder_open_f_t open_cb;
lv_img_decoder_read_line_f_t read_line_cb;
lv_img_decoder_close_f_t close_cb;
#if LV_USE_USER_DATA
lv_img_decoder_user_data_t user_data;
#endif
}lv_img_decoder_t;
typedef struct _lv_img_decoder_dsc {
lv_img_decoder_t * decoder;
const lv_style_t * style;
const void * src;
lv_img_src_t src_type;
lv_img_header_t header;
#if LV_USE_USER_DATA
void * user_data;
#endif
}lv_img_decoder_dsc_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize the image decoder module
*/
void lv_img_decoder_init(void);
/**
* Get information about an image.
* Try the created image decoder one by one. Once one is able to get info that info will be used.
* @param src the image source. Can be
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
* 3) Symbol: E.g. `LV_SYMBOL_OK`
* @param header the image info will be stored here
* @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
*/
lv_res_t lv_img_decoder_get_info(const char * src, lv_img_header_t * header);
/**
* Open an image.
* Try the created image decoder one by one. Once one is able to open the image that decoder is save in `dsc`
* @param dsc describe a decoding session. Simply a pointer to an `lv_img_decoder_dsc_t` variable.
* @param src the image source. Can be
* 1) File name: E.g. "S:folder/img1.png" (The drivers needs to registered via `lv_fs_add_drv()`)
* 2) Variable: Pointer to an `lv_img_dsc_t` variable
* 3) Symbol: E.g. `LV_SYMBOL_OK`
* @param style the style of the image
* @return LV_IMG_DECODER_OPEN_FAIL: can open the image
* NULL: the image is opened but `lv_img_decoder_read_line` needs to be used to get the info line by line
* Else: a pointer to a buffer which holds the uncompressed pixels of the image
*/
const uint8_t * lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, const lv_style_t * style);
/**
* Read a line from an opened image
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
* @param x start X coordinate (from left)
* @param y start Y coordinate (from top)
* @param len number of pixels to read
* @param buf store the data here
* @return LV_RES_OK: success; LV_RES_INV: an error occurred
*/
lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf);
/**
* Close a decoding session
* @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
*/
void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc);
/**
* Create a new image decoder
* @return pointer to the new image decoder
*/
lv_img_decoder_t * lv_img_decoder_create(void);
/**
* Delete an image decoder
* @param decoder pointer to an image decoder
*/
void lv_img_decoder_delete(lv_img_decoder_t * decoder);
/**
* Set a callback to get information about the image
* @param decoder pointer to an image decoder
* @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
*/
void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb);
/**
* Set a callback to open an image
* @param decoder pointer to an image decoder
* @param open_cb a function to open an image
*/
void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb);
/**
* Set a callback to a decoded line of an image
* @param decoder pointer to an image decoder
* @param read_line_cb a function to read a line of an image
*/
void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb);
/**
* Set a callback to close a decoding session. E.g. close files and free other resources.
* @param decoder pointer to an image decoder
* @param close_cb a function to close a decoding session
*/
void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb);
/**
* Set a custom user data in an image decoder.
* @param decoder pointer to an image decoder
* @param user_data the user data to set
*/
static inline void lv_img_decoder_set_user_data(lv_img_decoder_t * decoder, lv_img_decoder_t user_data)
{
memcpy(&decoder->user_data, &user_data, sizeof(user_data));
}
/**
* Get the user data
* @param decoder pointer to an image decoder
* @return the user data
*/
static inline lv_img_decoder_user_data_t lv_img_decoder_get_user_data(lv_img_decoder_t * decoder)
{
return decoder->user_data;
}
/**
* Get a pointer to the user data
* @param decoder pointer to an image decoder
* @return pointer to the user data
*/
static inline lv_img_decoder_user_data_t * lv_img_decoder_get_user_data_ptr(lv_img_decoder_t * decoder)
{
return &decoder->user_data;
}
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_TEMPL_H*/

View File

@@ -125,7 +125,7 @@ void lv_font_builtin_init(void)
#if LV_USE_FONT_DEJAVU_30 != 0
lv_font_add(&lv_font_symbol_30, &lv_font_dejavu_30);
#else
lv_font_add(&lv_font_symbol_30_basic, NULL);
lv_font_add(&lv_font_symbol_30, NULL);
#endif
#endif

View File

@@ -61,6 +61,7 @@ void lv_disp_drv_init(lv_disp_drv_t * driver)
driver->ver_res = LV_VER_RES_MAX;
driver->buffer = NULL;
driver->rotated = 0;
driver->color_chroma_key = LV_COLOR_TRANSP;
#if LV_ANTIALIAS
driver->antialiasing = true;
@@ -71,6 +72,10 @@ void lv_disp_drv_init(lv_disp_drv_t * driver)
driver->mem_fill_cb = NULL;
#endif
#if LV_USE_USER_DATA
driver->user_data = NULL;
#endif
driver->set_px_cb = NULL;
}
@@ -124,21 +129,20 @@ lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
disp_def = disp; /*Temporarily change the default screen to create the default screens on the
new display*/
disp->inv_p = 0;
disp->act_scr = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/
disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
disp->sys_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
lv_obj_set_style(disp->top_layer, &lv_style_transp);
lv_obj_set_style(disp->sys_layer, &lv_style_transp);
disp->inv_p = 0;
lv_obj_invalidate(disp->act_scr);
disp_def = disp_def_tmp; /*Revert the default display*/
/*Create a refresh task*/
disp->refr_task =
lv_task_create(lv_disp_refr_task, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, disp);
disp->refr_task = lv_task_create(lv_disp_refr_task, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, disp);
lv_mem_assert(disp->refr_task);
if(disp->refr_task == NULL) return NULL;

View File

@@ -92,22 +92,19 @@ typedef struct _disp_drv_t
#if LV_USE_GPU
/*OPTIONAL: Blend two memories using opacity (GPU only)*/
void (*mem_blend_cb)(lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
void (*mem_blend_cb)(struct _disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
/*OPTIONAL: Fill a memory with a color (GPU only)*/
void (*mem_fill_cb)(lv_color_t * dest_buf, const lv_area_t * dest_area,
void (*mem_fill_cb)(struct _disp_drv_t * disp_drv, lv_color_t * dest_buf, const lv_area_t * dest_area,
const lv_area_t * fill_area, lv_color_t color);
#endif
#if LV_USE_USER_DATA_SINGLE
lv_disp_drv_user_data_t user_data;
#endif
/*On CHROMA_KEYED images this color will be transparent.
* `LV_COLOR_TRANSP` by default. (lv_conf.h)*/
lv_color_t color_chroma_key;
#if LV_USE_USER_DATA_MULTI
lv_disp_drv_user_data_t flush_user_data;
lv_disp_drv_user_data_t rounder_user_data;
lv_disp_drv_user_data_t set_px_user_data;
lv_disp_drv_user_data_t monitor_user_data;
#if LV_USE_USER_DATA
lv_disp_drv_user_data_t user_data;
#endif
} lv_disp_drv_t;

View File

@@ -54,6 +54,7 @@ typedef uint8_t lv_indev_type_t;
enum { LV_INDEV_STATE_REL = 0, LV_INDEV_STATE_PR };
typedef uint8_t lv_indev_state_t;
/*Data type when an input device is read */
typedef struct
{
@@ -73,15 +74,14 @@ typedef struct _lv_indev_drv_t
/*Input device type*/
lv_indev_type_t type;
/*Function pointer to read_cb data. Return 'true' if there is still data to be read_cb
* (buffered)*/
/*Function pointer to read input device data.
* Return 'true' if there is still data to be read (buffered)*/
bool (*read_cb)(struct _lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
#if LV_USE_USER_DATA_MULTI
lv_indev_drv_user_data_t read_user_data;
#endif
/*Called when an action happened on the input device.*/
void (*feedback_cb)(struct _lv_indev_drv_t *, uint8_t);
#if LV_USE_USER_DATA_SINGLE
#if LV_USE_USER_DATA
lv_indev_drv_user_data_t user_data;
#endif
@@ -143,8 +143,6 @@ typedef struct _lv_indev_proc_t
uint8_t wait_until_release : 1;
} lv_indev_proc_t;
typedef void (*lv_indev_feedback_t)(struct _lv_indev_t *, uint8_t);
struct _lv_obj_t;
struct _lv_group_t;
@@ -154,7 +152,6 @@ typedef struct _lv_indev_t
{
lv_indev_drv_t driver;
lv_indev_proc_t proc;
lv_indev_feedback_t feedback;
struct _lv_obj_t * cursor; /*Cursor for LV_INPUT_TYPE_POINTER*/
struct _lv_group_t * group; /*Keypad destination group*/
const lv_point_t * btn_points; /*Array points assigned to the button ()screen will be pressed

View File

@@ -33,7 +33,7 @@
/**********************
* STATIC PROTOTYPES
**********************/
static void anim_task(void * param);
static void anim_task(lv_task_t * param);
static bool anim_ready_handler(lv_anim_t * a);
/**********************
@@ -53,7 +53,7 @@ static bool anim_list_changed;
/**
* Init. the animation module
*/
void lv_anim_init(void)
void lv_anim_core_init(void)
{
lv_ll_init(&LV_GC_ROOT(_lv_anim_ll), sizeof(lv_anim_t));
last_task_run = lv_tick_get();
@@ -61,15 +61,30 @@ void lv_anim_init(void)
}
/**
* Create an animation
* @param anim_p an initialized 'anim_t' variable. Not required after call.
* Initialize an animation variable.
* E.g.:
* lv_anim_t a;
* lv_anim_init(&a);
* lv_anim_set_...(&a);
* lv_anim_craete(&a);
* @param a pointer to an `lv_anim_t` variable to initialize
*/
void lv_anim_create(lv_anim_t * anim_p)
void lv_anim_init(lv_anim_t * a)
{
memset(a, 0, sizeof(lv_anim_t));
a->time = 500;
a->end = 100;
}
/**
* Create an animation
* @param a an initialized 'anim_t' variable. Not required after call.
*/
void lv_anim_create(lv_anim_t * a)
{
LV_LOG_TRACE("animation create started")
/* Do not let two animations for the same 'var' with the same 'fp'*/
if(anim_p->fp != NULL)
lv_anim_del(anim_p->var, anim_p->fp); /*fp == NULL would delete all animations of var*/
if(a->exec_cb != NULL)
lv_anim_del(a->var, a->exec_cb); /*fp == NULL would delete all animations of var*/
/*Add the new animation to the animation linked list*/
lv_anim_t * new_anim = lv_ll_ins_head(&LV_GC_ROOT(_lv_anim_ll));
@@ -77,11 +92,11 @@ void lv_anim_create(lv_anim_t * anim_p)
if(new_anim == NULL) return;
/*Initialize the animation descriptor*/
anim_p->playback_now = 0;
memcpy(new_anim, anim_p, sizeof(lv_anim_t));
a->playback_now = 0;
memcpy(new_anim, a, sizeof(lv_anim_t));
/*Set the start value*/
if(new_anim->fp != NULL) new_anim->fp(new_anim->var, new_anim->start);
if(new_anim->exec_cb) new_anim->exec_cb(new_anim->var, new_anim->start);
/* Creating an animation changed the linked list.
* It's important if it happens in a ready callback. (see `anim_task`)*/
@@ -91,13 +106,13 @@ void lv_anim_create(lv_anim_t * anim_p)
}
/**
* Delete an animation for a variable with a given animator function
* Delete an animation of a variable with a given animator function
* @param var pointer to variable
* @param fp a function pointer which is animating 'var',
* or NULL to delete all animations of 'var'
* @param exec_cb a function pointer which is animating 'var',
* or NULL to delete all the animations of 'var'
* @return true: at least 1 animation is deleted, false: no animation is deleted
*/
bool lv_anim_del(void * var, lv_anim_fp_t fp)
bool lv_anim_del(void * var, lv_anim_exec_cb_t exec_cb)
{
lv_anim_t * a;
lv_anim_t * a_next;
@@ -107,7 +122,7 @@ bool lv_anim_del(void * var, lv_anim_fp_t fp)
/*'a' might be deleted, so get the next object while 'a' is valid*/
a_next = lv_ll_get_next(&LV_GC_ROOT(_lv_anim_ll), a);
if(a->var == var && (a->fp == fp || fp == NULL)) {
if(a->var == var && (a->exec_cb == exec_cb || exec_cb == NULL)) {
lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);
lv_mem_free(a);
anim_list_changed = true; /*Read by `anim_task`. It need to know if a delete occurred in
@@ -141,7 +156,7 @@ uint16_t lv_anim_count_running(void)
* @param end end value of the animation
* @return the required time [ms] for the animation with the given parameters
*/
uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end)
uint16_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end)
{
int32_t d = LV_MATH_ABS((int32_t)start - end);
uint32_t time = (int32_t)((int32_t)(d * 1000) / speed);
@@ -160,14 +175,16 @@ uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_linear(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_linear(const lv_anim_t * a)
{
/*Calculate the current step*/
uint16_t step;
if(a->time == a->act_time)
uint32_t step;
if(a->time == a->act_time) {
step = LV_ANIM_RESOLUTION; /*Use the last value if the time fully elapsed*/
else
step = (a->act_time * LV_ANIM_RESOLUTION) / a->time;
}
else {
step = ((int32_t)a->act_time * LV_ANIM_RESOLUTION) / a->time;
}
/* Get the new value which will be proportional to `step`
* and the `start` and `end` values*/
@@ -176,7 +193,7 @@ int32_t lv_anim_path_linear(const lv_anim_t * a)
new_value = new_value >> LV_ANIM_RES_SHIFT;
new_value += a->start;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -184,7 +201,7 @@ int32_t lv_anim_path_linear(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_in(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a)
{
/*Calculate the current step*/
uint32_t t;
@@ -200,7 +217,7 @@ int32_t lv_anim_path_ease_in(const lv_anim_t * a)
new_value = new_value >> 10;
new_value += a->start;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -208,7 +225,7 @@ int32_t lv_anim_path_ease_in(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_out(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a)
{
/*Calculate the current step*/
@@ -225,7 +242,7 @@ int32_t lv_anim_path_ease_out(const lv_anim_t * a)
new_value = new_value >> 10;
new_value += a->start;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -233,7 +250,7 @@ int32_t lv_anim_path_ease_out(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_in_out(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a)
{
/*Calculate the current step*/
@@ -250,7 +267,7 @@ int32_t lv_anim_path_ease_in_out(const lv_anim_t * a)
new_value = new_value >> 10;
new_value += a->start;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -258,7 +275,7 @@ int32_t lv_anim_path_ease_in_out(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_overshoot(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a)
{
/*Calculate the current step*/
@@ -275,7 +292,7 @@ int32_t lv_anim_path_overshoot(const lv_anim_t * a)
new_value = new_value >> 10;
new_value += a->start;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -283,7 +300,7 @@ int32_t lv_anim_path_overshoot(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_bounce(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a)
{
/*Calculate the current step*/
uint32_t t;
@@ -328,12 +345,11 @@ int32_t lv_anim_path_bounce(const lv_anim_t * a)
int32_t step = lv_bezier3(t, 1024, 1024, 800, 0);
int32_t new_value;
new_value = (int32_t)step * diff;
new_value = new_value >> 10;
new_value = a->end - new_value;
return new_value;
return (lv_anim_value_t)new_value;
}
/**
@@ -342,7 +358,7 @@ int32_t lv_anim_path_bounce(const lv_anim_t * a)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_step(const lv_anim_t * a)
lv_anim_value_t lv_anim_path_step(const lv_anim_t * a)
{
if(a->act_time >= a->time)
return a->end;
@@ -358,7 +374,7 @@ int32_t lv_anim_path_step(const lv_anim_t * a)
* Periodically handle the animations.
* @param param unused
*/
static void anim_task(void * param)
static void anim_task(lv_task_t * param)
{
(void)param;
@@ -369,7 +385,8 @@ static void anim_task(void * param)
}
uint32_t elaps = lv_tick_elaps(last_task_run);
a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));
a = lv_ll_get_head(&LV_GC_ROOT(_lv_anim_ll));
while(a != NULL) {
/*It can be set by `lv_anim_del()` typically in `end_cb`. If set then an animation delete
@@ -386,9 +403,10 @@ static void anim_task(void * param)
if(a->act_time > a->time) a->act_time = a->time;
int32_t new_value;
new_value = a->path(a);
new_value = a->path_cb(a);
if(a->fp != NULL) a->fp(a->var, new_value); /*Apply the calculated value*/
/*Apply the calculated value*/
if(a->exec_cb) a->exec_cb(a->var, new_value);
/*If the time is elapsed the animation is ready*/
if(a->act_time >= a->time) {
@@ -422,16 +440,17 @@ static bool anim_ready_handler(lv_anim_t * a)
* - no repeat, play back is enabled and play back is ready */
if((a->repeat == 0 && a->playback == 0) ||
(a->repeat == 0 && a->playback == 1 && a->playback_now == 1)) {
void (*cb)(void *) = a->end_cb;
void * p = a->var;
/*Create copy from the animation and delete the animation from the list.
* This way the `ready_cb` will see the animations like it's animation is ready deleted*/
lv_anim_t a_tmp;
memcpy(&a_tmp, a, sizeof(lv_anim_t));
lv_ll_rem(&LV_GC_ROOT(_lv_anim_ll), a);
lv_mem_free(a);
anim_list_changed = true;
/* Call the callback function at the end*/
/* Check if an animation is deleted in the cb function
* if yes then the caller function has to know this*/
if(cb != NULL) cb(p);
if(a_tmp.ready_cb != NULL) a_tmp.ready_cb(&a_tmp);
}
/*If the animation is not deleted then restart it*/
else {

View File

@@ -23,6 +23,7 @@ extern "C" {
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*********************
* DEFINES
@@ -34,46 +35,49 @@ extern "C" {
struct _lv_anim_t;
typedef int32_t (*lv_anim_path_t)(const struct _lv_anim_t *);
/*Type of the animated value*/
typedef int16_t lv_anim_value_t;
typedef void (*lv_anim_fp_t)(void *, int32_t);
typedef void (*lv_anim_cb_t)(void *);
/* Generic prototype of "animator" functions.
* First parameter is the variable to animate.
* Second parameter is the value to set.
* Compatible with `lv_xxx_set_yyy(obj, value)` functions*/
typedef void (*lv_anim_exec_cb_t)(void *, lv_anim_value_t);
/* Same as `lv_anim_exec_cb_t` but receives `lv_anim_t *` as the first parameter.
* It's more consistent but less convenient. Might be used by binding generator functions.*/
typedef void (*lv_anim_custom_exec_cb_t)(struct _lv_anim_t *, lv_anim_value_t);
/*Get the current value during an animation*/
typedef lv_anim_value_t (*lv_anim_path_cb_t)(const struct _lv_anim_t *);
/*Callback to call when the animation is ready*/
typedef void (*lv_anim_ready_cb_t)(struct _lv_anim_t *);
/*Describe an animation*/
typedef struct _lv_anim_t
{
void * var; /*Variable to animate*/
lv_anim_fp_t fp; /*Animator function*/
lv_anim_cb_t end_cb; /*Call it when the animation is ready*/
lv_anim_path_t path; /*An array with the steps of animations*/
lv_anim_exec_cb_t exec_cb; /*Function to execute to animate*/
lv_anim_path_cb_t path_cb; /*An array with the steps of animations*/
lv_anim_ready_cb_t ready_cb; /*Call it when the animation is ready*/
int32_t start; /*Start value*/
int32_t end; /*End value*/
uint16_t time; /*Animation time in ms*/
int16_t act_time; /*Current time in animation. Set to negative to make delay.*/
uint16_t playback_pause; /*Wait before play back*/
uint16_t repeat_pause; /*Wait before repeat*/
#if LV_USE_USER_DATA
lv_anim_user_data_t user_data; /*Custom user data*/
#endif
uint8_t playback : 1; /*When the animation is ready play it back*/
uint8_t repeat : 1; /*Repeat the animation infinitely*/
/*Animation system use these - user shouldn't set*/
uint8_t playback_now : 1; /*Play back is in progress*/
uint32_t has_run : 1; /*Indicates the animation has run it this round*/
uint32_t has_run : 1; /*Indicates the animation has run in this round*/
} lv_anim_t;
/*Example initialization
lv_anim_t a;
a.var = obj;
a.start = lv_obj_get_height(obj);
a.end = new_height;
a.fp = (lv_anim_fp_t)lv_obj_set_height;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.act_time = 0;
a.time = 200;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
lv_anim_create(&a);
*/
/**********************
* GLOBAL PROTOTYPES
**********************/
@@ -81,22 +85,192 @@ lv_anim_create(&a);
/**
* Init. the animation module
*/
void lv_anim_init(void);
void lv_anim_core_init(void);
/**
* Initialize an animation variable.
* E.g.:
* lv_anim_t a;
* lv_anim_init(&a);
* lv_anim_set_...(&a);
* lv_anim_create(&a);
* @param a pointer to an `lv_anim_t` variable to initialize
*/
void lv_anim_init(lv_anim_t * a);
/**
* Set a variable to animate function to execute on `var`
* @param a pointer to an initialized `lv_anim_t` variable
* @param var pointer to a variable to animate
* @param exec_cb a function to execute.
* LittelvGL's built-in functions can be used.
* E.g. lv_obj_set_x
*/
static inline void lv_anim_set_exec_cb(lv_anim_t * a, void * var, lv_anim_exec_cb_t exec_cb)
{
a->var = var;
a->exec_cb = exec_cb;
}
/**
* Set the duration and delay of an animation
* @param a pointer to an initialized `lv_anim_t` variable
* @param duration duration of the animation in milliseconds
* @param delay delay before the animation in milliseconds
*/
static inline void lv_anim_set_time(lv_anim_t * a, uint16_t duration, uint16_t delay)
{
a->time = duration;
a->act_time = -delay;
}
/**
* Set the start and end values of an animation
* @param a pointer to an initialized `lv_anim_t` variable
* @param start the start value
* @param end the end value
*/
static inline void lv_anim_set_values(lv_anim_t * a, lv_anim_value_t start, lv_anim_value_t end)
{
a->start = start;
a->end = end;
}
/**
* Similar to `lv_anim_set_var_and_cb` but `lv_anim_custom_exec_cb_t` receives
* `lv_anim_t * ` as its first parameter instead of `void *`.
* This function might be used when LittlevGL is binded to other languages because
* it's more consistent to have `lv_anim_t *` as first parameter.
* @param a pointer to an initialized `lv_anim_t` variable
* @param exec_cb a function to execute.
*/
static inline void lv_anim_set_custom_exec_cb(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb)
{
a->var = a;
a->exec_cb = (lv_anim_exec_cb_t)exec_cb;
}
/**
* Set the path (curve) of the animation.
* @param a pointer to an initialized `lv_anim_t` variable
* @param path_cb a function the get the current value of the animation.
* The built in functions starts with `lv_anim_path_...`
*/
static inline void lv_anim_set_path_cb(lv_anim_t * a, lv_anim_path_cb_t path_cb)
{
a->path_cb = path_cb;
}
/**
* Set a function call when the animation is ready
* @param a pointer to an initialized `lv_anim_t` variable
* @param ready_cb a function call when the animation is ready
*/
static inline void lv_anim_set_ready_cb(lv_anim_t * a, lv_anim_ready_cb_t ready_cb)
{
a->ready_cb = ready_cb;
}
/**
* Make the animation to play back to when the forward direction is ready
* @param a pointer to an initialized `lv_anim_t` variable
* @param wait_time time in milliseconds to wait before starting the back direction
*/
static inline void lv_anim_set_playback(lv_anim_t * a, uint16_t wait_time)
{
a->playback = 1;
a->playback_pause = wait_time;
}
/**
* Disable playback. (Disabled after `lv_anim_init()`)
* @param a pointer to an initialized `lv_anim_t` variable
*/
static inline void lv_anim_clear_playback(lv_anim_t * a)
{
a->playback = 0;
}
/**
* Make the animation to start again when ready.
* @param a pointer to an initialized `lv_anim_t` variable
* @param wait_time time in milliseconds to wait before starting the animation again
*/
static inline void lv_anim_set_repeat(lv_anim_t * a, uint16_t wait_time)
{
a->repeat = 1;
a->repeat_pause = wait_time;
}
/**
* Disable repeat. (Disabled after `lv_anim_init()`)
* @param a pointer to an initialized `lv_anim_t` variable
*/
static inline void lv_anim_clear_repeat(lv_anim_t * a)
{
a->repeat = 0;
}
/**
* Set a user specific data for the animation
* @param a pointer to an initialized `lv_anim_t` variable
* @param user_data the user data
*/
static inline void lv_anim_set_user_data(lv_anim_t * a, lv_anim_user_data_t user_data)
{
memcpy(&a->user_data, &user_data, sizeof(user_data));
}
/**
* Get the user data
* @param a pointer to an initialized `lv_anim_t` variable
* @return the user data
*/
static inline lv_anim_user_data_t lv_anim_get_user_data(lv_anim_t * a)
{
return a->user_data;
}
/**
* Get pointer to the user data
* @param a pointer to an initialized `lv_anim_t` variable
* @return pointer to the user data
*/
static inline lv_anim_user_data_t * lv_anim_get_user_data_ptr(lv_anim_t * a)
{
return &a->user_data;
}
/**
* Create an animation
* @param anim_p an initialized 'anim_t' variable. Not required after call.
* @param a an initialized 'anim_t' variable. Not required after call.
*/
void lv_anim_create(lv_anim_t * anim_p);
void lv_anim_create(lv_anim_t * a);
/**
* Delete an animation for a variable with a given animatior function
* Delete an animation of a variable with a given animator function
* @param var pointer to variable
* @param fp a function pointer which is animating 'var',
* or NULL to ignore it and delete all animation with 'var
* @param exec_cb a function pointer which is animating 'var',
* or NULL to ignore it and delete all the animations of 'var
* @return true: at least 1 animation is deleted, false: no animation is deleted
*/
bool lv_anim_del(void * var, lv_anim_fp_t fp);
bool lv_anim_del(void * var, lv_anim_exec_cb_t exec_cb);
/**
* Delete an aniamation by getting the animated variable from `a`.
* Only animations with `exec_cb` will be deleted.
* This function exist becasue it's logical that all anim functions receives an
* `lv_anim_t` as their first parameter. It's not practical in C but might makes
* the API more conequent and makes easier to genrate bindings.
* @param a pointer to an animation.
* @param exec_cb a function pointer which is animating 'var',
* or NULL to ignore it and delete all the animations of 'var
* @return true: at least 1 animation is deleted, false: no animation is deleted
*/
static inline bool lv_anim_custom_del(lv_anim_t * a, lv_anim_custom_exec_cb_t exec_cb)
{
return lv_anim_del(a->var, (lv_anim_exec_cb_t)exec_cb);
}
/**
* Get the number of currently running animations
@@ -111,49 +285,49 @@ uint16_t lv_anim_count_running(void);
* @param end end value of the animation
* @return the required time [ms] for the animation with the given parameters
*/
uint16_t lv_anim_speed_to_time(uint16_t speed, int32_t start, int32_t end);
uint16_t lv_anim_speed_to_time(uint16_t speed, lv_anim_value_t start, lv_anim_value_t end);
/**
* Calculate the current value of an animation applying linear characteristic
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_linear(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_linear(const lv_anim_t * a);
/**
* Calculate the current value of an animation slowing down the start phase
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_in(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_ease_in(const lv_anim_t * a);
/**
* Calculate the current value of an animation slowing down the end phase
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_out(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_ease_out(const lv_anim_t * a);
/**
* Calculate the current value of an animation applying an "S" characteristic (cosine)
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_ease_in_out(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_ease_in_out(const lv_anim_t * a);
/**
* Calculate the current value of an animation with overshoot at the end
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_overshoot(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_overshoot(const lv_anim_t * a);
/**
* Calculate the current value of an animation with 3 bounces
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_bounce(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_bounce(const lv_anim_t * a);
/**
* Calculate the current value of an animation applying step characteristic.
@@ -161,7 +335,8 @@ int32_t lv_anim_path_bounce(const lv_anim_t * a);
* @param a pointer to an animation
* @return the current value to set
*/
int32_t lv_anim_path_step(const lv_anim_t * a);
lv_anim_value_t lv_anim_path_step(const lv_anim_t * a);
/**********************
* MACROS
**********************/

View File

@@ -6,7 +6,12 @@
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../../lv_conf.h"
#endif
#include "lv_area.h"
#include "lv_math.h"
@@ -154,29 +159,6 @@ bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p)
return is_on;
}
#if LV_USE_EXTENDED_CLICK_AREA_TINY
/**
* Check if a point is on an area
* @param a_p pointer to an area
* @param p_p pointer to a point
* @param ext_hor extended horizontal padding
* @param ext_ver extended horizontal padding
* @return false:the point is out of the area
*/
bool lv_area_ext_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, uint8_t ext_hor, uint8_t ext_ver)
{
bool is_on = false;
if(( (p_p->x + ext_hor) >= a_p->x1 && p_p->x <= (a_p->x2 + ext_hor) ) &&
( (p_p->y + ext_ver) >= a_p->y1 && p_p->y <= (a_p->y2 + ext_ver)) ) {
is_on = true;
}
return is_on;
}
#endif
/**
* Check if two area has common parts
* @param a1_p pointer to an area.

View File

@@ -16,6 +16,11 @@ extern "C" {
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../../lv_conf.h"
#endif
/*********************
* DEFINES
@@ -140,18 +145,6 @@ void lv_area_join(lv_area_t * a_res_p, const lv_area_t * a1_p, const lv_area_t *
*/
bool lv_area_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p);
#if LV_USE_EXTENDED_CLICK_AREA_TINY
/**
* Check if a point is on an area
* @param a_p pointer to an area
* @param p_p pointer to a point
* @param ext_hor extended horizontal padding
* @param ext_ver extended horizontal padding
* @return false:the point is out of the area
*/
bool lv_area_ext_is_point_on(const lv_area_t * a_p, const lv_point_t * p_p, uint8_t ext_hor, uint8_t ext_ver);
#endif
/**
* Check if two area has common parts
* @param a1_p pointer to an area.

View File

@@ -37,6 +37,7 @@ extern "C" {
prefix lv_ll_t _lv_file_ll; \
prefix lv_ll_t _lv_anim_ll; \
prefix lv_ll_t _lv_group_ll; \
prefix lv_ll_t _lv_img_defoder_ll; \
prefix void * _lv_task_act;
#define LV_NO_PREFIX

View File

@@ -214,22 +214,39 @@ void lv_ll_clear(lv_ll_t * ll_p)
* @param ll_ori_p pointer to the original (old) linked list
* @param ll_new_p pointer to the new linked list
* @param node pointer to a node
* @param head true: be the head in the new list
* false be the head in the new list
*/
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node)
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head)
{
lv_ll_rem(ll_ori_p, node);
/*Set node as head*/
node_set_prev(ll_new_p, node, NULL);
node_set_next(ll_new_p, node, ll_new_p->head);
if(head) {
/*Set node as head*/
node_set_prev(ll_new_p, node, NULL);
node_set_next(ll_new_p, node, ll_new_p->head);
if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
node_set_prev(ll_new_p, ll_new_p->head, node);
}
if(ll_new_p->head != NULL) { /*If there is old head then before it goes the new*/
node_set_prev(ll_new_p, ll_new_p->head, node);
}
ll_new_p->head = node; /*Set the new head in the dsc.*/
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
ll_new_p->tail = node;
ll_new_p->head = node; /*Set the new head in the dsc.*/
if(ll_new_p->tail == NULL) { /*If there is no tail (first node) set the tail too*/
ll_new_p->tail = node;
}
} else {
/*Set node as tail*/
node_set_prev(ll_new_p, node, ll_new_p->tail);
node_set_next(ll_new_p, node, NULL);
if(ll_new_p->tail != NULL) { /*If there is old tail then after it goes the new*/
node_set_next(ll_new_p, ll_new_p->tail, node);
}
ll_new_p->tail = node; /*Set the new tail in the dsc.*/
if(ll_new_p->head == NULL) { /*If there is no head (first node) set the head too*/
ll_new_p->head = node;
}
}
}
@@ -301,6 +318,22 @@ void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act)
return prev;
}
/**
* Return the length of the linked list.
* @param ll_p pointer to linked list
* @return length of the linked list
*/
uint32_t lv_ll_get_len(const lv_ll_t *ll_p){
uint32_t len = 0;
void * node;
for(node=lv_ll_get_head(ll_p); node!=NULL; node=lv_ll_get_next(ll_p, node)) {
len++;
}
return len;
}
void lv_ll_swap(lv_ll_t * ll_p, void * n1_p, void * n2_p)
{
(void)(ll_p);
@@ -338,6 +371,9 @@ void lv_ll_move_before(lv_ll_t * ll_p, void * n_act, void * n_after)
/*If `n_act` was moved before NULL then it become the new tail*/
if(n_after == NULL) ll_p->tail = n_act;
/*If `n_act` was moved before `NULL` then it's the new head*/
if(n_before == NULL) ll_p->head = n_act;
}
/**

View File

@@ -89,8 +89,10 @@ void lv_ll_clear(lv_ll_t * ll_p);
* @param ll_ori_p pointer to the original (old) linked list
* @param ll_new_p pointer to the new linked list
* @param node pointer to a node
* @param head true: be the head in the new list
* false be the head in the new list
*/
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node);
void lv_ll_chg_list(lv_ll_t * ll_ori_p, lv_ll_t * ll_new_p, void * node, bool head);
/**
* Return with head node of the linked list
@@ -122,6 +124,13 @@ void * lv_ll_get_next(const lv_ll_t * ll_p, const void * n_act);
*/
void * lv_ll_get_prev(const lv_ll_t * ll_p, const void * n_act);
/**
* Return the length of the linked list.
* @param ll_p pointer to linked list
* @return length of the linked list
*/
uint32_t lv_ll_get_len(const lv_ll_t *ll_p);
/**
* Move a nodw before an other node in the same linked list
* @param ll_p pointer to a linked list

View File

@@ -27,7 +27,7 @@
/**********************
* STATIC VARIABLES
**********************/
static void (*print_cb)(lv_log_level_t, const char *, uint32_t, const char *);
static lv_log_print_g_cb_t custom_print_cb;
/**********************
* MACROS
@@ -38,14 +38,14 @@ static void (*print_cb)(lv_log_level_t, const char *, uint32_t, const char *);
**********************/
/**
* Register custom print (or anything else) function to call when log is added
* @param f a function pointer:
* `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char *
* dsc)`
* Register custom print/write function to call when a log is added.
* It can format its "File path", "Line number" and "Description" as required
* and send the formatted log message to a consol or serial port.
* @param print_cb a function pointer to print a log
*/
void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *))
void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb)
{
print_cb = f;
custom_print_cb = print_cb;
}
/**
@@ -65,7 +65,7 @@ void lv_log_add(lv_log_level_t level, const char * file, int line, const char *
static const char * lvl_prefix[] = {"Trace", "Info", "Warn", "Error"};
printf("%s: %s \t(%s #%d)\n", lvl_prefix[level], dsc, file, line);
#else
if(print_cb) print_cb(level, file, line, dsc);
if(custom_print_cb) custom_print_cb(level, file, line, dsc);
#endif
}
}

View File

@@ -39,17 +39,22 @@ typedef int8_t lv_log_level_t;
* TYPEDEFS
**********************/
/**
* Log print function. Receives "Log Level", "File path", "Line number" and "Description".
*/
typedef void (*lv_log_print_g_cb_t) (lv_log_level_t level, const char *, uint32_t, const char *);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Register custom print (or anything else) function to call when log is added
* @param f a function pointer:
* `void my_print (lv_log_level_t level, const char * file, uint32_t line, const char *
* dsc)`
* Register custom print/write function to call when a log is added.
* It can format its "File path", "Line number" and "Description" as required
* and send the formatted log message to a consol or serial port.
* @param print_cb a function pointer to print a log
*/
void lv_log_register_print(void f(lv_log_level_t, const char *, uint32_t, const char *));
void lv_log_register_print_cb(lv_log_print_g_cb_t print_cb);
/**
* Add a log

View File

@@ -19,7 +19,7 @@
* DEFINES
*********************/
/*Add memory junk on alloc (0xaa) and free(0xbb) (just for testing purposes)*/
#define LV_MEM_ADD_JUNK 0
#define LV_MEM_ADD_JUNK 1
#ifdef LV_MEM_ENV64
#define MEM_UNIT uint64_t
@@ -126,7 +126,9 @@ void * lv_mem_alloc(uint32_t size)
#endif
void * alloc = NULL;
#if LV_MEM_CUSTOM == 0 /*Use the allocation from dyn_mem*/
#if LV_MEM_CUSTOM == 0
/*Use the built-in allocators*/
lv_mem_ent_t * e = NULL;
// Search for a appropriate entry
@@ -141,7 +143,8 @@ void * lv_mem_alloc(uint32_t size)
// End if there is not next entry OR the alloc. is successful
} while(e != NULL && alloc == NULL);
#else /*Use custom, user defined malloc function*/
#else
/*Use custom, user defined malloc function*/
#if LV_ENABLE_GC == 1 /*gc must not include header*/
alloc = LV_MEM_CUSTOM_ALLOC(size);
#else /* LV_ENABLE_GC */
@@ -150,6 +153,7 @@ void * lv_mem_alloc(uint32_t size)
if(alloc != NULL) {
((lv_mem_ent_t *)alloc)->header.s.d_size = size;
((lv_mem_ent_t *)alloc)->header.s.used = 1;
alloc = &((lv_mem_ent_t *)alloc)->first_data;
}
#endif /* LV_ENABLE_GC */

View File

@@ -20,6 +20,8 @@
* DEFINES
*********************/
#define IDLE_MEAS_PERIOD 500 /*[ms]*/
#define DEF_PRIO LV_TASK_PRIO_MID
#define DEF_PERIOD 500
/**********************
* TYPEDEFS
@@ -28,7 +30,7 @@
/**********************
* STATIC PROTOTYPES
**********************/
static bool lv_task_exec(lv_task_t * lv_task_p);
static bool lv_task_exec(lv_task_t * task);
/**********************
* STATIC VARIABLES
@@ -49,7 +51,7 @@ static bool task_created;
/**
* Init the lv_task module
*/
void lv_task_init(void)
void lv_task_core_init(void)
{
lv_ll_init(&LV_GC_ROOT(_lv_task_ll), sizeof(lv_task_t));
@@ -138,7 +140,7 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
if(task_deleted)
break; /*If a task was deleted then this or the next item might be corrupted*/
if(task_created)
break; /*If a task was deleted then this or the next item might be corrupted*/
break; /*If a task was created then this or the next item might be corrupted*/
LV_GC_ROOT(_lv_task_act) = next; /*Load the next task*/
}
@@ -159,130 +161,168 @@ LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void)
LV_LOG_TRACE("lv_task_handler ready");
}
/**
* Create an "empty" task. It needs to initialzed with at least
* `lv_task_set_cb` and `lv_task_set_period`
* @return pointer to the craeted task
*/
lv_task_t * lv_task_create_basic(void)
{
lv_task_t * new_task = NULL;
lv_task_t * tmp;
/*Create task lists in order of priority from high to low*/
tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
/*It's the first task*/
if(NULL == tmp) {
new_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
lv_mem_assert(new_task);
if(new_task == NULL) return NULL;
}
/*Insert the new task to proper place according to its priority*/
else {
do {
if(tmp->prio <= DEF_PRIO) {
new_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
lv_mem_assert(new_task);
if(new_task == NULL) return NULL;
break;
}
tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);
} while(tmp != NULL);
/*Only too high priority tasks were found. Add the task to the end*/
if(tmp == NULL) {
new_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
lv_mem_assert(new_task);
if(new_task == NULL) return NULL;
}
}
new_task->period = DEF_PERIOD;
new_task->task_cb = NULL;
new_task->prio = DEF_PRIO;
new_task->once = 0;
new_task->last_run = lv_tick_get();
new_task->user_data= NULL;
task_created = true;
return new_task;
}
/**
* Create a new lv_task
* @param task a function which is the task itself
* @param period call period in ms unit
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
* @param param free parameter
* @param user_data custom parameter
* @return pointer to the new task
*/
lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio, void * param)
lv_task_t * lv_task_create(lv_task_cb_t task_cb, uint32_t period, lv_task_prio_t prio, void * user_data)
{
lv_task_t * new_lv_task = NULL;
lv_task_t * tmp;
lv_task_t * new_task = lv_task_create_basic();
lv_mem_assert(new_task);
if(new_task == NULL) return NULL;
/*Create task lists in order of priority from high to low*/
tmp = lv_ll_get_head(&LV_GC_ROOT(_lv_task_ll));
if(NULL == tmp) { /*First task*/
new_lv_task = lv_ll_ins_head(&LV_GC_ROOT(_lv_task_ll));
lv_mem_assert(new_lv_task);
if(new_lv_task == NULL) return NULL;
} else {
do {
if(tmp->prio <= prio) {
new_lv_task = lv_ll_ins_prev(&LV_GC_ROOT(_lv_task_ll), tmp);
lv_mem_assert(new_lv_task);
if(new_lv_task == NULL) return NULL;
break;
}
tmp = lv_ll_get_next(&LV_GC_ROOT(_lv_task_ll), tmp);
} while(tmp != NULL);
lv_task_set_cb(new_task, task_cb);
lv_task_set_period(new_task, period);
lv_task_set_prio(new_task, prio);
new_task->user_data = user_data;
if(tmp == NULL) { /*Only too high priority tasks were found*/
new_lv_task = lv_ll_ins_tail(&LV_GC_ROOT(_lv_task_ll));
lv_mem_assert(new_lv_task);
if(new_lv_task == NULL) return NULL;
}
}
return new_task;
}
new_lv_task->period = period;
new_lv_task->task = task;
new_lv_task->prio = prio;
new_lv_task->param = param;
new_lv_task->once = 0;
new_lv_task->last_run = lv_tick_get();
task_created = true;
return new_lv_task;
/**
* Set the callback the task (the function to call periodically)
* @param task pointer to a task
* @param task_cb teh function to call periodically
*/
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb)
{
task->task_cb = task_cb;
}
/**
* Delete a lv_task
* @param lv_task_p pointer to task created by lv_task_p
* @param task pointer to task created by task
*/
void lv_task_del(lv_task_t * lv_task_p)
void lv_task_del(lv_task_t * task)
{
lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), lv_task_p);
lv_ll_rem(&LV_GC_ROOT(_lv_task_ll), task);
lv_mem_free(lv_task_p);
lv_mem_free(task);
if(LV_GC_ROOT(_lv_task_act) == lv_task_p) task_deleted = true; /*The active task was deleted*/
if(LV_GC_ROOT(_lv_task_act) == task) task_deleted = true; /*The active task was deleted*/
}
/**
* Set new priority for a lv_task
* @param lv_task_p pointer to a lv_task
* @param task pointer to a lv_task
* @param prio the new priority
*/
void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio)
void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio)
{
if(task->prio == prio) return;
/*Find the tasks with new priority*/
lv_task_t * i;
LV_LL_READ(LV_GC_ROOT(_lv_task_ll), i)
{
if(i->prio <= prio) {
if(i != lv_task_p) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, i);
if(i != task) lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, i);
break;
}
}
/*There was no such a low priority so far then add the node to the tail*/
if(i == NULL) {
lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), lv_task_p, NULL);
lv_ll_move_before(&LV_GC_ROOT(_lv_task_ll), task, NULL);
}
lv_task_p->prio = prio;
task->prio = prio;
}
/**
* Set new period for a lv_task
* @param lv_task_p pointer to a lv_task
* @param task pointer to a lv_task
* @param period the new period
*/
void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period)
void lv_task_set_period(lv_task_t * task, uint32_t period)
{
lv_task_p->period = period;
task->period = period;
}
/**
* Make a lv_task ready. It will not wait its period.
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_ready(lv_task_t * lv_task_p)
void lv_task_ready(lv_task_t * task)
{
lv_task_p->last_run = lv_tick_get() - lv_task_p->period - 1;
task->last_run = lv_tick_get() - task->period - 1;
}
/**
* Delete the lv_task after one call
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_once(lv_task_t * lv_task_p)
void lv_task_once(lv_task_t * task)
{
lv_task_p->once = 1;
task->once = 1;
}
/**
* Reset a lv_task.
* It will be called the previously set period milliseconds later.
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_reset(lv_task_t * lv_task_p)
void lv_task_reset(lv_task_t * task)
{
lv_task_p->last_run = lv_tick_get();
task->last_run = lv_tick_get();
}
/**
@@ -309,25 +349,25 @@ uint8_t lv_task_get_idle(void)
/**
* Execute task if its the priority is appropriate
* @param lv_task_p pointer to lv_task
* @param task pointer to lv_task
* @return true: execute, false: not executed
*/
static bool lv_task_exec(lv_task_t * lv_task_p)
static bool lv_task_exec(lv_task_t * task)
{
bool exec = false;
/*Execute if at least 'period' time elapsed*/
uint32_t elp = lv_tick_elaps(lv_task_p->last_run);
if(elp >= lv_task_p->period) {
lv_task_p->last_run = lv_tick_get();
uint32_t elp = lv_tick_elaps(task->last_run);
if(elp >= task->period) {
task->last_run = lv_tick_get();
task_deleted = false;
task_created = false;
lv_task_p->task(lv_task_p->param);
if(task->task_cb) task->task_cb(task);
/*Delete if it was a one shot lv_task*/
if(task_deleted == false) { /*The task might be deleted by itself as well*/
if(lv_task_p->once != 0) {
lv_task_del(lv_task_p);
if(task->once != 0) {
lv_task_del(task);
}
}
exec = true;

View File

@@ -34,6 +34,14 @@ extern "C" {
/**********************
* TYPEDEFS
**********************/
struct _lv_task_t;
/**
* Tasks execte this type type of functions.
*/
typedef void (*lv_task_cb_t)(struct _lv_task_t *);
/**
* Possible priorities for lv_tasks
*/
@@ -51,12 +59,14 @@ typedef uint8_t lv_task_prio_t;
/**
* Descriptor of a lv_task
*/
typedef struct
typedef struct _lv_task_t
{
uint32_t period;
uint32_t last_run;
void (*task)(void *);
void * param;
lv_task_cb_t task_cb;
void * user_data;
uint8_t prio : 3;
uint8_t once : 1;
} lv_task_t;
@@ -68,62 +78,75 @@ typedef struct
/**
* Init the lv_task module
*/
void lv_task_init(void);
void lv_task_core_init(void);
/**
* Call it periodically to handle lv_tasks.
*/
LV_ATTRIBUTE_TASK_HANDLER void lv_task_handler(void);
/**
* Create an "empty" task. It needs to initialzed with at least
* `lv_task_set_cb` and `lv_task_set_period`
* @return pointer to the craeted task
*/
lv_task_t * lv_task_create_basic(void);
/**
* Create a new lv_task
* @param task a function which is the task itself
* @param period call period in ms unit
* @param prio priority of the task (LV_TASK_PRIO_OFF means the task is stopped)
* @param param free parameter
* @param user_data custom parameter
* @return pointer to the new task
*/
lv_task_t * lv_task_create(void (*task)(void *), uint32_t period, lv_task_prio_t prio,
void * param);
lv_task_t * lv_task_create(lv_task_cb_t task_cb, uint32_t period, lv_task_prio_t prio, void * user_data);
/**
* Delete a lv_task
* @param lv_task_p pointer to task created by lv_task_p
* @param task pointer to task_cb created by task
*/
void lv_task_del(lv_task_t * lv_task_p);
void lv_task_del(lv_task_t * task);
/**
* Set the callback the task (the function to call periodically)
* @param task pointer to a task
* @param task_cb the function to call periodically
*/
void lv_task_set_cb(lv_task_t * task, lv_task_cb_t task_cb);
/**
* Set new priority for a lv_task
* @param lv_task_p pointer to a lv_task
* @param task pointer to a lv_task
* @param prio the new priority
*/
void lv_task_set_prio(lv_task_t * lv_task_p, lv_task_prio_t prio);
void lv_task_set_prio(lv_task_t * task, lv_task_prio_t prio);
/**
* Set new period for a lv_task
* @param lv_task_p pointer to a lv_task
* @param task pointer to a lv_task
* @param period the new period
*/
void lv_task_set_period(lv_task_t * lv_task_p, uint32_t period);
void lv_task_set_period(lv_task_t * task, uint32_t period);
/**
* Make a lv_task ready. It will not wait its period.
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_ready(lv_task_t * lv_task_p);
void lv_task_ready(lv_task_t * task);
/**
* Delete the lv_task after one call
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_once(lv_task_t * lv_task_p);
void lv_task_once(lv_task_t * task);
/**
* Reset a lv_task.
* It will be called the previously set period milliseconds later.
* @param lv_task_p pointer to a lv_task.
* @param task pointer to a lv_task.
*/
void lv_task_reset(lv_task_t * lv_task_p);
void lv_task_reset(lv_task_t * task);
/**
* Enable or disable the whole lv_task handling

View File

@@ -38,6 +38,7 @@
**********************/
static bool is_break_char(uint32_t letter);
#if LV_TXT_ENC == LV_TXT_ENC_UTF8
static uint8_t lv_txt_utf8_size(const char * str);
static uint32_t lv_txt_unicode_to_utf8(uint32_t letter_uni);
static uint32_t lv_txt_utf8_conv_wc(uint32_t c);
@@ -46,7 +47,16 @@ static uint32_t lv_txt_utf8_prev(const char * txt, uint32_t * i_start);
static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id);
static uint32_t lv_txt_utf8_get_char_id(const char * txt, uint32_t byte_id);
static uint32_t lv_txt_utf8_get_length(const char * txt);
#elif LV_TXT_ENC == LV_TXT_ENC_ASCII
static uint8_t lv_txt_iso8859_1_size(const char * str);
static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni);
static uint32_t lv_txt_iso8859_1_conv_wc(uint32_t c);
static uint32_t lv_txt_iso8859_1_next(const char * txt, uint32_t * i);
static uint32_t lv_txt_iso8859_1_prev(const char * txt, uint32_t * i_start);
static uint32_t lv_txt_iso8859_1_get_byte_id(const char * txt, uint32_t utf8_id);
static uint32_t lv_txt_iso8859_1_get_char_id(const char * txt, uint32_t byte_id);
static uint32_t lv_txt_iso8859_1_get_length(const char * txt);
#endif
/**********************
* STATIC VARIABLES
**********************/
@@ -54,6 +64,7 @@ static uint32_t lv_txt_utf8_get_length(const char * txt);
/**********************
* GLOBAL VARIABLES
**********************/
#if LV_TXT_ENC == LV_TXT_ENC_UTF8
uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_utf8_size;
uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_utf8;
uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_utf8_conv_wc;
@@ -62,6 +73,17 @@ uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_utf8_pre
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_utf8_get_byte_id;
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_utf8_get_char_id;
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_utf8_get_length;
#elif LV_TXT_ENC == LV_TXT_ENC_ASCII
uint8_t (*lv_txt_encoded_size)(const char *) = lv_txt_iso8859_1_size;
uint32_t (*lv_txt_unicode_to_encoded)(uint32_t) = lv_txt_unicode_to_iso8859_1;
uint32_t (*lv_txt_encoded_conv_wc)(uint32_t) = lv_txt_iso8859_1_conv_wc;
uint32_t (*lv_txt_encoded_next)(const char *, uint32_t *) = lv_txt_iso8859_1_next;
uint32_t (*lv_txt_encoded_prev)(const char *, uint32_t *) = lv_txt_iso8859_1_prev;
uint32_t (*lv_txt_encoded_get_byte_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_byte_id;
uint32_t (*lv_encoded_get_char_id)(const char *, uint32_t) = lv_txt_iso8859_1_get_char_id;
uint32_t (*lv_txt_get_encoded_length)(const char *) = lv_txt_iso8859_1_get_length;
#endif
/**********************
* MACROS
@@ -313,7 +335,7 @@ lv_coord_t lv_txt_get_width(const char * txt, uint16_t length, const lv_font_t *
lv_coord_t char_width = lv_font_get_width(font, letter);
if(char_width > 0) {
width += lv_font_get_width(font, letter);
width += char_width;
width += letter_space;
}
}
@@ -413,6 +435,7 @@ void lv_txt_cut(char * txt, uint32_t pos, uint32_t len)
}
}
#if LV_TXT_ENC == LV_TXT_ENC_UTF8
/*******************************
* UTF-8 ENCODER/DECOER
******************************/
@@ -654,6 +677,121 @@ static uint32_t lv_txt_utf8_get_length(const char * txt)
return len;
}
#elif LV_TXT_ENC == LV_TXT_ENC_ASCII
/*******************************
* ASCII ENCODER/DECOER
******************************/
/**
* Give the size of an ISO8859-1 coded character
* @param str pointer to a character in a string
* @return length of the UTF-8 character (1,2,3 or 4). O on invalid code
*/
static uint8_t lv_txt_iso8859_1_size(const char * str)
{
(void) str; /*Unused*/
return 1;
}
/**
* Convert an Unicode letter to ISO8859-1.
* @param letter_uni an Unicode letter
* @return ISO8859-1 coded character in Little Endian to be compatible with C chars (e.g. 'Á', 'Ű')
*/
static uint32_t lv_txt_unicode_to_iso8859_1(uint32_t letter_uni)
{
if(letter_uni < 128) return letter_uni;
else return ' ';
}
/**
* Convert wide characters to ASCII, however wide characters in ASCII range (e.g. 'A') are ASCII compatible by default.
* So this function does nothing just returns with `c`.
* @param c a character, e.g. 'A'
* @return same as `c`
*/
static uint32_t lv_txt_iso8859_1_conv_wc(uint32_t c)
{
return c;
}
/**
* Decode an ISO8859-1 character from a string.
* @param txt pointer to '\0' terminated string
* @param i start byte index in 'txt' where to start.
* After call it will point to the next UTF-8 char in 'txt'.
* NULL to use txt[0] as index
* @return the decoded Unicode character or 0 on invalid UTF-8 code
*/
static uint32_t lv_txt_iso8859_1_next(const char * txt, uint32_t * i)
{
if(i == NULL) return txt[1]; /*Get the next char */
uint8_t letter = txt[*i] ;
(*i)++;
return letter;
}
/**
* Get previous ISO8859-1 character form a string.
* @param txt pointer to '\0' terminated string
* @param i start byte index in 'txt' where to start. After the call it will point to the previous UTF-8 char in 'txt'.
* @return the decoded Unicode character or 0 on invalid UTF-8 code
*/
static uint32_t lv_txt_iso8859_1_prev(const char * txt, uint32_t * i)
{
if(i == NULL) return *(txt - 1); /*Get the prev. char */
(*i)--;
uint8_t letter = txt[*i] ;
return letter;
}
/**
* Convert a character index (in an ISO8859-1 text) to byte index.
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
* @param txt a '\0' terminated UTF-8 string
* @param utf8_id character index
* @return byte index of the 'utf8_id'th letter
*/
static uint32_t lv_txt_iso8859_1_get_byte_id(const char * txt, uint32_t utf8_id)
{
(void) txt; /*Unused*/
return utf8_id; /*In Non encoded no difference*/
}
/**
* Convert a byte index (in an ISO8859-1 text) to character index.
* E.g. in "AÁRT" index of 'R' is 2th char but start at byte 3 because 'Á' is 2 bytes long
* @param txt a '\0' terminated UTF-8 string
* @param byte_id byte index
* @return character index of the letter at 'byte_id'th position
*/
static uint32_t lv_txt_iso8859_1_get_char_id(const char * txt, uint32_t byte_id)
{
(void) txt; /*Unused*/
return byte_id; /*In Non encoded no difference*/
}
/**
* Get the number of characters (and NOT bytes) in a string. Decode it with UTF-8 if enabled.
* E.g.: "ÁBC" is 3 characters (but 4 bytes)
* @param txt a '\0' terminated char string
* @return number of characters
*/
static uint32_t lv_txt_iso8859_1_get_length(const char * txt)
{
return strlen(txt);
}
#else
#error "Invalid character encoding. See `LV_TXT_ENC` in `lv_conf.h`"
#endif
/**********************
* STATIC FUNCTIONS
**********************/

View File

@@ -29,6 +29,9 @@ extern "C" {
*********************/
#define LV_TXT_COLOR_CMD "#"
#define LV_TXT_ENC_UTF8 1
#define LV_TXT_ENC_ASCII 2
/**********************
* TYPEDEFS
**********************/

44
src/lv_misc/lv_types.h Normal file
View File

@@ -0,0 +1,44 @@
/**
* @file lv_types.h
*
*/
#ifndef LV_TYPES_H
#define LV_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
enum {
LV_RES_INV = 0, /*Typically indicates that the object is deleted (become invalid) in the action
function or an operation was failed*/
LV_RES_OK, /*The object is valid (no deleted) after the action*/
};
typedef uint8_t lv_res_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_TYPES_H*/

View File

@@ -30,8 +30,10 @@
static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode_t mode);
static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param);
static void lv_bar_animate(void * bar, int32_t value);
static void lv_bar_anim_ready(void * bar);
#if LV_USE_ANIMATION
static void lv_bar_anim(void * bar, lv_anim_value_t value);
static void lv_bar_anim_ready(lv_anim_t * a);
#endif
/**********************
* STATIC VARIABLES
@@ -73,10 +75,12 @@ lv_obj_t * lv_bar_create(lv_obj_t * par, const lv_obj_t * copy)
ext->min_value = 0;
ext->max_value = 100;
ext->cur_value = 0;
#if LV_USE_ANIMATION
ext->anim_time = 200;
ext->anim_start = 0;
ext->anim_end = 0;
ext->anim_state = LV_BAR_ANIM_STATE_INV;
#endif
ext->sym = 0;
ext->style_indic = &lv_style_pretty_color;
@@ -158,9 +162,9 @@ void lv_bar_set_value(lv_obj_t * bar, int16_t value, bool anim)
a.var = bar;
a.start = LV_BAR_ANIM_STATE_START;
a.end = LV_BAR_ANIM_STATE_END;
a.fp = (lv_anim_fp_t)lv_bar_animate;
a.path = lv_anim_path_linear;
a.end_cb = lv_bar_anim_ready;
a.exec_cb = (lv_anim_exec_cb_t)lv_bar_anim;
a.path_cb = lv_anim_path_linear;
a.ready_cb = lv_bar_anim_ready;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
@@ -241,10 +245,11 @@ int16_t lv_bar_get_value(const lv_obj_t * bar)
{
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
/*If animated tell that it's already at the end value*/
#if LV_USE_ANIMATION
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) return ext->anim_end;
#endif
/*No animation, simple return the current value*/
else
return ext->cur_value;
return ext->cur_value;
}
/**
@@ -340,8 +345,11 @@ static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode
#endif
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
if(ext->cur_value != ext->min_value || ext->sym ||
ext->anim_start != LV_BAR_ANIM_STATE_INV) {
if(ext->cur_value != ext->min_value || ext->sym
#if LV_USE_ANIMATION
|| ext->anim_start != LV_BAR_ANIM_STATE_INV
#endif
) {
const lv_style_t * style_indic = lv_bar_get_style(bar, LV_BAR_STYLE_INDIC);
lv_area_t indic_area;
lv_area_copy(&indic_area, &bar->coords);
@@ -355,6 +363,7 @@ static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode
if(w >= h) {
/*Horizontal*/
#if LV_USE_ANIMATION
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
/*Calculate the coordinates of anim. start and end*/
lv_coord_t anim_start_x =
@@ -369,7 +378,9 @@ static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode
indic_area.x2 =
anim_start_x +
(((anim_end_x - anim_start_x) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
} else {
}else
#endif
{
indic_area.x2 = (int32_t)((int32_t)w * (ext->cur_value - ext->min_value)) /
(ext->max_value - ext->min_value);
}
@@ -388,6 +399,7 @@ static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode
}
}
} else {
#if LV_USE_ANIMATION
if(ext->anim_state != LV_BAR_ANIM_STATE_INV) {
/*Calculate the coordinates of anim. start and end*/
lv_coord_t anim_start_y =
@@ -402,7 +414,9 @@ static bool lv_bar_design(lv_obj_t * bar, const lv_area_t * mask, lv_design_mode
indic_area.y1 =
anim_start_y +
(((anim_end_y - anim_start_y) * ext->anim_state) >> LV_BAR_ANIM_STATE_NORM);
} else {
} else
#endif
{
indic_area.y1 = (int32_t)((int32_t)h * (ext->cur_value - ext->min_value)) /
(ext->max_value - ext->min_value);
}
@@ -475,18 +489,20 @@ static lv_res_t lv_bar_signal(lv_obj_t * bar, lv_signal_t sign, void * param)
return res;
}
static void lv_bar_animate(void * bar, int32_t value)
#if LV_USE_ANIMATION
static void lv_bar_anim(void * bar, lv_anim_value_t value)
{
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
ext->anim_state = value;
lv_obj_invalidate(bar);
}
static void lv_bar_anim_ready(void * bar)
static void lv_bar_anim_ready(lv_anim_t * a)
{
lv_bar_ext_t * ext = lv_obj_get_ext_attr(bar);
lv_bar_ext_t * ext = lv_obj_get_ext_attr(a->var);
ext->anim_state = LV_BAR_ANIM_STATE_INV;
lv_bar_set_value(bar, ext->anim_end, false);
lv_bar_set_value(a->var, ext->anim_end, false);
}
#endif
#endif

View File

@@ -22,10 +22,12 @@ extern "C" {
#if LV_USE_BAR != 0
#include "../lv_core/lv_obj.h"
#include "../lv_misc/lv_anim.h"
#include "lv_cont.h"
#include "lv_btn.h"
#include "lv_label.h"
/*********************
* DEFINES
*********************/
@@ -46,10 +48,12 @@ typedef struct
int16_t cur_value; /*Current value of the bar*/
int16_t min_value; /*Minimum value of the bar*/
int16_t max_value; /*Maximum value of the bar*/
int16_t anim_start;
int16_t anim_end;
int16_t anim_state;
uint16_t anim_time;
#if LV_USE_ANIMATION
lv_anim_value_t anim_start;
lv_anim_value_t anim_end;
lv_anim_value_t anim_state;
lv_anim_value_t anim_time;
#endif
uint8_t sym : 1; /*Symmetric: means the center is around zero value*/
const lv_style_t * style_indic; /*Style of the indicator*/
} lv_bar_ext_t;

View File

@@ -35,8 +35,8 @@ static bool lv_btn_design(lv_obj_t * btn, const lv_area_t * mask, lv_design_mode
static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param);
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val);
static void lv_btn_ink_effect_anim_ready(void * p);
static void lv_btn_ink_effect_anim(lv_obj_t * btn, lv_anim_value_t val);
static void lv_btn_ink_effect_anim_ready(lv_anim_t * a);
#endif
/**********************
@@ -502,7 +502,7 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
/*Forget the old inked button*/
if(ink_obj != NULL && ink_obj != btn) {
lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);
lv_anim_del(ink_obj, (lv_anim_exec_cb_t)lv_btn_ink_effect_anim);
lv_obj_invalidate(ink_obj);
ink_obj = NULL;
}
@@ -517,9 +517,9 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
a.var = btn;
a.start = 0;
a.end = LV_BTN_INK_VALUE_MAX;
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
a.path = lv_anim_path_linear;
a.end_cb = lv_btn_ink_effect_anim_ready;
a.exec_cb = (lv_anim_exec_cb_t)lv_btn_ink_effect_anim;
a.path_cb = lv_anim_path_linear;
a.ready_cb = lv_btn_ink_effect_anim_ready;
a.act_time = 0;
a.time = ext->ink_in_time;
a.playback = 0;
@@ -586,9 +586,9 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
a.var = ink_obj;
a.start = LV_BTN_INK_VALUE_MAX;
a.end = 0;
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
a.path = lv_anim_path_linear;
a.end_cb = lv_btn_ink_effect_anim_ready;
a.exec_cb = (lv_anim_exec_cb_t)lv_btn_ink_effect_anim;
a.path_cb = lv_anim_path_linear;
a.ready_cb = lv_btn_ink_effect_anim_ready;
a.act_time = 0;
a.time = ext->ink_out_time;
a.playback = 0;
@@ -606,25 +606,10 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
} else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) {
if(lv_btn_get_toggle(btn)) lv_btn_set_state(btn, LV_BTN_STATE_REL);
}
// else if(c == LV_KEY_ENTER) {
// if(lv_btn_get_toggle(btn)) {
// if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR)
// lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL); else if(state ==
// LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR)
// lv_btn_set_state(btn, LV_BTN_STATE_REL);
// } else {
// if(state == LV_BTN_STATE_REL || state == LV_BTN_STATE_PR)
// lv_btn_set_state(btn, LV_BTN_STATE_REL); else if(state ==
// LV_BTN_STATE_TGL_REL || state == LV_BTN_STATE_TGL_PR)
// lv_btn_set_state(btn, LV_BTN_STATE_TGL_REL);
// }
// res = lv_obj_send_event(btn, LV_EVENT_VALUE_CHANGED);
// if(res != LV_RES_OK) return res;
// }
} else if(sign == LV_SIGNAL_CLEANUP) {
#if LV_USE_ANIMATION && LV_BTN_INK_EFFECT
if(btn == ink_obj) {
lv_anim_del(ink_obj, (lv_anim_fp_t)lv_btn_ink_effect_anim);
lv_anim_del(ink_obj, (lv_anim_exec_cb_t)lv_btn_ink_effect_anim);
ink_obj = NULL;
}
#endif
@@ -647,7 +632,7 @@ static lv_res_t lv_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * param)
* @param btn pointer to the animated button
* @param val the new radius
*/
static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val)
static void lv_btn_ink_effect_anim(lv_obj_t * btn, lv_anim_value_t val)
{
if(btn) {
ink_act_value = val;
@@ -657,11 +642,11 @@ static void lv_btn_ink_effect_anim(lv_obj_t * btn, int32_t val)
/**
* Called to clean up when the ink animation is ready
* @param p unused
* @param a unused
*/
static void lv_btn_ink_effect_anim_ready(void * p)
static void lv_btn_ink_effect_anim_ready(lv_anim_t * a)
{
(void)p; /*Unused*/
(void) a; /*Unused*/
lv_btn_ext_t * ext = lv_obj_get_ext_attr(ink_obj);
lv_btn_state_t state = lv_btn_get_state(ink_obj);
@@ -671,20 +656,20 @@ static void lv_btn_ink_effect_anim_ready(void * p)
if((state == LV_BTN_STATE_REL || state == LV_BTN_STATE_TGL_REL) && ext->toggle == 0 &&
ink_playback == false) {
lv_anim_t a;
a.var = ink_obj;
a.start = LV_BTN_INK_VALUE_MAX;
a.end = 0;
a.fp = (lv_anim_fp_t)lv_btn_ink_effect_anim;
a.path = lv_anim_path_linear;
a.end_cb = lv_btn_ink_effect_anim_ready;
a.act_time = -ext->ink_wait_time;
a.time = ext->ink_out_time;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
lv_anim_create(&a);
lv_anim_t new_a;
new_a.var = ink_obj;
new_a.start = LV_BTN_INK_VALUE_MAX;
new_a.end = 0;
new_a.exec_cb = (lv_anim_exec_cb_t)lv_btn_ink_effect_anim;
new_a.path_cb = lv_anim_path_linear;
new_a.ready_cb = lv_btn_ink_effect_anim_ready;
new_a.act_time = -ext->ink_wait_time;
new_a.time = ext->ink_out_time;
new_a.playback = 0;
new_a.playback_pause = 0;
new_a.repeat = 0;
new_a.repeat_pause = 0;
lv_anim_create(&new_a);
ink_playback = true;
} else {

View File

@@ -55,12 +55,12 @@ typedef struct
lv_cont_ext_t cont; /*Ext. of ancestor*/
/*New data for this type */
const lv_style_t * styles[LV_BTN_STATE_NUM]; /*Styles in each state*/
lv_btn_state_t state; /*Current state of the button from 'lv_btn_state_t' enum*/
#if LV_BTN_INK_EFFECT
uint16_t ink_in_time; /*[ms] Time of ink fill effect (0: disable ink effect)*/
uint16_t ink_wait_time; /*[ms] Wait before the ink disappears */
uint16_t ink_out_time; /*[ms] Time of ink disappearing*/
#endif
lv_btn_state_t state : 3; /*Current state of the button from 'lv_btn_state_t' enum*/
uint8_t toggle : 1; /*1: Toggle enabled*/
} lv_btn_ext_t;

View File

@@ -401,6 +401,9 @@ void lv_btnm_set_btn_width(const lv_obj_t * btnm, uint16_t btn_id, uint8_t width
/**
* Make the button matrix like a selector widget (only one button may be toggled at a time).
*
* Toggling must be enabled on the buttons you want to be selected with `lv_btnm_set_ctrl` or `lv_btnm_set_btn_ctrl_all`.
*
* @param btnm Button matrix object
* @param one_toggle Whether "one toggle" mode is enabled
*/
@@ -721,7 +724,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
button_is_inactive(ext->ctrl_bits[ext->btn_id_act]) == false &&
button_is_hidden(ext->ctrl_bits[ext->btn_id_act]) == false) {
uint32_t b = ext->btn_id_act;
lv_event_send(btnm, LV_EVENT_SELECTED, &b);
res = lv_event_send(btnm, LV_EVENT_SELECTED, &b);
}
}
} else if(sign == LV_SIGNAL_PRESSING) {
@@ -737,8 +740,10 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
}
if(btn_pr != LV_BTNM_BTN_NONE) {
uint32_t b = ext->btn_id_act;
lv_event_send(btnm, LV_EVENT_SELECTED, &b);
invalidate_button_area(btnm, btn_pr);
res = lv_event_send(btnm, LV_EVENT_SELECTED, &b);
if(res == LV_RES_OK) {
invalidate_button_area(btnm, btn_pr);
}
}
}
@@ -773,7 +778,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
button_is_inactive(ext->ctrl_bits[ext->btn_id_act]) == false &&
button_is_hidden(ext->ctrl_bits[ext->btn_id_act]) == false) {
uint32_t b = ext->btn_id_act;
lv_event_send(btnm, LV_EVENT_SELECTED, &b);
res = lv_event_send(btnm, LV_EVENT_SELECTED, &b);
}
}
} else if(sign == LV_SIGNAL_LONG_PRESS_REP) {
@@ -782,7 +787,7 @@ static lv_res_t lv_btnm_signal(lv_obj_t * btnm, lv_signal_t sign, void * param)
button_is_inactive(ext->ctrl_bits[ext->btn_id_act]) == false &&
button_is_hidden(ext->ctrl_bits[ext->btn_id_act]) == false) {
uint32_t b = ext->btn_id_act;
lv_event_send(btnm, LV_EVENT_SELECTED, &b);
res = lv_event_send(btnm, LV_EVENT_SELECTED, &b);
}
}
} else if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_DEFOCUS) {

View File

@@ -42,7 +42,7 @@ enum {
LV_BTNM_CTRL_INACTIVE = 0x0020,
LV_BTNM_CTRL_TGL_ENABLE = 0x0040,
LV_BTNM_CTRL_TGL_STATE = 0x0080,
LV_BTNM_CTRL_CLICK_TRIG = 0x0100,
LV_BTNM_CTRL_CLICK_TRIG = 0x0100, /*1: Send LV_EVENT_SELECTED on CLICK, 0: Send LV_EVENT_SELECTED on PRESS*/
};
typedef uint16_t lv_btnm_ctrl_t;
@@ -170,6 +170,9 @@ void lv_btnm_set_btn_width(const lv_obj_t * btnm, uint16_t btn_id, uint8_t width
/**
* Make the button matrix like a selector widget (only one button may be toggled at a time).
*
* Toggling must be enabled on the buttons you want to be selected with `lv_btnm_set_ctrl` or `lv_btnm_set_btn_ctrl_all`.
*
* @param btnm Button matrix object
* @param one_toggle Whether "one toggle" mode is enabled
*/

View File

@@ -430,7 +430,7 @@ static bool lv_calendar_design(lv_obj_t * calendar, const lv_area_t * mask, lv_d
{
/*Return false if the object is not covers the mask_p area*/
if(mode == LV_DESIGN_COVER_CHK) {
return false;
return ancestor_design(calendar, mask, mode);
}
/*Draw the object*/
else if(mode == LV_DESIGN_DRAW_MAIN) {
@@ -487,6 +487,8 @@ static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void *
}
ext->pressed_date.year = 0;
ext->pressed_date.month = 0;
ext->pressed_date.day = 0;
} else if(calculate_touched_day(calendar, &p)) {
if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);
ext->btn_pressing = 0;
@@ -494,10 +496,11 @@ static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void *
if(ext->btn_pressing != 0) lv_obj_invalidate(calendar);
ext->btn_pressing = 0;
ext->pressed_date.year = 0;
ext->pressed_date.month = 0;
ext->pressed_date.day = 0;
}
} else if(sign == LV_SIGNAL_PRESS_LOST) {
lv_calendar_ext_t * ext = lv_obj_get_ext_attr(calendar);
ext->pressed_date.year = 0;
ext->btn_pressing = 0;
lv_obj_invalidate(calendar);
@@ -522,7 +525,6 @@ static lv_res_t lv_calendar_signal(lv_obj_t * calendar, lv_signal_t sign, void *
if(res != LV_RES_OK) return res;
}
ext->pressed_date.year = 0;
ext->btn_pressing = 0;
lv_obj_invalidate(calendar);
} else if(sign == LV_SIGNAL_CONTROL) {

View File

@@ -283,12 +283,11 @@ void lv_canvas_mult_buf(lv_obj_t * canvas, void * to_copy, lv_coord_t w, lv_coor
(uint16_t)((uint16_t)canvas_buf_color[j].ch.green * copy_buf_color[j].ch.green) >>
6;
#else
canvas_buf_color[j].ch.red =
(uint16_t)((uint16_t)canvas_buf_color[j].ch.red * copy_buf_color[j].ch.red) >> 6;
canvas_buf_color[j].ch.blue =
(uint16_t)((uint16_t)canvas_buf_color[j].ch.blue * copy_buf_color[j].ch.blue) >> 6;
canvas_buf_color[j].ch.red =
(uint16_t)((uint16_t)canvas_buf_color[j].ch.red * copy_buf_color[j].ch.red) >> 6;
uint8_t green_canvas = (canvas_buf_color[j].ch.green_h << 3) + (canvas_buf_color[j].ch.green_l);
uint8_t green_buf = (copy_buf_color[j].ch.green_h << 3) + (copy_buf_color[j].ch.green_l);
uint8_t green_res = (uint16_t)((uint16_t)green_canvas * green_buf) >> 6;
canvas_buf_color[j].ch.green_h = (green_res >> 3) & 0x07;
canvas_buf_color[j].ch.green_l = green_res & 0x07;
#endif /*LV_COLOR_16_SWAP*/
#elif LV_COLOR_DEPTH == 8

View File

@@ -9,6 +9,7 @@
#include "lv_chart.h"
#if LV_USE_CHART != 0
#include "../lv_core/lv_refr.h"
#include "../lv_draw/lv_draw.h"
#include "../lv_themes/lv_theme.h"
@@ -42,6 +43,9 @@ static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask);
static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mask);
static void lv_chart_draw_areas(lv_obj_t * chart, const lv_area_t * mask);
static void lv_chart_draw_axes(lv_obj_t * chart, const lv_area_t * mask);
static void lv_chart_inv_lines(lv_obj_t * chart, uint16_t i);
static void lv_chart_inv_points(lv_obj_t * chart, uint16_t i);
static void lv_chart_inv_cols(lv_obj_t * chart, uint16_t i);
/**********************
* STATIC VARIABLES
@@ -79,15 +83,17 @@ lv_obj_t * lv_chart_create(lv_obj_t * par, const lv_obj_t * copy)
if(ext == NULL) return NULL;
lv_ll_init(&ext->series_ll, sizeof(lv_chart_series_t));
ext->series.num = 0;
ext->ymin = LV_CHART_YMIN_DEF;
ext->ymax = LV_CHART_YMAX_DEF;
ext->hdiv_cnt = LV_CHART_HDIV_DEF;
ext->vdiv_cnt = LV_CHART_VDIV_DEF;
ext->point_cnt = LV_CHART_PNUM_DEF;
ext->type = LV_CHART_TYPE_LINE;
ext->series.opa = LV_OPA_COVER;
ext->series.dark = LV_OPA_50;
ext->series.num = 0;
ext->ymin = LV_CHART_YMIN_DEF;
ext->ymax = LV_CHART_YMAX_DEF;
ext->hdiv_cnt = LV_CHART_HDIV_DEF;
ext->vdiv_cnt = LV_CHART_VDIV_DEF;
ext->point_cnt = LV_CHART_PNUM_DEF;
ext->type = LV_CHART_TYPE_LINE;
ext->update_mode = LV_CHART_UPDATE_MODE_SHIFT;
ext->series.opa = LV_OPA_COVER;
ext->series.dark = LV_OPA_50;
ext->series.width = 2;
ext->margin = 0;
memset(&ext->x_axis, 0, sizeof(ext->x_axis));
@@ -155,7 +161,6 @@ lv_chart_series_t * lv_chart_add_series(lv_obj_t * chart, lv_color_t color)
if(ser == NULL) return NULL;
ser->color = color;
ser->points = lv_mem_alloc(sizeof(lv_coord_t) * ext->point_cnt);
lv_mem_assert(ser->points);
if(ser->points == NULL) {
@@ -392,13 +397,36 @@ void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y
*/
void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y)
{
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
if(ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT) {
ser->points[ser->start_point] = y; /*This was the place of the former left most value, after shifting it is the rightmost*/
ser->start_point = (ser->start_point + 1) % ext->point_cnt;
lv_chart_refresh(chart);
} else if(ext->update_mode == LV_CHART_UPDATE_MODE_CIRCULAR) {
ser->points[ser->start_point] = y;
ser->points[ser->start_point] =
y; /*This was the place of the former left most value, after shifting it is the rightmost*/
ser->start_point = (ser->start_point + 1) % ext->point_cnt;
if(ext->type & LV_CHART_TYPE_LINE) lv_chart_inv_lines(chart, ser->start_point);
if(ext->type & LV_CHART_TYPE_COLUMN) lv_chart_inv_cols(chart, ser->start_point);
if(ext->type & LV_CHART_TYPE_POINT) lv_chart_inv_points(chart, ser->start_point);
if(ext->type & LV_CHART_TYPE_VERTICAL_LINE) lv_chart_inv_lines(chart, ser->start_point);
if(ext->type & LV_CHART_TYPE_AREA) lv_chart_inv_lines(chart, ser->start_point);
lv_chart_refresh(chart);
ser->start_point = (ser->start_point + 1) % ext->point_cnt;/*update the x for next incoming y*/
}
}
/**
* Set update mode of the chart object.
* @param chart pointer to a chart object
* @param update mode
*/
void lv_chart_set_update_mode(lv_obj_t * chart, lv_chart_update_mode_t update_mode)
{
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
if(ext->update_mode == update_mode) return;
ext->update_mode = update_mode;
lv_obj_invalidate(chart);
}
/**
@@ -705,10 +733,12 @@ static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask)
{
style.line.color = ser->color;
lv_coord_t start_point = ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0;
p1.x = 0 + x_ofs;
p2.x = 0 + x_ofs;
p_prev = ser->start_point;
p_prev = start_point;
y_tmp = (int32_t)((int32_t)ser->points[p_prev] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
p2.y = h - y_tmp + y_ofs;
@@ -719,7 +749,7 @@ static void lv_chart_draw_lines(lv_obj_t * chart, const lv_area_t * mask)
p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
p_act = (ser->start_point + i) % ext->point_cnt;
p_act = (start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
@@ -762,8 +792,10 @@ static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask)
style_point.body.radius = ext->series.width;
/*Go through all data lines*/
LV_LL_READ_BACK(ext->series_ll, ser)
{
LV_LL_READ_BACK(ext->series_ll, ser) {
lv_coord_t start_point = ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0;
style_point.body.main_color = ser->color;
style_point.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark);
@@ -771,9 +803,11 @@ static void lv_chart_draw_points(lv_obj_t * chart, const lv_area_t * mask)
cir_a.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
cir_a.x2 = cir_a.x1 + style_point.body.radius;
cir_a.x1 -= style_point.body.radius;
p_act = (ser->start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
p_act = (start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
cir_a.y1 = h - y_tmp + y_ofs;
cir_a.y2 = cir_a.y1 + style_point.body.radius;
cir_a.y1 -= style_point.body.radius;
@@ -822,18 +856,23 @@ static void lv_chart_draw_cols(lv_obj_t * chart, const lv_area_t * mask)
x_act += chart->coords.x1 + x_ofs;
/*Draw the current point of all data line*/
LV_LL_READ_BACK(ext->series_ll, ser)
{
rects.body.main_color = ser->color;
rects.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark);
LV_LL_READ_BACK(ext->series_ll, ser) {
lv_coord_t start_point = ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0;
col_a.x1 = x_act;
col_a.x2 = col_a.x1 + col_w;
x_act += col_w;
lv_coord_t p_act = (ser->start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
col_a.y1 = h - y_tmp + chart->coords.y1;
if(col_a.x2 < mask->x1) continue;
if(col_a.x1 > mask->x2) break;
rects.body.main_color = ser->color;
rects.body.grad_color = lv_color_mix(LV_COLOR_BLACK, ser->color, ext->series.dark);
lv_coord_t p_act = (start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
col_a.y1 = h - y_tmp + chart->coords.y1;
mask_ret = lv_area_intersect(&col_mask, mask, &col_a);
if(mask_ret != false && ser->points[p_act] != LV_CHART_POINT_DEF) {
@@ -861,7 +900,8 @@ static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mas
uint16_t i;
lv_point_t p1;
lv_point_t p2;
lv_coord_t h = lv_obj_get_height(chart);
lv_coord_t p_act;
lv_coord_t h = lv_obj_get_height(chart);
lv_coord_t x_ofs = chart->coords.x1;
lv_coord_t y_ofs = chart->coords.y1;
int32_t y_tmp;
@@ -873,8 +913,8 @@ static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mas
style.line.width = ext->series.width;
/*Go through all data lines*/
LV_LL_READ_BACK(ext->series_ll, ser)
{
LV_LL_READ_BACK(ext->series_ll, ser) {
lv_coord_t start_point = ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0;
style.line.color = ser->color;
p1.x = 0 + x_ofs;
@@ -884,9 +924,11 @@ static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mas
p2.y = h - y_tmp + y_ofs;
p1.y = p2.y;
for(i = 0; i < ext->point_cnt; i++) {
for(i = 0; i < ext->point_cnt; i++)
{
p_act = (start_point + i) % ext->point_cnt;
y_tmp = (int32_t)((int32_t)ser->points[i] - ext->ymin) * h;
y_tmp = (int32_t)((int32_t) ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
p2.y = h - y_tmp + y_ofs;
@@ -894,11 +936,11 @@ static void lv_chart_draw_vertical_lines(lv_obj_t * chart, const lv_area_t * mas
p2.x++;
}
if(ser->points[i] != LV_CHART_POINT_DEF) {
if(ser->points[p_act] != LV_CHART_POINT_DEF) {
lv_draw_line(&p1, &p2, mask, &style, opa_scale);
}
p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
p2.x = ((w * p_act) / (ext->point_cnt - 1)) + x_ofs;
p1.x = p2.x;
p1.y = p2.y;
}
@@ -929,15 +971,14 @@ static void lv_chart_draw_areas(lv_obj_t * chart, const lv_area_t * mask)
lv_style_copy(&style, &lv_style_plain);
/*Go through all data lines*/
LV_LL_READ_BACK(ext->series_ll, ser)
{
LV_LL_READ_BACK(ext->series_ll, ser) {
lv_coord_t start_point = ext->update_mode == LV_CHART_UPDATE_MODE_SHIFT ? ser->start_point : 0;
style.body.main_color = ser->color;
style.body.opa = ext->series.opa;
p1.x = 0 + x_ofs;
p2.x = 0 + x_ofs;
p_prev = ser->start_point;
p_prev = start_point;
y_tmp = (int32_t)((int32_t)ser->points[p_prev] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
p2.y = h - y_tmp + y_ofs;
@@ -946,8 +987,8 @@ static void lv_chart_draw_areas(lv_obj_t * chart, const lv_area_t * mask)
p1.x = p2.x;
p1.y = p2.y;
p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
p_act = (ser->start_point + i) % ext->point_cnt;
p_act = (start_point + i) % ext->point_cnt;
p2.x = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
y_tmp = (int32_t)((int32_t)ser->points[p_act] - ext->ymin) * h;
y_tmp = y_tmp / (ext->ymax - ext->ymin);
@@ -957,12 +998,12 @@ static void lv_chart_draw_areas(lv_obj_t * chart, const lv_area_t * mask)
ser->points[p_act] != LV_CHART_POINT_DEF) {
lv_point_t triangle_points[3];
triangle_points[0] = p1;
triangle_points[1].x = p2.x;
triangle_points[1].y = y_ofs + h;
triangle_points[1] = p2;
triangle_points[2].x = p1.x;
triangle_points[2].y = y_ofs + h;
triangle_points[2].y = chart->coords.y2;
lv_draw_triangle(triangle_points, mask, &style, opa_scale);
triangle_points[2] = p2;
triangle_points[2].x = p2.x;
triangle_points[0].y =chart->coords.y2;
lv_draw_triangle(triangle_points, mask, &style, opa_scale);
}
p_prev = p_act;
@@ -1200,4 +1241,80 @@ static void lv_chart_draw_axes(lv_obj_t * chart, const lv_area_t * mask)
lv_chart_draw_y_ticks(chart, mask);
lv_chart_draw_x_ticks(chart, mask);
}
/**
* invalid area of the new line data lines on a chart
* @param obj pointer to chart object
*/
static void lv_chart_inv_lines(lv_obj_t * chart, uint16_t i)
{
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
lv_coord_t w = lv_obj_get_width(chart);
lv_coord_t x_ofs = chart->coords.x1;
if(i < ext->point_cnt) {
lv_area_t coords;
lv_obj_get_coords(chart, &coords);
if(i < ext->point_cnt - 1) {
coords.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs - ext->series.width;
coords.x2 = ((w * (i + 1)) / (ext->point_cnt - 1)) + x_ofs + ext->series.width;
lv_inv_area(lv_obj_get_disp(chart), &coords);
}
if(i > 0) {
coords.x1 = ((w * (i - 1)) / (ext->point_cnt - 1)) + x_ofs - ext->series.width;
coords.x2 = ((w * i) / (ext->point_cnt - 1)) + x_ofs + ext->series.width;
lv_inv_area(lv_obj_get_disp(chart), &coords);
}
}
}
/**
* invalid area of the new point data lines on a chart
* @param chart pointer to chart object
* @param mask mask, inherited from the design function
*/
static void lv_chart_inv_points(lv_obj_t * chart, uint16_t i)
{
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
lv_area_t cir_a;
lv_coord_t w = lv_obj_get_width(chart);
lv_coord_t x_ofs = chart->coords.x1;
lv_obj_get_coords(chart, &cir_a);
cir_a.x1 = ((w * i) / (ext->point_cnt - 1)) + x_ofs;
cir_a.x2 = cir_a.x1 + ext->series.width;
cir_a.x1 -= ext->series.width;
lv_inv_area(lv_obj_get_disp(chart), &cir_a);
}
/**
* invalid area of the new column data lines on a chart
* @param chart pointer to chart object
* @param mask mask, inherited from the design function
*/
static void lv_chart_inv_cols(lv_obj_t * chart, uint16_t i)
{
lv_chart_ext_t * ext = lv_obj_get_ext_attr(chart);
lv_area_t col_a;
lv_coord_t w = lv_obj_get_width(chart);
lv_coord_t col_w = w / ((ext->series.num + 1) * ext->point_cnt); /* Suppose + 1 series as separator*/
lv_coord_t x_ofs = col_w / 2; /*Shift with a half col.*/
lv_coord_t x_act;
x_act = (int32_t)((int32_t) w * i) / ext->point_cnt;
x_act += chart->coords.x1 + x_ofs;
lv_obj_get_coords(chart, &col_a);
col_a.x1 = x_act;
col_a.x2 = col_a.x1 + col_w;
lv_inv_area(lv_obj_get_disp(chart), &col_a);
}
#endif

View File

@@ -44,6 +44,14 @@ enum {
};
typedef uint8_t lv_chart_type_t;
/*Chart update mode*/
enum
{
LV_CHART_UPDATE_MODE_SHIFT,
LV_CHART_UPDATE_MODE_CIRCULAR,
};
typedef uint8_t lv_chart_update_mode_t;
typedef struct
{
lv_coord_t * points;
@@ -81,6 +89,7 @@ typedef struct
lv_chart_axis_cfg_t y_axis;
lv_chart_axis_cfg_t x_axis;
uint16_t margin;
uint8_t update_mode: 1;
struct
{
lv_coord_t width; /*Line width or point radius*/
@@ -191,7 +200,7 @@ void lv_chart_init_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t
* @param ser pointer to a data series on 'chart'
* @param y_array array of 'lv_coord_t' points (with 'points count' elements )
*/
void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t * y_array);
void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y_array[]);
/**
* Shift all data right and set the most right data on a data line
@@ -201,6 +210,13 @@ void lv_chart_set_points(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t *
*/
void lv_chart_set_next(lv_obj_t * chart, lv_chart_series_t * ser, lv_coord_t y);
/**
* Set update mode of the chart object.
* @param chart pointer to a chart object
* @param update mode
*/
void lv_chart_set_update_mode(lv_obj_t * chart, lv_chart_update_mode_t update_mode);
/**
* Set the style of a chart
* @param chart pointer to a chart object

View File

@@ -22,7 +22,7 @@
* DEFINES
*********************/
#if LV_USE_ANIMATION
#ifndef LV_DDLIST_ANIM_TIME
#ifndef LV_DDLIST_DEF_ANIM_TIME
#define LV_DDLIST_DEF_ANIM_TIME 200 /*ms*/
#endif
#else
@@ -43,8 +43,12 @@ static lv_res_t lv_ddlist_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void *
static lv_res_t release_handler(lv_obj_t * ddlist);
static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en);
static void lv_ddlist_pos_current_option(lv_obj_t * ddlist);
static void lv_ddlist_anim_cb(lv_obj_t * ddlist);
static void lv_ddlist_adjust_height(lv_obj_t * ddlist, int32_t height);
static void lv_ddlist_refr_width(lv_obj_t* ddlist);
#if LV_USE_ANIMATION
static void lv_ddlist_anim_ready_cb(lv_anim_t * a);
static void lv_ddlist_anim_finish(lv_obj_t* ddlist);
static void lv_ddlist_adjust_height(lv_obj_t * ddlist, lv_anim_value_t height);
#endif
/**********************
* STATIC VARIABLES
@@ -171,11 +175,26 @@ void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options)
for(i = 0; options[i] != '\0'; i++) {
if(options[i] == '\n') ext->option_cnt++;
}
ext->option_cnt++; /*Last option in the at row*/
ext->option_cnt++; /*Last option has no `\n`*/
ext->sel_opt_id = 0;
ext->sel_opt_id_ori = 0;
lv_label_set_text(ext->label, options);
lv_ddlist_refr_width(ddlist);
switch(lv_label_get_align(ext->label)) {
case LV_LABEL_ALIGN_LEFT:
lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0);
break;
case LV_LABEL_ALIGN_CENTER:
lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0);
break;
case LV_LABEL_ALIGN_RIGHT:
lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0);
break;
}
lv_ddlist_refr_size(ddlist, false);
}
@@ -220,15 +239,9 @@ void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h)
* @param ddlist pointer to a drop down list
* @param fit fit mode from `lv_fit_t` (Typically `LV_FIT_NONE` or `LV_FIT_TIGHT`)
*/
void lv_ddlist_set_fit(lv_obj_t * ddlist, lv_fit_t fit)
void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, lv_fit_t fit)
{
lv_cont_set_fit2(ddlist, fit, LV_FIT_NONE);
if(fit == LV_FIT_NONE) {
lv_page_set_scrl_fit2(ddlist, LV_FIT_FLOOD, LV_FIT_NONE);
} else {
lv_page_set_scrl_fit2(ddlist, LV_FIT_TIGHT, LV_FIT_NONE);
}
lv_cont_set_fit2(ddlist, fit, lv_cont_get_fit_bottom(ddlist));
lv_ddlist_refr_size(ddlist, false);
}
@@ -285,7 +298,10 @@ void lv_ddlist_set_style(lv_obj_t * ddlist, lv_ddlist_style_t type, const lv_sty
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
switch(type) {
case LV_DDLIST_STYLE_BG: lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style); break;
case LV_DDLIST_STYLE_BG:
lv_page_set_style(ddlist, LV_PAGE_STYLE_BG, style);
lv_ddlist_refr_width(ddlist);
break;
case LV_DDLIST_STYLE_SB: lv_page_set_style(ddlist, LV_PAGE_STYLE_SB, style); break;
case LV_DDLIST_STYLE_SEL:
ext->sel_style = style;
@@ -300,6 +316,18 @@ void lv_ddlist_set_align(lv_obj_t * ddlist, lv_label_align_t align)
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
lv_label_set_align(ext->label, align);
switch(align) {
case LV_LABEL_ALIGN_LEFT:
lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0);
break;
case LV_LABEL_ALIGN_CENTER:
lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0);
break;
case LV_LABEL_ALIGN_RIGHT:
lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0);
break;
}
}
/*=====================
* Getter functions
@@ -765,6 +793,7 @@ static lv_res_t release_handler(lv_obj_t * ddlist)
/*Leave edit mode once a new item is selected*/
lv_indev_t * indev = lv_indev_get_act();
if(lv_indev_get_type(indev) == LV_INDEV_TYPE_ENCODER) {
ext->sel_opt_id_ori = ext->sel_opt_id;
lv_group_t * g = lv_obj_get_group(ddlist);
if(lv_group_get_editing(g)) {
lv_group_set_editing(g, false);
@@ -794,10 +823,9 @@ static lv_res_t release_handler(lv_obj_t * ddlist)
}
ext->sel_opt_id = new_opt;
ext->sel_opt_id_ori = ext->sel_opt_id;
}
ext->sel_opt_id_ori = ext->sel_opt_id;
lv_res_t res = lv_event_send(ddlist, LV_EVENT_VALUE_CHANGED, &ext->sel_opt_id);
if(res != LV_RES_OK) return res;
@@ -826,14 +854,19 @@ static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en)
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
const lv_style_t * style = lv_obj_get_style(ddlist);
lv_coord_t new_height;
if(ext->opened) { /*Open the list*/
if(ext->fix_height == 0)
/*Open the list*/
if(ext->opened) {
if(ext->fix_height == 0) {
new_height = lv_obj_get_height(lv_page_get_scrl(ddlist)) + style->body.padding.top +
style->body.padding.bottom;
else
} else {
new_height = ext->fix_height;
}
} else { /*Close the list*/
}
/*Close the list*/
else {
const lv_font_t * font = style->text.font;
const lv_style_t * label_style = lv_obj_get_style(ext->label);
lv_coord_t font_h = lv_font_get_height(font);
@@ -847,42 +880,57 @@ static void lv_ddlist_refr_size(lv_obj_t * ddlist, bool anim_en)
lv_ddlist_pos_current_option(ddlist);
if(ext->opened) lv_page_set_sb_mode(ddlist, LV_SB_MODE_UNHIDE);
#if LV_USE_ANIMATION
lv_anim_del(ddlist, (lv_anim_fp_t)lv_obj_set_height); /*If an animation is in progress then
lv_anim_del(ddlist, (lv_anim_exec_cb_t)lv_ddlist_adjust_height); /*If an animation is in progress then
it will overwrite this changes*/
} else {
lv_anim_t a;
a.var = ddlist;
a.start = lv_obj_get_height(ddlist);
a.end = new_height;
a.fp = (lv_anim_fp_t)lv_ddlist_adjust_height;
a.path = lv_anim_path_linear;
a.end_cb = (lv_anim_cb_t)lv_ddlist_anim_cb;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
ext->force_sel = 1; /*Keep the list item selected*/
lv_anim_create(&a);
/*Force animation complete to fix highlight selection*/
lv_ddlist_anim_finish(ddlist);
} else {
/*Run the animation only if the the size will be different*/
if(lv_obj_get_height(ddlist) != new_height) {
lv_anim_t a;
a.var = ddlist;
a.start = lv_obj_get_height(ddlist);
a.end = new_height;
a.exec_cb = (lv_anim_exec_cb_t)lv_ddlist_adjust_height;
a.path_cb = lv_anim_path_linear;
a.ready_cb = lv_ddlist_anim_ready_cb;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
ext->force_sel = 1; /*Keep the list item selected*/
lv_anim_create(&a);
}
#endif
}
}
#if LV_USE_ANIMATION
/**
* Position the list and remove the selection highlight if it's closed.
* Called at end of list animation.
* @param ddlist pointer to a drop down list
* @param a pointer to the animation
*/
static void lv_ddlist_anim_cb(lv_obj_t * ddlist)
static void lv_ddlist_anim_ready_cb(lv_anim_t * a)
{
lv_obj_t * ddlist = a->var;
lv_ddlist_anim_finish(ddlist);
}
/**
* Clean up after the open animation
* @param ddlist
*/
static void lv_ddlist_anim_finish(lv_obj_t* ddlist)
{
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
lv_ddlist_pos_current_option(ddlist);
ext->force_sel = 0; /*Turn off drawing of selection*/
if(ext->opened) lv_page_set_sb_mode(ddlist, LV_SB_MODE_UNHIDE);
}
@@ -892,11 +940,12 @@ static void lv_ddlist_anim_cb(lv_obj_t * ddlist)
* @param ddlist Drop down list object
* @param height New drop down list height
*/
static void lv_ddlist_adjust_height(lv_obj_t * ddlist, int32_t height)
static void lv_ddlist_adjust_height(lv_obj_t * ddlist, lv_anim_value_t height)
{
lv_obj_set_height(ddlist, height);
lv_ddlist_pos_current_option(ddlist);
}
#endif
/**
* Set the position of list when it is closed to show the selected item
@@ -916,6 +965,20 @@ static void lv_ddlist_pos_current_option(lv_obj_t * ddlist)
ext->label->coords.y1 - scrl->coords.y1;
lv_obj_set_y(scrl, -line_y1 + (h - font_h) / 2);
lv_obj_invalidate(ddlist);
}
/**
* Be sure the width of the scrollable exactly fits the ddlist
* @param ddlist pointer to a ddlist
*/
static void lv_ddlist_refr_width(lv_obj_t* ddlist)
{
/*Set the TIGHT fit horizontally the set the width to the content*/
lv_page_set_scrl_fit2(ddlist, LV_FIT_TIGHT, lv_page_get_scrl_fit_bottom(ddlist));
/*Revert FILL fit to fill the parent with the options area. It allows to RIGHT/CENTER align the text*/
lv_page_set_scrl_fit2(ddlist, LV_FIT_FILL, lv_page_get_scrl_fit_bottom(ddlist));
}
#endif

View File

@@ -109,7 +109,7 @@ void lv_ddlist_set_fix_height(lv_obj_t * ddlist, lv_coord_t h);
* @param ddlist pointer to a drop down list
* @param fit fit mode from `lv_fit_t` (Typically `LV_FIT_NONE` or `LV_FIT_TIGHT`)
*/
void lv_ddlist_set_fit(lv_obj_t * ddlist, lv_fit_t fit);
void lv_ddlist_set_hor_fit(lv_obj_t * ddlist, lv_fit_t fit);
/**
* Set arrow draw in a drop down list

View File

@@ -15,6 +15,7 @@
#endif
#include "../lv_themes/lv_theme.h"
#include "../lv_draw/lv_img_decoder.h"
#include "../lv_misc/lv_fs.h"
#include "../lv_misc/lv_txt.h"
#include "../lv_misc/lv_log.h"
@@ -148,7 +149,7 @@ void lv_img_set_src(lv_obj_t * img, const void * src_img)
}
lv_img_header_t header;
lv_img_dsc_get_info(src_img, &header);
lv_img_decoder_get_info(src_img, &header);
/*Save the source*/
if(src_type == LV_IMG_SRC_VARIABLE) {

View File

@@ -281,7 +281,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig
src = ext->img_src_left[state];
if(src) {
lv_img_dsc_get_info(src, &header);
lv_img_decoder_get_info(src, &header);
left_w = header.w;
coords.x1 = imgbtn->coords.x1;
coords.y1 = imgbtn->coords.y1;
@@ -292,7 +292,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig
src = ext->img_src_right[state];
if(src) {
lv_img_dsc_get_info(src, &header);
lv_img_decoder_get_info(src, &header);
right_w = header.w;
coords.x1 = imgbtn->coords.x2 - header.w + 1;
coords.y1 = imgbtn->coords.y1;
@@ -305,7 +305,7 @@ static bool lv_imgbtn_design(lv_obj_t * imgbtn, const lv_area_t * mask, lv_desig
if(src) {
lv_coord_t obj_w = lv_obj_get_width(imgbtn);
lv_coord_t i;
lv_img_dsc_get_info(src, &header);
lv_img_decoder_get_info(src, &header);
coords.x1 = imgbtn->coords.x1 + left_w;
coords.y1 = imgbtn->coords.y1;
@@ -375,7 +375,7 @@ static void refr_img(lv_obj_t * imgbtn)
#endif
lv_res_t info_res;
info_res = lv_img_dsc_get_info(src, &header);
info_res = lv_img_decoder_get_info(src, &header);
if(info_res == LV_RES_OK) {
ext->act_cf = header.cf;
#if LV_IMGBTN_TILED == 0

View File

@@ -16,6 +16,7 @@
/*********************
* DEFINES
*********************/
#define LV_KB_CTRL_BTN_FLAGS (LV_BTNM_CTRL_NO_REPEAT | LV_BTNM_CTRL_CLICK_TRIG)
/**********************
* TYPEDEFS
@@ -37,10 +38,10 @@ static const char * kb_map_lc[] = {"1#", "q", "w", "e", "r", "t", "y", "u", "i",
LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
static const lv_btnm_ctrl_t kb_ctrl_lc_map[] = {
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, (6 | LV_BTNM_CTRL_NO_REPEAT),
3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 6, 2,
2};
LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
static const char * kb_map_uc[] = {"1#", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "Bksp", "\n",
"abc", "A", "S", "D", "F", "G", "H", "J", "K", "L", "Enter", "\n",
@@ -48,10 +49,10 @@ static const char * kb_map_uc[] = {"1#", "Q", "W", "E", "R", "T", "Y", "U", "I",
LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
static const lv_btnm_ctrl_t kb_ctrl_uc_map[] = {
5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, (6 | LV_BTNM_CTRL_NO_REPEAT),
3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 6, 2,
2};
LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7,
LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2};
static const char * kb_map_spec[] = {"0", "1", "2", "3", "4" ,"5", "6", "7", "8", "9", "Bksp", "\n",
"abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">", "\n",
@@ -59,17 +60,21 @@ static const char * kb_map_spec[] = {"0", "1", "2", "3", "4" ,"5", "6", "7", "8"
LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""};
static const lv_btnm_ctrl_t kb_ctrl_spec_map[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, (2 | LV_BTNM_CTRL_NO_REPEAT),
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
2, 6, 2, 2};
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
LV_KB_CTRL_BTN_FLAGS | 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
LV_KB_CTRL_BTN_FLAGS | 2, LV_KB_CTRL_BTN_FLAGS | 2, 6, 2, 2};
static const char * kb_map_num[] = {"1", "2", "3", LV_SYMBOL_CLOSE, "\n",
"4", "5", "6", LV_SYMBOL_OK, "\n",
"7", "8", "9", "Bksp", "\n",
"+/-", "0", ".", LV_SYMBOL_LEFT, LV_SYMBOL_RIGHT, ""};
static const lv_btnm_ctrl_t kb_ctrl_num_map[] = {1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1};
static const lv_btnm_ctrl_t kb_ctrl_num_map[] = {
1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2,
LV_KB_CTRL_BTN_FLAGS | 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 1, LV_KB_CTRL_BTN_FLAGS | 1};
/* clang-format on */
/**********************
@@ -113,7 +118,12 @@ lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy)
/*Init the new keyboard keyboard*/
if(copy == NULL) {
lv_obj_set_size(new_kb, LV_DPI * 3, LV_DPI * 2);
/* Set a size which fits into the parent.
* Don't use `par` directly because if the window is created on a page it is moved to the
* scrollable so the parent has changed */
lv_obj_set_size(new_kb, lv_obj_get_width_fit(lv_obj_get_parent(new_kb)),
lv_obj_get_height_fit(lv_obj_get_parent(new_kb)) / 2);
lv_obj_align(new_kb, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0);
lv_obj_set_event_cb(new_kb, lv_kb_def_event_cb);
lv_btnm_set_map(new_kb, kb_map_lc);
@@ -317,7 +327,7 @@ const lv_style_t * lv_kb_get_style(const lv_obj_t * kb, lv_kb_style_t type)
*/
void lv_kb_def_event_cb(lv_obj_t * kb, lv_event_t event)
{
if(event != LV_EVENT_PRESSED && event != LV_EVENT_LONG_PRESSED_REPEAT) return;
if(event != LV_EVENT_SELECTED && event != LV_EVENT_LONG_PRESSED_REPEAT) return;
lv_kb_ext_t * ext = lv_obj_get_ext_attr(kb);
uint16_t btn_id = lv_btnm_get_active_btn(kb);
@@ -344,18 +354,23 @@ void lv_kb_def_event_cb(lv_obj_t * kb, lv_event_t event)
lv_btnm_set_ctrl_map(kb, kb_ctrl_spec_map);
return;
} else if(strcmp(txt, LV_SYMBOL_CLOSE) == 0) {
if(kb->event_cb) {
lv_event_send(kb, LV_EVENT_CANCEL, NULL);
if(kb->event_cb != lv_kb_def_event_cb) {
lv_res_t res = lv_event_send(kb, LV_EVENT_CANCEL, NULL);
if(res != LV_RES_OK) return;
} else {
lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/
lv_obj_del(kb);
return;
}
return;
} else if(strcmp(txt, LV_SYMBOL_OK) == 0) {
if(kb->event_cb)
lv_event_send(kb, LV_EVENT_APPLY, NULL);
else
if(kb->event_cb != lv_kb_def_event_cb) {
lv_res_t res = lv_event_send(kb, LV_EVENT_APPLY, NULL);
if(res != LV_RES_OK) return;
}
else {
lv_kb_set_ta(kb, NULL); /*De-assign the text area to hide it cursor if needed*/
}
return;
}

View File

@@ -41,6 +41,11 @@ static void lv_label_revert_dots(lv_obj_t * label);
static void lv_label_set_offset_x(lv_obj_t * label, lv_coord_t x);
static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y);
#endif
static bool lv_label_set_dot_tmp(lv_obj_t *label, char *data, uint16_t len);
static char * lv_label_get_dot_tmp(lv_obj_t *label);
static void lv_label_dot_tmp_free(lv_obj_t *label);
/**********************
* STATIC VARIABLES
**********************/
@@ -85,11 +90,17 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy)
ext->align = LV_LABEL_ALIGN_LEFT;
ext->dot_end = LV_LABEL_DOT_END_INV;
ext->long_mode = LV_LABEL_LONG_EXPAND;
#if LV_USE_ANIMATION
ext->anim_speed = LV_LABEL_DEF_SCROLL_SPEED;
#endif
ext->offset.x = 0;
ext->offset.y = 0;
ext->selection_start = -1;
ext->selection_end = -1;
#if LV_LABEL_TEXT_SEL
ext->txt_sel_start = LV_LABEL_TEXT_SEL_OFF;
ext->txt_sel_end = LV_LABEL_TEXT_SEL_OFF;
#endif
ext->dot.tmp_ptr = NULL;
ext->dot_tmp_alloc = 0;
lv_obj_set_design_cb(new_label, lv_label_design);
lv_obj_set_signal_cb(new_label, lv_label_signal);
@@ -121,7 +132,14 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy)
memcpy(ext->text, copy_ext->text, lv_mem_get_size(copy_ext->text));
}
memcpy(ext->dot_tmp, copy_ext->dot_tmp, sizeof(ext->dot_tmp));
if(copy_ext->dot_tmp_alloc && copy_ext->dot.tmp_ptr ){
int len = strlen(copy_ext->dot.tmp_ptr);
lv_label_set_dot_tmp(new_label, ext->dot.tmp_ptr, len);
}
else{
memcpy(ext->dot.tmp, copy_ext->dot.tmp, sizeof(ext->dot.tmp));
}
ext->dot_tmp_alloc = copy_ext->dot_tmp_alloc;
ext->dot_end = copy_ext->dot_end;
/*Refresh the style with new signal function*/
@@ -248,10 +266,10 @@ void lv_label_set_long_mode(lv_obj_t * label, lv_label_long_mode_t long_mode)
#if LV_USE_ANIMATION
/*Delete the old animation (if exists)*/
lv_anim_del(label, (lv_anim_fp_t)lv_obj_set_x);
lv_anim_del(label, (lv_anim_fp_t)lv_obj_set_y);
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_x);
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_y);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_obj_set_x);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_obj_set_y);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_x);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_y);
#endif
ext->offset.x = 0;
ext->offset.y = 0;
@@ -327,6 +345,7 @@ void lv_label_set_body_draw(lv_obj_t * label, bool en)
*/
void lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed)
{
#if LV_USE_ANIMATION
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
if(ext->anim_speed == anim_speed) return;
@@ -335,6 +354,24 @@ void lv_label_set_anim_speed(lv_obj_t * label, uint16_t anim_speed)
if(ext->long_mode == LV_LABEL_LONG_ROLL || ext->long_mode == LV_LABEL_LONG_ROLL_CIRC) {
lv_label_refr_text(label);
}
#endif
}
void lv_label_set_text_sel_start( lv_obj_t * label, uint16_t index ) {
#if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
ext->txt_sel_start = index;
lv_obj_invalidate(label);
#endif
}
void lv_label_set_text_sel_end( lv_obj_t * label, uint16_t index )
{
#if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
ext->txt_sel_end = index;
lv_obj_invalidate(label);
#endif
}
/*=====================
@@ -404,8 +441,12 @@ bool lv_label_get_body_draw(const lv_obj_t * label)
*/
uint16_t lv_label_get_anim_speed(const lv_obj_t * label)
{
#if LV_USE_ANIMATION
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
return ext->anim_speed;
#else
return 0;
#endif
}
/**
@@ -556,6 +597,37 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)
return lv_encoded_get_char_id(txt, i);
}
/**
* @brief Get the selection start index.
* @param label pointer to a label object.
* @return selection start index. `LV_LABEL_TXT_SEL_OFF` if nothing is selected.
*/
uint16_t lv_label_get_text_sel_start( const lv_obj_t * label ) {
#if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
return ext->txt_sel_start;
#else
return LV_LABEL_TEXT_SEL_OFF;
#endif
}
/**
* @brief Get the selection end index.
* @param label pointer to a label object.
* @return selection end index. `LV_LABEL_TXT_SEL_OFF` if nothing is selected.
*/
uint16_t lv_label_get_text_sel_end( const lv_obj_t * label ) {
#if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
return ext->txt_sel_end;
#else
(void) label; /*Unused*/
return LV_LABEL_TEXT_SEL_OFF;
#endif
}
/**
* Check if a character is drawn under a point.
* @param label Label object
@@ -761,7 +833,7 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_
}
lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ext->offset,
ext->selection_start, ext->selection_end);
lv_label_get_text_sel_start(label), lv_label_get_text_sel_end(label));
if(ext->long_mode == LV_LABEL_LONG_ROLL_CIRC) {
lv_point_t size;
@@ -774,8 +846,9 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_
ofs.x = ext->offset.x + size.x +
lv_font_get_width(style->text.font, ' ') * LV_LABEL_WAIT_CHAR_COUNT;
ofs.y = ext->offset.y;
lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs,
ext->selection_start, ext->selection_end);
lv_label_get_text_sel_start(label), lv_label_get_text_sel_end(label));
}
/*Draw the text again below the original to make an circular effect */
@@ -783,7 +856,7 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_
ofs.x = ext->offset.x;
ofs.y = ext->offset.y + size.y + lv_font_get_height(style->text.font);
lv_draw_label(&coords, mask, style, opa_scale, ext->text, flag, &ofs,
ext->selection_start, ext->selection_end);
lv_label_get_text_sel_start(label), lv_label_get_text_sel_end(label));
}
}
}
@@ -811,6 +884,7 @@ static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param
lv_mem_free(ext->text);
ext->text = NULL;
}
lv_label_dot_tmp_free(label);
} else if(sign == LV_SIGNAL_STYLE_CHG) {
/*Revert dots for proper refresh*/
lv_label_revert_dots(label);
@@ -882,8 +956,8 @@ static void lv_label_refr_text(lv_obj_t * label)
anim.repeat = 1;
anim.playback = 1;
anim.start = 0;
anim.end_cb = NULL;
anim.path = lv_anim_path_linear;
anim.ready_cb = NULL;
anim.path_cb = lv_anim_path_linear;
anim.playback_pause =
(((lv_font_get_width(style->text.font, ' ') + style->text.letter_space) * 1000) /
ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT;
@@ -893,24 +967,24 @@ static void lv_label_refr_text(lv_obj_t * label)
bool hor_anim = false;
if(size.x > lv_obj_get_width(label)) {
anim.end = lv_obj_get_width(label) - size.x;
anim.fp = (lv_anim_fp_t)lv_label_set_offset_x;
anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_x;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim);
hor_anim = true;
} else {
/*Delete the offset animation if not required*/
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_x);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_x);
ext->offset.x = 0;
}
if(size.y > lv_obj_get_height(label) && hor_anim == false) {
anim.end = lv_obj_get_height(label) - size.y - (lv_font_get_height(font));
anim.fp = (lv_anim_fp_t)lv_label_set_offset_y;
anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_y;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim);
} else {
/*Delete the offset animation if not required*/
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_y);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_y);
ext->offset.y = 0;
}
#endif
@@ -926,32 +1000,32 @@ static void lv_label_refr_text(lv_obj_t * label)
anim.act_time =
-(((lv_font_get_width(style->text.font, ' ') + style->text.letter_space) * 1000) /
ext->anim_speed) * LV_LABEL_WAIT_CHAR_COUNT;
anim.end_cb = NULL;
anim.path = lv_anim_path_linear;
anim.ready_cb = NULL;
anim.path_cb = lv_anim_path_linear;
anim.playback_pause = 0;
anim.repeat_pause = 0;
bool hor_anim = false;
if(size.x > lv_obj_get_width(label)) {
anim.end = -size.x - lv_font_get_width(font, ' ') * LV_LABEL_WAIT_CHAR_COUNT;
anim.fp = (lv_anim_fp_t)lv_label_set_offset_x;
anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_x;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim);
hor_anim = true;
} else {
/*Delete the offset animation if not required*/
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_x);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_x);
ext->offset.x = 0;
}
if(size.y > lv_obj_get_height(label) && hor_anim == false) {
anim.end = -size.y - (lv_font_get_height(font));
anim.fp = (lv_anim_fp_t)lv_label_set_offset_y;
anim.exec_cb = (lv_anim_exec_cb_t)lv_label_set_offset_y;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim);
} else {
/*Delete the offset animation if not required*/
lv_anim_del(label, (lv_anim_fp_t)lv_label_set_offset_y);
lv_anim_del(label, (lv_anim_exec_cb_t)lv_label_set_offset_y);
ext->offset.y = 0;
}
#endif
@@ -982,15 +1056,13 @@ static void lv_label_refr_text(lv_obj_t * label)
lv_txt_encoded_next(ext->text, &byte_id);
}
memcpy(ext->dot_tmp, &ext->text[byte_id_ori], len);
ext->dot_tmp[len] = '\0'; /*Close with a zero*/
for(i = 0; i < LV_LABEL_DOT_NUM; i++) {
ext->text[byte_id_ori + i] = '.';
if( lv_label_set_dot_tmp(label, &ext->text[byte_id_ori], len ) ){
for(i = 0; i < LV_LABEL_DOT_NUM; i++) {
ext->text[byte_id_ori + i] = '.';
}
ext->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0';
ext->dot_end = letter_id + LV_LABEL_DOT_NUM;
}
ext->text[byte_id_ori + LV_LABEL_DOT_NUM] = '\0';
ext->dot_end = letter_id + LV_LABEL_DOT_NUM;
}
}
/*In break mode only the height can change*/
@@ -1015,10 +1087,13 @@ static void lv_label_revert_dots(lv_obj_t * label)
/*Restore the characters*/
uint8_t i = 0;
while(ext->dot_tmp[i] != '\0') {
ext->text[byte_i + i] = ext->dot_tmp[i];
char* dot_tmp = lv_label_get_dot_tmp(label);
while(ext->text[byte_i + i] != '\0') {
ext->text[byte_i + i] = dot_tmp[i];
i++;
}
ext->text[byte_i + i] = dot_tmp[i];
lv_label_dot_tmp_free(label);
ext->dot_end = LV_LABEL_DOT_END_INV;
}
@@ -1038,4 +1113,64 @@ static void lv_label_set_offset_y(lv_obj_t * label, lv_coord_t y)
lv_obj_invalidate(label);
}
#endif
/**
* Store `len` characters from `data`. Allocates space if necessary.
*
* @param label pointer to label object
* @param len Number of characters to store.
* @return true on success.
*/
static bool lv_label_set_dot_tmp(lv_obj_t *label, char *data, uint16_t len){
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
lv_label_dot_tmp_free( label ); /* Deallocate any existing space */
if( len > sizeof(char *) ){
/* Memory needs to be allocated. Allocates an additional byte
* for a NULL-terminator so it can be copied. */
ext->dot.tmp_ptr = lv_mem_alloc(len + 1);
if( ext->dot.tmp_ptr == NULL ){
LV_LOG_ERROR("Failed to allocate memory for dot_tmp_ptr");
return false;
}
memcpy(ext->dot.tmp_ptr, data, len);
ext->dot.tmp_ptr[len]='\0';
ext->dot_tmp_alloc = true;
}
else {
/* Characters can be directly stored in object */
ext->dot_tmp_alloc = false;
memcpy(ext->dot.tmp, data, len);
}
return true;
}
/**
* Get the stored dot_tmp characters
* @param label pointer to label object
* @return char pointer to a stored characters. Is *not* necessarily NULL-terminated.
*/
static char * lv_label_get_dot_tmp(lv_obj_t *label){
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
if( ext->dot_tmp_alloc ){
return ext->dot.tmp_ptr;
}
else{
return ext->dot.tmp;
}
}
/**
* Free the dot_tmp_ptr field if it was previously allocated.
* Always clears the field
* @param label pointer to label object.
*/
static void lv_label_dot_tmp_free(lv_obj_t *label){
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
if( ext->dot_tmp_alloc && ext->dot.tmp_ptr ){
lv_mem_free(ext->dot.tmp_ptr);
}
ext->dot_tmp_alloc = false;
ext->dot.tmp_ptr = NULL;
}
#endif

View File

@@ -29,8 +29,9 @@ extern "C" {
/*********************
* DEFINES
*********************/
#define LV_LABEL_DOT_NUM 3
#define LV_LABEL_POS_LAST 0xFFFF
#define LV_LABEL_DOT_NUM 3
#define LV_LABEL_POS_LAST 0xFFFF
#define LV_LABEL_TEXT_SEL_OFF 0xFFFF
/**********************
* TYPEDEFS
@@ -62,20 +63,29 @@ typedef struct
/*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/
/*New data for this type */
char * text; /*Text of the label*/
lv_label_long_mode_t long_mode; /*Determinate what to do with the long texts*/
char dot_tmp[LV_LABEL_DOT_NUM * 4 +
1]; /*Store the character which are replaced by dots (Handled by the library)*/
union{
char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled by the library)*/
char tmp[ sizeof(char *) ]; /* Directly store the characters if <=4 characters */
} dot;
uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/
uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/
lv_point_t offset; /*Text draw position offset*/
#if LV_USE_ANIMATION
uint16_t anim_speed; /*Speed of scroll and roll animation in px/sec unit*/
#endif
#if LV_LABEL_TEXT_SEL
uint16_t txt_sel_start; /*Left-most selection character*/
uint16_t txt_sel_end; /*Right-most selection character*/
#endif
lv_label_long_mode_t long_mode : 3; /*Determinate what to do with the long texts*/
uint8_t static_txt : 1; /*Flag to indicate the text is static*/
uint8_t align : 2; /*Align type from 'lv_label_align_t'*/
uint8_t recolor : 1; /*Enable in-line letter re-coloring*/
uint8_t expand : 1; /*Ignore real width (used by the library with LV_LABEL_LONG_ROLL)*/
uint8_t body_draw : 1; /*Draw background body*/
int selection_start; /*Left-most selection character*/
int selection_end; /*Right-most selection character*/
uint8_t dot_tmp_alloc : 1; /*True if dot_tmp has been allocated. False if dot_tmp directly holds up to 4 bytes of characters */
} lv_label_ext_t;
/**********************
@@ -164,6 +174,21 @@ static inline void lv_label_set_style(lv_obj_t * label, const lv_style_t * style
{
lv_obj_set_style(label, style);
}
/**
* @brief Set the selection start index.
* @param label pointer to a label object.
* @param index index to set. `LV_LABEL_TXT_SEL_OFF` to select nothing.
*/
void lv_label_set_text_sel_start( lv_obj_t * label, uint16_t index );
/**
* @brief Set the selection end index.
* @param label pointer to a label object.
* @param index index to set. `LV_LABEL_TXT_SEL_OFF` to select nothing.
*/
void lv_label_set_text_sel_end( lv_obj_t * label, uint16_t index );
/*=====================
* Getter functions
*====================*/
@@ -246,6 +271,21 @@ static inline const lv_style_t * lv_label_get_style(const lv_obj_t * label)
return lv_obj_get_style(label);
}
/**
* @brief Get the selection start index.
* @param label pointer to a label object.
* @return selection start index. `LV_LABEL_TXT_SEL_OFF` if nothing is selected.
*/
uint16_t lv_label_get_text_sel_start( const lv_obj_t * label );
/**
* @brief Get the selection end index.
* @param label pointer to a label object.
* @return selection end index. `LV_LABEL_TXT_SEL_OFF` if nothing is selected.
*/
uint16_t lv_label_get_text_sel_end( const lv_obj_t * label );
/*=====================
* Other functions
*====================*/

View File

@@ -106,7 +106,7 @@ lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy)
* so the array can NOT be a local variable which will be destroyed
* @param point_num number of points in 'point_a'
*/
void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num)
void lv_line_set_points(lv_obj_t * line, const lv_point_t point_a[], uint16_t point_num)
{
lv_line_ext_t * ext = lv_obj_get_ext_attr(line);
ext->point_array = point_a;

View File

@@ -63,7 +63,7 @@ lv_obj_t * lv_line_create(lv_obj_t * par, const lv_obj_t * copy);
* so the array can NOT be a local variable which will be destroyed
* @param point_num number of points in 'point_a'
*/
void lv_line_set_points(lv_obj_t * line, const lv_point_t * point_a, uint16_t point_num);
void lv_line_set_points(lv_obj_t * line, const lv_point_t point_a[], uint16_t point_num);
/**
* Enable (or disable) the auto-size option. The size of the object will fit to its points.

View File

@@ -94,7 +94,9 @@ lv_obj_t * lv_list_create(lv_obj_t * par, const lv_obj_t * copy)
ext->styles_btn[LV_BTN_STATE_TGL_REL] = &lv_style_btn_tgl_rel;
ext->styles_btn[LV_BTN_STATE_TGL_PR] = &lv_style_btn_tgl_pr;
ext->styles_btn[LV_BTN_STATE_INA] = &lv_style_btn_ina;
#if LV_USE_ANIMATION
ext->anim_time = LV_LIST_DEF_ANIM_TIME;
#endif
ext->single_mode = false;
ext->size = 0;
@@ -249,11 +251,11 @@ lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt,
* lv_list_ext_t.size
* @return true: successfully deleted
*/
bool lv_list_remove(const lv_obj_t * list, uint32_t index)
bool lv_list_remove(const lv_obj_t * list, uint16_t index)
{
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
if(index >= ext->size) return false;
uint32_t count = 0;
uint16_t count = 0;
lv_obj_t * e = lv_list_get_next_btn(list, NULL);
while(e != NULL) {
if(count == index) {
@@ -288,7 +290,8 @@ void lv_list_set_single_mode(lv_obj_t * list, bool mode)
/**
* Make a button selected
* @param list pointer to a list object
* @param btn pointer to a button to selectthe
* @param btn pointer to a button to select
* NULL to not select any buttons
*/
void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn)
{
@@ -303,6 +306,9 @@ void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn)
}
ext->selected_btn = btn;
/*Don't forgat whci hbutton was selected.
* It will be restored when the list is focused.*/
if(btn != NULL) {
ext->last_sel = btn;
}
@@ -314,7 +320,7 @@ void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn)
else if(s == LV_BTN_STATE_TGL_REL)
lv_btn_set_state(ext->selected_btn, LV_BTN_STATE_TGL_PR);
lv_page_focus(list, ext->selected_btn, ext->anim_time);
lv_page_focus(list, ext->selected_btn, lv_list_get_anim_time(list) );
}
}
@@ -327,13 +333,13 @@ void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn)
*/
void lv_list_set_anim_time(lv_obj_t * list, uint16_t anim_time)
{
#if LV_USE_ANIMATION
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
#if LV_USE_ANIMATION == 0
anim_time = 0;
#endif
if(ext->anim_time == anim_time) return;
ext->anim_time = anim_time;
#endif
}
/**
@@ -538,7 +544,7 @@ int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn)
* @param list pointer to a list object
* @return the number of buttons in the list
*/
uint32_t lv_list_get_size(const lv_obj_t * list)
uint16_t lv_list_get_size(const lv_obj_t * list)
{
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
return ext->size;
@@ -565,8 +571,12 @@ lv_obj_t * lv_list_get_btn_selected(const lv_obj_t * list)
*/
uint16_t lv_list_get_anim_time(const lv_obj_t * list)
{
#if LV_USE_ANIMATION
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
return ext->anim_time;
#else
return 0;
#endif
}
/**
@@ -582,8 +592,8 @@ const lv_style_t * lv_list_get_style(const lv_obj_t * list, lv_list_style_t type
switch(type) {
case LV_LIST_STYLE_BG: style = lv_page_get_style(list, LV_PAGE_STYLE_BG); break;
case LV_LIST_STYLE_SCRL: style = lv_page_get_style(list, LV_PAGE_STYLE_SB); break;
case LV_LIST_STYLE_SB: style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); break;
case LV_LIST_STYLE_SCRL: style = lv_page_get_style(list, LV_PAGE_STYLE_SCRL); break;
case LV_LIST_STYLE_SB: style = lv_page_get_style(list, LV_PAGE_STYLE_SB); break;
case LV_LIST_STYLE_EDGE_FLASH:
style = lv_page_get_style(list, LV_PAGE_STYLE_EDGE_FLASH);
break;
@@ -618,8 +628,7 @@ void lv_list_up(const lv_obj_t * list)
if(e_prev != NULL) {
lv_coord_t new_y =
lv_obj_get_height(list) - (lv_obj_get_y(e_prev) + lv_obj_get_height(e_prev));
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
if(ext->anim_time == 0) {
if(lv_list_get_anim_time(list) == 0) {
lv_obj_set_y(scrl, new_y);
} else {
#if LV_USE_ANIMATION
@@ -627,9 +636,9 @@ void lv_list_up(const lv_obj_t * list)
a.var = scrl;
a.start = lv_obj_get_y(scrl);
a.end = new_y;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = LV_LIST_DEF_ANIM_TIME;
a.playback = 0;
@@ -661,8 +670,7 @@ void lv_list_down(const lv_obj_t * list)
while(e != NULL) {
if(e->coords.y1 < list->coords.y1) {
lv_coord_t new_y = -lv_obj_get_y(e);
lv_list_ext_t * ext = lv_obj_get_ext_attr(list);
if(ext->anim_time == 0) {
if(lv_list_get_anim_time(list) == 0) {
lv_obj_set_y(scrl, new_y);
} else {
#if LV_USE_ANIMATION
@@ -670,9 +678,9 @@ void lv_list_down(const lv_obj_t * list)
a.var = scrl;
a.start = lv_obj_get_y(scrl);
a.end = new_y;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = LV_LIST_DEF_ANIM_TIME;
a.playback = 0;
@@ -680,7 +688,6 @@ void lv_list_down(const lv_obj_t * list)
a.repeat = 0;
a.repeat_pause = 0;
lv_anim_create(&a);
#endif
}
break;

View File

@@ -52,14 +52,17 @@ typedef struct
{
lv_page_ext_t page; /*Ext. of ancestor*/
/*New data for this type */
uint16_t anim_time; /*Scroll animation time*/
const lv_style_t * styles_btn[LV_BTN_STATE_NUM]; /*Styles of the list element buttons*/
const lv_style_t * style_img; /*Style of the list element images on buttons*/
uint32_t size; /*the number of items(buttons) in the list*/
bool single_mode; /* whether single selected mode is enabled */
uint16_t size; /*the number of items(buttons) in the list*/
#if LV_USE_ANIMATION
uint16_t anim_time; /*Scroll animation time*/
#endif
uint8_t single_mode:1; /* whether single selected mode is enabled */
#if LV_USE_GROUP
lv_obj_t *
last_sel; /* The last selected button. It will be reverted when the list is focused again */
lv_obj_t * last_sel; /* The last selected button. It will be reverted when the list is focused again */
lv_obj_t * selected_btn; /* The button is currently being selected*/
#endif
} lv_list_ext_t;
@@ -117,7 +120,7 @@ lv_obj_t * lv_list_add(lv_obj_t * list, const void * img_src, const char * txt,
* lv_list_ext_t.size
* @return true: successfully deleted
*/
bool lv_list_remove(const lv_obj_t * list, uint32_t index);
bool lv_list_remove(const lv_obj_t * list, uint16_t index);
/*=====================
* Setter functions
@@ -133,9 +136,10 @@ void lv_list_set_single_mode(lv_obj_t * list, bool mode);
#if LV_USE_GROUP
/**
* Make a button selected. Can be used while navigating in the list with a keypad.
* Make a button selected
* @param list pointer to a list object
* @param btn pointer to a button to select
* NULL to not select any buttons
*/
void lv_list_set_btn_selected(lv_obj_t * list, lv_obj_t * btn);
#endif
@@ -245,7 +249,7 @@ int32_t lv_list_get_btn_index(const lv_obj_t * list, const lv_obj_t * btn);
* @param list pointer to a list object
* @return the number of buttons in the list
*/
uint32_t lv_list_get_size(const lv_obj_t * list);
uint16_t lv_list_get_size(const lv_obj_t * list);
#if LV_USE_GROUP
/**

View File

@@ -36,7 +36,9 @@
**********************/
static lv_res_t lv_mbox_signal(lv_obj_t * mbox, lv_signal_t sign, void * param);
static void mbox_realign(lv_obj_t * mbox);
static void lv_mbox_close_end_cb(lv_obj_t * mbox);
#if LV_USE_ANIMATION
static void lv_mbox_close_ready_cb(lv_anim_t * a);
#endif
static void lv_mbox_default_event_cb(lv_obj_t * mbox, lv_event_t event);
/**********************
@@ -77,7 +79,9 @@ lv_obj_t * lv_mbox_create(lv_obj_t * par, const lv_obj_t * copy)
ext->text = NULL;
ext->btnm = NULL;
#if LV_USE_ANIMATION
ext->anim_time = LV_MBOX_CLOSE_ANIM_TIME;
#endif
/*The signal and design functions are not copied so set them here*/
lv_obj_set_signal_cb(new_mbox, lv_mbox_signal);
@@ -182,12 +186,14 @@ void lv_mbox_set_text(lv_obj_t * mbox, const char * txt)
*/
void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time)
{
#if LV_USE_ANIMATION
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
#if LV_USE_ANIMATION == 0
anim_time = 0;
#endif
ext->anim_time = anim_time;
#else
(void) mbox;
(void) anim_time;
#endif
}
/**
@@ -198,18 +204,46 @@ void lv_mbox_set_anim_time(lv_obj_t * mbox, uint16_t anim_time)
void lv_mbox_start_auto_close(lv_obj_t * mbox, uint16_t delay)
{
#if LV_USE_ANIMATION
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
if(ext->anim_time != 0) {
if(lv_mbox_get_anim_time(mbox) != 0) {
/*Add shrinking animations*/
lv_obj_animate(mbox, LV_ANIM_GROW_H | LV_ANIM_OUT, ext->anim_time, delay, NULL);
lv_obj_animate(mbox, LV_ANIM_GROW_V | LV_ANIM_OUT, ext->anim_time, delay,
lv_mbox_close_end_cb);
lv_anim_t a;
a.var = mbox;
a.start = lv_obj_get_height(mbox);
a.end = 0;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_height;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = -delay;
a.time = lv_mbox_get_anim_time(mbox);
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
lv_anim_create(&a);
a.start = lv_obj_get_width(mbox);
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_width;
a.ready_cb = lv_mbox_close_ready_cb;
lv_anim_create(&a);
/*Disable fit to let shrinking work*/
lv_cont_set_fit(mbox, LV_FIT_NONE);
} else {
lv_obj_animate(mbox, LV_ANIM_NONE, ext->anim_time, delay, lv_mbox_close_end_cb);
/*Create an animation to delete the mbox `delay` ms later*/
lv_anim_t a;
a.var = mbox;
a.start = 0;
a.end = 1;
a.exec_cb = (lv_anim_exec_cb_t)NULL;
a.path_cb = lv_anim_path_linear;
a.ready_cb = lv_mbox_close_ready_cb;
a.act_time = -delay;
a.time = 0;
a.playback = 0;
a.playback_pause = 0;
a.repeat = 0;
a.repeat_pause = 0;
lv_anim_create(&a);
}
#else
(void)delay; /*Unused*/
@@ -326,8 +360,13 @@ const char * lv_mbox_get_active_btn_text(lv_obj_t * mbox)
*/
uint16_t lv_mbox_get_anim_time(const lv_obj_t * mbox)
{
#if LV_USE_ANIMATION
lv_mbox_ext_t * ext = lv_obj_get_ext_attr(mbox);
return ext->anim_time;
#else
(void) mbox;
return 0;
#endif
}
/**
@@ -491,14 +530,16 @@ static void mbox_realign(lv_obj_t * mbox)
}
}
static void lv_mbox_close_end_cb(lv_obj_t * mbox)
#if LV_USE_ANIMATION
static void lv_mbox_close_ready_cb(lv_anim_t * a)
{
lv_obj_del(mbox);
lv_obj_del(a->var);
}
#endif
static void lv_mbox_default_event_cb(lv_obj_t * mbox, lv_event_t event)
{
if(event != LV_EVENT_CLICKED) return;
if(event != LV_EVENT_SELECTED) return;
uint16_t btn_id = lv_mbox_get_active_btn(mbox);
if(btn_id == LV_BTNM_BTN_NONE) return;

View File

@@ -54,7 +54,9 @@ typedef struct
/*New data for this type */
lv_obj_t * text; /*Text of the message box*/
lv_obj_t * btnm; /*Button matrix for the buttons*/
#if LV_USE_ANIMATION
uint16_t anim_time; /*Duration of close animation [ms] (0: no animation)*/
#endif
} lv_mbox_ext_t;
enum {

View File

@@ -40,9 +40,11 @@ static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mo
static bool lv_scrl_design(lv_obj_t * scrl, const lv_area_t * mask, lv_design_mode_t mode);
static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param);
static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);
static void edge_flash_anim(void * page, int32_t v);
static void edge_flash_anim_end(void * page);
static void scrl_def_event_cb(lv_obj_t * scrl, lv_event_t event);
#if LV_USE_ANIMATION
static void edge_flash_anim(void * page, lv_anim_value_t v);
static void edge_flash_anim_end(lv_anim_t * a);
#endif
/**********************
* STATIC VARIABLES
@@ -86,6 +88,7 @@ lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy)
ext->sb.ver_draw = 0;
ext->sb.style = &lv_style_pretty;
ext->sb.mode = LV_SB_MODE_AUTO;
#if LV_USE_ANIMATION
ext->edge_flash.enabled = 0;
ext->edge_flash.bottom_ip = 0;
ext->edge_flash.top_ip = 0;
@@ -93,6 +96,7 @@ lv_obj_t * lv_page_create(lv_obj_t * par, const lv_obj_t * copy)
ext->edge_flash.right_ip = 0;
ext->edge_flash.state = 0;
ext->edge_flash.style = &lv_style_plain_color;
#endif
ext->arrow_scroll = 0;
ext->scroll_prop = 0;
ext->scroll_prop_ip = 0;
@@ -233,8 +237,13 @@ void lv_page_set_scroll_propagation(lv_obj_t * page, bool en)
*/
void lv_page_set_edge_flash(lv_obj_t * page, bool en)
{
#if LV_USE_ANIMATION
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
ext->edge_flash.enabled = en ? 1 : 0;
#else
(void) page;
(void) en;
#endif
}
/**
@@ -258,7 +267,9 @@ void lv_page_set_style(lv_obj_t * page, lv_page_style_t type, const lv_style_t *
lv_obj_refresh_ext_draw_pad(page);
lv_obj_invalidate(page);
break;
#if LV_USE_ANIMATION
case LV_PAGE_STYLE_EDGE_FLASH: ext->edge_flash.style = style; break;
#endif
}
}
@@ -318,8 +329,13 @@ bool lv_page_get_scroll_propagation(lv_obj_t * page)
*/
bool lv_page_get_edge_flash(lv_obj_t * page)
{
#if LV_USE_ANIMATION
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
return ext->edge_flash.enabled == 0 ? false : true;
#else
(void) page;
return false;
#endif
}
/**
@@ -365,7 +381,9 @@ const lv_style_t * lv_page_get_style(const lv_obj_t * page, lv_page_style_t type
case LV_PAGE_STYLE_BG: style = lv_obj_get_style(page); break;
case LV_PAGE_STYLE_SCRL: style = lv_obj_get_style(ext->scrl); break;
case LV_PAGE_STYLE_SB: style = ext->sb.style; break;
#if LV_USE_ANIMATION
case LV_PAGE_STYLE_EDGE_FLASH: style = ext->edge_flash.style; break;
#endif
default: style = NULL; break;
}
@@ -428,17 +446,15 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time)
{
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
#if LV_USE_ANIMATION == 0
anim_time = 0;
#else
#if LV_USE_ANIMATION
/* Be sure there is no position changing animation in progress
* because it can overide the current changes*/
lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_x);
lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_y);
lv_anim_del(page, (lv_anim_fp_t)lv_obj_set_pos);
lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_x);
lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_y);
lv_anim_del(ext->scrl, (lv_anim_fp_t)lv_obj_set_pos);
lv_anim_del(page, (lv_anim_exec_cb_t)lv_obj_set_x);
lv_anim_del(page, (lv_anim_exec_cb_t)lv_obj_set_y);
lv_anim_del(ext->scrl, (lv_anim_exec_cb_t)lv_obj_set_x);
lv_anim_del(ext->scrl, (lv_anim_exec_cb_t)lv_obj_set_y);
#else
anim_time = 0;
#endif
const lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_BG);
@@ -500,17 +516,17 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, uint16_t anim_time)
a.start = lv_obj_get_y(ext->scrl);
a.end = scrlable_y;
a.time = anim_time;
a.end_cb = NULL;
a.ready_cb = NULL;
a.playback = 0;
a.repeat = 0;
a.var = ext->scrl;
a.path = lv_anim_path_linear;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.path_cb = lv_anim_path_linear;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
lv_anim_create(&a);
a.start = lv_obj_get_x(ext->scrl);
a.end = scrlable_x;
a.fp = (lv_anim_fp_t)lv_obj_set_x;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_x;
lv_anim_create(&a);
#endif
}
@@ -530,9 +546,9 @@ void lv_page_scroll_hor(lv_obj_t * page, lv_coord_t dist)
a.var = scrl;
a.start = lv_obj_get_x(scrl);
a.end = a.start + dist;
a.fp = (lv_anim_fp_t)lv_obj_set_x;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_x;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = LV_PAGE_SCROLL_ANIM_TIME;
a.playback = 0;
@@ -559,9 +575,9 @@ void lv_page_scroll_ver(lv_obj_t * page, lv_coord_t dist)
a.var = scrl;
a.start = lv_obj_get_y(scrl);
a.end = a.start + dist;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = LV_PAGE_SCROLL_ANIM_TIME;
a.playback = 0;
@@ -588,9 +604,9 @@ void lv_page_start_edge_flash(lv_obj_t * page)
a.var = page;
a.start = 0;
a.end = LV_PAGE_END_FLASH_SIZE;
a.fp = (lv_anim_fp_t)edge_flash_anim;
a.path = lv_anim_path_linear;
a.end_cb = edge_flash_anim_end;
a.exec_cb = (lv_anim_exec_cb_t)edge_flash_anim;
a.path_cb = lv_anim_path_linear;
a.ready_cb = edge_flash_anim_end;
a.act_time = 0;
a.time = LV_PAGE_END_ANIM_TIME;
a.playback = 1;
@@ -631,7 +647,7 @@ static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mo
style_tmp.body.border.width = 0;
lv_draw_rect(&page->coords, mask, &style_tmp, lv_obj_get_opa_scale(page));
} else if(mode == LV_DESIGN_DRAW_POST) { /*Draw the scroll bars finally*/
} else if(mode == LV_DESIGN_DRAW_POST) {
/*Draw only a border*/
style_tmp.body.shadow.width = 0;
style_tmp.body.opa = LV_OPA_TRANSP;
@@ -661,41 +677,46 @@ static bool lv_page_design(lv_obj_t * page, const lv_area_t * mask, lv_design_mo
lv_draw_rect(&sb_area, mask, ext->sb.style, lv_obj_get_opa_scale(page));
}
lv_coord_t page_w = lv_obj_get_width(page);
lv_coord_t page_h = lv_obj_get_height(page);
lv_area_t flash_area;
#if LV_USE_ANIMATION
{
lv_coord_t page_w = lv_obj_get_width(page);
lv_coord_t page_h = lv_obj_get_height(page);
if(ext->edge_flash.top_ip) {
flash_area.x1 = page->coords.x1 - page_w;
flash_area.x2 = page->coords.x2 + page_w;
flash_area.y1 = page->coords.y1 - 3 * page_w + ext->edge_flash.state;
flash_area.y2 = page->coords.y1 + ext->edge_flash.state;
} else if(ext->edge_flash.bottom_ip) {
flash_area.x1 = page->coords.x1 - page_w;
flash_area.x2 = page->coords.x2 + page_w;
flash_area.y1 = page->coords.y2 - ext->edge_flash.state;
flash_area.y2 = page->coords.y2 + 3 * page_w - ext->edge_flash.state;
} else if(ext->edge_flash.right_ip) {
flash_area.x1 = page->coords.x2 - ext->edge_flash.state;
flash_area.x2 = page->coords.x2 + 3 * page_h - ext->edge_flash.state;
flash_area.y1 = page->coords.y1 - page_h;
flash_area.y2 = page->coords.y2 + page_h;
} else if(ext->edge_flash.left_ip) {
flash_area.x1 = page->coords.x1 - 3 * page_h + ext->edge_flash.state;
flash_area.x2 = page->coords.x1 + ext->edge_flash.state;
flash_area.y1 = page->coords.y1 - page_h;
flash_area.y2 = page->coords.y2 + page_h;
}
lv_area_t flash_area;
if(ext->edge_flash.left_ip || ext->edge_flash.right_ip || ext->edge_flash.top_ip ||
ext->edge_flash.bottom_ip) {
lv_style_t flash_style;
lv_style_copy(&flash_style, ext->edge_flash.style);
flash_style.body.radius = LV_RADIUS_CIRCLE;
uint32_t opa = (flash_style.body.opa * ext->edge_flash.state) / LV_PAGE_END_FLASH_SIZE;
flash_style.body.opa = opa;
lv_draw_rect(&flash_area, mask, &flash_style, lv_obj_get_opa_scale(page));
if(ext->edge_flash.top_ip) {
flash_area.x1 = page->coords.x1 - page_w;
flash_area.x2 = page->coords.x2 + page_w;
flash_area.y1 = page->coords.y1 - 3 * page_w + ext->edge_flash.state;
flash_area.y2 = page->coords.y1 + ext->edge_flash.state;
} else if(ext->edge_flash.bottom_ip) {
flash_area.x1 = page->coords.x1 - page_w;
flash_area.x2 = page->coords.x2 + page_w;
flash_area.y1 = page->coords.y2 - ext->edge_flash.state;
flash_area.y2 = page->coords.y2 + 3 * page_w - ext->edge_flash.state;
} else if(ext->edge_flash.right_ip) {
flash_area.x1 = page->coords.x2 - ext->edge_flash.state;
flash_area.x2 = page->coords.x2 + 3 * page_h - ext->edge_flash.state;
flash_area.y1 = page->coords.y1 - page_h;
flash_area.y2 = page->coords.y2 + page_h;
} else if(ext->edge_flash.left_ip) {
flash_area.x1 = page->coords.x1 - 3 * page_h + ext->edge_flash.state;
flash_area.x2 = page->coords.x1 + ext->edge_flash.state;
flash_area.y1 = page->coords.y1 - page_h;
flash_area.y2 = page->coords.y2 + page_h;
}
if(ext->edge_flash.left_ip || ext->edge_flash.right_ip || ext->edge_flash.top_ip ||
ext->edge_flash.bottom_ip) {
lv_style_t flash_style;
lv_style_copy(&flash_style, ext->edge_flash.style);
flash_style.body.radius = LV_RADIUS_CIRCLE;
uint32_t opa = (flash_style.body.opa * ext->edge_flash.state) / LV_PAGE_END_FLASH_SIZE;
flash_style.body.opa = opa;
lv_draw_rect(&flash_area, mask, &flash_style, lv_obj_get_opa_scale(page));
}
}
#endif
}
return true;
@@ -770,19 +791,25 @@ static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param)
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
lv_obj_t * child;
if(sign == LV_SIGNAL_CHILD_CHG) { /*Automatically move children to the scrollable object*/
const lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);
lv_fit_t fit_left = lv_page_get_scrl_fit_left(page);
lv_fit_t fit_top = lv_page_get_scrl_fit_top(page);
child = lv_obj_get_child(page, NULL);
while(child != NULL) {
if(lv_obj_is_protected(child, LV_PROTECT_PARENT) == false) {
lv_obj_t * tmp = child;
child = lv_obj_get_child(page, child); /*Get the next child before move this*/
/*Reposition the child to take padding into account*/
const lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);
tmp->coords.x1 += style->body.padding.left;
tmp->coords.x2 += style->body.padding.left;
tmp->coords.y1 += style->body.padding.top;
tmp->coords.y2 += style->body.padding.top;
/* Reposition the child to take padding into account (Only if it's on (0;0) now)
* It's required to keep new the object on the same coordinate if FIT is enabled.*/
if((tmp->coords.x1 == page->coords.x1) && (fit_left == LV_FIT_TIGHT || fit_left == LV_FIT_FILL)) {
tmp->coords.x1 += style->body.padding.left;
tmp->coords.x2 += style->body.padding.left;
}
if((tmp->coords.y1 == page->coords.y1) && (fit_top == LV_FIT_TIGHT || fit_top == LV_FIT_FILL)) {
tmp->coords.y1 += style->body.padding.top;
tmp->coords.y2 += style->body.padding.top;
}
lv_obj_set_parent(tmp, ext->scrl);
} else {
child = lv_obj_get_child(page, child);
@@ -933,21 +960,25 @@ static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, voi
new_x = lv_area_get_width(&page_coords) - lv_area_get_width(&scrl_coords) -
page_style->body.padding.right; /* Right align */
refr_x = true;
#if LV_USE_ANIMATION
if(page_ext->edge_flash.enabled && page_ext->edge_flash.left_ip == 0 &&
page_ext->edge_flash.right_ip == 0 && page_ext->edge_flash.top_ip == 0 &&
page_ext->edge_flash.bottom_ip == 0) {
lv_page_start_edge_flash(page);
page_ext->edge_flash.right_ip = 1;
}
#endif
} else if(scrl_coords.x1 > page_coords.x1 + page_style->body.padding.left) {
new_x = page_style->body.padding.left; /*Left align*/
refr_x = true;
#if LV_USE_ANIMATION
if(page_ext->edge_flash.enabled && page_ext->edge_flash.left_ip == 0 &&
page_ext->edge_flash.right_ip == 0 && page_ext->edge_flash.top_ip == 0 &&
page_ext->edge_flash.bottom_ip == 0) {
lv_page_start_edge_flash(page);
page_ext->edge_flash.left_ip = 1;
}
#endif
}
}
@@ -972,21 +1003,25 @@ static lv_res_t lv_page_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, voi
new_y = lv_area_get_height(&page_coords) - lv_area_get_height(&scrl_coords) -
page_style->body.padding.bottom; /* Bottom align */
refr_y = true;
#if LV_USE_ANIMATION
if(page_ext->edge_flash.enabled && page_ext->edge_flash.left_ip == 0 &&
page_ext->edge_flash.right_ip == 0 && page_ext->edge_flash.top_ip == 0 &&
page_ext->edge_flash.bottom_ip == 0) {
lv_page_start_edge_flash(page);
page_ext->edge_flash.bottom_ip = 1;
}
#endif
} else if(scrl_coords.y1 > page_coords.y1 + page_style->body.padding.top) {
new_y = page_style->body.padding.top; /*Top align*/
refr_y = true;
#if LV_USE_ANIMATION
if(page_ext->edge_flash.enabled && page_ext->edge_flash.left_ip == 0 &&
page_ext->edge_flash.right_ip == 0 && page_ext->edge_flash.top_ip == 0 &&
page_ext->edge_flash.bottom_ip == 0) {
lv_page_start_edge_flash(page);
page_ext->edge_flash.top_ip = 1;
}
#endif
}
}
@@ -1044,13 +1079,21 @@ static void scrl_def_event_cb(lv_obj_t * scrl, lv_event_t event)
{
lv_obj_t * page = lv_obj_get_parent(scrl);
if(event == LV_EVENT_PRESSED || event == LV_EVENT_PRESSING || event == LV_EVENT_PRESS_LOST ||
event == LV_EVENT_RELEASED || event == LV_EVENT_SHORT_CLICKED ||
event == LV_EVENT_LONG_PRESSED || event == LV_EVENT_LONG_PRESSED_REPEAT ||
event == LV_EVENT_LONG_HOVER_IN || event == LV_EVENT_LONG_HOVER_OUT ||
event == LV_EVENT_FOCUSED || event == LV_EVENT_DEFOCUSED) {
/*clang-format off*/
if(event == LV_EVENT_PRESSED ||
event == LV_EVENT_PRESSING ||
event == LV_EVENT_PRESS_LOST ||
event == LV_EVENT_RELEASED ||
event == LV_EVENT_SHORT_CLICKED ||
event == LV_EVENT_CLICKED ||
event == LV_EVENT_LONG_PRESSED ||
event == LV_EVENT_LONG_PRESSED_REPEAT ||
event == LV_EVENT_FOCUSED ||
event == LV_EVENT_DEFOCUSED)
{
lv_event_send(page, event, lv_event_get_data());
}
/*clang-format on*/
}
/**
@@ -1110,15 +1153,16 @@ static void lv_page_sb_refresh(lv_obj_t * page)
return;
}
/*Horizontal scrollbar*/
/*Full sized horizontal scrollbar*/
if(scrl_w <=
obj_w - style->body.padding.left - style->body.padding.right) { /*Full sized scroll bar*/
obj_w - style->body.padding.left - style->body.padding.right) {
lv_area_set_width(&ext->sb.hor_area, obj_w - 2 * sb_hor_pad);
lv_area_set_pos(&ext->sb.hor_area, sb_hor_pad,
obj_h - ext->sb.style->body.padding.inner -
ext->sb.style->body.padding.bottom);
obj_h - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.bottom);
if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 0;
} else {
}
/*Smaller horizontal scrollbar*/
else {
size_tmp = (obj_w * (obj_w - (2 * sb_hor_pad))) /
(scrl_w + style->body.padding.left + style->body.padding.right);
if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE;
@@ -1135,16 +1179,16 @@ static void lv_page_sb_refresh(lv_obj_t * page)
if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.hor_draw = 1;
}
/*Vertical scrollbar*/
if(scrl_h <=
obj_h - style->body.padding.top - style->body.padding.bottom) { /*Full sized scroll bar*/
/*Full sized vertical scroll bar*/
if(scrl_h <= obj_h - style->body.padding.top - style->body.padding.bottom) {
lv_area_set_height(&ext->sb.ver_area, obj_h - 2 * sb_ver_pad);
lv_area_set_pos(&ext->sb.ver_area,
obj_w - ext->sb.style->body.padding.inner -
ext->sb.style->body.padding.right,
obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.right,
sb_ver_pad);
if(ext->sb.mode == LV_SB_MODE_AUTO || ext->sb.mode == LV_SB_MODE_DRAG) ext->sb.ver_draw = 0;
} else {
}
/*Smaller vertical scroll bar*/
else {
size_tmp = (obj_h * (obj_h - (2 * sb_ver_pad))) /
(scrl_h + style->body.padding.top + style->body.padding.bottom);
if(size_tmp < LV_PAGE_SB_MIN_SIZE) size_tmp = LV_PAGE_SB_MIN_SIZE;
@@ -1152,7 +1196,7 @@ static void lv_page_sb_refresh(lv_obj_t * page)
lv_area_set_pos(
&ext->sb.ver_area,
obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.bottom,
obj_w - ext->sb.style->body.padding.inner - ext->sb.style->body.padding.right,
sb_ver_pad +
(-(lv_obj_get_y(scrl) - ext->sb.style->body.padding.bottom) *
(obj_h - size_tmp - 2 * sb_ver_pad)) /
@@ -1180,21 +1224,23 @@ static void lv_page_sb_refresh(lv_obj_t * page)
}
}
static void edge_flash_anim(void * page, int32_t v)
#if LV_USE_ANIMATION
static void edge_flash_anim(void * page, lv_anim_value_t v)
{
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
ext->edge_flash.state = v;
lv_obj_invalidate(page);
}
static void edge_flash_anim_end(void * page)
static void edge_flash_anim_end(lv_anim_t * a)
{
lv_page_ext_t * ext = lv_obj_get_ext_attr(page);
lv_page_ext_t * ext = lv_obj_get_ext_attr(a->var);
ext->edge_flash.top_ip = 0;
ext->edge_flash.bottom_ip = 0;
ext->edge_flash.left_ip = 0;
ext->edge_flash.right_ip = 0;
lv_obj_invalidate(page);
lv_obj_invalidate(a->var);
}
#endif
#endif

View File

@@ -28,6 +28,7 @@ extern "C" {
#include "lv_cont.h"
#include "../lv_core/lv_indev.h"
#include "../lv_misc/lv_anim.h"
/*********************
* DEFINES
@@ -76,9 +77,10 @@ typedef struct
uint8_t ver_draw : 1; /*1: vertical scrollbar is visible now (Handled by the library)*/
lv_sb_mode_t mode : 3; /*Scrollbar visibility from 'lv_page_sb_mode_t'*/
} sb;
#if LV_USE_ANIMATION
struct
{
uint16_t state; /*Store the current size of the edge flash effect*/
lv_anim_value_t state; /*Store the current size of the edge flash effect*/
const lv_style_t * style; /*Style of edge flash effect (usually homogeneous circle)*/
uint8_t enabled : 1; /*1: Show a flash animation on the edge*/
uint8_t top_ip : 1; /*Used internally to show that top most position is reached (flash is In
@@ -90,6 +92,7 @@ typedef struct
uint8_t left_ip : 1; /*Used internally to show that left most position is reached (flash is
In Progress)*/
} edge_flash;
#endif
uint8_t arrow_scroll : 1; /*1: Enable scrolling with LV_KEY_LEFT/RIGHT/UP/DOWN*/
uint8_t scroll_prop : 1; /*1: Propagate the scrolling the the parent if the edge is reached*/
@@ -340,7 +343,7 @@ static inline lv_fit_t lv_page_get_scrl_fit_right(const lv_obj_t * page)
* @param page pointer to a page object
* @return an element of `lv_fit_t`
*/
static inline lv_fit_t lv_page_get_scrl_get_fit_top(const lv_obj_t * page)
static inline lv_fit_t lv_page_get_scrl_fit_top(const lv_obj_t * page)
{
return lv_cont_get_fit_top(lv_page_get_scrl(page));
}

View File

@@ -127,7 +127,7 @@ lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy)
* @param preload pointer to a preload object
* @param deg length of the arc
*/
void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg)
void lv_preload_set_arc_length(lv_obj_t * preload, lv_anim_value_t deg)
{
lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);
@@ -170,7 +170,6 @@ void lv_preload_set_style(lv_obj_t * preload, lv_preload_style_t type, const lv_
* */
void lv_preload_set_anim_type(lv_obj_t * preload, lv_preload_type_t type)
{
#if LV_USE_ANIMATION
lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);
/*delete previous animation*/
@@ -189,9 +188,9 @@ void lv_preload_set_anim_type(lv_obj_t * preload, lv_preload_type_t type)
a.start = 0;
a.end = 360;
}
a.fp = (lv_anim_fp_t)lv_preload_spinner_anim;
a.path = lv_anim_path_ease_in_out;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_preload_spinner_anim;
a.path_cb = lv_anim_path_ease_in_out;
a.ready_cb = NULL;
a.act_time = 0;
a.time = ext->time;
a.playback = 0;
@@ -211,9 +210,9 @@ void lv_preload_set_anim_type(lv_obj_t * preload, lv_preload_type_t type)
b.start = ext->arc_length;
b.end = 360 - ext->arc_length;
}
b.fp = (lv_anim_fp_t)lv_preload_set_arc_length;
b.path = lv_anim_path_ease_in_out;
b.end_cb = NULL;
b.exec_cb = (lv_anim_exec_cb_t)lv_preload_set_arc_length;
b.path_cb = lv_anim_path_ease_in_out;
b.ready_cb = NULL;
b.act_time = 0;
b.time = ext->time;
b.playback = 1;
@@ -237,9 +236,9 @@ void lv_preload_set_anim_type(lv_obj_t * preload, lv_preload_type_t type)
a.start = 0;
a.end = 360;
}
a.fp = (lv_anim_fp_t)lv_preload_spinner_anim;
a.path = lv_anim_path_ease_in_out;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_preload_spinner_anim;
a.path_cb = lv_anim_path_ease_in_out;
a.ready_cb = NULL;
a.act_time = 0;
a.time = ext->time;
a.playback = 0;
@@ -250,8 +249,6 @@ void lv_preload_set_anim_type(lv_obj_t * preload, lv_preload_type_t type)
break;
}
}
#endif // LV_USE_ANIMATION
}
void lv_preload_set_anim_dir(lv_obj_t * preload, lv_preload_dir_t dir) {
@@ -269,7 +266,7 @@ void lv_preload_set_anim_dir(lv_obj_t * preload, lv_preload_dir_t dir) {
* Get the arc length [degree] of the a pre loader
* @param preload pointer to a pre loader object
*/
uint16_t lv_preload_get_arc_length(const lv_obj_t * preload)
lv_anim_value_t lv_preload_get_arc_length(const lv_obj_t * preload)
{
lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);
return ext->arc_length;
@@ -328,7 +325,7 @@ lv_preload_dir_t lv_preload_get_anim_dir(lv_obj_t * preload) {
* @param ptr pointer to preloader
* @param val the current desired value [0..360]
*/
void lv_preload_spinner_anim(void * ptr, int32_t val)
void lv_preload_spinner_anim(void * ptr, lv_anim_value_t val)
{
lv_obj_t * preload = ptr;
lv_preload_ext_t * ext = lv_obj_get_ext_attr(preload);

View File

@@ -31,6 +31,7 @@ extern "C" {
#endif
#include "../lv_core/lv_obj.h"
#include "../lv_misc/lv_anim.h"
#include "lv_arc.h"
/*********************
@@ -58,7 +59,7 @@ typedef struct
{
lv_arc_ext_t arc; /*Ext. of ancestor*/
/*New data for this type */
uint16_t arc_length; /*Length of the spinning indicator in degree*/
lv_anim_value_t arc_length; /*Length of the spinning indicator in degree*/
uint16_t time; /*Time of one round*/
lv_preload_type_t anim_type:1; /*Type of the arc animation*/
lv_preload_dir_t anim_dir:1; /*Animation Direction*/
@@ -92,7 +93,7 @@ lv_obj_t * lv_preload_create(lv_obj_t * par, const lv_obj_t * copy);
* @param preload pointer to a preload object
* @param deg length of the arc
*/
void lv_preload_set_arc_length(lv_obj_t * preload, uint16_t deg);
void lv_preload_set_arc_length(lv_obj_t * preload, lv_anim_value_t deg);
/**
* Set the spin time of the arc
@@ -135,7 +136,7 @@ void lv_preload_set_anim_dir(lv_obj_t * preload, lv_preload_dir_t dir);
* Get the arc length [degree] of the a pre loader
* @param preload pointer to a pre loader object
*/
uint16_t lv_preload_get_arc_length(const lv_obj_t * preload);
lv_anim_value_t lv_preload_get_arc_length(const lv_obj_t * preload);
/**
* Get the spin time of the arc
@@ -175,7 +176,7 @@ lv_preload_dir_t lv_preload_get_anim_dir(lv_obj_t * preload);
* @param type which style should be get
* @return style pointer to the style
* */
void lv_preload_spinner_anim(void * ptr, int32_t val);
void lv_preload_spinner_anim(void * ptr, lv_anim_value_t val);
/**********************
* MACROS

View File

@@ -17,7 +17,7 @@
* DEFINES
*********************/
#if LV_USE_ANIMATION
#ifndef LV_ROLLER_ANIM_TIME
#ifndef LV_ROLLER_DEF_ANIM_TIME
#define LV_ROLLER_DEF_ANIM_TIME 200 /*ms*/
#endif
#else
@@ -36,7 +36,11 @@ static bool lv_roller_design(lv_obj_t * roller, const lv_area_t * mask, lv_desig
static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign, void * param);
static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * param);
static void refr_position(lv_obj_t * roller, bool anim_en);
static void refr_height(lv_obj_t * roller);
static void inf_normalize(void * roller_scrl);
#if LV_USE_ANIMATION
static void scroll_anim_ready_cb(lv_anim_t * a);
#endif
static void draw_bg(lv_obj_t * roller, const lv_area_t * mask);
/**********************
@@ -86,8 +90,7 @@ lv_obj_t * lv_roller_create(lv_obj_t * par, const lv_obj_t * copy)
if(copy == NULL) {
lv_obj_t * scrl = lv_page_get_scrl(new_roller);
lv_obj_set_drag(scrl, true); /*In ddlist it might be disabled*/
lv_page_set_scrl_fit2(new_roller, LV_FIT_TIGHT,
LV_FIT_NONE); /*Height is specified directly*/
lv_page_set_scrl_fit2(new_roller, LV_FIT_TIGHT, LV_FIT_NONE); /*Height is specified directly*/
lv_ddlist_open(new_roller, false);
lv_ddlist_set_anim_time(new_roller, LV_ROLLER_DEF_ANIM_TIME);
lv_ddlist_set_stay_open(new_roller, true);
@@ -140,6 +143,11 @@ void lv_roller_set_options(lv_obj_t * roller, const char * options, bool inf)
if(inf == false) {
ext->inf = 0;
lv_ddlist_set_options(roller, options);
/* Make sure the roller's height and the scrollable's height is refreshed.
* They are refreshed in `LV_SIGNAL_COORD_CHG` but if the new options has the same width
* that signal won't be called. (It called because LV_FIT_TIGHT hor fit)*/
refr_height(roller);
} else {
ext->inf = 1;
@@ -154,9 +162,13 @@ void lv_roller_set_options(lv_obj_t * roller, const char * options, bool inf)
lv_ddlist_set_options(roller, opt_extra);
lv_mem_free(opt_extra);
/* Make sure the roller's height and the scrollable's height is refreshed.
* They are refreshed in `LV_SIGNAL_COORD_CHG` but if the new options has the same width
* that signal won't be called. (It called because LV_FIT_TIGHT hor fit)*/
refr_height(roller);
uint16_t real_id_cnt = ext->ddlist.option_cnt / LV_ROLLER_INF_PAGES;
ext->ddlist.sel_opt_id =
((LV_ROLLER_INF_PAGES / 2) + 1) * real_id_cnt; /*Select the middle page*/
lv_roller_set_selected(roller, ((LV_ROLLER_INF_PAGES / 2) + 1) * real_id_cnt, false); /*Select the middle page*/
}
}
@@ -386,21 +398,9 @@ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * par
}
lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);
lv_align_t obj_align = LV_ALIGN_IN_LEFT_MID;
if(ext->ddlist.label) {
lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label);
if(LV_LABEL_ALIGN_CENTER == label_align)
obj_align = LV_ALIGN_CENTER;
else if(LV_LABEL_ALIGN_RIGHT == label_align)
obj_align = LV_ALIGN_IN_RIGHT_MID;
}
if(sign == LV_SIGNAL_STYLE_CHG) {
lv_obj_set_height(lv_page_get_scrl(roller),
lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller));
lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0);
lv_anim_del(lv_page_get_scrl(roller), (lv_anim_fp_t)lv_obj_set_y);
lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id);
refr_height(roller);
refr_position(roller, false);
} else if(sign == LV_SIGNAL_CORD_CHG) {
@@ -408,12 +408,10 @@ static lv_res_t lv_roller_signal(lv_obj_t * roller, lv_signal_t sign, void * par
if(lv_obj_get_width(roller) != lv_area_get_width(param) ||
lv_obj_get_height(roller) != lv_area_get_height(param)) {
lv_ddlist_set_fix_height(roller, lv_obj_get_height(roller));
lv_obj_set_height(lv_page_get_scrl(roller),
lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller));
lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0);
lv_anim_del(lv_page_get_scrl(roller), (lv_anim_fp_t)lv_obj_set_y);
refr_height(roller);
#if LV_USE_ANIMATION
lv_anim_del(lv_page_get_scrl(roller), (lv_anim_exec_cb_t)lv_obj_set_y);
#endif
lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id);
refr_position(roller, false);
}
@@ -512,7 +510,8 @@ static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign,
lv_coord_t label_y1 = ext->ddlist.label->coords.y1 - roller->coords.y1;
lv_coord_t label_unit = font_h + style_label->text.line_space;
lv_coord_t mid = (roller->coords.y2 - roller->coords.y1) / 2;
id = (mid - label_y1 + style_label->text.line_space / 2) / label_unit;
id = (mid - label_y1 + style_label->text.line_space / 2) / label_unit;
if(id < 0) id = 0;
if(id >= ext->ddlist.option_cnt) id = ext->ddlist.option_cnt - 1;
@@ -521,19 +520,25 @@ static lv_res_t lv_roller_scrl_signal(lv_obj_t * roller_scrl, lv_signal_t sign,
ext->ddlist.sel_opt_id_ori = id;
res = lv_event_send(roller, LV_EVENT_VALUE_CHANGED, &id);
if(res != LV_RES_OK) return res;
} else if(sign == LV_SIGNAL_RELEASED) {
/*If picked an option by clicking then set it*/
}
/*If picked an option by clicking then set it*/
else if(sign == LV_SIGNAL_RELEASED) {
if(!lv_indev_is_dragging(indev)) {
id = ext->ddlist.sel_opt_id;
#if LV_USE_GROUP
/*In edit mode go to navigate mode if an option is selected*/
lv_group_t * g = lv_obj_get_group(roller);
bool editing = lv_group_get_editing(g);
if(editing)
lv_group_set_editing(
g, false); /*In edit mode go to navigate mode if an option is selected*/
lv_group_set_editing(g, false);
#endif
}
}
else if(sign == LV_SIGNAL_PRESSED) {
#if LV_USE_ANIMATION
lv_anim_del(roller_scrl, (lv_anim_exec_cb_t)lv_obj_set_y);
#endif
}
/*Position the scrollable according to the new selected option*/
if(id != -1) {
@@ -615,7 +620,11 @@ static void refr_position(lv_obj_t * roller, bool anim_en)
/* Normally the animtaion's `end_cb` sets correct position of the roller is infinite.
* But without animations do it manually*/
if(anim_en == false || ext->ddlist.anim_time == 0) {
if(anim_en == false
#if LV_USE_ANIMATION
|| ext->ddlist.anim_time == 0
#endif
) {
inf_normalize(roller_scrl);
}
@@ -624,7 +633,11 @@ static void refr_position(lv_obj_t * roller, bool anim_en)
ext->ddlist.label->coords.y1 - roller_scrl->coords.y1;
lv_coord_t new_y = -line_y1 + (h - font_h) / 2;
if(ext->ddlist.anim_time == 0 || anim_en == false) {
if( anim_en == false
#if LV_USE_ANIMATION
|| ext->ddlist.anim_time == 0
#endif
) {
lv_obj_set_y(roller_scrl, new_y);
} else {
#if LV_USE_ANIMATION
@@ -632,9 +645,9 @@ static void refr_position(lv_obj_t * roller, bool anim_en)
a.var = roller_scrl;
a.start = lv_obj_get_y(roller_scrl);
a.end = new_y;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.path = lv_anim_path_linear;
a.end_cb = inf_normalize;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
a.path_cb = lv_anim_path_linear;
a.ready_cb = scroll_anim_ready_cb;
a.act_time = 0;
a.time = ext->ddlist.anim_time;
a.playback = 0;
@@ -646,6 +659,31 @@ static void refr_position(lv_obj_t * roller, bool anim_en)
}
}
/**
* Refresh the height of the roller and the scrolable
* @param roller pointer to roller
*/
static void refr_height(lv_obj_t * roller)
{
lv_roller_ext_t * ext = lv_obj_get_ext_attr(roller);
lv_align_t obj_align = LV_ALIGN_IN_LEFT_MID;
if(ext->ddlist.label) {
lv_label_align_t label_align = lv_label_get_align(ext->ddlist.label);
if(LV_LABEL_ALIGN_CENTER == label_align)
obj_align = LV_ALIGN_CENTER;
else if(LV_LABEL_ALIGN_RIGHT == label_align)
obj_align = LV_ALIGN_IN_RIGHT_MID;
}
lv_obj_set_height(lv_page_get_scrl(roller),
lv_obj_get_height(ext->ddlist.label) + lv_obj_get_height(roller));
lv_obj_align(ext->ddlist.label, NULL, obj_align, 0, 0);
#if LV_USE_ANIMATION
lv_anim_del(lv_page_get_scrl(roller), (lv_anim_exec_cb_t)lv_obj_set_y);
#endif
lv_ddlist_set_selected(roller, ext->ddlist.sel_opt_id);
}
/**
* Set the middle page for the roller if inifinte is enabled
* @param scrl pointer to the roller's scrollable (lv_obj_t *)
@@ -677,4 +715,11 @@ static void inf_normalize(void * scrl)
}
}
#if LV_USE_ANIMATION
static void scroll_anim_ready_cb(lv_anim_t * a)
{
inf_normalize(a->var);
}
#endif
#endif

View File

@@ -104,7 +104,7 @@ void lv_roller_set_visible_row_count(lv_obj_t * roller, uint8_t row_cnt);
*/
static inline void lv_roller_set_hor_fit(lv_obj_t * roller, lv_fit_t fit)
{
lv_ddlist_set_fit(roller, fit);
lv_ddlist_set_hor_fit(roller, fit);
}
/**

View File

@@ -321,6 +321,7 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
if(slider_w >= slider_h) {
lv_coord_t indic_w = lv_area_get_width(&area_indic);
#if LV_USE_ANIMATION
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
/*Calculate the coordinates of anim. start and end*/
lv_coord_t anim_start_x =
@@ -334,7 +335,10 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
* `anim_end`)*/
area_indic.x2 =
anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
} else {
}
else
#endif
{
area_indic.x2 =
(int32_t)((int32_t)indic_w * (cur_value - min_value)) / (max_value - min_value);
}
@@ -347,6 +351,7 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
} else {
lv_coord_t indic_h = lv_area_get_height(&area_indic);
#if LV_USE_ANIMATION
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
/*Calculate the coordinates of anim. start and end*/
lv_coord_t anim_start_y =
@@ -360,7 +365,10 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
* `anim_end`)*/
area_indic.y1 =
anim_start_y + (((anim_end_y - anim_start_y) * ext->bar.anim_state) >> 8);
} else {
}
else
#endif
{
area_indic.y1 =
(int32_t)((int32_t)indic_h * (cur_value - min_value)) / (max_value - min_value);
}
@@ -395,6 +403,7 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
knob_area.x1 = area_indic.x2 - slider_h / 2;
knob_area.x2 = knob_area.x1 + slider_h - 1;
} else {
#if LV_USE_ANIMATION
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
lv_coord_t w = slider_w - slider_h - 1;
lv_coord_t anim_start_x =
@@ -408,7 +417,9 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
* `anim_end`)*/
knob_area.x1 =
anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
} else {
} else
#endif
{
knob_area.x1 =
(int32_t)((int32_t)(slider_w - slider_h - 1) * (cur_value - min_value)) /
(max_value - min_value);
@@ -425,6 +436,7 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
knob_area.y1 = area_indic.y1 - slider_w / 2;
knob_area.y2 = knob_area.y1 + slider_w - 1;
} else {
#if LV_USE_ANIMATION
if(ext->bar.anim_state != LV_BAR_ANIM_STATE_INV) {
lv_coord_t h = slider_h - slider_w - 1;
lv_coord_t anim_start_x =
@@ -438,7 +450,9 @@ static bool lv_slider_design(lv_obj_t * slider, const lv_area_t * mask, lv_desig
* `anim_end`)*/
knob_area.y2 =
anim_start_x + (((anim_end_x - anim_start_x) * ext->bar.anim_state) >> 8);
} else {
} else
#endif
{
knob_area.y2 =
(int32_t)((int32_t)(slider_h - slider_w - 1) * (cur_value - min_value)) /
(max_value - min_value);

View File

@@ -42,8 +42,7 @@ typedef struct
lv_bar_ext_t bar; /*Ext. of ancestor*/
/*New data for this type */
const lv_style_t * style_knob; /*Style of the knob*/
int16_t
drag_value; /*Store a temporal value during press until release (Handled by the library)*/
int16_t drag_value; /*Store a temporal value during press until release (Handled by the library)*/
uint8_t knob_in : 1; /*1: Draw the knob inside the bar*/
} lv_slider_ext_t;

View File

@@ -38,9 +38,6 @@ extern "C" {
* TYPEDEFS
**********************/
/*callback on value change*/
typedef void (*lv_spinbox_value_changed_cb_t)(lv_obj_t * spinbox, int32_t new_value);
/*Data of spinbox*/
typedef struct
{

View File

@@ -202,6 +202,9 @@ void lv_sw_set_anim_time(lv_obj_t * sw, uint16_t anim_time)
#if LV_USE_ANIMATION
lv_sw_ext_t * ext = lv_obj_get_ext_attr(sw);
ext->anim_time = anim_time;
#else
(void) sw;
(void) anim_time;
#endif
}

View File

@@ -107,7 +107,6 @@ bool lv_sw_toggle(lv_obj_t * sw, bool anim);
*/
void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, const lv_style_t * style);
#if LV_USE_ANIMATION
/**
* Set the animation time of the switch
* @param sw pointer to a switch object
@@ -115,7 +114,6 @@ void lv_sw_set_style(lv_obj_t * sw, lv_sw_style_t type, const lv_style_t * style
* @return style pointer to a style
*/
void lv_sw_set_anim_time(lv_obj_t * sw, uint16_t anim_time);
#endif
/*=====================
* Getter functions

View File

@@ -22,12 +22,12 @@
*********************/
/*Test configuration*/
#ifndef LV_TA_CURSOR_BLINK_TIME
#define LV_TA_CURSOR_BLINK_TIME 400 /*ms*/
#ifndef LV_TA_DEF_CURSOR_BLINK_TIME
#define LV_TA_DEF_CURSOR_BLINK_TIME 400 /*ms*/
#endif
#ifndef LV_TA_PWD_SHOW_TIME
#define LV_TA_PWD_SHOW_TIME 1500 /*ms*/
#ifndef LV_TA_DEF_PWD_SHOW_TIME
#define LV_TA_DEF_PWD_SHOW_TIME 1500 /*ms*/
#endif
#define LV_TA_DEF_WIDTH (2 * LV_DPI)
@@ -45,8 +45,9 @@ static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_
static lv_res_t lv_ta_signal(lv_obj_t * ta, lv_signal_t sign, void * param);
static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void * param);
#if LV_USE_ANIMATION
static void cursor_blink_anim(lv_obj_t * ta, uint8_t show);
static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x);
static void cursor_blink_anim(lv_obj_t * ta, lv_anim_value_t show);
static void pwd_char_hider_anim(lv_obj_t * ta, lv_anim_value_t x);
static void pwd_char_hider_anim_ready(lv_anim_t * a);
#endif
static void pwd_char_hider(lv_obj_t * ta);
static bool char_is_accepted(lv_obj_t * ta, uint32_t c);
@@ -101,16 +102,24 @@ lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy)
ext->cursor.state = 1;
ext->pwd_mode = 0;
ext->pwd_tmp = NULL;
ext->pwd_show_time = LV_TA_DEF_PWD_SHOW_TIME;
ext->accapted_chars = NULL;
ext->max_length = 0;
ext->cursor.style = NULL;
ext->cursor.blink_time = LV_TA_DEF_CURSOR_BLINK_TIME;
ext->cursor.pos = 0;
ext->cursor.type = LV_CURSOR_LINE;
ext->cursor.valid_x = 0;
ext->one_line = 0;
ext->text_sel_en = 0;
ext->label = NULL;
ext->placeholder = NULL;
#if LV_USE_ANIMATION
ext->pwd_show_time = 0;
ext->cursor.blink_time = 0;
#endif
lv_obj_set_signal_cb(new_ta, lv_ta_signal);
lv_obj_set_signal_cb(lv_page_get_scrl(new_ta), lv_ta_scrollable_signal);
lv_obj_set_design_cb(new_ta, lv_ta_design);
@@ -160,21 +169,23 @@ lv_obj_t * lv_ta_create(lv_obj_t * par, const lv_obj_t * copy)
}
#if LV_USE_ANIMATION
/*Create a cursor blinker animation*/
lv_anim_t a;
a.var = new_ta;
a.fp = (lv_anim_fp_t)cursor_blink_anim;
a.time = LV_TA_CURSOR_BLINK_TIME;
a.act_time = 0;
a.end_cb = NULL;
a.start = 1;
a.end = 0;
a.repeat = 1;
a.repeat_pause = 0;
a.playback = 1;
a.playback_pause = 0;
a.path = lv_anim_path_step;
lv_anim_create(&a);
if(ext->cursor.blink_time) {
/*Create a cursor blinker animation*/
lv_anim_t a;
a.var = new_ta;
a.exec_cb = (lv_anim_exec_cb_t)cursor_blink_anim;
a.time = ext->cursor.blink_time;
a.act_time = 0;
a.ready_cb = NULL;
a.start = 1;
a.end = 0;
a.repeat = 1;
a.repeat_pause = 0;
a.playback = 1;
a.playback_pause = 0;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
}
#endif
LV_LOG_INFO("text area created");
@@ -244,22 +255,23 @@ void lv_ta_add_char(lv_obj_t * ta, uint32_t c)
lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, (const char *)letter_buf);
#if LV_USE_ANIMATION && LV_TA_PWD_SHOW_TIME > 0
#if LV_USE_ANIMATION
/*Auto hide characters*/
lv_anim_t a;
a.var = ta;
a.fp = (lv_anim_fp_t)pwd_char_hider_anim;
a.time = LV_TA_PWD_SHOW_TIME;
a.exec_cb = (lv_anim_exec_cb_t)pwd_char_hider_anim;
a.time = ext->pwd_show_time;
a.act_time = 0;
a.end_cb = (lv_anim_cb_t)pwd_char_hider;
a.ready_cb = pwd_char_hider_anim_ready;
a.start = 0;
a.end = 1;
a.repeat = 0;
a.repeat_pause = 0;
a.playback = 0;
a.playback_pause = 0;
a.path = lv_anim_path_step;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
#else
pwd_char_hider(ta);
#endif
@@ -324,22 +336,22 @@ void lv_ta_add_text(lv_obj_t * ta, const char * txt)
lv_txt_ins(ext->pwd_tmp, ext->cursor.pos, txt);
#if LV_USE_ANIMATION && LV_TA_PWD_SHOW_TIME > 0
/*Auto hide characters*/
lv_anim_t a;
a.var = ta;
a.fp = (lv_anim_fp_t)pwd_char_hider_anim;
a.time = LV_TA_PWD_SHOW_TIME;
a.act_time = 0;
a.end_cb = (lv_anim_cb_t)pwd_char_hider;
a.start = 0;
a.end = 1;
a.repeat = 0;
a.repeat_pause = 0;
a.playback = 0;
a.playback_pause = 0;
a.path = lv_anim_path_step;
lv_anim_create(&a);
#if LV_USE_ANIMATION
/*Auto hide characters*/
lv_anim_t a;
a.var = ta;
a.exec_cb = (lv_anim_exec_cb_t)pwd_char_hider_anim;
a.time = ext->pwd_show_time;
a.act_time = 0;
a.ready_cb = pwd_char_hider_anim_ready;
a.start = 0;
a.end = 1;
a.repeat = 0;
a.repeat_pause = 0;
a.playback = 0;
a.playback_pause = 0;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
#else
pwd_char_hider(ta);
#endif
@@ -464,22 +476,22 @@ void lv_ta_set_text(lv_obj_t * ta, const char * txt)
if(ext->pwd_tmp == NULL) return;
strcpy(ext->pwd_tmp, txt);
#if LV_USE_ANIMATION && LV_TA_PWD_SHOW_TIME > 0
/*Auto hide characters*/
lv_anim_t a;
a.var = ta;
a.fp = (lv_anim_fp_t)pwd_char_hider_anim;
a.time = LV_TA_PWD_SHOW_TIME;
a.act_time = 0;
a.end_cb = (lv_anim_cb_t)pwd_char_hider;
a.start = 0;
a.end = 1;
a.repeat = 0;
a.repeat_pause = 0;
a.playback = 0;
a.playback_pause = 0;
a.path = lv_anim_path_step;
lv_anim_create(&a);
#if LV_USE_ANIMATION
/*Auto hide characters*/
lv_anim_t a;
a.var = ta;
a.exec_cb = (lv_anim_exec_cb_t)pwd_char_hider_anim;
a.time = ext->pwd_show_time;
a.act_time = 0;
a.ready_cb = pwd_char_hider_anim_ready;
a.start = 0;
a.end = 1;
a.repeat = 0;
a.repeat_pause = 0;
a.playback = 0;
a.playback_pause = 0;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
#else
pwd_char_hider(ta);
#endif
@@ -571,21 +583,23 @@ void lv_ta_set_cursor_pos(lv_obj_t * ta, int16_t pos)
ext->cursor.valid_x = cur_pos.x;
#if LV_USE_ANIMATION
/*Reset cursor blink animation*/
lv_anim_t a;
a.var = ta;
a.fp = (lv_anim_fp_t)cursor_blink_anim;
a.time = LV_TA_CURSOR_BLINK_TIME;
a.act_time = 0;
a.end_cb = NULL;
a.start = 1;
a.end = 0;
a.repeat = 1;
a.repeat_pause = 0;
a.playback = 1;
a.playback_pause = 0;
a.path = lv_anim_path_step;
lv_anim_create(&a);
if(ext->cursor.blink_time) {
/*Reset cursor blink animation*/
lv_anim_t a;
a.var = ta;
a.exec_cb = (lv_anim_exec_cb_t)cursor_blink_anim;
a.time = ext->cursor.blink_time;
a.act_time = 0;
a.ready_cb = NULL;
a.start = 1;
a.end = 0;
a.repeat = 1;
a.repeat_pause = 0;
a.playback = 1;
a.playback_pause = 0;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
}
#endif
refr_cursor_area(ta);
@@ -793,11 +807,72 @@ void lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, const lv_style_t * style
* @param ta pointer to a text area object
* @param en true or false to enable/disable selection mode
*/
void lv_ta_set_sel_mode(lv_obj_t * ta, bool en)
void lv_ta_set_text_sel(lv_obj_t * ta, bool en)
{
#if LV_LABEL_TEXT_SEL
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
ext->sel_mode = en;
ext->text_sel_en = en;
if(!en) lv_ta_clear_selection(ta);
#else
(void) ta; /*Unused*/
(void) en; /*Unused*/
#endif
}
/**
* Set how long show the password before changing it to '*'
* @param ta pointer to Text area
* @param time show time in milliseconds. 0: hide immediately.
*/
void lv_ta_set_pwd_show_time(lv_obj_t * ta, uint16_t time)
{
#if LV_USE_ANIMATION == 0
time = 0;
#endif
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
ext->pwd_show_time = time;
}
/**
* Set cursor blink animation time
* @param ta pointer to Text area
* @param time blink period. 0: disable blinking
*/
void lv_ta_set_cursor_blink_time(lv_obj_t * ta, uint16_t time)
{
#if LV_USE_ANIMATION == 0
time = 0;
#endif
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
ext->cursor.blink_time = time;
#if LV_USE_ANIMATION
if(ext->cursor.blink_time) {
/*Reset cursor blink animation*/
lv_anim_t a;
a.var = ta;
a.exec_cb = (lv_anim_exec_cb_t)cursor_blink_anim;
a.time = ext->cursor.blink_time;
a.act_time = 0;
a.ready_cb = NULL;
a.start = 1;
a.end = 0;
a.repeat = 1;
a.repeat_pause = 0;
a.playback = 1;
a.playback_pause = 0;
a.path_cb = lv_anim_path_step;
lv_anim_create(&a);
} else {
ext->cursor.state = 1;
}
#else
ext->cursor.state = 1;
#endif
}
/*=====================
@@ -942,32 +1017,6 @@ const lv_style_t * lv_ta_get_style(const lv_obj_t * ta, lv_ta_style_t type)
return style;
}
/**
* Get the selection index of the text area.
*
* The last character is exclusive (i.e. if the API says that the selection
* ranges from 6 to 7, only character 6 is selected).
* @param ta Text area object
* @param sel_start pointer to int used to hold first selected character
* @param sel_end pointer to int used to hold last selected character
*/
void lv_ta_get_selection(lv_obj_t * ta, int * sel_start, int * sel_end)
{
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
/*Force both values to -1 if there is no selection*/
if(ext_label->selection_start == -1 || ext_label->selection_end == -1) {
*sel_start = -1;
*sel_end = -1;
return;
}
*sel_start = ext_label->selection_start;
*sel_end = ext_label->selection_end;
}
/**
* Find whether text is selected or not.
* @param ta Text area object
@@ -975,10 +1024,19 @@ void lv_ta_get_selection(lv_obj_t * ta, int * sel_start, int * sel_end)
*/
bool lv_ta_text_is_selected(const lv_obj_t * ta)
{
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
#if LV_LABEL_TEXT_SEL
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
return (ext_label->selection_start == -1 || ext_label->selection_end == -1);
if((lv_label_get_text_sel_start(ext->label) == LV_LABEL_TEXT_SEL_OFF ||
lv_label_get_text_sel_end(ext->label) == LV_LABEL_TEXT_SEL_OFF)){
return true;
} else {
return false;
}
#else
(void) ta; /*Unused*/
return false;
#endif
}
/**
@@ -986,11 +1044,38 @@ bool lv_ta_text_is_selected(const lv_obj_t * ta)
* @param ta pointer to a text area object
* @return true: selection mode is enabled, false: disabled
*/
bool lv_ta_get_sel_mode(lv_obj_t * ta)
bool lv_ta_get_text_sel_en(lv_obj_t * ta)
{
#if LV_LABEL_TEXT_SEL
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
return ext->text_sel_en;
#else
(void) ta; /*Unused*/
return false;
#endif
}
/**
* Set how long show the password before changing it to '*'
* @param ta pointer to Text area
* @return show time in milliseconds. 0: hide immediately.
*/
uint16_t lv_ta_get_pwd_show_time(lv_obj_t * ta)
{
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
return ext->sel_mode;
return ext->pwd_show_time;
}
/**
* Set cursor blink animation time
* @param ta pointer to Text area
* @return time blink period. 0: disable blinking
*/
uint16_t lv_ta_get_cursor_blink_time(lv_obj_t * ta)
{
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
return ext->cursor.blink_time;
}
/*=====================
@@ -1003,14 +1088,17 @@ bool lv_ta_get_sel_mode(lv_obj_t * ta)
*/
void lv_ta_clear_selection(lv_obj_t * ta)
{
#if LV_LABEL_TEXT_SEL
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
if(ext_label->selection_start != -1 || ext_label->selection_end != -1) {
ext_label->selection_start = -1;
ext_label->selection_end = -1;
lv_obj_invalidate(ta);
if(lv_label_get_text_sel_start(ext->label) != LV_LABEL_TEXT_SEL_OFF ||
lv_label_get_text_sel_end(ext->label) != LV_LABEL_TEXT_SEL_OFF){
lv_label_set_text_sel_start(ext->label, LV_LABEL_TEXT_SEL_OFF);
lv_label_set_text_sel_end(ext->label, LV_LABEL_TEXT_SEL_OFF);
}
#else
(void) ta; /*Unused*/
#endif
}
/**
@@ -1182,7 +1270,7 @@ static bool lv_ta_scrollable_design(lv_obj_t * scrl, const lv_area_t * mask, lv_
cur_area.x1 += cur_style.body.padding.left;
cur_area.y1 += cur_style.body.padding.top;
lv_draw_label(&cur_area, mask, &cur_style, opa_scale, letter_buf, LV_TXT_FLAG_NONE, 0,
-1, -1);
LV_LABEL_TEXT_SEL_OFF, LV_LABEL_TEXT_SEL_OFF);
} else if(ext->cursor.type == LV_CURSOR_OUTLINE) {
cur_style.body.opa = LV_OPA_TRANSP;
@@ -1387,7 +1475,7 @@ static lv_res_t lv_ta_scrollable_signal(lv_obj_t * scrl, lv_signal_t sign, void
* @param ta pointer to a text area
* @param hide 1: hide the cursor, 0: show it
*/
static void cursor_blink_anim(lv_obj_t * ta, uint8_t show)
static void cursor_blink_anim(lv_obj_t * ta, lv_anim_value_t show)
{
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
if(show != ext->cursor.state) {
@@ -1412,12 +1500,21 @@ static void cursor_blink_anim(lv_obj_t * ta, uint8_t show)
* @param ta unused
* @param x unused
*/
static void pwd_char_hider_anim(lv_obj_t * ta, int32_t x)
static void pwd_char_hider_anim(lv_obj_t * ta, lv_anim_value_t x)
{
(void)ta;
(void)x;
}
/**
* Call when an animation is ready to convert all characters to '*'
* @param a pointer to the animation
*/
static void pwd_char_hider_anim_ready(lv_anim_t * a)
{
lv_obj_t * ta = a->var;
pwd_char_hider(ta);
}
#endif
/**
@@ -1640,18 +1737,12 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign,
}
lv_ta_ext_t * ext = lv_obj_get_ext_attr(ta);
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
lv_area_t label_coords;
bool click_outside_label;
uint16_t index_of_char_at_position;
lv_obj_get_coords(ext->label, &label_coords);
lv_point_t point_act, vect_act;
lv_indev_get_point(click_source, &point_act);
lv_indev_get_vect(click_source, &vect_act);
if(point_act.x < 0 || point_act.y < 0) return; /*Ignore event from keypad*/
@@ -1661,6 +1752,12 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign,
lv_coord_t label_width = lv_obj_get_width(ext->label);
uint16_t index_of_char_at_position;
#if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
bool click_outside_label;
/*Check if the click happened on the left side of the area outside the label*/
if(relative_position.x < 0) {
index_of_char_at_position = 0;
@@ -1675,52 +1772,71 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign,
click_outside_label = !lv_label_is_char_under_pos(ext->label, &relative_position);
}
if(ext->sel_mode && !ext->selecting && !click_outside_label && sign == LV_SIGNAL_PRESSED) {
/*Input device just went down. Store the selection start position*/
ext->tmp_sel_start = index_of_char_at_position;
ext->tmp_sel_end = -1;
ext->selecting = 1;
lv_obj_set_drag(lv_page_get_scrl(ta), false);
} else if(ext->selecting && sign == LV_SIGNAL_PRESSING) {
/*Input device may be moving. Store the end position */
ext->tmp_sel_end = index_of_char_at_position;
} else if(ext->selecting && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) {
/*Input device is released. Check if anything was selected.*/
lv_obj_set_drag(lv_page_get_scrl(ta), true);
if(ext->text_sel_en) {
if(!ext->text_sel_in_prog && !click_outside_label && sign == LV_SIGNAL_PRESSED) {
/*Input device just went down. Store the selection start position*/
ext->tmp_sel_start = index_of_char_at_position;
ext->tmp_sel_end = LV_LABEL_TEXT_SEL_OFF;
ext->text_sel_in_prog = 1;
lv_obj_set_drag(lv_page_get_scrl(ta), false);
} else if(ext->text_sel_in_prog && sign == LV_SIGNAL_PRESSING) {
/*Input device may be moving. Store the end position */
ext->tmp_sel_end = index_of_char_at_position;
} else if(ext->text_sel_in_prog && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) {
/*Input device is released. Check if anything was selected.*/
lv_obj_set_drag(lv_page_get_scrl(ta), true);
}
}
if(ext->selecting || sign == LV_SIGNAL_PRESSED)
if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED)
lv_ta_set_cursor_pos(ta, index_of_char_at_position);
if(ext->selecting) {
if(ext->text_sel_in_prog) {
/*If the selected area has changed then update the real values and*/
/*invalidate the text area.*/
if(ext->tmp_sel_start > ext->tmp_sel_end) {
if(ext_label->selection_start != ext->tmp_sel_end ||
ext_label->selection_end != ext->tmp_sel_start) {
ext_label->selection_start = ext->tmp_sel_end;
ext_label->selection_end = ext->tmp_sel_start;
if(ext_label->txt_sel_start != ext->tmp_sel_end ||
ext_label->txt_sel_end != ext->tmp_sel_start) {
ext_label->txt_sel_start = ext->tmp_sel_end;
ext_label->txt_sel_end = ext->tmp_sel_start;
lv_obj_invalidate(ta);
}
} else if(ext->tmp_sel_start < ext->tmp_sel_end) {
if(ext_label->selection_start != ext->tmp_sel_start ||
ext_label->selection_end != ext->tmp_sel_end) {
ext_label->selection_start = ext->tmp_sel_start;
ext_label->selection_end = ext->tmp_sel_end;
if(ext_label->txt_sel_start != ext->tmp_sel_start ||
ext_label->txt_sel_end != ext->tmp_sel_end) {
ext_label->txt_sel_start = ext->tmp_sel_start;
ext_label->txt_sel_end = ext->tmp_sel_end;
lv_obj_invalidate(ta);
}
} else {
if(ext_label->selection_start != -1 || ext_label->selection_end != -1) {
ext_label->selection_start = -1;
ext_label->selection_end = -1;
if(ext_label->txt_sel_start != LV_LABEL_TEXT_SEL_OFF ||
ext_label->txt_sel_end != LV_LABEL_TEXT_SEL_OFF) {
ext_label->txt_sel_start = LV_LABEL_TEXT_SEL_OFF;
ext_label->txt_sel_end = LV_LABEL_TEXT_SEL_OFF;
lv_obj_invalidate(ta);
}
}
/*Finish selection if necessary */
if(sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED) {
ext->selecting = 0;
ext->text_sel_in_prog = 0;
}
}
#else
/*Check if the click happened on the left side of the area outside the label*/
if(relative_position.x < 0) {
index_of_char_at_position = 0;
}
/*Check if the click happened on the right side of the area outside the label*/
else if(relative_position.x >= label_width) {
index_of_char_at_position = LV_TA_CURSOR_LAST;
} else {
index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position);
}
if(sign == LV_SIGNAL_PRESSED)
lv_ta_set_cursor_pos(ta, index_of_char_at_position);
#endif
}
#endif

View File

@@ -59,30 +59,32 @@ typedef struct
lv_page_ext_t page; /*Ext. of ancestor*/
/*New data for this type */
lv_obj_t * label; /*Label of the text area*/
lv_obj_t * placeholder; /*Place holder label of the text area, only visible if text is an empty
string*/
lv_obj_t * placeholder; /*Place holder label. only visible if text is an empty string*/
char * pwd_tmp; /*Used to store the original text in password mode*/
const char * accapted_chars; /*Only these characters will be accepted. NULL: accept all*/
uint16_t max_length; /*The max. number of characters. 0: no limit*/
uint8_t pwd_mode : 1; /*Replace characters with '*' */
uint8_t one_line : 1; /*One line mode (ignore line breaks)*/
uint16_t pwd_show_time; /*Time to show characters in password mode before change them to '*' */
struct
{
const lv_style_t * style; /*Style of the cursor (NULL to use label's style)*/
lv_coord_t valid_x; /*Used when stepping up/down in text area when stepping to a shorter
line. (Handled by the library)*/
uint16_t
pos; /*The current cursor position (0: before 1. letter; 1: before 2. letter etc.)*/
lv_area_t area; /*Cursor area relative to the Text Area*/
uint16_t txt_byte_pos; /*Byte index of the letter after (on) the cursor*/
lv_cursor_type_t type : 4; /*Shape of the cursor*/
uint8_t
state : 1; /*Indicates that the cursor is visible now or not (Handled by the library)*/
const lv_style_t * style; /* Style of the cursor (NULL to use label's style)*/
lv_coord_t valid_x; /* Used when stepping up/down to a shorter line.
* (Used by the library)*/
uint16_t pos; /* The current cursor position
* (0: before 1st letter; 1: before 2nd letter ...)*/
uint16_t blink_time; /*Blink period*/
lv_area_t area; /* Cursor area relative to the Text Area*/
uint16_t txt_byte_pos; /* Byte index of the letter after (on) the cursor*/
lv_cursor_type_t type : 4; /* Shape of the cursor*/
uint8_t state : 1; /*Cursor is visible now or not (Handled by the library)*/
} cursor;
int tmp_sel_start; /*Temporary value*/
int tmp_sel_end; /*Temporary value*/
uint8_t selecting : 1; /*User is in process of selecting */
uint8_t sel_mode : 1; /*Text can be selected on this text area*/
#if LV_LABEL_TEXT_SEL
uint16_t tmp_sel_start; /*Temporary value*/
uint16_t tmp_sel_end; /*Temporary value*/
uint8_t text_sel_in_prog : 1; /*User is in process of selecting */
uint8_t text_sel_en : 1; /*Text can be selected on this text area*/
#endif
uint8_t pwd_mode : 1; /*Replace characters with '*' */
uint8_t one_line : 1; /*One line mode (ignore line breaks)*/
} lv_ta_ext_t;
enum {
@@ -262,7 +264,21 @@ void lv_ta_set_style(lv_obj_t * ta, lv_ta_style_t type, const lv_style_t * style
* @param ta pointer to a text area object
* @param en true or false to enable/disable selection mode
*/
void lv_ta_set_sel_mode(lv_obj_t * ta, bool en);
void lv_ta_set_text_sel(lv_obj_t * ta, bool en);
/**
* Set how long show the password before changing it to '*'
* @param ta pointer to Text area
* @param time show time in milliseconds. 0: hide immediately.
*/
void lv_ta_set_pwd_show_time(lv_obj_t * ta, uint16_t time);
/**
* Set cursor blink animation time
* @param ta pointer to Text area
* @param time blink period. 0: disable blinking
*/
void lv_ta_set_cursor_blink_time(lv_obj_t * ta, uint16_t time);
/*=====================
* Getter functions
@@ -296,13 +312,6 @@ lv_obj_t * lv_ta_get_label(const lv_obj_t * ta);
*/
uint16_t lv_ta_get_cursor_pos(const lv_obj_t * ta);
/**
* Get the current cursor visibility.
* @param ta pointer to a text area object
* @return true: the cursor is drawn, false: the cursor is hidden
*/
// bool lv_ta_get_cursor_show(const lv_obj_t * ta);
/**
* Get the current cursor type.
* @param ta pointer to a text area object
@@ -376,18 +385,6 @@ static inline bool lv_ta_get_edge_flash(lv_obj_t * ta)
*/
const lv_style_t * lv_ta_get_style(const lv_obj_t * ta, lv_ta_style_t type);
/**
* Get the selection index of the text area.
*
* The last character is exclusive (i.e. if the API says that the selection
* ranges from 6 to 7, only character 6 is selected).
* @param ta Text area object
* @param sel_start pointer to int used to hold first selected character
* @param sel_end pointer to int used to hold last selected character
*/
void lv_ta_get_selection(lv_obj_t * ta, int * sel_start, int * sel_end);
/**
* Find whether text is selected or not.
* @param ta Text area object
@@ -400,7 +397,21 @@ bool lv_ta_text_is_selected(const lv_obj_t * ta);
* @param ta pointer to a text area object
* @return true: selection mode is enabled, false: disabled
*/
bool lv_ta_get_sel_mode(lv_obj_t * ta);
bool lv_ta_get_text_sel_en(lv_obj_t * ta);
/**
* Set how long show the password before changing it to '*'
* @param ta pointer to Text area
* @return show time in milliseconds. 0: hide immediately.
*/
uint16_t lv_ta_get_pwd_show_time(lv_obj_t * ta);
/**
* Set cursor blink animation time
* @param ta pointer to Text area
* @return time blink period. 0: disable blinking
*/
uint16_t lv_ta_get_cursor_blink_time(lv_obj_t * ta);
/*=====================
* Other functions

View File

@@ -18,7 +18,7 @@
* DEFINES
*********************/
#if LV_USE_ANIMATION
#ifndef LV_TABVIEW_ANIM_TIME
#ifndef LV_TABVIEW_DEF_ANIM_TIME
#define LV_TABVIEW_DEF_ANIM_TIME \
300 /*Animation time of focusing to the a list element [ms] (0: no animation) */
#endif
@@ -93,7 +93,9 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy)
ext->indic = NULL;
ext->btns = NULL;
ext->btns_pos = LV_TABVIEW_BTNS_POS_TOP;
#if LV_USE_ANIMATION
ext->anim_time = LV_TABVIEW_DEF_ANIM_TIME;
#endif
ext->btns_hide = 0;
/*The signal and design functions are not copied so set them here*/
@@ -113,17 +115,18 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy)
lv_obj_set_size(new_tabview, lv_obj_get_width_fit(lv_obj_get_parent(new_tabview)),
lv_obj_get_height_fit(lv_obj_get_parent(new_tabview)));
ext->content = lv_cont_create(new_tabview, NULL);
ext->btns = lv_btnm_create(new_tabview, NULL);
ext->indic = lv_obj_create(ext->btns, NULL);
lv_obj_set_height(ext->btns, 3 * LV_DPI / 4);
lv_btnm_set_map(ext->btns, tab_def);
lv_obj_set_event_cb(ext->btns, tab_btnm_event_cb);
ext->indic = lv_obj_create(ext->btns, NULL);
lv_obj_set_width(ext->indic, LV_DPI);
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_obj_set_click(ext->indic, false);
ext->content = lv_cont_create(new_tabview, NULL);
lv_cont_set_fit2(ext->content, LV_FIT_TIGHT, LV_FIT_NONE);
lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);
lv_cont_set_style(ext->content, &lv_style_transp_tight);
@@ -157,7 +160,9 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy)
ext->btns = lv_btnm_create(new_tabview, copy_ext->btns);
ext->indic = lv_obj_create(ext->btns, copy_ext->indic);
ext->content = lv_cont_create(new_tabview, copy_ext->content);
#if LV_USE_ANIMATION
ext->anim_time = copy_ext->anim_time;
#endif
ext->tab_name_ptr = lv_mem_alloc(sizeof(char *));
lv_mem_assert(ext->tab_name_ptr);
@@ -232,12 +237,43 @@ lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name)
strcpy(name_dm, name);
ext->tab_cnt++;
ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt + 1));
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt + 1));
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
ext->tab_name_ptr = lv_mem_realloc(ext->tab_name_ptr, sizeof(char *) * (ext->tab_cnt * 2));
break;
}
lv_mem_assert(ext->tab_name_ptr);
if(ext->tab_name_ptr == NULL) return NULL;
ext->tab_name_ptr[ext->tab_cnt - 1] = name_dm;
ext->tab_name_ptr[ext->tab_cnt] = "";
/* FIXME: It is not possible yet to switch tab button position from/to top/bottom from/to left/right at runtime.
* Method: clean extra \n when switch from LV_TABVIEW_BTNS_POS_LEFT or LV_TABVIEW_BTNS_POS_RIGHT
* to LV_TABVIEW_BTNS_POS_TOP or LV_TABVIEW_BTNS_POS_BOTTOM.
*/
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
ext->tab_name_ptr[ext->tab_cnt - 1] = name_dm;
ext->tab_name_ptr[ext->tab_cnt] = "";
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
if(ext->tab_cnt == 1) {
ext->tab_name_ptr[0] = name_dm;
ext->tab_name_ptr[1] = "";
} else {
ext->tab_name_ptr[ext->tab_cnt * 2 - 3] = "\n";
ext->tab_name_ptr[ext->tab_cnt * 2 - 2] = name_dm;
ext->tab_name_ptr[ext->tab_cnt * 2 - 1] = "";
}
break;
}
/* The button matrix's map still points to the old `tab_name_ptr` which might be freed by
* `lv_mem_realloc`. So make its current map invalid*/
@@ -249,21 +285,41 @@ lv_obj_t * lv_tabview_add_tab(lv_obj_t * tabview, const char * name)
/*Modify the indicator size*/
const lv_style_t * style_tabs = lv_obj_get_style(ext->btns);
lv_coord_t indic_width =
(lv_obj_get_width(tabview) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) -
style_tabs->body.padding.left - style_tabs->body.padding.right) /
ext->tab_cnt;
lv_obj_set_width(ext->indic, indic_width);
lv_obj_set_x(ext->indic, indic_width * ext->tab_cur +
style_tabs->body.padding.inner * ext->tab_cur +
style_tabs->body.padding.left);
lv_coord_t indic_size;
lv_coord_t max_h, btn_h, act_y;
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
indic_size =
(lv_obj_get_width(tabview) - style_tabs->body.padding.inner * (ext->tab_cnt - 1) -
style_tabs->body.padding.left - style_tabs->body.padding.right) /
ext->tab_cnt;
lv_obj_set_width(ext->indic, indic_size);
lv_obj_set_x(ext->indic, indic_size * ext->tab_cur +
style_tabs->body.padding.inner * ext->tab_cur +
style_tabs->body.padding.left);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
max_h = lv_obj_get_height(ext->btns) - style_tabs->body.padding.top - style_tabs->body.padding.bottom;
btn_h = max_h - ((ext->tab_cnt - 1) * style_tabs->body.padding.inner);
btn_h = btn_h / ext->tab_cnt;
btn_h--; /*-1 because e.g. height = 100 means 101 pixels (0..100)*/
act_y = style_tabs->body.padding.top + ext->tab_cur * (btn_h + style_tabs->body.padding.inner);
lv_obj_set_height(ext->indic, btn_h);
lv_obj_set_y(ext->indic, act_y);
break;
}
/*Set the first btn as active*/
if(ext->tab_cnt == 1) {
ext->tab_cur = 0;
tabview_realign(tabview); /*To set the proper btns height*/
}
tabview_realign(tabview); /*Set the size of the pages, tab buttons and indicator*/
lv_tabview_set_tab_act(tabview, ext->tab_cur, false);
return h;
@@ -298,9 +354,32 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en)
ext->tab_cur = id;
lv_coord_t cont_x = -(lv_obj_get_width(tabview) * id + style->body.padding.inner * id +
style->body.padding.left);
if(ext->anim_time == 0 || anim_en == false) {
lv_coord_t cont_x;
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
cont_x = -(lv_obj_get_width(tabview) * id + style->body.padding.inner * id +
style->body.padding.left);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
cont_x = -((lv_obj_get_width(tabview) - lv_obj_get_width(ext->btns)) * id +
style->body.padding.inner * id +
style->body.padding.left) +
lv_obj_get_width(ext->btns);
break;
case LV_TABVIEW_BTNS_POS_RIGHT:
cont_x = -((lv_obj_get_width(tabview) - lv_obj_get_width(ext->btns)) * id +
style->body.padding.inner * id +
style->body.padding.left);
break;
}
if( anim_en == false
#if LV_USE_ANIMATION
|| ext->anim_time == 0
#endif
) {
lv_obj_set_x(ext->content, cont_x);
} else {
#if LV_USE_ANIMATION
@@ -308,9 +387,9 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en)
a.var = ext->content;
a.start = lv_obj_get_x(ext->content);
a.end = cont_x;
a.fp = (lv_anim_fp_t)lv_obj_set_x;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_x;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
@@ -322,22 +401,60 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, bool anim_en)
}
/*Move the indicator*/
lv_coord_t indic_width = lv_obj_get_width(ext->indic);
const lv_style_t * tabs_style = lv_obj_get_style(ext->btns);
lv_coord_t indic_x =
indic_width * id + tabs_style->body.padding.inner * id + tabs_style->body.padding.left;
lv_coord_t indic_size;
lv_coord_t indic_pos;
if(ext->anim_time == 0 || anim_en == false) {
lv_obj_set_x(ext->indic, indic_x);
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
indic_size = lv_obj_get_width(ext->indic);
indic_pos = indic_size * id + tabs_style->body.padding.inner * id + tabs_style->body.padding.left;
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
indic_size = lv_obj_get_height(ext->indic);
indic_pos = tabs_style->body.padding.top + id * (indic_size + tabs_style->body.padding.inner);
break;
}
if( anim_en == false
#if LV_USE_ANIMATION
|| ext->anim_time == 0
#endif
) {
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_set_x(ext->indic, indic_pos);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_set_y(ext->indic, indic_pos);
break;
}
} else {
#if LV_USE_ANIMATION
lv_anim_t a;
a.var = ext->indic;
a.start = lv_obj_get_x(ext->indic);
a.end = indic_x;
a.fp = (lv_anim_fp_t)lv_obj_set_x;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
a.start = lv_obj_get_x(ext->indic);
a.end = indic_pos;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_x;
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
a.start = lv_obj_get_y(ext->indic);
a.end = indic_pos;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
break;
}
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
@@ -369,11 +486,13 @@ void lv_tabview_set_sliding(lv_obj_t * tabview, bool en)
*/
void lv_tabview_set_anim_time(lv_obj_t * tabview, uint16_t anim_time)
{
#if LV_USE_ANIMATION
lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);
#if LV_USE_ANIMATION == 0
anim_time = 0;
#endif
ext->anim_time = anim_time;
#else
(void) tabview;
(void) anim_time;
#endif
}
/**
@@ -407,7 +526,18 @@ void lv_tabview_set_style(lv_obj_t * tabview, lv_tabview_style_t type, const lv_
break;
case LV_TABVIEW_STYLE_INDIC:
lv_obj_set_style(ext->indic, style);
lv_obj_set_height(ext->indic, style->body.padding.inner);
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_set_height(ext->indic, style->body.padding.inner);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_set_width(ext->indic, style->body.padding.inner);
break;
}
tabview_realign(tabview);
break;
}
@@ -505,8 +635,13 @@ bool lv_tabview_get_sliding(const lv_obj_t * tabview)
*/
uint16_t lv_tabview_get_anim_time(const lv_obj_t * tabview)
{
#if LV_USE_ANIMATION
lv_tabview_ext_t * ext = lv_obj_get_ext_attr(tabview);
return ext->anim_time;
#else
(void) tabview;
return 0;
#endif
}
/**
@@ -765,16 +900,33 @@ static void tabpage_pressing_handler(lv_obj_t * tabview, lv_obj_t * tabpage)
ext->point_last.y = point_act.y;
/*Move the indicator*/
lv_coord_t indic_width = lv_obj_get_width(ext->indic);
const lv_style_t * tabs_style = lv_obj_get_style(ext->btns);
const lv_style_t * indic_style = lv_obj_get_style(ext->indic);
lv_coord_t p = ((tabpage->coords.x1 - tabview->coords.x1) *
(indic_width + tabs_style->body.padding.inner)) /
lv_obj_get_width(tabview);
lv_coord_t indic_size;
lv_coord_t p;
lv_coord_t indic_y;
const lv_style_t * indic_style;
lv_obj_set_x(ext->indic, indic_width * ext->tab_cur +
tabs_style->body.padding.inner * ext->tab_cur +
indic_style->body.padding.left - p);
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
indic_size = lv_obj_get_width(ext->indic);
indic_style = lv_obj_get_style(ext->indic);
p = ((tabpage->coords.x1 - tabview->coords.x1) *
(indic_size + tabs_style->body.padding.inner)) /
lv_obj_get_width(tabview);
lv_obj_set_x(ext->indic, indic_size * ext->tab_cur +
tabs_style->body.padding.inner * ext->tab_cur +
indic_style->body.padding.left - p);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
indic_size = lv_obj_get_height(ext->indic);
indic_y = tabs_style->body.padding.top +
ext->tab_cur * (indic_size + tabs_style->body.padding.inner);
lv_obj_set_y(ext->indic, indic_y);
break;
}
}
}
@@ -859,30 +1011,114 @@ static void tabview_realign(lv_obj_t * tabview)
const lv_style_t * style_btn_bg = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_BG);
const lv_style_t * style_btn_rel = lv_tabview_get_style(tabview, LV_TABVIEW_STYLE_BTN_REL);
/*Set the indicator widths*/
lv_coord_t indic_width =
(lv_obj_get_width(tabview) - style_btn_bg->body.padding.inner * (ext->tab_cnt - 1) -
style_btn_bg->body.padding.left - style_btn_bg->body.padding.right) /
ext->tab_cnt;
lv_obj_set_width(ext->indic, indic_width);
/*Set the indicator width/height*/
lv_coord_t indic_size;
lv_coord_t max_h;
/*Set the tabs height*/
lv_coord_t btns_height = lv_font_get_height(style_btn_rel->text.font) +
style_btn_rel->body.padding.top +
style_btn_rel->body.padding.bottom +
style_btn_bg->body.padding.top + style_btn_bg->body.padding.bottom;
lv_obj_set_height(ext->btns, btns_height);
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
indic_size =
(lv_obj_get_width(tabview) - style_btn_bg->body.padding.inner * (ext->tab_cnt - 1) -
style_btn_bg->body.padding.left - style_btn_bg->body.padding.right) /
ext->tab_cnt;
lv_obj_set_width(ext->indic, indic_size);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_set_height(ext->btns, lv_obj_get_height(tabview));
lv_obj_set_height(ext->content, lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns));
max_h = lv_obj_get_height(ext->btns) - style_btn_bg->body.padding.top - style_btn_bg->body.padding.bottom;
indic_size = max_h - ((ext->tab_cnt - 1) * style_btn_bg->body.padding.inner);
indic_size = indic_size / ext->tab_cnt;
indic_size--; /*-1 because e.g. height = 100 means 101 pixels (0..100)*/
lv_obj_set_height(ext->indic, indic_size);
break;
}
/*Set the tabs height/width*/
lv_coord_t btns_size;
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
btns_size = lv_font_get_height(style_btn_rel->text.font) +
style_btn_rel->body.padding.top +
style_btn_rel->body.padding.bottom +
style_btn_bg->body.padding.top + style_btn_bg->body.padding.bottom;
lv_obj_set_height(ext->btns, btns_size);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
btns_size = lv_font_get_width(style_btn_rel->text.font, 0x0041) + // 'A'
style_btn_rel->body.padding.left +
style_btn_rel->body.padding.right +
style_btn_bg->body.padding.left + style_btn_bg->body.padding.right;
lv_obj_set_width(ext->btns, btns_size);
break;
}
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_set_height(ext->content, lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns));
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_set_height(ext->content, lv_obj_get_height(tabview));
break;
}
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(ext->content, ext->btns, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
lv_cont_set_fit2(ext->content, LV_FIT_TIGHT, LV_FIT_NONE);
lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);
lv_obj_set_height(ext->content,
lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns));
// lv_obj_set_height(ext->btns, 3 * LV_DPI / 4);
// lv_obj_set_width(ext->indic, LV_DPI);
break;
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_align(ext->content, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(ext->btns, ext->content, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0);
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_cont_set_fit2(ext->content, LV_FIT_TIGHT, LV_FIT_NONE);
lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);
lv_obj_set_height(ext->content,
lv_obj_get_height(tabview) - lv_obj_get_height(ext->btns));
break;
case LV_TABVIEW_BTNS_POS_LEFT:
lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(ext->content, tabview, LV_ALIGN_IN_TOP_LEFT, lv_obj_get_width(ext->btns), 0);
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
lv_cont_set_fit2(ext->content, LV_FIT_TIGHT, LV_FIT_NONE);
lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);
lv_obj_set_width(ext->content,
lv_obj_get_width(tabview) - lv_obj_get_width(ext->btns));
lv_obj_set_height(ext->btns, lv_obj_get_height(tabview));
lv_obj_set_width(ext->indic, style_btn_bg->body.padding.inner);
break;
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_align(ext->btns, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
lv_obj_align(ext->content, tabview, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_cont_set_fit2(ext->content, LV_FIT_TIGHT, LV_FIT_NONE);
lv_cont_set_layout(ext->content, LV_LAYOUT_ROW_T);
lv_obj_set_width(ext->content,
lv_obj_get_width(tabview) - lv_obj_get_width(ext->btns));
lv_obj_set_height(ext->btns, lv_obj_get_height(tabview));
lv_obj_set_width(ext->indic, style_btn_bg->body.padding.inner);
break;
}
}
@@ -891,13 +1127,43 @@ static void tabview_realign(lv_obj_t * tabview)
while(pages != NULL) {
if(lv_obj_get_signal_cb(pages) ==
tabpage_signal) { /*Be sure adjust only the pages (user can other things)*/
lv_obj_set_size(pages, lv_obj_get_width(tabview), lv_obj_get_height(ext->content));
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_set_size(
pages,
lv_obj_get_width(tabview),
lv_obj_get_height(ext->content)
);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_set_size(
pages,
lv_obj_get_width(tabview) - lv_obj_get_width(ext->btns),
lv_obj_get_height(ext->content)
);
break;
}
}
pages = lv_obj_get_child(ext->content, pages);
}
if(!ext->btns_hide) {
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
switch(ext->btns_pos) {
case LV_TABVIEW_BTNS_POS_TOP:
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0);
break;
case LV_TABVIEW_BTNS_POS_BOTTOM:
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_LEFT, 0, 0);
break;
case LV_TABVIEW_BTNS_POS_LEFT:
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
break;
case LV_TABVIEW_BTNS_POS_RIGHT:
lv_obj_align(ext->indic, ext->btns, LV_ALIGN_IN_TOP_LEFT, 0, 0);
break;
}
}
lv_tabview_set_tab_act(tabview, ext->tab_cur, false);

View File

@@ -45,6 +45,8 @@ extern "C" {
enum {
LV_TABVIEW_BTNS_POS_TOP,
LV_TABVIEW_BTNS_POS_BOTTOM,
LV_TABVIEW_BTNS_POS_LEFT,
LV_TABVIEW_BTNS_POS_RIGHT
};
typedef uint8_t lv_tabview_btns_pos_t;
@@ -60,13 +62,15 @@ typedef struct
lv_point_t point_last;
uint16_t tab_cur;
uint16_t tab_cnt;
#if LV_USE_ANIMATION
uint16_t anim_time;
#endif
uint8_t slide_enable : 1; /*1: enable horizontal sliding by touch pad*/
uint8_t draging : 1;
uint8_t drag_hor : 1;
uint8_t scroll_ver : 1;
uint8_t btns_hide : 1;
lv_tabview_btns_pos_t btns_pos : 1;
lv_tabview_btns_pos_t btns_pos : 2;
} lv_tabview_ext_t;
enum {

View File

@@ -17,7 +17,7 @@
* DEFINES
*********************/
#if LV_USE_ANIMATION
#ifndef LV_TILEVIEW_ANIM_TIME
#ifndef LV_TILEVIEW_DEF_ANIM_TIME
#define LV_TILEVIEW_DEF_ANIM_TIME 300 /*Animation time loading a tile [ms] (0: no animation) */
#endif
#else
@@ -78,7 +78,9 @@ lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy)
if(ancestor_design == NULL) ancestor_design = lv_obj_get_design_cb(new_tileview);
/*Initialize the allocated 'ext' */
#if LV_USE_ANIMATION
ext->anim_time = LV_TILEVIEW_DEF_ANIM_TIME;
#endif
ext->act_id.x = 0;
ext->act_id.y = 0;
ext->valid_pos = NULL;
@@ -109,7 +111,9 @@ lv_obj_t * lv_tileview_create(lv_obj_t * par, const lv_obj_t * copy)
lv_tileview_ext_t * copy_ext = lv_obj_get_ext_attr(copy);
ext->act_id.x = copy_ext->act_id.x;
ext->act_id.y = copy_ext->act_id.y;
#if LV_USE_ANIMATION
ext->anim_time = copy_ext->anim_time;
#endif
/*Refresh the style with new signal function*/
lv_obj_refresh_style(new_tileview);
@@ -211,9 +215,9 @@ void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, b
lv_anim_t a;
a.var = scrl;
a.fp = (lv_anim_fp_t)lv_obj_set_x;
a.path = lv_anim_path_linear;
a.end_cb = NULL;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_x;
a.path_cb = lv_anim_path_linear;
a.ready_cb = NULL;
a.act_time = 0;
a.time = ext->anim_time;
a.playback = 0;
@@ -228,9 +232,9 @@ void lv_tileview_set_tile_act(lv_obj_t * tileview, lv_coord_t x, lv_coord_t y, b
}
if(y_coord != y_act) {
a.start = y_act;
a.end = y_coord;
a.fp = (lv_anim_fp_t)lv_obj_set_y;
a.start = y_act;
a.end = y_coord;
a.exec_cb = (lv_anim_exec_cb_t)lv_obj_set_y;
lv_anim_create(&a);
}
#endif
@@ -366,6 +370,7 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
ext->drag_ver = 1;
}
#if LV_USE_ANIMATION
if(ext->drag_hor) {
ext->page.edge_flash.top_ip = 0;
ext->page.edge_flash.bottom_ip = 0;
@@ -375,6 +380,7 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
ext->page.edge_flash.right_ip = 0;
ext->page.edge_flash.left_ip = 0;
}
#endif
lv_coord_t x = lv_obj_get_x(scrl);
lv_coord_t y = lv_obj_get_y(scrl);
@@ -383,12 +389,14 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
if(ext->drag_top_en == 0) {
if(y > -(ext->act_id.y * h) && indev->proc.types.pointer.vect.y > 0 &&
ext->drag_hor == 0) {
#if LV_USE_ANIMATION
if(ext->page.edge_flash.enabled && ext->page.edge_flash.left_ip == 0 &&
ext->page.edge_flash.right_ip == 0 && ext->page.edge_flash.top_ip == 0 &&
ext->page.edge_flash.bottom_ip == 0) {
ext->page.edge_flash.top_ip = 1;
lv_page_start_edge_flash(tileview);
}
#endif
lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.top);
}
@@ -396,12 +404,14 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
if(ext->drag_bottom_en == 0 && indev->proc.types.pointer.vect.y < 0 &&
ext->drag_hor == 0) {
if(y < -(ext->act_id.y * h)) {
#if LV_USE_ANIMATION
if(ext->page.edge_flash.enabled && ext->page.edge_flash.left_ip == 0 &&
ext->page.edge_flash.right_ip == 0 && ext->page.edge_flash.top_ip == 0 &&
ext->page.edge_flash.bottom_ip == 0) {
ext->page.edge_flash.bottom_ip = 1;
lv_page_start_edge_flash(tileview);
}
#endif
}
lv_obj_set_y(scrl, -ext->act_id.y * h + style_bg->body.padding.top);
@@ -409,12 +419,14 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
if(ext->drag_left_en == 0) {
if(x > -(ext->act_id.x * w) && indev->proc.types.pointer.vect.x > 0 &&
ext->drag_ver == 0) {
#if LV_USE_ANIMATION
if(ext->page.edge_flash.enabled && ext->page.edge_flash.left_ip == 0 &&
ext->page.edge_flash.right_ip == 0 && ext->page.edge_flash.top_ip == 0 &&
ext->page.edge_flash.bottom_ip == 0) {
ext->page.edge_flash.left_ip = 1;
lv_page_start_edge_flash(tileview);
}
#endif
lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.left);
}
@@ -422,12 +434,14 @@ static lv_res_t lv_tileview_scrl_signal(lv_obj_t * scrl, lv_signal_t sign, void
if(ext->drag_right_en == 0 && indev->proc.types.pointer.vect.x < 0 &&
ext->drag_ver == 0) {
if(x < -(ext->act_id.x * w)) {
#if LV_USE_ANIMATION
if(ext->page.edge_flash.enabled && ext->page.edge_flash.left_ip == 0 &&
ext->page.edge_flash.right_ip == 0 && ext->page.edge_flash.top_ip == 0 &&
ext->page.edge_flash.bottom_ip == 0) {
ext->page.edge_flash.right_ip = 1;
lv_page_start_edge_flash(tileview);
}
#endif
}
lv_obj_set_x(scrl, -ext->act_id.x * w + style_bg->body.padding.top);

View File

@@ -31,17 +31,15 @@ extern "C" {
* TYPEDEFS
**********************/
/* parametes: pointer to a tileview object, x, y (tile coordinates to load)
* return: LV_RES_INV: to prevent the loading of the tab; LV_RES_OK: if everything is fine*/
typedef lv_res_t (*lv_tileview_action_t)(lv_obj_t *, lv_coord_t, lv_coord_t);
/*Data of tileview*/
typedef struct
{
lv_page_ext_t page;
/*New data for this type */
const lv_point_t * valid_pos;
#if LV_USE_ANIMATION
uint16_t anim_time;
#endif
lv_point_t act_id;
uint8_t drag_top_en : 1;
uint8_t drag_bottom_en : 1;

View File

@@ -64,7 +64,6 @@ lv_obj_t * lv_win_create(lv_obj_t * par, const lv_obj_t * copy)
ext->page = NULL;
ext->header = NULL;
ext->title = NULL;
ext->style_header = &lv_style_plain_color;
ext->style_btn_rel = &lv_style_btn_rel;
ext->style_btn_pr = &lv_style_btn_pr;
ext->btn_size = (LV_DPI) / 2;
@@ -538,7 +537,8 @@ static void lv_win_realign(lv_obj_t * win)
btn = lv_obj_get_child_back(ext->header, btn);
}
lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, ext->style_header->body.padding.left, 0);
const lv_style_t * style_header = lv_win_get_style(win, LV_WIN_STYLE_HEADER);
lv_obj_align(ext->title, NULL, LV_ALIGN_IN_LEFT_MID, style_header->body.padding.left, 0);
lv_obj_set_pos(ext->header, 0, 0);

View File

@@ -61,7 +61,6 @@ typedef struct
lv_obj_t * page; /*Pointer to a page which holds the content*/
lv_obj_t * header; /*Pointer to the header container of the window*/
lv_obj_t * title; /*Pointer to the title label of the window*/
const lv_style_t * style_header; /*Style of the header container*/
const lv_style_t * style_btn_rel; /*Control button releases style*/
const lv_style_t * style_btn_pr; /*Control button pressed style*/
lv_coord_t btn_size; /*Size of the control buttons (square)*/

View File

@@ -57,6 +57,15 @@ void lv_theme_set_current(lv_theme_t * th)
{
#if LV_THEME_LIVE_UPDATE == 0
current_theme = th;
#if LV_USE_GROUP
/*Copy group style modification callback functions*/
memcpy(&current_theme->group, &th->group, sizeof(th->group));
#endif
/*Let the object know their style might change*/
lv_obj_report_style_mod(NULL);
#else
uint32_t style_num = sizeof(th->style) / sizeof(lv_style_t *); /*Number of styles in a theme*/
@@ -87,10 +96,10 @@ void lv_theme_set_current(lv_theme_t * th)
/*Let the object know their style might change*/
lv_obj_report_style_mod(NULL);
#if LV_USE_GROUP
lv_group_report_style_mod(NULL);
#endif
#if LV_USE_GROUP
lv_group_report_style_mod(NULL);
#endif
}

View File

@@ -328,8 +328,8 @@ typedef struct
#if LV_USE_GROUP
struct
{
lv_group_style_mod_func_t style_mod;
lv_group_style_mod_func_t style_mod_edit;
lv_group_style_mod_cb_t style_mod_cb;
lv_group_style_mod_cb_t style_mod_edit_cb;
} group;
#endif
} lv_theme_t;

View File

@@ -929,8 +929,8 @@ lv_theme_t * lv_theme_alien_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -450,8 +450,8 @@ lv_theme_t * lv_theme_default_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -908,8 +908,8 @@ lv_theme_t * lv_theme_material_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -497,8 +497,8 @@ lv_theme_t * lv_theme_mono_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -901,8 +901,8 @@ lv_theme_t * lv_theme_nemo_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -818,8 +818,8 @@ lv_theme_t * lv_theme_night_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -450,8 +450,8 @@ lv_theme_t * lv_theme_templ_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;

View File

@@ -874,8 +874,8 @@ lv_theme_t * lv_theme_zen_init(uint16_t hue, lv_font_t * font)
win_init();
#if LV_USE_GROUP
theme.group.style_mod = style_mod;
theme.group.style_mod_edit = style_mod_edit;
theme.group.style_mod_cb = style_mod;
theme.group.style_mod_edit_cb = style_mod_edit;
#endif
return &theme;