diff --git a/lv_conf_template.h b/lv_conf_template.h index 75d21c677..ccb01f402 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -585,12 +585,6 @@ typedef void * lv_obj_user_data_t; /*Button matrix (dependencies: -)*/ #define LV_USE_BTNMATRIX 1 -/*Calendar (dependencies: -)*/ -#define LV_USE_CALENDAR 1 -#if LV_USE_CALENDAR -# define LV_CALENDAR_WEEK_STARTS_MONDAY 0 -#endif - /*Canvas (dependencies: lv_img)*/ #define LV_USE_CANVAS 1 @@ -603,12 +597,6 @@ typedef void * lv_obj_user_data_t; # define LV_CHART_AXIS_TICK_LABEL_MAX_LEN 256 #endif -/*Container (dependencies: -*/ -#define LV_USE_CONT 1 - -/*Color picker (dependencies: -*/ -#define LV_USE_CPICKER 1 - /*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ #define LV_USE_DROPDOWN 1 #if LV_USE_DROPDOWN != 0 @@ -629,9 +617,6 @@ typedef void * lv_obj_user_data_t; # define LV_IMGBTN_TILED 0 #endif -/*Keyboard (dependencies: lv_btnm)*/ -#define LV_USE_KEYBOARD 1 - /*Label (dependencies: -*/ #define LV_USE_LABEL 1 #if LV_USE_LABEL != 0 @@ -648,56 +633,12 @@ typedef void * lv_obj_user_data_t; # define LV_LABEL_LONG_TXT_HINT 0 #endif -/*LED (dependencies: -)*/ -#define LV_USE_LED 1 -#if LV_USE_LED -# define LV_LED_BRIGHT_MIN 120 /*Minimal brightness*/ -# define LV_LED_BRIGHT_MAX 255 /*Maximal brightness*/ -#endif - /*Line (dependencies: -*/ #define LV_USE_LINE 1 -/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ -#define LV_USE_LIST 1 -#if LV_USE_LIST != 0 -/*Default animation time of focusing to a list element [ms] (0: no animation) */ -# define LV_LIST_DEF_ANIM_TIME 100 -#endif - -/*Line meter (dependencies: *;)*/ -#define LV_USE_LINEMETER 1 -#if LV_USE_LINEMETER -/* Draw line more precisely at cost of performance. - * Useful if there are lot of lines any minor are visible - * 0: No extra precision - * 1: Some extra precision - * 2: Best precision - */ -# define LV_LINEMETER_PRECISE 1 -#endif - /*Mask (dependencies: -)*/ #define LV_USE_OBJMASK 1 -/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ -#define LV_USE_MSGBOX 1 - -/*Page (dependencies: lv_cont)*/ -#define LV_USE_PAGE 1 -#if LV_USE_PAGE != 0 -/*Focus default animation time [ms] (0: no animation)*/ -# define LV_PAGE_DEF_ANIM_TIME 400 -#endif - -/*Preload (dependencies: lv_arc, lv_anim)*/ -#define LV_USE_SPINNER 1 -#if LV_USE_SPINNER != 0 -# define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/ -# define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/ -# define LV_SPINNER_DEF_ANIM LV_SPINNER_TYPE_SPINNING_ARC -#endif - /*Roller (dependencies: lv_ddlist)*/ #define LV_USE_ROLLER 1 #if LV_USE_ROLLER != 0 @@ -711,9 +652,6 @@ typedef void * lv_obj_user_data_t; /*Slider (dependencies: lv_bar)*/ #define LV_USE_SLIDER 1 -/*Spinbox (dependencies: lv_ta)*/ -#define LV_USE_SPINBOX 1 - /*Switch (dependencies: lv_slider)*/ #define LV_USE_SWITCH 1 @@ -731,24 +669,6 @@ typedef void * lv_obj_user_data_t; # define LV_TABLE_CELL_STYLE_CNT 4 #endif - -/*Tab (dependencies: lv_page, lv_btnm)*/ -#define LV_USE_TABVIEW 1 -# if LV_USE_TABVIEW != 0 -/*Time of slide animation [ms] (0: no animation)*/ -# define LV_TABVIEW_DEF_ANIM_TIME 300 -#endif - -/*Tileview (dependencies: lv_page) */ -#define LV_USE_TILEVIEW 1 -#if LV_USE_TILEVIEW -/*Time of slide animation [ms] (0: no animation)*/ -# define LV_TILEVIEW_DEF_ANIM_TIME 300 -#endif - -/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ -#define LV_USE_WIN 1 - /*================== * Non-user section *==================*/ diff --git a/lvgl.h b/lvgl.h index e0e4e7036..7be04f10d 100644 --- a/lvgl.h +++ b/lvgl.h @@ -49,34 +49,20 @@ extern "C" { #include "src/lv_widgets/lv_img.h" #include "src/lv_widgets/lv_label.h" #include "src/lv_widgets/lv_line.h" -#include "src/lv_widgets/lv_page.h" -#include "src/lv_widgets/lv_cont.h" -#include "src/lv_widgets/lv_list.h" #include "src/lv_widgets/lv_chart.h" #include "src/lv_widgets/lv_table.h" #include "src/lv_widgets/lv_checkbox.h" -#include "src/lv_widgets/lv_cpicker.h" #include "src/lv_widgets/lv_bar.h" #include "src/lv_widgets/lv_slider.h" -#include "src/lv_widgets/lv_led.h" #include "src/lv_widgets/lv_btnmatrix.h" -#include "src/lv_widgets/lv_keyboard.h" #include "src/lv_widgets/lv_dropdown.h" #include "src/lv_widgets/lv_roller.h" #include "src/lv_widgets/lv_textarea.h" #include "src/lv_widgets/lv_canvas.h" -#include "src/lv_widgets/lv_win.h" -#include "src/lv_widgets/lv_tabview.h" -#include "src/lv_widgets/lv_tileview.h" -#include "src/lv_widgets/lv_msgbox.h" #include "src/lv_widgets/lv_objmask.h" #include "src/lv_widgets/lv_gauge.h" -#include "src/lv_widgets/lv_linemeter.h" #include "src/lv_widgets/lv_switch.h" #include "src/lv_widgets/lv_arc.h" -#include "src/lv_widgets/lv_spinner.h" -#include "src/lv_widgets/lv_calendar.h" -#include "src/lv_widgets/lv_spinbox.h" #include "src/lv_draw/lv_img_cache.h" diff --git a/lvgl.mk b/lvgl.mk index bbea98d35..f2eabe8be 100644 --- a/lvgl.mk +++ b/lvgl.mk @@ -1,10 +1 @@ -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_core/lv_core.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_hal/lv_hal.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_widgets/lv_widgets.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_font/lv_font.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc/lv_misc.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_themes/lv_themes.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_draw/lv_draw.mk -include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_gpu/lv_gpu.mk - - +CSRCS += $(shell find -L lvgl -name \*.c) diff --git a/src/lv_api_map.h b/src/lv_api_map.h index 6006216cb..ab0d019b9 100644 --- a/src/lv_api_map.h +++ b/src/lv_api_map.h @@ -27,173 +27,10 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -/*--------------------- - * V6.0 COMPATIBILITY - *--------------------*/ -#if LV_USE_API_EXTENSION_V6 - -static inline void lv_task_once(lv_task_t * task) -{ - lv_task_set_repeat_count(task, 1); -} - -#if LV_USE_CHECKBOX - -#define lv_checkbox_set_static_text lv_checkbox_set_text_static - -#endif - -#if LV_USE_CHART - -#define lv_chart_get_point_cnt lv_chart_get_point_count - -#endif - - -#if LV_USE_DROPDOWN - -static inline void lv_dropdown_set_draw_arrow(lv_obj_t * ddlist, bool en) -{ - if(en) lv_dropdown_set_symbol(ddlist, LV_SYMBOL_DOWN); - else lv_dropdown_set_symbol(ddlist, NULL); -} - -static inline bool lv_dropdown_get_draw_arrow(lv_obj_t * ddlist) -{ - if(lv_dropdown_get_symbol(ddlist)) return true; - else return false; -} - -#define lv_dropdown_set_static_options lv_dropdown_set_options_static - -#endif - -#if LV_USE_BAR - -/** - * Make the bar symmetric to zero. The indicator will grow from zero instead of the minimum - * position. - * @param bar pointer to a bar object - * @param en true: enable disable symmetric behavior; false: disable - * @deprecated As of v7.0, you should use `lv_bar_set_type` instead. - */ -static inline void lv_bar_set_sym(lv_obj_t * bar, bool en) -{ - if(en) - lv_bar_set_type(bar, LV_BAR_TYPE_SYMMETRICAL); - else - lv_bar_set_type(bar, LV_BAR_TYPE_NORMAL); -} - -/** - * Get whether the bar is symmetric or not. - * @param bar pointer to a bar object - * @return true: symmetric is enabled; false: disable - * @deprecated As of v7.0, you should use `lv_bar_get_type` instead. - */ -static inline bool lv_bar_get_sym(lv_obj_t * bar) -{ - return lv_bar_get_type(bar) == LV_BAR_TYPE_SYMMETRICAL; -} - -#endif - -#if LV_USE_LABEL - -#define lv_label_set_static_text lv_label_set_text_static - -#endif - -#if LV_USE_SLIDER - -/** - * Make the slider symmetric to zero. The indicator will grow from zero instead of the minimum - * position. - * @param slider pointer to a bar object - * @param en true: enable disable symmetric behavior; false: disable - * @deprecated As of v7.0, you should use `lv_slider_set_type` instead. - */ -static inline void lv_slider_set_sym(lv_obj_t * slider, bool en) -{ - lv_bar_set_sym(slider, en); -} - -/** - * Get whether the slider is symmetric or not. - * @param slider pointer to a slider object - * @return true: symmetric is enabled; false: disable - * @deprecated As of v7.0, you should use `lv_slider_get_type` instead. - */ -static inline bool lv_slider_get_sym(lv_obj_t * slider) -{ - return lv_bar_get_sym(slider); -} - -#endif - -#if LV_USE_ROLLER - -/** - * Set a fixed width for the roller. - * @param roller pointer to a roller object - * @param w width - * @deprecated As of v7.0, you should use `lv_roller_set_auto_fit` and set the width normally instead. - */ -static inline void lv_roller_set_fix_width(lv_obj_t * roller, lv_coord_t w) -{ - lv_roller_set_auto_fit(roller, false); - lv_obj_set_width(roller, w); -} - - -#endif - - -#if LV_USE_PAGE -#define lv_scrlbar_mode_t lv_scrollbar_mode_t - -#define LV_SCRLBAR_MODE_OFF LV_SCROLLBAR_MODE_OFF -#define LV_SCRLBAR_MODE_ON LV_SCROLLBAR_MODE_ON -#define LV_SCRLBAR_MODE_DRAG LV_SCROLLBAR_MODE_DRAG -#define LV_SCRLBAR_MODE_AUTO LV_SCROLLBAR_MODE_AUTO -#define LV_SCRLBAR_MODE_HIDE LV_SCROLLBAR_MODE_HIDE -#define LV_SCRLBAR_MODE_UNHIDE LV_SCROLLBAR_MODE_UNHIDE - - -static inline void lv_page_set_scrlbar_mode(lv_obj_t * page, lv_scrlbar_mode_t sb_mode) -{ - lv_page_set_scrollbar_mode(page, sb_mode); -} -static inline lv_scrollbar_mode_t lv_page_get_scrlbar_mode(lv_obj_t * page) -{ - return lv_page_get_scrollbar_mode(page); -} - - -static inline lv_obj_t * lv_page_get_scrl(lv_obj_t * page) -{ - return lv_page_get_scrollable(page); -} -#endif - - -#endif /*LV_USE_API_EXTENSION_V6*/ - - - - /*--------------------- * V7.0 COMPATIBILITY *--------------------*/ #if LV_USE_API_EXTENSION_V7 -#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 #if LV_USE_CHART static inline void lv_chart_set_range(lv_obj_t * chart, lv_coord_t ymin, lv_coord_t ymax) @@ -212,17 +49,17 @@ static inline void lv_chart_clear_serie(lv_obj_t * chart, lv_chart_series_t * se static inline void lv_obj_align_origo(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) { - lv_obj_align_mid(obj, base, align, x_ofs, y_ofs); +// lv_obj_align_mid(obj, base, align, x_ofs, y_ofs); } static inline void lv_obj_align_origo_x(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs) { - lv_obj_align_mid_y(obj, base, align, x_ofs); +// lv_obj_align_mid_y(obj, base, align, x_ofs); } static inline void lv_obj_align_origo_y(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t y_ofs) { - lv_obj_align_mid_y(obj, base, align, y_ofs); +// lv_obj_align_mid_y(obj, base, align, y_ofs); } #endif /*LV_USE_API_EXTENSION_V6*/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 5287c7471..09e1b2a84 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -1490,24 +1490,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ # endif #endif -/*Calendar (dependencies: -)*/ -#ifndef LV_USE_CALENDAR -# ifdef CONFIG_LV_USE_CALENDAR -# define LV_USE_CALENDAR CONFIG_LV_USE_CALENDAR -# else -# define LV_USE_CALENDAR 1 -# endif -#endif -#if LV_USE_CALENDAR -#ifndef LV_CALENDAR_WEEK_STARTS_MONDAY -# ifdef CONFIG_LV_CALENDAR_WEEK_STARTS_MONDAY -# define LV_CALENDAR_WEEK_STARTS_MONDAY CONFIG_LV_CALENDAR_WEEK_STARTS_MONDAY -# else -# define LV_CALENDAR_WEEK_STARTS_MONDAY 0 -# endif -#endif -#endif - /*Canvas (dependencies: lv_img)*/ #ifndef LV_USE_CANVAS # ifdef CONFIG_LV_USE_CANVAS @@ -1544,24 +1526,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #endif #endif -/*Container (dependencies: -*/ -#ifndef LV_USE_CONT -# ifdef CONFIG_LV_USE_CONT -# define LV_USE_CONT CONFIG_LV_USE_CONT -# else -# define LV_USE_CONT 1 -# endif -#endif - -/*Color picker (dependencies: -*/ -#ifndef LV_USE_CPICKER -# ifdef CONFIG_LV_USE_CPICKER -# define LV_USE_CPICKER CONFIG_LV_USE_CPICKER -# else -# define LV_USE_CPICKER 1 -# endif -#endif - /*Drop down list (dependencies: lv_page, lv_label, lv_symbol_def.h)*/ #ifndef LV_USE_DROPDOWN # ifdef CONFIG_LV_USE_DROPDOWN @@ -1618,15 +1582,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #endif #endif -/*Keyboard (dependencies: lv_btnm)*/ -#ifndef LV_USE_KEYBOARD -# ifdef CONFIG_LV_USE_KEYBOARD -# define LV_USE_KEYBOARD CONFIG_LV_USE_KEYBOARD -# else -# define LV_USE_KEYBOARD 1 -# endif -#endif - /*Label (dependencies: -*/ #ifndef LV_USE_LABEL # ifdef CONFIG_LV_USE_LABEL @@ -1673,31 +1628,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #endif #endif -/*LED (dependencies: -)*/ -#ifndef LV_USE_LED -# ifdef CONFIG_LV_USE_LED -# define LV_USE_LED CONFIG_LV_USE_LED -# else -# define LV_USE_LED 1 -# endif -#endif -#if LV_USE_LED -#ifndef LV_LED_BRIGHT_MIN -# ifdef CONFIG_LV_LED_BRIGHT_MIN -# define LV_LED_BRIGHT_MIN CONFIG_LV_LED_BRIGHT_MIN -# else -# define LV_LED_BRIGHT_MIN 120 /*Minimal brightness*/ -# endif -#endif -#ifndef LV_LED_BRIGHT_MAX -# ifdef CONFIG_LV_LED_BRIGHT_MAX -# define LV_LED_BRIGHT_MAX CONFIG_LV_LED_BRIGHT_MAX -# else -# define LV_LED_BRIGHT_MAX 255 /*Maximal brightness*/ -# endif -#endif -#endif - /*Line (dependencies: -*/ #ifndef LV_USE_LINE # ifdef CONFIG_LV_USE_LINE @@ -1707,49 +1637,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ # endif #endif -/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/ -#ifndef LV_USE_LIST -# ifdef CONFIG_LV_USE_LIST -# define LV_USE_LIST CONFIG_LV_USE_LIST -# else -# define LV_USE_LIST 1 -# endif -#endif -#if LV_USE_LIST != 0 -/*Default animation time of focusing to a list element [ms] (0: no animation) */ -#ifndef LV_LIST_DEF_ANIM_TIME -# ifdef CONFIG_LV_LIST_DEF_ANIM_TIME -# define LV_LIST_DEF_ANIM_TIME CONFIG_LV_LIST_DEF_ANIM_TIME -# else -# define LV_LIST_DEF_ANIM_TIME 100 -# endif -#endif -#endif - -/*Line meter (dependencies: *;)*/ -#ifndef LV_USE_LINEMETER -# ifdef CONFIG_LV_USE_LINEMETER -# define LV_USE_LINEMETER CONFIG_LV_USE_LINEMETER -# else -# define LV_USE_LINEMETER 1 -# endif -#endif -#if LV_USE_LINEMETER -/* Draw line more precisely at cost of performance. - * Useful if there are lot of lines any minor are visible - * 0: No extra precision - * 1: Some extra precision - * 2: Best precision - */ -#ifndef LV_LINEMETER_PRECISE -# ifdef CONFIG_LV_LINEMETER_PRECISE -# define LV_LINEMETER_PRECISE CONFIG_LV_LINEMETER_PRECISE -# else -# define LV_LINEMETER_PRECISE 1 -# endif -#endif -#endif - /*Mask (dependencies: -)*/ #ifndef LV_USE_OBJMASK # ifdef CONFIG_LV_USE_OBJMASK @@ -1759,66 +1646,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ # endif #endif -/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/ -#ifndef LV_USE_MSGBOX -# ifdef CONFIG_LV_USE_MSGBOX -# define LV_USE_MSGBOX CONFIG_LV_USE_MSGBOX -# else -# define LV_USE_MSGBOX 1 -# endif -#endif - -/*Page (dependencies: lv_cont)*/ -#ifndef LV_USE_PAGE -# ifdef CONFIG_LV_USE_PAGE -# define LV_USE_PAGE CONFIG_LV_USE_PAGE -# else -# define LV_USE_PAGE 1 -# endif -#endif -#if LV_USE_PAGE != 0 -/*Focus default animation time [ms] (0: no animation)*/ -#ifndef LV_PAGE_DEF_ANIM_TIME -# ifdef CONFIG_LV_PAGE_DEF_ANIM_TIME -# define LV_PAGE_DEF_ANIM_TIME CONFIG_LV_PAGE_DEF_ANIM_TIME -# else -# define LV_PAGE_DEF_ANIM_TIME 400 -# endif -#endif -#endif - -/*Preload (dependencies: lv_arc, lv_anim)*/ -#ifndef LV_USE_SPINNER -# ifdef CONFIG_LV_USE_SPINNER -# define LV_USE_SPINNER CONFIG_LV_USE_SPINNER -# else -# define LV_USE_SPINNER 1 -# endif -#endif -#if LV_USE_SPINNER != 0 -#ifndef LV_SPINNER_DEF_ARC_LENGTH -# ifdef CONFIG_LV_SPINNER_DEF_ARC_LENGTH -# define LV_SPINNER_DEF_ARC_LENGTH CONFIG_LV_SPINNER_DEF_ARC_LENGTH -# else -# define LV_SPINNER_DEF_ARC_LENGTH 60 /*[deg]*/ -# endif -#endif -#ifndef LV_SPINNER_DEF_SPIN_TIME -# ifdef CONFIG_LV_SPINNER_DEF_SPIN_TIME -# define LV_SPINNER_DEF_SPIN_TIME CONFIG_LV_SPINNER_DEF_SPIN_TIME -# else -# define LV_SPINNER_DEF_SPIN_TIME 1000 /*[ms]*/ -# endif -#endif -#ifndef LV_SPINNER_DEF_ANIM -# ifdef CONFIG_LV_SPINNER_DEF_ANIM -# define LV_SPINNER_DEF_ANIM CONFIG_LV_SPINNER_DEF_ANIM -# else -# define LV_SPINNER_DEF_ANIM LV_SPINNER_TYPE_SPINNING_ARC -# endif -#endif -#endif - /*Roller (dependencies: lv_ddlist)*/ #ifndef LV_USE_ROLLER # ifdef CONFIG_LV_USE_ROLLER @@ -1856,15 +1683,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ # endif #endif -/*Spinbox (dependencies: lv_ta)*/ -#ifndef LV_USE_SPINBOX -# ifdef CONFIG_LV_USE_SPINBOX -# define LV_USE_SPINBOX CONFIG_LV_USE_SPINBOX -# else -# define LV_USE_SPINBOX 1 -# endif -#endif - /*Switch (dependencies: lv_slider)*/ #ifndef LV_USE_SWITCH # ifdef CONFIG_LV_USE_SWITCH @@ -1925,53 +1743,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #endif -/*Tab (dependencies: lv_page, lv_btnm)*/ -#ifndef LV_USE_TABVIEW -# ifdef CONFIG_LV_USE_TABVIEW -# define LV_USE_TABVIEW CONFIG_LV_USE_TABVIEW -# else -# define LV_USE_TABVIEW 1 -# endif -#endif -# if LV_USE_TABVIEW != 0 -/*Time of slide animation [ms] (0: no animation)*/ -#ifndef LV_TABVIEW_DEF_ANIM_TIME -# ifdef CONFIG_LV_TABVIEW_DEF_ANIM_TIME -# define LV_TABVIEW_DEF_ANIM_TIME CONFIG_LV_TABVIEW_DEF_ANIM_TIME -# else -# define LV_TABVIEW_DEF_ANIM_TIME 300 -# endif -#endif -#endif - -/*Tileview (dependencies: lv_page) */ -#ifndef LV_USE_TILEVIEW -# ifdef CONFIG_LV_USE_TILEVIEW -# define LV_USE_TILEVIEW CONFIG_LV_USE_TILEVIEW -# else -# define LV_USE_TILEVIEW 1 -# endif -#endif -#if LV_USE_TILEVIEW -/*Time of slide animation [ms] (0: no animation)*/ -#ifndef LV_TILEVIEW_DEF_ANIM_TIME -# ifdef CONFIG_LV_TILEVIEW_DEF_ANIM_TIME -# define LV_TILEVIEW_DEF_ANIM_TIME CONFIG_LV_TILEVIEW_DEF_ANIM_TIME -# else -# define LV_TILEVIEW_DEF_ANIM_TIME 300 -# endif -#endif -#endif - -/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/ -#ifndef LV_USE_WIN -# ifdef CONFIG_LV_USE_WIN -# define LV_USE_WIN CONFIG_LV_USE_WIN -# else -# define LV_USE_WIN 1 -# endif -#endif - /*================== * Non-user section *==================*/ diff --git a/src/lv_core/lv_core.mk b/src/lv_core/lv_core.mk index b46c01625..fab150b13 100644 --- a/src/lv_core/lv_core.mk +++ b/src/lv_core/lv_core.mk @@ -1,7 +1,13 @@ +CSRCS += lv_grid.c CSRCS += lv_group.c CSRCS += lv_indev.c +CSRCS += lv_indev_scroll.c CSRCS += lv_disp.c CSRCS += lv_obj.c +CSRCS += lv_obj_pos.c +CSRCS += lv_obj_style.c +CSRCS += lv_obj_draw.c +CSRCS += lv_obj_scroll.c CSRCS += lv_refr.c CSRCS += lv_style.c diff --git a/src/lv_core/lv_disp.c b/src/lv_core/lv_disp.c index 440232b64..ea4a87003 100644 --- a/src/lv_core/lv_disp.c +++ b/src/lv_core/lv_disp.c @@ -229,8 +229,8 @@ void lv_scr_load_anim(lv_obj_t * new_scr, lv_scr_load_anim_t anim_type, uint32_t /*Be sure both screens are in a normal position*/ lv_obj_set_pos(new_scr, 0, 0); lv_obj_set_pos(lv_scr_act(), 0, 0); - lv_style_remove_prop(lv_obj_get_local_style(new_scr, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); - lv_style_remove_prop(lv_obj_get_local_style(lv_scr_act(), LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + lv_style_remove_prop(_lv_obj_get_local_style(new_scr, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + lv_style_remove_prop(_lv_obj_get_local_style(lv_scr_act(), LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); lv_anim_t a_new; lv_anim_init(&a_new); @@ -403,6 +403,6 @@ static void scr_anim_ready(lv_anim_t * a) if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr); d->prev_scr = NULL; - lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); + lv_style_remove_prop(_lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); } #endif diff --git a/src/lv_core/lv_flex.c b/src/lv_core/lv_flex.c new file mode 100644 index 000000000..b10f04c78 --- /dev/null +++ b/src/lv_core/lv_flex.c @@ -0,0 +1,439 @@ +/** + * @file lv_flex.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_flex.h" +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + lv_coord_t grow_unit; + lv_coord_t track_cross_size; + lv_coord_t track_main_size; + uint32_t item_cnt; +}track_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +//static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_size, lv_coord_t * grow_unit, lv_coord_t * track_cross_size, lv_coord_t * track_main_size, uint32_t * item_cnt); +static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_main_size, track_t * t); +static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, lv_flex_place_t main_place, track_t * t); +static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap); + +static lv_flex_dir_t get_dir(const lv_obj_t * obj); +static bool get_rev(const lv_obj_t * obj); +static bool get_wrap(const lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/*===================== + * Setter functions + *====================*/ + +void lv_obj_set_flex_dir(lv_obj_t * obj, lv_flex_dir_t flex_dir) +{ + lv_obj_allocate_spec_attr(obj); + + if(obj->spec_attr->flex_cont.dir == flex_dir) return; + + obj->spec_attr->flex_cont.dir = flex_dir & 0x3; + obj->spec_attr->flex_cont.wrap = flex_dir & _LV_FLEX_WRAP ? 1 : 0; + obj->spec_attr->flex_cont.rev = flex_dir & _LV_FLEX_REVERSE ? 1 : 0; + _lv_flex_refresh(obj); +} + +void lv_obj_set_flex_place(lv_obj_t * obj, lv_flex_place_t item_place, lv_flex_place_t track_place) +{ + lv_obj_allocate_spec_attr(obj); + if(obj->spec_attr->flex_cont.item_place == item_place && + obj->spec_attr->flex_cont.track_place == track_place) { + return; + } + + obj->spec_attr->flex_cont.item_place = item_place; + obj->spec_attr->flex_cont.track_place = track_place; + + _lv_flex_refresh(obj); +} + +void lv_obj_set_flex_gap(lv_obj_t * obj, lv_coord_t gap) +{ + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + + if(obj->spec_attr->flex_cont.gap == gap) return; + + obj->spec_attr->flex_cont.gap = gap; + + _lv_flex_refresh(obj); +} + +void lv_obj_set_flex_item(lv_obj_t * obj, bool en) +{ + if(en) { + lv_coord_t f = _LV_COORD_FELX(LV_FLEX_PLACE_START); + lv_obj_set_pos(obj, f, f); + } else { + lv_obj_set_pos(obj, lv_obj_get_x(obj), lv_obj_get_y(obj)); + } +} + +void lv_obj_set_flex_item_place(lv_obj_t * obj, lv_flex_place_t place) +{ + if(place == LV_FLEX_PLACE_NONE) { + lv_obj_set_pos(obj, lv_obj_get_x(obj), lv_obj_get_x(obj)); + } else { + lv_coord_t f = _LV_COORD_FELX(place); + lv_obj_set_pos(obj, f, f); + } +} + +/*===================== + * Getter functions + *====================*/ + +lv_flex_dir_t lv_obj_get_flex_dir(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.dir; + else return LV_FLEX_DIR_NONE; +} + +lv_flex_place_t lv_obj_get_flex_item_place(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.item_place; + else return LV_FLEX_PLACE_START; +} + +lv_flex_place_t lv_obj_get_flex_track_place(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.track_place; + else return LV_FLEX_PLACE_START; +} + +lv_coord_t lv_obj_get_flex_gap(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.gap; + else return 0; +} + +lv_flex_place_t lv_obj_get_flex_self_place(lv_obj_t * obj) +{ + lv_coord_t x = lv_obj_get_x(obj); + if(LV_COORD_IS_FLEX(x)) return LV_COORD_GET_FLEX(x); + else return LV_FLEX_PLACE_NONE; +} + +void _lv_flex_refresh(lv_obj_t * cont) +{ + lv_flex_dir_t dir = get_dir(cont); + + if(dir == LV_FLEX_DIR_NONE) return; + + bool rtl = lv_obj_get_base_dir(cont) == LV_BIDI_DIR_RTL ? true : false; + bool row = dir == LV_FLEX_DIR_ROW ? true : false; + /*Count the grow units and free space*/ + lv_coord_t max_main_size = (row ? lv_obj_get_width_fit(cont) : lv_obj_get_height_fit(cont)); + lv_coord_t abs_y = cont->coords.y1 + lv_obj_get_style_pad_top(cont, LV_OBJ_PART_MAIN) - lv_obj_get_scroll_y(cont); + lv_coord_t abs_x = cont->coords.x1 + lv_obj_get_style_pad_left(cont, LV_OBJ_PART_MAIN) - lv_obj_get_scroll_x(cont); + + lv_flex_place_t cross_place = lv_obj_get_flex_track_place(cont); + lv_flex_place_t main_place = cont->spec_attr->flex_cont.item_place; + lv_ll_t * ll = _lv_obj_get_child_ll(cont); + lv_coord_t * cross_pos = (row ? &abs_y : &abs_x); + + if((row && cont->h_set == LV_SIZE_AUTO) || + (!row && cont->w_set == LV_SIZE_AUTO)) + { + cross_place = LV_FLEX_PLACE_START; + } + + if(rtl && !row) { + if(cross_place == LV_FLEX_PLACE_START) cross_place = LV_FLEX_PLACE_END; + else if(cross_place == LV_FLEX_PLACE_END) cross_place = LV_FLEX_PLACE_START; + } + + lv_coord_t total_track_cross_size = 0; + lv_coord_t gap = 0; + uint32_t track_cnt = 0; + lv_obj_t * track_first_item; + lv_obj_t * next_track_first_item; + bool rev = get_rev(cont); + + if(cross_place != LV_FLEX_PLACE_START) { + track_first_item = rev ? _lv_ll_get_head(ll) : _lv_ll_get_tail(ll); + track_t t; + while(track_first_item) { + /*Search the first item of the next row */ + next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &t); + total_track_cross_size += t.track_cross_size; + track_cnt++; + track_first_item = next_track_first_item; + } + + lv_coord_t max_cross_size = (row ? lv_obj_get_height_fit(cont) : lv_obj_get_width_fit(cont)); + place_content(cross_place, max_cross_size, total_track_cross_size, track_cnt, cross_pos, &gap); + } + + track_first_item = rev ? _lv_ll_get_head(ll) : _lv_ll_get_tail(ll); + + if(rtl && !row) { + *cross_pos += total_track_cross_size; + } + + while(track_first_item) { + track_t t; + /*Search the first item of the next row */ + next_track_first_item = find_track_end(cont, track_first_item, max_main_size, &t); + + if(rtl && !row) { + *cross_pos -= t.track_cross_size; + } + children_repos(cont, track_first_item, next_track_first_item, abs_x, abs_y, max_main_size, main_place, &t); + track_first_item = next_track_first_item; + + if(rtl && !row) { + *cross_pos -= gap; + } else { + *cross_pos += t.track_cross_size + gap; + } + } + LV_ASSERT_MEM_INTEGRITY(); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_obj_t * find_track_end(lv_obj_t * cont, lv_obj_t * item_start, lv_coord_t max_main_size, track_t * t) +{ + bool wrap = get_wrap(cont); + bool rev = get_rev(cont); + lv_coord_t gap = lv_obj_get_flex_gap(cont); + bool row = get_dir(cont) == LV_FLEX_DIR_ROW ? true : false; + lv_coord_t(*get_main_size)(const lv_obj_t *) = (row ? lv_obj_get_width_margin : lv_obj_get_height_margin); + lv_coord_t(*get_cross_size)(const lv_obj_t *) = (!row ? lv_obj_get_width_margin : lv_obj_get_height_margin); + void * (*ll_iter)(const lv_ll_t * , const void *) = rev ? _lv_ll_get_next : _lv_ll_get_prev; + + lv_ll_t * ll = _lv_obj_get_child_ll(cont); + + lv_coord_t grow_sum = 0; + t->track_main_size = 0; + uint32_t grow_item_cnt = 0; + t->track_cross_size = 0; + t->grow_unit = 0; + t->item_cnt = 0; + + lv_obj_t * item = item_start; + while(item) { + /*Ignore non-flex items*/ + lv_coord_t main_set = (row ? item->x_set : item->y_set); + if(LV_COORD_IS_FLEX(main_set) == false) { + item = ll_iter(ll, item); + continue; + } + + lv_coord_t main_size = (row ? item->w_set : item->h_set); + if(_LV_FLEX_GET_GROW(main_size)) { + grow_sum += _LV_FLEX_GET_GROW(main_size); + grow_item_cnt++; + } else { + lv_coord_t item_size = get_main_size(item) + gap; + if(wrap && t->track_main_size + item_size > max_main_size) break; + t->track_main_size += item_size; + } + t->track_cross_size = LV_MATH_MAX(get_cross_size(item), t->track_cross_size); + + item = ll_iter(ll, item); + t->item_cnt++; + } + + if(t->track_main_size > 0) t->track_main_size -= gap; /*There is no gap after the last item*/ + + if(grow_item_cnt && grow_sum) { + lv_coord_t s = max_main_size - t->track_main_size; + s -= grow_item_cnt * gap; + t->grow_unit = s / grow_sum; + t->track_main_size = max_main_size; /*If there is at least one "grow item" the track takes the full space*/ + } else { + t->grow_unit = 0; + } + + /*Have at least one item in a row*/ + if(item && item == item_start) { + item = ll_iter(ll, item); + if(item) { + t->track_cross_size = get_cross_size(item); + t->track_main_size = get_main_size(item); + t->item_cnt = 1; + } + } + + return item; +} + + +static void children_repos(lv_obj_t * cont, lv_obj_t * item_first, lv_obj_t * item_last, lv_coord_t abs_x, lv_coord_t abs_y, lv_coord_t max_main_size, lv_flex_place_t main_place, track_t * t) +{ + bool rev = get_rev(cont); + lv_coord_t gap = lv_obj_get_flex_gap(cont); + bool row = get_dir(cont) == LV_FLEX_DIR_ROW ? true : false; + + lv_coord_t(*obj_get_main_size)(const lv_obj_t *) = (row ? lv_obj_get_width_margin : lv_obj_get_height_margin); + lv_coord_t(*obj_get_cross_size)(const lv_obj_t *) = (!row ? lv_obj_get_width_margin : lv_obj_get_height_margin); + void (*area_set_main_size)(lv_area_t *, lv_coord_t) = (row ? lv_area_set_width : lv_area_set_height); + void (*area_set_cross_size)(lv_area_t *, lv_coord_t) = (!row ? lv_area_set_width : lv_area_set_height); + lv_coord_t (*area_get_main_size)(const lv_area_t *) = (!row ? lv_area_get_width : lv_area_get_height); + lv_style_int_t (*get_margin_start)(const lv_obj_t *, uint8_t part) = (row ? lv_obj_get_style_margin_left : lv_obj_get_style_margin_top); + lv_style_int_t (*get_margin_end)(const lv_obj_t *, uint8_t part) = (row ? lv_obj_get_style_margin_right : lv_obj_get_style_margin_bottom); + void * (*ll_iter)(const lv_ll_t * , const void *) = rev ? _lv_ll_get_next : _lv_ll_get_prev; + + bool rtl = lv_obj_get_base_dir(cont) == LV_BIDI_DIR_RTL ? true : false; + + if(row && rtl) abs_x += lv_obj_get_width_fit(cont); + + lv_ll_t * ll = _lv_obj_get_child_ll(cont); + lv_coord_t main_pos = 0; + + lv_coord_t place_gap; + place_content(main_place, max_main_size, t->track_main_size, t->item_cnt, &main_pos, &place_gap); + /*Reposition the children*/ + lv_obj_t * item = item_first; /*Just to use a shorter name*/ + while(item != item_last) { + + /*Ignore non-flex items*/ + lv_coord_t main_set = (row ? item->x_set : item->y_set); + if(LV_COORD_IS_FLEX(main_set) == false) { + item = ll_iter(ll, item); + continue; + } + + lv_coord_t main_size = (row ? item->w_set : item->h_set); + if(_LV_FLEX_GET_GROW(main_size) || LV_COORD_GET_FLEX(main_set) == LV_FLEX_PLACE_STRETCH) { + lv_area_t old_coords; + lv_area_copy(&old_coords, &item->coords); + + if(_LV_FLEX_GET_GROW(main_size)) { + lv_coord_t s = _LV_FLEX_GET_GROW(main_size) * t->grow_unit; + s -= get_margin_start(item, LV_OBJ_PART_MAIN) + get_margin_end(item, LV_OBJ_PART_MAIN); + area_set_main_size(&item->coords, s); + } + if(LV_COORD_GET_FLEX(main_set) == LV_FLEX_PLACE_STRETCH) { + area_set_cross_size(&item->coords, t->track_cross_size); + } + + if(lv_area_get_height(&old_coords) != area_get_main_size(&item->coords)) { + lv_obj_invalidate(item); + item->signal_cb(item, LV_SIGNAL_COORD_CHG, &old_coords); + lv_obj_invalidate(item); + } + } + + lv_coord_t cross_pos = 0; + lv_coord_t cross_set = (row ? item->y_set : item->x_set); + switch(LV_COORD_GET_FLEX(cross_set)) { + case LV_FLEX_PLACE_CENTER: + cross_pos = (t->track_cross_size - obj_get_cross_size(item)) / 2; + break; + case LV_FLEX_PLACE_END: + cross_pos = t->track_cross_size - obj_get_cross_size(item); + break; + } + + if(row && rtl) { + main_pos -= obj_get_main_size(item) + gap + place_gap; + } + + lv_coord_t diff_x = abs_x - item->coords.x1 + lv_obj_get_style_margin_left(item, LV_OBJ_PART_MAIN); + lv_coord_t diff_y = abs_y - item->coords.y1 + lv_obj_get_style_margin_top(item, LV_OBJ_PART_MAIN); + diff_x += row ? main_pos : cross_pos; + diff_y += row ? cross_pos : main_pos; + + if(diff_x || diff_y) { + item->coords.x1 += diff_x; + item->coords.x2 += diff_x; + item->coords.y1 += diff_y; + item->coords.y2 += diff_y; + _lv_obj_move_children_by(item, diff_x, diff_y); + } + + if(!(row && rtl)) { + main_pos += obj_get_main_size(item) + gap + place_gap; + } + item = ll_iter(ll, item); + } +} + +static void place_content(lv_coord_t place, lv_coord_t max_size, lv_coord_t track_size, lv_coord_t item_cnt, lv_coord_t * start_pos, lv_coord_t * gap) +{ + if(item_cnt <= 1) { + switch(place) { + case LV_FLEX_PLACE_SPACE_BETWEEN: + case LV_FLEX_PLACE_SPACE_AROUND: + case LV_FLEX_PLACE_SPACE_EVENLY: + place = LV_FLEX_PLACE_CENTER; + break; + } + } + + switch(place) { + case LV_FLEX_PLACE_CENTER: + *gap = 0; + *start_pos += (max_size - track_size) / 2; + break; + case LV_FLEX_PLACE_END: + *gap = 0; + *start_pos += max_size - track_size; + break; + case LV_FLEX_PLACE_SPACE_BETWEEN: + *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt - 1); + break; + case LV_FLEX_PLACE_SPACE_AROUND: + *gap += (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt); + *start_pos += *gap / 2; + break; + case LV_FLEX_PLACE_SPACE_EVENLY: + *gap = (lv_coord_t)(max_size - track_size) / (lv_coord_t)(item_cnt + 1); + *start_pos += *gap; + break; + default: + *gap = 0; + } +} + +static lv_flex_dir_t get_dir(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.dir; + else return false; +} + +static bool get_rev(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.rev; + else return false; +} + +static bool get_wrap(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->flex_cont.wrap; + else return false; +} diff --git a/src/lv_core/lv_flex.h b/src/lv_core/lv_flex.h new file mode 100644 index 000000000..a8c31e02f --- /dev/null +++ b/src/lv_core/lv_flex.h @@ -0,0 +1,162 @@ +/** + * @file lv_flex.h + * + */ + +#ifndef LV_FLEX_H +#define LV_FLEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/** Can be set as width or height (on main axis) to grow the object in order fill the free space*/ +#define LV_FLEX_GROW(grow) (_LV_COORD_FELX(grow)) + +#define _LV_FLEX_GET_GROW(v) (LV_COORD_IS_FLEX(v) ? LV_COORD_GET_FLEX(v) : 0) + +#define _LV_FLEX_WRAP (1 << 2) +#define _LV_FLEX_REVERSE (1 << 3) + +/********************** + * TYPEDEFS + **********************/ + +/* Can't include lv_obj.h because it includes this header file */ +struct _lv_obj_t; + +typedef enum { + LV_FLEX_PLACE_NONE, + LV_FLEX_PLACE_START, + LV_FLEX_PLACE_END, + LV_FLEX_PLACE_CENTER, + LV_FLEX_PLACE_STRETCH, + LV_FLEX_PLACE_SPACE_EVENLY, + LV_FLEX_PLACE_SPACE_AROUND, + LV_FLEX_PLACE_SPACE_BETWEEN, +}lv_flex_place_t; + +typedef enum { + LV_FLEX_DIR_NONE, + LV_FLEX_DIR_ROW = 0x01, + LV_FLEX_DIR_COLUMN = 0x02, + LV_FLEX_DIR_ROW_WRAP = LV_FLEX_DIR_ROW | _LV_FLEX_WRAP, + LV_FLEX_DIR_ROW_REVERSE = LV_FLEX_DIR_ROW | _LV_FLEX_REVERSE, + LV_FLEX_DIR_ROW_WRAP_REVERSE = LV_FLEX_DIR_ROW | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, + LV_FLEX_DIR_COLUMN_WRAP = LV_FLEX_DIR_COLUMN | _LV_FLEX_WRAP, + LV_FLEX_DIR_COLUMN_REVERSE = LV_FLEX_DIR_COLUMN | _LV_FLEX_REVERSE, + LV_FLEX_DIR_COLUMN_WRAP_REVERSE = LV_FLEX_DIR_COLUMN | _LV_FLEX_WRAP | _LV_FLEX_REVERSE, +}lv_flex_dir_t; + +typedef struct { + lv_coord_t gap; + uint8_t dir :2; + uint8_t wrap :1; + uint8_t rev :1; + uint8_t item_place :3; + uint8_t track_place :3; +}lv_flex_cont_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/*===================== + * Setter functions + *====================*/ + +/** + * Makes an object a flex container by setting the direction of the layout. + * The children explicitly needs to be made flex items with + * `lv_obj_set_flex_item()` or `lv_obj_set_flex_item_place()` + * @param obj pointer to an object + * @param flex_dir the flex direction, an element of `lv_flex_dir_t` + */ +void lv_obj_set_flex_dir(struct _lv_obj_t * obj, lv_flex_dir_t flex_dir); + +/** + * Set how to place the items and the tracks + * @param obj point to a flex container + * @param item_place tells how to distribute the free space among the items in the same track + * @param track_place tells how to distribute the free space among the tracks + * @note if the base direction is RTL and the direction is ROW, LV_FLEX_START means the right side + */ +void lv_obj_set_flex_place(struct _lv_obj_t * obj, lv_flex_place_t item_place, lv_flex_place_t track_place); + +/** + * Make an object flex item, i.e. allow setting it's coordinate according to the parent's flex settings. + * @param obj pointer to an object + */ +void lv_obj_set_flex_item(struct _lv_obj_t * obj, bool en); + +/** + * Set how the place the item in it's track in the cross direction. + * It has a visible effect only if the objects in the same track has different size in the cross direction. + * For ROW direction it means how to place the objects vertically in their row. + * For COLUMN direction it means how to place the objects horizontally in their column. + * @param obj pointer to a flex item + * @param place: + * - `LV_FLEX_PLACE_START` top/left (in case of RTL base direction right) + * - `LV_FLEX_PLACE_CENTER` center + * - `LV_FLEX_PLACE_END` bottom/right (in case of RTL base direction left) + */ +void lv_obj_set_flex_item_place(struct _lv_obj_t * obj, lv_flex_place_t place); + +/*===================== + * Getter functions + *====================*/ + +/** + * Get the flex direction of an object + * @param obj pointer to an object + * @return the flex direction of `obj` + */ +lv_flex_dir_t lv_obj_get_flex_dir(const struct _lv_obj_t * obj); + +/** + * Get the item placement of a flex container + * @param obj pointer to an object + * @return the item placement + */ +lv_flex_place_t lv_obj_get_flex_item_place(const struct _lv_obj_t * obj); + +/** + * Get the track placement of a flex container + * @param obj pointer to an object + * @return the track placement + */ +lv_flex_place_t lv_obj_get_flex_track_place(const struct _lv_obj_t * obj); + +/** + * Get how the flex item is placed in its track in the cross direction. + * For ROW direction it means how the item is placed vertically in its row. + * For COLUMN direction it means how the item is placed horizontally in its column. + * @param obj pointer to a flex item + * @return `LV_FLEX_PLACE_NONE/START/CENTER/END` + */ +lv_flex_place_t lv_obj_get_flex_self_place(struct _lv_obj_t * obj); +/** + * Rearrange the flex items of a flex container + * @param cont pointer to a flex container object + */ +void _lv_flex_refresh(struct _lv_obj_t * cont); + + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_FLEX_H*/ diff --git a/src/lv_core/lv_grid.c b/src/lv_core/lv_grid.c new file mode 100644 index 000000000..f87c9e2e8 --- /dev/null +++ b/src/lv_core/lv_grid.c @@ -0,0 +1,538 @@ +/** + * @file lv_align.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_grid.h" +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ +#define LV_OBJX_NAME "lv_obj" + +/********************** + * TYPEDEFS + **********************/ +typedef struct { + uint32_t col; + uint32_t row; + lv_point_t grid_abs; +}item_repos_hint_t; + +/********************** + * STATIC PROTOTYPES + **********************/ +static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * calc); +static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc); +static void item_repos(lv_obj_t * cont, lv_obj_t * item, _lv_grid_calc_t * calc, item_repos_hint_t * hint); +static lv_coord_t grid_place(lv_coord_t cont_size, bool auto_size, uint8_t place, lv_coord_t gap, uint32_t track_num, lv_coord_t * size_array, lv_coord_t * pos_array, bool reverse); +static void report_grid_change_core(const lv_grid_t * grid, lv_obj_t * obj); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_grid_init(lv_grid_t * grid) +{ + _lv_memset_00(grid,sizeof(lv_grid_t)); + grid->col_place = LV_GRID_START; + grid->row_place = LV_GRID_START; +} + +void lv_grid_set_template(lv_grid_t * grid, const lv_coord_t * col_dsc, uint8_t col_cnt, const lv_coord_t * row_dsc, uint8_t row_cnt) +{ + grid->col_dsc = col_dsc; + grid->col_dsc_len = col_cnt; + grid->row_dsc = row_dsc; + grid->row_dsc_len = row_cnt; +} + + +void lv_grid_set_place(lv_grid_t * grid, uint8_t col_place, uint8_t row_place) +{ + grid->col_place = col_place; + grid->row_place = row_place; +} + +void lv_grid_set_gap(lv_grid_t * grid, lv_coord_t col_gap, uint8_t row_gap) +{ + grid->col_gap = col_gap; + grid->row_gap = row_gap; + +} +/** + * Set a grid for an object + * @param obj pointer to an object + * @param grid the grid to set + */ +void lv_obj_set_grid(lv_obj_t * obj, const lv_grid_t * grid) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + obj->spec_attr->grid = grid; + + _lv_grid_full_refresh(obj); +} + +/** + * Get the grid of an object + * @param obj pointer to an object + * @return the grid, NULL if no grid + */ +const lv_grid_t * lv_obj_get_grid(lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + + if(obj->spec_attr) return obj->spec_attr->grid; + return NULL; +} + +void lv_obj_set_grid_cell(lv_obj_t * obj, lv_coord_t col_pos, lv_coord_t row_pos) +{ + lv_obj_set_pos(obj, col_pos, row_pos); +} + +/** + * Notify all object if a style is modified + * @param grid pointer to a grid. Only the objects with this grid will be notified + * (NULL to notify all objects with any grid) + */ +void lv_obj_report_grid_change(const lv_grid_t * grid) +{ + lv_disp_t * d = lv_disp_get_next(NULL); + + while(d) { + lv_obj_t * i; + _LV_LL_READ(&d->scr_ll, i) { + report_grid_change_core(grid, i); + } + d = lv_disp_get_next(d); + } +} + +/** + * Calculate the grid cells coordinates + * @param cont an object that has a grid + * @param calc store the calculated cells sizes here + * @note `_lv_grid_calc_free(calc_out)` needs to be called when `calc_out` is not needed anymore + */ +void _lv_grid_calc(struct _lv_obj_t * cont, _lv_grid_calc_t * calc_out) +{ + lv_grid_t * g = lv_obj_get_grid(cont); + if(g == NULL) return; + if(g->col_dsc == NULL || g->row_dsc == NULL) return; + if(g->col_dsc_len == 0 || g->row_dsc_len == 0) return; + + if(lv_obj_get_child(cont, NULL) == NULL) { + _lv_memset_00(calc_out, sizeof(_lv_grid_calc_t)); + return; + } +// printf("calc: %d, %d\n", obj->grid->col_dsc_len, obj->grid->row_dsc_len); + + calc_rows(cont, calc_out); + calc_cols(cont, calc_out); + + bool rev = lv_obj_get_base_dir(cont) == LV_BIDI_DIR_RTL ? true : false; + bool auto_w = cont->w_set == LV_SIZE_AUTO ? true : false; + lv_coord_t cont_w = lv_obj_get_width_fit(cont); + calc_out->grid_w = grid_place(cont_w, auto_w, g->col_place, g->col_gap, calc_out->col_num, calc_out->w, calc_out->x, rev); + + bool auto_h = cont->h_set == LV_SIZE_AUTO ? true : false; + lv_coord_t cont_h = lv_obj_get_height_fit(cont); + calc_out->grid_h = grid_place(cont_h, auto_h, g->row_place, g->row_gap, calc_out->row_num, calc_out->h, calc_out->y, false); + + LV_ASSERT_MEM_INTEGRITY(); +} + +/** + * Free the a grid calculation's data + * @param calc pointer to the calculated gtrid cell coordinates + */ +void _lv_grid_calc_free(_lv_grid_calc_t * calc) +{ + _lv_mem_buf_release(calc->x); + _lv_mem_buf_release(calc->y); + _lv_mem_buf_release(calc->w); + _lv_mem_buf_release(calc->h); +} + +/** + * Check if the object's grid columns has FR cells or not + * @param obj pointer to an object + * @return true: has FR; false: has no FR + */ +bool _lv_grid_has_fr_col(struct _lv_obj_t * obj) +{ + lv_grid_t * g = lv_obj_get_grid(obj); + if(g->col_dsc == NULL) return false; + + uint32_t i; + for(i = 0; i < g->col_dsc_len; i++) { + if(LV_GRID_IS_FR(g->col_dsc[i])) return true; + } + + return false; +} + +/** + * Check if the object's grid rows has FR cells or not + * @param obj pointer to an object + * @return true: has FR; false: has no FR + */ +bool _lv_grid_has_fr_row(struct _lv_obj_t * obj) +{ + lv_grid_t * g = lv_obj_get_grid(obj); + if(g == NULL) return false; + if(g->row_dsc == NULL) return false; + + uint32_t i; + for(i = 0; i < g->row_dsc_len; i++) { + if(LV_GRID_IS_FR(g->row_dsc[i])) return true; + } + + return false; +} + +/** + * Refresh the all grid item on a container + * @param cont pointer to a grid container object + */ +void _lv_grid_full_refresh(lv_obj_t * cont) +{ + /*Calculate the grid*/ + if(lv_obj_get_grid(cont) == NULL) return; + _lv_grid_calc_t calc; + _lv_grid_calc(cont, &calc); + + + item_repos_hint_t hint; + _lv_memset_00(&hint, sizeof(hint)); + + /* Calculate the grids absolute x and y coordinates. + * It will be used as helper during item repositioning to avoid calculating this value for every children*/ + lv_coord_t pad_left = lv_obj_get_style_pad_left(cont, LV_OBJ_PART_MAIN); + lv_coord_t pad_top = lv_obj_get_style_pad_top(cont, LV_OBJ_PART_MAIN); + hint.grid_abs.x = pad_left + cont->coords.x1 - lv_obj_get_scroll_x(cont); + hint.grid_abs.y = pad_top + cont->coords.y1 - lv_obj_get_scroll_y(cont); + + lv_obj_t * item = lv_obj_get_child_back(cont, NULL); + while(item) { + if(LV_COORD_IS_GRID(item->x_set) && LV_COORD_IS_GRID(item->y_set)) { + item_repos(cont, item, &calc, &hint); + } + item = lv_obj_get_child_back(cont, item); + } + _lv_grid_calc_free(&calc); + + if(cont->w_set == LV_SIZE_AUTO || cont->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(cont, cont->w_set, cont->h_set); + } +} + +/** + * Refresh the position of a grid item + * @param item pointer to a grid item + */ +void lv_grid_item_refr_pos(lv_obj_t * item) +{ + /*Calculate the grid*/ + lv_obj_t * cont = lv_obj_get_parent(item); + if(cont == NULL) return; + if(cont->spec_attr == NULL) return; + if(cont->spec_attr->grid == NULL) return; + _lv_grid_calc_t calc; + _lv_grid_calc(cont, &calc); + + item_repos(cont, item, &calc, NULL); + + _lv_grid_calc_free(&calc); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void calc_cols(lv_obj_t * cont, _lv_grid_calc_t * calc) +{ + const lv_grid_t * grid = cont->spec_attr->grid; + uint32_t i; + + lv_coord_t cont_w = lv_obj_get_width_fit(cont); + + calc->col_num = grid->col_dsc_len; + calc->x = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->col_num); + calc->w = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->col_num); + + uint32_t col_fr_cnt = 0; + lv_coord_t grid_w = 0; + bool auto_w = cont->w_set == LV_SIZE_AUTO ? true : false; + + for(i = 0; i < calc->col_num; i++) { + lv_coord_t x = grid->col_dsc[i]; + if(LV_GRID_IS_FR(x)) col_fr_cnt += LV_GRID_GET_FR(x); + else { + calc->w[i] = x; + grid_w += x; + } + } + + cont_w -= grid->col_gap * (calc->col_num - 1); + lv_coord_t free_w = cont_w - grid_w; + + for(i = 0; i < calc->col_num; i++) { + lv_coord_t x = grid->col_dsc[i]; + if(LV_GRID_IS_FR(x)) { + if(auto_w) calc->w[i] = 0; /*Fr is considered zero if the cont has auto width*/ + else { + lv_coord_t f = LV_GRID_GET_FR(x); + calc->w[i] = (free_w * f) / col_fr_cnt; + } + } + } +} + +static void calc_rows(lv_obj_t * cont, _lv_grid_calc_t * calc) +{ + const lv_grid_t * grid = cont->spec_attr->grid; + uint32_t i; + + calc->row_num = grid->row_dsc_len; + calc->y = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->row_num); + calc->h = _lv_mem_buf_get(sizeof(lv_coord_t) * calc->row_num); + + uint32_t row_fr_cnt = 0; + lv_coord_t grid_h = 0; + + bool auto_h = cont->h_set == LV_SIZE_AUTO ? true : false; + + + for(i = 0; i < grid->row_dsc_len; i++) { + lv_coord_t x = grid->row_dsc[i]; + if(LV_GRID_IS_FR(x)) row_fr_cnt += LV_GRID_GET_FR(x); + else { + calc->h[i] = x; + grid_h += x; + } + } + + lv_coord_t cont_h = lv_obj_get_height_fit(cont) - grid->row_gap * (grid->row_dsc_len - 1); + lv_coord_t free_h = cont_h - grid_h; + + for(i = 0; i < grid->row_dsc_len; i++) { + lv_coord_t x = grid->row_dsc[i]; + if(LV_GRID_IS_FR(x)) { + if(auto_h) calc->h[i] = 0; /*Fr is considered zero if the obj has auto height*/ + else { + lv_coord_t f = LV_GRID_GET_FR(x); + calc->h[i] = (free_h * f) / row_fr_cnt; + } + } + } +} + +/** + * Reposition a grid item in its cell + * @param cont a grid container object + * @param item a grid item to reposition + * @param calc the calculated grid of `cont` + * @param child_id_ext helper value if the ID of the child is know (order from the oldest) else -1 + * @param grid_abs helper value, the absolute position of the grid, NULL if unknown + */ +static void item_repos(lv_obj_t * cont, lv_obj_t * item, _lv_grid_calc_t * calc, item_repos_hint_t * hint) +{ + if(_lv_obj_is_grid_item(item) == false) return; + + uint32_t col_pos = LV_GRID_GET_CELL_POS(item->x_set); + uint32_t col_span = LV_GRID_GET_CELL_SPAN(item->x_set); + uint32_t row_pos = LV_GRID_GET_CELL_POS(item->y_set); + uint32_t row_span = LV_GRID_GET_CELL_SPAN(item->y_set); + + lv_coord_t col_x1 = calc->x[col_pos]; + lv_coord_t col_x2 = calc->x[col_pos + col_span - 1] + calc->w[col_pos + col_span - 1]; + lv_coord_t col_w = col_x2 - col_x1; + + lv_coord_t row_y1 = calc->y[row_pos]; + lv_coord_t row_y2 = calc->y[row_pos + row_span - 1] + calc->h[row_pos + row_span - 1]; + lv_coord_t row_h = row_y2 - row_y1; + + uint8_t x_flag = LV_GRID_GET_CELL_PLACE(item->x_set); + uint8_t y_flag = LV_GRID_GET_CELL_PLACE(item->y_set); + + /*If the item has RTL base dir switch start and end*/ + if(lv_obj_get_base_dir(item) == LV_BIDI_DIR_RTL) { + if(x_flag == LV_GRID_START) x_flag = LV_GRID_END; + else if(x_flag == LV_GRID_END) x_flag = LV_GRID_START; + } + + lv_coord_t x; + lv_coord_t y; + lv_coord_t item_w = lv_obj_get_width(item); + lv_coord_t item_h = lv_obj_get_height(item); + + lv_coord_t margin_top = lv_obj_get_style_margin_top(item, LV_OBJ_PART_MAIN); + lv_coord_t margin_bottom = lv_obj_get_style_margin_bottom(item, LV_OBJ_PART_MAIN); + lv_coord_t margin_left = lv_obj_get_style_margin_left(item, LV_OBJ_PART_MAIN); + lv_coord_t margin_right = lv_obj_get_style_margin_right(item, LV_OBJ_PART_MAIN); + + switch(x_flag) { + case LV_GRID_START: + x = calc->x[col_pos] + margin_left; + break; + case LV_GRID_STRETCH: + x = calc->x[col_pos] + margin_left; + item_w = col_w - margin_left - margin_right; + item->w_set = LV_SIZE_STRETCH; + break; + case LV_GRID_CENTER: + x = calc->x[col_pos] + (col_w - (item_w + margin_left - margin_right)) / 2; + break; + case LV_GRID_END: + x = calc->x[col_pos] + col_w - lv_obj_get_width(item) - margin_right; + break; + } + + switch(y_flag) { + case LV_GRID_START: + y = calc->y[row_pos] + margin_top; + break; + case LV_GRID_STRETCH: + y = calc->y[row_pos] + margin_top; + item_h = row_h - margin_top - margin_bottom; + item->h_set = LV_SIZE_STRETCH; + break; + case LV_GRID_CENTER: + y = calc->y[row_pos] + (row_h - (item_h + margin_top + margin_bottom)) / 2; + break; + case LV_GRID_END: + y = calc->y[row_pos] + row_h - lv_obj_get_height(item) - margin_bottom; + break; + } + + /*Set a new size if required*/ + if(lv_obj_get_width(item) != item_w || lv_obj_get_height(item) != item_h) { + lv_area_t old_coords; + lv_area_copy(&old_coords, &item->coords); + lv_obj_invalidate(item); + lv_area_set_width(&item->coords, item_w); + lv_area_set_height(&item->coords, item_h); + lv_obj_invalidate(item); + item->signal_cb(item, LV_SIGNAL_COORD_CHG, &old_coords); + + } + bool moved = true; + if(hint) { + if(hint->grid_abs.x + x == item->coords.x1 && hint->grid_abs.y + y == item->coords.y1) moved = false; + } + + if(moved) _lv_obj_move_to(item, x, y, false); +} + +/** + * Place the grid track according to place methods. It keeps the track sizes but sets their position. + * It can process both columns or rows according to the passed parameters. + * @param cont_size size of the containers content area (width/height) + * @param auto_size true: the container has auto size in the current direction + * @param place placeing method + * @param gap grid gap + * @param track_num number of tracks + * @param size_array array with the track sizes + * @param pos_array write the positions of the tracks here + * @return the total size of the grid + */ +static lv_coord_t grid_place(lv_coord_t cont_size, bool auto_size, uint8_t place, lv_coord_t gap, uint32_t track_num, lv_coord_t * size_array, lv_coord_t * pos_array, bool reverse) +{ + lv_coord_t grid_size = 0; + int32_t i; + + if(auto_size) { + pos_array[0] = 0; + } else { + /*With spaced placements gap will be calculated from the remaining space*/ + if(place == LV_GRID_SPACE_AROUND || place == LV_GRID_SPACE_BETWEEN || place == LV_GRID_SPACE_EVENLY) { + gap = 0; + if(track_num == 1) place = LV_GRID_CENTER; + } + + /*Get the full grid size with gap*/ + for(i = 0; i < track_num; i++) { + grid_size += size_array[i] + gap; + } + grid_size -= gap; + + /*Calculate the position of the first item and set gap is necessary*/ + switch(place) { + case LV_GRID_START: + pos_array[0] = 0; + break; + case LV_GRID_CENTER: + pos_array[0] = (cont_size - grid_size) / 2; + break; + case LV_GRID_END: + pos_array[0] = cont_size - grid_size; + break; + case LV_GRID_SPACE_BETWEEN: + pos_array[0] = 0; + gap = (lv_coord_t)(cont_size - grid_size) / (lv_coord_t)(track_num - 1); + break; + case LV_GRID_SPACE_AROUND: + gap = (lv_coord_t)(cont_size - grid_size) / (lv_coord_t)(track_num); + pos_array[0] = gap / 2; + break; + case LV_GRID_SPACE_EVENLY: + gap = (lv_coord_t)(cont_size - grid_size) / (lv_coord_t)(track_num + 1); + pos_array[0] = gap; + break; + + } + } + + /*Set the position of all tracks from the start position, gaps and track sizes*/ + for(i = 0; i < track_num - 1; i++) { + pos_array[i + 1] = pos_array[i] + size_array[i] + gap; + } + + lv_coord_t total_gird_size = pos_array[track_num - 1] + size_array[track_num - 1] - pos_array[0]; + + if(reverse) { + for(i = 0; i < track_num; i++) { + pos_array[i] = cont_size - pos_array[i] - size_array[i]; + } + + } + + /*Return the full size of the grid*/ + return total_gird_size; +} + + +/** + * Refresh the grid of all children of an object. (Called recursively) + * @param grid refresh objects only with this grid. + * @param obj pointer to an object + */ +static void report_grid_change_core(const lv_grid_t * grid, lv_obj_t * obj) +{ + if(obj->spec_attr) { + if(obj->spec_attr->grid == grid || (obj->spec_attr->grid && grid == NULL)) _lv_grid_full_refresh(obj); + } + + lv_obj_t * child = lv_obj_get_child(obj, NULL); + while(child) { + report_grid_change_core(grid, child); + child = lv_obj_get_child(obj, child); + } + +} diff --git a/src/lv_core/lv_grid.h b/src/lv_core/lv_grid.h new file mode 100644 index 000000000..3de13459c --- /dev/null +++ b/src/lv_core/lv_grid.h @@ -0,0 +1,143 @@ +/** + * @file lv_grid.h + * + */ + +#ifndef LV_GRID_H +#define LV_GRID_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_misc/lv_area.h" + +/********************* + * DEFINES + *********************/ + +/** + * Some helper defines + * */ +#define _LV_GRID_CELL_SHIFT 4 +#define _LV_GRID_CELL_POS_MASK ((1 << _LV_GRID_CELL_SHIFT) - 1) +#define _LV_GRID_CELL_SPAN_MASK (_LV_GRID_CELL_POS_MASK << _LV_GRID_CELL_SHIFT) +#define _LV_GRID_CELL_FLAG_MASK (_LV_GRID_CELL_POS_MASK << (2 * _LV_GRID_CELL_SHIFT)) +#define _LV_GRID_CELL_PLACE(b) ((b) << (_LV_GRID_CELL_SHIFT * 2)) + +#define LV_GRID_START 0 +#define LV_GRID_CENTER 1 +#define LV_GRID_END 2 +#define LV_GRID_STRETCH 3 +#define LV_GRID_SPACE_EVENLY 4 +#define LV_GRID_SPACE_AROUND 5 +#define LV_GRID_SPACE_BETWEEN 6 + +#define LV_GRID_CELL_START(pos, span) (_LV_COORD_GRID((pos) | ((span) << (_LV_GRID_CELL_SHIFT)) | _LV_GRID_CELL_PLACE(LV_GRID_START))) +#define LV_GRID_CELL_END(pos, span) (_LV_COORD_GRID((pos) | ((span) << (_LV_GRID_CELL_SHIFT)) | _LV_GRID_CELL_PLACE(LV_GRID_END))) +#define LV_GRID_CELL_CENTER(pos, span) (_LV_COORD_GRID((pos) | ((span) << (_LV_GRID_CELL_SHIFT)) | _LV_GRID_CELL_PLACE(LV_GRID_CENTER))) +#define LV_GRID_CELL_STRETCH(pos, span) (_LV_COORD_GRID((pos) | ((span) << (_LV_GRID_CELL_SHIFT)) | _LV_GRID_CELL_PLACE(LV_GRID_STRETCH))) + +#define LV_GRID_GET_CELL_POS(c) ((c) & _LV_GRID_CELL_POS_MASK) +#define LV_GRID_GET_CELL_SPAN(c) (((c) & _LV_GRID_CELL_SPAN_MASK) >> _LV_GRID_CELL_SHIFT) +#define LV_GRID_GET_CELL_PLACE(c) ((c) >> (_LV_GRID_CELL_SHIFT * 2) & 0x7) + +#define LV_GRID_FR(x) (_LV_COORD_GRID(x)) +#define LV_GRID_IS_FR(x) (LV_COORD_IS_GRID(x)) +#define LV_GRID_GET_FR(x) (LV_COORD_GET_GRID(x)) + +/********************** + * TYPEDEFS + **********************/ + +/* Can't include lv_obj.h because it includes this header file */ +struct _lv_obj_t; +typedef struct _lv_obj_t lv_obj_t; + +typedef struct { + const lv_coord_t * col_dsc; + const lv_coord_t * row_dsc; + uint8_t col_dsc_len; + uint8_t row_dsc_len; + lv_coord_t col_gap; + lv_coord_t row_gap; + uint8_t col_place; + uint8_t row_place; +}lv_grid_t; + +typedef struct { + lv_coord_t * x; + lv_coord_t * y; + lv_coord_t * w; + lv_coord_t * h; + uint32_t col_num; + uint32_t row_num; + lv_coord_t grid_w; + lv_coord_t grid_h; +}_lv_grid_calc_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +void lv_grid_init(lv_grid_t * grid); + +void lv_grid_set_template(lv_grid_t * grid, const lv_coord_t * col_dsc, uint8_t col_cnt, const lv_coord_t * row_dsc, uint8_t row_cnt); + +void lv_grid_set_place(lv_grid_t * grid, uint8_t col_place, uint8_t row_place); + +void lv_grid_set_gap(lv_grid_t * grid, lv_coord_t col_gap, uint8_t row_gap); + +/** + * Set a grid for an object + * @param obj pointer to an object + * @param grid the grid to set + */ +void lv_obj_set_grid(lv_obj_t * obj, const lv_grid_t * grid); + +/** + * Get the grid of an object + * @param obj pointer to an object + * @return the grid, NULL if no grid + */ +const lv_grid_t * lv_obj_get_grid(lv_obj_t * obj); + +void lv_obj_set_grid_cell(lv_obj_t * obj, lv_coord_t col_pos, lv_coord_t row_pos); + +/** + * Notify all object if a style is modified + * @param grid pointer to a grid. Only the objects with this grid will be notified + * (NULL to notify all objects with any grid) + */ +void lv_obj_report_grid_change(const lv_grid_t * grid); + +void _lv_grid_calc(struct _lv_obj_t * obj, _lv_grid_calc_t * calc); + +void _lv_grid_calc_free(_lv_grid_calc_t * calc); + +bool _lv_grid_has_fr_col(struct _lv_obj_t * obj); + +bool _lv_grid_has_fr_row(struct _lv_obj_t * obj); + + +void _lv_grid_full_refresh(lv_obj_t * cont); + +void lv_grid_item_refr_pos(lv_obj_t * item); + + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GRID_H*/ diff --git a/src/lv_core/lv_group.c b/src/lv_core/lv_group.c index 9f2f554dc..b3468528b 100644 --- a/src/lv_core/lv_group.c +++ b/src/lv_core/lv_group.c @@ -31,7 +31,6 @@ static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *), void * (*move)(const lv_ll_t *, const void *)); static void lv_group_refocus(lv_group_t * g); -static void obj_to_foreground(lv_obj_t * obj); /********************** * STATIC VARIABLES @@ -93,8 +92,8 @@ void lv_group_del(lv_group_t * group) /*Remove the objects from the group*/ lv_obj_t ** obj; - _LV_LL_READ(group->obj_ll, obj) { - (*obj)->group_p = NULL; + _LV_LL_READ(&group->obj_ll, obj) { + if((*obj)->spec_attr) (*obj)->spec_attr->group_p = NULL; } _lv_ll_clear(&(group->obj_ll)); @@ -112,7 +111,7 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) if(group == NULL) return; /*Do not add the object twice*/ lv_obj_t ** obj_i; - _LV_LL_READ(group->obj_ll, obj_i) { + _LV_LL_READ(&group->obj_ll, obj_i) { if((*obj_i) == obj) { LV_LOG_INFO("lv_group_add_obj: the object is already added to this group"); return; @@ -120,15 +119,18 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) } /*If the object is already in a group and focused then defocus it*/ - if(obj->group_p) { + lv_group_t * group_cur = lv_obj_get_group(obj); + if(group_cur) { if(lv_obj_is_focused(obj)) { - lv_group_refocus(obj->group_p); + lv_group_refocus(group_cur); LV_LOG_INFO("lv_group_add_obj: assign object to an other group"); } } - obj->group_p = group; + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + obj->spec_attr->group_p = group; + lv_obj_t ** next = _lv_ll_ins_tail(&group->obj_ll); LV_ASSERT_MEM(next); if(next == NULL) return; @@ -147,7 +149,7 @@ void lv_group_add_obj(lv_group_t * group, lv_obj_t * obj) */ void lv_group_remove_obj(lv_obj_t * obj) { - lv_group_t * g = obj->group_p; + lv_group_t * g = lv_obj_get_group(obj); if(g == NULL) return; /*Focus on the next object*/ @@ -173,11 +175,11 @@ void lv_group_remove_obj(lv_obj_t * obj) /*Search the object and remove it from its group */ lv_obj_t ** i; - _LV_LL_READ(g->obj_ll, i) { + _LV_LL_READ(&g->obj_ll, i) { if(*i == obj) { _lv_ll_remove(&g->obj_ll, i); lv_mem_free(i); - obj->group_p = NULL; + if(obj->spec_attr) obj->spec_attr->group_p = NULL; break; } } @@ -198,8 +200,8 @@ void lv_group_remove_all_objs(lv_group_t * group) /*Remove the objects from the group*/ lv_obj_t ** obj; - _LV_LL_READ(group->obj_ll, obj) { - (*obj)->group_p = NULL; + _LV_LL_READ(&group->obj_ll, obj) { + if((*obj)->spec_attr) (*obj)->spec_attr->group_p = NULL; } _lv_ll_clear(&(group->obj_ll)); @@ -212,7 +214,7 @@ void lv_group_remove_all_objs(lv_group_t * group) void lv_group_focus_obj(lv_obj_t * obj) { if(obj == NULL) return; - lv_group_t * g = obj->group_p; + lv_group_t * g = lv_obj_get_group(obj); if(g == NULL) return; if(g->frozen != 0) return; @@ -223,7 +225,7 @@ void lv_group_focus_obj(lv_obj_t * obj) lv_group_set_editing(g, false); lv_obj_t ** i; - _LV_LL_READ(g->obj_ll, i) { + _LV_LL_READ(&g->obj_ll, i) { if(*i == obj) { if(g->obj_focus != NULL) { (*g->obj_focus)->signal_cb(*g->obj_focus, LV_SIGNAL_DEFOCUS, NULL); @@ -240,9 +242,6 @@ void lv_group_focus_obj(lv_obj_t * obj) lv_res_t res = lv_event_send(*g->obj_focus, LV_EVENT_FOCUSED, NULL); if(res != LV_RES_OK) return; lv_obj_invalidate(*g->obj_focus); - - /*If the object or its parent has `top == true` bring it to the foreground*/ - obj_to_foreground(*g->obj_focus); } break; } @@ -487,10 +486,10 @@ static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *) can_move = true; if(obj_next == NULL) continue; - if(lv_obj_get_state(*obj_next, LV_OBJ_PART_MAIN) & LV_STATE_DISABLED) continue; + if(lv_obj_get_state(*obj_next) & LV_STATE_DISABLED) continue; - /*Hidden and disabled objects don't receive focus*/ - if(!lv_obj_get_hidden(*obj_next)) break; + /*Hidden objects don't receive focus*/ + if(lv_obj_has_flag(*obj_next, LV_OBJ_FLAG_HIDDEN) == false) break; } if(obj_next == group->obj_focus) return; /*There's only one visible object and it's already focused*/ @@ -508,28 +507,10 @@ static void focus_next_core(lv_group_t * group, void * (*begin)(const lv_ll_t *) lv_res_t res = lv_event_send(*group->obj_focus, LV_EVENT_FOCUSED, NULL); if(res != LV_RES_OK) return; - /*If the object or its parent has `top == true` bring it to the foreground*/ - obj_to_foreground(*group->obj_focus); - lv_obj_invalidate(*group->obj_focus); if(group->focus_cb) group->focus_cb(group); } -static void obj_to_foreground(lv_obj_t * obj) -{ - /*Search for 'top' attribute*/ - lv_obj_t * i = obj; - lv_obj_t * last_top = NULL; - while(i != NULL) { - if(i->top != 0) last_top = i; - i = lv_obj_get_parent(i); - } - - if(last_top != NULL) { - /*Move the last_top object to the foreground*/ - lv_obj_move_foreground(last_top); - } -} #endif /*LV_USE_GROUP != 0*/ diff --git a/src/lv_core/lv_indev.c b/src/lv_core/lv_indev.c index 16aa34529..6be36ad7d 100644 --- a/src/lv_core/lv_indev.c +++ b/src/lv_core/lv_indev.c @@ -9,10 +9,11 @@ #include "lv_indev.h" #include "lv_disp.h" #include "lv_obj.h" +#include "lv_indev_scroll.h" +#include "lv_group.h" +#include "lv_refr.h" #include "../lv_hal/lv_hal_tick.h" -#include "../lv_core/lv_group.h" -#include "../lv_core/lv_refr.h" #include "../lv_misc/lv_task.h" #include "../lv_misc/lv_math.h" @@ -40,9 +41,6 @@ static void indev_proc_press(lv_indev_proc_t * proc); static void indev_proc_release(lv_indev_proc_t * proc); static void indev_proc_reset_query_handler(lv_indev_t * indev); static void indev_click_focus(lv_indev_proc_t * proc); -static void indev_drag(lv_indev_proc_t * proc); -static void indev_drag_throw(lv_indev_proc_t * proc); -static lv_obj_t * get_dragged_obj(lv_obj_t * obj); static void indev_gesture(lv_indev_proc_t * proc); static bool indev_reset_check(lv_indev_proc_t * proc); @@ -213,7 +211,7 @@ void lv_indev_set_cursor(lv_indev_t * indev, lv_obj_t * cur_obj) indev->cursor = cur_obj; lv_obj_set_parent(indev->cursor, lv_disp_get_layer_sys(indev->driver.disp)); lv_obj_set_pos(indev->cursor, indev->proc.types.pointer.act_point.x, indev->proc.types.pointer.act_point.y); - lv_obj_set_click(indev->cursor, false); + lv_obj_clear_flag(indev->cursor, LV_OBJ_FLAG_CLICKABLE); } #if LV_USE_GROUP @@ -289,20 +287,33 @@ uint32_t lv_indev_get_key(const lv_indev_t * indev) } /** - * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and + * Check the current scroll direction of an input device (for LV_INDEV_TYPE_POINTER and * LV_INDEV_TYPE_BUTTON) * @param indev pointer to an input device - * @return true: drag is in progress + * @return LV_SCROLL_DIR_NONE: no scrolling now + * LV_SCROLL_DIR_HOR/VER */ -bool lv_indev_is_dragging(const lv_indev_t * indev) +lv_scroll_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev) { if(indev == NULL) return false; if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return false; - return indev->proc.types.pointer.drag_in_prog == 0 ? false : true; + return indev->proc.types.pointer.scroll_dir; +} +/** + * Get the currently scrolled object (for LV_INDEV_TYPE_POINTER and + * LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @return pointer to the currently scrolled object or NULL if no scrolling by this indev + */ +lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev) +{ + if(indev == NULL) return NULL; + if(indev->driver.type != LV_INDEV_TYPE_POINTER && indev->driver.type != LV_INDEV_TYPE_BUTTON) return NULL; + return indev->proc.types.pointer.scroll_obj; } /** - * Get the types.pointer.vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and + * Get the movement vector of an input device (for LV_INDEV_TYPE_POINTER and * LV_INDEV_TYPE_BUTTON) * @param indev pointer to an input device * @param point pointer to a point to store the types.pointer.vector @@ -325,36 +336,6 @@ void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point) } } -/** - * Manually finish dragging. - * `LV_SIGNAL_DRAG_END` and `LV_EVENT_DRAG_END` will be sent. - * @param indev pointer to an input device - * @return `LV_RES_INV` if the object being dragged was deleted. Else `LV_RES_OK`. - */ -lv_res_t lv_indev_finish_drag(lv_indev_t * indev) -{ - if(indev == NULL) return LV_RES_OK; - if(indev->driver.type != LV_INDEV_TYPE_POINTER) return LV_RES_OK; - if(indev->proc.types.pointer.drag_in_prog == 0) return LV_RES_OK; - - indev->proc.types.pointer.drag_in_prog = 0; - indev->proc.types.pointer.drag_throw_vect.x = 0; - indev->proc.types.pointer.drag_throw_vect.y = 0; - - lv_obj_t * drag_obj; - drag_obj = get_dragged_obj(indev->proc.types.pointer.act_obj); - if(drag_obj == NULL) return LV_RES_OK; - - lv_res_t res; - res = drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, NULL); - if(res != LV_RES_OK) return res; - - res = lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL); - if(res != LV_RES_OK) return res; - - return res; -} - /** * Do nothing until the next release * @param indev pointer to an input device @@ -847,9 +828,9 @@ static void indev_proc_press(lv_indev_proc_t * proc) &proc->types.pointer.act_point); new_obj_searched = true; } - /*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(indev_obj_act, LV_PROTECT_PRESS_LOST) == false) { + /*If there is last object but it is not scrolled and not protected also search*/ + else if(proc->types.pointer.scroll_obj == NULL && + lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_PRESS_LOCK) == false) { indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_sys(disp), &proc->types.pointer.act_point); if(indev_obj_act == NULL) indev_obj_act = lv_indev_search_obj(lv_disp_get_layer_top(disp), &proc->types.pointer.act_point); @@ -857,19 +838,17 @@ static void indev_proc_press(lv_indev_proc_t * proc) &proc->types.pointer.act_point); new_obj_searched = true; } - /*If a draggable or a protected object was the last then keep it*/ - else { - } - /*The last object might have drag throw. Stop it manually*/ + /*The last object might have scroll throw. Stop it manually*/ if(new_obj_searched && proc->types.pointer.last_obj) { - proc->types.pointer.drag_throw_vect.x = 0; - proc->types.pointer.drag_throw_vect.y = 0; - indev_drag_throw(proc); + proc->types.pointer.scroll_throw_vect.x = 0; + proc->types.pointer.scroll_throw_vect.y = 0; + _lv_scroll_throw_handler(proc); + if(indev_reset_check(proc)) return; } /*Do not use disabled objects*/ - if(indev_obj_act && (lv_obj_get_state(indev_obj_act, LV_OBJ_PART_MAIN) & LV_STATE_DISABLED)) { + if(indev_obj_act && (lv_obj_get_state(indev_obj_act) & LV_STATE_DISABLED)) { indev_obj_act = proc->types.pointer.act_obj; } @@ -883,11 +862,10 @@ static void indev_proc_press(lv_indev_proc_t * proc) /*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); + lv_signal_send(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 = indev_obj_act; /*Save the pressed object*/ @@ -897,32 +875,17 @@ static void indev_proc_press(lv_indev_proc_t * proc) /* Save the time when the obj pressed to count long press time.*/ proc->pr_timestamp = lv_tick_get(); proc->long_pr_sent = 0; - proc->types.pointer.drag_limit_out = 0; - proc->types.pointer.drag_in_prog = 0; - proc->types.pointer.drag_sum.x = 0; - proc->types.pointer.drag_sum.y = 0; - proc->types.pointer.drag_dir = LV_DRAG_DIR_BOTH; + proc->types.pointer.scroll_sum.x = 0; + proc->types.pointer.scroll_sum.y = 0; + proc->types.pointer.scroll_dir = LV_SCROLL_DIR_NONE; proc->types.pointer.gesture_sent = 0; proc->types.pointer.gesture_sum.x = 0; proc->types.pointer.gesture_sum.y = 0; proc->types.pointer.vect.x = 0; proc->types.pointer.vect.y = 0; - /*Search for 'top' attribute*/ - lv_obj_t * i = indev_obj_act; - lv_obj_t * last_top = NULL; - while(i != NULL) { - 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_move_foreground(last_top); - } - /*Send a signal about the press*/ - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSED, indev_act); + lv_signal_send(indev_obj_act, LV_SIGNAL_PRESSED, indev_act); if(indev_reset_check(proc)) return; lv_event_send(indev_obj_act, LV_EVENT_PRESSED, NULL); @@ -937,43 +900,36 @@ static void indev_proc_press(lv_indev_proc_t * proc) } } - /*Calculate the types.pointer.vector*/ + /*Calculate the vector and apply a low pass filter: new value = 0.5 * old_value + 0.5 * new_value*/ proc->types.pointer.vect.x = proc->types.pointer.act_point.x - proc->types.pointer.last_point.x; proc->types.pointer.vect.y = proc->types.pointer.act_point.y - proc->types.pointer.last_point.y; - proc->types.pointer.drag_throw_vect.x = (proc->types.pointer.drag_throw_vect.x * 5) >> 3; - proc->types.pointer.drag_throw_vect.y = (proc->types.pointer.drag_throw_vect.y * 5) >> 3; + proc->types.pointer.scroll_throw_vect.x = (proc->types.pointer.scroll_throw_vect.x * 4) >> 3; + proc->types.pointer.scroll_throw_vect.y = (proc->types.pointer.scroll_throw_vect.y * 4) >> 3; - if(proc->types.pointer.drag_throw_vect.x < 0) - proc->types.pointer.drag_throw_vect.x++; - else if(proc->types.pointer.drag_throw_vect.x > 0) - proc->types.pointer.drag_throw_vect.x--; + proc->types.pointer.scroll_throw_vect.x += (proc->types.pointer.vect.x * 4) >> 3; + proc->types.pointer.scroll_throw_vect.y += (proc->types.pointer.vect.y * 4) >> 3; - if(proc->types.pointer.drag_throw_vect.y < 0) - proc->types.pointer.drag_throw_vect.y++; - else if(proc->types.pointer.drag_throw_vect.y > 0) - proc->types.pointer.drag_throw_vect.y--; + proc->types.pointer.scroll_throw_vect_ori = proc->types.pointer.scroll_throw_vect; - proc->types.pointer.drag_throw_vect.x += (proc->types.pointer.vect.x * 4) >> 3; - 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(indev_obj_act != NULL) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_PRESSING, indev_act); + if(indev_obj_act) { + lv_signal_send(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; + if(indev_act->proc.wait_until_release) return; - indev_drag(proc); + _lv_scroll_handler(proc); + if(indev_reset_check(proc)) return; indev_gesture(proc); 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) { + /*If there is no scrolling then check for long press time*/ + if(proc->types.pointer.scroll_obj == NULL && 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) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS, indev_act); + lv_signal_send(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; @@ -985,11 +941,12 @@ static void indev_proc_press(lv_indev_proc_t * proc) proc->longpr_rep_timestamp = lv_tick_get(); } } + /*Send long press repeated signal*/ - if(proc->types.pointer.drag_in_prog == 0 && proc->long_pr_sent == 1) { + if(proc->types.pointer.scroll_obj == NULL && proc->long_pr_sent == 1) { /*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) { - indev_obj_act->signal_cb(indev_obj_act, LV_SIGNAL_LONG_PRESS_REP, indev_act); + lv_signal_send(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; @@ -1013,73 +970,39 @@ static void indev_proc_release(lv_indev_proc_t * proc) proc->wait_until_release = 0; } indev_obj_act = proc->types.pointer.act_obj; + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; /*Forget the act obj and send a released signal */ 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(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(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); - if(indev_reset_check(proc)) return; - } - - lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); - if(indev_reset_check(proc)) return; - } - - 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 `indev_proc_press` would set `indev_obj_act = NULL`*/ - else { - 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) { + /*Send CLICK if no scrolling*/ + if(scroll_obj == NULL) { + if(proc->long_pr_sent == 0) { lv_event_send(indev_obj_act, LV_EVENT_SHORT_CLICKED, NULL); if(indev_reset_check(proc)) return; } - if(proc->types.pointer.drag_in_prog == 0) { - lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); - if(indev_reset_check(proc)) return; - } - - lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); + lv_event_send(indev_obj_act, LV_EVENT_CLICKED, NULL); if(indev_reset_check(proc)) return; } - /*Send LV_EVENT_DRAG_THROW_BEGIN if required */ - /*If drag parent is active check recursively the drag_parent attribute*/ - lv_obj_t * drag_obj = get_dragged_obj(indev_obj_act); - if(drag_obj) { - if(lv_obj_get_drag_throw(drag_obj) && proc->types.pointer.drag_in_prog) { - if(drag_obj->signal_cb) drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_THROW_BEGIN, NULL); - if(indev_reset_check(proc)) return; + /*Send RELEASE signal and event*/ + lv_signal_send(indev_obj_act, LV_SIGNAL_RELEASED, indev_act); + if(indev_reset_check(proc)) return; - lv_event_send(drag_obj, LV_EVENT_DRAG_THROW_BEGIN, NULL); - if(indev_reset_check(proc)) return; - } - } + lv_event_send(indev_obj_act, LV_EVENT_RELEASED, NULL); + if(indev_reset_check(proc)) return; proc->types.pointer.act_obj = NULL; proc->pr_timestamp = 0; proc->longpr_rep_timestamp = 0; + } /*The reset can be set in the signal function. * 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(scroll_obj) { + _lv_scroll_throw_handler(proc); if(indev_reset_check(proc)) return; } } @@ -1096,16 +1019,15 @@ static void indev_proc_reset_query_handler(lv_indev_t * indev) if(indev->proc.reset_query) { indev->proc.types.pointer.act_obj = NULL; indev->proc.types.pointer.last_obj = NULL; - indev->proc.types.pointer.drag_limit_out = 0; - indev->proc.types.pointer.drag_in_prog = 0; + indev->proc.types.pointer.scroll_obj = NULL; indev->proc.long_pr_sent = 0; indev->proc.pr_timestamp = 0; indev->proc.longpr_rep_timestamp = 0; - indev->proc.types.pointer.drag_sum.x = 0; - indev->proc.types.pointer.drag_sum.y = 0; - indev->proc.types.pointer.drag_dir = LV_DRAG_DIR_BOTH; - indev->proc.types.pointer.drag_throw_vect.x = 0; - indev->proc.types.pointer.drag_throw_vect.y = 0; + indev->proc.types.pointer.scroll_sum.x = 0; + indev->proc.types.pointer.scroll_sum.y = 0; + indev->proc.types.pointer.scroll_dir = LV_SCROLL_DIR_NONE; + indev->proc.types.pointer.scroll_throw_vect.x = 0; + indev->proc.types.pointer.scroll_throw_vect.y = 0; indev->proc.types.pointer.gesture_sum.x = 0; indev->proc.types.pointer.gesture_sum.y = 0; indev->proc.reset_query = 0; @@ -1123,10 +1045,11 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point) lv_obj_t * found_p = NULL; /*If the point is on this object check its children too*/ - if(lv_obj_hittest(obj, point)) { + if(lv_obj_hit_test(obj, point)) { lv_obj_t * i; - _LV_LL_READ(obj->child_ll, i) { + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ(ll, i) { found_p = lv_indev_search_obj(i, point); /*If a child was found then break*/ @@ -1137,10 +1060,10 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point) /*If then the children was not ok, and this obj is clickable * and it or its parent is not hidden then save this object*/ - if(found_p == NULL && lv_obj_get_click(obj) != false) { + if(found_p == NULL && lv_obj_has_flag(obj, LV_OBJ_FLAG_CLICKABLE)) { lv_obj_t * hidden_i = obj; while(hidden_i != NULL) { - if(lv_obj_get_hidden(hidden_i) == true) break; + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN) == true) break; hidden_i = lv_obj_get_parent(hidden_i); } /*No parent found with hidden == true*/ @@ -1158,8 +1081,8 @@ 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 && + lv_obj_t * obj_to_focus = _lv_obj_get_focused_obj(indev_obj_act); + if(lv_obj_has_flag(indev_obj_act, LV_OBJ_FLAG_CLICK_FOCUSABLE) && proc->types.pointer.last_pressed != obj_to_focus) { #if LV_USE_GROUP lv_group_t * g_act = lv_obj_get_group(obj_to_focus); @@ -1246,256 +1169,21 @@ static void indev_click_focus(lv_indev_proc_t * proc) } -/** - * Handle the dragging of indev_proc_p->types.pointer.act_obj - * @param indev pointer to a input device state - */ -static void indev_drag(lv_indev_proc_t * proc) -{ - lv_obj_t * drag_obj = get_dragged_obj(proc->types.pointer.act_obj); - bool drag_just_started = false; - - if(drag_obj == NULL) return; - - if(lv_obj_get_drag(drag_obj) == false) return; - - - lv_drag_dir_t allowed_dirs = lv_obj_get_drag_dir(drag_obj); - - /*Count the movement by drag*/ - if(proc->types.pointer.drag_limit_out == 0) { - proc->types.pointer.drag_sum.x += proc->types.pointer.vect.x; - proc->types.pointer.drag_sum.y += proc->types.pointer.vect.y; - - /*Enough move?*/ - bool hor_en = false; - bool ver_en = false; - if(allowed_dirs == LV_DRAG_DIR_HOR || allowed_dirs == LV_DRAG_DIR_BOTH) { - hor_en = true; - } - - if(allowed_dirs == LV_DRAG_DIR_VER || allowed_dirs == LV_DRAG_DIR_BOTH) { - ver_en = true; - } - - if(allowed_dirs == LV_DRAG_DIR_ONE) { - if(LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y)) { - hor_en = true; - } - else { - ver_en = true; - } - } - - /*If a move is greater then LV_DRAG_LIMIT then begin the drag*/ - if((hor_en && LV_MATH_ABS(proc->types.pointer.drag_sum.x) >= indev_act->driver.drag_limit) || - (ver_en && LV_MATH_ABS(proc->types.pointer.drag_sum.y) >= indev_act->driver.drag_limit)) { - proc->types.pointer.drag_limit_out = 1; - drag_just_started = true; - } - } - - /*If the drag limit is exceeded handle the dragging*/ - if(proc->types.pointer.drag_limit_out != 0) { - /*Set new position if the vector is not zero*/ - if(proc->types.pointer.vect.x != 0 || proc->types.pointer.vect.y != 0) { - - lv_coord_t prev_x = drag_obj->coords.x1; - lv_coord_t prev_y = drag_obj->coords.y1; - lv_coord_t prev_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); - lv_coord_t prev_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); - - /*Get the coordinates of the object and modify them*/ - lv_coord_t act_x = lv_obj_get_x(drag_obj); - lv_coord_t act_y = lv_obj_get_y(drag_obj); - - if(allowed_dirs == LV_DRAG_DIR_BOTH) { - if(drag_just_started) { - proc->types.pointer.drag_dir = LV_DRAG_DIR_BOTH; - act_x += proc->types.pointer.drag_sum.x; - act_y += proc->types.pointer.drag_sum.y; - } - } - else if(allowed_dirs == LV_DRAG_DIR_HOR) { - if(drag_just_started) { - proc->types.pointer.drag_dir = LV_DRAG_DIR_HOR; - proc->types.pointer.drag_sum.y = 0; - act_x += proc->types.pointer.drag_sum.x; - } - } - else if(allowed_dirs == LV_DRAG_DIR_VER) { - if(drag_just_started) { - proc->types.pointer.drag_dir = LV_DRAG_DIR_VER; - proc->types.pointer.drag_sum.x = 0; - act_y += proc->types.pointer.drag_sum.y; - } - } - else if(allowed_dirs == LV_DRAG_DIR_ONE) { - if(drag_just_started) { - if(LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y)) { - proc->types.pointer.drag_dir = LV_DRAG_DIR_HOR; - proc->types.pointer.drag_sum.y = 0; - act_x += proc->types.pointer.drag_sum.x; - } - else { - proc->types.pointer.drag_dir = LV_DRAG_DIR_VER; - proc->types.pointer.drag_sum.x = 0; - act_y += proc->types.pointer.drag_sum.y; - } - } - } - - /*Move the object*/ - if(allowed_dirs == LV_DRAG_DIR_HOR || - allowed_dirs == LV_DRAG_DIR_BOTH || - (allowed_dirs == LV_DRAG_DIR_ONE && - LV_MATH_ABS(proc->types.pointer.drag_sum.x) > LV_MATH_ABS(proc->types.pointer.drag_sum.y))) { - act_x += proc->types.pointer.vect.x; - } - if(allowed_dirs == LV_DRAG_DIR_VER || - allowed_dirs == LV_DRAG_DIR_BOTH || - (allowed_dirs == LV_DRAG_DIR_ONE && - LV_MATH_ABS(proc->types.pointer.drag_sum.x) < LV_MATH_ABS(proc->types.pointer.drag_sum.y))) { - act_y += proc->types.pointer.vect.y; - } - - uint16_t inv_buf_size = - lv_disp_get_inv_buf_size(indev_act->driver.disp); /*Get the number of currently invalidated areas*/ - - lv_obj_set_pos(drag_obj, act_x, act_y); - proc->types.pointer.drag_in_prog = 1; - - /*If the object didn't moved then clear the invalidated areas*/ - if(drag_obj->coords.x1 == prev_x && drag_obj->coords.y1 == prev_y) { - /*In a special case if the object is moved on a page and - * the scrollable has fit == true and the object is dragged of the page then - * while its coordinate is not changing only the parent's size is reduced */ - lv_coord_t act_par_w = lv_obj_get_width(lv_obj_get_parent(drag_obj)); - lv_coord_t act_par_h = lv_obj_get_height(lv_obj_get_parent(drag_obj)); - if(act_par_w == prev_par_w && act_par_h == prev_par_h) { - uint16_t new_inv_buf_size = lv_disp_get_inv_buf_size(indev_act->driver.disp); - _lv_disp_pop_from_inv_buf(indev_act->driver.disp, new_inv_buf_size - inv_buf_size); - } - } - - /*Set the drag in progress flag*/ - /*Send the drag begin signal on first move*/ - if(drag_just_started) { - drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_BEGIN, indev_act); - if(indev_reset_check(proc)) return; - - lv_event_send(drag_obj, LV_EVENT_DRAG_BEGIN, NULL); - if(indev_reset_check(proc)) return; - } - - } - } -} - -/** - * Handle throwing by drag if the drag is ended - * @param indev pointer to an input device state - */ -static void indev_drag_throw(lv_indev_proc_t * proc) -{ - if(proc->types.pointer.drag_in_prog == 0) return; - - lv_obj_t * drag_obj = get_dragged_obj(proc->types.pointer.last_obj); - - if(drag_obj == NULL) return; - - /*Return if the drag throw is not enabled*/ - 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); - if(indev_reset_check(proc)) return; - - lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL); - return; - } - - lv_drag_dir_t allowed_dirs = lv_obj_get_drag_dir(drag_obj); - - /*Reduce the vectors*/ - proc->types.pointer.drag_throw_vect.x = - proc->types.pointer.drag_throw_vect.x * (100 - indev_act->driver.drag_throw) / 100; - proc->types.pointer.drag_throw_vect.y = - proc->types.pointer.drag_throw_vect.y * (100 - indev_act->driver.drag_throw) / 100; - - if(proc->types.pointer.drag_throw_vect.x != 0 || proc->types.pointer.drag_throw_vect.y != 0) { - /*Get the coordinates and modify them*/ - lv_area_t coords_ori; - lv_obj_get_coords(drag_obj, &coords_ori); - lv_coord_t act_x = lv_obj_get_x(drag_obj) + proc->types.pointer.drag_throw_vect.x; - lv_coord_t act_y = lv_obj_get_y(drag_obj) + proc->types.pointer.drag_throw_vect.y; - - if(allowed_dirs == LV_DRAG_DIR_BOTH) lv_obj_set_pos(drag_obj, act_x, act_y); - else if(allowed_dirs == LV_DRAG_DIR_HOR) lv_obj_set_x(drag_obj, act_x); - else if(allowed_dirs == LV_DRAG_DIR_VER) lv_obj_set_y(drag_obj, act_y); - else if(allowed_dirs == LV_DRAG_DIR_ONE) { - if(proc->types.pointer.drag_sum.x) lv_obj_set_x(drag_obj, act_x); - else lv_obj_set_y(drag_obj, act_y); - } - lv_area_t coord_new; - lv_obj_get_coords(drag_obj, &coord_new); - - /*If non of the coordinates are changed then do not continue throwing*/ - if((coords_ori.x1 == coord_new.x1 || proc->types.pointer.drag_throw_vect.x == 0) && - (coords_ori.y1 == coord_new.y1 || proc->types.pointer.drag_throw_vect.y == 0)) { - proc->types.pointer.drag_in_prog = 0; - proc->types.pointer.vect.x = 0; - proc->types.pointer.vect.y = 0; - 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(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 - signal*/ - else { - proc->types.pointer.drag_in_prog = 0; - drag_obj->signal_cb(drag_obj, LV_SIGNAL_DRAG_END, indev_act); - if(indev_reset_check(proc)) return; - lv_event_send(drag_obj, LV_EVENT_DRAG_END, NULL); - if(indev_reset_check(proc)) return; - } -} - - -/** - * Get the really dragged object by taking `drag_parent` into account. - * @param obj the start object - * @return the object to really drag - */ -static lv_obj_t * get_dragged_obj(lv_obj_t * obj) -{ - if(obj == NULL) return NULL; - lv_obj_t * drag_obj = obj; - while(lv_obj_get_drag_parent(drag_obj) != false && drag_obj != NULL) { - drag_obj = lv_obj_get_parent(drag_obj); - } - - return drag_obj; -} - /** * Handle the gesture of indev_proc_p->types.pointer.act_obj * @param indev pointer to a input device state */ -static void indev_gesture(lv_indev_proc_t * proc) +void indev_gesture(lv_indev_proc_t * proc) { + if(proc->types.pointer.scroll_obj) return; if(proc->types.pointer.gesture_sent) return; lv_obj_t * gesture_obj = proc->types.pointer.act_obj; /*If gesture parent is active check recursively the gesture attribute*/ - while(gesture_obj && lv_obj_get_gesture_parent(gesture_obj)) { + while(gesture_obj && lv_obj_has_flag(gesture_obj, LV_OBJ_FLAG_GESTURE_BUBBLE)) { gesture_obj = lv_obj_get_parent(gesture_obj); } @@ -1538,6 +1226,7 @@ static void indev_gesture(lv_indev_proc_t * proc) } + /** * 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' diff --git a/src/lv_core/lv_indev.h b/src/lv_core/lv_indev.h index 403081f22..53c5b8451 100644 --- a/src/lv_core/lv_indev.h +++ b/src/lv_core/lv_indev.h @@ -15,7 +15,7 @@ extern "C" { *********************/ #include "lv_obj.h" #include "../lv_hal/lv_hal_indev.h" -#include "../lv_core/lv_group.h" +#include "lv_group.h" /********************* * DEFINES @@ -120,36 +120,36 @@ lv_gesture_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev); uint32_t lv_indev_get_key(const lv_indev_t * indev); /** - * Check if there is dragging with an input device or not (for LV_INDEV_TYPE_POINTER and + * Check the current scroll direction of an input device (for LV_INDEV_TYPE_POINTER and * LV_INDEV_TYPE_BUTTON) * @param indev pointer to an input device - * @return true: drag is in progress + * @return LV_SCROLL_DIR_NONE: no scrolling now + * LV_SCROLL_DIR_HOR/VER */ -bool lv_indev_is_dragging(const lv_indev_t * indev); +lv_scroll_dir_t lv_indev_get_scroll_dir(const lv_indev_t * indev); /** - * Get the vector of dragging of an input device (for LV_INDEV_TYPE_POINTER and + * Get the currently scrolled object (for LV_INDEV_TYPE_POINTER and * LV_INDEV_TYPE_BUTTON) * @param indev pointer to an input device - * @param point pointer to a point to store the vector + * @return pointer to the currently scrolled object or NULL if no scrolling by this indev + */ +lv_obj_t * lv_indev_get_scroll_obj(const lv_indev_t * indev); + +/** + * Get the movement vector of an input device (for LV_INDEV_TYPE_POINTER and + * LV_INDEV_TYPE_BUTTON) + * @param indev pointer to an input device + * @param point pointer to a point to store the types.pointer.vector */ void lv_indev_get_vect(const lv_indev_t * indev, lv_point_t * point); -/** - * Manually finish dragging. - * `LV_SIGNAL_DRAG_END` and `LV_EVENT_DRAG_END` will be sent. - * @param indev pointer to an input device - * @return `LV_RES_INV` if the object being dragged was deleted. Else `LV_RES_OK`. - */ -lv_res_t lv_indev_finish_drag(lv_indev_t * indev); - /** * Do nothing until the next release * @param indev pointer to an input device */ void lv_indev_wait_release(lv_indev_t * indev); - /** * Gets a pointer to the currently active object in indev proc functions. * NULL if no object is currently being handled or if groups aren't used. diff --git a/src/lv_core/lv_indev_scroll.c b/src/lv_core/lv_indev_scroll.c new file mode 100644 index 000000000..f95dd0685 --- /dev/null +++ b/src/lv_core/lv_indev_scroll.c @@ -0,0 +1,561 @@ +/** + * @file lv_indev_scroll.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_indev.h" +#include "lv_indev_scroll.h" + +/********************* + * DEFINES + *********************/ +#define ELASTIC_SLOWNESS_FACTOR 4 /*Scrolling on elastic parts are slower by this factor*/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_obj_t * find_scroll_obj(lv_indev_proc_t * proc); +static void init_scroll_limits(lv_indev_proc_t * proc); +static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs); +static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs); +static void scroll_limit_diff(lv_indev_proc_t * proc, lv_coord_t * diff_x, lv_coord_t * diff_y); +static lv_coord_t scroll_throw_predict_y(lv_indev_proc_t * proc); +static lv_coord_t scroll_throw_predict_x(lv_indev_proc_t * proc); +static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Handle scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_scroll_handler(lv_indev_proc_t * proc) +{ + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; + /*If there is no scroll object yet try to find one*/ + if(scroll_obj == NULL) { + proc->types.pointer.scroll_sum.x += proc->types.pointer.vect.x; + proc->types.pointer.scroll_sum.y += proc->types.pointer.vect.y; + + scroll_obj = find_scroll_obj(proc); + if(scroll_obj == NULL) return; + + init_scroll_limits(proc); + + lv_indev_t * indev_act = lv_indev_get_act(); + lv_signal_send(scroll_obj, LV_SIGNAL_SCROLL_BEGIN, indev_act); + if(proc->reset_query) return; + lv_event_send(scroll_obj, LV_EVENT_SCROLL_BEGIN, indev_act); + if(proc->reset_query) return; + } + + /*Set new position or scroll if the vector is not zero*/ + if(proc->types.pointer.vect.x != 0 || proc->types.pointer.vect.y != 0) { + lv_coord_t diff_x = 0; + lv_coord_t diff_y = 0; + + if(proc->types.pointer.scroll_dir == LV_SCROLL_DIR_HOR) { + lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); + lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); + diff_x = elastic_diff(scroll_obj, proc->types.pointer.vect.x, sl, sr); + } else { + lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); + lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); + diff_y = elastic_diff(scroll_obj, proc->types.pointer.vect.y, st, sb); + } + + lv_dir_t scroll_dir = lv_obj_get_scroll_dir(scroll_obj); + if((scroll_dir & LV_DIR_LEFT) == 0 && diff_x > 0) diff_x = 0; + if((scroll_dir & LV_DIR_RIGHT) == 0 && diff_x < 0) diff_x = 0; + if((scroll_dir & LV_DIR_TOP) == 0 && diff_y > 0) diff_y = 0; + if((scroll_dir & LV_DIR_BOTTOM) == 0 && diff_y < 0) diff_y = 0; + + /*Respect the scroll limit area*/ + scroll_limit_diff(proc, &diff_x, &diff_y); + + _lv_obj_scroll_by_raw(scroll_obj, diff_x, diff_y); + proc->types.pointer.scroll_sum.x += diff_x; + proc->types.pointer.scroll_sum.y += diff_y; + } +} + + +/** + * Handle throwing after scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_scroll_throw_handler(lv_indev_proc_t * proc) +{ + lv_obj_t * scroll_obj = proc->types.pointer.scroll_obj; + if(scroll_obj == NULL) return; + if(proc->types.pointer.scroll_dir == LV_SCROLL_DIR_NONE) return; + + + lv_indev_t * indev_act = lv_indev_get_act(); + lv_coord_t scroll_throw = indev_act->driver.scroll_throw; + + if(lv_obj_has_flag(scroll_obj, LV_OBJ_FLAG_SCROLL_MOMENTUM) == false) { + proc->types.pointer.scroll_throw_vect.y = 0; + proc->types.pointer.scroll_throw_vect.x = 0; + } + + lv_snap_align_t align_x = lv_obj_get_snap_align_x(scroll_obj); + lv_snap_align_t align_y = lv_obj_get_snap_align_y(scroll_obj); + + if(proc->types.pointer.scroll_dir == LV_SCROLL_DIR_VER) { + proc->types.pointer.scroll_throw_vect.x = 0; + /*If no snapping "throw"*/ + if(align_y == LV_SCROLL_SNAP_ALIGN_NONE) { + proc->types.pointer.scroll_throw_vect.y = + proc->types.pointer.scroll_throw_vect.y * (100 - scroll_throw) / 100; + + lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); + lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); + + proc->types.pointer.scroll_throw_vect.y = elastic_diff(scroll_obj, proc->types.pointer.scroll_throw_vect.y, st, sb); + + _lv_obj_scroll_by_raw(scroll_obj, 0, proc->types.pointer.scroll_throw_vect.y); + } + /*With snapping find the nearest snap point and scroll there*/ + else { + lv_coord_t diff_y = scroll_throw_predict_y(proc); + proc->types.pointer.scroll_throw_vect.y = 0; + scroll_limit_diff(proc, NULL, &diff_y); + lv_coord_t y = find_snap_point_y(scroll_obj, LV_COORD_MIN, LV_COORD_MAX, diff_y); + lv_obj_scroll_by(scroll_obj, 0, diff_y + y, LV_ANIM_ON); + } + } + else if(proc->types.pointer.scroll_dir == LV_SCROLL_DIR_HOR) { + proc->types.pointer.scroll_throw_vect.y = 0; + /*If no snapping "throw"*/ + if(align_x == LV_SCROLL_SNAP_ALIGN_NONE) { + proc->types.pointer.scroll_throw_vect.x = + proc->types.pointer.scroll_throw_vect.x * (100 - scroll_throw) / 100; + + lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); + lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); + + proc->types.pointer.scroll_throw_vect.x = elastic_diff(scroll_obj, proc->types.pointer.scroll_throw_vect.x, sl ,sr); + + _lv_obj_scroll_by_raw(scroll_obj, proc->types.pointer.scroll_throw_vect.x, 0); + } + /*With snapping find the nearest snap point and scroll there*/ + else { + lv_coord_t diff_x = scroll_throw_predict_x(proc); + proc->types.pointer.scroll_throw_vect.x = 0; + scroll_limit_diff(proc, &diff_x, NULL); + lv_coord_t x = find_snap_point_x(scroll_obj, LV_COORD_MIN, LV_COORD_MAX, diff_x); + lv_obj_scroll_by(scroll_obj, x + diff_x, 0, LV_ANIM_ON); + } + } + + /*Check if the scroll has finished */ + if(proc->types.pointer.scroll_throw_vect.x == 0 && proc->types.pointer.scroll_throw_vect.y == 0) { + /*Revert if scrolled in*/ + /*If vertically scrollable and not controlled by snap*/ + if(align_y == LV_SCROLL_SNAP_ALIGN_NONE) { + lv_coord_t st = lv_obj_get_scroll_top(scroll_obj); + lv_coord_t sb = lv_obj_get_scroll_bottom(scroll_obj); + if(st > 0 || sb > 0) { + if(st < 0) { + lv_obj_scroll_by(scroll_obj, 0, st, LV_ANIM_ON); + } + else if(sb < 0) { + lv_obj_scroll_by(scroll_obj, 0, -sb, LV_ANIM_ON); + } + } + } + + /*If horizontally scrollable and not controlled by snap*/ + if(align_x == LV_SCROLL_SNAP_ALIGN_NONE) { + lv_coord_t sl = lv_obj_get_scroll_left(scroll_obj); + lv_coord_t sr = lv_obj_get_scroll_right(scroll_obj); + if (sl > 0 || sr > 0) { + if(sl < 0) { + lv_obj_scroll_by(scroll_obj, sl, 0, LV_ANIM_ON); + } + else if(sr < 0) { + lv_obj_scroll_by(scroll_obj, -sr, 0, LV_ANIM_ON); + } + } + } + + lv_signal_send(scroll_obj, LV_SIGNAL_SCROLL_END, indev_act); + if(proc->reset_query) return; + lv_event_send(scroll_obj, LV_EVENT_SCROLL_END, indev_act); + if(proc->reset_query) return; + + proc->types.pointer.scroll_dir = LV_SCROLL_DIR_NONE; + proc->types.pointer.scroll_obj = NULL; + } +} + +/** + * Predict where would a scroll throw end + * @param indev pointer to an input device + * @param dir `LV_DIR_VER` or `LV_DIR_HOR` + * @return the difference compared to the current position when the throw would be finished + */ +lv_coord_t _lv_scroll_throw_predict(lv_indev_t * indev, lv_dir_t dir) +{ + if(indev == NULL) return 0; + lv_coord_t v; + switch(dir) { + case LV_DIR_VER: + v = indev->proc.types.pointer.scroll_throw_vect_ori.y; + break; + case LV_DIR_HOR: + v = indev->proc.types.pointer.scroll_throw_vect_ori.x; + break; + default: + return 0; + } + + lv_coord_t scroll_throw = indev->driver.scroll_throw; + lv_coord_t sum = 0; + while(v) { + sum += v; + v = v * (100 - scroll_throw) / 100; + } + + return sum; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static lv_obj_t * find_scroll_obj(lv_indev_proc_t * proc) +{ + lv_obj_t * obj_candidate = NULL; + lv_dir_t dir_candidate = LV_DIR_NONE; + lv_indev_t * indev_act = lv_indev_get_act(); + lv_coord_t scroll_limit = indev_act->driver.scroll_limit; + + /* Go until find an scrollable object in the current direction + * More precisely: + * 1. Check the pressed object and all of its ancestors and try to find an object which is scrollable + * 2. Scrollable means it has some content out of it's area + * 3. If an object can be scrolled into the current direction then use it ("real match"") + * 4. If can be scrolled on the current axis (hor/ver) save it as candidate (at least show an elastic scroll effect) + * 5. Use the last candidate. Always the "deepest" parent or the object from point 3 */ + lv_obj_t * obj_act = proc->types.pointer.act_obj; + while(obj_act) { + if(lv_obj_has_flag(obj_act, LV_OBJ_FLAG_SCROLLABLE) == false) { + obj_act = lv_obj_get_parent(obj_act); + continue; + } + + /*Decide if it's a horizontal or vertical scroll*/ + bool hor_en = false; + bool ver_en = false; + if(LV_MATH_ABS(proc->types.pointer.scroll_sum.x) > LV_MATH_ABS(proc->types.pointer.scroll_sum.y)) { + hor_en = true; + } + else { + ver_en = true; + } + + /*Consider both up-down or left/right scrollable according to the current direction*/ + bool up_en = ver_en; + bool down_en = ver_en; + bool left_en = hor_en; + bool right_en = hor_en; + + /*The object might have disabled some directions.*/ + lv_dir_t scroll_dir = lv_obj_get_scroll_dir(obj_act); + if((scroll_dir & LV_DIR_LEFT) == 0) left_en = false; + if((scroll_dir & LV_DIR_RIGHT) == 0) right_en = false; + if((scroll_dir & LV_DIR_TOP) == 0) up_en = false; + if((scroll_dir & LV_DIR_BOTTOM) == 0) down_en = false; + + /*The object is scrollable to a direction if its content overflow in that direction. */ + lv_coord_t st = lv_obj_get_scroll_top(obj_act); + lv_coord_t sb = lv_obj_get_scroll_bottom(obj_act); + lv_coord_t sl = lv_obj_get_scroll_left(obj_act); + lv_coord_t sr = lv_obj_get_scroll_right(obj_act); + + /* If this object is scrollable into the current scroll direction then save it as a candidate. + * It's important only to be scrollable on the current axis (hor/ver) because if the scroll + * is propagated to this object it can show at least elastic scroll effect. + * But if not hor/ver scrollable do not scroll it at all (so it's not a good candidate) */ + if((st > 0 || sb > 0) && + ((up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || + (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit))) + { + obj_candidate = obj_act; + dir_candidate = LV_SCROLL_DIR_VER; + } + + if((sl > 0 || sr > 0) && + ((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || + (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit))) + { + obj_candidate = obj_act; + dir_candidate = LV_SCROLL_DIR_HOR; + } + + if(st <= 0) up_en = false; + if(sb <= 0) down_en = false; + if(sl <= 0) left_en = false; + if(sr <= 0) right_en = false; + + /*If the object really can be scrolled into the current direction the use it. */ + if((left_en && proc->types.pointer.scroll_sum.x >= scroll_limit) || + (right_en && proc->types.pointer.scroll_sum.x <= - scroll_limit) || + (up_en && proc->types.pointer.scroll_sum.y >= scroll_limit) || + (down_en && proc->types.pointer.scroll_sum.y <= - scroll_limit)) + { + proc->types.pointer.scroll_dir = hor_en ? LV_SCROLL_DIR_HOR : LV_SCROLL_DIR_VER; + break; + } + + /*Try the parent */ + obj_act = lv_obj_get_parent(obj_act); + } + + /*Use the last candidate*/ + if(obj_candidate) { + proc->types.pointer.scroll_dir = dir_candidate; + proc->types.pointer.scroll_obj = obj_candidate; + proc->types.pointer.scroll_sum.x = 0; + proc->types.pointer.scroll_sum.y = 0; + } + + return obj_candidate; +} + +static void init_scroll_limits(lv_indev_proc_t * proc) +{ + lv_obj_t * obj = proc->types.pointer.scroll_obj; + /*If there no STOP allow scrolling anywhere*/ + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_STOP) == false) { + lv_area_set(&proc->types.pointer.scroll_area, LV_COORD_MIN, LV_COORD_MIN, LV_COORD_MAX, LV_COORD_MAX); + } + /*With STOP limit the scrolling to the perv and next snap point*/ + else { + switch(lv_obj_get_snap_align_y(obj)) { + case LV_SCROLL_SNAP_ALIGN_START: + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y1 + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y1 - 1, 0); + break; + case LV_SCROLL_SNAP_ALIGN_END: + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, obj->coords.y2, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, obj->coords.y2, 0); + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: { + lv_coord_t y_mid = obj->coords.y1 + lv_area_get_height(&obj->coords) / 2; + proc->types.pointer.scroll_area.y1 = find_snap_point_y(obj, y_mid + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.y2 = find_snap_point_y(obj, LV_COORD_MIN, y_mid - 1, 0); + break; + } + default: + proc->types.pointer.scroll_area.y1 = LV_COORD_MIN; + proc->types.pointer.scroll_area.y2 = LV_COORD_MAX; + break; + } + + switch(lv_obj_get_snap_align_x(obj)) { + case LV_SCROLL_SNAP_ALIGN_START: + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x1, 0); + break; + case LV_SCROLL_SNAP_ALIGN_END: + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, obj->coords.x2, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, obj->coords.x2, 0); + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: { + lv_coord_t x_mid = obj->coords.x1 + lv_area_get_width(&obj->coords) / 2; + proc->types.pointer.scroll_area.x1 = find_snap_point_x(obj, x_mid + 1, LV_COORD_MAX, 0); + proc->types.pointer.scroll_area.x2 = find_snap_point_x(obj, LV_COORD_MIN, x_mid - 1, 0); + break; + } + default: + proc->types.pointer.scroll_area.x1 = LV_COORD_MIN; + proc->types.pointer.scroll_area.x2 = LV_COORD_MAX; + break; + } + } + + /*Allow scrolling on the edges. It will be reverted to the edge due to snapping anyway*/ + if(proc->types.pointer.scroll_area.x1 == 0) proc->types.pointer.scroll_area.x1 = LV_COORD_MIN; + if(proc->types.pointer.scroll_area.x2 == 0) proc->types.pointer.scroll_area.x2 = LV_COORD_MAX; + if(proc->types.pointer.scroll_area.y1 == 0) proc->types.pointer.scroll_area.y1 = LV_COORD_MIN; + if(proc->types.pointer.scroll_area.y2 == 0) proc->types.pointer.scroll_area.y2 = LV_COORD_MAX; +} + +static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs) +{ + lv_snap_align_t align = lv_obj_get_snap_align_x(obj); + if(align == LV_SCROLL_SNAP_ALIGN_NONE) return 0; + + lv_coord_t dist = LV_COORD_MAX; + + lv_obj_t * child = lv_obj_get_child_back(obj, NULL); + while(child) { + if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPABLE)) { + lv_coord_t x_child = 0; + lv_coord_t x_parent = 0; + switch(align) { + case LV_SCROLL_SNAP_ALIGN_START: + x_child = child->coords.x1; + x_parent = obj->coords.x1; + break; + case LV_SCROLL_SNAP_ALIGN_END: + x_child = child->coords.x2; + x_parent = obj->coords.x2; + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: + x_child = child->coords.x1 + lv_area_get_width(&child->coords) / 2; + x_parent = obj->coords.x1 + lv_area_get_width(&obj->coords) / 2; + } + + x_child += ofs; + if(x_child >= min && x_child <= max) { + lv_coord_t x = x_child - x_parent; + if(LV_MATH_ABS(x) < LV_MATH_ABS(dist)) dist = x; + } + } + + child = lv_obj_get_child_back(obj, child); + } + + return dist == LV_COORD_MAX ? 0: -dist; +} + +/** + * Search for snap point in the `min` - `max` range. + * @param obj the object on which snap point should be found + * @param min ignore snap points smaller then this. (Absolute coordinate) + * @param max ignore snap points greater then this. (Absolute coordinate) + * @param ofs offset to snap points. Useful the get a snap point in an imagined case + * what if children are already moved by this value + * @return the distance of the snap point. + */ +static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coord_t max, lv_coord_t ofs) +{ + lv_snap_align_t align = lv_obj_get_snap_align_y(obj); + if(align == LV_SCROLL_SNAP_ALIGN_NONE) return 0; + + lv_coord_t dist = LV_COORD_MAX; + + lv_obj_t * child = lv_obj_get_child_back(obj, NULL); + while(child) { + if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPABLE)) { + lv_coord_t y_child = 0; + lv_coord_t y_parent = 0; + switch(align) { + case LV_SCROLL_SNAP_ALIGN_START: + y_child = child->coords.y1; + y_parent = obj->coords.y1; + break; + case LV_SCROLL_SNAP_ALIGN_END: + y_child = child->coords.y2; + y_parent = obj->coords.y2; + break; + case LV_SCROLL_SNAP_ALIGN_CENTER: + y_child = child->coords.y1 + lv_area_get_height(&child->coords) / 2; + y_parent = obj->coords.y1 + lv_area_get_height(&obj->coords) / 2; + } + + y_child += ofs; + if(y_child >= min && y_child <= max) { + lv_coord_t y = y_child - y_parent; + if(LV_MATH_ABS(y) < LV_MATH_ABS(dist)) dist = y; + } + } + + child = lv_obj_get_child_back(obj, child); + } + + return dist == LV_COORD_MAX ? 0 : -dist; +} + +static void scroll_limit_diff(lv_indev_proc_t * proc, lv_coord_t * diff_x, lv_coord_t * diff_y) +{ + if(diff_y) { + if(proc->types.pointer.scroll_sum.y + *diff_y < proc->types.pointer.scroll_area.y1) { + *diff_y = proc->types.pointer.scroll_area.y1 - proc->types.pointer.scroll_sum.y; + } + + if(proc->types.pointer.scroll_sum.y + *diff_y > proc->types.pointer.scroll_area.y2) { + *diff_y = proc->types.pointer.scroll_area.y2 - proc->types.pointer.scroll_sum.y; + } + } + + if(diff_x) { + if(proc->types.pointer.scroll_sum.x + *diff_x < proc->types.pointer.scroll_area.x1) { + *diff_x = proc->types.pointer.scroll_area.x1 - proc->types.pointer.scroll_sum.x; + } + + if(proc->types.pointer.scroll_sum.x + *diff_x > proc->types.pointer.scroll_area.x2) { + *diff_x = proc->types.pointer.scroll_area.x2 - proc->types.pointer.scroll_sum.x; + } + } +} + + + +static lv_coord_t scroll_throw_predict_y(lv_indev_proc_t * proc) +{ + lv_coord_t y = proc->types.pointer.scroll_throw_vect.y; + lv_coord_t move = 0; + + lv_indev_t * indev_act = lv_indev_get_act(); + lv_coord_t scroll_throw = indev_act->driver.scroll_throw; + + while(y) { + move += y; + y = y * (100 - scroll_throw) / 100; + } + return move; +} + + +static lv_coord_t scroll_throw_predict_x(lv_indev_proc_t * proc) +{ + lv_coord_t x = proc->types.pointer.scroll_throw_vect.x; + lv_coord_t move = 0; + + lv_indev_t * indev_act = lv_indev_get_act(); + lv_coord_t scroll_throw = indev_act->driver.scroll_throw; + + while(x) { + move += x; + x = x * (100 - scroll_throw) / 100; + } + return move; +} + +static lv_coord_t elastic_diff(lv_obj_t * obj, lv_coord_t diff, lv_coord_t scroll_start, lv_coord_t scroll_end) +{ + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_SCROLL_ELASTIC)) { + /*Elastic scroll if scrolled in*/ + if(scroll_end < 0) diff = (diff + ELASTIC_SLOWNESS_FACTOR / 2) / ELASTIC_SLOWNESS_FACTOR; + else if(scroll_start < 0) diff = (diff + ELASTIC_SLOWNESS_FACTOR / 2) / ELASTIC_SLOWNESS_FACTOR; + } else { + /*Scroll back to the boundary id required*/ + if(scroll_end + diff < 0) diff = - scroll_end; + if(scroll_start - diff < 0) diff = scroll_start; + } + + return diff; +} + diff --git a/src/lv_core/lv_indev_scroll.h b/src/lv_core/lv_indev_scroll.h new file mode 100644 index 000000000..600ddf0f2 --- /dev/null +++ b/src/lv_core/lv_indev_scroll.h @@ -0,0 +1,59 @@ +/** + * @file lv_indev_scroll.h + * + */ + +#ifndef LV_INDEV_SCROLL_H +#define LV_INDEV_SCROLL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_obj.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Handle scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_scroll_handler(lv_indev_proc_t * proc); + + +/** + * Handle throwing after scrolling. Called by LVGL during input device processing + * @param proc pointer to an input device's proc field + */ +void _lv_scroll_throw_handler(lv_indev_proc_t * proc); + +/** + * Predict where would a scroll throw end + * @param indev pointer to an input device + * @param dir `LV_DIR_VER` or `LV_DIR_HOR` + * @return the difference compared to the current position when the throw would be finished + */ +lv_coord_t _lv_scroll_throw_predict(lv_indev_t * indev, lv_dir_t dir); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_INDEV_SCROLL_H*/ diff --git a/src/lv_core/lv_obj.c b/src/lv_core/lv_obj.c index 02edcb4b5..d20ab51df 100644 --- a/src/lv_core/lv_obj.c +++ b/src/lv_core/lv_obj.c @@ -27,11 +27,6 @@ #include #include -#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT - #include "../lv_gpu/lv_gpu_nxp_pxp.h" - #include "../lv_gpu/lv_gpu_nxp_pxp_osa.h" -#endif - #if defined(LV_GC_INCLUDE) #include LV_GC_INCLUDE #endif /* LV_ENABLE_GC */ @@ -53,6 +48,7 @@ #define LV_OBJX_NAME "lv_obj" #define LV_OBJ_DEF_WIDTH (LV_DPX(100)) #define LV_OBJ_DEF_HEIGHT (LV_DPX(50)) +#define GRID_DEBUG 0 /*Draw rectangles on grid cells*/ /********************** * TYPEDEFS @@ -63,92 +59,16 @@ typedef struct _lv_event_temp_data { struct _lv_event_temp_data * prev; } lv_event_temp_data_t; -typedef struct { - lv_obj_t * obj; - lv_style_property_t prop; - uint8_t part; - union { - lv_color_t _color; - lv_style_int_t _int; - lv_opa_t _opa; - const void * _ptr; - } start_value; - union { - lv_color_t _color; - lv_style_int_t _int; - lv_opa_t _opa; - const void * _ptr; - } end_value; -} lv_style_trans_t; - -typedef struct { - lv_draw_rect_dsc_t rect; - lv_draw_label_dsc_t label; - lv_draw_line_dsc_t line; - lv_draw_img_dsc_t img; - lv_style_int_t pad_top; - lv_style_int_t pad_bottom; - lv_style_int_t pad_right; - lv_style_int_t pad_left; - lv_style_int_t pad_inner; - lv_style_int_t margin_top; - lv_style_int_t margin_bottom; - lv_style_int_t margin_left; - lv_style_int_t margin_right; - lv_style_int_t size; - lv_style_int_t transform_width; - lv_style_int_t transform_height; - lv_style_int_t transform_angle; - lv_style_int_t transform_zoom; - lv_style_int_t scale_width; - lv_style_int_t scale_border_width; - lv_style_int_t scale_end_border_width; - lv_style_int_t scale_end_line_width; - lv_color_t scale_grad_color; - lv_color_t scale_end_color; - lv_opa_t opa_scale; - uint32_t clip_corder : 1; - uint32_t border_post : 1; -} style_snapshot_t; - -typedef enum { - STYLE_COMPARE_SAME, - STYLE_COMPARE_VISUAL_DIFF, - STYLE_COMPARE_DIFF, -} style_snapshot_res_t; - /********************** * STATIC PROTOTYPES **********************/ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode); static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param); -static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff); -static void report_style_mod_core(void * style_p, lv_obj_t * obj); -static void refresh_children_style(lv_obj_t * obj); -static void base_dir_refr_children(lv_obj_t * obj); -static void obj_align_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set, - lv_coord_t x_ofs, lv_coord_t y_ofs); -static void obj_align_mid_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set, - lv_coord_t x_ofs, lv_coord_t y_ofs); -#if LV_USE_ANIMATION -static lv_style_trans_t * trans_create(lv_obj_t * obj, lv_style_property_t prop, uint8_t part, lv_state_t prev_state, - lv_state_t new_state); -static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_trans_t * tr_limit); -static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v); -static void trans_anim_start_cb(lv_anim_t * a); -static void trans_anim_ready_cb(lv_anim_t * a); -static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v); -static void fade_in_anim_ready(lv_anim_t * a); -#endif static void lv_event_mark_deleted(lv_obj_t * obj); static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_find); static void lv_obj_del_async_cb(void * obj); static void obj_del_core(lv_obj_t * obj); -static void update_style_cache(lv_obj_t * obj, uint8_t part, uint16_t prop); -static void update_style_cache_children(lv_obj_t * obj); -static void invalidate_style_cache(lv_obj_t * obj, uint8_t part, lv_style_property_t prop); -static void style_snapshot(lv_obj_t * obj, uint8_t part, style_snapshot_t * shot); -static style_snapshot_res_t style_snapshot_compare(style_snapshot_t * shot1, style_snapshot_t * shot2); +static void base_dir_refr_children(lv_obj_t * obj); /********************** * STATIC VARIABLES @@ -199,14 +119,7 @@ void lv_init(void) lv_gpu_stm32_dma2d_init(); #endif -#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT - if(lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) { - LV_LOG_ERROR("PXP init error. STOP.\n"); - for(; ;) ; - } -#endif - - _lv_ll_init(&LV_GC_ROOT(_lv_obj_style_trans_ll), sizeof(lv_style_trans_t)); + _lv_obj_style_init(); _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); _lv_ll_init(&LV_GC_ROOT(_lv_indev_ll), sizeof(lv_indev_t)); @@ -267,7 +180,9 @@ void lv_deinit(void) * Create a basic object * @param parent pointer to a parent object. * If NULL then a screen will be created - * @param copy pointer to a base object, if not NULL then the new object will be copied from it + * + * @param copy DEPRECATED, will be removed in v9. + * Pointer to an other base object to copy. * @return pointer to the new object */ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) @@ -289,16 +204,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) _lv_memset_00(new_obj, sizeof(lv_obj_t)); -#if LV_USE_BIDI - new_obj->base_dir = LV_BIDI_BASE_DIR_DEF; -#else - new_obj->base_dir = LV_BIDI_DIR_LTR; -#endif - /*Set the callbacks*/ new_obj->signal_cb = lv_obj_signal; new_obj->design_cb = lv_obj_design; - new_obj->event_cb = NULL; /*Set coordinates to full screen size*/ new_obj->coords.x1 = 0; @@ -310,8 +218,10 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) else { LV_LOG_TRACE("Object create started"); LV_ASSERT_OBJ(parent, LV_OBJX_NAME); - - new_obj = _lv_ll_ins_head(&parent->child_ll); + if(parent->spec_attr == NULL) { + parent->spec_attr = lv_obj_allocate_spec_attr(parent); + } + new_obj = _lv_ll_ins_head(&parent->spec_attr->child_ll); LV_ASSERT_MEM(new_obj); if(new_obj == NULL) return NULL; @@ -319,16 +229,9 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->parent = parent; -#if LV_USE_BIDI - new_obj->base_dir = LV_BIDI_DIR_INHERIT; -#else - new_obj->base_dir = LV_BIDI_DIR_LTR; -#endif - /*Set the callbacks (signal:cb is required in `lv_obj_get_base_dir` if `LV_USE_ASSERT_OBJ` is enabled)*/ new_obj->signal_cb = lv_obj_signal; new_obj->design_cb = lv_obj_design; - new_obj->event_cb = NULL; new_obj->coords.y1 = parent->coords.y1; new_obj->coords.y2 = parent->coords.y1 + LV_OBJ_DEF_HEIGHT; @@ -340,57 +243,24 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) new_obj->coords.x1 = parent->coords.x1; new_obj->coords.x2 = parent->coords.x1 + LV_OBJ_DEF_WIDTH; } + new_obj->w_set = lv_area_get_width(&new_obj->coords); + new_obj->h_set = lv_area_get_height(&new_obj->coords); } - - _lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); - - - new_obj->ext_draw_pad = 0; - -#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL - _lv_memset_00(&new_obj->ext_click_pad, sizeof(new_obj->ext_click_pad)); -#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY - new_obj->ext_click_pad_hor = 0; - new_obj->ext_click_pad_ver = 0; -#endif - - /*Init realign*/ -#if LV_USE_OBJ_REALIGN - new_obj->realign.align = LV_ALIGN_CENTER; - new_obj->realign.xofs = 0; - new_obj->realign.yofs = 0; - new_obj->realign.base = NULL; - new_obj->realign.auto_realign = 0; -#endif - - /*Init. user date*/ -#if LV_USE_USER_DATA - _lv_memset_00(&new_obj->user_data, sizeof(lv_obj_user_data_t)); -#endif - - -#if LV_USE_GROUP - new_obj->group_p = NULL; -#endif - /*Set attributes*/ - new_obj->adv_hittest = 0; - new_obj->click = 1; - new_obj->drag = 0; - new_obj->drag_throw = 0; - new_obj->drag_parent = 0; - new_obj->drag_dir = LV_DRAG_DIR_BOTH; - new_obj->hidden = 0; - new_obj->top = 0; - new_obj->protect = LV_PROTECT_NONE; - new_obj->parent_event = 0; - new_obj->gesture_parent = parent ? 1 : 0; - new_obj->focus_parent = 0; + new_obj->flags = LV_OBJ_FLAG_CLICKABLE; + new_obj->flags |= LV_OBJ_FLAG_SNAPABLE; + new_obj->flags |= LV_OBJ_FLAG_PRESS_LOCK; + new_obj->flags |= LV_OBJ_FLAG_CLICK_FOCUSABLE; + new_obj->flags |= LV_OBJ_FLAG_SCROLLABLE; + new_obj->flags |= LV_OBJ_FLAG_SCROLL_ELASTIC; + new_obj->flags |= LV_OBJ_FLAG_SCROLL_MOMENTUM; + if(parent) new_obj->flags |= LV_OBJ_FLAG_GESTURE_BUBBLE; new_obj->state = LV_STATE_DEFAULT; new_obj->ext_attr = NULL; + lv_style_list_init(&new_obj->style_list); lv_style_list_init(&new_obj->style_list); if(copy == NULL) { if(parent != NULL) lv_theme_apply(new_obj, LV_THEME_OBJ); @@ -402,63 +272,29 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy) /*Copy the attributes if required*/ if(copy != NULL) { lv_area_copy(&new_obj->coords, ©->coords); - new_obj->ext_draw_pad = copy->ext_draw_pad; - -#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL - lv_area_copy(&new_obj->ext_click_pad, ©->ext_click_pad); -#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY - new_obj->ext_click_pad_hor = copy->ext_click_pad_hor; - new_obj->ext_click_pad_ver = copy->ext_click_pad_ver; -#endif - - /*Set user data*/ -#if LV_USE_USER_DATA - _lv_memcpy(&new_obj->user_data, ©->user_data, sizeof(lv_obj_user_data_t)); -#endif - - new_obj->base_dir = copy->base_dir; - - /*Copy realign*/ -#if LV_USE_OBJ_REALIGN - new_obj->realign.align = copy->realign.align; - new_obj->realign.xofs = copy->realign.xofs; - new_obj->realign.yofs = copy->realign.yofs; - new_obj->realign.base = copy->realign.base; - new_obj->realign.auto_realign = copy->realign.auto_realign; -#endif - - /*Only copy the `event_cb`. `signal_cb` and `design_cb` will be copied in the derived - * object type (e.g. `lv_btn`)*/ - new_obj->event_cb = copy->event_cb; - - /*Copy attributes*/ - new_obj->adv_hittest = copy->adv_hittest; - new_obj->click = copy->click; - new_obj->drag = copy->drag; - new_obj->drag_dir = copy->drag_dir; - new_obj->drag_throw = copy->drag_throw; - new_obj->drag_parent = copy->drag_parent; - new_obj->hidden = copy->hidden; - new_obj->top = copy->top; - new_obj->parent_event = copy->parent_event; - - new_obj->protect = copy->protect; - new_obj->gesture_parent = copy->gesture_parent; - new_obj->focus_parent = copy->focus_parent; + new_obj->flags = copy->flags; + if(copy->spec_attr) { + lv_obj_allocate_spec_attr(new_obj); + _lv_memcpy_small(new_obj->spec_attr, copy->spec_attr, sizeof(lv_obj_spec_attr_t)); + } #if LV_USE_GROUP /*Add to the same group*/ - if(copy->group_p != NULL) { - lv_group_add_obj(copy->group_p, new_obj); + if(copy->spec_attr && copy->spec_attr->group_p) { + new_obj->spec_attr->group_p = NULL; /*It was simply copied */ + lv_group_add_obj(copy->spec_attr->group_p, new_obj); } #endif /*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)); - } - } + lv_obj_set_size(new_obj, lv_obj_get_width(copy), lv_obj_get_height(copy)); + } + } else { + lv_obj_set_pos(new_obj, 0, 0); + } /*Send a signal to the parent to notify it about the new child*/ if(parent != NULL) { parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, new_obj); @@ -571,7 +407,7 @@ void lv_obj_invalidate(const lv_obj_t * obj) /*Truncate the area to the object*/ lv_area_t obj_coords; - lv_coord_t ext_size = obj->ext_draw_pad; + lv_coord_t ext_size = _lv_obj_get_ext_draw_pad(obj); lv_area_copy(&obj_coords, &obj->coords); obj_coords.x1 -= ext_size; obj_coords.y1 -= ext_size; @@ -590,7 +426,7 @@ void lv_obj_invalidate(const lv_obj_t * obj) */ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) { - if(lv_obj_get_hidden(obj)) return false; + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_HIDDEN)) return false; /*Invalidate the object only if it belongs to the curent or previous'*/ lv_obj_t * obj_scr = lv_obj_get_screen(obj); @@ -602,7 +438,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) /*Truncate the area to the object*/ lv_area_t obj_coords; - lv_coord_t ext_size = obj->ext_draw_pad; + lv_coord_t ext_size = _lv_obj_get_ext_draw_pad(obj); lv_area_copy(&obj_coords, &obj->coords); obj_coords.x1 -= ext_size; obj_coords.y1 -= ext_size; @@ -619,7 +455,7 @@ bool lv_obj_area_is_visible(const lv_obj_t * obj, lv_area_t * area) while(par != NULL) { is_common = _lv_area_intersect(area, area, &par->coords); if(is_common == false) return false; /*If no common parts with parent break;*/ - if(lv_obj_get_hidden(par)) return false; /*If the parent is hidden then the child is hidden and won't be drawn*/ + if(lv_obj_has_flag(par, LV_OBJ_FLAG_HIDDEN)) return false; /*If the parent is hidden then the child is hidden and won't be drawn*/ par = lv_obj_get_parent(par); } @@ -638,7 +474,7 @@ bool lv_obj_is_visible(const lv_obj_t * obj) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_area_t obj_coords; - lv_coord_t ext_size = obj->ext_draw_pad; + lv_coord_t ext_size = _lv_obj_get_ext_draw_pad(obj); lv_area_copy(&obj_coords, &obj->coords); obj_coords.x1 -= ext_size; obj_coords.y1 -= ext_size; @@ -679,6 +515,10 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) lv_obj_invalidate(obj); + if(parent->spec_attr == NULL) { + parent->spec_attr = lv_obj_allocate_spec_attr(parent); + } + lv_obj_t * old_par = obj->parent; lv_point_t old_pos; old_pos.y = lv_obj_get_y(obj); @@ -692,7 +532,7 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) old_pos.x = old_par->coords.x2 - obj->coords.x2; } - _lv_ll_chg_list(&obj->parent->child_ll, &parent->child_ll, obj, true); + _lv_ll_chg_list(_lv_obj_get_child_ll(obj->parent), _lv_obj_get_child_ll(parent), obj, true); obj->parent = parent; @@ -706,7 +546,7 @@ void lv_obj_set_parent(lv_obj_t * obj, lv_obj_t * parent) } /*Notify the original parent because one of its children is lost*/ - old_par->signal_cb(old_par, LV_SIGNAL_CHILD_CHG, NULL); + old_par->signal_cb(old_par, LV_SIGNAL_CHILD_CHG, obj); /*Notify the new parent about the child*/ parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj); @@ -723,13 +563,14 @@ void lv_obj_move_foreground(lv_obj_t * obj) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_t * parent = lv_obj_get_parent(obj); + lv_ll_t * ll = _lv_obj_get_child_ll(parent); /*Do nothing of already in the foreground*/ - if(_lv_ll_get_head(&parent->child_ll) == obj) return; + if(_lv_ll_get_head(ll) == obj) return; lv_obj_invalidate(parent); - _lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, true); + _lv_ll_chg_list(ll, ll, obj, true); /*Notify the new parent about the child*/ parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj); @@ -746,13 +587,14 @@ void lv_obj_move_background(lv_obj_t * obj) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_t * parent = lv_obj_get_parent(obj); + lv_ll_t * ll = _lv_obj_get_child_ll(parent); /*Do nothing of already in the background*/ - if(_lv_ll_get_tail(&parent->child_ll) == obj) return; + if(_lv_ll_get_tail(ll) == obj) return; lv_obj_invalidate(parent); - _lv_ll_chg_list(&parent->child_ll, &parent->child_ll, obj, false); + _lv_ll_chg_list(ll, ll, obj, false); /*Notify the new parent about the child*/ parent->signal_cb(parent, LV_SIGNAL_CHILD_CHG, obj); @@ -764,391 +606,6 @@ void lv_obj_move_background(lv_obj_t * obj) * Coordinate set * ------------------*/ -/** - * Set relative the position of an object (relative to the parent) - * @param obj pointer to an object - * @param x new distance from the left side of the parent - * @param y new distance from the top of the parent - */ -void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - /*Convert x and y to absolute coordinates*/ - lv_obj_t * par = obj->parent; - - if(par) { - x = x + par->coords.x1; - y = y + par->coords.y1; - } - - - /*Calculate and set the movement*/ - lv_point_t diff; - diff.x = x - obj->coords.x1; - diff.y = y - obj->coords.y1; - - /* Do nothing if the position is not changed */ - /* It is very important else recursive positioning can - * occur without position change*/ - if(diff.x == 0 && diff.y == 0) return; - - /*Invalidate the original area*/ - lv_obj_invalidate(obj); - - /*Save the original coordinates*/ - lv_area_t ori; - lv_obj_get_coords(obj, &ori); - - obj->coords.x1 += diff.x; - obj->coords.y1 += diff.y; - obj->coords.x2 += diff.x; - obj->coords.y2 += diff.y; - - refresh_children_position(obj, diff.x, diff.y); - - /*Inform the object about its new coordinates*/ - obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori); - - /*Send a signal to the parent too*/ - if(par) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj); - - /*Invalidate the new area*/ - lv_obj_invalidate(obj); -} - -/** - * Set the x coordinate of a object - * @param obj pointer to an object - * @param x new distance from the left side from the parent - */ -void lv_obj_set_x(lv_obj_t * obj, lv_coord_t x) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_obj_set_pos(obj, x, lv_obj_get_y(obj)); -} - -/** - * Set the y coordinate of a object - * @param obj pointer to an object - * @param y new distance from the top of the parent - */ -void lv_obj_set_y(lv_obj_t * obj, lv_coord_t y) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_obj_set_pos(obj, lv_obj_get_x(obj), y); -} - -/** - * Set the size of an object - * @param obj pointer to an object - * @param w new width - * @param h new height - */ -void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - /* Do nothing if the size is not changed */ - /* It is very important else recursive resizing can - * occur without size change*/ - if(lv_obj_get_width(obj) == w && lv_obj_get_height(obj) == h) { - return; - } - - /*Invalidate the original area*/ - lv_obj_invalidate(obj); - - /*Save the original coordinates*/ - lv_area_t ori; - lv_obj_get_coords(obj, &ori); - - /*Set the length and height*/ - obj->coords.y2 = obj->coords.y1 + h - 1; - if(lv_obj_get_base_dir(obj) == LV_BIDI_DIR_RTL) { - obj->coords.x1 = obj->coords.x2 - w + 1; - } - else { - obj->coords.x2 = obj->coords.x1 + w - 1; - } - - /*Send a signal to the object with its new coordinates*/ - obj->signal_cb(obj, LV_SIGNAL_COORD_CHG, &ori); - - /*Send a signal to the parent too*/ - lv_obj_t * par = lv_obj_get_parent(obj); - if(par != NULL) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj); - - /*Tell the children the parent's size has changed*/ - lv_obj_t * i; - _LV_LL_READ(obj->child_ll, i) { - i->signal_cb(i, LV_SIGNAL_PARENT_SIZE_CHG, &ori); - } - - /*Invalidate the new area*/ - lv_obj_invalidate(obj); - - /*Automatically realign the object if required*/ -#if LV_USE_OBJ_REALIGN - if(obj->realign.auto_realign) lv_obj_realign(obj); -#endif -} - -/** - * Set the width of an object - * @param obj pointer to an object - * @param w new width - */ -void lv_obj_set_width(lv_obj_t * obj, lv_coord_t w) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_obj_set_size(obj, w, lv_obj_get_height(obj)); -} - -/** - * Set the height of an object - * @param obj pointer to an object - * @param h new height - */ -void lv_obj_set_height(lv_obj_t * obj, lv_coord_t h) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_obj_set_size(obj, lv_obj_get_width(obj), h); -} - -/** - * Set the width reduced by the left and right padding. - * @param obj pointer to an object - * @param w the width without paddings - */ -void lv_obj_set_width_fit(lv_obj_t * obj, lv_coord_t w) -{ - lv_style_int_t pleft = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN); - lv_style_int_t pright = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN); - - lv_obj_set_width(obj, w - pleft - pright); -} - -/** - * Set the height reduced by the top and bottom padding. - * @param obj pointer to an object - * @param h the height without paddings - */ -void lv_obj_set_height_fit(lv_obj_t * obj, lv_coord_t h) -{ - lv_style_int_t ptop = lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN); - lv_style_int_t pbottom = lv_obj_get_style_pad_bottom(obj, LV_OBJ_PART_MAIN); - - lv_obj_set_height(obj, h - ptop - pbottom); -} - -/** - * Set the width of an object by taking the left and right margin into account. - * The object width will be `obj_w = w - margin_left - margin_right` - * @param obj pointer to an object - * @param w new height including margins - */ -void lv_obj_set_width_margin(lv_obj_t * obj, lv_coord_t w) -{ - lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN); - lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN); - - lv_obj_set_width(obj, w - mleft - mright); -} - -/** - * Set the height of an object by taking the top and bottom margin into account. - * The object height will be `obj_h = h - margin_top - margin_bottom` - * @param obj pointer to an object - * @param h new height including margins - */ -void lv_obj_set_height_margin(lv_obj_t * obj, lv_coord_t h) -{ - lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN); - lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN); - - lv_obj_set_height(obj, h - mtop - mbottom); -} - -/** - * Align an object to an other object. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param x_ofs x coordinate offset after alignment - * @param y_ofs y coordinate offset after alignment - */ -void lv_obj_align(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) base = lv_obj_get_parent(obj); - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - obj_align_core(obj, base, align, true, true, x_ofs, y_ofs); - -#if LV_USE_OBJ_REALIGN - /*Save the last align parameters to use them in `lv_obj_realign`*/ - obj->realign.align = align; - obj->realign.xofs = x_ofs; - obj->realign.yofs = y_ofs; - obj->realign.base = base; - obj->realign.mid_align = 0; -#endif -} - -/** - * Align an object to an other object horizontally. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param x_ofs x coordinate offset after alignment - */ -void lv_obj_align_x(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) base = lv_obj_get_parent(obj); - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - obj_align_core(obj, base, align, true, false, x_ofs, 0); -} - -/** - * Align an object to an other object vertically. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param y_ofs y coordinate offset after alignment - */ -void lv_obj_align_y(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t y_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) base = lv_obj_get_parent(obj); - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - obj_align_core(obj, base, align, false, true, 0, y_ofs); -} - -/** - * Align an object's middle point to an other object. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param x_ofs x coordinate offset after alignment - * @param y_ofs y coordinate offset after alignment - */ -void lv_obj_align_mid(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) { - base = lv_obj_get_parent(obj); - } - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - - obj_align_mid_core(obj, base, align, true, true, x_ofs, y_ofs); - -#if LV_USE_OBJ_REALIGN - /*Save the last align parameters to use them in `lv_obj_realign`*/ - obj->realign.align = align; - obj->realign.xofs = x_ofs; - obj->realign.yofs = y_ofs; - obj->realign.base = base; - obj->realign.mid_align = 1; -#endif -} - -/** - * Align an object's middle point to an other object horizontally. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param x_ofs x coordinate offset after alignment - */ -void lv_obj_align_mid_x(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t x_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) { - base = lv_obj_get_parent(obj); - } - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - - obj_align_mid_core(obj, base, align, true, false, x_ofs, 0); -} - - -/** - * Align an object's middle point to an other object vertically. - * @param obj pointer to an object to align - * @param base pointer to an object (if NULL the parent is used). 'obj' will be aligned to it. - * @param align type of alignment (see 'lv_align_t' enum) - * @param y_ofs y coordinate offset after alignment - */ -void lv_obj_align_mid_y(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, lv_coord_t y_ofs) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(base == NULL) { - base = lv_obj_get_parent(obj); - } - - LV_ASSERT_OBJ(base, LV_OBJX_NAME); - - - obj_align_mid_core(obj, base, align, false, true, 0, y_ofs); -} - -/** - * Realign the object based on the last `lv_obj_align` parameters. - * @param obj pointer to an object - */ -void lv_obj_realign(lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#if LV_USE_OBJ_REALIGN - if(obj->realign.mid_align) - lv_obj_align_mid(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); - else - lv_obj_align(obj, obj->realign.base, obj->realign.align, obj->realign.xofs, obj->realign.yofs); -#else - (void)obj; - LV_LOG_WARN("lv_obj_realign: no effect because LV_USE_OBJ_REALIGN = 0"); -#endif -} - -/** - * Enable the automatic realign of the object when its size has changed based on the last - * `lv_obj_align` parameters. - * @param obj pointer to an object - * @param en true: enable auto realign; false: disable auto realign - */ -void lv_obj_set_auto_realign(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#if LV_USE_OBJ_REALIGN - obj->realign.auto_realign = en ? 1 : 0; -#else - (void)obj; - (void)en; - LV_LOG_WARN("lv_obj_set_auto_realign: no effect because LV_USE_OBJ_REALIGN = 0"); -#endif -} /** @@ -1166,497 +623,41 @@ void lv_obj_set_ext_click_area(lv_obj_t * obj, lv_coord_t left, lv_coord_t right LV_ASSERT_OBJ(obj, LV_OBJX_NAME); #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; + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + objrare_attr->->ext_click_pad.x1 = left; + objrare_attr->->ext_click_pad.x2 = right; + objrare_attr->->ext_click_pad.y1 = top; + objrare_attr->->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); + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + obj->spec_attr->ext_click_pad = LV_MATH_MAX4(left, right, top, bottom); #else - (void)obj; /*Unused*/ - (void)left; /*Unused*/ - (void)right; /*Unused*/ - (void)top; /*Unused*/ - (void)bottom; /*Unused*/ + LV_UNUSED(obj); + LV_UNUSED(left); + LV_UNUSED(right); + LV_UNUSED(top); + LV_UNUSED(bottom); #endif } +/** + * Get the extended draw area of an object. + * @param obj pointer to an object + * @return the size extended draw area around the real coordinates + */ +lv_coord_t _lv_obj_get_ext_draw_pad(const lv_obj_t * obj) +{ + if(obj->spec_attr) return obj->spec_attr->ext_draw_pad; + else return 0; +} /*--------------------- * Appearance set *--------------------*/ -/** - * Add a new style to the style list of an object. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param style pointer to a style to add (Only its pointer will be saved) - */ -void lv_obj_add_style(lv_obj_t * obj, uint8_t part, lv_style_t * style) -{ - if(style == NULL) return; - - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - if(style_dsc == NULL) { - LV_LOG_WARN("Can't find style with part: %d", part); - return; - } - - _lv_style_list_add_style(style_dsc, style); -#if LV_USE_ANIMATION - trans_del(obj, part, 0xFF, NULL); -#endif - lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); -} - -/** - * Remove a style from the style list of an object. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param style pointer to a style to remove - */ -void lv_obj_remove_style(lv_obj_t * obj, uint8_t part, lv_style_t * style) -{ - if(style == NULL) return; - - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - if(style_dsc == NULL) { - LV_LOG_WARN("Can't find style with part: %d", part); - return; - } - - _lv_style_list_remove_style(style_dsc, style); -#if LV_USE_ANIMATION - trans_del(obj, part, 0xFF, NULL); -#endif - lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); -} - -/** - * Reset a style to the default (empty) state. - * Release all used memories and cancel pending related transitions. - * Typically used in `LV_SIGN_CLEAN_UP. - * @param obj pointer to an object - * @param part the part of the object which style list should be reseted. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - */ -void lv_obj_clean_style_list(lv_obj_t * obj, uint8_t part) -{ - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - if(style_dsc == NULL) { - LV_LOG_WARN("lv_obj_clean_style_list: can't find style with `part`"); - return; - } - - _lv_style_list_reset(style_dsc); -#if LV_USE_ANIMATION - trans_del(obj, part, 0xFF, NULL); -#endif -} - -/** - * Reset a style to the default (empty) state. - * Release all used memories and cancel pending related transitions. - * Also notifies the object about the style change. - * @param obj pointer to an object - * @param part the part of the object which style list should be reseted. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - */ -void lv_obj_reset_style_list(lv_obj_t * obj, uint8_t part) -{ - lv_obj_clean_style_list(obj, part); - - lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); -} - -/** - * Set a local style property of a part of an object in a given state. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop a style property ORed with a state. - * E.g. `LV_STYLE_BORDER_WIDTH | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)` - * @param the value to set - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has integer type - */ -void _lv_obj_set_style_local_int(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_int_t value) -{ - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - _lv_style_list_set_local_int(style_dsc, prop, value); -#if LV_USE_ANIMATION - trans_del(obj, part, prop, NULL); -#endif - lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK)); -} - -/** - * Set a local style property of a part of an object in a given state. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop a style property ORed with a state. - * E.g. `LV_STYLE_BORDER_COLOR | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)` - * @param the value to set - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has color type - */ -void _lv_obj_set_style_local_color(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_color_t color) -{ - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - _lv_style_list_set_local_color(style_dsc, prop, color); -#if LV_USE_ANIMATION - trans_del(obj, part, prop, NULL); -#endif - lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK)); -} - -/** - * Set a local style property of a part of an object in a given state. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop a style property ORed with a state. - * E.g. `LV_STYLE_BORDER_OPA | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)` - * @param the value to set - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has opacity type - */ -void _lv_obj_set_style_local_opa(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_opa_t opa) -{ - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - _lv_style_list_set_local_opa(style_dsc, prop, opa); -#if LV_USE_ANIMATION - trans_del(obj, part, prop, NULL); -#endif - lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK)); -} - -/** - * Set a local style property of a part of an object in a given state. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop a style property ORed with a state. - * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)` - * @param value the value to set - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has pointer type - */ -void _lv_obj_set_style_local_ptr(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, const void * value) -{ - lv_style_list_t * style_dsc = lv_obj_get_style_list(obj, part); - _lv_style_list_set_local_ptr(style_dsc, prop, value); -#if LV_USE_ANIMATION - trans_del(obj, part, prop, NULL); -#endif - lv_obj_refresh_style(obj, part, prop & (~LV_STYLE_STATE_MASK)); -} - -/** - * Remove a local style property from a part of an object with a given state. - * @param obj pointer to an object - * @param part the part of the object which style property should be removed. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop a style property ORed with a state. - * E.g. `LV_STYLE_TEXT_FONT | (LV_STATE_PRESSED << LV_STYLE_STATE_POS)` - * @note shouldn't be used directly. Use the specific property remove functions instead. - * For example: `lv_obj_style_remove_border_opa()` - * @return true: the property was found and removed; false: the property was not found - */ -bool lv_obj_remove_style_local_prop(lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - lv_style_t * style = lv_obj_get_local_style(obj, part); - if(style) return lv_style_remove_prop(style, prop); - else return false; -} - -/** - * Notify an object (and its children) about its style is modified - * @param obj pointer to an object - * @param part the part of the object which style property should be refreshed. - * @param prop `LV_STYLE_PROP_ALL` or an `LV_STYLE_...` property. It is used to optimize what needs to be refreshed. - */ -void lv_obj_refresh_style(lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - invalidate_style_cache(obj, part, prop); - - /*If a real style refresh is required*/ - bool real_refr = false; - switch(prop) { - case LV_STYLE_PROP_ALL: - case LV_STYLE_CLIP_CORNER: - case LV_STYLE_SIZE: - case LV_STYLE_TRANSFORM_WIDTH: - case LV_STYLE_TRANSFORM_HEIGHT: - case LV_STYLE_TRANSFORM_ANGLE: - case LV_STYLE_TRANSFORM_ZOOM: - case LV_STYLE_PAD_TOP: - case LV_STYLE_PAD_BOTTOM: - case LV_STYLE_PAD_LEFT: - case LV_STYLE_PAD_RIGHT: - case LV_STYLE_PAD_INNER: - case LV_STYLE_MARGIN_TOP: - case LV_STYLE_MARGIN_BOTTOM: - case LV_STYLE_MARGIN_LEFT: - case LV_STYLE_MARGIN_RIGHT: - case LV_STYLE_OUTLINE_WIDTH: - case LV_STYLE_OUTLINE_PAD: - case LV_STYLE_OUTLINE_OPA: - case LV_STYLE_SHADOW_WIDTH: - case LV_STYLE_SHADOW_OPA: - case LV_STYLE_SHADOW_OFS_X: - case LV_STYLE_SHADOW_OFS_Y: - case LV_STYLE_SHADOW_SPREAD: - case LV_STYLE_VALUE_LETTER_SPACE: - case LV_STYLE_VALUE_LINE_SPACE: - case LV_STYLE_VALUE_OFS_X: - case LV_STYLE_VALUE_OFS_Y: - case LV_STYLE_VALUE_ALIGN: - case LV_STYLE_VALUE_STR: - case LV_STYLE_VALUE_FONT: - case LV_STYLE_VALUE_OPA: - case LV_STYLE_TEXT_LETTER_SPACE: - case LV_STYLE_TEXT_LINE_SPACE: - case LV_STYLE_TEXT_FONT: - case LV_STYLE_LINE_WIDTH: - real_refr = true; - break; - default: - real_refr = false; - } - - if(real_refr) { - lv_obj_invalidate(obj); - obj->signal_cb(obj, LV_SIGNAL_STYLE_CHG, NULL); - - switch(prop) { - case LV_STYLE_PROP_ALL: - case LV_STYLE_MARGIN_TOP: - case LV_STYLE_MARGIN_BOTTOM: - case LV_STYLE_MARGIN_LEFT: - case LV_STYLE_MARGIN_RIGHT: - if(obj->parent) obj->parent->signal_cb(obj->parent, LV_SIGNAL_CHILD_CHG, NULL); - break; - } - - lv_obj_invalidate(obj); - - /*Send style change signals*/ - if(prop == LV_STYLE_PROP_ALL || (prop & LV_STYLE_INHERIT_MASK)) refresh_children_style(obj); - } - else { - lv_obj_invalidate(obj); - } -} - -/** - * Notify all object if a style is modified - * @param style pointer to a style. Only the objects with this style will be notified - * (NULL to notify all objects) - */ -void lv_obj_report_style_mod(lv_style_t * style) -{ - lv_disp_t * d = lv_disp_get_next(NULL); - - while(d) { - lv_obj_t * i; - _LV_LL_READ(d->scr_ll, i) { - report_style_mod_core(style, i); - } - d = lv_disp_get_next(d); - } -} - -/** - * Enable/disable the use of style cahche for an object - * @param obj pointer to an object - * @param dis true: disable; false: enable (re-enable) - */ -void _lv_obj_disable_style_caching(lv_obj_t * obj, bool dis) -{ - uint8_t part; - for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - list->ignore_cache = dis; - } - for(part = _LV_OBJ_PART_REAL_FIRST; part < 0xFF; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - list->ignore_cache = dis; - } -} - /*----------------- * Attribute set *----------------*/ -/** - * Hide an object. It won't be visible and clickable. - * @param obj pointer to an object - * @param en true: hide the object - */ -void lv_obj_set_hidden(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ - - obj->hidden = en == false ? 0 : 1; - - if(!obj->hidden) lv_obj_invalidate(obj); /*Invalidate when not hidden (hidden objects are ignored) */ - - lv_obj_t * par = lv_obj_get_parent(obj); - if(par) par->signal_cb(par, LV_SIGNAL_CHILD_CHG, obj); -} - -/** - * Set whether advanced hit-testing is enabled on an object - * @param obj pointer to an object - * @param en true: advanced hit-testing is enabled - */ -void lv_obj_set_adv_hittest(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->adv_hittest = en == false ? 0 : 1; -} - -/** - * Enable or disable the clicking of an object - * @param obj pointer to an object - * @param en true: make the object clickable - */ -void lv_obj_set_click(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->click = (en == true ? 1 : 0); -} - -/** - * Enable to bring this object to the foreground if it - * or any of its children is clicked - * @param obj pointer to an object - * @param en true: enable the auto top feature - */ -void lv_obj_set_top(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->top = (en == true ? 1 : 0); -} - -/** - * Enable the dragging of an object - * @param obj pointer to an object - * @param en true: make the object draggable - */ -void lv_obj_set_drag(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(en == true) lv_obj_set_click(obj, true); /*Drag is useless without enabled clicking*/ - obj->drag = (en == true ? 1 : 0); -} - -/** - * Set the directions an object can be dragged in - * @param obj pointer to an object - * @param drag_dir bitwise OR of allowed directions an object can be dragged in - */ -void lv_obj_set_drag_dir(lv_obj_t * obj, lv_drag_dir_t drag_dir) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->drag_dir = drag_dir; - - if(obj->drag_dir != 0) lv_obj_set_drag(obj, true); /*Drag direction requires drag*/ -} - -/** - * Enable the throwing of an object after is is dragged - * @param obj pointer to an object - * @param en true: enable the drag throw - */ -void lv_obj_set_drag_throw(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->drag_throw = (en == true ? 1 : 0); -} - -/** - * Enable to use parent for drag related operations. - * If trying to drag the object the parent will be moved instead - * @param obj pointer to an object - * @param en true: enable the 'drag parent' for the object - */ -void lv_obj_set_drag_parent(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->drag_parent = (en == true ? 1 : 0); -} - -/** -* Enable to use parent for gesture related operations. -* If trying to gesture the object the parent will be moved instead -* @param obj pointer to an object -* @param en true: enable the 'gesture parent' for the object -*/ -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 - * @param en true: enable the event propagation - */ -void lv_obj_set_parent_event(lv_obj_t * obj, bool en) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - obj->parent_event = (en == true ? 1 : 0); -} - /** * Set the base direction of the object * @param obj pointer to an object @@ -1671,7 +672,8 @@ void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir) return; } - obj->base_dir = dir; + lv_obj_allocate_spec_attr(obj); + obj->spec_attr->base_dir = dir; lv_signal_send(obj, LV_SIGNAL_BASE_DIR_CHG, NULL); /* Notify the children about the parent base dir has changed. @@ -1679,31 +681,25 @@ void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir) base_dir_refr_children(obj); } -/** - * Set a bit or bits in the protect filed - * @param obj pointer to an object - * @param prot 'OR'-ed values from `lv_protect_t` - */ -void lv_obj_add_protect(lv_obj_t * obj, uint8_t prot) + +void lv_obj_add_flag(lv_obj_t * obj, lv_obj_flag_t f) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - obj->protect |= prot; + obj->flags |= f; } -/** - * Clear a bit or bits in the protect filed - * @param obj pointer to an object - * @param prot 'OR'-ed values from `lv_protect_t` - */ -void lv_obj_clear_protect(lv_obj_t * obj, uint8_t prot) + + +void lv_obj_clear_flag(lv_obj_t * obj, lv_obj_flag_t f) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - prot = (~prot) & 0xFF; - obj->protect &= prot; + obj->flags &= (~f); } + + /** * Set the state (fully overwrite) of an object. * If specified in the styles a transition animation will be started @@ -1717,43 +713,22 @@ void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); +#if LV_USE_ANIMATION == 0 + obj->state = new_state; + _lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); +#else lv_state_t prev_state = obj->state; - style_snapshot_res_t cmp_res = STYLE_COMPARE_SAME; - uint8_t part; - for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) { - lv_style_list_t * style_list = lv_obj_get_style_list(obj, part); - if(style_list == NULL) break; /*No more style lists*/ - obj->state = prev_state; - style_snapshot_t shot_pre; - style_snapshot(obj, part, &shot_pre); - obj->state = new_state; - style_snapshot_t shot_post; - style_snapshot(obj, part, &shot_post); - style_snapshot_res_t r = style_snapshot_compare(&shot_pre, &shot_post); - if(r == STYLE_COMPARE_DIFF) { - cmp_res = STYLE_COMPARE_DIFF; - break; - } - if(r == STYLE_COMPARE_VISUAL_DIFF) { - cmp_res = STYLE_COMPARE_VISUAL_DIFF; - } - } + _lv_style_state_cmp_t cmp_res = _lv_obj_style_state_compare(obj, prev_state, new_state); obj->state = new_state; - if(cmp_res == STYLE_COMPARE_SAME) { - return; - } + /*If there is no difference in styles there is nothing else to do*/ + if(cmp_res == _LV_STYLE_STATE_CMP_SAME) return; -#if LV_USE_ANIMATION == 0 - if(cmp_res == STYLE_COMPARE_DIFF) lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); - else if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); -#else - - - for(part = 0; part < _LV_OBJ_PART_REAL_LAST; part++) { - lv_style_list_t * style_list = lv_obj_get_style_list(obj, part); + uint8_t part; + for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) { + lv_style_list_t * style_list = _lv_obj_get_style_list(obj, part); if(style_list == NULL) break; /*No more style lists*/ if(style_list->ignore_trans) continue; @@ -1773,45 +748,26 @@ void lv_obj_set_state(lv_obj_t * obj, lv_state_t new_state) if(props[i] != 0) { _lv_style_list_add_trans_style(style_list); - lv_style_trans_t * tr = trans_create(obj, props[i], part, prev_state, new_state); - - /*If there is a pending anim for this property remove it*/ - if(tr) { - tr->obj = obj; - tr->prop = props[i]; - tr->part = part; - - lv_anim_t a; - lv_anim_init(&a); - lv_anim_set_var(&a, tr); - lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)trans_anim_cb); - lv_anim_set_start_cb(&a, trans_anim_start_cb); - lv_anim_set_ready_cb(&a, trans_anim_ready_cb); - lv_anim_set_values(&a, 0x00, 0xFF); - lv_anim_set_time(&a, time); - lv_anim_set_delay(&a, delay); - lv_anim_set_path(&a, path); - a.early_apply = 0; - lv_anim_start(&a); - } + _lv_obj_create_style_transition(obj, props[i], part, prev_state, new_state, time, delay, path); } } - if(cmp_res == STYLE_COMPARE_DIFF) lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); - - if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) { - invalidate_style_cache(obj, part, LV_STYLE_PROP_ALL); + if(cmp_res == _LV_STYLE_STATE_CMP_VISUAL_DIFF) { +#if LV_STYLE_CACHE_LEVEL > 0 + _lv_obj_invalidate_style_cache(obj, part, LV_STYLE_PROP_ALL); +#endif } - } - if(cmp_res == STYLE_COMPARE_VISUAL_DIFF) { - lv_obj_invalidate(obj); } + if(cmp_res == _LV_STYLE_STATE_CMP_DIFF) _lv_obj_refresh_style(obj, LV_OBJ_PART_ALL, LV_STYLE_PROP_ALL); + else if(cmp_res == _LV_STYLE_STATE_CMP_VISUAL_DIFF) lv_obj_invalidate(obj); #endif + } + /** * Add a given state or states to the object. The other state bits will remain unchanged. * If specified in the styles a transition animation will be started @@ -1846,26 +802,6 @@ void lv_obj_clear_state(lv_obj_t * obj, lv_state_t state) } } -#if LV_USE_ANIMATION -/** - * Finish all pending transitions on a part of an object - * @param obj pointer to an object - * @param part part of the object, e.g `LV_BRN_PART_MAIN` or `LV_OBJ_PART_ALL` for all parts - */ -void lv_obj_finish_transitions(lv_obj_t * obj, uint8_t part) -{ - /*Animate all related transition to the end value*/ - lv_style_trans_t * tr; - _LV_LL_READ_BACK(LV_GC_ROOT(_lv_obj_style_trans_ll), tr) { - if(tr->obj == obj && (part == tr->part || part == LV_OBJ_PART_ALL)) { - trans_anim_cb(tr, 255); - } - } - - /*Free all related transition data*/ - trans_del(obj, part, 0xFF, NULL); -} -#endif /** * Set a an event handler function for an object. @@ -1876,8 +812,9 @@ void lv_obj_finish_transitions(lv_obj_t * obj, uint8_t part) void lv_obj_set_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + if(obj->spec_attr == NULL) obj->spec_attr = lv_obj_allocate_spec_attr(obj); - obj->event_cb = event_cb; + obj->spec_attr->event_cb = event_cb; } /** @@ -1894,13 +831,13 @@ lv_res_t lv_event_send(lv_obj_t * obj, lv_event_t event, const void * data) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_res_t res; - res = lv_event_send_func(obj->event_cb, obj, event, data); + res = lv_event_send_func(lv_obj_get_event_cb(obj), obj, event, data); return res; } /** * Send LV_EVENT_REFRESH event to an object - * @param obj point to an object. (Can NOT be NULL) + * @param obj point to an obejct. (Can NOT be NULL) * @return LV_RES_OK: success, LV_RES_INV: to object become invalid (e.g. deleted) due to this event. */ lv_res_t lv_event_send_refresh(lv_obj_t * obj) @@ -1934,11 +871,10 @@ void lv_event_send_refresh_recursive(lv_obj_t * obj) lv_res_t res = lv_event_send_refresh(obj); if(res != LV_RES_OK) return; /*If invalid returned do not check the children*/ - lv_obj_t * child = lv_obj_get_child(obj, NULL); - while(child) { + lv_obj_t * child; + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ(ll, child) { lv_event_send_refresh_recursive(child); - - child = lv_obj_get_child(obj, child); } } } @@ -1996,7 +932,8 @@ lv_res_t lv_event_send_func(lv_event_cb_t event_xcb, lv_obj_t * obj, lv_event_t } if(obj) { - if(obj->parent_event && obj->parent) { + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE) && obj->parent) { + lv_res_t res = lv_event_send(obj->parent, event, data); if(res != LV_RES_OK) { return LV_RES_INV; @@ -2073,6 +1010,7 @@ void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); void * new_ext = lv_mem_realloc(obj->ext_attr, ext_size); + LV_ASSERT_MEM(new_ext); if(new_ext == NULL) return NULL; obj->ext_attr = new_ext; @@ -2080,19 +1018,37 @@ void * lv_obj_allocate_ext_attr(lv_obj_t * obj, uint16_t ext_size) } /** - * Send a 'LV_SIGNAL_REFR_EXT_SIZE' signal to the object to refresh the extended draw area. - * he object needs to be invalidated by `lv_obj_invalidate(obj)` manually after this function. + * Allocate a new ext. data for an object * @param obj pointer to an object + * @param ext_size the size of the new ext. data + * @return pointer to the allocated ext. + * If out of memory NULL is returned and the original ext is preserved */ -void lv_obj_refresh_ext_draw_pad(lv_obj_t * obj) +lv_obj_spec_attr_t * lv_obj_allocate_spec_attr(lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - obj->ext_draw_pad = 0; - obj->signal_cb(obj, LV_SIGNAL_REFR_EXT_DRAW_PAD, NULL); + if(obj->spec_attr == NULL) { + static uint32_t x = 0; + x++; + obj->spec_attr = lv_mem_alloc(sizeof(lv_obj_spec_attr_t)); + LV_ASSERT_MEM(obj->spec_attr); + if(obj->spec_attr == NULL) return NULL; + + _lv_memset_00(obj->spec_attr, sizeof(lv_obj_spec_attr_t)); + _lv_ll_init(&(obj->spec_attr->child_ll), sizeof(lv_obj_t)); + + obj->spec_attr->scroll_dir = LV_DIR_ALL; + obj->spec_attr->base_dir = LV_BIDI_DIR_INHERIT; + obj->spec_attr->scroll_mode = LV_SCROLL_MODE_AUTO; + + } + return obj->spec_attr; } + + /*======================= * Getter functions *======================*/ @@ -2134,9 +1090,9 @@ lv_disp_t * lv_obj_get_disp(const lv_obj_t * obj) scr = lv_obj_get_screen(obj); /*get the screen of `obj`*/ lv_disp_t * d; - _LV_LL_READ(LV_GC_ROOT(_lv_disp_ll), d) { + _LV_LL_READ(&LV_GC_ROOT(_lv_disp_ll), d) { lv_obj_t * s; - _LV_LL_READ(d->scr_ll, s) { + _LV_LL_READ(&d->scr_ll, s) { if(s == scr) return d; } } @@ -2172,16 +1128,9 @@ lv_obj_t * lv_obj_get_child(const lv_obj_t * obj, const lv_obj_t * child) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - lv_obj_t * result = NULL; - - if(child == NULL) { - result = _lv_ll_get_head(&obj->child_ll); - } - else { - result = _lv_ll_get_next(&obj->child_ll, child); - } - - return result; + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + if (child) return _lv_ll_get_next(ll, child); + else return _lv_ll_get_head(ll); } /** @@ -2195,16 +1144,53 @@ lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - lv_obj_t * result = NULL; + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + if(child) return _lv_ll_get_prev(ll, child); + else return _lv_ll_get_tail(ll); +} - if(child == NULL) { - result = _lv_ll_get_tail(&obj->child_ll); - } - else { - result = _lv_ll_get_prev(&obj->child_ll, child); +/** + * Get the Nth child of an object. 0th is the lastly created. + * @param obj pointer to an object whose children should be get + * @param id of a child + * @return the child or `NULL` if `id` was greater then the `number of children - 1` + */ +lv_obj_t * lv_obj_get_child_by_id(const lv_obj_t * obj, uint32_t id) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + + lv_obj_t * child = lv_obj_get_child_back(obj, NULL); + uint32_t i; + for(i = 0; i < id; i++) { + child = lv_obj_get_child_back(obj, child); } - return result; + return child; +} + +/** + * Get the child index of an object. + * If this object is the firstly created child of its parent 0 will be return. + * If its the second child return 1, etc. + * @param obj pointer to an object whose index should be get + * @return the child index of the object. + */ +uint32_t lv_obj_get_child_id(const lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, LV_OBJX_NAME); + + lv_obj_t * parent = lv_obj_get_parent(obj); + if(parent == NULL) return 0; + + uint32_t id = 0; + lv_obj_t * child; + + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ_BACK(ll, child) { + if(child == obj) return id; + id++; + } + return id; } /** @@ -2212,14 +1198,15 @@ lv_obj_t * lv_obj_get_child_back(const lv_obj_t * obj, const lv_obj_t * child) * @param obj pointer to an object * @return children number of 'obj' */ -uint16_t lv_obj_count_children(const lv_obj_t * obj) +uint32_t lv_obj_count_children(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_t * i; uint16_t cnt = 0; - _LV_LL_READ(obj->child_ll, i) cnt++; + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ(ll, i) cnt++; return cnt; } @@ -2228,14 +1215,15 @@ uint16_t lv_obj_count_children(const lv_obj_t * obj) * @param obj pointer to an object * @return children number of 'obj' */ -uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj) +uint32_t lv_obj_count_children_recursive(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); lv_obj_t * i; uint16_t cnt = 0; - _LV_LL_READ(obj->child_ll, i) { + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ(ll, i) { cnt++; /*Count the child*/ cnt += lv_obj_count_children_recursive(i); /*recursively count children's children*/ } @@ -2248,827 +1236,109 @@ uint16_t lv_obj_count_children_recursive(const lv_obj_t * obj) *--------------------*/ /** - * Copy the coordinates of an object to an area - * @param obj pointer to an object - * @param cords_p pointer to an area to store the coordinates - */ -void lv_obj_get_coords(const lv_obj_t * obj, lv_area_t * cords_p) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_area_copy(cords_p, &obj->coords); -} - -/** - * Reduce area retried by `lv_obj_get_coords()` the get graphically usable area of an object. - * (Without the size of the border or other extra graphical elements) - * @param coords_p store the result area here - */ -void lv_obj_get_inner_coords(const lv_obj_t * obj, lv_area_t * coords_p) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_border_side_t part = lv_obj_get_style_border_side(obj, LV_OBJ_PART_MAIN); - lv_coord_t w = lv_obj_get_style_border_width(obj, LV_OBJ_PART_MAIN); - - if(part & LV_BORDER_SIDE_LEFT) coords_p->x1 += w; - - if(part & LV_BORDER_SIDE_RIGHT) coords_p->x2 -= w; - - if(part & LV_BORDER_SIDE_TOP) coords_p->y1 += w; - - if(part & LV_BORDER_SIDE_BOTTOM) coords_p->y2 -= w; -} - -/** - * Get the x coordinate of object - * @param obj pointer to an object - * @return distance of 'obj' from the left side of its parent - */ -lv_coord_t lv_obj_get_x(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_coord_t rel_x; - lv_obj_t * parent = lv_obj_get_parent(obj); - if(parent) { - rel_x = obj->coords.x1 - parent->coords.x1; - } - else { - rel_x = obj->coords.x1; - } - return rel_x; -} - -/** - * Get the y coordinate of object - * @param obj pointer to an object - * @return distance of 'obj' from the top of its parent - */ -lv_coord_t lv_obj_get_y(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_coord_t rel_y; - lv_obj_t * parent = lv_obj_get_parent(obj); - if(parent) { - rel_y = obj->coords.y1 - parent->coords.y1; - } - else { - rel_y = obj->coords.y1; - } - return rel_y; -} - -/** - * Get the width of an object - * @param obj pointer to an object - * @return the width - */ -lv_coord_t lv_obj_get_width(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return lv_area_get_width(&obj->coords); -} - -/** - * Get the height of an object - * @param obj pointer to an object - * @return the height - */ -lv_coord_t lv_obj_get_height(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return lv_area_get_height(&obj->coords); -} - -/** - * Get that width reduced by the left and right padding. - * @param obj pointer to an object - * @return the width which still fits into the container - */ -lv_coord_t lv_obj_get_width_fit(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_style_int_t left = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN); - lv_style_int_t right = lv_obj_get_style_pad_right(obj, LV_OBJ_PART_MAIN); - - return lv_obj_get_width(obj) - left - right; -} - -/** - * Get that height reduced by the top an bottom padding. - * @param obj pointer to an object - * @return the height which still fits into the container - */ -lv_coord_t lv_obj_get_height_fit(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - lv_style_int_t top = lv_obj_get_style_pad_top((lv_obj_t *)obj, LV_OBJ_PART_MAIN); - lv_style_int_t bottom = lv_obj_get_style_pad_bottom((lv_obj_t *)obj, LV_OBJ_PART_MAIN); - - return lv_obj_get_height(obj) - top - bottom; -} - -/** - * Get the height of an object by taking the top and bottom margin into account. - * The returned height will be `obj_h + margin_top + margin_bottom` - * @param obj pointer to an object - * @return the height including thee margins - */ -lv_coord_t lv_obj_get_height_margin(lv_obj_t * obj) -{ - lv_style_int_t mtop = lv_obj_get_style_margin_top(obj, LV_OBJ_PART_MAIN); - lv_style_int_t mbottom = lv_obj_get_style_margin_bottom(obj, LV_OBJ_PART_MAIN); - - return lv_obj_get_height(obj) + mtop + mbottom; -} - -/** - * Get the width of an object by taking the left and right margin into account. - * The returned width will be `obj_w + margin_left + margin_right` - * @param obj pointer to an object - * @return the height including thee margins - */ -lv_coord_t lv_obj_get_width_margin(lv_obj_t * obj) -{ - lv_style_int_t mleft = lv_obj_get_style_margin_left(obj, LV_OBJ_PART_MAIN); - lv_style_int_t mright = lv_obj_get_style_margin_right(obj, LV_OBJ_PART_MAIN); - - return lv_obj_get_width(obj) + mleft + mright; -} - -/** - * Set that width reduced by the left and right padding of the parent. - * @param obj pointer to an object - * @param div indicates how many columns are assumed. - * If 1 the width will be set the the parent's width - * If 2 only half parent width - inner padding of the parent - * If 3 only third parent width - 2 * inner padding of the parent - * @param span how many columns are combined - * @return the width according to the given parameters - */ -lv_coord_t lv_obj_get_width_grid(lv_obj_t * obj, uint8_t div, uint8_t span) -{ - lv_coord_t obj_w = lv_obj_get_width_fit(obj); - lv_style_int_t pinner = lv_obj_get_style_pad_inner(obj, LV_OBJ_PART_MAIN); - - lv_coord_t r = (obj_w - (div - 1) * pinner) / div; - - r = r * span + (span - 1) * pinner; - return r; -} - -/** - * Get that height reduced by the top and bottom padding of the parent. - * @param obj pointer to an object - * @param div indicates how many rows are assumed. - * If 1 the height will be set the the parent's height - * If 2 only half parent height - inner padding of the parent - * If 3 only third parent height - 2 * inner padding of the parent - * @param span how many rows are combined - * @return the height according to the given parameters - */ -lv_coord_t lv_obj_get_height_grid(lv_obj_t * obj, uint8_t div, uint8_t span) -{ - lv_coord_t obj_h = lv_obj_get_height_fit(obj); - lv_style_int_t pinner = lv_obj_get_style_pad_inner(obj, LV_OBJ_PART_MAIN); - - lv_coord_t r = (obj_h - (div - 1) * pinner) / div; - - r = r * span + (span - 1) * pinner; - return r; -} - -/** - * Get the automatic realign property of the object. - * @param obj pointer to an object - * @return true: auto realign is enabled; false: auto realign is disabled - */ -bool lv_obj_get_auto_realign(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#if LV_USE_OBJ_REALIGN - return obj->realign.auto_realign ? true : false; -#else - (void)obj; - return false; -#endif -} - -/** - * Get the left padding of extended clickable area + * Get the extended extended clickable area in a direction * @param obj pointer to an object + * @param dir in which direction get the extended area (`LV_DIR_LEFT/RIGHT/TOP`) * @return the extended left padding */ -lv_coord_t lv_obj_get_ext_click_pad_left(const lv_obj_t * obj) +lv_coord_t lv_obj_get_ext_click_area(const lv_obj_t * obj, lv_dir_t dir) { - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); -#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.x1; -#else - (void)obj; /*Unused*/ +#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_OFF + LV_UNUSED(obj); + LV_UNUSED(dir); return 0; +#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY + LV_UNUSED(dir); + if(obj->spec_attr) return obj->spec_attr->ext_click_pad; + else return 0; +#else + switch(dir) { + case LV_DIR_LEFT: + return obj->ext_click_pad.x1; + case LV_DIR_RIGHT: + return obj->ext_click_pad.x2; + case LV_DIR_TOP: + return obj->ext_click_pad.y1; + case LV_DIR_BOTTOM: + return obj->ext_click_pad.y2; + default: + return 0; + } +#endif +} + + +/** + * Check if a given screen-space point is on an object's coordinates. + * This method is intended to be used mainly by advanced hit testing algorithms to check + * whether the point is even within the object (as an optimization). + * @param obj object to check + * @param point screen-space point + */ +bool _lv_obj_is_click_point_on(lv_obj_t * obj, const lv_point_t * point) +{ +#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_OFF + return _lv_area_is_point_on(&obj->coords, point, 0); +#else + lv_area_t ext_area; + ext_area.x1 = obj->coords.x1 - lv_obj_get_ext_click_area(obj, LV_DIR_LEFT); + ext_area.x2 = obj->coords.x2 + lv_obj_get_ext_click_area(obj, LV_DIR_RIGHT); + ext_area.y1 = obj->coords.y1 - lv_obj_get_ext_click_area(obj, LV_DIR_TOP); + ext_area.y2 = obj->coords.y2 + lv_obj_get_ext_click_area(obj, LV_DIR_BOTTOM); + + return _lv_area_is_point_on(&ext_area, point, 0); #endif } /** - * Get the right padding of extended clickable area - * @param obj pointer to an object - * @return the extended right padding + * Hit-test an object given a particular point in screen space. + * @param obj object to hit-test + * @param point screen-space point + * @return true if the object is considered under the point */ -lv_coord_t lv_obj_get_ext_click_pad_right(const lv_obj_t * obj) +bool lv_obj_hit_test(lv_obj_t * obj, lv_point_t * point) { - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#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 - (void)obj; /*Unused*/ - return 0; -#endif + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_ADV_HITTEST)) { + lv_hit_test_info_t hit_info; + hit_info.point = point; + hit_info.result = true; + obj->signal_cb(obj, LV_SIGNAL_HIT_TEST, &hit_info); + return hit_info.result; + } + else { + return _lv_obj_is_click_point_on(obj, point); + } } - -/** - * 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) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#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 - (void)obj; /*Unused*/ - return 0; -#endif -} - -/** - * 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) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - -#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 - (void)obj; /*Unused*/ - return 0; -#endif -} - -/** - * Get the extended size attribute of an object - * @param obj pointer to an object - * @return the extended size attribute - */ -lv_coord_t lv_obj_get_ext_draw_pad(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->ext_draw_pad; -} - /*----------------- * Appearance get *---------------*/ -lv_style_list_t * lv_obj_get_style_list(const lv_obj_t * obj, uint8_t part) -{ - if(part == LV_OBJ_PART_MAIN) return &((lv_obj_t *)obj)->style_list; - - lv_get_style_info_t info; - info.part = part; - info.result = NULL; - - lv_res_t res; - res = lv_signal_send((lv_obj_t *)obj, LV_SIGNAL_GET_STYLE, &info); - - if(res != LV_RES_OK) return NULL; - - return info.result; -} - -/** - * Get a style property of a part of an object in the object's current state. - * If there is a running transitions it is taken into account - * @param obj pointer to an object - * @param part the part of the object which style property should be get. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop the property to get. E.g. `LV_STYLE_BORDER_WIDTH`. - * The state of the object will be added internally - * @return the value of the property of the given part in the current state. - * If the property is not found a default value will be returned. - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_width()` - * @note for performance reasons it's not checked if the property really has integer type - */ -lv_style_int_t _lv_obj_get_style_int(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - lv_style_property_t prop_ori = prop; - - lv_style_attr_t attr; - attr = prop_ori >> 8; - - lv_style_int_t value_act; - lv_res_t res = LV_RES_INV; - const lv_obj_t * parent = obj; - while(parent) { - lv_style_list_t * list = lv_obj_get_style_list(parent, part); - if(!list->ignore_cache && list->style_cnt > 0) { - if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop & (~LV_STYLE_STATE_MASK)); - - bool def = false; - switch(prop & (~LV_STYLE_STATE_MASK)) { - case LV_STYLE_CLIP_CORNER: - if(list->clip_corner_off) def = true; - break; - case LV_STYLE_TEXT_LETTER_SPACE: - case LV_STYLE_TEXT_LINE_SPACE: - if(list->text_space_zero) def = true; - break; - case LV_STYLE_TRANSFORM_ANGLE: - case LV_STYLE_TRANSFORM_WIDTH: - case LV_STYLE_TRANSFORM_HEIGHT: - case LV_STYLE_TRANSFORM_ZOOM: - if(list->transform_all_zero) def = true; - break; - case LV_STYLE_BORDER_WIDTH: - if(list->border_width_zero) def = true; - break; - case LV_STYLE_BORDER_SIDE: - if(list->border_side_full) def = true; - break; - case LV_STYLE_BORDER_POST: - if(list->border_post_off) def = true; - break; - case LV_STYLE_OUTLINE_WIDTH: - if(list->outline_width_zero) def = true; - break; - case LV_STYLE_RADIUS: - if(list->radius_zero) def = true; - break; - case LV_STYLE_SHADOW_WIDTH: - if(list->shadow_width_zero) def = true; - break; - case LV_STYLE_PAD_TOP: - case LV_STYLE_PAD_BOTTOM: - case LV_STYLE_PAD_LEFT: - case LV_STYLE_PAD_RIGHT: - if(list->pad_all_zero) def = true; - break; - case LV_STYLE_MARGIN_TOP: - case LV_STYLE_MARGIN_BOTTOM: - case LV_STYLE_MARGIN_LEFT: - case LV_STYLE_MARGIN_RIGHT: - if(list->margin_all_zero) def = true; - break; - case LV_STYLE_BG_BLEND_MODE: - case LV_STYLE_BORDER_BLEND_MODE: - case LV_STYLE_IMAGE_BLEND_MODE: - case LV_STYLE_LINE_BLEND_MODE: - case LV_STYLE_OUTLINE_BLEND_MODE: - case LV_STYLE_PATTERN_BLEND_MODE: - case LV_STYLE_SHADOW_BLEND_MODE: - case LV_STYLE_TEXT_BLEND_MODE: - case LV_STYLE_VALUE_BLEND_MODE: - if(list->blend_mode_all_normal) def = true; - break; - case LV_STYLE_TEXT_DECOR: - if(list->text_decor_none) def = true; - break; - } - - if(def) { - break; - } - } - - lv_state_t state = lv_obj_get_state(parent, part); - prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS); - - res = _lv_style_list_get_int(list, prop, &value_act); - if(res == LV_RES_OK) return value_act; - - if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break; - - /*If not found, check the `MAIN` style first*/ - if(part != LV_OBJ_PART_MAIN) { - part = LV_OBJ_PART_MAIN; - continue; - } - - /*Check the parent too.*/ - parent = lv_obj_get_parent(parent); - } - - /*Handle unset values*/ - prop = prop & (~LV_STYLE_STATE_MASK); - switch(prop) { - case LV_STYLE_BORDER_SIDE: - return LV_BORDER_SIDE_FULL; - case LV_STYLE_SIZE: - return LV_DPI / 20; - case LV_STYLE_SCALE_WIDTH: - return LV_DPI / 8; - case LV_STYLE_BG_GRAD_STOP: - return 255; - case LV_STYLE_TRANSFORM_ZOOM: - return LV_IMG_ZOOM_NONE; - } - - return 0; -} - -/** - * Get a style property of a part of an object in the object's current state. - * If there is a running transitions it is taken into account - * @param obj pointer to an object - * @param part the part of the object which style property should be get. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop the property to get. E.g. `LV_STYLE_BORDER_COLOR`. - * The state of the object will be added internally - * @return the value of the property of the given part in the current state. - * If the property is not found a default value will be returned. - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_color()` - * @note for performance reasons it's not checked if the property really has color type - */ -lv_color_t _lv_obj_get_style_color(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - lv_style_property_t prop_ori = prop; - - lv_style_attr_t attr; - attr = prop_ori >> 8; - - lv_color_t value_act; - lv_res_t res = LV_RES_INV; - const lv_obj_t * parent = obj; - while(parent) { - lv_style_list_t * list = lv_obj_get_style_list(parent, part); - - lv_state_t state = lv_obj_get_state(parent, part); - prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS); - - res = _lv_style_list_get_color(list, prop, &value_act); - if(res == LV_RES_OK) return value_act; - - if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break; - - /*If not found, check the `MAIN` style first*/ - if(part != LV_OBJ_PART_MAIN) { - part = LV_OBJ_PART_MAIN; - continue; - } - - /*Check the parent too.*/ - parent = lv_obj_get_parent(parent); - } - - /*Handle unset values*/ - prop = prop & (~LV_STYLE_STATE_MASK); - switch(prop) { - case LV_STYLE_BG_COLOR: - case LV_STYLE_BG_GRAD_COLOR: - return LV_COLOR_WHITE; - } - - return LV_COLOR_BLACK; -} - -/** - * Get a style property of a part of an object in the object's current state. - * If there is a running transitions it is taken into account - * @param obj pointer to an object - * @param part the part of the object which style property should be get. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop the property to get. E.g. `LV_STYLE_BORDER_OPA`. - * The state of the object will be added internally - * @return the value of the property of the given part in the current state. - * If the property is not found a default value will be returned. - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has opacity type - */ -lv_opa_t _lv_obj_get_style_opa(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - lv_style_property_t prop_ori = prop; - - lv_style_attr_t attr; - attr = prop_ori >> 8; - - lv_opa_t value_act; - lv_res_t res = LV_RES_INV; - const lv_obj_t * parent = obj; - while(parent) { - lv_style_list_t * list = lv_obj_get_style_list(parent, part); - - if(!list->ignore_cache && list->style_cnt > 0) { - if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop & (~LV_STYLE_STATE_MASK)); - bool def = false; - switch(prop & (~LV_STYLE_STATE_MASK)) { - case LV_STYLE_OPA_SCALE: - if(list->opa_scale_cover) def = true; - break; - case LV_STYLE_BG_OPA: - if(list->bg_opa_cover) return LV_OPA_COVER; /*Special case, not the default value is used*/ - if(list->bg_opa_transp) def = true; - break; - case LV_STYLE_IMAGE_RECOLOR_OPA: - if(list->img_recolor_opa_transp) def = true; - break; - } - - if(def) { - break; - } - } - - - lv_state_t state = lv_obj_get_state(parent, part); - prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS); - - res = _lv_style_list_get_opa(list, prop, &value_act); - if(res == LV_RES_OK) return value_act; - - if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break; - - /*If not found, check the `MAIN` style first*/ - if(part != LV_OBJ_PART_MAIN) { - part = LV_OBJ_PART_MAIN; - continue; - } - - /*Check the parent too.*/ - parent = lv_obj_get_parent(parent); - } - - /*Handle unset values*/ - prop = prop & (~LV_STYLE_STATE_MASK); - switch(prop) { - case LV_STYLE_BG_OPA: - case LV_STYLE_IMAGE_RECOLOR_OPA: - case LV_STYLE_PATTERN_RECOLOR_OPA: - return LV_OPA_TRANSP; - } - - return LV_OPA_COVER; -} - -/** - * Get a style property of a part of an object in the object's current state. - * If there is a running transitions it is taken into account - * @param obj pointer to an object - * @param part the part of the object which style property should be get. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @param prop the property to get. E.g. `LV_STYLE_TEXT_FONT`. - * The state of the object will be added internally - * @return the value of the property of the given part in the current state. - * If the property is not found a default value will be returned. - * @note shouldn't be used directly. Use the specific property get functions instead. - * For example: `lv_obj_style_get_border_opa()` - * @note for performance reasons it's not checked if the property really has pointer type - */ -const void * _lv_obj_get_style_ptr(const lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - lv_style_property_t prop_ori = prop; - - lv_style_attr_t attr; - attr = prop_ori >> 8; - - const void * value_act; - lv_res_t res = LV_RES_INV; - const lv_obj_t * parent = obj; - while(parent) { - lv_style_list_t * list = lv_obj_get_style_list(parent, part); - - if(!list->ignore_cache && list->style_cnt > 0) { - if(!list->valid_cache) update_style_cache((lv_obj_t *)parent, part, prop & (~LV_STYLE_STATE_MASK)); - bool def = false; - switch(prop & (~LV_STYLE_STATE_MASK)) { - case LV_STYLE_VALUE_STR: - if(list->value_txt_str) def = true; - break; - case LV_STYLE_PATTERN_IMAGE: - if(list->pattern_img_null) def = true; - break; - case LV_STYLE_TEXT_FONT: - if(list->text_font_normal) def = true; - break; - } - - if(def) { - break; - } - } - - lv_state_t state = lv_obj_get_state(parent, part); - prop = (uint16_t)prop_ori + ((uint16_t)state << LV_STYLE_STATE_POS); - - res = _lv_style_list_get_ptr(list, prop, &value_act); - if(res == LV_RES_OK) return value_act; - - if(LV_STYLE_ATTR_GET_INHERIT(attr) == 0) break; - - /*If not found, check the `MAIN` style first*/ - if(part != LV_OBJ_PART_MAIN) { - part = LV_OBJ_PART_MAIN; - continue; - } - - /*Check the parent too.*/ - parent = lv_obj_get_parent(parent); - } - - /*Handle unset values*/ - prop = prop & (~LV_STYLE_STATE_MASK); - switch(prop) { - case LV_STYLE_TEXT_FONT: - case LV_STYLE_VALUE_FONT: - return lv_theme_get_font_normal(); -#if LV_USE_ANIMATION - case LV_STYLE_TRANSITION_PATH: - return &lv_anim_path_def; -#endif - } - - return NULL; -} - -/** - * Get the local style of a part of an object. - * @param obj pointer to an object - * @param part the part of the object which style property should be set. - * E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_PART_MAIN`, `LV_SLIDER_PART_KNOB` - * @return pointer to the local style if exists else `NULL`. - */ -lv_style_t * lv_obj_get_local_style(lv_obj_t * obj, uint8_t part) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - lv_style_list_t * style_list = lv_obj_get_style_list(obj, part); - return lv_style_list_get_local_style(style_list); -} /*----------------- * Attribute get *----------------*/ -/** - * Get the hidden attribute of an object - * @param obj pointer to an object - * @return true: the object is hidden - */ -bool lv_obj_get_hidden(const lv_obj_t * obj) +bool lv_obj_has_flag(const lv_obj_t * obj, lv_obj_flag_t f) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - return obj->hidden == 0 ? false : true; + return obj->flags & f ? true : false; } -/** - * Get whether advanced hit-testing is enabled on an object - * @param obj pointer to an object - * @return true: advanced hit-testing is enabled - */ -bool lv_obj_get_adv_hittest(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->adv_hittest == 0 ? false : true; -} - -/** - * Get the click enable attribute of an object - * @param obj pointer to an object - * @return true: the object is clickable - */ -bool lv_obj_get_click(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->click == 0 ? false : true; -} - -/** - * Get the top enable attribute of an object - * @param obj pointer to an object - * @return true: the auto top feature is enabled - */ -bool lv_obj_get_top(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->top == 0 ? false : true; -} - -/** - * Get the drag enable attribute of an object - * @param obj pointer to an object - * @return true: the object is draggable - */ -bool lv_obj_get_drag(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->drag == 0 ? false : true; -} - -/** - * Get the directions an object can be dragged - * @param obj pointer to an object - * @return bitwise OR of allowed directions an object can be dragged in - */ -lv_drag_dir_t lv_obj_get_drag_dir(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->drag_dir; -} - -/** - * Get the drag throw enable attribute of an object - * @param obj pointer to an object - * @return true: drag throw is enabled - */ -bool lv_obj_get_drag_throw(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->drag_throw == 0 ? false : true; -} - -/** - * Get the drag parent attribute of an object - * @param obj pointer to an object - * @return true: drag parent is enabled - */ -bool lv_obj_get_drag_parent(const lv_obj_t * obj) -{ - return obj->drag_parent == 0 ? false : true; -} - -/** -* Get the gesture parent attribute of an object -* @param obj pointer to an object -* @return true: gesture parent is enabled -*/ -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 - * @return true: drag parent is enabled - */ -bool lv_obj_get_parent_event(const lv_obj_t * obj) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->parent_event == 0 ? false : true; -} - - lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); #if LV_USE_BIDI + if(obj->spec_attr == NULL) return LV_BIDI_DIR_LTR; const lv_obj_t * parent = obj; while(parent) { - if(parent->base_dir != LV_BIDI_DIR_INHERIT) return parent->base_dir; + /*If the base dir set use it. If not set assume INHERIT so got the next parent*/ + if(parent->spec_attr) { + if(parent->spec_attr->base_dir != LV_BIDI_DIR_INHERIT) return parent->spec_attr->base_dir; + } parent = lv_obj_get_parent(parent); } @@ -3080,47 +1350,11 @@ lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj) #endif } -/** - * Get the protect field of an object - * @param obj pointer to an object - * @return protect field ('OR'ed values of `lv_protect_t`) - */ -uint8_t lv_obj_get_protect(const lv_obj_t * obj) +lv_state_t lv_obj_get_state(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - return obj->protect; -} - -/** - * Check at least one bit of a given protect bitfield is set - * @param obj pointer to an object - * @param prot protect bits to test ('OR'ed values of `lv_protect_t`) - * @return false: none of the given bits are set, true: at least one bit is set - */ -bool lv_obj_is_protected(const lv_obj_t * obj, uint8_t prot) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return (obj->protect & prot) == 0 ? false : true; -} - -lv_state_t lv_obj_get_state(const lv_obj_t * obj, uint8_t part) -{ - LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - if(part < _LV_OBJ_PART_REAL_LAST) return ((lv_obj_t *)obj)->state; - - /*If a real part is asked, then use the object's signal to get its state. - * A real object can be in different state then the main part - * and only the object itself knows who to get it's state. */ - lv_get_state_info_t info; - info.part = part; - info.result = LV_STATE_DEFAULT; - lv_signal_send((lv_obj_t *)obj, LV_SIGNAL_GET_STATE_DSC, &info); - - return info.result; - + return ((lv_obj_t *)obj)->state; } /** @@ -3156,7 +1390,8 @@ lv_event_cb_t lv_obj_get_event_cb(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - return obj->event_cb; + if(obj->spec_attr) return obj->spec_attr->event_cb; + else return NULL; } /*------------------ @@ -3215,9 +1450,10 @@ void lv_obj_get_type(const lv_obj_t * obj, lv_obj_type_t * buf) */ lv_obj_user_data_t lv_obj_get_user_data(const lv_obj_t * obj) { + static lv_obj_user_data_t empty = {0}; LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - - return obj->user_data; + if(obj->spec_attr) return obj->spec_attr->user_data; + else return empty; } /** @@ -3229,7 +1465,8 @@ lv_obj_user_data_t * lv_obj_get_user_data_ptr(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - return (lv_obj_user_data_t *)&obj->user_data; + if(obj->spec_attr) return obj->spec_attr->user_data; + return &obj->spec_attr->user_data; } /** @@ -3241,7 +1478,8 @@ void lv_obj_set_user_data(lv_obj_t * obj, lv_obj_user_data_t data) { LV_ASSERT_OBJ(obj, LV_OBJX_NAME); - _lv_memcpy(&obj->user_data, &data, sizeof(lv_obj_user_data_t)); + if(obj->spec_attr == NULL) lv_obj_allocate_spec_attr(obj); + _lv_memcpy(&obj->spec_attr->user_data, &data, sizeof(lv_obj_user_data_t)); } #endif @@ -3255,7 +1493,8 @@ void * lv_obj_get_group(const lv_obj_t * obj) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); #if LV_USE_GROUP - return obj->group_p; + if(obj->spec_attr) return obj->spec_attr->group_p; + else return NULL; #else LV_UNUSED(obj); return NULL; @@ -3272,8 +1511,9 @@ bool lv_obj_is_focused(const lv_obj_t * obj) LV_ASSERT_OBJ(obj, LV_OBJX_NAME); #if LV_USE_GROUP - if(obj->group_p) { - if(lv_group_get_focused(obj->group_p) == obj) return true; + lv_group_t * g = lv_obj_get_group(obj); + if(g) { + if(lv_group_get_focused(g) == obj) return true; } return false; #else @@ -3282,62 +1522,50 @@ bool lv_obj_is_focused(const lv_obj_t * obj) #endif } +/** + * Tell if an object is an instance of a certain widget type or not + * @param obj pointer to an object + * @param type_str the type to check. The name of the widget's type, g.g. "lv_label", "lv_btn", etc + * @return true: `obj` has the given type + * @note Not only the "final" type matters. Therefore every widget has "lv_obj" type and "lv_slider" is an "lv_bar" too. + */ +bool lv_obj_is_instance_of(lv_obj_t * obj, const char * type_str) +{ + lv_obj_type_t type; + lv_obj_get_type(obj, &type); + uint8_t cnt; + for(cnt = 0; cnt < LV_MAX_ANCESTOR_NUM; cnt++) { + if(type.type[cnt] == NULL) break; + if(!strcmp(type.type[cnt], type_str)) return true; + } + return false; +} + +lv_ll_t * _lv_obj_get_child_ll(const lv_obj_t * obj) +{ + if(obj->spec_attr) return &obj->spec_attr->child_ll; + else return NULL; +} /*------------------- * OTHER FUNCTIONS *------------------*/ -/** - * Check if a given screen-space point is on an object's coordinates. - * - * This method is intended to be used mainly by advanced hit testing algorithms to check - * whether the point is even within the object (as an optimization). - * @param obj object to check - * @param point screen-space point - */ -bool lv_obj_is_point_on_coords(lv_obj_t * obj, const lv_point_t * point) -{ -#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_TINY - lv_area_t ext_area; - ext_area.x1 = obj->coords.x1 - obj->ext_click_pad_hor; - ext_area.x2 = obj->coords.x2 + obj->ext_click_pad_hor; - ext_area.y1 = obj->coords.y1 - obj->ext_click_pad_ver; - ext_area.y2 = obj->coords.y2 + obj->ext_click_pad_ver; - - if(!_lv_area_is_point_on(&ext_area, point, 0)) { -#elif LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL - lv_area_t ext_area; - ext_area.x1 = obj->coords.x1 - obj->ext_click_pad.x1; - ext_area.x2 = obj->coords.x2 + obj->ext_click_pad.x2; - ext_area.y1 = obj->coords.y1 - obj->ext_click_pad.y1; - ext_area.y2 = obj->coords.y2 + obj->ext_click_pad.y2; - - if(!_lv_area_is_point_on(&ext_area, point, 0)) { -#else - if(!_lv_area_is_point_on(&obj->coords, point, 0)) { -#endif - return false; - } - return true; -} /** - * Hit-test an object given a particular point in screen space. - * @param obj object to hit-test - * @param point screen-space point - * @return true if the object is considered under the point + * Get the really focused object by taking `focus_parent` into account. + * @param obj the start object + * @return the object to really focus */ -bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point) +lv_obj_t * _lv_obj_get_focused_obj(const lv_obj_t * obj) { - if(obj->adv_hittest) { - lv_hit_test_info_t hit_info; - hit_info.point = point; - hit_info.result = true; - obj->signal_cb(obj, LV_SIGNAL_HIT_TEST, &hit_info); - return hit_info.result; + if(obj == NULL) return NULL; + const lv_obj_t * focus_obj = obj; + while(lv_obj_has_flag(focus_obj, LV_OBJ_FLAG_FOCUS_BUBBLE) != false && focus_obj != NULL) { + focus_obj = lv_obj_get_parent(focus_obj); } - else - return lv_obj_is_point_on_coords(obj, point); + + return (lv_obj_t *)focus_obj; } /** @@ -3347,7 +1575,7 @@ bool lv_obj_hittest(lv_obj_t * obj, lv_point_t * point) * @param name name of the object. E.g. "lv_btn". (Only the pointer is saved) * @return LV_RES_OK */ -lv_res_t lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name) +lv_res_t _lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name) { uint8_t i; for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/ @@ -3358,364 +1586,6 @@ lv_res_t lv_obj_handle_get_type_signal(lv_obj_type_t * buf, const char * name) return LV_RES_OK; } -/** - * Initialize a rectangle descriptor from an object's styles - * @param obj pointer to an object - * @param type type of style. E.g. `LV_OBJ_PART_MAIN`, `LV_BTN_STYLE_REL` or `LV_PAGE_STYLE_SCRL` - * @param draw_dsc the descriptor the initialize - * @note Only the relevant fields will be set. - * E.g. if `border width == 0` the other border properties won't be evaluated. - */ -void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint8_t part, lv_draw_rect_dsc_t * draw_dsc) -{ - draw_dsc->radius = lv_obj_get_style_radius(obj, part); - -#if LV_USE_OPA_SCALE - lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part); - if(opa_scale <= LV_OPA_MIN) { - draw_dsc->bg_opa = LV_OPA_TRANSP; - draw_dsc->border_opa = LV_OPA_TRANSP; - draw_dsc->shadow_opa = LV_OPA_TRANSP; - draw_dsc->pattern_opa = LV_OPA_TRANSP; - draw_dsc->value_opa = LV_OPA_TRANSP; - return; - } -#endif - - if(draw_dsc->bg_opa != LV_OPA_TRANSP) { - draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part); - if(draw_dsc->bg_opa > LV_OPA_MIN) { - draw_dsc->bg_color = lv_obj_get_style_bg_color(obj, part); - draw_dsc->bg_grad_dir = lv_obj_get_style_bg_grad_dir(obj, part); - if(draw_dsc->bg_grad_dir != LV_GRAD_DIR_NONE) { - draw_dsc->bg_grad_color = lv_obj_get_style_bg_grad_color(obj, part); - draw_dsc->bg_main_color_stop = lv_obj_get_style_bg_main_stop(obj, part); - draw_dsc->bg_grad_color_stop = lv_obj_get_style_bg_grad_stop(obj, part); - } - -#if LV_USE_BLEND_MODES - draw_dsc->bg_blend_mode = lv_obj_get_style_bg_blend_mode(obj, part); -#endif - } - } - - draw_dsc->border_width = lv_obj_get_style_border_width(obj, part); - if(draw_dsc->border_width) { - if(draw_dsc->border_opa != LV_OPA_TRANSP) { - draw_dsc->border_opa = lv_obj_get_style_border_opa(obj, part); - if(draw_dsc->border_opa > LV_OPA_MIN) { - draw_dsc->border_side = lv_obj_get_style_border_side(obj, part); - draw_dsc->border_color = lv_obj_get_style_border_color(obj, part); - } -#if LV_USE_BLEND_MODES - draw_dsc->border_blend_mode = lv_obj_get_style_border_blend_mode(obj, part); -#endif - } - } - -#if LV_USE_OUTLINE - draw_dsc->outline_width = lv_obj_get_style_outline_width(obj, part); - if(draw_dsc->outline_width) { - if(draw_dsc->outline_opa != LV_OPA_TRANSP) { - draw_dsc->outline_opa = lv_obj_get_style_outline_opa(obj, part); - if(draw_dsc->outline_opa > LV_OPA_MIN) { - draw_dsc->outline_pad = lv_obj_get_style_outline_pad(obj, part); - draw_dsc->outline_color = lv_obj_get_style_outline_color(obj, part); - } -#if LV_USE_BLEND_MODES - draw_dsc->outline_blend_mode = lv_obj_get_style_outline_blend_mode(obj, part); -#endif - } - } -#endif - -#if LV_USE_PATTERN - draw_dsc->pattern_image = lv_obj_get_style_pattern_image(obj, part); - if(draw_dsc->pattern_image) { - if(draw_dsc->pattern_opa != LV_OPA_TRANSP) { - draw_dsc->pattern_opa = lv_obj_get_style_pattern_opa(obj, part); - if(draw_dsc->pattern_opa > LV_OPA_MIN) { - draw_dsc->pattern_recolor_opa = lv_obj_get_style_pattern_recolor_opa(obj, part); - draw_dsc->pattern_repeat = lv_obj_get_style_pattern_repeat(obj, part); - if(lv_img_src_get_type(draw_dsc->pattern_image) == LV_IMG_SRC_SYMBOL) { - draw_dsc->pattern_recolor = lv_obj_get_style_pattern_recolor(obj, part); - draw_dsc->pattern_font = lv_obj_get_style_text_font(obj, part); - } - else if(draw_dsc->pattern_recolor_opa > LV_OPA_MIN) { - draw_dsc->pattern_recolor = lv_obj_get_style_pattern_recolor(obj, part); - } -#if LV_USE_BLEND_MODES - draw_dsc->pattern_blend_mode = lv_obj_get_style_pattern_blend_mode(obj, part); -#endif - } - } - } -#endif - -#if LV_USE_SHADOW - draw_dsc->shadow_width = lv_obj_get_style_shadow_width(obj, part); - if(draw_dsc->shadow_width) { - if(draw_dsc->shadow_opa > LV_OPA_MIN) { - draw_dsc->shadow_opa = lv_obj_get_style_shadow_opa(obj, part); - if(draw_dsc->shadow_opa > LV_OPA_MIN) { - draw_dsc->shadow_ofs_x = lv_obj_get_style_shadow_ofs_x(obj, part); - draw_dsc->shadow_ofs_y = lv_obj_get_style_shadow_ofs_y(obj, part); - draw_dsc->shadow_spread = lv_obj_get_style_shadow_spread(obj, part); - draw_dsc->shadow_color = lv_obj_get_style_shadow_color(obj, part); -#if LV_USE_BLEND_MODES - draw_dsc->shadow_blend_mode = lv_obj_get_style_shadow_blend_mode(obj, part); -#endif - } - } - } -#endif - -#if LV_USE_VALUE_STR - draw_dsc->value_str = lv_obj_get_style_value_str(obj, part); - if(draw_dsc->value_str) { - if(draw_dsc->value_opa > LV_OPA_MIN) { - draw_dsc->value_opa = lv_obj_get_style_value_opa(obj, part); - if(draw_dsc->value_opa > LV_OPA_MIN) { - draw_dsc->value_ofs_x = lv_obj_get_style_value_ofs_x(obj, part); - draw_dsc->value_ofs_y = lv_obj_get_style_value_ofs_y(obj, part); - draw_dsc->value_color = lv_obj_get_style_value_color(obj, part); - draw_dsc->value_font = lv_obj_get_style_value_font(obj, part); - draw_dsc->value_letter_space = lv_obj_get_style_value_letter_space(obj, part); - draw_dsc->value_line_space = lv_obj_get_style_value_line_space(obj, part); - draw_dsc->value_align = lv_obj_get_style_value_align(obj, part); -#if LV_USE_BLEND_MODES - draw_dsc->value_blend_mode = lv_obj_get_style_value_blend_mode(obj, part); -#endif - } - } - } -#endif - -#if LV_USE_OPA_SCALE - if(opa_scale < LV_OPA_MAX) { - draw_dsc->bg_opa = (uint16_t)((uint16_t)draw_dsc->bg_opa * opa_scale) >> 8; - draw_dsc->border_opa = (uint16_t)((uint16_t)draw_dsc->border_opa * opa_scale) >> 8; - draw_dsc->shadow_opa = (uint16_t)((uint16_t)draw_dsc->shadow_opa * opa_scale) >> 8; - draw_dsc->pattern_opa = (uint16_t)((uint16_t)draw_dsc->pattern_opa * opa_scale) >> 8; - draw_dsc->value_opa = (uint16_t)((uint16_t)draw_dsc->value_opa * opa_scale) >> 8; - } -#endif -} - -void lv_obj_init_draw_label_dsc(lv_obj_t * obj, uint8_t part, lv_draw_label_dsc_t * draw_dsc) -{ - draw_dsc->opa = lv_obj_get_style_text_opa(obj, part); - if(draw_dsc->opa <= LV_OPA_MIN) return; - -#if LV_USE_OPA_SCALE - lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part); - if(opa_scale < LV_OPA_MAX) { - draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8; - } - if(draw_dsc->opa <= LV_OPA_MIN) return; -#endif - - draw_dsc->color = lv_obj_get_style_text_color(obj, part); - draw_dsc->letter_space = lv_obj_get_style_text_letter_space(obj, part); - draw_dsc->line_space = lv_obj_get_style_text_line_space(obj, part); - draw_dsc->decor = lv_obj_get_style_text_decor(obj, part); -#if LV_USE_BLEND_MODES - draw_dsc->blend_mode = lv_obj_get_style_text_blend_mode(obj, part); -#endif - - draw_dsc->font = lv_obj_get_style_text_font(obj, part); - - if(draw_dsc->sel_start != LV_DRAW_LABEL_NO_TXT_SEL && draw_dsc->sel_end != LV_DRAW_LABEL_NO_TXT_SEL) { - draw_dsc->sel_color = lv_obj_get_style_text_sel_color(obj, part); - draw_dsc->sel_bg_color = lv_obj_get_style_text_sel_bg_color(obj, part); - } - -#if LV_USE_BIDI - draw_dsc->bidi_dir = lv_obj_get_base_dir(obj); -#endif -} - -void lv_obj_init_draw_img_dsc(lv_obj_t * obj, uint8_t part, lv_draw_img_dsc_t * draw_dsc) -{ - draw_dsc->opa = lv_obj_get_style_image_opa(obj, part); - if(draw_dsc->opa <= LV_OPA_MIN) return; - -#if LV_USE_OPA_SCALE - lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part); - if(opa_scale < LV_OPA_MAX) { - draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8; - } - if(draw_dsc->opa <= LV_OPA_MIN) return; -#endif - - draw_dsc->angle = 0; - draw_dsc->zoom = LV_IMG_ZOOM_NONE; - draw_dsc->pivot.x = lv_area_get_width(&obj->coords) / 2; - draw_dsc->pivot.y = lv_area_get_height(&obj->coords) / 2; - - draw_dsc->recolor_opa = lv_obj_get_style_image_recolor_opa(obj, part); - if(draw_dsc->recolor_opa > 0) { - draw_dsc->recolor = lv_obj_get_style_image_recolor(obj, part); - } -#if LV_USE_BLEND_MODES - draw_dsc->blend_mode = lv_obj_get_style_image_blend_mode(obj, part); -#endif -} - -void lv_obj_init_draw_line_dsc(lv_obj_t * obj, uint8_t part, lv_draw_line_dsc_t * draw_dsc) -{ - draw_dsc->width = lv_obj_get_style_line_width(obj, part); - if(draw_dsc->width == 0) return; - - draw_dsc->opa = lv_obj_get_style_line_opa(obj, part); - if(draw_dsc->opa <= LV_OPA_MIN) return; - -#if LV_USE_OPA_SCALE - lv_opa_t opa_scale = lv_obj_get_style_opa_scale(obj, part); - if(opa_scale < LV_OPA_MAX) { - draw_dsc->opa = (uint16_t)((uint16_t)draw_dsc->opa * opa_scale) >> 8; - } - if(draw_dsc->opa <= LV_OPA_MIN) return; -#endif - - draw_dsc->color = lv_obj_get_style_line_color(obj, part); - - draw_dsc->dash_width = lv_obj_get_style_line_dash_width(obj, part); - if(draw_dsc->dash_width) { - draw_dsc->dash_gap = lv_obj_get_style_line_dash_gap(obj, part); - } - - draw_dsc->round_start = lv_obj_get_style_line_rounded(obj, part); - draw_dsc->round_end = draw_dsc->round_start; - -#if LV_USE_BLEND_MODES - draw_dsc->blend_mode = lv_obj_get_style_line_blend_mode(obj, part); -#endif -} - -/** - * Get the required extra size (around the object's part) to draw shadow, outline, value etc. - * @param obj pointer to an object - * @param part part of the object - */ -lv_coord_t lv_obj_get_draw_rect_ext_pad_size(lv_obj_t * obj, uint8_t part) -{ - lv_coord_t s = 0; - - lv_coord_t sh_width = lv_obj_get_style_shadow_width(obj, part); - if(sh_width) { - lv_opa_t sh_opa = lv_obj_get_style_shadow_opa(obj, part); - if(sh_opa > LV_OPA_MIN) { - sh_width = sh_width / 2; /*THe blur adds only half width*/ - sh_width++; - sh_width += lv_obj_get_style_shadow_spread(obj, part); - lv_style_int_t sh_ofs_x = lv_obj_get_style_shadow_ofs_x(obj, part); - lv_style_int_t sh_ofs_y = lv_obj_get_style_shadow_ofs_y(obj, part); - sh_width += LV_MATH_MAX(LV_MATH_ABS(sh_ofs_x), LV_MATH_ABS(sh_ofs_y)); - s = LV_MATH_MAX(s, sh_width); - } - } - - const char * value_str = lv_obj_get_style_value_str(obj, part); - if(value_str) { - lv_opa_t value_opa = lv_obj_get_style_value_opa(obj, part); - if(value_opa > LV_OPA_MIN) { - lv_style_int_t letter_space = lv_obj_get_style_value_letter_space(obj, part); - lv_style_int_t line_space = lv_obj_get_style_value_letter_space(obj, part); - const lv_font_t * font = lv_obj_get_style_value_font(obj, part); - - lv_point_t txt_size; - _lv_txt_get_size(&txt_size, value_str, font, letter_space, line_space, LV_COORD_MAX, LV_TXT_FLAG_NONE); - - lv_area_t value_area; - value_area.x1 = 0; - value_area.y1 = 0; - value_area.x2 = txt_size.x - 1; - value_area.y2 = txt_size.y - 1; - - lv_style_int_t align = lv_obj_get_style_value_align(obj, part); - lv_style_int_t xofs = lv_obj_get_style_value_ofs_x(obj, part); - lv_style_int_t yofs = lv_obj_get_style_value_ofs_y(obj, part); - lv_point_t p_align; - _lv_area_align(&obj->coords, &value_area, align, &p_align); - - value_area.x1 += p_align.x + xofs; - value_area.y1 += p_align.y + yofs; - value_area.x2 += p_align.x + xofs; - value_area.y2 += p_align.y + yofs; - - s = LV_MATH_MAX(s, obj->coords.x1 - value_area.x1); - s = LV_MATH_MAX(s, obj->coords.y1 - value_area.y1); - s = LV_MATH_MAX(s, value_area.x2 - obj->coords.x2); - s = LV_MATH_MAX(s, value_area.y2 - obj->coords.y2); - } - } - - lv_style_int_t outline_width = lv_obj_get_style_outline_width(obj, part); - if(outline_width) { - lv_opa_t outline_opa = lv_obj_get_style_outline_opa(obj, part); - if(outline_opa > LV_OPA_MIN) { - lv_style_int_t outline_pad = lv_obj_get_style_outline_pad(obj, part); - s = LV_MATH_MAX(s, outline_pad + outline_width); - } - } - - lv_coord_t w = lv_obj_get_style_transform_width(obj, part); - lv_coord_t h = lv_obj_get_style_transform_height(obj, part); - lv_coord_t wh = LV_MATH_MAX(w, h); - if(wh > 0) s += wh; - - return s; -} - -/** - * Fade in (from transparent to fully cover) an object and all its children using an `opa_scale` animation. - * @param obj the object to fade in - * @param time duration of the animation [ms] - * @param delay wait before the animation starts [ms] - */ -void lv_obj_fade_in(lv_obj_t * obj, uint32_t time, uint32_t delay) -{ -#if LV_USE_ANIMATION - lv_anim_t a; - lv_anim_init(&a); - lv_anim_set_var(&a, obj); - lv_anim_set_values(&a, LV_OPA_TRANSP, LV_OPA_COVER); - lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)opa_scale_anim); - lv_anim_set_ready_cb(&a, fade_in_anim_ready); - lv_anim_set_time(&a, time); - lv_anim_set_delay(&a, delay); - lv_anim_start(&a); -#else - (void) obj; /*Unused*/ - (void) time; /*Unused*/ - (void) delay; /*Unused*/ -#endif -} - -/** - * Fade out (from fully cover to transparent) an object and all its children using an `opa_scale` animation. - * @param obj the object to fade in - * @param time duration of the animation [ms] - * @param delay wait before the animation starts [ms] - */ -void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay) -{ -#if LV_USE_ANIMATION - lv_anim_t a; - lv_anim_init(&a); - lv_anim_set_var(&a, obj); - lv_anim_set_values(&a, LV_OPA_COVER, LV_OPA_TRANSP); - lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)opa_scale_anim); - lv_anim_set_time(&a, time); - lv_anim_set_delay(&a, delay); - lv_anim_start(&a); -#else - (void) obj; /*Unused*/ - (void) time; /*Unused*/ - (void) delay; /*Unused*/ -#endif -} /** * Check if any object has a given type @@ -3723,7 +1593,7 @@ void lv_obj_fade_out(lv_obj_t * obj, uint32_t time, uint32_t delay) * @param obj_type type of the object. (e.g. "lv_btn") * @return true: valid */ -bool lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type) +bool _lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type) { if(obj_type[0] == '\0') return true; @@ -3745,12 +1615,12 @@ bool lv_debug_check_obj_type(const lv_obj_t * obj, const char * obj_type) * @param obj_type type of the object. (e.g. "lv_btn") * @return true: valid */ -bool lv_debug_check_obj_valid(const lv_obj_t * obj) +bool _lv_debug_check_obj_valid(const lv_obj_t * obj) { lv_disp_t * disp = lv_disp_get_next(NULL); while(disp) { lv_obj_t * scr; - _LV_LL_READ(disp->scr_ll, scr) { + _LV_LL_READ(&disp->scr_ll, scr) { if(scr == obj) return true; bool found = obj_valid_child(scr, obj); @@ -3777,7 +1647,8 @@ static void lv_obj_del_async_cb(void * obj) static void obj_del_core(lv_obj_t * obj) { /*Let the user free the resources used in `LV_EVENT_DELETE`*/ - lv_event_send(obj, LV_EVENT_DELETE, NULL); + lv_res_t res = lv_event_send(obj, LV_EVENT_DELETE, NULL); + if(res == LV_RES_INV) return; /*Delete from the group*/ #if LV_USE_GROUP @@ -3788,7 +1659,7 @@ static void obj_del_core(lv_obj_t * obj) /*Remove the animations from this object*/ #if LV_USE_ANIMATION lv_anim_del(obj, NULL); - trans_del(obj, 0xFF, 0xFF, NULL); + _lv_obj_remove_style_trans(obj); #endif /*Delete the user data*/ @@ -3799,14 +1670,15 @@ static void obj_del_core(lv_obj_t * obj) #endif /*Recursively delete the children*/ + lv_ll_t * ll = _lv_obj_get_child_ll(obj); lv_obj_t * i; - i = _lv_ll_get_head(&(obj->child_ll)); + i = _lv_ll_get_head(ll); while(i != NULL) { /*Call the recursive delete to the child too*/ obj_del_core(i); /*Set i to the new head node*/ - i = _lv_ll_get_head(&(obj->child_ll)); + i = _lv_ll_get_head(ll); } lv_event_mark_deleted(obj); @@ -3840,7 +1712,7 @@ static void obj_del_core(lv_obj_t * obj) _lv_ll_remove(&d->scr_ll, obj); } else { - _lv_ll_remove(&(par->child_ll), obj); + _lv_ll_remove(_lv_obj_get_child_ll(par), obj); } /*Delete the base objects*/ @@ -3909,26 +1781,15 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area lv_draw_mask_radius_param_t * mp = _lv_mem_buf_get(sizeof(lv_draw_mask_radius_param_t)); lv_coord_t r = lv_obj_get_style_radius(obj, LV_OBJ_PART_MAIN); - /* If it has border make the clip area 1 px smaller to avoid color bleeding - * The border will cover the minimal issue on the edges*/ - if(draw_dsc.border_post && draw_dsc.border_opa >= LV_OPA_MIN && draw_dsc.border_width > 0) { - lv_area_t cc_area; - cc_area.x1 = obj->coords.x1 + 1; - cc_area.y1 = obj->coords.y1 + 1; - cc_area.x2 = obj->coords.x2 - 1; - cc_area.y2 = obj->coords.y2 - 1; - lv_draw_mask_radius_init(mp, &cc_area, r, false); - } - /*If no border use the full size.*/ - else { - lv_draw_mask_radius_init(mp, &obj->coords, r, false); - } + lv_draw_mask_radius_init(mp, &obj->coords, r, false); /*Add the mask and use `obj+8` as custom id. Don't use `obj` directly because it might be used by the user*/ lv_draw_mask_add(mp, obj + 8); } } else if(mode == LV_DESIGN_DRAW_POST) { + _lv_obj_draw_scrollbar(obj, clip_area); + if(lv_obj_get_style_clip_corner(obj, LV_OBJ_PART_MAIN)) { lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(obj + 8); _lv_mem_buf_release(param); @@ -3954,26 +1815,63 @@ static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area coords.y2 += h; lv_draw_rect(&coords, clip_area, &draw_dsc); } + +#if GRID_DEBUG + /*Draw the grid cells*/ + if(lv_obj_get_grid(obj)) { + _lv_grid_calc_t calc; + _lv_grid_calc(obj, &calc); + + /*Create a color unique to this object. */ + uint32_t cx = ((lv_uintptr_t) obj) & 0xFFFFFF; + cx = (cx & 0xff) ^ ((cx >> 8) & 0xff) ^ ((cx >> 16) & 0xff) ^ ((cx >> 24) & 0xff); + lv_color_t c = lv_color_hsv_to_rgb(cx & 0xff, 100, 100); + + lv_draw_rect_dsc_t grid_rect_dsc; + lv_draw_rect_dsc_init(&grid_rect_dsc); + grid_rect_dsc.bg_color = c; + grid_rect_dsc.bg_opa = LV_OPA_10; + grid_rect_dsc.border_width = 2; + grid_rect_dsc.border_color = c; + grid_rect_dsc.border_opa = LV_OPA_30; + + lv_point_t grid_abs; + lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_OBJ_PART_MAIN); + lv_coord_t pad_top = lv_obj_get_style_pad_top(obj, LV_OBJ_PART_MAIN); + grid_abs.x = pad_left + obj->coords.x1 - lv_obj_get_scroll_x(obj); + grid_abs.y = pad_top + obj->coords.y1 - lv_obj_get_scroll_y(obj); + + uint32_t row; + uint32_t col; + for(row = 0; row < calc.row_num; row ++) { + for(col = 0; col < calc.col_num; col ++) { + lv_area_t a; + a.x1 = grid_abs.x + calc.x[col]; + a.x2 = a.x1 + calc.w[col]; + a.y1 = grid_abs.y + calc.y[row]; + a.y2 = a.y1 + calc.h[row]; + lv_draw_rect(&a, clip_area, &grid_rect_dsc); + } + } + + + _lv_grid_calc_free(&calc); + } +#endif } return LV_DESIGN_RES_OK; } - -/** - * Get the really focused object by taking `focus_parent` into account. - * @param obj the start object - * @return the object to really focus - */ -lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj) +static void base_dir_refr_children(lv_obj_t * obj) { - if(obj == NULL) return NULL; - const lv_obj_t * focus_obj = obj; - while(lv_obj_get_focus_parent(focus_obj) != false && focus_obj != NULL) { - focus_obj = lv_obj_get_parent(focus_obj); + lv_obj_t * child; + _LV_LL_READ(_lv_obj_get_child_ll(obj), child) { + if(lv_obj_get_base_dir(child) == LV_BIDI_DIR_INHERIT) { + lv_signal_send(child, LV_SIGNAL_BASE_DIR_CHG, NULL); + base_dir_refr_children(child); + } } - - return (lv_obj_t *)focus_obj; } /** @@ -3985,39 +1883,59 @@ lv_obj_t * lv_obj_get_focused_obj(const lv_obj_t * obj) */ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) { + lv_res_t res = LV_RES_OK; + if(sign == LV_SIGNAL_GET_STYLE) { lv_get_style_info_t * info = param; if(info->part == LV_OBJ_PART_MAIN) info->result = &obj->style_list; else info->result = NULL; return LV_RES_OK; } - else if(sign == LV_SIGNAL_GET_TYPE) return lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); - - lv_res_t res = LV_RES_OK; - - if(sign == LV_SIGNAL_CHILD_CHG) { - /*Return 'invalid' if the child change signal is not enabled*/ - if(lv_obj_is_protected(obj, LV_PROTECT_CHILD_CHG) != false) res = LV_RES_INV; - } - else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) { - lv_coord_t d = lv_obj_get_draw_rect_ext_pad_size(obj, LV_OBJ_PART_MAIN); - obj->ext_draw_pad = LV_MATH_MAX(obj->ext_draw_pad, d); - } -#if LV_USE_OBJ_REALIGN - else if(sign == LV_SIGNAL_PARENT_SIZE_CHG) { - if(obj->realign.auto_realign) { - lv_obj_realign(obj); - } - } -#endif - else if(sign == LV_SIGNAL_STYLE_CHG) { - lv_obj_refresh_ext_draw_pad(obj); + else if(sign == LV_SIGNAL_GET_TYPE) { + return _lv_obj_handle_get_type_signal(param, LV_OBJX_NAME); } else if(sign == LV_SIGNAL_PRESSED) { lv_obj_add_state(obj, LV_STATE_PRESSED); } - else if(sign == LV_SIGNAL_RELEASED || sign == LV_SIGNAL_PRESS_LOST) { + else if(sign == LV_SIGNAL_RELEASED) { lv_obj_clear_state(obj, LV_STATE_PRESSED); + + /*Go the checked state if enabled*/ + if(lv_indev_get_scroll_obj(param) == NULL && lv_obj_has_flag(obj, LV_OBJ_FLAG_CHECKABLE)) { + uint32_t toggled = 0; + if(!(lv_obj_get_state(obj) & LV_STATE_CHECKED)) { + lv_obj_add_state(obj, LV_STATE_CHECKED); + toggled = 0; + } + else { + lv_obj_clear_state(obj, LV_STATE_CHECKED); + toggled = 1; + } + + res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, &toggled); + if(res != LV_RES_OK) return res; + } + } + else if(sign == LV_SIGNAL_PRESS_LOST) { + lv_obj_clear_state(obj, LV_STATE_PRESSED); + } + else if(sign == LV_SIGNAL_CONTROL) { +#if LV_USE_GROUP + if(lv_obj_has_flag(obj, LV_OBJ_FLAG_CHECKABLE)) { + uint32_t state = 0; + char c = *((char *)param); + if(c == LV_KEY_RIGHT || c == LV_KEY_UP) { + lv_obj_set_state(obj, LV_STATE_CHECKED); + state = 1; + } + else if(c == LV_KEY_LEFT || c == LV_KEY_DOWN) { + lv_obj_clear_state(obj, LV_STATE_CHECKED); + state = 0; + } + res = lv_event_send(obj, LV_EVENT_VALUE_CHANGED, &state); + if(res != LV_RES_OK) return res; + } +#endif } else if(sign == LV_SIGNAL_FOCUS) { bool editing = false; @@ -4029,14 +1947,14 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) state |= LV_STATE_EDITED; /*if using focus mode, change target to parent*/ - obj = lv_obj_get_focused_obj(obj); + obj = _lv_obj_get_focused_obj(obj); lv_obj_add_state(obj, state); } else { /*if using focus mode, change target to parent*/ - obj = lv_obj_get_focused_obj(obj); + obj = _lv_obj_get_focused_obj(obj); lv_obj_add_state(obj, LV_STATE_FOCUSED); lv_obj_clear_state(obj, LV_STATE_EDITED); @@ -4045,514 +1963,85 @@ static lv_res_t lv_obj_signal(lv_obj_t * obj, lv_signal_t sign, void * param) else if(sign == LV_SIGNAL_DEFOCUS) { /*if using focus mode, change target to parent*/ - obj = lv_obj_get_focused_obj(obj); + obj = _lv_obj_get_focused_obj(obj); lv_obj_clear_state(obj, LV_STATE_FOCUSED | LV_STATE_EDITED); } + else if(sign == LV_SIGNAL_COORD_CHG) { + + bool w_new = true; + bool h_new = true; + if(param) { + if(lv_area_get_width(param) == lv_obj_get_width(obj)) w_new = false; + if(lv_area_get_height(param) == lv_obj_get_height(obj)) h_new = false; + } + + if(w_new || h_new) { + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + lv_obj_t * child; + _LV_LL_READ(ll, child) { + if((LV_COORD_IS_PCT(child->w_set) && w_new) || + (LV_COORD_IS_PCT(child->h_set) && h_new)) + { + lv_obj_set_size(child, child->w_set, child->h_set); + } + } + if(lv_obj_get_grid(obj)) _lv_grid_full_refresh(obj); + if(lv_obj_get_flex_dir(obj) != LV_FLEX_DIR_NONE) _lv_flex_refresh(obj); + } + } + else if(sign == LV_SIGNAL_CHILD_CHG) { + if(param == NULL || _lv_obj_is_flex_item(param)) { + _lv_flex_refresh(obj); + } + + if(obj->w_set == LV_SIZE_AUTO || obj->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(obj, obj->w_set, obj->h_set); + } + } + else if(sign == LV_SIGNAL_SCROLL) { + res = lv_event_send(obj, LV_EVENT_SCROLL, NULL); + if(res != LV_RES_OK) return res; + } + else if(sign == LV_SIGNAL_SCROLL_END) { + if(lv_obj_get_scroll_mode(obj) == LV_SCROLL_MODE_ACTIVE) { + lv_obj_invalidate(obj); + } + } + else if(sign == LV_SIGNAL_REFR_EXT_DRAW_PAD) { + lv_coord_t * s = param; + lv_coord_t d = _lv_obj_get_draw_rect_ext_pad_size(obj, LV_OBJ_PART_MAIN); + *s = LV_MATH_MAX(*s, d); + } + else if(sign == LV_SIGNAL_STYLE_CHG) { + if(_lv_obj_is_grid_item(obj)) lv_grid_item_refr_pos(obj); + if(lv_obj_get_grid(obj)) _lv_grid_full_refresh(obj); + + if(_lv_obj_is_flex_item(obj)) _lv_flex_refresh(lv_obj_get_parent(obj)); + if(lv_obj_get_flex_dir(obj)) _lv_flex_refresh(obj); + + /*Reposition non grid objects on by one*/ + lv_obj_t * child; + + lv_ll_t * ll = _lv_obj_get_child_ll(obj); + _LV_LL_READ(ll, child) { + if(LV_COORD_IS_PX(child->x_set) || LV_COORD_IS_PX(child->y_set)) { + lv_obj_set_pos(child, child->x_set, child->y_set); + } + } + + if(obj->w_set == LV_SIZE_AUTO || obj->h_set == LV_SIZE_AUTO) { + lv_obj_set_size(obj, obj->w_set, obj->h_set); + } + _lv_obj_refresh_ext_draw_pad(obj); + } else if(sign == LV_SIGNAL_CLEANUP) { - lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN); + _lv_obj_reset_style_list_no_refr(obj, LV_OBJ_PART_MAIN); } return res; } -/** - * Reposition the children of an object. (Called recursively) - * @param obj pointer to an object which children will be repositioned - * @param x_diff x coordinate shift - * @param y_diff y coordinate shift - */ -static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_diff) -{ - lv_obj_t * i; - _LV_LL_READ(obj->child_ll, i) { - i->coords.x1 += x_diff; - i->coords.y1 += y_diff; - i->coords.x2 += x_diff; - i->coords.y2 += y_diff; - - refresh_children_position(i, x_diff, y_diff); - } -} - -/** - * Refresh the style of all children of an object. (Called recursively) - * @param style refresh objects only with this style_list. - * @param obj pointer to an object - */ -static void report_style_mod_core(void * style, lv_obj_t * obj) -{ - uint8_t part; - for(part = 0; part != _LV_OBJ_PART_REAL_LAST; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - - uint8_t ci; - for(ci = 0; ci < list->style_cnt; ci++) { - /* changed class to _class to allow compilation as c++ */ - lv_style_t * _class = lv_style_list_get_style(list, ci); - if(_class == style || style == NULL) { - lv_obj_refresh_style(obj, part, LV_STYLE_PROP_ALL); - break; - } - } - } - - lv_obj_t * child = lv_obj_get_child(obj, NULL); - while(child) { - report_style_mod_core(style, child); - child = lv_obj_get_child(obj, child); - } - -} - -/** - * Recursively refresh the style of the children. Go deeper until a not NULL style is found - * because the NULL styles are inherited from the parent - * @param obj pointer to an object - */ -static void refresh_children_style(lv_obj_t * obj) -{ - lv_obj_t * child = lv_obj_get_child(obj, NULL); - while(child != NULL) { - lv_obj_invalidate(child); - child->signal_cb(child, LV_SIGNAL_STYLE_CHG, NULL); - lv_obj_invalidate(child); - - refresh_children_style(child); /*Check children too*/ - child = lv_obj_get_child(obj, child); - } -} - -static void base_dir_refr_children(lv_obj_t * obj) -{ - lv_obj_t * child; - child = lv_obj_get_child(obj, NULL); - - while(child) { - if(child->base_dir == LV_BIDI_DIR_INHERIT) { - lv_signal_send(child, LV_SIGNAL_BASE_DIR_CHG, NULL); - base_dir_refr_children(child); - } - - child = lv_obj_get_child(obj, child); - } -} - -static void obj_align_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set, - lv_coord_t x_ofs, lv_coord_t y_ofs) -{ - lv_point_t new_pos; - _lv_area_align(&base->coords, &obj->coords, align, &new_pos); - - /*Bring together the coordination system of base and obj*/ - lv_obj_t * par = lv_obj_get_parent(obj); - lv_coord_t par_abs_x = par->coords.x1; - lv_coord_t par_abs_y = par->coords.y1; - new_pos.x += x_ofs; - new_pos.y += y_ofs; - new_pos.x -= par_abs_x; - new_pos.y -= par_abs_y; - - if(x_set && y_set) lv_obj_set_pos(obj, new_pos.x, new_pos.y); - else if(x_set) lv_obj_set_x(obj, new_pos.x); - else if(y_set) lv_obj_set_y(obj, new_pos.y); -} - -static void obj_align_mid_core(lv_obj_t * obj, const lv_obj_t * base, lv_align_t align, bool x_set, bool y_set, - lv_coord_t x_ofs, lv_coord_t y_ofs) -{ - lv_coord_t new_x = lv_obj_get_x(obj); - lv_coord_t new_y = lv_obj_get_y(obj); - - lv_coord_t obj_w_half = lv_obj_get_width(obj) / 2; - lv_coord_t obj_h_half = lv_obj_get_height(obj) / 2; - - - switch(align) { - case LV_ALIGN_CENTER: - new_x = lv_obj_get_width(base) / 2 - obj_w_half; - new_y = lv_obj_get_height(base) / 2 - obj_h_half; - break; - - case LV_ALIGN_IN_TOP_LEFT: - new_x = -obj_w_half; - new_y = -obj_h_half; - break; - case LV_ALIGN_IN_TOP_MID: - new_x = lv_obj_get_width(base) / 2 - obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_IN_TOP_RIGHT: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_IN_BOTTOM_LEFT: - new_x = -obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - case LV_ALIGN_IN_BOTTOM_MID: - new_x = lv_obj_get_width(base) / 2 - obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_IN_BOTTOM_RIGHT: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_IN_LEFT_MID: - new_x = -obj_w_half; - new_y = lv_obj_get_height(base) / 2 - obj_h_half; - break; - - case LV_ALIGN_IN_RIGHT_MID: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = lv_obj_get_height(base) / 2 - obj_h_half; - break; - - case LV_ALIGN_OUT_TOP_LEFT: - new_x = -obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_OUT_TOP_MID: - new_x = lv_obj_get_width(base) / 2 - obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_OUT_TOP_RIGHT: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_OUT_BOTTOM_LEFT: - new_x = -obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_OUT_BOTTOM_MID: - new_x = lv_obj_get_width(base) / 2 - obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_OUT_BOTTOM_RIGHT: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_OUT_LEFT_TOP: - new_x = -obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_OUT_LEFT_MID: - new_x = -obj_w_half; - new_y = lv_obj_get_height(base) / 2 - obj_h_half; - break; - - case LV_ALIGN_OUT_LEFT_BOTTOM: - new_x = -obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - - case LV_ALIGN_OUT_RIGHT_TOP: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = -obj_h_half; - break; - - case LV_ALIGN_OUT_RIGHT_MID: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = lv_obj_get_height(base) / 2 - obj_h_half; - break; - - case LV_ALIGN_OUT_RIGHT_BOTTOM: - new_x = lv_obj_get_width(base) - obj_w_half; - new_y = lv_obj_get_height(base) - obj_h_half; - break; - } - - /*Bring together the coordination system of base and obj*/ - lv_obj_t * par = lv_obj_get_parent(obj); - lv_coord_t base_abs_x = base->coords.x1; - lv_coord_t base_abs_y = base->coords.y1; - lv_coord_t par_abs_x = par->coords.x1; - lv_coord_t par_abs_y = par->coords.y1; - new_x += x_ofs + base_abs_x; - new_y += y_ofs + base_abs_y; - new_x -= par_abs_x; - new_y -= par_abs_y; - if(x_set && y_set) lv_obj_set_pos(obj, new_x, new_y); - else if(x_set) lv_obj_set_x(obj, new_x); - else if(y_set) lv_obj_set_y(obj, new_y); - -} - - - -#if LV_USE_ANIMATION - -/** - * Allocate and initialize a transition for a property of an object if the properties value is different in the new state. - * It allocates `lv_style_trans_t` in `_lv_obj_style_trans_ll` and set only `start/end_values`. No animation will be created here. - * @param obj and object to add the transition - * @param prop the property to apply the transaction - * @param part the part of the object to apply the transaction - * @param prev_state the previous state of the objects - * @param new_state the new state of the object - * @return pointer to the allocated `the transaction` variable or `NULL` if no transition created - */ -static lv_style_trans_t * trans_create(lv_obj_t * obj, lv_style_property_t prop, uint8_t part, lv_state_t prev_state, - lv_state_t new_state) -{ - lv_style_trans_t * tr; - lv_style_list_t * style_list = lv_obj_get_style_list(obj, part); - lv_style_t * style_trans = _lv_style_list_get_transition_style(style_list); - - bool cahche_ori = style_list->ignore_cache; - - /*Get the previous and current values*/ - if((prop & 0xF) < LV_STYLE_ID_COLOR) { /*Int*/ - style_list->skip_trans = 1; - style_list->ignore_cache = 1; - obj->state = prev_state; - lv_style_int_t int1 = _lv_obj_get_style_int(obj, part, prop); - obj->state = new_state; - lv_style_int_t int2 = _lv_obj_get_style_int(obj, part, prop); - style_list->skip_trans = 0; - style_list->ignore_cache = cahche_ori; - - if(int1 == int2) return NULL; - obj->state = prev_state; - int1 = _lv_obj_get_style_int(obj, part, prop); - obj->state = new_state; - _lv_style_set_int(style_trans, prop, int1); /*Be sure `trans_style` has a valid value */ - - if(prop == LV_STYLE_RADIUS) { - if(int1 == LV_RADIUS_CIRCLE || int2 == LV_RADIUS_CIRCLE) { - lv_coord_t whalf = lv_obj_get_width(obj) / 2; - lv_coord_t hhalf = lv_obj_get_width(obj) / 2; - if(int1 == LV_RADIUS_CIRCLE) int1 = LV_MATH_MIN(whalf + 1, hhalf + 1); - if(int2 == LV_RADIUS_CIRCLE) int2 = LV_MATH_MIN(whalf + 1, hhalf + 1); - } - } - - tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll)); - LV_ASSERT_MEM(tr); - if(tr == NULL) return NULL; - tr->start_value._int = int1; - tr->end_value._int = int2; - } - else if((prop & 0xF) < LV_STYLE_ID_OPA) { /*Color*/ - style_list->skip_trans = 1; - style_list->ignore_cache = 1; - obj->state = prev_state; - lv_color_t c1 = _lv_obj_get_style_color(obj, part, prop); - obj->state = new_state; - lv_color_t c2 = _lv_obj_get_style_color(obj, part, prop); - style_list->skip_trans = 0; - style_list->ignore_cache = cahche_ori; - - if(c1.full == c2.full) return NULL; - obj->state = prev_state; - c1 = _lv_obj_get_style_color(obj, part, prop); - obj->state = new_state; - _lv_style_set_color(style_trans, prop, c1); /*Be sure `trans_style` has a valid value */ - - tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll)); - LV_ASSERT_MEM(tr); - if(tr == NULL) return NULL; - tr->start_value._color = c1; - tr->end_value._color = c2; - } - else if((prop & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/ - style_list->skip_trans = 1; - style_list->ignore_cache = 1; - obj->state = prev_state; - lv_opa_t o1 = _lv_obj_get_style_opa(obj, part, prop); - obj->state = new_state; - lv_opa_t o2 = _lv_obj_get_style_opa(obj, part, prop); - style_list->skip_trans = 0; - style_list->ignore_cache = cahche_ori; - - if(o1 == o2) return NULL; - - obj->state = prev_state; - o1 = _lv_obj_get_style_opa(obj, part, prop); - obj->state = new_state; - _lv_style_set_opa(style_trans, prop, o1); /*Be sure `trans_style` has a valid value */ - - tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll)); - LV_ASSERT_MEM(tr); - if(tr == NULL) return NULL; - tr->start_value._opa = o1; - tr->end_value._opa = o2; - } - else { /*Ptr*/ - obj->state = prev_state; - style_list->skip_trans = 1; - style_list->ignore_cache = 1; - const void * p1 = _lv_obj_get_style_ptr(obj, part, prop); - obj->state = new_state; - const void * p2 = _lv_obj_get_style_ptr(obj, part, prop); - style_list->skip_trans = 0; - style_list->ignore_cache = cahche_ori; - - if(memcmp(&p1, &p2, sizeof(const void *)) == 0) return NULL; - obj->state = prev_state; - p1 = _lv_obj_get_style_ptr(obj, part, prop); - obj->state = new_state; - _lv_style_set_ptr(style_trans, prop, p1); /*Be sure `trans_style` has a valid value */ - - tr = _lv_ll_ins_head(&LV_GC_ROOT(_lv_obj_style_trans_ll)); - LV_ASSERT_MEM(tr); - if(tr == NULL) return NULL; - tr->start_value._ptr = p1; - tr->end_value._ptr = p2; - } - - return tr; -} - -/** - * Remove the transition from object's part's property. - * - Remove the transition from `_lv_obj_style_trans_ll` and free it - * - Delete pending transitions - * @param obj pointer to an object which transition(s) should be removed - * @param part a part of object or 0xFF to remove from all parts - * @param prop a property or 0xFF to remove all properties - * @param tr_limit delete transitions only "older" then this. `NULL` is not used - */ -static void trans_del(lv_obj_t * obj, uint8_t part, lv_style_property_t prop, lv_style_trans_t * tr_limit) -{ - lv_style_trans_t * tr; - lv_style_trans_t * tr_prev; - tr = _lv_ll_get_tail(&LV_GC_ROOT(_lv_obj_style_trans_ll)); - while(tr != NULL) { - if(tr == tr_limit) break; - - /*'tr' might be deleted, so get the next object while 'tr' is valid*/ - tr_prev = _lv_ll_get_prev(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr); - - if(tr->obj == obj && (part == tr->part || part == 0xFF) && (prop == tr->prop || prop == 0xFF)) { - /* Remove the transitioned property from trans. style - * to allow changing it by normal styles*/ - lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part); - lv_style_t * style_trans = _lv_style_list_get_transition_style(list); - lv_style_remove_prop(style_trans, tr->prop); - - lv_anim_del(tr, NULL); - _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr); - lv_mem_free(tr); - } - tr = tr_prev; - } -} - -static void trans_anim_cb(lv_style_trans_t * tr, lv_anim_value_t v) -{ - lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part); - lv_style_t * style = _lv_style_list_get_transition_style(list); - - if((tr->prop & 0xF) < LV_STYLE_ID_COLOR) { /*Value*/ - lv_style_int_t x; - if(v == 0) x = tr->start_value._int; - else if(v == 255) x = tr->end_value._int; - else x = tr->start_value._int + ((int32_t)((int32_t)(tr->end_value._int - tr->start_value._int) * v) >> 8); - _lv_style_set_int(style, tr->prop, x); - } - else if((tr->prop & 0xF) < LV_STYLE_ID_OPA) { /*Color*/ - lv_color_t x; - if(v <= 0) x = tr->start_value._color; - else if(v >= 255) x = tr->end_value._color; - else x = lv_color_mix(tr->end_value._color, tr->start_value._color, v); - _lv_style_set_color(style, tr->prop, x); - } - else if((tr->prop & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/ - lv_opa_t x; - if(v <= 0) x = tr->start_value._opa; - else if(v >= 255) x = tr->end_value._opa; - else x = tr->start_value._opa + (((tr->end_value._opa - tr->start_value._opa) * v) >> 8); - _lv_style_set_opa(style, tr->prop, x); - } - else { - const void * x; - if(v < 128) x = tr->start_value._ptr; - else x = tr->end_value._ptr; - _lv_style_set_ptr(style, tr->prop, x); - } - lv_obj_refresh_style(tr->obj, tr->part, tr->prop); - -} - -static void trans_anim_start_cb(lv_anim_t * a) -{ - lv_style_trans_t * tr = a->var; - - lv_style_property_t prop_tmp = tr->prop; - - /*Start the animation from the current value*/ - if((prop_tmp & 0xF) < LV_STYLE_ID_COLOR) { /*Int*/ - tr->start_value._int = _lv_obj_get_style_int(tr->obj, tr->part, prop_tmp); - } - else if((prop_tmp & 0xF) < LV_STYLE_ID_OPA) { /*Color*/ - tr->start_value._color = _lv_obj_get_style_color(tr->obj, tr->part, prop_tmp); - } - else if((prop_tmp & 0xF) < LV_STYLE_ID_PTR) { /*Opa*/ - tr->start_value._opa = _lv_obj_get_style_opa(tr->obj, tr->part, prop_tmp); - } - else { /*Ptr*/ - tr->start_value._ptr = _lv_obj_get_style_ptr(tr->obj, tr->part, prop_tmp); - } - - /*Init prop to an invalid values to be sure `trans_del` won't delete this added `tr`*/ - tr->prop = 0; - /*Delete the relate transition if any*/ - trans_del(tr->obj, tr->part, prop_tmp, tr); - - tr->prop = prop_tmp; - -} - -static void trans_anim_ready_cb(lv_anim_t * a) -{ - lv_style_trans_t * tr = a->var; - - /* Remove the transitioned property from trans. style - * if there no more transitions for this property - * It allows changing it by normal styles*/ - - bool running = false; - lv_style_trans_t * tr_i; - _LV_LL_READ(LV_GC_ROOT(_lv_obj_style_trans_ll), tr_i) { - if(tr_i != tr && tr_i->obj == tr->obj && tr_i->part == tr->part && tr_i->prop == tr->prop) { - running = true; - } - } - - if(!running) { - lv_style_list_t * list = lv_obj_get_style_list(tr->obj, tr->part); - lv_style_t * style_trans = _lv_style_list_get_transition_style(list); - lv_style_remove_prop(style_trans, tr->prop); - } - - _lv_ll_remove(&LV_GC_ROOT(_lv_obj_style_trans_ll), tr); - lv_mem_free(tr); -} - -static void opa_scale_anim(lv_obj_t * obj, lv_anim_value_t v) -{ - lv_obj_set_style_local_opa_scale(obj, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, v); -} - -static void fade_in_anim_ready(lv_anim_t * a) -{ - lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE); -} - -#endif static void lv_event_mark_deleted(lv_obj_t * obj) { @@ -4568,7 +2057,8 @@ static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_fin { /*Check all children of `parent`*/ lv_obj_t * child; - _LV_LL_READ(parent->child_ll, child) { + lv_ll_t * ll = _lv_obj_get_child_ll(parent); + _LV_LL_READ(ll, child) { if(child == obj_to_find) return true; /*Check the children*/ @@ -4578,292 +2068,3 @@ static bool obj_valid_child(const lv_obj_t * parent, const lv_obj_t * obj_to_fin return false; } - -static bool style_prop_is_cacheble(lv_style_property_t prop) -{ - - switch(prop) { - case LV_STYLE_PROP_ALL: - case LV_STYLE_CLIP_CORNER: - case LV_STYLE_TEXT_LETTER_SPACE: - case LV_STYLE_TEXT_LINE_SPACE: - case LV_STYLE_TEXT_FONT: - case LV_STYLE_TRANSFORM_ANGLE: - case LV_STYLE_TRANSFORM_WIDTH: - case LV_STYLE_TRANSFORM_HEIGHT: - case LV_STYLE_TRANSFORM_ZOOM: - case LV_STYLE_BORDER_WIDTH: - case LV_STYLE_OUTLINE_WIDTH: - case LV_STYLE_RADIUS: - case LV_STYLE_SHADOW_WIDTH: - case LV_STYLE_OPA_SCALE: - case LV_STYLE_BG_OPA: - case LV_STYLE_BORDER_SIDE: - case LV_STYLE_BORDER_POST: - case LV_STYLE_IMAGE_RECOLOR_OPA: - case LV_STYLE_VALUE_STR: - case LV_STYLE_PATTERN_IMAGE: - case LV_STYLE_PAD_TOP: - case LV_STYLE_PAD_BOTTOM: - case LV_STYLE_PAD_LEFT: - case LV_STYLE_PAD_RIGHT: - case LV_STYLE_MARGIN_TOP: - case LV_STYLE_MARGIN_BOTTOM: - case LV_STYLE_MARGIN_LEFT: - case LV_STYLE_MARGIN_RIGHT: - case LV_STYLE_BG_BLEND_MODE: - case LV_STYLE_BORDER_BLEND_MODE: - case LV_STYLE_IMAGE_BLEND_MODE: - case LV_STYLE_LINE_BLEND_MODE: - case LV_STYLE_OUTLINE_BLEND_MODE: - case LV_STYLE_PATTERN_BLEND_MODE: - case LV_STYLE_SHADOW_BLEND_MODE: - case LV_STYLE_TEXT_BLEND_MODE: - case LV_STYLE_VALUE_BLEND_MODE: - return true; - break; - default: - return false; - } -} - -/** - * Update the cache of style list - * @param obj pointer to an object - * @param part the part of the object - * @param prop the property which triggered the update - */ -static void update_style_cache(lv_obj_t * obj, uint8_t part, uint16_t prop) -{ - if(style_prop_is_cacheble(prop) == false) return; - - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - - bool ignore_cache_ori = list->ignore_cache; - list->ignore_cache = 1; - -#if LV_USE_OPA_SCALE - list->opa_scale_cover = lv_obj_get_style_opa_scale(obj, part) == LV_OPA_COVER ? 1 : 0; -#else - list->opa_scale_cover = 1; -#endif - list->text_decor_none = lv_obj_get_style_text_decor(obj, part) == LV_TEXT_DECOR_NONE ? 1 : 0; - list->text_font_normal = lv_obj_get_style_text_font(obj, part) == LV_THEME_DEFAULT_FONT_NORMAL ? 1 : 0; - - list->text_space_zero = 1; - if(lv_obj_get_style_text_letter_space(obj, part) != 0 || - lv_obj_get_style_text_line_space(obj, part) != 0) { - list->text_space_zero = 0; - } - - - lv_opa_t bg_opa = lv_obj_get_style_bg_opa(obj, part); - list->bg_opa_transp = bg_opa == LV_OPA_TRANSP ? 1 : 0; - list->bg_opa_cover = bg_opa == LV_OPA_COVER ? 1 : 0; - - list->border_width_zero = lv_obj_get_style_border_width(obj, part) == 0 ? 1 : 0; - list->border_side_full = lv_obj_get_style_border_side(obj, part) == LV_BORDER_SIDE_FULL ? 1 : 0; - list->border_post_off = lv_obj_get_style_border_post(obj, part) == 0 ? 1 : 0; - list->clip_corner_off = lv_obj_get_style_clip_corner(obj, part) == false ? 1 : 0; - list->img_recolor_opa_transp = lv_obj_get_style_image_recolor_opa(obj, part) == LV_OPA_TRANSP ? 1 : 0; - list->outline_width_zero = lv_obj_get_style_outline_width(obj, part) == 0 ? 1 : 0; - list->pattern_img_null = lv_obj_get_style_pattern_image(obj, part) == NULL ? 1 : 0; - list->radius_zero = lv_obj_get_style_radius(obj, part) == 0 ? 1 : 0; - list->shadow_width_zero = lv_obj_get_style_shadow_width(obj, part) == 0 ? 1 : 0; - list->value_txt_str = lv_obj_get_style_value_str(obj, part) == NULL ? 1 : 0; - - - list->transform_all_zero = 1; - if(lv_obj_get_style_transform_angle(obj, part) != 0 || - lv_obj_get_style_transform_width(obj, part) != 0 || - lv_obj_get_style_transform_height(obj, part) != 0 || - lv_obj_get_style_transform_zoom(obj, part) != LV_IMG_ZOOM_NONE) { - list->transform_all_zero = 0; - } - - list->pad_all_zero = 1; - if(lv_obj_get_style_pad_top(obj, part) != 0 || - lv_obj_get_style_pad_bottom(obj, part) != 0 || - lv_obj_get_style_pad_left(obj, part) != 0 || - lv_obj_get_style_pad_right(obj, part) != 0) { - list->pad_all_zero = 0; - } - - list->margin_all_zero = 1; - if(lv_obj_get_style_margin_top(obj, part) != 0 || - lv_obj_get_style_margin_bottom(obj, part) != 0 || - lv_obj_get_style_margin_left(obj, part) != 0 || - lv_obj_get_style_margin_right(obj, part) != 0) { - list->margin_all_zero = 0; - } - - list->blend_mode_all_normal = 1; -#if LV_USE_BLEND_MODES - if(lv_obj_get_style_bg_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_border_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_pattern_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_outline_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_value_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_text_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_line_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_image_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL || - lv_obj_get_style_shadow_blend_mode(obj, part) != LV_BLEND_MODE_NORMAL) { - list->blend_mode_all_normal = 0; - } -#endif - list->ignore_cache = ignore_cache_ori; - list->valid_cache = 1; -} - -/** - * Update the cache of style list - * @param obj pointer to an object - * @param part the part of the object - */ -static void update_style_cache_children(lv_obj_t * obj) -{ - uint8_t part; - for(part = 0; part != _LV_OBJ_PART_REAL_LAST; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - - bool ignore_cache_ori = list->ignore_cache; - list->ignore_cache = 1; - - list->opa_scale_cover = lv_obj_get_style_opa_scale(obj, part) == LV_OPA_COVER ? 1 : 0; - list->text_decor_none = lv_obj_get_style_text_decor(obj, part) == LV_TEXT_DECOR_NONE ? 1 : 0; - list->text_font_normal = lv_obj_get_style_text_font(obj, part) == lv_theme_get_font_normal() ? 1 : 0; - list->img_recolor_opa_transp = lv_obj_get_style_image_recolor_opa(obj, part) == LV_OPA_TRANSP ? 1 : 0; - - list->text_space_zero = 1; - if(lv_obj_get_style_text_letter_space(obj, part) != 0 || - lv_obj_get_style_text_line_space(obj, part) != 0) { - list->text_space_zero = 0; - } - - list->ignore_cache = ignore_cache_ori; - } - - lv_obj_t * child = lv_obj_get_child(obj, NULL); - while(child) { - update_style_cache_children(child); - child = lv_obj_get_child(obj, child); - } - -} - -/** - * Mark the object and all of it's children's style lists as invalid. - * The cache will be updated when a cached property asked nest time - * @param obj pointer to an object - */ -static void invalidate_style_cache(lv_obj_t * obj, uint8_t part, lv_style_property_t prop) -{ - if(style_prop_is_cacheble(prop) == false) return; - - if(part != LV_OBJ_PART_ALL) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) return; - list->valid_cache = 0; - } - else { - - for(part = 0; part < _LV_OBJ_PART_REAL_FIRST; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - list->valid_cache = 0; - } - for(part = _LV_OBJ_PART_REAL_FIRST; part < 0xFF; part++) { - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - if(list == NULL) break; - list->valid_cache = 0; - } - } - - lv_obj_t * child = lv_obj_get_child(obj, NULL); - while(child) { - update_style_cache_children(child); - child = lv_obj_get_child(obj, child); - } -} - -static void style_snapshot(lv_obj_t * obj, uint8_t part, style_snapshot_t * shot) -{ - _lv_obj_disable_style_caching(obj, true); - _lv_memset_00(shot, sizeof(style_snapshot_t)); - lv_draw_rect_dsc_init(&shot->rect); - lv_draw_label_dsc_init(&shot->label); - lv_draw_img_dsc_init(&shot->img); - lv_draw_line_dsc_init(&shot->line); - - lv_style_list_t * list = lv_obj_get_style_list(obj, part); - bool trans_ori = list->skip_trans; - list->skip_trans = 1; - - lv_obj_init_draw_rect_dsc(obj, part, &shot->rect); - lv_obj_init_draw_label_dsc(obj, part, &shot->label); - lv_obj_init_draw_img_dsc(obj, part, &shot->img); - lv_obj_init_draw_line_dsc(obj, part, &shot->line); - - - shot->pad_top = lv_obj_get_style_pad_top(obj, part); - shot->pad_bottom = lv_obj_get_style_pad_bottom(obj, part); - shot->pad_right = lv_obj_get_style_pad_right(obj, part); - shot->pad_left = lv_obj_get_style_pad_left(obj, part); - shot->pad_inner = lv_obj_get_style_pad_inner(obj, part); - shot->margin_top = lv_obj_get_style_margin_top(obj, part); - shot->margin_bottom = lv_obj_get_style_margin_bottom(obj, part); - shot->margin_left = lv_obj_get_style_margin_left(obj, part); - shot->margin_right = lv_obj_get_style_margin_right(obj, part); - shot->size = lv_obj_get_style_size(obj, part); - shot->transform_width = lv_obj_get_style_transform_width(obj, part); - shot->transform_height = lv_obj_get_style_transform_height(obj, part); - shot->transform_angle = lv_obj_get_style_transform_angle(obj, part); - shot->transform_zoom = lv_obj_get_style_transform_zoom(obj, part); - shot->scale_width = lv_obj_get_style_scale_width(obj, part); - shot->scale_border_width = lv_obj_get_style_scale_border_width(obj, part); - shot->scale_end_border_width = lv_obj_get_style_scale_end_border_width(obj, part); - shot->scale_end_line_width = lv_obj_get_style_scale_end_line_width(obj, part); - shot->scale_grad_color = lv_obj_get_style_scale_grad_color(obj, part); - shot->scale_end_color = lv_obj_get_style_scale_end_color(obj, part); - shot->opa_scale = lv_obj_get_style_opa_scale(obj, part); - shot->clip_corder = lv_obj_get_style_clip_corner(obj, part); - shot->border_post = lv_obj_get_style_border_post(obj, part); - - _lv_obj_disable_style_caching(obj, false); - list->skip_trans = trans_ori; -} - -static style_snapshot_res_t style_snapshot_compare(style_snapshot_t * shot1, style_snapshot_t * shot2) -{ - if(memcmp(shot1, shot2, sizeof(style_snapshot_t)) == 0) return STYLE_COMPARE_SAME; - - - if(shot1->pad_top != shot2->pad_top) return STYLE_COMPARE_DIFF; - if(shot1->pad_bottom != shot2->pad_bottom) return STYLE_COMPARE_DIFF; - if(shot1->pad_left != shot2->pad_right) return STYLE_COMPARE_DIFF; - if(shot1->pad_right != shot2->pad_right) return STYLE_COMPARE_DIFF; - if(shot1->pad_top != shot2->pad_top) return STYLE_COMPARE_DIFF; - if(shot1->pad_inner != shot2->pad_inner) return STYLE_COMPARE_DIFF; - if(shot1->margin_top != shot2->margin_top) return STYLE_COMPARE_DIFF; - if(shot1->margin_bottom != shot2->margin_bottom) return STYLE_COMPARE_DIFF; - if(shot1->margin_left != shot2->margin_right) return STYLE_COMPARE_DIFF; - if(shot1->margin_right != shot2->margin_right) return STYLE_COMPARE_DIFF; - if(shot1->margin_top != shot2->margin_top) return STYLE_COMPARE_DIFF; - if(shot1->transform_width != shot2->transform_width) return STYLE_COMPARE_DIFF; - if(shot1->transform_height != shot2->transform_height) return STYLE_COMPARE_DIFF; - if(shot1->transform_angle != shot2->transform_angle) return STYLE_COMPARE_DIFF; - if(shot1->transform_zoom != shot2->transform_zoom) return STYLE_COMPARE_DIFF; - if(shot1->rect.outline_width != shot2->rect.outline_width) return STYLE_COMPARE_DIFF; - if(shot1->rect.outline_pad != shot2->rect.outline_pad) return STYLE_COMPARE_DIFF; - if(shot1->rect.value_font != shot2->rect.value_font) return STYLE_COMPARE_DIFF; - if(shot1->rect.value_align != shot2->rect.value_align) return STYLE_COMPARE_DIFF; - if(shot1->rect.value_font != shot2->rect.value_font) return STYLE_COMPARE_DIFF; - if(shot1->rect.shadow_spread != shot2->rect.shadow_spread) return STYLE_COMPARE_DIFF; - if(shot1->rect.shadow_width != shot2->rect.shadow_width) return STYLE_COMPARE_DIFF; - if(shot1->rect.shadow_ofs_x != shot2->rect.shadow_ofs_x) return STYLE_COMPARE_DIFF; - if(shot1->rect.shadow_ofs_y != shot2->rect.shadow_ofs_y) return STYLE_COMPARE_DIFF; - - /*If not returned earlier its just a visual difference, a simple redraw is enough*/ - return STYLE_COMPARE_VISUAL_DIFF; -} diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index 2aabcd7ca..502e17c77 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -18,6 +18,8 @@ extern "C" { #include #include #include "lv_style.h" +#include "lv_grid.h" +#include "lv_flex.h" #include "../lv_misc/lv_types.h" #include "../lv_misc/lv_area.h" #include "../lv_misc/lv_color.h" @@ -56,7 +58,6 @@ extern "C" { struct _lv_obj_t; - /** Design modes */ enum { LV_DESIGN_DRAW_MAIN, /**< Draw the main portion of the object */ @@ -85,15 +86,15 @@ enum { LV_EVENT_PRESSED, /**< The object has been pressed*/ LV_EVENT_PRESSING, /**< The object is being pressed (called continuously while pressing)*/ LV_EVENT_PRESS_LOST, /**< User is still pressing but slid cursor/finger off of the object */ - LV_EVENT_SHORT_CLICKED, /**< User pressed object for a short period of time, then released it. Not called if dragged. */ - LV_EVENT_LONG_PRESSED, /**< Object has been pressed for at least `LV_INDEV_LONG_PRESS_TIME`. Not called if dragged.*/ + LV_EVENT_SHORT_CLICKED, /**< User pressed object for a short period of time, then released it. Not called if scrolled. */ + LV_EVENT_LONG_PRESSED, /**< Object has been pressed for at least `LV_INDEV_LONG_PRESS_TIME`. Not called if scrolled.*/ LV_EVENT_LONG_PRESSED_REPEAT, /**< Called after `LV_INDEV_LONG_PRESS_TIME` in every - `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_INDEV_LONG_PRESS_REP_TIME` ms. Not called if scrolled.*/ + LV_EVENT_CLICKED, /**< Called on release if not scrolled (regardless to long press)*/ LV_EVENT_RELEASED, /**< Called in every cases when the object has been released*/ - LV_EVENT_DRAG_BEGIN, - LV_EVENT_DRAG_END, - LV_EVENT_DRAG_THROW_BEGIN, + LV_EVENT_SCROLL_BEGIN, + LV_EVENT_SCROLL_END, + LV_EVENT_SCROLL, LV_EVENT_GESTURE, /**< The object has been gesture*/ LV_EVENT_KEY, LV_EVENT_FOCUSED, @@ -121,28 +122,27 @@ typedef void (*lv_event_cb_t)(struct _lv_obj_t * obj, lv_event_t event); * on the object. */ enum { /*General signals*/ - LV_SIGNAL_CLEANUP, /**< Object is being deleted */ - LV_SIGNAL_CHILD_CHG, /**< Child was removed/added */ - LV_SIGNAL_COORD_CHG, /**< Object coordinates/size have changed */ - LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */ - LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */ - LV_SIGNAL_BASE_DIR_CHG, /**