From aaa78ba9497d281ba005fe931acf9f02ad15ad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Tue, 19 May 2020 15:22:38 +0200 Subject: [PATCH 01/28] Added focus parent for v7 --- lv_conf_template.h | 4 ++++ src/lv_core/lv_group.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/lv_core/lv_group.h | 17 +++++++++++++++++ src/lv_core/lv_obj.c | 28 ++++++++++++++++++++++++++++ src/lv_core/lv_obj.h | 5 +++++ src/lv_widgets/lv_page.c | 6 ++++++ 6 files changed, 100 insertions(+) diff --git a/lv_conf_template.h b/lv_conf_template.h index 04efb35a4..caaa2ac5f 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -173,6 +173,10 @@ typedef void * lv_anim_user_data_t; #define LV_USE_GROUP 1 #if LV_USE_GROUP typedef void * lv_group_user_data_t; + +/* 1: Enable to apply focus style to different object */ +#define LV_USE_GROUP_FOCUS_PARENT 1 + #endif /*LV_USE_GROUP*/ /* 1: Enable GPU interface*/ diff --git a/src/lv_core/lv_group.c b/src/lv_core/lv_group.c index 057c78ecb..8b24f3f7c 100644 --- a/src/lv_core/lv_group.c +++ b/src/lv_core/lv_group.c @@ -149,6 +149,11 @@ void lv_group_remove_obj(lv_obj_t * obj) { lv_group_t * g = obj->group_p; if(g == NULL) return; + +#if LV_USE_GROUP_FOCUS_PARENT + lv_group_remove_focus_parent(obj); +#endif + if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/ /*Focus on the next object*/ @@ -201,6 +206,11 @@ void lv_group_remove_all_objs(lv_group_t * group) lv_obj_t ** obj; _LV_LL_READ(group->obj_ll, obj) { (*obj)->group_p = NULL; + +#if LV_USE_GROUP_FOCUS_PARENT + lv_group_remove_focus_parent(*obj); +#endif + } _lv_ll_clear(&(group->obj_ll)); @@ -532,4 +542,34 @@ static void obj_to_foreground(lv_obj_t * obj) } } + +#ifdef LV_USE_GROUP_FOCUS_PARENT +/** + * Set focus parent for the object (focus style will apply to parent, when child is focused) + * @param child Child object + * @param parent Parent object + */ +void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent) +{ + child->group_focus_parent = parent; + + /*if the child is in focused state right now, set focus state to parent*/ + if (lv_obj_is_focused(child)) + { + lv_obj_clear_state(child, LV_STATE_FOCUSED | LV_STATE_EDITED); + lv_obj_set_state(parent, LV_STATE_FOCUSED); + } +} + +/** + * Remove focus mode from child + * @param obj Child object + */ +void lv_group_remove_focus_parent(lv_obj_t * obj) +{ + obj->group_focus_parent = NULL; +} + +#endif + #endif /*LV_USE_GROUP != 0*/ diff --git a/src/lv_core/lv_group.h b/src/lv_core/lv_group.h index ef165ee38..ed4273820 100644 --- a/src/lv_core/lv_group.h +++ b/src/lv_core/lv_group.h @@ -228,6 +228,23 @@ bool lv_group_get_click_focus(const lv_group_t * group); */ bool lv_group_get_wrap(lv_group_t * group); +#ifdef LV_USE_GROUP_FOCUS_PARENT +/** + * Set focus parent for the object (focus style will apply to parent, when child is focused) + * @param child Child object + * @param parent Parent object + */ +void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent); + +/** + * Remove focus mode from child + * @param obj Child object + */ +void lv_group_remove_focus_parent(lv_obj_t * obj); + +#endif + + /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index c944f9b5a..c00d6185d 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -297,6 +297,11 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) #if LV_USE_GROUP new_obj->group_p = NULL; + +#if LV_USE_GROUP_FOCUS_PARENT + new_obj->group_focus_parent = NULL; +#endif + #endif /*Set attributes*/ @@ -3613,14 +3618,37 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) if(lv_group_get_editing(lv_obj_get_group(obj))) { uint8_t state = LV_STATE_FOCUSED; state |= LV_STATE_EDITED; + +#if LV_USE_GROUP_FOCUS_PARENT + /*if using focus mode, change target to parent*/ + if (obj->group_focus_parent) { + obj = obj->group_focus_parent; + } +#endif + lv_obj_add_state(obj, state); } else { + +#if LV_USE_GROUP_FOCUS_PARENT + /*if using focus mode, change target to parent*/ + if (obj->group_focus_parent) { + obj = obj->group_focus_parent; + } +#endif lv_obj_add_state(obj, LV_STATE_FOCUSED); lv_obj_clear_state(obj, LV_STATE_EDITED); } } else if(sign == LV_SIGNAL_DEFOCUS) { + +#if LV_USE_GROUP_FOCUS_PARENT + /*if using focus mode, change target to parent*/ + if (obj->group_focus_parent) { + obj = obj->group_focus_parent; + } +#endif + lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED); } #endif diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 0e3358d37..b914611ca 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -227,6 +227,11 @@ typedef struct _lv_obj_t { #if LV_USE_GROUP != 0 void * group_p; + +#if LV_USE_GROUP_FOCUS_PARENT + struct _lv_obj_t * group_focus_parent; /**< Pointer to focus parent object. */ +#endif + #endif uint8_t protect; /**< Automatically happening actions can be prevented. diff --git a/src/lv_widgets/lv_page.c b/src/lv_widgets/lv_page.c index 6ad65fe8f..eccbc5428 100644 --- a/src/lv_widgets/lv_page.c +++ b/src/lv_widgets/lv_page.c @@ -485,6 +485,12 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, lv_anim_enable_t anim_ lv_anim_del(ext->scrl, (lv_anim_exec_xcb_t)lv_obj_set_y); #endif +#ifdef LV_USE_GROUP_FOCUS_PARENT + /*if using focus mode, change target to parent*/ + if (obj->group_focus_parent) { + obj = obj->group_focus_parent; + } +#endif /*If obj is higher then the page focus where the "error" is smaller*/ lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1; From 2712f0aeaaedb245a93ae696b2be4487eba358aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Tue, 19 May 2020 15:31:34 +0200 Subject: [PATCH 02/28] Added macro LV_USE_GROUP_FOCUS_PARENT to automatic tests --- tests/build.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/build.py b/tests/build.py index 804d56396..fe4237bf1 100755 --- a/tests/build.py +++ b/tests/build.py @@ -58,6 +58,7 @@ minimal_monochrome = { "LV_VER_RES_MAX":64, "LV_COLOR_DEPTH":1, "LV_USE_GROUP":0, + "LV_USE_GROUP_FOCUS_PARENT":0, "LV_USE_ANIMATION":0, "LV_ANTIALIAS":0, "LV_GPU":0, @@ -137,6 +138,7 @@ all_obj_minimal_features = { "LV_VER_RES_MAX":240, "LV_COLOR_DEPTH":8, "LV_USE_GROUP":0, + "LV_USE_GROUP_FOCUS_PARENT":0, "LV_USE_ANIMATION":0, "LV_ANTIALIAS":0, "LV_GPU":0, @@ -214,6 +216,7 @@ all_obj_all_features = { "LV_COLOR_DEPTH":32, "LV_COLOR_SCREEN_TRANSP":1, "LV_USE_GROUP":1, + "LV_USE_GROUP_FOCUS_PARENT":1, "LV_USE_ANIMATION":1, "LV_ANTIALIAS":1, "LV_GPU":1, @@ -295,6 +298,7 @@ advanced_features = { "LV_COLOR_16_SWAP":1, "LV_COLOR_SCREEN_TRANSP":1, "LV_USE_GROUP":1, + "LV_USE_GROUP_FOCUS_PARENT":1, "LV_USE_ANIMATION":1, "LV_ANTIALIAS":1, "LV_GPU":1, From 10ca6d4215c72f8ccbfcecf9f13366b9ac431727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Tue, 19 May 2020 15:45:09 +0200 Subject: [PATCH 03/28] replaced #ifdef to #if --- src/lv_conf_internal.h | 6 ++++++ src/lv_core/lv_group.c | 17 ++++++++--------- src/lv_core/lv_group.h | 2 +- src/lv_core/lv_obj.c | 24 ++++++++++++------------ src/lv_widgets/lv_page.c | 6 +++--- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 2aa30c6f4..3c9974cc4 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -257,6 +257,12 @@ #define LV_USE_GROUP 1 #endif #if LV_USE_GROUP + +/* 1: Enable to apply focus style to different object */ +#ifndef LV_USE_GROUP_FOCUS_PARENT +#define LV_USE_GROUP_FOCUS_PARENT 1 +#endif + #endif /*LV_USE_GROUP*/ /* 1: Enable GPU interface*/ diff --git a/src/lv_core/lv_group.c b/src/lv_core/lv_group.c index 8b24f3f7c..c573a0b0a 100644 --- a/src/lv_core/lv_group.c +++ b/src/lv_core/lv_group.c @@ -543,7 +543,7 @@ static void obj_to_foreground(lv_obj_t * obj) } -#ifdef LV_USE_GROUP_FOCUS_PARENT +#if LV_USE_GROUP_FOCUS_PARENT /** * Set focus parent for the object (focus style will apply to parent, when child is focused) * @param child Child object @@ -551,14 +551,13 @@ static void obj_to_foreground(lv_obj_t * obj) */ void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent) { - child->group_focus_parent = parent; + child->group_focus_parent = parent; - /*if the child is in focused state right now, set focus state to parent*/ - if (lv_obj_is_focused(child)) - { - lv_obj_clear_state(child, LV_STATE_FOCUSED | LV_STATE_EDITED); - lv_obj_set_state(parent, LV_STATE_FOCUSED); - } + /*if the child is in focused state right now, set focus state to parent*/ + if(lv_obj_is_focused(child)) { + lv_obj_clear_state(child, LV_STATE_FOCUSED | LV_STATE_EDITED); + lv_obj_set_state(parent, LV_STATE_FOCUSED); + } } /** @@ -567,7 +566,7 @@ void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent) */ void lv_group_remove_focus_parent(lv_obj_t * obj) { - obj->group_focus_parent = NULL; + obj->group_focus_parent = NULL; } #endif diff --git a/src/lv_core/lv_group.h b/src/lv_core/lv_group.h index ed4273820..8726dbb58 100644 --- a/src/lv_core/lv_group.h +++ b/src/lv_core/lv_group.h @@ -228,7 +228,7 @@ bool lv_group_get_click_focus(const lv_group_t * group); */ bool lv_group_get_wrap(lv_group_t * group); -#ifdef LV_USE_GROUP_FOCUS_PARENT +#if LV_USE_GROUP_FOCUS_PARENT /** * Set focus parent for the object (focus style will apply to parent, when child is focused) * @param child Child object diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index c00d6185d..bfddd53d4 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -299,7 +299,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->group_p = NULL; #if LV_USE_GROUP_FOCUS_PARENT - new_obj->group_focus_parent = NULL; + new_obj->group_focus_parent = NULL; #endif #endif @@ -3621,9 +3621,9 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) #if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if (obj->group_focus_parent) { - obj = obj->group_focus_parent; - } + if(obj->group_focus_parent) { + obj = obj->group_focus_parent; + } #endif lv_obj_add_state(obj, state); @@ -3631,10 +3631,10 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) else { #if LV_USE_GROUP_FOCUS_PARENT - /*if using focus mode, change target to parent*/ - if (obj->group_focus_parent) { - obj = obj->group_focus_parent; - } + /*if using focus mode, change target to parent*/ + if(obj->group_focus_parent) { + obj = obj->group_focus_parent; + } #endif lv_obj_add_state(obj, LV_STATE_FOCUSED); lv_obj_clear_state(obj, LV_STATE_EDITED); @@ -3643,10 +3643,10 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) else if(sign == LV_SIGNAL_DEFOCUS) { #if LV_USE_GROUP_FOCUS_PARENT - /*if using focus mode, change target to parent*/ - if (obj->group_focus_parent) { - obj = obj->group_focus_parent; - } + /*if using focus mode, change target to parent*/ + if(obj->group_focus_parent) { + obj = obj->group_focus_parent; + } #endif lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED); diff --git a/src/lv_widgets/lv_page.c b/src/lv_widgets/lv_page.c index eccbc5428..9a50967e2 100644 --- a/src/lv_widgets/lv_page.c +++ b/src/lv_widgets/lv_page.c @@ -485,10 +485,10 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, lv_anim_enable_t anim_ lv_anim_del(ext->scrl, (lv_anim_exec_xcb_t)lv_obj_set_y); #endif -#ifdef LV_USE_GROUP_FOCUS_PARENT +#if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if (obj->group_focus_parent) { - obj = obj->group_focus_parent; + if(obj->group_focus_parent) { + obj = obj->group_focus_parent; } #endif From b23d945ed45d54796e49b4d85e04ee2c2a1555bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Thu, 21 May 2020 14:09:56 +0200 Subject: [PATCH 04/28] changed behavior to focus_parent flag --- lv_conf_template.h | 4 --- src/lv_conf_internal.h | 6 ---- src/lv_core/lv_group.c | 39 --------------------- src/lv_core/lv_group.h | 17 --------- src/lv_core/lv_obj.c | 76 ++++++++++++++++++++++++++++++---------- src/lv_core/lv_obj.h | 30 ++++++++++++---- src/lv_widgets/lv_page.c | 7 ++-- tests/build.py | 4 --- 8 files changed, 83 insertions(+), 100 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index caaa2ac5f..04efb35a4 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -173,10 +173,6 @@ typedef void * lv_anim_user_data_t; #define LV_USE_GROUP 1 #if LV_USE_GROUP typedef void * lv_group_user_data_t; - -/* 1: Enable to apply focus style to different object */ -#define LV_USE_GROUP_FOCUS_PARENT 1 - #endif /*LV_USE_GROUP*/ /* 1: Enable GPU interface*/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 3c9974cc4..2aa30c6f4 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -257,12 +257,6 @@ #define LV_USE_GROUP 1 #endif #if LV_USE_GROUP - -/* 1: Enable to apply focus style to different object */ -#ifndef LV_USE_GROUP_FOCUS_PARENT -#define LV_USE_GROUP_FOCUS_PARENT 1 -#endif - #endif /*LV_USE_GROUP*/ /* 1: Enable GPU interface*/ diff --git a/src/lv_core/lv_group.c b/src/lv_core/lv_group.c index c573a0b0a..057c78ecb 100644 --- a/src/lv_core/lv_group.c +++ b/src/lv_core/lv_group.c @@ -149,11 +149,6 @@ void lv_group_remove_obj(lv_obj_t * obj) { lv_group_t * g = obj->group_p; if(g == NULL) return; - -#if LV_USE_GROUP_FOCUS_PARENT - lv_group_remove_focus_parent(obj); -#endif - if(g->obj_focus == NULL) return; /*Just to be sure (Not possible if there is at least one object in the group)*/ /*Focus on the next object*/ @@ -206,11 +201,6 @@ void lv_group_remove_all_objs(lv_group_t * group) lv_obj_t ** obj; _LV_LL_READ(group->obj_ll, obj) { (*obj)->group_p = NULL; - -#if LV_USE_GROUP_FOCUS_PARENT - lv_group_remove_focus_parent(*obj); -#endif - } _lv_ll_clear(&(group->obj_ll)); @@ -542,33 +532,4 @@ static void obj_to_foreground(lv_obj_t * obj) } } - -#if LV_USE_GROUP_FOCUS_PARENT -/** - * Set focus parent for the object (focus style will apply to parent, when child is focused) - * @param child Child object - * @param parent Parent object - */ -void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent) -{ - child->group_focus_parent = parent; - - /*if the child is in focused state right now, set focus state to parent*/ - if(lv_obj_is_focused(child)) { - lv_obj_clear_state(child, LV_STATE_FOCUSED | LV_STATE_EDITED); - lv_obj_set_state(parent, LV_STATE_FOCUSED); - } -} - -/** - * Remove focus mode from child - * @param obj Child object - */ -void lv_group_remove_focus_parent(lv_obj_t * obj) -{ - obj->group_focus_parent = NULL; -} - -#endif - #endif /*LV_USE_GROUP != 0*/ diff --git a/src/lv_core/lv_group.h b/src/lv_core/lv_group.h index 8726dbb58..ef165ee38 100644 --- a/src/lv_core/lv_group.h +++ b/src/lv_core/lv_group.h @@ -228,23 +228,6 @@ bool lv_group_get_click_focus(const lv_group_t * group); */ bool lv_group_get_wrap(lv_group_t * group); -#if LV_USE_GROUP_FOCUS_PARENT -/** - * Set focus parent for the object (focus style will apply to parent, when child is focused) - * @param child Child object - * @param parent Parent object - */ -void lv_group_set_focus_parent(lv_obj_t * child, lv_obj_t * parent); - -/** - * Remove focus mode from child - * @param obj Child object - */ -void lv_group_remove_focus_parent(lv_obj_t * obj); - -#endif - - /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index bfddd53d4..54f03332a 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -298,10 +298,6 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) #if LV_USE_GROUP new_obj->group_p = NULL; -#if LV_USE_GROUP_FOCUS_PARENT - new_obj->group_focus_parent = NULL; -#endif - #endif /*Set attributes*/ @@ -316,6 +312,7 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->protect = LV_PROTECT_NONE; new_obj->parent_event = 0; new_obj->gesture_parent = 1; + new_obj->focus_parent = 0; new_obj->state = LV_STATE_DEFAULT; new_obj->ext_attr = NULL; @@ -1523,6 +1520,31 @@ void lv_obj_set_gesture_parent(lv_obj_t * obj, bool en) obj->gesture_parent = (en == true ? 1 : 0); } +/** +* Enable to use parent for focus state. +* When object is focused the parent will get the state instead (visual only) +* @param obj pointer to an object +* @param en true: enable the 'focus parent' for the object +*/ +void lv_obj_set_focus_parent(lv_obj_t * obj, bool en) +{ + if (lv_obj_is_focused(obj)) { + if (en) { + obj->focus_parent = 1; + lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED); + lv_obj_set_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED); + } + else { + lv_obj_clear_state(lv_obj_get_focused_obj(obj), LV_STATE_FOCUSED | LV_STATE_EDITED); + lv_obj_set_state(obj, LV_STATE_FOCUSED); + obj->focus_parent = 0; + } + } + else { + obj->focus_parent = (en == true ? 1 : 0); + } +} + /** * Propagate the events to the parent too * @param obj pointer to an object @@ -2724,6 +2746,16 @@ bool lv_obj_get_gesture_parent(const lv_obj_t * obj) return obj->gesture_parent == 0 ? false : true; } +/** +* Get the focus parent attribute of an object +* @param obj pointer to an object +* @return true: focus parent is enabled +*/ +bool lv_obj_get_focus_parent(const lv_obj_t * obj) +{ + return obj->focus_parent == 0 ? false : true; +} + /** * Get the drag parent attribute of an object * @param obj pointer to an object @@ -3570,6 +3602,23 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area return LV_DESIGN_RES_OK; } + +/** + * Get the really dragged object by taking `focus_parent` into account. + * @param obj the start object + * @return the object to really focus + */ +lv_obj_t * lv_obj_get_focused_obj(lv_obj_t * obj) +{ + if(obj == NULL) return NULL; + lv_obj_t * focus_obj = obj; + while(lv_obj_get_focus_parent(focus_obj) != false && focus_obj != NULL) { + focus_obj = lv_obj_get_parent(focus_obj); + } + + return focus_obj; +} + /** * Signal function of the basic object * @param obj pointer to an object @@ -3619,35 +3668,24 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) uint8_t state = LV_STATE_FOCUSED; state |= LV_STATE_EDITED; -#if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if(obj->group_focus_parent) { - obj = obj->group_focus_parent; - } -#endif + obj = lv_obj_get_focused_obj(obj); lv_obj_add_state(obj, state); } else { -#if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if(obj->group_focus_parent) { - obj = obj->group_focus_parent; - } -#endif + obj = lv_obj_get_focused_obj(obj); + lv_obj_add_state(obj, LV_STATE_FOCUSED); lv_obj_clear_state(obj, LV_STATE_EDITED); } } else if(sign == LV_SIGNAL_DEFOCUS) { -#if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if(obj->group_focus_parent) { - obj = obj->group_focus_parent; - } -#endif + obj = lv_obj_get_focused_obj(obj); lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED); } diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index b914611ca..1d73f302d 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -220,18 +220,14 @@ typedef struct _lv_obj_t { uint8_t top : 1; /**< 1: If the object or its children is clicked it goes to the foreground*/ uint8_t parent_event : 1; /**< 1: Send the object's events to the parent too. */ uint8_t adv_hittest : 1; /**< 1: Use advanced hit-testing (slower) */ - uint8_t gesture_parent : 1; /**< 1: Parent will be gesture instead*/ + uint8_t gesture_parent : 1; /**< 1: Parent will be gesture instead*/ + uint8_t focus_parent : 1; /**< 1: Parent will be focused instead*/ lv_drag_dir_t drag_dir : 3; /**< Which directions the object can be dragged in */ lv_bidi_dir_t base_dir : 2; /**< Base direction of texts related to this object */ #if LV_USE_GROUP != 0 void * group_p; - -#if LV_USE_GROUP_FOCUS_PARENT - struct _lv_obj_t * group_focus_parent; /**< Pointer to focus parent object. */ -#endif - #endif uint8_t protect; /**< Automatically happening actions can be prevented. @@ -1314,6 +1310,28 @@ void * lv_obj_get_group(const lv_obj_t * obj); */ bool lv_obj_is_focused(const lv_obj_t * obj); +/** + * Get the really dragged object by taking `focus_parent` into account. + * @param obj the start object + * @return the object to really focus + */ +lv_obj_t * lv_obj_get_focused_obj(lv_obj_t * obj); + +/** +* Enable to use parent for focus state. +* When object is focused the parent will get the state instead (visual only) +* @param obj pointer to an object +* @param en true: enable the 'focus parent' for the object +*/ +void lv_obj_set_focus_parent(lv_obj_t * obj, bool en); + +/** +* Get the focus parent attribute of an object +* @param obj pointer to an object +* @return true: focus parent is enabled +*/ +bool lv_obj_get_focus_parent(const lv_obj_t * obj); + /*------------------- * OTHER FUNCTIONS *------------------*/ diff --git a/src/lv_widgets/lv_page.c b/src/lv_widgets/lv_page.c index 9a50967e2..5989b2978 100644 --- a/src/lv_widgets/lv_page.c +++ b/src/lv_widgets/lv_page.c @@ -485,12 +485,9 @@ void lv_page_focus(lv_obj_t * page, const lv_obj_t * obj, lv_anim_enable_t anim_ lv_anim_del(ext->scrl, (lv_anim_exec_xcb_t)lv_obj_set_y); #endif -#if LV_USE_GROUP_FOCUS_PARENT /*if using focus mode, change target to parent*/ - if(obj->group_focus_parent) { - obj = obj->group_focus_parent; - } -#endif + obj = lv_obj_get_focused_obj(obj); + /*If obj is higher then the page focus where the "error" is smaller*/ lv_coord_t obj_y = obj->coords.y1 - ext->scrl->coords.y1; diff --git a/tests/build.py b/tests/build.py index fe4237bf1..804d56396 100755 --- a/tests/build.py +++ b/tests/build.py @@ -58,7 +58,6 @@ minimal_monochrome = { "LV_VER_RES_MAX":64, "LV_COLOR_DEPTH":1, "LV_USE_GROUP":0, - "LV_USE_GROUP_FOCUS_PARENT":0, "LV_USE_ANIMATION":0, "LV_ANTIALIAS":0, "LV_GPU":0, @@ -138,7 +137,6 @@ all_obj_minimal_features = { "LV_VER_RES_MAX":240, "LV_COLOR_DEPTH":8, "LV_USE_GROUP":0, - "LV_USE_GROUP_FOCUS_PARENT":0, "LV_USE_ANIMATION":0, "LV_ANTIALIAS":0, "LV_GPU":0, @@ -216,7 +214,6 @@ all_obj_all_features = { "LV_COLOR_DEPTH":32, "LV_COLOR_SCREEN_TRANSP":1, "LV_USE_GROUP":1, - "LV_USE_GROUP_FOCUS_PARENT":1, "LV_USE_ANIMATION":1, "LV_ANTIALIAS":1, "LV_GPU":1, @@ -298,7 +295,6 @@ advanced_features = { "LV_COLOR_16_SWAP":1, "LV_COLOR_SCREEN_TRANSP":1, "LV_USE_GROUP":1, - "LV_USE_GROUP_FOCUS_PARENT":1, "LV_USE_ANIMATION":1, "LV_ANTIALIAS":1, "LV_GPU":1, From 8f19010b17fd8bb43c6bf48148d920749b7bee59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Thu, 21 May 2020 17:27:37 +0200 Subject: [PATCH 05/28] Update src/lv_core/lv_obj.c Co-authored-by: Gabor Kiss-Vamosi --- src/lv_core/lv_obj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 54f03332a..2214967e5 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -3604,7 +3604,7 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area /** - * Get the really dragged object by taking `focus_parent` into account. + * Get the really focused object by taking `focus_parent` into account. * @param obj the start object * @return the object to really focus */ @@ -4041,4 +4041,3 @@ static void lv_event_mark_deleted(lv_obj_t * obj) } } - From 1666c8cb4fb9e609819b0c70f92f2c6aed2f631a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Sat, 23 May 2020 14:53:23 +0200 Subject: [PATCH 06/28] handle focus_parent in pointer indevs --- src/lv_core/lv_indev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 6b0e23aba..5d7261162 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -1092,8 +1092,9 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point) static void indev_click_focus(lv_indev_proc_t * proc) { /*Handle click focus*/ + lv_obj_t * obj_to_focus = lv_obj_get_focused_obj(indev_obj_act); if(lv_obj_is_protected(indev_obj_act, LV_PROTECT_CLICK_FOCUS) == false && - proc->types.pointer.last_pressed != indev_obj_act) { + proc->types.pointer.last_pressed != obj_to_focus) { #if LV_USE_GROUP lv_group_t * g_act = lv_obj_get_group(indev_obj_act); lv_group_t * g_prev = proc->types.pointer.last_pressed ? lv_obj_get_group(proc->types.pointer.last_pressed) : NULL; @@ -1172,7 +1173,7 @@ static void indev_click_focus(lv_indev_proc_t * proc) lv_event_send(indev_obj_act, LV_EVENT_FOCUSED, NULL); if(indev_reset_check(proc)) return; #endif - proc->types.pointer.last_pressed = indev_obj_act; + proc->types.pointer.last_pressed = obj_to_focus; } } From 691ce778008d92b336b18783213ceeb00531c498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Hor=C3=ADnek?= Date: Mon, 25 May 2020 15:51:20 +0200 Subject: [PATCH 07/28] Modified version for encoder input proc. Now you can also pass buttons LEFT/RIGHT to emulate the encoder, good for joysticks or small keypads. All other keys are passed trought. --- src/lv_core/lv_indev.c | 244 ++++++++++++++++++++++++-------------- src/lv_hal/lv_hal_indev.c | 5 + 2 files changed, 157 insertions(+), 92 deletions(-) diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 6b0e23aba..b48343a26 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -607,8 +607,158 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data) indev_obj_act = lv_group_get_focused(g); if(indev_obj_act == NULL) return; - /*Process the steps first. They are valid only with released button*/ - if(data->state == LV_INDEV_STATE_REL) { + /*Process the steps they are valid only with released button*/ + if(data->state != LV_INDEV_STATE_REL) { + data->enc_diff = 0; + } + + /*Refresh the focused object. It might change due to lv_group_focus_prev/next*/ + indev_obj_act = lv_group_get_focused(g); + if(indev_obj_act == NULL) return; + + /*Button press happened*/ + if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_REL) { + + i->proc.pr_timestamp = lv_tick_get(); + + if (data->key == LV_KEY_ENTER) { + bool editable = false; + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); + + if(lv_group_get_editing(g) == true || editable == false) { + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL); + if(indev_reset_check(&i->proc)) return; + } + } else if(data->key == LV_KEY_LEFT) { + /*emulate encoder left*/ + data->enc_diff--; + } else if(data->key == LV_KEY_RIGHT) { + /*emulate encoder right*/ + data->enc_diff++; + } else if(data->key == LV_KEY_ESC) { + /*Send the ESC as a normal KEY*/ + lv_group_send_data(g, LV_KEY_ESC); + + lv_event_send(indev_obj_act, LV_EVENT_CANCEL, NULL); + if(indev_reset_check(&i->proc)) return; + } + /*Just send other keys to the object (e.g. 'A' or `LV_GROUP_KEY_RIGHT`)*/ + else { + lv_group_send_data(g, data->key); + } + } + /*Pressing*/ + else if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_PR) { + /* Long press*/ + if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver.long_press_time) { + + i->proc.long_pr_sent = 1; + i->proc.longpr_rep_timestamp = lv_tick_get(); + + if (data->key == LV_KEY_ENTER) { + bool editable = false; + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); + + /*On enter long press toggle edit mode.*/ + if(editable) { + /*Don't leave edit mode if there is only one object (nowhere to navigate)*/ + if(_lv_ll_is_empty(&g->obj_ll) == false) { + lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/ + } + } + /*If not editable then just send a long press signal*/ + else { + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL); + if(indev_reset_check(&i->proc)) return; + lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL); + if(indev_reset_check(&i->proc)) return; + } + } + + i->proc.long_pr_sent = 1; + } + /*Long press repeated time has elapsed?*/ + else if(i->proc.long_pr_sent != 0 && lv_tick_elaps(i->proc.longpr_rep_timestamp) > i->driver.long_press_rep_time) { + + i->proc.longpr_rep_timestamp = lv_tick_get(); + + if(data->key == LV_KEY_ENTER) { + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS_REP, NULL); + if(indev_reset_check(&i->proc)) return; + lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED_REPEAT, NULL); + if(indev_reset_check(&i->proc)) return; + } + else if(data->key == LV_KEY_LEFT) { + /*emulate encoder left*/ + data->enc_diff--; + } else if(data->key == LV_KEY_RIGHT) { + /*emulate encoder right*/ + data->enc_diff++; + } else { + lv_group_send_data(g, data->key); + if(indev_reset_check(&i->proc)) return; + } + + } + + } + /*Release happened*/ + else if(data->state == LV_INDEV_STATE_REL && last_state == LV_INDEV_STATE_PR) { + + if (data->key == LV_KEY_ENTER) { + bool editable = false; + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); + + /*The button was released on a non-editable object. Just send enter*/ + if(editable == false) { + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL); + if(indev_reset_check(&i->proc)) return; + + if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); + if(indev_reset_check(&i->proc)) return; + } + /*An object is being edited and the button is released. */ + else if(g->editing) { + /*Ignore long pressed enter release because it comes from mode switch*/ + if(!i->proc.long_pr_sent || _lv_ll_is_empty(&g->obj_ll)) { + indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); + if(indev_reset_check(&i->proc)) return; + + lv_group_send_data(g, LV_KEY_ENTER); + } + } + /*If the focused object is editable and now in navigate mode then on enter switch edit + mode*/ + else if(editable && !g->editing && !i->proc.long_pr_sent) { + lv_group_set_editing(g, true); /*Set edit mode*/ + } + } + + i->proc.pr_timestamp = 0; + i->proc.long_pr_sent = 0; + } + indev_obj_act = NULL; + + /*if encoder steps or simulated steps via left/right keys*/ + if (data->enc_diff != 0) { /*In edit mode send LEFT/RIGHT keys*/ if(lv_group_get_editing(g)) { int32_t s; @@ -631,96 +781,6 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data) } } - /*Refresh the focused object. It might change due to lv_group_focus_prev/next*/ - indev_obj_act = lv_group_get_focused(g); - if(indev_obj_act == NULL) return; - - /*Button press happened*/ - if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_REL) { - bool editable = false; - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); - - i->proc.pr_timestamp = lv_tick_get(); - if(lv_group_get_editing(g) == true || editable == false) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL); - if(indev_reset_check(&i->proc)) return; - } - } - /*Pressing*/ - else if(data->state == LV_INDEV_STATE_PR && last_state == LV_INDEV_STATE_PR) { - if(i->proc.long_pr_sent == 0 && lv_tick_elaps(i->proc.pr_timestamp) > i->driver.long_press_time) { - bool editable = false; - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); - - /*On enter long press toggle edit mode.*/ - if(editable) { - /*Don't leave edit mode if there is only one object (nowhere to navigate)*/ - if(_lv_ll_is_empty(&g->obj_ll) == false) { - lv_group_set_editing(g, lv_group_get_editing(g) ? false : true); /*Toggle edit mode on long press*/ - } - } - /*If not editable then just send a long press signal*/ - else { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, NULL); - if(indev_reset_check(&i->proc)) return; - lv_event_send(indev_obj_act, LV_EVENT_LONG_PRESSED, NULL); - if(indev_reset_check(&i->proc)) return; - } - i->proc.long_pr_sent = 1; - } - } - /*Release happened*/ - else if(data->state == LV_INDEV_STATE_REL && last_state == LV_INDEV_STATE_PR) { - - bool editable = false; - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_GET_EDITABLE, &editable); - - /*The button was released on a non-editable object. Just send enter*/ - if(editable == false) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL); - if(indev_reset_check(&i->proc)) return; - - if(i->proc.long_pr_sent == 0) lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); - if(indev_reset_check(&i->proc)) return; - } - /*An object is being edited and the button is released. */ - else if(g->editing) { - /*Ignore long pressed enter release because it comes from mode switch*/ - if(!i->proc.long_pr_sent || _lv_ll_is_empty(&g->obj_ll)) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_RELEASED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); - if(indev_reset_check(&i->proc)) return; - - lv_group_send_data(g, LV_KEY_ENTER); - } - } - /*If the focused object is editable and now in navigate mode then on enter switch edit - mode*/ - else if(editable && !g->editing && !i->proc.long_pr_sent) { - lv_group_set_editing(g, true); /*Set edit mode*/ - } - - i->proc.pr_timestamp = 0; - i->proc.long_pr_sent = 0; - } - indev_obj_act = NULL; #else (void)data; /*Unused*/ (void)i; /*Unused*/ diff --git a/src/lv_hal/lv_hal_indev.c b/src/lv_hal/lv_hal_indev.c index 0dd328a5c..b99b57beb 100644 --- a/src/lv_hal/lv_hal_indev.c +++ b/src/lv_hal/lv_hal_indev.c @@ -143,6 +143,11 @@ bool _lv_indev_read(lv_indev_t * indev, lv_indev_data_t * data) else if(indev->driver.type == LV_INDEV_TYPE_KEYPAD) { data->key = indev->proc.types.keypad.last_key; } + /*For compatibility assume that used button was enter (encoder push) */ + else if(indev->driver.type == LV_INDEV_TYPE_ENCODER) { + data->key = LV_KEY_ENTER; + data->enc_diff = 0; + } if(indev->driver.read_cb) { LV_LOG_TRACE("idnev read started"); From 2be22d3bef9322963494c97a32634b1ecbe5e41e Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 27 May 2020 11:22:01 +0200 Subject: [PATCH 08/28] list: leaving edit mode with encoder --- src/lv_widgets/lv_list.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lv_widgets/lv_list.c b/src/lv_widgets/lv_list.c index 65c79bd2b..b460157a3 100644 --- a/src/lv_widgets/lv_list.c +++ b/src/lv_widgets/lv_list.c @@ -712,6 +712,11 @@ static lv_res_t lv_list_signal(lv_obj_t * list, lv_signal_t sign, void * param) if(ext->last_sel_btn) lv_list_focus_btn(list, ext->last_sel_btn); else lv_list_focus_btn(list, lv_list_get_next_btn(list, NULL)); } + if(indev_type == LV_INDEV_TYPE_ENCODER && lv_group_get_editing(g) == false) { + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); + if(ext->act_sel_btn) lv_obj_clear_state(ext->act_sel_btn, LV_STATE_PRESSED); + if(ext->last_sel_btn) lv_obj_clear_state(ext->last_sel_btn, LV_STATE_PRESSED); + } #endif } else if(sign == LV_SIGNAL_DEFOCUS) { @@ -811,8 +816,10 @@ static lv_res_t lv_list_btn_signal(lv_obj_t * btn, lv_signal_t sign, void * para else if(sign == LV_SIGNAL_CLEANUP) { #if LV_USE_GROUP lv_obj_t * list = lv_obj_get_parent(lv_obj_get_parent(btn)); + lv_list_ext_t * ext = lv_obj_get_ext_attr(list); lv_obj_t * sel = lv_list_get_btn_selected(list); if(sel == btn) lv_list_focus_btn(list, lv_list_get_next_btn(list, btn)); + if(ext->last_sel_btn == btn) ext->last_sel_btn = NULL; #endif } From e3b5a14275256189d5c30850810479538ae33e70 Mon Sep 17 00:00:00 2001 From: Deon Marais Date: Fri, 5 Jun 2020 11:58:33 +0200 Subject: [PATCH 09/28] Add align-member and set/get functions --- src/lv_widgets/lv_btnmatrix.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/lv_widgets/lv_btnmatrix.h b/src/lv_widgets/lv_btnmatrix.h index 04effd2ff..f9d9b06a0 100644 --- a/src/lv_widgets/lv_btnmatrix.h +++ b/src/lv_widgets/lv_btnmatrix.h @@ -59,6 +59,7 @@ typedef struct { uint16_t btn_id_act; /*Index of the active button (being pressed/released etc) or LV_BTNMATRIX_BTN_NONE */ uint8_t recolor : 1; /*Enable button recoloring*/ uint8_t one_check : 1; /*Single button toggled at once*/ + uint8_t align : 2; /*Align type from 'lv_label_align_t'*/ } lv_btnmatrix_ext_t; enum { @@ -169,6 +170,13 @@ void lv_btnmatrix_set_btn_width(lv_obj_t * btnm, uint16_t btn_id, uint8_t width) * @param one_chk Whether "one check" mode is enabled */ void lv_btnmatrix_set_one_check(lv_obj_t * btnm, bool one_chk); + +/** + * Set the align of the map text (left, right or center) + * @param btnm pointer to a btnmatrix object + * @param align LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +void lv_btnmatrix_set_align(lv_obj_t* btnm, lv_label_align_t align); /*===================== * Getter functions @@ -236,6 +244,14 @@ bool lv_btnmatrix_get_btn_ctrl(lv_obj_t * btnm, uint16_t btn_id, lv_btnmatrix_ct * @return whether "one toggle" mode is enabled */ bool lv_btnmatrix_get_one_check(const lv_obj_t * btnm); + +/** + * Get the align attribute + * @param btnm pointer to a btnmatrix object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_btnmatrix_get_align(const lv_obj_t* btnm); + /********************** * MACROS **********************/ From 0e1b02e3281f2abc307f063e9f1f6abd171a1d7d Mon Sep 17 00:00:00 2001 From: Deon Marais Date: Fri, 5 Jun 2020 12:05:34 +0200 Subject: [PATCH 10/28] Add lv_btnmatrix_set/gett_align capability --- src/lv_widgets/lv_btnmatrix.c | 48 ++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/lv_widgets/lv_btnmatrix.c b/src/lv_widgets/lv_btnmatrix.c index ea49348b3..3b2a3d0a8 100644 --- a/src/lv_widgets/lv_btnmatrix.c +++ b/src/lv_widgets/lv_btnmatrix.c @@ -422,6 +422,23 @@ void lv_btnmatrix_set_one_check(lv_obj_t * btnm, bool one_chk) make_one_button_toggled(btnm, 0); } +/** + * Set the align of the map text (left, right or center) + * @param btnm pointer to a btnmatrix object + * @param align LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +void lv_btnmatrix_set_align(lv_obj_t* btnm, lv_label_align_t align) +{ + LV_ASSERT_OBJ(btnm, LV_OBJX_NAME); + + lv_btnmatrix_ext_t* ext = lv_obj_get_ext_attr(btnm); + if (ext->align == align) return; + + ext->align = align; + + lv_obj_invalidate(btnm); +} + /*===================== * Getter functions *====================*/ @@ -563,6 +580,32 @@ bool lv_btnmatrix_get_one_check(const lv_obj_t * btnm) return ext->one_check; } +/** + * Get the align attribute + * @param btnm pointer to a btnmatrix object + * @return LV_LABEL_ALIGN_LEFT, LV_LABEL_ALIGN_RIGHT or LV_LABEL_ALIGN_CENTER + */ +lv_label_align_t lv_btnmatrix_get_align(const lv_obj_t* btnm) +{ + LV_ASSERT_OBJ(btnm, LV_OBJX_NAME); + + lv_btnmatrix_ext_t* ext = lv_obj_get_ext_attr(btnm); + + lv_label_align_t align = ext->align; + + if (align == LV_LABEL_ALIGN_AUTO) { +#if LV_USE_BIDI + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm); + if (base_dir == LV_BIDI_DIR_RTL) align = LV_LABEL_ALIGN_RIGHT; + else align = LV_LABEL_ALIGN_LEFT; +#else + align = LV_LABEL_ALIGN_LEFT; +#endif + } + + return align; +} + /********************** * STATIC FUNCTIONS **********************/ @@ -598,7 +641,10 @@ static lv_design_res_t lv_btnmatrix_design(lv_obj_t * btnm, const lv_area_t * cl uint16_t btn_i = 0; uint16_t txt_i = 0; lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE; - if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR; + if (ext->recolor) txt_flag |= LV_TXT_FLAG_RECOLOR; + lv_label_align_t align = lv_btnmatrix_get_align(btnm); + if (align == LV_LABEL_ALIGN_CENTER) txt_flag |= LV_TXT_FLAG_CENTER; + if (align == LV_LABEL_ALIGN_RIGHT) txt_flag |= LV_TXT_FLAG_RIGHT; lv_draw_rect_dsc_t draw_rect_rel_dsc; lv_draw_label_dsc_t draw_label_rel_dsc; From 0d897136c9758cec6f22e1c7d2a8cc2eacc65183 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 Jun 2020 11:10:11 +0100 Subject: [PATCH 11/28] Added LV_BLEND_BUF_ATTR as blend_buf MUST be in DMA accessible RAM --- src/lv_draw/lv_draw_blend.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index f87ca5733..ea446c765 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -338,7 +338,7 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co else { #if LV_USE_GPU if(disp->driver.gpu_blend_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { - static lv_color_t blend_buf[LV_HOR_RES_MAX]; + LV_BLEND_BUF_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX]; for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full; for(y = draw_area->y1; y <= draw_area->y2; y++) { @@ -352,7 +352,8 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { - static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0}; + /* blend_buf MUST be in DMA accessible RAM (depending on linker this isn't always the case - CCMRAM) */ + LV_BLEND_BUF_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0}; if(blend_buf[0].full != color.full) lv_color_fill(blend_buf, color, LV_HOR_RES_MAX); lv_coord_t line_h = LV_HOR_RES_MAX / draw_area_w; From cd9f34076e9c850accce52abf92a28df2db4afee Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 Jun 2020 11:10:51 +0100 Subject: [PATCH 12/28] Modified DMA2D fill, copy and blend functions to use direct register writes --- src/lv_gpu/lv_gpu_stm32_dma2d.c | 111 ++++++++++++++++---------------- src/lv_gpu/lv_gpu_stm32_dma2d.h | 6 ++ 2 files changed, 60 insertions(+), 57 deletions(-) diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index b1a52b1a3..a756e3af5 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -11,19 +11,14 @@ #if LV_USE_GPU_STM32_DMA2D -#if defined(STM32F4) - #include "stm32f4xx_hal.h" -#elif defined(STM32F7) - #include "stm32f7xx_hal.h" -#else - #error "Not supported STM32 family to use DMA2D" -#endif +#include "stm32f429xx.h" /********************* * DEFINES *********************/ #if LV_COLOR_16_SWAP + // TODO: F7 has red blue swap bit in control register for all layers and output #error "Can't use DMA2D with LV_COLOR_16_SWAP 1" #endif @@ -32,11 +27,9 @@ #endif #if LV_COLOR_DEPTH == 16 - #define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 - #define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 + #define DMA2D_COLOR_FORMAT DMA2D_RGB565 #elif LV_COLOR_DEPTH == 32 - #define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_ARGB8888 - #define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888 + #define DMA2D_COLOR_FORMAT DMA2D_ARGB8888 #else /*Can't use GPU with other formats*/ #endif @@ -54,7 +47,6 @@ static void dma2d_wait(void); /********************** * STATIC VARIABLES **********************/ -static DMA2D_HandleTypeDef hdma2d; /********************** * MACROS @@ -64,6 +56,18 @@ static DMA2D_HandleTypeDef hdma2d; * GLOBAL FUNCTIONS **********************/ +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_gpu_stm32_dma2d_init(void) +{ + /* Enable DMA2D clock */ + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; + + /* set output colour mode */ + DMA2D->OPFCCR = DMA2D_COLOR_FORMAT; +} + /** * Fill an area in the buffer with a color * @param buf a buffer which should be filled @@ -77,18 +81,16 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo { invalidate_cache(); - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_R2M; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = buf_w - fill_w; - hdma2d.LayerCfg[1].InputAlpha = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = 0; + DMA2D->CR = 0x30000; + DMA2D->OMAR = (uint32_t)buf; + /* as input color mode is same as output we don't need to convert here do we? */ + DMA2D->OCOLR = color.full; + DMA2D->OOR = buf_w - fill_w; + DMA2D->NLR = (fill_w << DMA2D_NLR_PL_Pos) | (fill_h << DMA2D_NLR_NL_Pos); + + /* start transfer */ + DMA2D->CR |= DMA2D_CR_START_Msk; - /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d); - HAL_DMA2D_ConfigLayer(&hdma2d, 1); - HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h); dma2d_wait(); } @@ -106,6 +108,7 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h) { +#if 0 invalidate_cache(); /* Configure the DMA2D Mode, Color Mode and line output offset */ @@ -134,6 +137,7 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t HAL_DMA2D_ConfigLayer(&hdma2d, 1); HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h); dma2d_wait(); +#endif } /** @@ -151,22 +155,17 @@ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_ { invalidate_cache(); - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_M2M; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = buf_w - copy_w; + DMA2D->CR = 0; + /* copy output colour mode, this register controls both input and output colour format */ + DMA2D->FGPFCCR = DMA2D_COLOR_FORMAT; + DMA2D->FGMAR = (uint32_t)map; + DMA2D->FGOR = map_w - copy_w; + DMA2D->OMAR = (uint32_t)buf; + DMA2D->OOR = buf_w - copy_w; + DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos); - /* Foreground layer */ - hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = 0xFF; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = map_w - copy_w; - - /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d); - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - HAL_DMA2D_ConfigLayer(&hdma2d, 1); - HAL_DMA2D_Start(&hdma2d, (uint32_t)map, (uint32_t)buf, copy_w, copy_h); + /* start transfer */ + DMA2D->CR |= DMA2D_CR_START_Msk; dma2d_wait(); } @@ -185,28 +184,26 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { invalidate_cache(); + DMA2D->CR = 0x20000; - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_M2M_BLEND; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = buf_w - copy_w; + DMA2D->BGPFCCR = DMA2D_COLOR_FORMAT; + DMA2D->BGMAR = (uint32_t)buf; + DMA2D->BGOR = buf_w - copy_w; - /* Background layer */ - hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[0].InputOffset = buf_w - copy_w; + DMA2D->FGPFCCR = (uint32_t)DMA2D_COLOR_FORMAT + /* alpha mode 2, replace with foreground * alpha value */ + | (2 << DMA2D_FGPFCCR_AM_Pos) + /* alpha value */ + | (opa << DMA2D_FGPFCCR_ALPHA_Pos); + DMA2D->FGMAR = (uint32_t)map; + DMA2D->FGOR = map_w - copy_w; - /* Foreground layer */ - hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = opa; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = map_w - copy_w; + DMA2D->OMAR = (uint32_t)buf; + DMA2D->OOR = buf_w - copy_w; + DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos); - /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d); - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - HAL_DMA2D_ConfigLayer(&hdma2d, 1); - HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h); + /* start transfer */ + DMA2D->CR |= DMA2D_CR_START_Msk; dma2d_wait(); } @@ -226,7 +223,7 @@ static void invalidate_cache(void) static void dma2d_wait(void) { lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - while(HAL_DMA2D_PollForTransfer(&hdma2d, 0) == HAL_TIMEOUT) { + while(DMA2D->CR & DMA2D_CR_START_Msk) { if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver); } } diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.h b/src/lv_gpu/lv_gpu_stm32_dma2d.h index 9f757d8ff..52e4b2fe4 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.h +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.h @@ -20,6 +20,12 @@ extern "C" { * DEFINES *********************/ +#define DMA2D_ARGB8888 0 +#define DMA2D_RGB888 1 +#define DMA2D_RGB565 2 +#define DMA2D_ARGB1555 3 +#define DMA2D_ARGB4444 4 + /********************** * TYPEDEFS **********************/ From bb5c6437fff58d11622fd68b4bc868ee2bc44c90 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 5 Jun 2020 14:04:52 +0100 Subject: [PATCH 13/28] Added GPU init to lv_init Changed blend buffer attr to more general LV_DMA_ATTR Added define for CMSIS header Fixed bug with turning on peripheral clock --- src/lv_core/lv_obj.c | 9 +++++++++ src/lv_draw/lv_draw_blend.c | 4 ++-- src/lv_gpu/lv_gpu_stm32_dma2d.c | 5 ++++- src/lv_gpu/lv_gpu_stm32_dma2d.h | 5 +++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index fa0ad53ac..dbc630928 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -38,6 +38,10 @@ #include LV_THEME_DEFAULT_INCLUDE +#if LV_USE_GPU_STM32_DMA2D +#include "../lv_gpu/lv_gpu_stm32_dma2d.h" +#endif + /********************* * DEFINES *********************/ @@ -139,6 +143,11 @@ void lv_init(void) _lv_group_init(); #endif +#if LV_USE_GPU_STM32_DMA2D + /*Initialize DMA2D GPU*/ + lv_gpu_stm32_dma2d_init(); +#endif + _lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(lv_style_trans_t)); _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index ea446c765..3bdd7e0d7 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -338,7 +338,7 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co else { #if LV_USE_GPU if(disp->driver.gpu_blend_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { - LV_BLEND_BUF_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX]; + LV_DMA_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX]; for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full; for(y = draw_area->y1; y <= draw_area->y2; y++) { @@ -353,7 +353,7 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { /* blend_buf MUST be in DMA accessible RAM (depending on linker this isn't always the case - CCMRAM) */ - LV_BLEND_BUF_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0}; + LV_DMA_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0}; if(blend_buf[0].full != color.full) lv_color_fill(blend_buf, color, LV_HOR_RES_MAX); lv_coord_t line_h = LV_HOR_RES_MAX / draw_area_w; diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index a756e3af5..7e7367331 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -11,7 +11,7 @@ #if LV_USE_GPU_STM32_DMA2D -#include "stm32f429xx.h" +#include LV_CPU_DMA2D_CMSIS_INCLUDE /********************* * DEFINES @@ -64,6 +64,9 @@ void lv_gpu_stm32_dma2d_init(void) /* Enable DMA2D clock */ RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN; + /* Delay after setting peripheral clock */ + volatile uint32_t temp = RCC->AHB1ENR; + /* set output colour mode */ DMA2D->OPFCCR = DMA2D_COLOR_FORMAT; } diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.h b/src/lv_gpu/lv_gpu_stm32_dma2d.h index 52e4b2fe4..035647199 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.h +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.h @@ -34,6 +34,11 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +/** + * Turn on the peripheral and set output color mode, this only needs to be done once + */ +void lv_gpu_stm32_dma2d_init(void); + /** * Fill an area in the buffer with a color * @param buf a buffer which should be filled From 0867f72cb94b37607e93227c4cba5637d783561d Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 8 Jun 2020 08:40:50 +0100 Subject: [PATCH 14/28] Rename attribute define to match existing options style Moved static array declaration to top of file Added attribute define to template and checker headers --- lv_conf_template.h | 4 ++++ src/lv_conf_internal.h | 6 ++++++ src/lv_draw/lv_draw_blend.c | 7 ++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index d6a9c4543..5335c3ef2 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -249,6 +249,10 @@ typedef void * lv_img_decoder_user_data_t; */ #define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning +/* Prefix variables that are used in GPU accelerated operations, often these need to be + * placed in RAM sections that are DMA accessible */ +#define LV_ATTRIBUTE_DMA + /*=================== * HAL settings *==================*/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 42cf547ba..08f3be42f 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -363,6 +363,12 @@ #define LV_EXPORT_CONST_INT(int_value) struct _silence_gcc_warning #endif +/* Prefix variables that are used in GPU accelerated operations, often these need to be + * placed in RAM sections that are DMA accessible */ +#ifndef LV_ATTRIBUTE_DMA +#define LV_ATTRIBUTE_DMA +#endif + /*=================== * HAL settings *==================*/ diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 3bdd7e0d7..6a2bb1915 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -60,6 +60,10 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co * STATIC VARIABLES **********************/ +#if LV_USE_GPU || LV_USE_GPU_STM32_DMA2D +LV_ATTRIBUTE_DMA static lv_color_t blend_buf[LV_HOR_RES_MAX]; +#endif + /********************** * MACROS **********************/ @@ -338,7 +342,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co else { #if LV_USE_GPU if(disp->driver.gpu_blend_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { - LV_DMA_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX]; for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full; for(y = draw_area->y1; y <= draw_area->y2; y++) { @@ -352,8 +355,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { - /* blend_buf MUST be in DMA accessible RAM (depending on linker this isn't always the case - CCMRAM) */ - LV_DMA_ATTR static lv_color_t blend_buf[LV_HOR_RES_MAX] = {0}; if(blend_buf[0].full != color.full) lv_color_fill(blend_buf, color, LV_HOR_RES_MAX); lv_coord_t line_h = LV_HOR_RES_MAX / draw_area_w; From 14de809fa5821fbe0406cdd87ce6c25b0d7a0881 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 8 Jun 2020 14:10:30 +0200 Subject: [PATCH 15/28] fix warings --- src/lv_core/lv_obj.c | 6 +++--- src/lv_core/lv_obj.h | 36 +++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index f49d0c8c0..fcff75481 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -3681,15 +3681,15 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area * @param obj the start object * @return the object to really focus */ -lv_obj_t * lv_obj_get_focused_obj(lv_obj_t * obj) +lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj) { if(obj == NULL) return NULL; - lv_obj_t * focus_obj = obj; + const lv_obj_t * focus_obj = obj; while(lv_obj_get_focus_parent(focus_obj) != false && focus_obj != NULL) { focus_obj = lv_obj_get_parent(focus_obj); } - return focus_obj; + return (lv_obj_t*)focus_obj; } /** diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index c0c9782b6..f58cb7f8d 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -686,6 +686,14 @@ void lv_obj_set_drag_throw(lv_obj_t * obj, bool en); */ void lv_obj_set_drag_parent(lv_obj_t * obj, bool en); +/** +* Enable to use parent for focus state. +* When object is focused the parent will get the state instead (visual only) +* @param obj pointer to an object +* @param en true: enable the 'focus parent' for the object +*/ +void lv_obj_set_focus_parent(lv_obj_t * obj, bool en); + /** * Enable to use parent for gesture related operations. * If trying to gesture the object the parent will be moved instead @@ -1189,6 +1197,15 @@ bool lv_obj_get_drag_throw(const lv_obj_t * obj); */ bool lv_obj_get_drag_parent(const lv_obj_t * obj); + +/** +* Get the focus parent attribute of an object +* @param obj pointer to an object +* @return true: focus parent is enabled +*/ +bool lv_obj_get_focus_parent(const lv_obj_t * obj); + + /** * Get the drag parent attribute of an object * @param obj pointer to an object @@ -1321,26 +1338,11 @@ void * lv_obj_get_group(const lv_obj_t * obj); bool lv_obj_is_focused(const lv_obj_t * obj); /** - * Get the really dragged object by taking `focus_parent` into account. + * Get the really focused object by taking `focus_parent` into account. * @param obj the start object * @return the object to really focus */ -lv_obj_t * lv_obj_get_focused_obj(lv_obj_t * obj); - -/** -* Enable to use parent for focus state. -* When object is focused the parent will get the state instead (visual only) -* @param obj pointer to an object -* @param en true: enable the 'focus parent' for the object -*/ -void lv_obj_set_focus_parent(lv_obj_t * obj, bool en); - -/** -* Get the focus parent attribute of an object -* @param obj pointer to an object -* @return true: focus parent is enabled -*/ -bool lv_obj_get_focus_parent(const lv_obj_t * obj); +lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj); /*------------------- * OTHER FUNCTIONS From 9c8c8aee72532075b1308963ef0537c5f5843038 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 8 Jun 2020 14:13:33 +0200 Subject: [PATCH 16/28] update CHANGLEOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 998e9afbe..13bd032b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## v7.1.0 (under development) +*Available in the `dev` branch* +- Add `focus_parent` attribute to `lv_obj` ## v7.0.2 (under development) *Available in the `master` branch* From 47549350383d3ba8d06407c54a78a279eff8d8c2 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 8 Jun 2020 14:15:14 +0200 Subject: [PATCH 17/28] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13bd032b2..1c17aa52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## v7.1.0 (under development) *Available in the `dev` branch* - Add `focus_parent` attribute to `lv_obj` +- Allow using buttons in encoder input device ## v7.0.2 (under development) *Available in the `master` branch* From 94b2e0f1a30c6a8c00ce75e486cf2180bbe6c0e5 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 8 Jun 2020 14:16:25 +0200 Subject: [PATCH 18/28] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c17aa52c..0d9e541de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,14 @@ ## v7.1.0 (under development) *Available in the `dev` branch* + +### New features - Add `focus_parent` attribute to `lv_obj` - Allow using buttons in encoder input device +- Add lv_btnmatrix_set/get_align capability + +### Bugfixes +- None ## v7.0.2 (under development) *Available in the `master` branch* From 3c70a1b5a2c4846ecd20d5dc2fb2a43a38718d11 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 8 Jun 2020 18:36:30 +0100 Subject: [PATCH 19/28] Fixed typo in include define Added help in lv_conf_template.h --- lv_conf_template.h | 2 ++ src/lv_gpu/lv_gpu_stm32_dma2d.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index 5335c3ef2..c02b6a428 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -178,6 +178,8 @@ typedef void * lv_group_user_data_t; /* 1: Enable GPU interface*/ #define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 0 +/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor */ +#define LV_GPU_DMA2D_CMSIS_INCLUDE /* 1: Enable file system (might be required for images */ #define LV_USE_FILESYSTEM 1 diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 7e7367331..5d51b0920 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -11,7 +11,7 @@ #if LV_USE_GPU_STM32_DMA2D -#include LV_CPU_DMA2D_CMSIS_INCLUDE +#include LV_GPU_DMA2D_CMSIS_INCLUDE /********************* * DEFINES From 0ebcf7e26612d77903d1a7dbefbef9f8c16a6b14 Mon Sep 17 00:00:00 2001 From: "artur.vieira" Date: Mon, 8 Jun 2020 20:22:06 +0100 Subject: [PATCH 20/28] Added Max Used propriety to lv_mem_monitor_t struct --- src/lv_misc/lv_mem.c | 19 ++++++++++++++++--- src/lv_misc/lv_mem.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lv_misc/lv_mem.c b/src/lv_misc/lv_mem.c index ef570a04c..583492bef 100644 --- a/src/lv_misc/lv_mem.c +++ b/src/lv_misc/lv_mem.c @@ -85,7 +85,7 @@ typedef struct { #endif static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/ - +static uint32_t mem_max_size; /*Tracks the maximum total size of memory allocated from the internal heap*/ static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE]; static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE]; @@ -118,10 +118,11 @@ void _lv_mem_init(void) /*Allocate a large array to store the dynamically allocated data*/ static LV_MEM_ATTR MEM_UNIT work_mem_int[LV_MEM_SIZE / sizeof(MEM_UNIT)]; work_mem = (uint8_t *)work_mem_int; + mem_max_size = 0; #else work_mem = (uint8_t *)LV_MEM_ADR; #endif - + lv_mem_ent_t * full = (lv_mem_ent_t *)work_mem; full->header.s.used = 0; /*The total mem size id reduced by the first header and the close patterns */ @@ -200,7 +201,18 @@ void * lv_mem_alloc(size_t size) if(alloc != NULL) _lv_memset(alloc, 0xaa, size); #endif - if(alloc == NULL) LV_LOG_WARN("Couldn't allocate memory"); + if(alloc == NULL) { + LV_LOG_WARN("Couldn't allocate memory"); + }else{ + #if LV_MEM_CUSTOM == 0 + /* just a safety check, should always be true */ + if ((uint32_t) alloc > (uint32_t) work_mem) { + if ((((uint32_t) alloc - (uint32_t) work_mem) + size) > mem_max_size) { + mem_max_size = ((uint32_t) alloc - (uint32_t) work_mem) + size; + } + } + #endif + } return alloc; } @@ -424,6 +436,7 @@ void lv_mem_monitor(lv_mem_monitor_t * mon_p) e = ent_get_next(e); } mon_p->total_size = LV_MEM_SIZE; + mon_p->max_used = mem_max_size; mon_p->used_pct = 100 - (100U * mon_p->free_size) / mon_p->total_size; if(mon_p->free_size > 0) { mon_p->frag_pct = (uint32_t)mon_p->free_biggest_size * 100U / mon_p->free_size; diff --git a/src/lv_misc/lv_mem.h b/src/lv_misc/lv_mem.h index 8bd5cf00d..2b1e8a00e 100644 --- a/src/lv_misc/lv_mem.h +++ b/src/lv_misc/lv_mem.h @@ -41,6 +41,7 @@ typedef struct { uint32_t free_size; /**< Size of available memory */ uint32_t free_biggest_size; uint32_t used_cnt; + uint32_t max_used; /**< Max size of Heap memory used */ uint8_t used_pct; /**< Percentage used */ uint8_t frag_pct; /**< Amount of fragmentation */ } lv_mem_monitor_t; From 91acf877c680da43ce05ec4a420d2956247ebda8 Mon Sep 17 00:00:00 2001 From: arturv2000 Date: Mon, 8 Jun 2020 21:00:12 +0100 Subject: [PATCH 21/28] Attempt to correct error in tests --- src/lv_misc/lv_mem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lv_misc/lv_mem.c b/src/lv_misc/lv_mem.c index 583492bef..530d50197 100644 --- a/src/lv_misc/lv_mem.c +++ b/src/lv_misc/lv_mem.c @@ -206,9 +206,9 @@ void * lv_mem_alloc(size_t size) }else{ #if LV_MEM_CUSTOM == 0 /* just a safety check, should always be true */ - if ((uint32_t) alloc > (uint32_t) work_mem) { - if ((((uint32_t) alloc - (uint32_t) work_mem) + size) > mem_max_size) { - mem_max_size = ((uint32_t) alloc - (uint32_t) work_mem) + size; + if ((uintptr_t) alloc > (uintptr_t) work_mem) { + if ((((uintptr_t) alloc - (uintptr_t) work_mem) + size) > mem_max_size) { + mem_max_size = ((uintptr_t) alloc - (uintptr_t) work_mem) + size; } } #endif From 71e23c4e1394e43afb00dff02116735181323b76 Mon Sep 17 00:00:00 2001 From: microwavesafe Date: Tue, 9 Jun 2020 09:45:12 +0100 Subject: [PATCH 22/28] Added example include defines --- lv_conf_template.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index c02b6a428..b95000cac 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -178,7 +178,8 @@ typedef void * lv_group_user_data_t; /* 1: Enable GPU interface*/ #define LV_USE_GPU 1 /*Only enables `gpu_fill_cb` and `gpu_blend_cb` in the disp. drv- */ #define LV_USE_GPU_STM32_DMA2D 0 -/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor */ +/*If enabling LV_USE_GPU_STM32_DMA2D, LV_GPU_DMA2D_CMSIS_INCLUDE must be defined to include path of CMSIS header of target processor +e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE /* 1: Enable file system (might be required for images */ From ce8d3334074bad89c909ca49c113611f924083ee Mon Sep 17 00:00:00 2001 From: arturv2000 Date: Tue, 9 Jun 2020 09:46:42 +0100 Subject: [PATCH 23/28] Update src/lv_misc/lv_mem.c Co-authored-by: Gabor Kiss-Vamosi --- src/lv_misc/lv_mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lv_misc/lv_mem.c b/src/lv_misc/lv_mem.c index 530d50197..3b2db31fe 100644 --- a/src/lv_misc/lv_mem.c +++ b/src/lv_misc/lv_mem.c @@ -85,7 +85,7 @@ typedef struct { #endif static uint32_t zero_mem; /*Give the address of this variable if 0 byte should be allocated*/ -static uint32_t mem_max_size; /*Tracks the maximum total size of memory allocated from the internal heap*/ +static uint32_t mem_max_size; /*Tracks the maximum total size of memory ever used from the internal heap*/ static uint8_t mem_buf1_32[MEM_BUF_SMALL_SIZE]; static uint8_t mem_buf2_32[MEM_BUF_SMALL_SIZE]; From 14a359679a77b10ba5826fdbaac2e36dd8b8a8da Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 9 Jun 2020 13:41:24 +0200 Subject: [PATCH 24/28] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d9e541de..4d5645685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Add `focus_parent` attribute to `lv_obj` - Allow using buttons in encoder input device - Add lv_btnmatrix_set/get_align capability +- DMA2D: Remove dependency on ST CubeMX HAL ### Bugfixes - None From dca12fcd7a5d51706f3f00a0309a265bb8ad30b3 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Wed, 10 Jun 2020 10:14:12 +0200 Subject: [PATCH 25/28] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f7811cbc..1921150e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Allow using buttons in encoder input device - Add lv_btnmatrix_set/get_align capability - DMA2D: Remove dependency on ST CubeMX HAL +- Added `max_used` propriety to `lv_mem_monitor_t` struct ### Bugfixes - None From a265165038950676861ad57b5709354ea89b5c17 Mon Sep 17 00:00:00 2001 From: Carlos Diaz Date: Fri, 12 Jun 2020 06:26:59 -0500 Subject: [PATCH 26/28] Add lv_win_add_btn_left (#1566) Closes #1535 --- src/lv_api_map.h | 9 ++ src/lv_widgets/lv_spinner.c | 26 +++--- src/lv_widgets/lv_spinner.h | 54 ++++++------ src/lv_widgets/lv_win.c | 171 +++++++++++++++++++++++++++++++----- src/lv_widgets/lv_win.h | 12 ++- 5 files changed, 210 insertions(+), 62 deletions(-) diff --git a/src/lv_api_map.h b/src/lv_api_map.h index f194a5881..2f18a7ede 100644 --- a/src/lv_api_map.h +++ b/src/lv_api_map.h @@ -176,6 +176,15 @@ static inline lv_obj_t * lv_page_get_scrl(lv_obj_t * page) } #endif +#if LV_USE_WIN + +static inline lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src) +{ + return lv_win_add_btn_right(win, img_src); +} + +#endif + #endif /*LV_USE_API_EXTENSION_V6*/ /********************** diff --git a/src/lv_widgets/lv_spinner.c b/src/lv_widgets/lv_spinner.c index 1df16ca09..773228d1f 100644 --- a/src/lv_widgets/lv_spinner.c +++ b/src/lv_widgets/lv_spinner.c @@ -56,22 +56,22 @@ static lv_design_cb_t ancestor_design; **********************/ /** - * Create a pre loader object - * @param par pointer to an object, it will be the parent of the new pre loader - * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from + * Create a spinner object + * @param par pointer to an object, it will be the parent of the new spinner + * @param copy pointer to a spinner object, if not NULL then the new object will be copied from * it - * @return pointer to the created pre loader + * @return pointer to the created spinner */ lv_obj_t * lv_spinner_create(lv_obj_t * par, const lv_obj_t * copy) { LV_LOG_TRACE("spinner create started"); - /*Create the ancestor of pre loader*/ + /*Create the ancestor of spinner*/ lv_obj_t * spinner = lv_arc_create(par, copy); LV_ASSERT_MEM(spinner); if(spinner == NULL) return NULL; - /*Allocate the pre loader type specific extended data*/ + /*Allocate the spinner type specific extended data*/ lv_spinner_ext_t * ext = lv_obj_allocate_ext_attr(spinner, sizeof(lv_spinner_ext_t)); LV_ASSERT_MEM(ext); if(ext == NULL) { @@ -154,7 +154,7 @@ void lv_spinner_set_spin_time(lv_obj_t * spinner, uint16_t time) /** * Set the animation type of a spinnereer. - * @param spinner pointer to pre loader object + * @param spinner pointer to spinner object * @param type animation type of the spinner * */ void lv_spinner_set_type(lv_obj_t * spinner, lv_spinner_type_t type) @@ -230,8 +230,8 @@ void lv_spinner_set_dir(lv_obj_t * spinner, lv_spinner_dir_t dir) *====================*/ /** - * Get the arc length [degree] of the a pre loader - * @param spinner pointer to a pre loader object + * Get the arc length [degree] of the a spinner + * @param spinner pointer to a spinner object */ lv_anim_value_t lv_spinner_get_arc_length(const lv_obj_t * spinner) { @@ -243,7 +243,7 @@ lv_anim_value_t lv_spinner_get_arc_length(const lv_obj_t * spinner) /** * Get the spin time of the arc - * @param spinner pointer to a pre loader object [milliseconds] + * @param spinner pointer to a spinner object [milliseconds] */ uint16_t lv_spinner_get_spin_time(const lv_obj_t * spinner) { @@ -255,7 +255,7 @@ uint16_t lv_spinner_get_spin_time(const lv_obj_t * spinner) /** * Get the animation type of a spinnereer. - * @param spinner pointer to pre loader object + * @param spinner pointer to spinner object * @return animation type * */ lv_spinner_type_t lv_spinner_get_type(lv_obj_t * spinner) @@ -301,8 +301,8 @@ void lv_spinner_anim_cb(void * ptr, lv_anim_value_t val) **********************/ /** - * Signal function of the pre loader - * @param spinner pointer to a pre loader object + * Signal function of the spinner + * @param spinner pointer to a spinner object * @param sign a signal type from lv_signal_t enum * @param param pointer to a signal specific variable * @return LV_RES_OK: the object is not deleted in the function; LV_RES_INV: the object is deleted diff --git a/src/lv_widgets/lv_spinner.h b/src/lv_widgets/lv_spinner.h index e9127d94a..6649202e4 100644 --- a/src/lv_widgets/lv_spinner.h +++ b/src/lv_widgets/lv_spinner.h @@ -1,5 +1,5 @@ /** - * @file lv_preload.h + * @file lv_spinner.h * */ @@ -19,11 +19,11 @@ extern "C" { /*Testing of dependencies*/ #if LV_USE_ARC == 0 -#error "lv_preload: lv_arc is required. Enable it in lv_conf.h (LV_USE_ARC 1) " +#error "lv_spinner: lv_arc is required. Enable it in lv_conf.h (LV_USE_ARC 1) " #endif #if LV_USE_ANIMATION == 0 -#error "lv_preload: animations are required. Enable it in lv_conf.h (LV_USE_ANIMATION 1) " +#error "lv_spinner: animations are required. Enable it in lv_conf.h (LV_USE_ANIMATION 1) " #endif #include "../lv_core/lv_obj.h" @@ -57,7 +57,7 @@ enum { }; typedef uint8_t lv_spinner_dir_t; -/*Data of pre loader*/ +/*Data of spinner*/ typedef struct { lv_arc_ext_t arc; /*Ext. of ancestor*/ /*New data for this type */ @@ -82,11 +82,11 @@ typedef uint8_t lv_spinner_style_t; **********************/ /** - * Create a pre loader objects - * @param par pointer to an object, it will be the parent of the new pre loader - * @param copy pointer to a pre loader object, if not NULL then the new object will be copied from + * Create a spinner object + * @param par pointer to an object, it will be the parent of the new spinner + * @param copy pointer to a spinner object, if not NULL then the new object will be copied from * it - * @return pointer to the created pre loader + * @return pointer to the created spinner */ lv_obj_t * lv_spinner_create(lv_obj_t * par, const lv_obj_t * copy); @@ -96,17 +96,17 @@ lv_obj_t * lv_spinner_create(lv_obj_t * par, const lv_obj_t * copy); /** * Set the length of the spinning arc in degrees - * @param preload pointer to a preload object + * @param spinner pointer to a spinner object * @param deg length of the arc */ -void lv_spinner_set_arc_length(lv_obj_t * preload, lv_anim_value_t deg); +void lv_spinner_set_arc_length(lv_obj_t * spinner, lv_anim_value_t deg); /** * Set the spin time of the arc - * @param preload pointer to a preload object + * @param spinner pointer to a spinner object * @param time time of one round in milliseconds */ -void lv_spinner_set_spin_time(lv_obj_t * preload, uint16_t time); +void lv_spinner_set_spin_time(lv_obj_t * spinner, uint16_t time); /*===================== * Setter functions @@ -114,47 +114,47 @@ void lv_spinner_set_spin_time(lv_obj_t * preload, uint16_t time); /** * Set the animation type of a spinner. - * @param preload pointer to pre loader object - * @param type animation type of the preload + * @param spinner pointer to spinner object + * @param type animation type of the spinner * */ -void lv_spinner_set_type(lv_obj_t * preload, lv_spinner_type_t type); +void lv_spinner_set_type(lv_obj_t * spinner, lv_spinner_type_t type); /** * Set the animation direction of a spinner - * @param preload pointer to pre loader object - * @param direction animation direction of the preload + * @param spinner pointer to spinner object + * @param direction animation direction of the spinner */ -void lv_spinner_set_dir(lv_obj_t * preload, lv_spinner_dir_t dir); +void lv_spinner_set_dir(lv_obj_t * spinner, lv_spinner_dir_t dir); /*===================== * Getter functions *====================*/ /** - * Get the arc length [degree] of the a pre loader - * @param preload pointer to a pre loader object + * Get the arc length [degree] of the a spinner + * @param spinner pointer to a spinner object */ -lv_anim_value_t lv_spinner_get_arc_length(const lv_obj_t * preload); +lv_anim_value_t lv_spinner_get_arc_length(const lv_obj_t * spinner); /** * Get the spin time of the arc - * @param preload pointer to a pre loader object [milliseconds] + * @param spinner pointer to a spinner object [milliseconds] */ -uint16_t lv_spinner_get_spin_time(const lv_obj_t * preload); +uint16_t lv_spinner_get_spin_time(const lv_obj_t * spinner); /** * Get the animation type of a spinner. - * @param preload pointer to pre loader object + * @param spinner pointer to spinner object * @return animation type * */ -lv_spinner_type_t lv_spinner_get_type(lv_obj_t * preload); +lv_spinner_type_t lv_spinner_get_type(lv_obj_t * spinner); /** * Get the animation direction of a spinner - * @param preload pointer to pre loader object + * @param spinner pointer to spinner object * @return animation direction */ -lv_spinner_dir_t lv_spinner_get_dir(lv_obj_t * preload); +lv_spinner_dir_t lv_spinner_get_dir(lv_obj_t * spinner); /*===================== * Other functions diff --git a/src/lv_widgets/lv_win.c b/src/lv_widgets/lv_win.c index cccd2af57..d5c773361 100644 --- a/src/lv_widgets/lv_win.c +++ b/src/lv_widgets/lv_win.c @@ -23,6 +23,22 @@ * TYPEDEFS **********************/ +/** Extended data of win_btn*/ +typedef struct { + /** Ext. of ancestor*/ + lv_btn_ext_t btn; + + /** Which side of the header should the button be aligned to. + * 0: Align to right (default), 1: Align to left */ + uint8_t alignment_in_header : 1; +} lv_win_btn_ext_t; + +enum { + LV_WIN_BTN_ALIGN_RIGHT = 0, /**< Align button to right of the header */ + LV_WIN_BTN_ALIGN_LEFT /**< Align button to left of the header */ +}; +typedef uint8_t lv_win_btn_align_t; + /********************** * STATIC PROTOTYPES **********************/ @@ -30,6 +46,9 @@ static lv_res_t lv_win_signal(lv_obj_t * win, lv_signal_t sign, void * param); static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * clip_area, lv_design_mode_t mode); static lv_style_list_t * lv_win_get_style(lv_obj_t * win, uint8_t part); static void lv_win_realign(lv_obj_t * win); +static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src); +static void lv_win_btn_set_alignment(lv_obj_t * par, const lv_win_btn_align_t alignment); +static lv_win_btn_align_t lv_win_btn_get_alignment(const lv_obj_t * par); /********************** * STATIC VARIABLES @@ -166,23 +185,39 @@ void lv_win_clean(lv_obj_t * win) * Add control button to the header of the window * @param win pointer to a window object * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @param alignment button alignment on the header * @return pointer to the created button object */ -lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src) +lv_obj_t * lv_win_add_btn_right(lv_obj_t * win, const void * img_src) { LV_ASSERT_OBJ(win, LV_OBJX_NAME); LV_ASSERT_NULL(img_src); lv_win_ext_t * ext = lv_obj_get_ext_attr(win); - lv_obj_t * btn = lv_btn_create(ext->header, NULL); - lv_theme_apply(btn, LV_THEME_WIN_BTN); - lv_coord_t btn_size = lv_obj_get_height_fit(ext->header); - lv_obj_set_size(btn, btn_size, btn_size); + lv_obj_t * btn = lv_win_btn_create(ext->header, img_src); + lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_RIGHT); - lv_obj_t * img = lv_img_create(btn, NULL); - lv_obj_set_click(img, false); - lv_img_set_src(img, img_src); + lv_win_realign(win); + + return btn; +} + +/** + * Add control button on the left side of the window header + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn_left(lv_obj_t * win, const void * img_src) +{ + LV_ASSERT_OBJ(win, LV_OBJX_NAME); + LV_ASSERT_NULL(img_src); + + lv_win_ext_t * ext = lv_obj_get_ext_attr(win); + + lv_obj_t * btn = lv_win_btn_create(ext->header, img_src); + lv_win_btn_set_alignment(btn, LV_WIN_BTN_ALIGN_LEFT); lv_win_realign(win); @@ -501,7 +536,8 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * lv_obj_t * win = lv_obj_get_parent(header); lv_win_ext_t * ext = lv_obj_get_ext_attr(win); - lv_style_int_t left = lv_obj_get_style_pad_left(header, LV_OBJ_PART_MAIN); + lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER); + lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER); lv_draw_label_dsc_t label_dsc; lv_draw_label_dsc_init(&label_dsc); @@ -510,13 +546,29 @@ static lv_design_res_t lv_win_header_design(lv_obj_t * header, const lv_area_t * lv_area_t txt_area; lv_point_t txt_size; - _lv_txt_get_size(&txt_size, ext->title_txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX, label_dsc.flag); - txt_area.x1 = header->coords.x1 + left; + lv_obj_t * btn = NULL; + + lv_coord_t btn_h = lv_obj_get_height_fit(header); + lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h; + + /*Get x position of the title (should be on the right of the buttons on the left)*/ + + lv_coord_t left_btn_offset = 0; + btn = lv_obj_get_child_back(ext->header, NULL); + while(btn != NULL) { + if (LV_WIN_BTN_ALIGN_LEFT == lv_win_btn_get_alignment(btn)) { + left_btn_offset += btn_w + header_inner; + } + + btn = lv_obj_get_child_back(header, btn); + } + + txt_area.x1 = header->coords.x1 + header_left + left_btn_offset; txt_area.y1 = header->coords.y1 + (lv_obj_get_height(header) - txt_size.y) / 2; - txt_area.x2 = txt_area.x1 + txt_size.x; + txt_area.x2 = txt_area.x1 + txt_size.x + left_btn_offset; txt_area.y2 = txt_area.y1 + txt_size.y; lv_draw_label(&txt_area, clip_area, &label_dsc, ext->title_txt, NULL); @@ -644,23 +696,52 @@ static void lv_win_realign(lv_obj_t * win) lv_obj_set_width(ext->header, lv_obj_get_width(win)); lv_obj_t * btn; - lv_obj_t * btn_prev = NULL; + lv_obj_t * btn_prev_at_left = NULL; + lv_obj_t * btn_prev_at_right = NULL; + + bool is_header_right_side_empty = true; + bool is_header_left_side_empty = true; + lv_coord_t btn_h = lv_obj_get_height_fit(ext->header); lv_coord_t btn_w = ext->btn_w != 0 ? ext->btn_w : btn_h; lv_style_int_t header_inner = lv_obj_get_style_pad_inner(win, LV_WIN_PART_HEADER); lv_style_int_t header_right = lv_obj_get_style_pad_right(win, LV_WIN_PART_HEADER); + lv_style_int_t header_left = lv_obj_get_style_pad_left(win, LV_WIN_PART_HEADER); + /*Refresh the size of all control buttons*/ btn = lv_obj_get_child_back(ext->header, NULL); while(btn != NULL) { - lv_obj_set_size(btn, btn_h, btn_w); - if(btn_prev == NULL) { - lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, -header_right, 0); + lv_obj_set_size(btn, btn_w, btn_h); + uint8_t btn_alignment = lv_win_btn_get_alignment(btn); + + if (LV_WIN_BTN_ALIGN_RIGHT == btn_alignment) { + if (is_header_right_side_empty) { + /* Align the button to the right of the header */ + lv_obj_align(btn, ext->header, LV_ALIGN_IN_RIGHT_MID, -header_right, 0); + + is_header_right_side_empty = false; + } else { + /* Align the button to the left of the previous button */ + lv_obj_align(btn, btn_prev_at_right, LV_ALIGN_OUT_LEFT_MID, -header_inner, 0); + } + + btn_prev_at_right = btn; } - else { - lv_obj_align(btn, btn_prev, LV_ALIGN_OUT_LEFT_MID, - header_inner, 0); + else if (LV_WIN_BTN_ALIGN_LEFT == btn_alignment) { + if (is_header_left_side_empty) { + /* Align the button to the right of the header */ + lv_obj_align(btn, ext->header, LV_ALIGN_IN_LEFT_MID, header_left, 0); + + is_header_left_side_empty = false; + } else { + /* Align the button to the right of the previous button */ + lv_obj_align(btn, btn_prev_at_left, LV_ALIGN_OUT_RIGHT_MID, header_inner, 0); + } + + btn_prev_at_left = btn; } - btn_prev = btn; - btn = lv_obj_get_child_back(ext->header, btn); + + btn = lv_obj_get_child_back(ext->header, btn); } lv_obj_set_pos(ext->header, 0, 0); @@ -669,4 +750,54 @@ static void lv_win_realign(lv_obj_t * win) lv_obj_align(ext->page, ext->header, LV_ALIGN_OUT_BOTTOM_LEFT, 0, 0); } +static lv_obj_t * lv_win_btn_create(lv_obj_t * par, const void * img_src) +{ + LV_LOG_TRACE("win btn create started"); + + lv_obj_t * win_btn; + + win_btn = lv_btn_create(par, NULL); + LV_ASSERT_MEM(win_btn); + if(win_btn == NULL) return NULL; + + /*Allocate the extended data*/ + lv_win_btn_ext_t * ext = lv_obj_allocate_ext_attr(win_btn, sizeof(lv_win_btn_ext_t)); + LV_ASSERT_MEM(ext); + if(ext == NULL) { + lv_obj_del(win_btn); + return NULL; + } + + ext->alignment_in_header = LV_WIN_BTN_ALIGN_RIGHT; + + lv_obj_set_click(win_btn, true); + lv_win_btn_set_alignment(win_btn, LV_WIN_BTN_ALIGN_RIGHT); + + lv_theme_apply(win_btn, LV_THEME_WIN_BTN); + lv_coord_t btn_size = lv_obj_get_height_fit(par); + lv_obj_set_size(win_btn, btn_size, btn_size); + + lv_obj_t * img = lv_img_create(win_btn, NULL); + lv_obj_set_click(img, false); + lv_img_set_src(img, img_src); + + LV_LOG_INFO("win btn created"); + + return win_btn; +} + +static void lv_win_btn_set_alignment(lv_obj_t * win_btn, const uint8_t alignment) +{ + lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn); + + ext->alignment_in_header = alignment; +} + +static uint8_t lv_win_btn_get_alignment(const lv_obj_t * win_btn) +{ + lv_win_btn_ext_t * ext = lv_obj_get_ext_attr(win_btn); + + return ext->alignment_in_header; +} + #endif diff --git a/src/lv_widgets/lv_win.h b/src/lv_widgets/lv_win.h index 6c868ee50..bbdd4d8df 100644 --- a/src/lv_widgets/lv_win.h +++ b/src/lv_widgets/lv_win.h @@ -92,12 +92,20 @@ void lv_win_clean(lv_obj_t * win); *=====================*/ /** - * Add control button to the header of the window + * Add control button on the right side of the window header * @param win pointer to a window object * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) * @return pointer to the created button object */ -lv_obj_t * lv_win_add_btn(lv_obj_t * win, const void * img_src); +lv_obj_t * lv_win_add_btn_right(lv_obj_t * win, const void * img_src); + +/** + * Add control button on the left side of the window header + * @param win pointer to a window object + * @param img_src an image source ('lv_img_t' variable, path to file or a symbol) + * @return pointer to the created button object + */ +lv_obj_t * lv_win_add_btn_left(lv_obj_t * win, const void * img_src); /*===================== * Setter functions From 43cc512e5a455f6d4f9fe485ec26c6ffeff12891 Mon Sep 17 00:00:00 2001 From: OH1BDF Date: Fri, 12 Jun 2020 14:28:11 +0300 Subject: [PATCH 27/28] Added functions to set multiple paddings and margins at once (#1565) --- src/lv_core/lv_obj_style_dec.h | 93 ++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/lv_core/lv_obj_style_dec.h b/src/lv_core/lv_obj_style_dec.h index de1b57bee..e1b65f720 100644 --- a/src/lv_core/lv_obj_style_dec.h +++ b/src/lv_core/lv_obj_style_dec.h @@ -199,6 +199,99 @@ _LV_OBJ_STYLE_SET_GET_DECLARE(SCALE_END_COLOR, scale_end_color, lv_color_t, _col #undef _LV_OBJ_STYLE_SET_GET_DECLARE + +static inline void lv_obj_set_style_local_pad_all(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_pad_top(obj, part, state, value); + lv_obj_set_style_local_pad_bottom(obj, part, state, value); + lv_obj_set_style_local_pad_left(obj, part, state, value); + lv_obj_set_style_local_pad_right(obj, part, state, value); +} + + +static inline void lv_style_set_pad_all(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_pad_top(style, state, value); + lv_style_set_pad_bottom(style, state, value); + lv_style_set_pad_left(style, state, value); + lv_style_set_pad_right(style, state, value); +} + + +static inline void lv_obj_set_style_local_pad_hor(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_pad_left(obj, part, state, value); + lv_obj_set_style_local_pad_right(obj, part, state, value); +} + + +static inline void lv_style_set_pad_hor(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_pad_left(style, state, value); + lv_style_set_pad_right(style, state, value); +} + + +static inline void lv_obj_set_style_local_pad_ver(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_pad_top(obj, part, state, value); + lv_obj_set_style_local_pad_bottom(obj, part, state, value); +} + + +static inline void lv_style_set_pad_ver(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_pad_top(style, state, value); + lv_style_set_pad_bottom(style, state, value); +} + + +static inline void lv_obj_set_style_local_margin_all(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_margin_top(obj, part, state, value); + lv_obj_set_style_local_margin_bottom(obj, part, state, value); + lv_obj_set_style_local_margin_left(obj, part, state, value); + lv_obj_set_style_local_margin_right(obj, part, state, value); +} + + +static inline void lv_style_set_margin_all(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_margin_top(style, state, value); + lv_style_set_margin_bottom(style, state, value); + lv_style_set_margin_left(style, state, value); + lv_style_set_margin_right(style, state, value); +} + + +static inline void lv_obj_set_style_local_margin_hor(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_margin_left(obj, part, state, value); + lv_obj_set_style_local_margin_right(obj, part, state, value); +} + + +static inline void lv_style_set_margin_hor(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_margin_left(style, state, value); + lv_style_set_margin_right(style, state, value); +} + + +static inline void lv_obj_set_style_local_margin_ver(lv_obj_t * obj, uint8_t part, lv_state_t state, lv_style_int_t value) +{ + lv_obj_set_style_local_margin_top(obj, part, state, value); + lv_obj_set_style_local_margin_bottom(obj, part, state, value); +} + + +static inline void lv_style_set_margin_ver(lv_style_t * style, lv_state_t state, lv_style_int_t value) +{ + lv_style_set_margin_top(style, state, value); + lv_style_set_margin_bottom(style, state, value); +} + + #ifdef __cplusplus } /* extern "C" */ #endif From 59165f077e899ebdbb4ab22a86521743f2a21cc1 Mon Sep 17 00:00:00 2001 From: besitzeruf Date: Tue, 16 Jun 2020 11:16:46 +0200 Subject: [PATCH 28/28] - Fix when border of the image (bottom and right sides) are drawn with different width ( decreased by 1) --- src/lv_draw/lv_img_buf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lv_draw/lv_img_buf.c b/src/lv_draw/lv_img_buf.c index d5d4cf940..0607662c5 100644 --- a/src/lv_draw/lv_img_buf.c +++ b/src/lv_draw/lv_img_buf.c @@ -528,8 +528,8 @@ void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t LV_UNUSED(pivot); res->x1 = 0; res->y1 = 0; - res->x2 = w; - res->y2 = h; + res->x2 = w - 1; + res->y2 = h - 1; #endif }